/* Encodes the string represented by value as the string type type into the * CERT_NAME_BLOB output. If there is an error and ppszError is not NULL, * *ppszError is set to the first failing character. If there is no error, * output's pbData must be freed with LocalFree. */ static BOOL CRYPT_EncodeValueWithType(DWORD dwCertEncodingType, const struct X500TokenW *value, PCERT_NAME_BLOB output, DWORD type, LPCWSTR *ppszError) { CERT_NAME_VALUE nameValue = { type, { 0, NULL } }; BOOL ret = TRUE; if (value->end > value->start) { nameValue.Value.pbData = CryptMemAlloc((value->end - value->start) * sizeof(WCHAR)); if (!nameValue.Value.pbData) { SetLastError(ERROR_OUTOFMEMORY); ret = FALSE; } } if (ret) { if (value->end > value->start) { DWORD i; LPWSTR ptr = (LPWSTR)nameValue.Value.pbData; for (i = 0; i < value->end - value->start; i++) { *ptr++ = value->start[i]; if (value->start[i] == '"') i++; } nameValue.Value.cbData = (LPBYTE)ptr - nameValue.Value.pbData; } ret = CryptEncodeObjectEx(dwCertEncodingType, X509_UNICODE_NAME_VALUE, &nameValue, CRYPT_ENCODE_ALLOC_FLAG, NULL, &output->pbData, &output->cbData); if (!ret && ppszError) { if (type == CERT_RDN_NUMERIC_STRING && GetLastError() == CRYPT_E_INVALID_NUMERIC_STRING) *ppszError = value->start + output->cbData; else if (type == CERT_RDN_PRINTABLE_STRING && GetLastError() == CRYPT_E_INVALID_PRINTABLE_STRING) *ppszError = value->start + output->cbData; else if (type == CERT_RDN_IA5_STRING && GetLastError() == CRYPT_E_INVALID_IA5_STRING) *ppszError = value->start + output->cbData; } CryptMemFree(nameValue.Value.pbData); } return ret; }
BOOL WINAPI CertStrToNameW(DWORD dwCertEncodingType, LPCWSTR pszX500, DWORD dwStrType, void *pvReserved, BYTE *pbEncoded, DWORD *pcbEncoded, LPCWSTR *ppszError) { CERT_NAME_INFO info = { 0, NULL }; LPCWSTR str; struct KeynameKeeper keeper; DWORD i, error = ERROR_SUCCESS; BOOL ret = TRUE; TRACE("(%08lx, %s, %08lx, %p, %p, %p, %p)\n", dwCertEncodingType, debugstr_w(pszX500), dwStrType, pvReserved, pbEncoded, pcbEncoded, ppszError); CRYPT_InitializeKeynameKeeper(&keeper); str = pszX500; while (str && *str && !error && ret) { struct X500TokenW token; error = CRYPT_GetNextKeyW(str, &token, ppszError); if (!error && token.start) { PCCRYPT_OID_INFO keyOID; CRYPT_KeynameKeeperFromTokenW(&keeper, &token); keyOID = CryptFindOIDInfo(CRYPT_OID_INFO_NAME_KEY, keeper.keyName, CRYPT_RDN_ATTR_OID_GROUP_ID); if (!keyOID) { if (ppszError) *ppszError = token.start; error = CRYPT_E_INVALID_X500_STRING; } else { str = token.end; while (isspace(*str)) str++; if (*str != '=') { if (ppszError) *ppszError = str; error = CRYPT_E_INVALID_X500_STRING; } else { static const WCHAR commaSep[] = { ',',0 }; static const WCHAR semiSep[] = { ';',0 }; static const WCHAR crlfSep[] = { '\r','\n',0 }; static const WCHAR allSeps[] = { ',',';','\r','\n',0 }; LPCWSTR sep; str++; if (dwStrType & CERT_NAME_STR_COMMA_FLAG) sep = commaSep; else if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG) sep = semiSep; else if (dwStrType & CERT_NAME_STR_CRLF_FLAG) sep = crlfSep; else sep = allSeps; error = CRYPT_GetNextValueW(str, dwStrType, sep, &token, ppszError); if (!error) { str = token.end; ret = CRYPT_ValueToRDN(dwCertEncodingType, &info, keyOID, &token, ppszError); } } } } } CRYPT_FreeKeynameKeeper(&keeper); if (!error) { ret = CryptEncodeObjectEx(dwCertEncodingType, X509_NAME, &info, 0, NULL, pbEncoded, pcbEncoded); for (i = 0; i < info.cRDN; i++) { DWORD j; for (j = 0; j < info.rgRDN[i].cRDNAttr; j++) LocalFree(info.rgRDN[i].rgRDNAttr[j].Value.pbData); CryptMemFree(info.rgRDN[i].rgRDNAttr); } CryptMemFree(info.rgRDN); } else { SetLastError(error); ret = FALSE; } return ret; }
/** * * save public or private key to PEM format * * ofile : name of file to write PEM encoded key * pemType : type of key being saved * rsa : RSA object with public and private keys * */ int rsa_write_key(RSA* rsa, const char* ofile, int pemType) { DWORD pkiLen, derLen; LPVOID pki, derData; BOOL ok = FALSE; // public key? if (pemType == RSA_PUBLIC_KEY) { // get size of public key info if (CryptExportPublicKeyInfo(rsa->prov, AT_KEYEXCHANGE, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, NULL, &pkiLen)) { // allocate memory pki = xmalloc(pkiLen); // export public key info if (CryptExportPublicKeyInfo(rsa->prov, AT_KEYEXCHANGE, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pki, &pkiLen)) { // get size of DER encoding if (CryptEncodeObjectEx( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_PUBLIC_KEY_INFO, pki, 0, NULL, NULL, &derLen)) { derData = xmalloc(derLen); // convert to DER format ok = CryptEncodeObjectEx( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_PUBLIC_KEY_INFO, pki, 0, NULL, derData, &derLen); // write to PEM file if (ok) { rsa_write_pem(RSA_PUBLIC_KEY, derData, derLen, ofile); xfree(derData); } } } } } else { // get length of PKCS#8 encoding if (CryptExportPKCS8(rsa->prov, AT_KEYEXCHANGE, szOID_RSA_RSA, 0, NULL, NULL, &pkiLen)) { pki = xmalloc(pkiLen); if (pki != NULL) { // export the private key ok = CryptExportPKCS8(rsa->prov, AT_KEYEXCHANGE, szOID_RSA_RSA, 0x8000, NULL, pki, &pkiLen); // write key to PEM file if (ok) { rsa_write_pem(RSA_PRIVATE_KEY, pki, pkiLen, ofile); } xfree(pki); } } } return ok; }
inline std::vector<unsigned char> create_req_blob(stcrypt::cert_name_t const& name, NCRYPT_KEY_HANDLE const subject_public_key, boost::optional<stcrypt::cert_name_t const&> const& issuer = boost::none){ auto const& subject_name_2 = name.x500_string(); auto const subject_name = subject_name_2.c_str(); wchar_t const*const dummy_issuer_name = L""; boost::uuids::uuid const serial_and_unique_id( (boost::uuids::random_generator()()) ); std::vector<BYTE> serial_blob_data; serial_blob_data.reserve( serial_and_unique_id.static_size() ); std::copy(serial_and_unique_id.begin(), serial_and_unique_id.end(), std::back_inserter(serial_blob_data) ); CERT_INFO cert_info={0}; cert_info.dwVersion = CERT_V3; cert_info.SerialNumber.pbData = serial_blob_data.data(); cert_info.SerialNumber.cbData = serial_blob_data.size(); cert_info.SubjectUniqueId.pbData = serial_blob_data.data(); cert_info.SubjectUniqueId.cbData = serial_blob_data.size(); CRYPT_ALGORITHM_IDENTIFIER signature_alg={OID_G34311_DSTU4145_SIGN,0}; cert_info.SignatureAlgorithm = signature_alg; SYSTEMTIME cs; GetSystemTime(&cs); {auto const r = SystemTimeToFileTime(&cs, &cert_info.NotBefore); assert(r);} cs.wYear += 1; {auto const r = SystemTimeToFileTime(&cs, &cert_info.NotAfter); assert(r);} std::vector<unsigned char> subject_name_blob_data; std::vector<unsigned char> issuer_name_blob_data; ms_cert::cert_str_to_name_blob(subject_name, cert_info.Subject, subject_name_blob_data); if(issuer){ auto const& issuer_x500_string = issuer->x500_string(); ms_cert::cert_str_to_name_blob(issuer_x500_string.c_str(), cert_info.Issuer, issuer_name_blob_data); } else { ms_cert::cert_str_to_name_blob(dummy_issuer_name, cert_info.Issuer, issuer_name_blob_data); } DWORD pub_key_size; if( !CryptExportPublicKeyInfoEx(subject_public_key, 0, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, OID_DSTU4145_PUBKEY, 0, 0, 0, &pub_key_size) ){ STCRYPT_UNEXPECTED(); } STCRYPT_CHECK(pub_key_size!=0); std::vector<unsigned char> subject_pub_key_info_data(pub_key_size); if( !CryptExportPublicKeyInfoEx(subject_public_key, 0, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, OID_DSTU4145_PUBKEY, 0, 0, static_cast<CERT_PUBLIC_KEY_INFO*>( static_cast<void*>(subject_pub_key_info_data.data())), &pub_key_size) ){ STCRYPT_UNEXPECTED(); } subject_pub_key_info_data.resize(pub_key_size); CERT_PUBLIC_KEY_INFO * subject_pub_key_info = static_cast<CERT_PUBLIC_KEY_INFO*>( static_cast<void*>( subject_pub_key_info_data.data() ) ); cert_info.SubjectPublicKeyInfo = *subject_pub_key_info; DWORD cert_encoded_size = 0; STCRYPT_CHECK( CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, &cert_info, 0, 0, 0, &cert_encoded_size)!=0 ); STCRYPT_CHECK( cert_encoded_size!=0 ); std::vector<unsigned char> cert_to_be_signed_blob(cert_encoded_size); STCRYPT_CHECK( CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, &cert_info, 0, 0, cert_to_be_signed_blob.data(), &cert_encoded_size)!=0 ); cert_to_be_signed_blob.resize( cert_encoded_size ); return cert_to_be_signed_blob; }