Feature request: add functionality to retrieve the the server certificate in a client request
Rationale
This request is related to this SO Question where I asked whether or not it is possible to get the peer certificate when running a client request.
It is quite logical that the implemented hack is not going to be supported. I do, however, have use-cases in which it is required to retrieve the peer certificate. And I was hoping on working together to find a clean solution.
In protocols like Kerberos and NTLM the server certificate is used in followup steps of the authentication protocol.
A possible solution
If there is a better solution that would be great as well. Just trying to offer something workable
An extra parameter like retrieve_peer_certificate to the method aiohttp.Client._request which is default False and would make sure that a property like peer_certificate would be set in the response object. It would it be possible internally use a _get_transport that would return the SSLSocket if the connection is SSL/TLS on which you would be able to call getpeercert
Maybe add a getpeercert() method is enough.
Unfortunately no.
- Peer cert can be retrieved in two forms: binary and dict.
- Peer name could be interested in case of rotating DNS
- Used cipher and other SSL options list selected ALPN/NPN protocols are also very important in some cases.
@asvetlov Maybe we can expose the underlying socket (SSLSocket) object from a specified interface? They can be useful in many ways.
This feature would be very useful!
This feature would be very useful!
I definitely agree.
There are five SSL related things available by transport.get_extra_info(): peercert, cipher, compression, ssl_object.
Honestly, I have no idea are they valid and available after the transport closing and SSLObject shutting down.
Would somebody come with a test and investigate?
I can retrieve the certificate on aiohttp 3.8.3 with:
async with aiohttp.ClientSession() as session:
r = await session.get('https://bbc.com')
cert = r.connection.transport.get_extra_info('peercert')
so this looks resolved to me.
I think this should be reopened, as the connection is closed in client_reqrep.ClientResponse._response_eof and the third line may execute after that, which will make the code above fail. After a little testing, the proper solution seems to be to add ClientResponse.certificate and populate it inside _response_eof, if the connection is still valid. Should I prepare a PR for this?
Should I prepare a PR for this?
Sure, we can take a look.