@@ -269,83 +269,106 @@ void aws_close_cert_store(HCERTSTORE cert_store) {
269269 CertCloseStore (cert_store , 0 );
270270}
271271
272- static int s_cert_context_import_rsa_private_key (
272+ enum aws_rsa_private_key_container_type {
273+ AWS_RPKCT_PERSIST_TO_USER_PROFILE ,
274+ AWS_RPKCT_PERSIST_TO_GLOBAL ,
275+ AWS_RPKCT_EPHEMERAL ,
276+ };
277+
278+ static int s_cert_context_import_rsa_private_key_to_key_container (
273279 PCCERT_CONTEXT certs ,
274280 const BYTE * key ,
275281 DWORD decoded_len ,
276- bool is_client_mode ,
277282 wchar_t uuid_wstr [AWS_UUID_STR_LEN ],
283+ enum aws_rsa_private_key_container_type key_container_type ,
278284 HCRYPTPROV * out_crypto_provider ,
279- HCRYPTKEY * out_private_key_handle ) {
285+ HCRYPTKEY * out_private_key_handle ,
286+ bool * tls13_disabled ) {
280287
281288 /* out-params will adopt these resources if the function is successful.
282289 * if function fails these resources will be cleaned up before returning */
283290 HCRYPTPROV crypto_prov = 0 ;
284291 HCRYPTKEY h_key = 0 ;
285292
286- if (is_client_mode ) {
287- /* use CRYPT_VERIFYCONTEXT so that keys are ephemeral (not stored to disk, registry, etc) */
288- if (!CryptAcquireContextW (& crypto_prov , NULL , NULL , PROV_RSA_FULL , CRYPT_VERIFYCONTEXT )) {
289- AWS_LOGF_ERROR (
290- AWS_LS_IO_PKI ,
291- "static: error creating a new rsa crypto context for key with errno %d" ,
292- (int )GetLastError ());
293- aws_raise_error (AWS_ERROR_SYS_CALL_FAILURE );
294- goto on_error ;
295- }
293+ const wchar_t * container_name = NULL ;
294+ DWORD acquire_context_flags = 0 ;
296295
297- if (!CryptImportKey (crypto_prov , key , decoded_len , 0 , 0 , & h_key )) {
298- AWS_LOGF_ERROR (
299- AWS_LS_IO_PKI , "static: failed to import rsa key into crypto provider, error code %d" , GetLastError ());
300- aws_raise_error (AWS_ERROR_SYS_CALL_FAILURE );
301- goto on_error ;
302- }
296+ switch (key_container_type ) {
297+ case AWS_RPKCT_PERSIST_TO_USER_PROFILE :
298+ container_name = uuid_wstr ;
299+ acquire_context_flags = CRYPT_NEWKEYSET ;
300+ break ;
301+ case AWS_RPKCT_PERSIST_TO_GLOBAL :
302+ container_name = uuid_wstr ;
303+ acquire_context_flags = CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET ;
304+ break ;
305+ case AWS_RPKCT_EPHEMERAL :
306+ break ;
307+ }
308+
309+ if (!CryptAcquireContextW (& crypto_prov , container_name , NULL , PROV_RSA_FULL , acquire_context_flags )) {
310+ AWS_LOGF_WARN (
311+ AWS_LS_IO_PKI ,
312+ "static: error creating a new rsa crypto context for key: key container type %d; error code %d" ,
313+ (int )key_container_type ,
314+ (int )GetLastError ());
315+ aws_raise_error (AWS_ERROR_SYS_CALL_FAILURE );
316+ goto on_error ;
317+ }
318+
319+ if (!CryptImportKey (crypto_prov , key , decoded_len , 0 , 0 , & h_key )) {
320+ AWS_LOGF_ERROR (
321+ AWS_LS_IO_PKI ,
322+ "static: failed to import rsa key into crypto provider: key container type %d; error code %d" ,
323+ (int )key_container_type ,
324+ GetLastError ());
325+ aws_raise_error (AWS_ERROR_SYS_CALL_FAILURE );
326+ goto on_error ;
327+ }
303328
329+ if (key_container_type == AWS_RPKCT_EPHEMERAL ) {
304330 if (!CertSetCertificateContextProperty (certs , CERT_KEY_PROV_HANDLE_PROP_ID , 0 , (void * )crypto_prov )) {
305331 AWS_LOGF_ERROR (
306332 AWS_LS_IO_PKI ,
307- "static: error creating a new certificate context for rsa key with errno %d" ,
333+ "static: error setting a certificate context property for rsa key: key container type %d; error code "
334+ "%d" ,
335+ (int )key_container_type ,
308336 (int )GetLastError ());
309337 aws_raise_error (AWS_ERROR_SYS_CALL_FAILURE );
310338 goto on_error ;
311339 }
340+ /* Secure Channel doesn't support TLS 1.3 with ephemeral keys. */
341+ AWS_LOGF_INFO (AWS_LS_IO_PKI , "static: TLS 1.3 does not support ephemeral keys, disabling TLS 1.3" );
342+ * tls13_disabled = true;
312343 } else {
313- if (!CryptAcquireContextW (& crypto_prov , uuid_wstr , NULL , PROV_RSA_FULL , CRYPT_NEWKEYSET )) {
314- AWS_LOGF_ERROR (
315- AWS_LS_IO_PKI , "static: error creating a new rsa crypto context with errno %d" , (int )GetLastError ());
316- aws_raise_error (AWS_ERROR_SYS_CALL_FAILURE );
317- goto on_error ;
318- }
319-
320- if (!CryptImportKey (crypto_prov , key , decoded_len , 0 , 0 , & h_key )) {
321- AWS_LOGF_ERROR (
322- AWS_LS_IO_PKI , "static: failed to import rsa key into crypto provider, error code %d" , GetLastError ());
323- aws_raise_error (AWS_ERROR_SYS_CALL_FAILURE );
324- goto on_error ;
325- }
326-
327344 CRYPT_KEY_PROV_INFO key_prov_info ;
328345 AWS_ZERO_STRUCT (key_prov_info );
329346 key_prov_info .pwszContainerName = uuid_wstr ;
330347 key_prov_info .dwProvType = PROV_RSA_FULL ;
348+ if (key_container_type == AWS_RPKCT_PERSIST_TO_GLOBAL ) {
349+ key_prov_info .dwFlags = CRYPT_MACHINE_KEYSET ;
350+ }
331351 key_prov_info .dwKeySpec = AT_KEYEXCHANGE ;
332352
333353 if (!CertSetCertificateContextProperty (certs , CERT_KEY_PROV_INFO_PROP_ID , 0 , & key_prov_info )) {
334354 AWS_LOGF_ERROR (
335355 AWS_LS_IO_PKI ,
336- "static: error creating a new certificate context for key with errno %d" ,
356+ "static: error setting a certificate context property: key container type %d; error code %d" ,
357+ (int )key_container_type ,
337358 (int )GetLastError ());
338359 aws_raise_error (AWS_ERROR_SYS_CALL_FAILURE );
339360 goto on_error ;
340361 }
341362 }
342363
364+ AWS_LOGF_DEBUG (
365+ AWS_LS_IO_PKI , "static: successfully imported rsa private key, key container type %d" , (int )key_container_type );
366+
343367 * out_crypto_provider = crypto_prov ;
344368 * out_private_key_handle = h_key ;
345369 return AWS_OP_SUCCESS ;
346370
347371on_error :
348-
349372 if (h_key != 0 ) {
350373 CryptDestroyKey (h_key );
351374 }
@@ -357,6 +380,51 @@ static int s_cert_context_import_rsa_private_key(
357380 return AWS_OP_ERR ;
358381}
359382
383+ static int s_cert_context_import_rsa_private_key (
384+ PCCERT_CONTEXT certs ,
385+ const BYTE * key ,
386+ DWORD decoded_len ,
387+ bool is_client_mode ,
388+ wchar_t uuid_wstr [AWS_UUID_STR_LEN ],
389+ HCRYPTPROV * out_crypto_provider ,
390+ HCRYPTKEY * out_private_key_handle ,
391+ bool * tls13_disabled ) {
392+
393+ const enum aws_rsa_private_key_container_type client_available_key_container_types [] = {
394+ AWS_RPKCT_PERSIST_TO_USER_PROFILE ,
395+ AWS_RPKCT_PERSIST_TO_GLOBAL ,
396+ AWS_RPKCT_EPHEMERAL ,
397+ };
398+
399+ /* NOTE We didn't verify server-side with ephemeral keys, so use only persistent key containers. */
400+ const enum aws_rsa_private_key_container_type server_available_key_container_types [] = {
401+ AWS_RPKCT_PERSIST_TO_USER_PROFILE ,
402+ AWS_RPKCT_PERSIST_TO_GLOBAL ,
403+ };
404+
405+ size_t key_container_types_num = is_client_mode ? AWS_ARRAY_SIZE (client_available_key_container_types )
406+ : AWS_ARRAY_SIZE (server_available_key_container_types );
407+ const enum aws_rsa_private_key_container_type * available_key_container_types =
408+ is_client_mode ? client_available_key_container_types : server_available_key_container_types ;
409+
410+ /* Try importing into various Windows key containers until we succeed or exhaust all possible options. */
411+ for (size_t i = 0 ; i < key_container_types_num ; ++ i ) {
412+ if (s_cert_context_import_rsa_private_key_to_key_container (
413+ certs ,
414+ key ,
415+ decoded_len ,
416+ uuid_wstr ,
417+ available_key_container_types [i ],
418+ out_crypto_provider ,
419+ out_private_key_handle ,
420+ tls13_disabled ) == AWS_OP_SUCCESS ) {
421+ return AWS_OP_SUCCESS ;
422+ }
423+ }
424+
425+ return AWS_OP_ERR ;
426+ }
427+
360428#define ECC_256_MAGIC_NUMBER 0x20
361429#define ECC_384_MAGIC_NUMBER 0x30
362430
@@ -546,7 +614,8 @@ int aws_import_key_pair_to_cert_context(
546614 HCERTSTORE * store ,
547615 PCCERT_CONTEXT * certs ,
548616 HCRYPTPROV * crypto_provider ,
549- HCRYPTKEY * private_key_handle ) {
617+ HCRYPTKEY * private_key_handle ,
618+ bool * tls13_disabled ) {
550619
551620 struct aws_array_list certificates , private_keys ;
552621 AWS_ZERO_STRUCT (certificates );
@@ -724,7 +793,14 @@ int aws_import_key_pair_to_cert_context(
724793 switch (cert_type ) {
725794 case AWS_CT_X509_RSA :
726795 result = s_cert_context_import_rsa_private_key (
727- * certs , key , decoded_len , is_client_mode , uuid_wstr , crypto_provider , private_key_handle );
796+ * certs ,
797+ key ,
798+ decoded_len ,
799+ is_client_mode ,
800+ uuid_wstr ,
801+ crypto_provider ,
802+ private_key_handle ,
803+ tls13_disabled );
728804 break ;
729805
730806#ifndef AWS_SUPPORT_WIN7
0 commit comments