Подписать сертификат в PKCS#11

Чтобы подписать сертификат в OpenSSL, я использую функцию X509_sign(), передавая ей запрос (как X509_REQ*), ключ подписи и дайджест.

Теперь мой ключ подписи хранится в HSM, поэтому я не могу извлечь его, чтобы подписать сертификат. К сожалению, PKCS#11 не предоставляет эквивалент X509_sign(). Все, что у него есть, это C_Sign() / C_SignUpdate() / C_SignFinal() семейства функций, которые работают с необработанными данными, а не с сертификатами.

Может ли кто-нибудь помочь мне с образцом кода C/C++, как использовать PKCS#11 для подписи сертификата, созданного с помощью OpenSSL?


person Vitaly P    schedule 24.02.2015    source источник


Ответы (2)


Приведенный ниже код подписывает данную структуру X509* в HSM. Обработка ошибок опущена для ясности.

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");
    }
}
person Andrei Korostelev    schedule 27.02.2015
comment
Отличный ответ, Андрей! Точно по делу и делает то, что должен делать. - person Vitaly P; 27.02.2015

Другой способ подписать сертификат с помощью HSM — использовать функцию X509_sign(), но реализовать собственный обратный вызов для подписи.

Пример можно найти в https://github.com/OpenSC/libp11/blob/master/src/p11_pkey.c

pkcs11_pkey_method_rsa() - как добавить свой обратный вызов

pkcs11_try_pkey_rsa_sign(...) - как реализовать подписывание (RSA)

person 0xA0    schedule 20.04.2021