How to sign an OCSP request using a CloudHSM private key in Python

71 Views Asked by At

I am trying to sign my OCSP builder to create a valid OCSP response for client use. However I'm receiving this error when I try to sign my response builder: 'ERROR': "PKCS#11 Error: Unknown format (<class 'cryptography.x509.ocsp.OCSPResponseBuilder'>

I am using PyKCS11 to read my private key from my AWS CloudHSM, and using Python Cryptography's OCSP library to build my request.

def get(pem_certificate, pem_issuer, pem_responder_cert, logger):
    builder = create_response_GOOD(pem_certificate, pem_issuer, pem_responder_cert, logger)
    response = request_signature(builder, logger)

def create_response_GOOD(cert, issuerCert, responderCert, logger):
    logger.log(f"Generating good response...")
    builder = ocsp.OCSPResponseBuilder()
    builder = builder.add_response(
        cert=cert, issuer=issuerCert, algorithm=hashes.SHA256(),
        cert_status=ocsp.OCSPCertStatus.GOOD,
        this_update=datetime.datetime.now(),
        next_update=datetime.datetime.now(),
        revocation_time=None, revocation_reason=None
        ).responder_id(
            ocsp.OCSPResponderEncoding.HASH, responderCert
        )
    logger.log(f"Good response generated...")
    return builder


def request_signature(builder, logger):
    """
    Request the HSM for a signature of the builder.
    """
    hsm_credentials = 'cryptouser:pw12345'

    session = create_hsm_session()
    logger.log(f"Session created: {session}...")

    private_key = login_hsm_get_key(session, hsm_credentials, logger)
    logger.log(f"Private key pulled...")

    signature = sign_builder(session, builder, private_key, logger)
    logger.log(f"Signature generated: {signature}")

    session.logout()
    session.closeSession()

    return signature

def create_hsm_session():
    """
    Creates a HSM session and returns the session.

    :return: The HSM session.
    """

    # Load PKCS#11 LIB.
    pkcs11 = PyKCS11.PyKCS11Lib()
    pkcs11.load('/opt/cloudhsm/lib/libcloudhsm_pkcs11.so')

    try:
        # Get first slot as CloudHSM only has one slot.
        slot = pkcs11.getSlotList()[0]
        # Create Session.
        session = pkcs11.openSession(slot, CKF_RW_SESSION)

        return session

    except PyKCS11.PyKCS11Error:
        return {"ERROR": "PKCS#11 Error when creating session."}

def login_hsm_get_key(session, credentials, logger):
    """"
    Logs in to HSM with credentials returns users private key.

    :param session: The HSM session.
    :param credentials: The credentials to login to the HSM.

    :return: The users private key.
    """

    cert_LABEL = "issuing ca ocsp"

    try:
        # Login to HSM.
        session.login(credentials)

        # Get private key for user.
        private_key = session.findObjects([(CKA_CLASS, CKO_PRIVATE_KEY),(CKA_LABEL, cert_LABEL)])
        
        logger.log("Found %d objects: %s" % (len(private_key), [x.value() for x in private_key]))

        return private_key[0]
    except PyKCS11.PyKCS11Error:
        return {"ERROR": "PKCS#11 Error when logging in and getting private key."}
    
def sign_builder(session, builder, private_key, logger):
    """
    Signs a builder and returns a signed builder.

    :param session: The HSM session.
    :param payload: The payload to sign.
    :param private_key: The private key to use.

    :return: The signature.
    """
    try:
        mechanism = PyKCS11.Mechanism(CKM_SHA256_RSA_PKCS, None)
        signature = session.sign(private_key, builder, mechanism)

        return signature

    except PyKCS11.PyKCS11Error as e:
        logger.log(f"PKCS#11 Error: {e}")
        return {"ERROR": f"PKCS#11 Error: {e}"}

I tried signing the built response using cryptography's .sign method response = builder.sign(private_key, hashes.SHA256())

However this doesn't work because the private key is in the CloudHSM and PyKCS11 allows a method to interact with the key without exporting it. Which is why I'm attempting to use the PyKCS11 session.sign instead of the cryptography ocsp sign method which expects the private key itself.

I've attempted converting the builder object to byte data using:

'OCSPResponseBuilder' object has no attribute 'public_bytes' Please note I'm also using the Client SDK 5 version of the AWS CloudHSM command line tools.

0

There are 0 best solutions below