Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sign certificate in PKCS#11

To sign certificate in OpenSSL I use X509_sign() function by feeding it with a request (as X509_REQ*), a signing key and a digest.

Now I have my signing key stored in HSM, so I can't extract it to sign the certificate. Unfortunately PKCS#11 does not provide an equivalent to X509_sign(). All it has is C_Sign() / C_SignUpdate() / C_SignFinal() family of functions which operate on raw data, not on certificates.

Can someone help me with sample C/C++ code how to use PKCS#11 to sign a certificate created with OpenSSL?

like image 861
Vitaly P Avatar asked Feb 24 '15 09:02

Vitaly P


People also ask

What is a PKCS certificate?

PKCS#12 (also known as PKCS12 or PFX) is a binary format for storing a certificate chain and private key in a single, encryptable file. PKCS#12 files are commonly used to import and export certificates and private keys on Windows and macOS computers, and usually have the filename extensions .

How is a certificate signed?

The certificate is signed by the Issuing Certificate authority, and this it what guarantees the keys. Now when someone wants your public keys, you send them the certificate, they verify the signature on the certificate, and if it verifies, then they can trust your keys.


2 Answers

The code below signs the given X509* structure within HSM. Error handling is omitted for the sake of clarity.

void signCertInHsm(X509* x509, unsigned long pkcs11SigningAlgo, CK_FUNCTION_LIST_PTR p11, CK_SESSION_HANDLE p11session, CK_OBJECT_HANDLE pkcs11PrivKeyHandle)
{
    x509->cert_info->enc.modified = 1;

    // set signature algorithm in the certificate
    if (x509->cert_info->signature)
    {
        const int signingAlgoNid = pkcs11SignatureAlgorithmToNid(pkcs11SigningAlgo);
        X509_ALGOR_set0(x509->cert_info->signature, OBJ_nid2obj(signingAlgoNid), V_ASN1_NULL, NULL);
    }
    if (x509->sig_alg)
    {
        const int signingAlgoNid = pkcs11SignatureAlgorithmToNid(pkcs11SigningAlgo);
        X509_ALGOR_set0(x509->sig_alg, OBJ_nid2obj(signingAlgoNid), V_ASN1_NULL, NULL);
    }

    // DER-encode certificate
    unsigned char *certDerBuf = NULL;
    const size_t certDerLen = ASN1_item_i2d((ASN1_VALUE*)x509->cert_info, &certDerBuf, ASN1_ITEM_rptr(X509_CINF));

    CK_MECHANISM mechanism = { pkcs11SigningAlgo, NULL_PTR, 0 };
    p11->C_SignInit(p11session, &mechanism, pkcs11PrivKeyHandle);

    // determine signature size
    CK_ULONG signatureSize = 0;
    p11->C_Sign(p11session, certDerBuf, certDerLen, NULL, &signatureSize);

    // sign
    if (x509->signature->data)
        OPENSSL_free(x509->signature->data);
    x509->signature->data = (unsigned char*)OPENSSL_malloc(signatureSize);
    x509->signature->length = signatureSize;
    p11->C_Sign(p11session, certDerBuf, certDerLen, x509->signature->data, &signatureSize);

    x509->signature->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07);
    x509->signature->flags|=ASN1_STRING_FLAG_BITS_LEFT;

    OPENSSL_free(certDerBuf);
}

int pkcs11SignatureAlgorithmToNid(unsigned long algo)
{
    switch(algo)
    {
    case CKM_SHA1_RSA_PKCS: return NID_sha1WithRSAEncryption;
    case CKM_SHA256_RSA_PKCS: return NID_sha256WithRSAEncryption;
    //... add more mappings that your app supports
    default: throw std::invalid_argument("Not supported signature algorithm");
    }
}
like image 91
Andrei Korostelev Avatar answered Oct 06 '22 12:10

Andrei Korostelev


The another way to sign a certificate by HSM is by using the X509_sign() function, but implementing your own signing callback.

An example can be found in https://github.com/OpenSC/libp11/blob/master/src/p11_pkey.c

pkcs11_pkey_method_rsa() - is how to add your own callback

pkcs11_try_pkey_rsa_sign(...) - is how to implement the signing (RSA)

like image 29
0xA0 Avatar answered Oct 06 '22 12:10

0xA0