in source/windows/windows_pki_utils.c [515:732]
int aws_import_key_pair_to_cert_context(
struct aws_allocator *alloc,
const struct aws_byte_cursor *public_cert_chain,
const struct aws_byte_cursor *private_key,
bool is_client_mode,
HCERTSTORE *store,
PCCERT_CONTEXT *certs,
HCRYPTPROV *crypto_provider,
HCRYPTKEY *private_key_handle) {
struct aws_array_list certificates, private_keys;
AWS_ZERO_STRUCT(certificates);
AWS_ZERO_STRUCT(private_keys);
*certs = NULL;
*store = NULL;
*crypto_provider = 0;
*private_key_handle = 0;
int result = AWS_OP_ERR;
BYTE *key = NULL;
if (aws_array_list_init_dynamic(&certificates, alloc, 2, sizeof(struct aws_byte_buf))) {
return AWS_OP_ERR;
}
if (aws_decode_pem_to_buffer_list(alloc, public_cert_chain, &certificates)) {
AWS_LOGF_ERROR(
AWS_LS_IO_PKI, "static: failed to decode cert pem to buffer list with error %d", (int)aws_last_error());
goto clean_up;
}
if (aws_array_list_init_dynamic(&private_keys, alloc, 1, sizeof(struct aws_byte_buf))) {
goto clean_up;
}
if (aws_decode_pem_to_buffer_list(alloc, private_key, &private_keys)) {
AWS_LOGF_ERROR(
AWS_LS_IO_PKI, "static: failed to decode key pem to buffer list with error %d", (int)aws_last_error());
goto clean_up;
}
size_t cert_count = aws_array_list_length(&certificates);
AWS_LOGF_INFO(AWS_LS_IO_PKI, "static: loading certificate chain with %d certificates.", (int)cert_count);
*store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, (ULONG_PTR)NULL, CERT_STORE_CREATE_NEW_FLAG, NULL);
if (!*store) {
AWS_LOGF_ERROR(
AWS_LS_IO_PKI,
"static: failed to load in-memory/ephemeral certificate store, error code %d",
GetLastError());
aws_raise_error(AWS_ERROR_SYS_CALL_FAILURE);
goto clean_up;
}
for (size_t i = 0; i < cert_count; ++i) {
struct aws_byte_buf *byte_buf_ptr = NULL;
aws_array_list_get_at_ptr(&certificates, (void **)&byte_buf_ptr, i);
CERT_BLOB cert_blob;
cert_blob.pbData = byte_buf_ptr->buffer;
cert_blob.cbData = (DWORD)byte_buf_ptr->len;
DWORD content_type = 0;
PCERT_CONTEXT cert_context = NULL;
BOOL query_res = CryptQueryObject(
CERT_QUERY_OBJECT_BLOB,
&cert_blob,
CERT_QUERY_CONTENT_FLAG_CERT,
CERT_QUERY_FORMAT_FLAG_ALL,
0,
NULL,
&content_type,
NULL,
NULL,
NULL,
(const void **)&cert_context);
if (!query_res || cert_context == NULL) {
AWS_LOGF_ERROR(AWS_LS_IO_PKI, "static: invalid certificate blob, error code %d.", GetLastError());
aws_raise_error(AWS_IO_FILE_VALIDATION_FAILURE);
goto clean_up;
}
BOOL add_result = CertAddCertificateContextToStore(*store, cert_context, CERT_STORE_ADD_ALWAYS, NULL);
if (!add_result) {
AWS_LOGF_ERROR(AWS_LS_IO_PKI, "static: unable to add , error code %d.", GetLastError());
aws_raise_error(AWS_ERROR_SYS_CALL_FAILURE);
}
if (i != cert_count - 1 || !add_result) {
CertFreeCertificateContext(cert_context);
} else {
*certs = cert_context;
}
if (!add_result) {
goto clean_up;
}
}
if (*certs == NULL) {
aws_raise_error(AWS_IO_FILE_VALIDATION_FAILURE);
AWS_LOGF_ERROR(AWS_LS_IO_PKI, "static: no certificates found, error %s", aws_error_name(aws_last_error()));
goto clean_up;
}
struct aws_byte_buf *private_key_ptr = NULL;
DWORD decoded_len = 0;
enum aws_certificate_type cert_type = AWS_CT_X509_UNKNOWN;
size_t private_key_count = aws_array_list_length(&private_keys);
for (size_t i = 0; i < private_key_count; ++i) {
aws_array_list_get_at_ptr(&private_keys, (void **)&private_key_ptr, i);
if (CryptDecodeObjectEx(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
PKCS_RSA_PRIVATE_KEY,
private_key_ptr->buffer,
(DWORD)private_key_ptr->len,
CRYPT_DECODE_ALLOC_FLAG,
0,
&key,
&decoded_len)) {
cert_type = AWS_CT_X509_RSA;
}
#ifndef AWS_SUPPORT_WIN7
else if (CryptDecodeObjectEx(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
X509_ECC_PRIVATE_KEY,
private_key_ptr->buffer,
(DWORD)private_key_ptr->len,
CRYPT_DECODE_ALLOC_FLAG,
NULL,
&key,
&decoded_len)) {
cert_type = AWS_CT_X509_ECC;
}
#endif /* AWS_SUPPORT_WIN7 */
if (cert_type != AWS_CT_X509_UNKNOWN) {
break;
}
}
if (cert_type == AWS_CT_X509_UNKNOWN) {
aws_raise_error(AWS_IO_FILE_VALIDATION_FAILURE);
AWS_LOGF_ERROR(
AWS_LS_IO_PKI, "static: no acceptable private key found, error %s", aws_error_name(aws_last_error()));
goto clean_up;
}
struct aws_uuid uuid;
if (aws_uuid_init(&uuid)) {
AWS_LOGF_ERROR(AWS_LS_IO_PKI, "static: failed to create a uuid.");
goto clean_up;
}
char uuid_str[AWS_UUID_STR_LEN] = {0};
struct aws_byte_buf uuid_buf = aws_byte_buf_from_array(uuid_str, sizeof(uuid_str));
uuid_buf.len = 0;
aws_uuid_to_str(&uuid, &uuid_buf);
wchar_t uuid_wstr[AWS_UUID_STR_LEN] = {0};
size_t converted_chars = 0;
mbstowcs_s(&converted_chars, uuid_wstr, AWS_UUID_STR_LEN, uuid_str, sizeof(uuid_str));
(void)converted_chars;
switch (cert_type) {
case AWS_CT_X509_RSA:
result = s_cert_context_import_rsa_private_key(
*certs, key, decoded_len, is_client_mode, uuid_wstr, crypto_provider, private_key_handle);
break;
#ifndef AWS_SUPPORT_WIN7
case AWS_CT_X509_ECC:
result = s_cert_context_import_ecc_private_key(*certs, alloc, key, decoded_len, uuid_wstr);
break;
#endif /* AWS_SUPPORT_WIN7 */
default:
AWS_LOGF_ERROR(AWS_LS_IO_PKI, "static: failed to decode private key");
aws_raise_error(AWS_IO_FILE_VALIDATION_FAILURE);
goto clean_up;
}
clean_up:
aws_cert_chain_clean_up(&certificates);
aws_array_list_clean_up(&certificates);
aws_cert_chain_clean_up(&private_keys);
aws_array_list_clean_up(&private_keys);
LocalFree(key);
if (result == AWS_OP_ERR) {
if (*store != NULL) {
aws_close_cert_store(*store);
*store = NULL;
}
if (*certs) {
CertFreeCertificateContext(*certs);
*certs = NULL;
}
if (*crypto_provider != 0) {
CryptReleaseContext(*crypto_provider, 0);
*crypto_provider = 0;
}
if (*private_key_handle != 0) {
CryptDestroyKey(*private_key_handle);
*private_key_handle = 0;
}
}
return result;
}