X509 certificates - maintaining certification path - python

I'm working on X509 storage system for some python based program. All certificates are kept in PostgresSQL database for easy access. All working ok, when for each subject(user or CA authority) there is only one certificate. Then finding validation path is easy, as issuer field uniquely identify next certificate:
UserCert1(CA_cert_class1) -> CA_cert_class1(CA_cert_root) -> CA_cert_root(CA_cert_root)
The problems starts when some certificates are renewed due to expiration or any other reason.
Then two or more certificates have the same subject. In that case there is more than one possible certification paths.
UserCert1(CA_cert_class1) -> CA_cert_class1(CA_cert_root)(old)->....
-> CA_cert_class1(CA_cert_root)(new)->....
Trying each combination is not a solution. Also removing expired certificates is not a solution, as I need them to validate old digital signatures.
QUESTION: How to uniquely identify issuer cert within X509 certificate. I guess, this have something to do with X509v3 extensions. I'm not sure how to use them.

There is an X509v3 extension for this. It's the AKI (Authority Key Identifier). This number in the child certificate should match the SKI (Subject Key Identifier) in the parent certificate.
See RFC5280 for more details. The SKI can be derived by a hash of the Public Key, or anything that generates a unique number.

Certificate Issuer and Serial Number uniquely identifies a X.509 certificate (for all conforming certificate). Even if the certificate is renewed, its serial number should be different.
X509v3 extension such as subject unique identifier is not guaranteed to exist in the certificate.
Please try the combination of Issuer and Serial Number.

Related

urrlib Error - SSL: CERTIFICATE_VERIFY_FAILED - in CONDA environment [duplicate]

