int aws_import_key_pair_to_cert_context()

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;
}