@@ -636,16 +636,29 @@ SECURITY_STATUS schannel_verify_server_certificate(
636
636
return status ;
637
637
}
638
638
639
+ /*
640
+ Generate a random key container name.
641
+ Used to store private key in Windows key store.
642
+ */
643
+ #define KEY_CONTAINER_NAME_PREFIX L"MariaDB-Connector-C-"
644
+ static void generate_key_container_name (wchar_t * key_container_name , size_t key_container_name_len )
645
+ {
646
+ LARGE_INTEGER now ;
647
+ QueryPerformanceCounter (& now );
648
+ swprintf_s (key_container_name , key_container_name_len ,
649
+ L"MariaDB-Connector-C-%u-%u-%lld" ,GetCurrentProcessId (),GetCurrentThreadId (),now .QuadPart );
650
+ }
639
651
640
652
/* Attach private key (in PEM format) to client certificate */
641
- static SECURITY_STATUS load_private_key (CERT_CONTEXT * cert , char * private_key_str , size_t len , char * errmsg , size_t errmsg_len )
653
+ static SECURITY_STATUS load_private_key (client_cert_handle * cert_handle , char * private_key_str ,
654
+ size_t len , char * errmsg ,
655
+ size_t errmsg_len )
642
656
{
643
657
DWORD derlen = (DWORD )len ;
644
658
BYTE * derbuf = NULL ;
645
659
DWORD keyblob_len = 0 ;
646
660
BYTE * keyblob = NULL ;
647
- HCRYPTPROV hProv = 0 ;
648
- HCRYPTKEY hKey = 0 ;
661
+
649
662
CERT_KEY_CONTEXT cert_key_context = { 0 };
650
663
PCRYPT_PRIVATE_KEY_INFO pki = NULL ;
651
664
DWORD pki_len = 0 ;
@@ -695,24 +708,30 @@ static SECURITY_STATUS load_private_key(CERT_CONTEXT* cert, char* private_key_st
695
708
{
696
709
FAIL ("Failed to parse private key" );
697
710
}
711
+ generate_key_container_name (cert_handle -> key_container_name , sizeof (cert_handle -> key_container_name ) / sizeof (wchar_t ));
698
712
699
- if (!CryptAcquireContext (& hProv , NULL , MS_ENHANCED_PROV , PROV_RSA_FULL , CRYPT_VERIFYCONTEXT ))
713
+ if (!CryptAcquireContextW (& cert_handle -> prov ,
714
+ cert_handle -> key_container_name , MS_ENHANCED_PROV_W ,
715
+ PROV_RSA_FULL , CRYPT_NEWKEYSET ))
700
716
{
701
717
FAIL ("CryptAcquireContext failed" );
702
718
}
703
719
704
- if (!CryptImportKey (hProv , keyblob , keyblob_len , 0 , 0 , (HCRYPTKEY * )& hKey ))
720
+ if (!CryptImportKey (cert_handle -> prov , keyblob , keyblob_len , 0 , 0 ,
721
+ & cert_handle -> key ))
705
722
{
706
723
FAIL ("CryptImportKey failed" );
707
724
}
708
- cert_key_context .hCryptProv = hProv ;
709
- cert_key_context .dwKeySpec = AT_KEYEXCHANGE ;
710
- cert_key_context .cbSize = sizeof (cert_key_context );
711
-
712
- /* assign private key to certificate context */
713
- if (!CertSetCertificateContextProperty (cert , CERT_KEY_CONTEXT_PROP_ID ,
714
- CERT_STORE_NO_CRYPT_RELEASE_FLAG ,
715
- & cert_key_context ))
725
+ // Link the private key to the certificate
726
+ CRYPT_KEY_PROV_INFO keyProvInfo = {0 };
727
+ keyProvInfo .pwszContainerName = cert_handle -> key_container_name ;
728
+ keyProvInfo .pwszProvName = NULL ;
729
+ keyProvInfo .dwProvType = PROV_RSA_FULL ;
730
+ keyProvInfo .dwFlags = 0 ;
731
+ keyProvInfo .cProvParam = 0 ;
732
+ keyProvInfo .rgProvParam = NULL ;
733
+ keyProvInfo .dwKeySpec = AT_KEYEXCHANGE ;
734
+ if (!CertSetCertificateContextProperty (cert_handle -> cert , CERT_KEY_PROV_INFO_PROP_ID , 0 , & keyProvInfo ))
716
735
{
717
736
FAIL ("CertSetCertificateContextProperty failed" );
718
737
}
@@ -721,23 +740,17 @@ static SECURITY_STATUS load_private_key(CERT_CONTEXT* cert, char* private_key_st
721
740
LocalFree (derbuf );
722
741
LocalFree (keyblob );
723
742
LocalFree (pki );
724
- if (hKey )
725
- CryptDestroyKey (hKey );
726
- if (status )
727
- {
728
- if (hProv )
729
- CryptReleaseContext (hProv , 0 );
730
- }
731
743
return status ;
732
744
}
733
745
734
746
/*
735
747
Given PEM strings for certificate and private key,
736
748
create a client certificate*
737
749
*/
738
- static CERT_CONTEXT * create_client_certificate_mem (
750
+ static SECURITY_STATUS create_client_certificate_mem (
739
751
char * cert_file_content ,
740
752
char * key_file_content ,
753
+ client_cert_handle * cert_handle ,
741
754
char * errmsg ,
742
755
size_t errmsg_len )
743
756
{
@@ -764,7 +777,7 @@ static CERT_CONTEXT* create_client_certificate_mem(
764
777
CERT_QUERY_OBJECT_BLOB , & cert_blob ,
765
778
CERT_QUERY_CONTENT_FLAG_CERT ,
766
779
CERT_QUERY_FORMAT_FLAG_ALL , 0 , NULL , & actual_content_type ,
767
- NULL , NULL , NULL , (const void * * )& ctx ))
780
+ NULL , NULL , NULL , (const void * * )& cert_handle -> cert ))
768
781
{
769
782
FAIL ("Can't parse client certficate" );
770
783
}
@@ -777,7 +790,7 @@ static CERT_CONTEXT* create_client_certificate_mem(
777
790
if (begin && end )
778
791
{
779
792
/* Assign key to certificate.*/
780
- status = load_private_key (ctx , begin , (end - begin ), errmsg , errmsg_len );
793
+ status = load_private_key (cert_handle , begin , (end - begin ), errmsg , errmsg_len );
781
794
goto cleanup ;
782
795
}
783
796
}
@@ -789,21 +802,20 @@ static CERT_CONTEXT* create_client_certificate_mem(
789
802
}
790
803
791
804
cleanup :
792
- if (status && ctx )
793
- {
794
- CertFreeCertificateContext (ctx );
795
- ctx = NULL ;
796
- }
797
- return ctx ;
805
+ return status ;
798
806
}
799
807
800
808
801
809
/* Given cert and key, as PEM file names, create a client certificate */
802
- CERT_CONTEXT * schannel_create_cert_context (char * cert_file , char * key_file , char * errmsg , size_t errmsg_len )
810
+ SECURITY_STATUS schannel_create_cert_context (char * cert_file , char * key_file ,
811
+ client_cert_handle * cert_handle ,
812
+ char * errmsg , size_t errmsg_len )
803
813
{
804
- CERT_CONTEXT * ctx = NULL ;
805
814
char * key_file_content = NULL ;
806
815
char * cert_file_content = NULL ;
816
+ SECURITY_STATUS status = SEC_E_INTERNAL_ERROR ;
817
+
818
+ memset (cert_handle , 0 , sizeof (client_cert_handle ));
807
819
808
820
cert_file_content = pem_file_to_string (cert_file , errmsg , errmsg_len );
809
821
@@ -821,34 +833,45 @@ CERT_CONTEXT* schannel_create_cert_context(char* cert_file, char* key_file, char
821
833
goto cleanup ;
822
834
}
823
835
824
- ctx = create_client_certificate_mem (cert_file_content , key_file_content , errmsg , errmsg_len );
836
+ status = create_client_certificate_mem (cert_file_content , key_file_content , cert_handle , errmsg , errmsg_len );
825
837
826
838
cleanup :
827
839
LocalFree (cert_file_content );
828
840
if (cert_file != key_file )
829
841
LocalFree (key_file_content );
830
-
831
- return ctx ;
842
+ if (status )
843
+ schannel_free_cert_context (cert_handle );
844
+ return status ;
832
845
}
833
846
834
847
/*
835
848
Free certificate, and all resources, created by schannel_create_cert_context()
836
849
*/
837
- void schannel_free_cert_context (const CERT_CONTEXT * cert )
850
+ void schannel_free_cert_context (client_cert_handle * cert_handle )
838
851
{
839
- /* release provider handle which was acquires in load_private_key() */
840
- CERT_KEY_CONTEXT cert_key_context = { 0 };
841
- cert_key_context .cbSize = sizeof (cert_key_context );
842
- DWORD cbData = sizeof (CERT_KEY_CONTEXT );
843
- HCRYPTPROV hProv = 0 ;
844
-
845
- if (CertGetCertificateContextProperty (cert , CERT_KEY_CONTEXT_PROP_ID , & cert_key_context , & cbData ))
852
+ if (cert_handle -> key )
846
853
{
847
- hProv = cert_key_context .hCryptProv ;
854
+ CryptDestroyKey (cert_handle -> key );
855
+ cert_handle -> key = 0 ;
848
856
}
849
- CertFreeCertificateContext (cert );
850
- if (hProv )
857
+ if (cert_handle -> prov )
851
858
{
852
- CryptReleaseContext (cert_key_context .hCryptProv , 0 );
859
+ CryptReleaseContext (cert_handle -> prov , 0 );
860
+ cert_handle -> prov = 0 ;
861
+ }
862
+ if (cert_handle -> cert )
863
+ {
864
+ CertFreeCertificateContext (cert_handle -> cert );
865
+ cert_handle -> cert = 0 ;
866
+ }
867
+ if (cert_handle -> key_container_name [0 ])
868
+ {
869
+ if (!CryptAcquireContextW (& cert_handle -> prov , cert_handle -> key_container_name ,
870
+ MS_ENHANCED_PROV_W , PROV_RSA_FULL ,
871
+ CRYPT_DELETEKEYSET ))
872
+ {
873
+ assert (GetLastError () == NTE_BAD_KEYSET );
874
+ }
875
+ cert_handle -> key_container_name [0 ] = 0 ;
853
876
}
854
877
}
0 commit comments