【发布时间】:2020-11-24 13:00:33
【问题描述】:
我想使用带有 PKCS#11 的智能卡私钥签署证书请求。我的意思是签署 CSR 本身,而不是写证书作为回应。
所以我使用 OpenSSL 来创建 X509 证书请求,并且我想使用 PKCS#11 和 C_Sign 来创建签名。我该怎么做?
这是我目前拥有的,但是当我尝试使用 OpenSSL CLI 从该请求生成证书时,它说签名不匹配,所以我一定做错了什么。我不确定要传递 C_Sign 什么——现在我已经尝试了 i2d_X509_REQ() 的输出——以及如何在创建后将签名设置回 X509_REQ(我尝试构建 ASN1_BIT_STRING 对象)。
注意:这不是this question 的副本,因为这是一个证书,适用于旧版本的 OpenSSL 的 API。虽然,我试图通过手动公开 X509_REQ 结构的内部来使用答案(参见最后一个代码块)。
X509_REQ makeCSR() {
/* Create OpenSSL EVP_PKEY from exported public key components */
RSA* openssl_rsa = RSA_new();
BIGNUM* bn_modulus = BN_bin2bn(modulus.data(), (int) modulus.size(), nullptr);
BIGNUM* bn_public_exponent = BN_bin2bn(public_exponent.data(), (int) public_exponent.size(), nullptr);
int success = RSA_set0_key(openssl_rsa, bn_modulus, bn_public_exponent, nullptr);
EVP_PKEY* evp_pkey = EVP_PKEY_new();
/* Add public key to certificate request */
EVP_PKEY_assign(evp_pkey, EVP_PKEY_RSA, openssl_rsa);
X509_REQ* request = X509_REQ_new();
X509_REQ_set_pubkey(request, evp_pkey);
/* Set certificate request attributes */
// ...
/* Sign certificate request with smart card */
unsigned char* buffer { nullptr };
int size = i2d_X509_REQ(request, &buffer);
std::vector<unsigned char> der_encoded_request(buffer, buffer + size);
std::vector<unsigned char> signature = smartcard->signCertificateRequest(der_encoded_request);
/* Build signature object */
ASN1_BIT_STRING* asn1_signature = ASN1_BIT_STRING_new();
ASN1_BIT_STRING_set(asn1_signature, signature.data(), (int) signature.size());
asn1_signature->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
asn1_signature->flags |= ASN1_STRING_FLAG_BITS_LEFT;
X509_ALGOR* x509_algor = X509_ALGOR_new();
ASN1_OBJECT* a = OBJ_nid2obj(pkcs11SignatureAlgorithmToNid(CKM_SHA1_RSA_PKCS));
X509_ALGOR_set0(x509_algor, a, V_ASN1_NULL, nullptr);
/* Add signature to X509_REQ */
X509_REQ_set1_signature_algo(request, x509_algor);
X509_REQ_set0_signature(request, asn1_signature);
return request;
}
std::vector<unsigned char> signCertificateRequest(std::vector<unsigned char>& certificate_request)
{
CK_MECHANISM mechanism = { CKM_SHA1_RSA_PKCS, nullptr, 0 };
auto result = s_pkcs11->fn->C_SignInit(m_session_handle, &mechanism, private_key_handle);
unsigned long signature_length { 0 };
result = pkcs11->C_Sign(m_session_handle,
certificate_request.data(),
(unsigned long) certificate_request.size(),
nullptr,
&signature_length);
std::vector<unsigned char> signature(signature_length);
result = pkcs11->C_Sign(m_session_handle,
certificate_request.data(),
(unsigned long) certificate_request.size(),
signature.data(),
&signature_length);
return signature;
}
我也尝试过暴露 X509_REQ 的内部并将i2d_X509_REQ_INFO(&request->req_info, &buffer) 的输出传递给 C_Sign;或使用ASN1_item_i2d();并将签名输出直接复制到 request->signature->data.
request->req_info.enc.modified = 1;
X509_ALGOR_set0(&request->sig_alg,
OBJ_nid2obj(pkcs11SignatureAlgorithmToNid(CKM_SHA1_RSA_PKCS)),
V_ASN1_NULL,
nullptr);
unsigned char* certDerBuf = NULL;
const auto certDerLen = ASN1_item_i2d(ASN1_VALUE*) &request->req_info,
&certDerBuf,
ASN1_ITEM_rptr(X509_REQ_INFO));
std::vector<unsigned char> certDerVec(certDerBuf, certDerBuf + certDerLen);
std::vector<unsigned char> signature = smartcard->signCertificateRequest(certDerVec);
request->signature->data = (unsigned char*) OPENSSL_malloc(signature.size());
request->signature->length = (int) signature.size();
request->signature->data = signature.data();
【问题讨论】:
-
智能卡的整个安全点是不能在硬件级别从中获取私钥。所以忘记阅读 PKCS#11。您假设只是将一些数据发送到智能卡,它会给您回签名版本。 OpenSSL 不足以处理这种情况。您需要使用一些系统 API 来访问智能卡并要求它签署一些东西。
-
是的,这就是我使用 PKCS#11 的原因。我想将 CSR 发送到智能卡,以便它可以对其进行签名并将签名返回给我。
标签: c++ openssl signature pkcs#11 csr