Currently my client side HTTPS request code looks like this:
resp = requests.post(endpoint_predict_v100, files={'image': open(file_path, 'rb')}, verify=client_auth,
cert=(client_cert_path, client_secret_path))
This is an HTTPS request, the server root CA is client_auth and the client certificate and key are client_cert_path and client_secret_path.
because my server code is deployed and I cannot change much on that side, I am wondering if I can do the following on the client side:
enable server authentication only when the server root CA is provided by the client
enable client authentication only when the client cert and key are provided by the client.
I have found out that I am able to do the first thing, "enable server authentication only when the server root CA is provided by the client", by passing verify=False if the server root CA is not presented on the client side., referring to the Python requests docs. However, when I try to remove the cert=(client_cert_path, client_secret_path), the request will fail, throwing this error:
ssl.SSLError: [SSL] tlsv13 alert certificate required (_ssl.c:2570)
It seems that this error is suggesting I must pass in the client cert and key to make the server accept my request. but is there a way to disable client authentication on the client side, when the client cert and key are not present?
ssl.SSLError: [SSL] tlsv13 alert certificate required (_ssl.c:2570)
... is there a way to disable client authentication on the client side, when the client cert and key are not present?
The alert you get is because the server is requiring the client certificate. Since it is required by the server it is not sufficient to change some client side behavior only. This is similar to a server requesting authentication by password - this cannot be simply skipped in the client too.
With many servers there is a way to have client certificates optional, i.e. request a client certificate but don't insist that one is sent. How to do this with your specific server and if it is supported by your server at all is unknown though.
Related
I need your help.
I want to generate a certificate for a client for authorization on my api.
In my use case, I have an API that is hosted with python hypercorn and fastapi. Then I have multiple clients (also python (httpx)) that should request data from this api. For authentication between the client and the server, I want to use certificates. I want to provide the client with a certificate with which it can authorize itself with the server.
For generating the certificates i used this instruction: https://www.makethenmakeinstall.com/2014/05/ssl-client-authentication-step-by-step/
What did I do wrong, or how can I implement my use case?
server:
async def main():
config = Config.from_mapping(dict(
worker_class='trio',
certfile='server.cer',
keyfile='server.key',
verify_mode=VerifyMode.CERT_REQUIRED,
bind=f"0.0.0.0:{8000}"))
async with trio.open_nursery() as nursery:
nursery.start_soon(serve, app, config)
client:
import httpx
res = httpx.get("https://localhost:8000/", verify=True, cert=("client.cer", "client.key"))
res
When I execute the request in the client I get the following error:
ConnectError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate (_ssl.c:1123)
let's simplify how certificates work.
certificates used for authentication and authorization and this is what you're exactly doing in your case. your backend-server has its own certificate, and your client has his own certificate. your applications is set to recognize each other using these certificates and you're doing it in a great way.
but certificates are vulnerable and can be created locally, so I myself can create a certificate that says that I'm facebook or google. and here is the validation's role come; a well know authority that's already implemented in all browsers and OS - and we call it CA for a certification authority - signs your certificates, so when your server send its cert to a client, the client's browser would recognize the signature and tells you that the certificate is valid.
in your case here you have a self signed certificate, which means that for development purpose you've signed your cert by yourself "instead of the recognized CAs".
Overcoming such an issue would be in two ways.
you disable the validation in your code and in your client side as well. suits for development purpose or intra network.
sign your certificate and your client's certificate with a recognized authority like digicert, and add your CA in your trust-store.
I know in python-requests you can send your certificate via verify parameter.
Something like this:
url = requests.get('someurl', verify='certifacate.pem')
So I understand TLS handshake protocol does follow:
The 'client hello' message
The client initiates the handshake by sending a "hello" message to the server. The message will include which TLS version the client supports, the cipher suites supported, and a string of random bytes known as the "client random.
Then we have the server hello message that lets client know what cipher suite to use.
The 'server hello' message: In reply to the client hello message, the server sends a message containing the server's SSL certificate, the server's chosen cipher suite, and the "server random," another random string of bytes that's generated by the server.
In my code using wireshark I've identified that server requests TLS_AES_256_GCM_SHA384
server hello screenshot
I am confused, what are we sending in .certificate.pem file
From my understanding premaster secret it when the client sends one more random string of bytes, the "premaster secret." The premaster secret is encrypted with the public key and can only be decrypted with the private key by the server. (The client gets the public key from the server's SSL certificate.)
and as for session keys it is when both client and server generate session keys from the client random, the server random, and the premaster secret. They should arrive at the same results.
is it the premaster secret, or is it the session keys that we are sending as certificate.pem in verify parameter with request?
Do we generate these by using crypto algorithm since server is requesting TLS_AES_256_GCM_SHA384 - we could replicate the output using the same algorithm using crypto library and pass it into requests? Is this the purpose of verify parameter?
The site I am currently trying to reach has SSL Certificates etc and it only accepts certain client certificate. I am trying to understand if verify is the correct parameter I should be using.
No, the "verify" argument has nothing to do with client-side certificates. It's your root certificate which can be used to verify the authenticity of the server-side certificate. If you don't want to verify it, you can use on your own risk verify=False .
For client-side certificates, you need to use the "cert" argument: https://requests.readthedocs.io/en/master/user/advanced/#client-side-certificates . Example:
requests.get('https://example.org', cert=('/path/client.cert', '/path/client.key'))
I'm trying to implement mutual authentication on a ftps connection using ftplib module.
Here is my code:
Context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
Context.load_verify_locations(cafile=trusted.txt,capath=path)
Context.load_cert_chain(certfile=mycert.txt,keyfile=mikey.txt,password=xxxx)
Context.verify_mode=True
Ftp = ftplib.FTP_TLS(Context=Context)
Ftp.connect(host, port)
Ftp.auth()
Ftp.prot_p()
Ftp.set_pasv(True)
Ftp.cwd(dest_dir)
Ftp.storlines(xx,xx)
Ftp.close()
However above works fine only with client authentication set as no on ftps server side. When we try with client Auth yes
Error code is as below.
Ssl.SSLError: [SSL:SSLV3_ALERT_CERTIFICATE_UNKNOWN] sslv3 alert certificate unknown (_ssl.c:777)
I have the servers cert chain on ca file defined.
I have my trusted on servers side defined.
Still connection doesn't work well. And it works well if client Auth is disabled on server side.
Any suggestions on what could be wrong. Could it be ciphers?
I tried setting up ciphers but don't know how exchange happens in realtime. Or could this be that ftplib does not support fully mutually authentication at all??
Ssl.SSLError: [SSL:SSLV3_ALERT_CERTIFICATE_UNKNOWN] sslv3 alert certificate unknown (_ssl.c:777)
If you get this error in the client then the server failed to validate the client certificate, i.e. your mycert.txt and mikey.txt.
Since validation of the client certificate is done by the server you have to look at the server configuration and logs for more information of why your client certificate was not accepted. Typical problems are that the client certificate is a self-signed certificate, that the CA which issued the client certificate is not trusted in the server or that intermediate certificates are required to verify the certificate but the client is not sending these.
I am trying to connect to the Visa Direct API, but i am not passing the basic SSL certificate authetification, here is my code:
import requests
headers = { 'Content-Type' : 'Application/json' }
url = 'https://sandbox.visa.com/rsrv_vpp/v1/acnl'
payload = {"SystemsTraceAuditNumber":565690,
"RetrievalReferenceNumber":"505012455690",
"AcquiringBin":409999,
"AcquirerCountryCode":"840",
"PrimaryAccountNumber":"4895070000008881"}
r = requests.post(url, data=json.dumps(payload),
cert =('/etc/ssl/certs/sandbox_cert.pem'), headers=headers,
auth=('370df57a-a8aa-4446-a23e-44a0ef06ea09',
'6023e518-c36c-47a8-b16e-c8a5b3a941ef'))
Ass you can see i am using request and passing the cert argument along with the API user and password info but i keep getting the error:
requests.exceptions.SSLError: [Errno 1] _ssl.c:510: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
I get a SSL error when I try to open https://sandbox.visa.com/rsrv_vpp/v1/acnl in Google Chrome.
The Visa Docs say
SSL Server Authentication
The SSL server certificate installed on sandbox.visa.com servers is a
Visa issued self-signed certificate. Client applications need to add
the sandbox.visa.com SSL certificate to their local trust store to
prevent SSL Handshake errors at runtime.
Ensure that your application that connects to the Visa Direct API is
configured (or built) to use the trusted certificate store as a trust
store, and not a key store.
Verify that the application is configured to use the right password
associated with the trust store file.
It looks like you need to do do some SSL Authentication before you can connect to Visa.
I have a twisted webserver with TLS authentication, and it appears to hang when I connect to it over SMTP. Here is the block of twisted code to start the server:
(Note: certificateData is our private key and public key concatenated together, that appeared to be the only way to get a self signed certificate to work)
customFactory = CustomSMTPFactory(portal)
certificate = PrivateCertificate.loadPEM(certificateData)
contextFactory = certificate.options(certificate)
tlsFactory = TLSMemoryBIOFactory(contextFactory, False, customFactory)
a = service.Application("Custom Server")
internet.TCPServer(5870, tlsFactory).setServiceParent(a)
On the client, this line just hangs waiting to read data:
smtplib.SMTP('localhost',5870)
Any ideas? How do I setup TLS authentication on a twisted webserver?
Your server starts TLS from the beginning of the connection. Try smtplib.SMTP_SSL instead, so your client expects this.