Python TLS/ClientCertificateAuthentication error

snaiyer
snaiyer Member Posts: 6

Hi All,

I am trying to use Python to connect to solace and failing to connect with “unable to get local issuer certificate” error.
I have setup TLS with_certificate_validation and authentication strategy with ClientCertificateAuthentication.of. I have tried various combinations to use with or without TLS, while creating the messaging service. Fails at messaging_service.connect().

Our Java application already successfully talks to solace and is authenticated using trust store and key store file in .jks format, along with other needed properties.
For Python I am trying use the same trust store and key store certs in .jks format (I hope that’s acceptable) but fails with the error above. Not sure if any additional authentication is required but followed API docs and howtos, to pass in all the required parameters.
Any help is appreciated.

Tagged:

Comments

  • marc
    marc Member, Administrator, Moderator, Employee Posts: 959 admin

    Hi @snaiyer,

    Welcome to the community. I don't now off the top of my head but will try to find someone more familiar with our python API. My gut says that the Python API probably doesn't want a JKS (Java Keystore) file but I could be wrong.

  • snaiyer
    snaiyer Member Posts: 6

    Thanks @marc for responding. I will wait to hear, if what you said can be confirmed and if so, what would be the right format to use.
    Appreciate your help.

  • marc
    marc Member, Administrator, Moderator, Employee Posts: 959 admin
    edited September 2021 #4

    Hi @snaiyer,

    I've asked for a docs enhancement to explicitly specify the file types expected, but it looks like you will need to use a X.509 certificate in a .pem file. You should be able to use the keytool command to export the cert from your JKS into a pem file. I think keytool --list will give you your available certs and then you can use something similar to this keytool -exportcert -alias first-key-pair -keystore keystore.jks -rfc -file first-key-pair-cert.pem to create the pem. Note that I took that command from here which explains more.

    Hope that helps and let us know if it works for you!

  • snaiyer
    snaiyer Member Posts: 6

    Hi @marc

    Thanks again for confirming this and sharing the resource to convert the keys. So I did try by converting the keys but still didn’t work, which brings me to another question. I did try to use the intermediate converted .p12 truststore and keystore files with our Java application and they did work successfully. Which just proves conversion went well. The final .pem file which I tried to use in Python code, still doesn’t work.

    Question: if you can help clarify this as well. looking at the code below, now it seems like I need three different files, though I have only two files used in Java today. Refer sample code below:

    We initially setup trust store using trust_store_file_path in transport security. Here we pass trust store file path.

    Then ClientCertificateAuthentication.of expects two files:
    1. certificate_file - file that contains the client certificate.
    2. key_file - file that contains private key

    So is this correct that we need 3 different files as per documentation?

        try:
            transport_security = TLS.create() \
                .with_certificate_validation(True, validate_server_name=False,
                                             trust_store_file_path=SamplerUtil.get_trusted_store_dir())
    
            messaging_service = MessagingService.builder() \
                .from_properties(props) \
                .with_transport_security_strategy(transport_security) \
                .with_authentication_strategy(ClientCertificateAuthentication.of(certificate_file=key_store_url,
                                                                                 key_file=key_file,
                                                                                 key_password=key_store_password)) \
                .build(SamplerUtil.get_new_application_id())
    
  • amackenzie
    amackenzie Member, Employee Posts: 269 Solace Employee

    Hello,
    There are 2 different concepts at play in the code above.
    1. Transport security using TLS certificate. This is regarding the communication between your clients and the broker. This is widely used and is recommended for any broker on a network and the only option when using Solace Cloud broker services.
    2. Client Certificate authentication - this is how your session will be authenticated and has nothing to do with secure transport (except that secure transport is required to use client certificate authentication). It is used as an alternative to basic authentication (username/password), Kerberos, or LDAP (which is configured in the client as basic authentication). In the future we will also be supporting OAuth client authentication.

    So in your above code, there are 3 (at least) files required.

    For transport security, you are providing a path to a dir that has 1 or more certs that can be used to encrypt the data flow between client and server.

    For client certificate authentication, you are supplying the client cert, which is interrogated for the username (which must be registered as a client username in the broker) and a file path to the private key file, used in the TLS handshake, and if necessary, the password (not a file), to decrypt the private key file.

    If you are using client certificate authentication in your organization, great. Hopefully we can get it up and running with your Python apps. However, if you are using client certificate authentication to secure your communications with the broker, that is not its purpose and I would suggest using basic authentication. Client certificates are complex to manage across applications and users.

    I hope this helps.

  • snaiyer
    snaiyer Member Posts: 6

    Hi @amackenzie - thanks for your detailed explanation. That helps in understanding the API even better. I am talking to our internal solace team regarding getting the right certificates per Python API’s requirement. Hopefully that should resolve this.