I'm trying the use urllib.request.urlopen on a website starting with "https". Error output is:
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed
There are many great threads which cover this error. Including this one which mentions SSL Labs rating. I am able to use urllib.request.urlopen on every other "https" site I have tested.
SSL Labs shows the following output:
Key RSA 2048 bits (e 65537)
Issuer Let's Encrypt Authority X3
AIA: http://cert.int-x3.letsencrypt.org/
Signature algorithm SHA256withRSA
Extended Validation No
Certificate Transparency No
OCSP Must Staple No
Revocation information OCSP
Revocation status Good (not revoked)
DNS CAA No (more info)
Trusted Yes
To clarify, my question is: is there a solution for completing the handshake, that doesn't include bypassing the certificate verification? And if there is a solution, can it be solved entirely inside a python script on linux, macOS and Windows?
I cannot answer this question for urllib, but I was able to overcome this problem using python requests instead. Note this will only work if there is a trusted certificate chain for the website in question but the server is perhaps missing a root or intermediate certificate.
Using SSL labs server test (linked here), run the test and scroll down to certification paths. IF it IS the case that there are trusted cert paths, but the server is for some reason not providing the complete chain, you can download the full trusted path here as text. Copy the full certificate chain and save it as a .pem file and pass the path of this file to the requests function:
r = requests.get(url, verify = "path/to/chain.pem")
The requests module can throw all sorts of SSL related certification failures, many of which will be server side problems, and you really want to avoid disabling the SSL verification. This solution is only for the somewhat rare case where a full certificate exists but the issuer or server in question has sloppily omitted either a root or intermediate cert.
You can work around this by adding your missing intermediate certificate to the active X509Store:
cert_text = '''
-----BEGIN CERTIFICATE-----
...put your actual certificate text here...
-----END CERTIFICATE-----
'''
# fill this out depending on which specific intermediate cert you're missing
missing_cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert_text)
context = ssl.create_default_context() # load default trusted certificates
store = context.get_cert_store() # get the X509Store for that context
store.add_cert(missing_cert) # add your missing cert to it
urllib.request.urlopen(site, context=context)
Note that if you only need to talk to the one server for which you're doing this, you could just pass an appropriate cafile or capath argument to create_default_context().
I was able to solve this issue (for debian-based system, I'm running Debian 9). I still need to test solutions on macOS and Windows.
On the SSL Labs report, under the "Certification Paths" header, it showed:
1 Sent by server www.exampleSITE.com
BLAH BLAH BLAH
2 Extra download Let's Encrypt Authority X3
BLAH BLAH BLAH
3 In trust store DST Root CA X3 Self-signed
BLAH BLAH BLAH
I navigated to /etc/ssl/certs/ and noticed there was no Let's Encrypt certificates present. I then downloaded the .pem and rehashed.
cd /etc/ssl/certs
sudo wget https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem
sudo c_rehash
Then I tested the python line that was giving me an error earlier
page = urllib.request.urlopen('https://www.exampleSITE.com').read()
and it successfully retrieved the page.

Does PyOpenSSL verify_certificate() do signature verification

I use PyOpenSSL verify_certificate() to verify certificate chains. My code seems to work. But I was wondering if the function also checks the signatures along the certificate chain. Lets assume we have the chain ca_cert -> i_ca_cert -> s_cert. Thus ca_cert signed i_ca_cert and i_ca_cert signed s_cert. Does verify_certificate() check whether the signer's (RSA) key was used to sign the certificate and whether the signature is correct, for every certificate along the chain?
But I was wondering if the function also checks the signatures along the certificate chain
Of course it does. Otherwise what is the purpose of chain verification? From the OpenSSL documentation (man 1ssl verify on linux):
The final operation is to check the validity of the certificate chain. The validity period is checked against the current system time and the notBefore and notAfter dates in the certificate. The certificate signatures are also checked at this point.

Manually verify certificates in Python3 ssl

I am developing the client- and server-side of a Python3 application. They must communicate over TLS using self-signed certs.
The connection should always be established, even if both have never seen the other, thus neither has the other's cert in its trust store. Verification shall happen after the handshake with a custom method.
However, Python's ssl library attempts to verify the certificate during handshake and this fails if the incoming cert is unknown and has no valid certificate chain. Setting verify_mode to CERT_NONE is also not an option, since I do require the certificates from both sides for my custom verification method.
So my question: How can I require a certificate from the other side but turn off automatic verification during handshake? Or maybe I can pass a custom verifyer-method that gets called?
Thanks!
You can use ssl.get_server_certificate((host,port)). It will return the certificate in PEM format.

python m2crypt and load_key, but i have only a .cert files

I have a problem.I'm testing some tips about Apple passbook with python. I'm using M2Crypto to obtain the signature.
The code is:
def passwordCallback(*args, **kwds):
return password
smime = SMIME.SMIME()
smime.load_key(key, certificate, callback=passwordCallback)
pk7 = smime.sign(SMIME.BIO.MemoryBuffer(manifest), flags=SMIME.PKCS7_DETACHED | SMIME.PKCS7_BINARY)
pem = SMIME.BIO.MemoryBuffer()
pk7.write(pem)
der = ''.join(l.strip() for l in pem.read().split('-----')[2].splitlines()).decode('base64')
The code is supposed to work well and generate the signature content, the problem is with the "key" and the "certificate".
This two variable are the name of certificate.pem and key.pem, but I have donwloaded only the pass.cert file from the Apple Developer portal.
How is possible to obtain this two files, with openssl or something similar?
SOLVED:
I have solved with this link
http://www.raywenderlich.com/3443/apple-push-notification-services-tutorial-part-12
You need to either obtain a certificate from a third-party certification authority (CA) or create a self-signed certificate using something like the process described in openSSL. If you are just testing some code a self-signed cert will work, but a CA-issued cert provides other users some indication that you are who you the cert says you are. You could create a self-signed cert claiming to be Tim_Cook#apple.com, but no reputable CA would issue you such a cert.

How do I use m2crypto to validate a X509 certificate chain in a non-SSL setting

I'm trying to figure out how to, using m2crypto, validate the chain of trust from a public key version of a X509 certificate back to one of a set of known root CA's when the chain may be arbitrarily long. The SSL.Context module looks promising except that I'm not doing this in the context of a SSL connection and I can't see how the information passed to load_verify_locations is used.
Essentially, I'm looking for the interface that's equivalent to:
openssl verify pub_key_x509_cert
Is there something like that in m2crypto?
Thanks.
I have modified a different M2Crypto patch and with this we are able to verify a X509 Certificate against a chain of CAs, plus it allows the usage of Certificate Revocation List (CRL)s.
The heart of allowing chain verification with M2Crypto is exposing "verify_cert()" on a X509_Store_Context.
Basic flow is:
Add your CAs/CRLs to a X509_Store
Use a X509_Store_Context to verify the certificate of interest
My patch enhances CRL support as well as allowing chain verification.
https://bugzilla.osafoundation.org/show_bug.cgi?id=12954#c2
We are using this patch as part of Pulp, we have a wiki page below which shares some more info on how we are doing the verification with a chain:
https://fedorahosted.org/pulp/wiki/CertChainVerification
There is a patch that might need to be updated slightly, and it would need unit tests for me to check it in. Contributions welcome!
Another convoluted way would be to create an in-memory SSL session where you do the validation. The Twisted wrapper effectively works this way; Twisted acts as dumb network pipe without knowing anything about the data, and M2Crypto encrypts/decrypts the data in memory, doing certificate validation on the side.

Categories

Resources