1

Working with an HSM I can download the public key of a RSA 4096, and can use the HSM to encrypt a blob using the corresponding private key, which I can't download. I'm trying to find a reference to how I can use the HSM apis, to build the X509 certificate myself. I could find the example below in python, wrapping up openssl libs. It does mostly all, but

from OpenSSL import crypto, SSL
from socket import gethostname
from pprint import pprint
from time import gmtime, mktime

CERT_FILE = "selfsigned.crt"
KEY_FILE = "private.key"

def create_self_signed_cert():

    # create a key pair
    k = crypto.PKey()
    k.generate_key(crypto.TYPE_RSA, 1024)

    # create a self-signed cert
    cert = crypto.X509()
    cert.get_subject().C = "UK"
    cert.get_subject().ST = "London"
    cert.get_subject().L = "London"
    cert.get_subject().O = "Dummy Company Ltd"
    cert.get_subject().OU = "Dummy Company Ltd"
    cert.get_subject().CN = gethostname()
    cert.set_serial_number(1000)
    cert.gmtime_adj_notBefore(0)
    cert.gmtime_adj_notAfter(10*365*24*60*60)
    cert.set_issuer(cert.get_subject())
    cert.set_pubkey(k)
    cert.sign(k, 'sha1')

    open(CERT_FILE, "wt").write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
    open(KEY_FILE, "wt").write(crypto.dump_privatekey(crypto.FILETYPE_PEM, k))

create_self_signed_cert()

Mostly what I would expect to be possible is to replace the line

   cert.sign(k, 'sha1')

by the corresponding calls to the APIs of my HSM with "an export" of the structure of "cert". Is it possible at all ?

user2123288
  • 1,103
  • 1
  • 13
  • 22
  • If it *were* possible, wouldn't that completely defeat the purpose of having certificates? – Scott Hunter Dec 17 '19 at 20:31
  • Not at all. You generate certificates with a private key. Doing encryption in hardware based devices for which you have some sort of credentials, rather than on a file sitting on your computer is actually the way that you want to do it. Normally OpenSSL or other desktops would support engines that talk with the HSM transparently. In my case want to be able to do it programmatically. – user2123288 Dec 18 '19 at 18:40

2 Answers2

1

So after one day of research I found a satisfactory answer at Adding a signature to a certificate . While there seems to be some Python examples out how to build the certificate through Python with pyasn1, the most robust seems to be the ones in java using boucycastle libraries. I also found a strong answer how to incorporate it with openssl here How to generate certificate if private key is in HSM? (mostly points 3 and 4), but the approach is far beyond my capacities.

user2123288
  • 1,103
  • 1
  • 13
  • 22
0

When you want someone else, like your HSM, to sign a certificate for you the standard way to do that is to generate a Certificate Signing Request (CSR) and send the CSR to the signer. The CSR can contain all of the fields that you can set when making a certificate, and those values will be reflected in the resulting certificate.

While you can do this with the OpenSSL library that you are using, see X509Req, their documentation (and I quote) "strongly suggests" that you use the cryptography library instead. (They're maintained by the same group of people.)

In the cryptography library you use the CertificateSigningRequestBuilder to make a CSR. To quote from their docs:

>>> from cryptography import x509
>>> from cryptography.hazmat.primitives import hashes
>>> from cryptography.hazmat.primitives.asymmetric import rsa
>>> from cryptography.x509.oid import AttributeOID, NameOID
>>> private_key = rsa.generate_private_key(
...     public_exponent=65537,
...     key_size=2048,
... )
>>> builder = x509.CertificateSigningRequestBuilder()
>>> builder = builder.subject_name(x509.Name([
...     x509.NameAttribute(NameOID.COMMON_NAME, u'cryptography.io'),
... ]))
>>> builder = builder.add_extension(
...     x509.BasicConstraints(ca=False, path_length=None), critical=True,
... )
>>> builder = builder.add_attribute(
...     AttributeOID.CHALLENGE_PASSWORD, b"changeit"
... )
>>> request = builder.sign(
...     private_key, hashes.SHA256()
... )
>>> isinstance(request, x509.CertificateSigningRequest)
True

To render out the CSR in the format usually used for sending them around:

>>> from cryptography.hazmat.primitives import serialization
>>> request.public_bytes(serialization.Encoding.PEM)
Jason Heiss
  • 671
  • 6
  • 11
  • 1
    Wrong answer. Even from a CSR, a certificate should be built at the CA side and if this CA must use a HSM, the original question remains perfectly valid and standard. – StratocastFlo Mar 09 '22 at 12:39