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?
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 .
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.
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");
}
}
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With