Sign CSR from client using CA root certificate in python
Asked Answered
M

2

15

I am new to python and still learning it so my question can be little naive. Please bear with it ;)

The problem is client will be sending CSR and I want to sign it with my CA root certificate and return the signed certificate back to client.

I have been using this command to do it using command line

openssl x509 -req -in device.csr -CA root.pem -CAkey root.key -CAcreateserial -out device.crt -days 500

same thing I want achieve using python. I have come across python library for openssl pyopenssl

is it possible using this library ? How ? or shoudl I go for M2Crypto ?

Meticulous answered 16/4, 2014 at 8:25 Comment(0)
U
20

You can indeed go with pyOpenSSL. As you are saying you already have CA root certificate and a private key, and CSR will be sent by a client then you can use functions of crypto to read all those ( CA cert, private key and Device CSR ) from file or manage to have them in buffer.

Use below functions to start with. Check dir(crypto) and crypto.function_name.__doc__on python interpreter for more info :) You need to import crypto from pyOpenSSL

  1. crypto.load_certificate_request() - to get device CSR obj
  2. crypto.load_privatekey() - to get private key obj for CA private key
  3. crypto.load_certificate() - to get CA root certificate

then you can write simple funcation to return certificate

def create_cert():
    cert = crypto.X509()
    cert.set_serial_number(serial_no)
    cert.gmtime_adj_notBefore(notBeforeVal)
    cert.gmtime_adj_notAfter(notAfterVal)
    cert.set_issuer(caCert.get_subject())
    cert.set_subject(deviceCsr.get_subject())
    cert.set_pubkey(deviceCsr.get_pubkey())
    cert.sign(CAprivatekey, digest)
    return cert

where caCert , deviceCsr and CAprivatekey are values from above three funcations. Now that you have certificate with you, you can write this to a file using crypto.dump_certificate(crypto.FILETYPE_PEM, cert) with file name of your choice.

You can modify this function as per your requirement. After this you can verify generated device certificate with CA root certificate with openssl command e.g. openssl verify -CApath <CA cert path> <name of device cert file>

You can also go through few examples from github. M2Crypto Example , pyOpenSSL example

Hope this gives you idea about the implementation

Untrimmed answered 16/4, 2014 at 19:37 Comment(0)
P
12

The maintainer of pyOpenSSL recommends to use cryptography module for X509 manipulation (see note on top of the documentation page: https://www.pyopenssl.org/en/stable/api/crypto.html).

Here is the code to create a certificate from a CSR signed by a CA:

def sign_certificate_request(csr_cert, ca_cert, private_ca_key):
    cert = x509.CertificateBuilder().subject_name(
        csr_cert.subject
    ).issuer_name(
        ca_cert.subject
    ).public_key(
        csr_cert.public_key()
    ).serial_number(
        x509.random_serial_number()
    ).not_valid_before(
        datetime.utcnow()
    ).not_valid_after(
        # Our certificate will be valid for 10 days
        datetime.utcnow() + timedelta(days=10)
    # Sign our certificate with our private key
    ).sign(private_ca_key, hashes.SHA256())

    # return DER certificate
    return cert.public_bytes(serialization.Encoding.DER)
  • csr_cert is the cryptography CSR certificate object - can be loaded from a file with x509.load_der_x509_csr()
  • ca_cert is the cryptography certificate object - can be loaded from a file with x509.load_pem_x509_certificate()
  • private_ca_key is the cryptography private key object - can be loaded from a file with serialization.load_pem_private_key()
Pegram answered 13/1, 2021 at 22:17 Comment(2)
It looks to me like the argument to issuer_name() should be ca_cert.subject, not ca_cert.issuer?Phaeton
@ErikForsberg You are right. Feel free to update my post as you found the issue :-)Pegram

© 2022 - 2024 — McMap. All rights reserved.