5

I am trying to sign a public/private key pair by a temporary Root CA, steps followed are next:

  1. Create a self-signed root authority certificate (CertCreateSelfSignCertificate) (Done)
  2. Generate public/private key pair (CryptGenKey) (Done)
  3. Sign public/private key pair by root authority certificate (TODO) (I have been trying using CertCreateSelfSignCertificate function, nevertheless it seems that it is not possible...)

I have been following the steps mentioned in next link: link

With powershell works fine, but I don't know how to implement it with Microsoft CryptoApi C++. Example Powershell:

$testCert = New-SelfSignedCertificate -CertStoreLocation Cert:\LocalMachine\My -DnsName "SignedByRootCA" -KeyExportPolicy Exportable -KeyLength 2048 -KeyUsage DigitalSignature,KeyEncipherment -Signer $rootCert

Currently, I obtain a certificate without private key, so how can I assign a private key to my signed certificate? My current code is showed below:

// Open the CA cert to get the issuer information and a handle to sign the cert
PCCERT_CONTEXT caCert = NULL;
CertificateStore certStore{};
certStore.Open(certStore.ROOT);
certStore.FindCertContext(tmpThumbprint, caCert);
NCRYPT_KEY_HANDLE caKey = NULL;
DWORD caKeySpec = 0;
BOOL fCallerFreeProvOrNCryptKey = FALSE;
CryptAcquireCertificatePrivateKey(caCert, CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG, NULL, &caKey, &caKeySpec, &fCallerFreeProvOrNCryptKey);

// A structure which contains the information of a certificate
CERT_INFO certificateInfo;
memset(&certificateInfo, 0, sizeof(CERT_INFO));
certificateInfo.dwVersion = CERT_V3;
certificateInfo.SignatureAlgorithm = signatureAlgorithm;
certificateInfo.NotBefore = notBefore;
certificateInfo.NotAfter = notAfter;
certificateInfo.Issuer = caCert->pCertInfo->Subject;
certificateInfo.Subject = static_cast<CERT_NAME_BLOB>(*subject);
certificateInfo.cExtension = 1;
certificateInfo.rgExtension = certExt;
BYTE serialNumber[16];
CryptGenRandom(caKey, 16, serialNumber);
certificateInfo.SerialNumber.pbData = serialNumber;
certificateInfo.SerialNumber.cbData = 16;

// Exports the public key information associated with the corresponding private key of the provider.
bool result = false;
PCERT_PUBLIC_KEY_INFO pkInfo = NULL;
CryptExportPublicKeyInfo(csp.Get(), AT_KEYEXCHANGE, X509_ASN_ENCODING, NULL, &cbEncode);
pkInfo = (PCERT_PUBLIC_KEY_INFO)malloc(cbEncode);
CryptExportPublicKeyInfo(csp.Get(), AT_KEYEXCHANGE, X509_ASN_ENCODING, pkInfo, &cbEncode);
certificateInfo.SubjectPublicKeyInfo = *pkInfo;

// Encode and sign Certificate and decode
result = CryptSignAndEncodeCertificate(caKey, caKeySpec, X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, &certificateInfo, &signatureAlgorithm, NULL, nullptr, &cbEncode);
pbEncode = (BYTE*)malloc(cbEncode);
result = CryptSignAndEncodeCertificate(caKey, caKeySpec, X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, &certificateInfo, &signatureAlgorithm, NULL, pbEncode, &cbEncode);
PCCERT_CONTEXT certContext = CertCreateCertificateContext(X509_ASN_ENCODING, pbEncode, cbEncode);
result = CryptAcquireCertificatePrivateKey(certContext, CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG, NULL, &caKey, &caKeySpec, &fCallerFreeProvOrNCryptKey); //FAILS!!! Error NTE_BAD_PUBLIC_KEY
DWORD e = GetLastError();

Are there any way to do it?

Alberto Bricio
  • 402
  • 1
  • 6
  • 22
  • 2
    You have to use CertEnroll COM interfaces to do that. There are no other built-in APIs to generate CA-signed certificates. – Crypt32 Jan 14 '20 at 18:43
  • @Crypt32 Please, could you give any example with C++ and CertEnroll COM interfaces? – Alberto Bricio Jan 15 '20 at 08:08
  • 1
    I don't have examples in C++. But I have examples in PowerShell you can translate to C++: https://learn.microsoft.com/archive/blogs/vishalagarwal/generating-a-certificate-self-signed-using-powershell-and-certenroll-interfaces. CertEnroll interfaces: https://learn.microsoft.com/en-us/windows/win32/seccertenroll/certenroll-interfaces – Crypt32 Jan 15 '20 at 08:18
  • 1
    call `CertSetCertificateContextProperty` with `CERT_KEY_PROV_INFO_PROP_ID` – RbMm Jan 29 '20 at 00:06
  • @RbMm That's it! thanks :) – Alberto Bricio Jan 29 '20 at 08:59

0 Answers0