The python programming language can be used to create a self signed certificate. Self Signed Certificates can be used for internal systems that do not need automatic public trust from a well known CA (Certification Authority). The downside to using self signed certificates is that they must be explicitly trusted, but sometimes this is preferred for increased security. Below we will demonstrate an example of using the python requests module to trust the full certificate chain, or in this case, the one certificate in the chain being self signed. As a prerequisite to this article, read our instructions on generating a CSR in python to create the public/private key pair to be used in this example.
How to create a self signed certificate in Python
If you do not need a publicly trusted SSL certificate you can use self signed certificates for internal SSL encryption. Mind you will have to explicitly trust the self signed certificate, it can greatly simplify your SSL implementation on internal servers if you can just generate certificates on the fly without having to interact with an external CA.
First, you will generate a private key. For this example we will be using RSA having a key size of 2048, the lowest recommended bit size.
from cryptography.hazmat.primitives.asymmetric import rsa
key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
)
Next, generate the self signed certificate. The certificate will contain data about who you are and who your organization is. Note that the subject and issuer will always be the same for a self signed certificate. This is also trust of any pubic or private Root CA certificate, because a root certificate is also self signed.
After writing the python code to create the certificate, it must then be signed by the private key generated in the previous step.
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes
subject = issuer = x509.Name([
x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"),
x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"Virginia"),
x509.NameAttribute(NameOID.LOCALITY_NAME, u"Richmond"),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"My Organization"),
x509.NameAttribute(NameOID.COMMON_NAME, u"example.com"),
])
cert = x509.CertificateBuilder().subject_name(
subject
).issuer_name(
issuer
).public_key(
key.public_key()
).serial_number(
x509.random_serial_number()
).not_valid_before(
datetime.datetime.utcnow()
).not_valid_after(
datetime.datetime.utcnow() + datetime.timedelta(days=365)
).add_extension(
x509.SubjectAlternativeName([x509.DNSName(u"localhost")]),
critical=False,
).sign(key, hashes.SHA256())
You now have a self signed certificate that was generated by the python programming language.
Trust a self signed certificate in Python requests
If the OS (Operating System), or application you are running your python requests code from does not trust the certificates protecting the server you are connecting to, you will receive the following error or one similar:
requests.exceptions.SSLError: [Errno 1] _ssl.c:507: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
In the event you see this error, you will need to explicitly trust the certificates being returned by the external system if indeed they are to be trusted. To do this, use the verify
parameter in your requests code to trust the certificate.
requests.post(url, data=data, verify='/path/to/certificate.pem')
Note that if the certificate you are trusting is a self signed certificate, the above command will work as is. If the certificate is a Root CA certificate with intermediates also in the chain of trust, make sure to include the intermediate certificates in the .pem file you are pointing to.
Determine public or private key type in Python
The examples above used the RSA algorithm when generating the key pair. To verify this the key type or to check an unknown key type in python, you can use the isinstance
method passing in the key and the algorithm. See below for an example on how to determine the key type of a public key or a private key in python.
public_key = cert.public_key()
if isinstance(public_key, rsa.RSAPublicKey):
# This is an RSA key
elif isinstance(public_key, ec.EllipticCurvePublicKey):
# This is an EC key
else:
# It's neither an RSA or EC key.
Note that in the above example the public key algorithm is being checked. If you want to know the private key algorithm, you must first get the public key to be passed into the isinstance
checks.
Conclusion
This article demonstrated how to programmatically create a self signed certificate using python. In addition, it demonstrated how to trust a self signed certificate in the python requests library. Leave us a comment if you have any questions or would like to see additional examples of using or trusting self signed certificates in python.
Leave a Reply