[PATCH 0/3] MR10198: crypt32: Support importing cert-only PKCS12 blobs in PFXImportCertStore.
Fix https://bugs.winehq.org/show_bug.cgi?id=52330 by adding manual parsing logic that can deal with stores with no keys. Confirmed that authorization through the "Manual Authorization" option succeeds in iZotope Audiolens 1.5.0. Also add a drive-by fix to verify PKCS12 MAC. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10198
From: Tatsuyuki Ishi <ishitatsuyuki@gmail.com> gnutls_pkcs12_simple_parse() assumes the blob includes at least one private key, which is not true for some applications. Add our own parsing loop, capable of handling zero or one private key. Still assume that there is up to one key and up to one chain, to avoid complexity of key/cert matching. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52330 --- dlls/crypt32/crypt32_private.h | 1 + dlls/crypt32/pfx.c | 33 +++-- dlls/crypt32/unixlib.c | 219 ++++++++++++++++++++++++++++----- 3 files changed, 209 insertions(+), 44 deletions(-) diff --git a/dlls/crypt32/crypt32_private.h b/dlls/crypt32/crypt32_private.h index f5918ef0359..17253bde695 100644 --- a/dlls/crypt32/crypt32_private.h +++ b/dlls/crypt32/crypt32_private.h @@ -483,6 +483,7 @@ struct open_cert_store_params CRYPT_DATA_BLOB *pfx; const WCHAR *password; cert_store_data_t *data_ret; + unsigned int *key_count_ret; }; struct import_store_key_params diff --git a/dlls/crypt32/pfx.c b/dlls/crypt32/pfx.c index a5a5e4b9087..97285ad21a7 100644 --- a/dlls/crypt32/pfx.c +++ b/dlls/crypt32/pfx.c @@ -141,10 +141,11 @@ static BOOL set_key_prov_info( const void *ctx, HCRYPTPROV prov ) HCERTSTORE WINAPI PFXImportCertStore( CRYPT_DATA_BLOB *pfx, const WCHAR *password, DWORD flags ) { DWORD i = 0, size; + unsigned int key_count = 0; HCERTSTORE store = NULL; HCRYPTPROV prov = 0; cert_store_data_t data = 0; - struct open_cert_store_params open_params = { pfx, password, &data }; + struct open_cert_store_params open_params = { pfx, password, &data, &key_count }; struct close_cert_store_params close_params; if (!pfx) @@ -163,8 +164,11 @@ HCERTSTORE WINAPI PFXImportCertStore( CRYPT_DATA_BLOB *pfx, const WCHAR *passwor } if (CRYPT32_CALL( open_cert_store, &open_params )) return NULL; - prov = import_key( data, flags ); - if (!prov) goto error; + if (key_count) + { + prov = import_key( data, flags ); + if (!prov) goto error; + } if (!(store = CertOpenStore( CERT_STORE_PROV_MEMORY, 0, 0, 0, NULL ))) { @@ -188,21 +192,24 @@ HCERTSTORE WINAPI PFXImportCertStore( CRYPT_DATA_BLOB *pfx, const WCHAR *passwor WARN( "CertCreateContext failed %08lx\n", GetLastError() ); goto error; } - if (flags & PKCS12_NO_PERSIST_KEY) + if (prov) { - if (!set_key_context( ctx, prov )) + if (flags & PKCS12_NO_PERSIST_KEY) + { + if (!set_key_context( ctx, prov )) + { + WARN( "failed to set context property %08lx\n", GetLastError() ); + CertFreeCertificateContext( ctx ); + goto error; + } + } + else if (!set_key_prov_info( ctx, prov )) { - WARN( "failed to set context property %08lx\n", GetLastError() ); + WARN( "failed to set provider info property %08lx\n", GetLastError() ); CertFreeCertificateContext( ctx ); goto error; } } - else if (!set_key_prov_info( ctx, prov )) - { - WARN( "failed to set provider info property %08lx\n", GetLastError() ); - CertFreeCertificateContext( ctx ); - goto error; - } if (!CertAddCertificateContextToStore( store, ctx, CERT_STORE_ADD_ALWAYS, NULL )) { WARN( "CertAddCertificateContextToStore failed %08lx\n", GetLastError() ); @@ -217,7 +224,7 @@ HCERTSTORE WINAPI PFXImportCertStore( CRYPT_DATA_BLOB *pfx, const WCHAR *passwor return store; error: - CryptReleaseContext( prov, 0 ); + if (prov) CryptReleaseContext( prov, 0 ); CertCloseStore( store, 0 ); close_params.data = data; CRYPT32_CALL( close_cert_store, &close_params ); diff --git a/dlls/crypt32/unixlib.c b/dlls/crypt32/unixlib.c index 345051cc6c7..89be8b67ba3 100644 --- a/dlls/crypt32/unixlib.c +++ b/dlls/crypt32/unixlib.c @@ -51,12 +51,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(crypt); WINE_DECLARE_DEBUG_CHANNEL(winediag); -/* Not present in gnutls version < 3.0 */ -int gnutls_pkcs12_simple_parse(gnutls_pkcs12_t p12, const char *password, - gnutls_x509_privkey_t *key, gnutls_x509_crt_t **chain, unsigned int *chain_len, - gnutls_x509_crt_t **extra_certs, unsigned int *extra_certs_len, - gnutls_x509_crl_t * crl, unsigned int flags); - int gnutls_x509_privkey_get_pk_algorithm2(gnutls_x509_privkey_t, unsigned int*); static void *libgnutls_handle; @@ -66,13 +60,25 @@ MAKE_FUNCPTR(gnutls_global_init); MAKE_FUNCPTR(gnutls_global_set_log_function); MAKE_FUNCPTR(gnutls_global_set_log_level); MAKE_FUNCPTR(gnutls_perror); +MAKE_FUNCPTR(gnutls_pkcs12_bag_decrypt); +MAKE_FUNCPTR(gnutls_pkcs12_bag_deinit); +MAKE_FUNCPTR(gnutls_pkcs12_bag_get_count); +MAKE_FUNCPTR(gnutls_pkcs12_bag_get_data); +MAKE_FUNCPTR(gnutls_pkcs12_bag_get_type); +MAKE_FUNCPTR(gnutls_pkcs12_bag_init); MAKE_FUNCPTR(gnutls_pkcs12_deinit); +MAKE_FUNCPTR(gnutls_pkcs12_get_bag); MAKE_FUNCPTR(gnutls_pkcs12_import); MAKE_FUNCPTR(gnutls_pkcs12_init); -MAKE_FUNCPTR(gnutls_pkcs12_simple_parse); +MAKE_FUNCPTR(gnutls_x509_crt_deinit); MAKE_FUNCPTR(gnutls_x509_crt_export); +MAKE_FUNCPTR(gnutls_x509_crt_import); +MAKE_FUNCPTR(gnutls_x509_crt_init); +MAKE_FUNCPTR(gnutls_x509_privkey_deinit); MAKE_FUNCPTR(gnutls_x509_privkey_export_rsa_raw2); MAKE_FUNCPTR(gnutls_x509_privkey_get_pk_algorithm2); +MAKE_FUNCPTR(gnutls_x509_privkey_import_pkcs8); +MAKE_FUNCPTR(gnutls_x509_privkey_init); #undef MAKE_FUNCPTR static void gnutls_log( int level, const char *msg ) @@ -113,13 +119,25 @@ static NTSTATUS process_attach( void *args ) LOAD_FUNCPTR(gnutls_global_set_log_function) LOAD_FUNCPTR(gnutls_global_set_log_level) LOAD_FUNCPTR(gnutls_perror) + LOAD_FUNCPTR(gnutls_pkcs12_bag_decrypt) + LOAD_FUNCPTR(gnutls_pkcs12_bag_deinit) + LOAD_FUNCPTR(gnutls_pkcs12_bag_get_count) + LOAD_FUNCPTR(gnutls_pkcs12_bag_get_data) + LOAD_FUNCPTR(gnutls_pkcs12_bag_get_type) + LOAD_FUNCPTR(gnutls_pkcs12_bag_init) LOAD_FUNCPTR(gnutls_pkcs12_deinit) + LOAD_FUNCPTR(gnutls_pkcs12_get_bag) LOAD_FUNCPTR(gnutls_pkcs12_import) LOAD_FUNCPTR(gnutls_pkcs12_init) - LOAD_FUNCPTR(gnutls_pkcs12_simple_parse) + LOAD_FUNCPTR(gnutls_x509_crt_deinit) LOAD_FUNCPTR(gnutls_x509_crt_export) + LOAD_FUNCPTR(gnutls_x509_crt_import) + LOAD_FUNCPTR(gnutls_x509_crt_init) + LOAD_FUNCPTR(gnutls_x509_privkey_deinit) LOAD_FUNCPTR(gnutls_x509_privkey_export_rsa_raw2) LOAD_FUNCPTR(gnutls_x509_privkey_get_pk_algorithm2) + LOAD_FUNCPTR(gnutls_x509_privkey_import_pkcs8) + LOAD_FUNCPTR(gnutls_x509_privkey_init) #undef LOAD_FUNCPTR if ((ret = pgnutls_global_init()) != GNUTLS_E_SUCCESS) @@ -178,13 +196,16 @@ static NTSTATUS import_store_key( void *args ) struct import_store_key_params *params = args; struct cert_store_data *data = get_store_data( params->data ); int i, ret; - unsigned int bitlen = data->key_bitlen; + unsigned int bitlen; gnutls_datum_t m, e, d, p, q, u, e1, e2; BLOBHEADER *hdr; RSAPUBKEY *rsakey; BYTE *src, *dst; DWORD size; + if (!data->key) return STATUS_NOT_FOUND; + bitlen = data->key_bitlen; + size = sizeof(*hdr) + sizeof(*rsakey) + (bitlen * 9 / 16); if (!params->buf || *params->buf_size < size) { @@ -272,16 +293,136 @@ static char *password_to_ascii( const WCHAR *str ) return ret; } +static int parse_bag_datum( gnutls_pkcs12_bag_t bag, unsigned int index, const char *pwd, + gnutls_x509_crt_t *certs, unsigned int *cert_count, + gnutls_x509_privkey_t *key ) +{ + gnutls_datum_t data; + int type = pgnutls_pkcs12_bag_get_type( bag, index ); + + if (pgnutls_pkcs12_bag_get_data( bag, index, &data ) < 0) return -1; + + switch (type) + { + case GNUTLS_BAG_CERTIFICATE: + { + gnutls_x509_crt_t crt; + + if (pgnutls_x509_crt_init( &crt ) < 0) return -1; + if (pgnutls_x509_crt_import( crt, &data, GNUTLS_X509_FMT_DER ) < 0) + { + pgnutls_x509_crt_deinit( crt ); + return -1; + } + certs[(*cert_count)++] = crt; + break; + } + case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY: + case GNUTLS_BAG_PKCS8_KEY: + if (*key) break; /* already found a key */ + if (pgnutls_x509_privkey_init( key ) < 0) return -1; + if (pgnutls_x509_privkey_import_pkcs8( *key, &data, GNUTLS_X509_FMT_DER, pwd, + type == GNUTLS_BAG_PKCS8_KEY ? GNUTLS_PKCS_PLAIN : 0 ) < 0) + { + pgnutls_x509_privkey_deinit( *key ); + *key = NULL; + return -1; + } + break; + } + return 0; +} + +static int parse_pkcs12_bag( gnutls_pkcs12_t p12, unsigned int index, const char *pwd, + gnutls_x509_crt_t *certs, unsigned int *cert_count, + gnutls_x509_privkey_t *key ) +{ + gnutls_pkcs12_bag_t bag; + unsigned int j, bag_count; + int ret = -1; + + if (pgnutls_pkcs12_bag_init( &bag ) < 0) return -1; + if (pgnutls_pkcs12_get_bag( p12, index, bag ) < 0) goto done; + + if (pgnutls_pkcs12_bag_get_type( bag, 0 ) == GNUTLS_BAG_ENCRYPTED + && pgnutls_pkcs12_bag_decrypt( bag, pwd ) < 0) + goto done; + + bag_count = pgnutls_pkcs12_bag_get_count( bag ); + for (j = 0; j < bag_count; j++) + if (parse_bag_datum( bag, j, pwd, certs, cert_count, key ) < 0) goto done; + + ret = 0; +done: + pgnutls_pkcs12_bag_deinit( bag ); + return ret; +} + +static NTSTATUS parse_pkcs12_bags( gnutls_pkcs12_t p12, const char *pwd, + gnutls_x509_crt_t **certs_ret, unsigned int *cert_count_ret, + gnutls_x509_privkey_t *key_ret ) +{ + gnutls_x509_privkey_t key = NULL; + gnutls_x509_crt_t *certs = NULL; + unsigned int i, bag_count, total_items = 0, cert_count = 0; + NTSTATUS status = STATUS_INVALID_PARAMETER; + + for (i = 0; ; i++) + { + gnutls_pkcs12_bag_t bag; + int count; + + if (pgnutls_pkcs12_bag_init( &bag ) < 0) goto error; + if (pgnutls_pkcs12_get_bag( p12, i, bag ) < 0) + { + pgnutls_pkcs12_bag_deinit( bag ); + break; + } + if (pgnutls_pkcs12_bag_get_type( bag, 0 ) == GNUTLS_BAG_ENCRYPTED + && pgnutls_pkcs12_bag_decrypt( bag, pwd ) < 0) + goto error; + + count = pgnutls_pkcs12_bag_get_count( bag ); + pgnutls_pkcs12_bag_deinit( bag ); + if (count < 0) goto error; + total_items += count; + } + bag_count = i; + + if (!total_items) goto error; + if (!(certs = malloc( total_items * sizeof(*certs) ))) + { + status = STATUS_NO_MEMORY; + goto error; + } + + for (i = 0; i < bag_count; i++) + if (parse_pkcs12_bag( p12, i, pwd, certs, &cert_count, &key ) < 0) goto error; + + if (!cert_count) goto error; + + *certs_ret = certs; + *cert_count_ret = cert_count; + *key_ret = key; + return STATUS_SUCCESS; + +error: + for (i = 0; i < cert_count; i++) pgnutls_x509_crt_deinit( certs[i] ); + free( certs ); + if (key) pgnutls_x509_privkey_deinit( key ); + return status; +} + static NTSTATUS open_cert_store( void *args ) { struct open_cert_store_params *params = args; - gnutls_pkcs12_t p12; + gnutls_pkcs12_t p12 = NULL; gnutls_datum_t pfx_data; - gnutls_x509_privkey_t key; - gnutls_x509_crt_t *chain; - unsigned int chain_len; - unsigned int bitlen; + gnutls_x509_privkey_t key = NULL; + gnutls_x509_crt_t *certs = NULL; + unsigned int i, cert_count = 0, bitlen; char *pwd = NULL; + NTSTATUS status; int ret; struct cert_store_data *store_data; @@ -294,35 +435,44 @@ static NTSTATUS open_cert_store( void *args ) pfx_data.size = params->pfx->cbData; if ((ret = pgnutls_pkcs12_import( p12, &pfx_data, GNUTLS_X509_FMT_DER, 0 )) < 0) goto error; - if ((ret = pgnutls_pkcs12_simple_parse( p12, pwd ? pwd : "", &key, &chain, &chain_len, NULL, NULL, NULL, 0 )) < 0) - goto error; - - if ((ret = pgnutls_x509_privkey_get_pk_algorithm2( key, &bitlen )) < 0) - goto error; - - free( pwd ); + status = parse_pkcs12_bags( p12, pwd ? pwd : "", &certs, &cert_count, &key ); + if (status) + goto done; - if (ret != GNUTLS_PK_RSA) + if (key) { - FIXME( "key algorithm %u not supported\n", ret ); - pgnutls_pkcs12_deinit( p12 ); - return STATUS_INVALID_PARAMETER; + if ((ret = pgnutls_x509_privkey_get_pk_algorithm2( key, &bitlen )) < 0) goto error; + + if (ret != GNUTLS_PK_RSA) + { + FIXME( "key algorithm %u not supported\n", ret ); + status = STATUS_INVALID_PARAMETER; + goto done; + } } store_data = malloc( sizeof(*store_data) ); store_data->p12 = p12; store_data->key = key; - store_data->chain = chain; - store_data->key_bitlen = bitlen; - store_data->chain_len = chain_len; + store_data->chain = certs; + store_data->key_bitlen = key ? bitlen : 0; + store_data->chain_len = cert_count; + + free( pwd ); *params->data_ret = (ULONG_PTR)store_data; + *params->key_count_ret = key ? 1 : 0; return STATUS_SUCCESS; error: pgnutls_perror( ret ); - pgnutls_pkcs12_deinit( p12 ); + status = STATUS_INVALID_PARAMETER; +done: + for (i = 0; i < cert_count; i++) pgnutls_x509_crt_deinit( certs[i] ); + free( certs ); + if (key) pgnutls_x509_privkey_deinit( key ); + if (p12) pgnutls_pkcs12_deinit( p12 ); free( pwd ); - return STATUS_INVALID_PARAMETER; + return status; } static NTSTATUS import_store_cert( void *args ) @@ -355,6 +505,11 @@ static NTSTATUS close_cert_store( void *args ) if (params->data) { + unsigned int i; + for (i = 0; i < data->chain_len; i++) + pgnutls_x509_crt_deinit( data->chain[i] ); + free( data->chain ); + if (data->key) pgnutls_x509_privkey_deinit( data->key ); pgnutls_pkcs12_deinit( data->p12 ); free( data ); } @@ -721,6 +876,7 @@ static NTSTATUS wow64_open_cert_store( void *args ) PTR32 pfx; PTR32 password; PTR32 data_ret; + PTR32 key_count_ret; } const *params32 = args; const CRYPT_DATA_BLOB32 *pfx32 = ULongToPtr( params32->pfx ); @@ -729,7 +885,8 @@ static NTSTATUS wow64_open_cert_store( void *args ) { &pfx, ULongToPtr( params32->password ), - ULongToPtr( params32->data_ret ) + ULongToPtr( params32->data_ret ), + ULongToPtr( params32->key_count_ret ) }; return open_cert_store( ¶ms ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10198
From: Tatsuyuki Ishi <ishitatsuyuki@gmail.com> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52330 --- dlls/crypt32/tests/store.c | 130 +++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/dlls/crypt32/tests/store.c b/dlls/crypt32/tests/store.c index 7b7266db0b2..678d4810d8b 100644 --- a/dlls/crypt32/tests/store.c +++ b/dlls/crypt32/tests/store.c @@ -3303,6 +3303,98 @@ static const BYTE pfxdata[] = 0x69, 0x02, 0x02, 0x08, 0x00 }; +/* Cert-only PKCS#12 (no private key), empty password, legacy encryption. + * Generated with: + * openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes + * openssl pkcs12 -export -nokeys -in cert.pem -out cert_only.pfx -passout pass: -legacy + */ +static const BYTE pfx_cert_only[] = +{ + 0x30, 0x82, 0x03, 0xdc, 0x02, 0x01, 0x03, 0x30, 0x82, 0x03, 0x9a, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, + 0x03, 0x8b, 0x04, 0x82, 0x03, 0x87, 0x30, 0x82, 0x03, 0x83, 0x30, 0x82, + 0x03, 0x7f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, + 0x06, 0xa0, 0x82, 0x03, 0x70, 0x30, 0x82, 0x03, 0x6c, 0x02, 0x01, 0x00, + 0x30, 0x82, 0x03, 0x65, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x07, 0x01, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x0c, 0x01, 0x06, 0x30, 0x0e, 0x04, 0x08, 0xbc, 0xb4, 0x1e, + 0xbc, 0x95, 0xfd, 0x2a, 0x73, 0x02, 0x02, 0x08, 0x00, 0x80, 0x82, 0x03, + 0x38, 0x82, 0x05, 0xb7, 0x9d, 0x81, 0xd4, 0x12, 0xc8, 0x3f, 0x9f, 0xc7, + 0x75, 0x76, 0x42, 0x93, 0xae, 0x1f, 0xe8, 0x7d, 0x60, 0x61, 0x56, 0x14, + 0x8d, 0x22, 0x92, 0xa0, 0x08, 0x9f, 0x35, 0xf4, 0x60, 0xe2, 0x0c, 0xf6, + 0x24, 0x67, 0x66, 0x89, 0x43, 0x37, 0xfc, 0xc2, 0x69, 0x32, 0x20, 0x06, + 0x15, 0xb6, 0x01, 0xa6, 0xd5, 0xc0, 0xb0, 0xe8, 0x14, 0x80, 0xe9, 0xda, + 0x7e, 0x2e, 0x7b, 0xeb, 0xf0, 0x5d, 0x76, 0x8c, 0x26, 0xb3, 0xe7, 0xcb, + 0x02, 0x82, 0xf9, 0x50, 0x1a, 0x00, 0xcb, 0x76, 0x08, 0xbd, 0xe0, 0x4a, + 0x0a, 0x50, 0x6a, 0x93, 0x86, 0x0f, 0x0c, 0x29, 0x59, 0x26, 0xa7, 0xa0, + 0xbb, 0x09, 0x13, 0x42, 0xac, 0x15, 0x6b, 0x3e, 0xdd, 0x33, 0x4e, 0xf2, + 0xdb, 0x69, 0xed, 0xd3, 0x54, 0x6a, 0x83, 0x73, 0xba, 0xf7, 0x98, 0x88, + 0xc4, 0x61, 0xed, 0xb8, 0x1a, 0xbd, 0x82, 0x00, 0x1e, 0x53, 0x37, 0xe3, + 0xaf, 0xce, 0x6a, 0x32, 0x2f, 0x8b, 0x24, 0x47, 0x85, 0x1f, 0x0a, 0x92, + 0x22, 0x7a, 0x47, 0xd0, 0x4e, 0xb0, 0x11, 0xdd, 0x2e, 0x4d, 0xdb, 0x7c, + 0xac, 0xda, 0xa7, 0x14, 0x29, 0xce, 0x26, 0x73, 0x0d, 0xf1, 0x29, 0x80, + 0xf9, 0xe7, 0x7f, 0x0f, 0x8f, 0xde, 0x26, 0xdb, 0x75, 0x88, 0x52, 0x0e, + 0x28, 0x79, 0x29, 0x25, 0x60, 0x7e, 0x22, 0x76, 0xb0, 0x40, 0x49, 0xa1, + 0x05, 0xcc, 0xd1, 0x73, 0xdb, 0x41, 0x87, 0x34, 0xa4, 0x07, 0xce, 0x75, + 0xbf, 0x72, 0x6e, 0x43, 0x28, 0x07, 0xc7, 0x8f, 0xe3, 0xc1, 0xd3, 0x2b, + 0xb6, 0x14, 0xc0, 0xbb, 0x08, 0x31, 0x57, 0x5f, 0x41, 0x1d, 0xef, 0xe4, + 0x94, 0xe3, 0x21, 0x74, 0x2e, 0x44, 0x90, 0xa7, 0x3c, 0x54, 0x9b, 0x6f, + 0x13, 0xbe, 0x2e, 0xba, 0x7d, 0xc8, 0xf6, 0xc1, 0xf3, 0xdd, 0x0d, 0xde, + 0x46, 0xd6, 0xfc, 0xca, 0xac, 0x8b, 0xee, 0x5b, 0xa9, 0xcb, 0x02, 0xea, + 0x6e, 0xfc, 0xd0, 0x17, 0x88, 0x3f, 0xc5, 0x37, 0x8f, 0x69, 0xa0, 0xe6, + 0xf9, 0x9e, 0xf2, 0x23, 0x8f, 0x06, 0x12, 0x95, 0x6b, 0x93, 0xf7, 0x88, + 0x3e, 0xe2, 0xbb, 0x8c, 0x2d, 0x3b, 0xf7, 0xeb, 0x79, 0x66, 0x0c, 0xd2, + 0xf7, 0x00, 0x35, 0xe5, 0xa0, 0xe3, 0x33, 0xfa, 0x23, 0x3c, 0x9f, 0xc5, + 0x1d, 0x63, 0x8d, 0xc0, 0x40, 0x00, 0x17, 0x46, 0xf3, 0x43, 0x58, 0x22, + 0xd8, 0x3b, 0x90, 0xe0, 0x21, 0xd5, 0xf5, 0xec, 0xd7, 0x3e, 0x9b, 0x4d, + 0xd3, 0xf9, 0x9a, 0x31, 0x07, 0x8b, 0x5f, 0x7b, 0x63, 0xb6, 0xbb, 0xae, + 0xde, 0x2f, 0x5e, 0xad, 0x25, 0x4e, 0x46, 0x26, 0x3a, 0x36, 0x4a, 0x44, + 0x33, 0x11, 0x0a, 0xe8, 0xfb, 0x9c, 0x4c, 0x3d, 0x98, 0x9a, 0x20, 0xee, + 0x20, 0xf7, 0x0d, 0x1c, 0xd2, 0xaf, 0xb4, 0x2b, 0x05, 0x81, 0x0b, 0x61, + 0x7c, 0x4d, 0xdf, 0x5f, 0xc7, 0x2d, 0xc3, 0x96, 0xcc, 0xb4, 0xac, 0x88, + 0x7a, 0x4e, 0xcd, 0x49, 0x75, 0xe8, 0xb3, 0xea, 0x55, 0x85, 0x99, 0x2c, + 0x72, 0x60, 0xa1, 0x68, 0xc7, 0x91, 0xdf, 0x24, 0x6a, 0x5d, 0xeb, 0x0d, + 0xab, 0xb4, 0x14, 0x2f, 0x59, 0xb6, 0x68, 0x9f, 0xd8, 0xba, 0x7c, 0x8c, + 0x92, 0xb7, 0x60, 0xb0, 0x7e, 0x23, 0x84, 0x9f, 0x3a, 0xb1, 0x0b, 0xe4, + 0x12, 0x53, 0xe3, 0x4f, 0x23, 0x37, 0x90, 0x91, 0xae, 0xc1, 0x0e, 0xa4, + 0x36, 0x52, 0x9a, 0x9e, 0xea, 0x18, 0x3a, 0xf6, 0xdc, 0x48, 0x99, 0x2a, + 0x67, 0x1c, 0x70, 0x1b, 0x21, 0xa1, 0x3a, 0x85, 0x0a, 0x45, 0xe8, 0x80, + 0x12, 0x2f, 0x4b, 0x5e, 0x3b, 0x60, 0x0a, 0x5c, 0x2e, 0x7d, 0xcc, 0xb2, + 0xd0, 0xf7, 0xdb, 0xe0, 0x94, 0x14, 0x05, 0x0c, 0xa8, 0xc2, 0xd7, 0x03, + 0x2c, 0x43, 0x5a, 0xca, 0x33, 0xe2, 0x1c, 0xad, 0x70, 0x50, 0x0b, 0x96, + 0x53, 0x24, 0x27, 0x2b, 0x15, 0x8d, 0xa5, 0xc7, 0x8d, 0xd7, 0x0c, 0x1f, + 0xc7, 0x9f, 0x6c, 0x00, 0x67, 0x10, 0x08, 0x02, 0xc3, 0xd9, 0x5b, 0x95, + 0x99, 0x97, 0x8e, 0x25, 0xe8, 0xc8, 0x12, 0x9b, 0x1c, 0xb5, 0x89, 0xb1, + 0x22, 0x3b, 0xef, 0xc9, 0x42, 0x26, 0x5a, 0xe9, 0x82, 0x2e, 0xb1, 0xf2, + 0xbe, 0x41, 0xc8, 0xf5, 0x36, 0xe9, 0x4b, 0x48, 0x08, 0xfd, 0x2c, 0xf3, + 0x96, 0x85, 0xb7, 0xa3, 0xd3, 0xe0, 0xcb, 0x59, 0x93, 0x15, 0x72, 0xe7, + 0xaf, 0x93, 0x35, 0x21, 0x19, 0x68, 0xc2, 0xaf, 0x86, 0x9a, 0x93, 0xc8, + 0x06, 0xec, 0x27, 0xd2, 0x25, 0x87, 0x4f, 0x3f, 0x4f, 0x40, 0xf4, 0xa6, + 0x58, 0x5d, 0xe0, 0x17, 0xec, 0x3f, 0x14, 0xf2, 0xa8, 0xba, 0xfa, 0x38, + 0x9d, 0x15, 0x64, 0x61, 0x08, 0xda, 0xb8, 0xff, 0xd3, 0x9d, 0x64, 0x94, + 0x86, 0xa2, 0xd8, 0x03, 0xca, 0xa6, 0x01, 0xdd, 0xb9, 0xd3, 0x93, 0xef, + 0xe6, 0x58, 0x49, 0x87, 0xb4, 0xc2, 0x89, 0x34, 0xd4, 0x2a, 0x43, 0x3d, + 0x6d, 0xf6, 0x97, 0x4c, 0x3b, 0xb6, 0xcb, 0x41, 0x8b, 0x36, 0x1c, 0x0d, + 0x8a, 0xd5, 0x2b, 0x28, 0xd7, 0x02, 0x3e, 0x0e, 0xc3, 0xc6, 0x2b, 0xb5, + 0x71, 0xc7, 0x3b, 0xa9, 0x3f, 0xbe, 0x43, 0xb7, 0x0a, 0x3e, 0xfe, 0x7e, + 0xc6, 0xe2, 0xf3, 0xd3, 0xec, 0xf3, 0x96, 0x91, 0xbc, 0x08, 0x85, 0x51, + 0xea, 0x7f, 0xa8, 0x67, 0x40, 0x2d, 0x3f, 0x9b, 0x5b, 0x8d, 0xf9, 0xcb, + 0xd5, 0x07, 0x9d, 0x4b, 0xf0, 0x89, 0x4e, 0x6c, 0xf8, 0xf3, 0xc9, 0x47, + 0x70, 0x9a, 0xff, 0xbe, 0x63, 0xd4, 0xdf, 0x0b, 0xdd, 0xbe, 0xc6, 0x33, + 0x9d, 0xd3, 0xfa, 0x03, 0x91, 0x3a, 0x45, 0x1d, 0x05, 0xa0, 0xd0, 0x6e, + 0x45, 0x21, 0x60, 0x48, 0xda, 0x4f, 0x41, 0x7e, 0x0f, 0xe5, 0xec, 0xec, + 0x75, 0x8d, 0x73, 0x26, 0x36, 0xa9, 0x6a, 0xc1, 0x4b, 0x99, 0x5f, 0x04, + 0x8a, 0xac, 0xe1, 0x32, 0x2e, 0xa1, 0xfb, 0x86, 0xcd, 0x9f, 0xdd, 0x61, + 0x15, 0xef, 0xf8, 0x3f, 0xeb, 0x41, 0x54, 0x1e, 0xb0, 0xa5, 0x7f, 0x41, + 0x7f, 0xbf, 0xd8, 0x58, 0x3a, 0x80, 0x11, 0x4d, 0x7a, 0xd6, 0x37, 0x13, + 0x1f, 0xd4, 0xb4, 0x25, 0x9b, 0x82, 0x26, 0x60, 0x99, 0x30, 0x39, 0x30, + 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, + 0x04, 0x14, 0x34, 0xa9, 0x11, 0xce, 0xfe, 0xe2, 0x68, 0xff, 0x42, 0x47, + 0xea, 0x7a, 0xfc, 0xe9, 0x5a, 0xed, 0x69, 0x5a, 0x63, 0x9a, 0x04, 0x10, + 0xe5, 0xeb, 0x13, 0x32, 0xa7, 0x47, 0x9b, 0xf8, 0x2f, 0x66, 0x41, 0x01, + 0x1e, 0xc6, 0x23, 0x55, 0x02, 0x02, 0x08, 0x00 +}; + static void test_PFXImportCertStore(void) { HCERTSTORE store; @@ -3320,6 +3412,44 @@ static void test_PFXImportCertStore(void) ok( store == NULL, "got %p\n", store ); ok( GetLastError() == ERROR_INVALID_PARAMETER, "got %lu\n", GetLastError() ); + /* cert-only PKCS#12 (no private key), empty password */ + pfx.pbData = (BYTE *)pfx_cert_only; + pfx.cbData = sizeof(pfx_cert_only); + + ret = PFXIsPFXBlob( &pfx ); + ok( ret, "got %lu\n", GetLastError() ); + + store = PFXImportCertStore( &pfx, L"", 0 ); + ok( store != NULL, "got %lu\n", GetLastError() ); + if (store) + { + count = countCertsInStore( store ); + ok( count == 1, "got %lu\n", count ); + + cert = CertFindCertificateInStore( store, X509_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, NULL ); + ok( cert != NULL, "got %lu\n", GetLastError() ); + if (cert) + { + ok( cert->dwCertEncodingType == X509_ASN_ENCODING, "got %lu\n", cert->dwCertEncodingType ); + ok( cert->pbCertEncoded != NULL, "pbCertEncoded not set\n" ); + ok( cert->pCertInfo != NULL, "pCertInfo not set\n" ); + + /* no private key should be associated */ + size = sizeof(key); + SetLastError( 0xdeadbeef ); + ret = CertGetCertificateContextProperty( cert, CERT_KEY_CONTEXT_PROP_ID, &key, &size ); + ok( !ret && GetLastError() == CRYPT_E_NOT_FOUND, "got %08lx\n", GetLastError() ); + + size = sizeof(buf); + SetLastError( 0xdeadbeef ); + ret = CertGetCertificateContextProperty( cert, CERT_KEY_PROV_INFO_PROP_ID, keyprov, &size ); + ok( !ret && GetLastError() == CRYPT_E_NOT_FOUND, "got %08lx\n", GetLastError() ); + + CertFreeCertificateContext( cert ); + } + CertCloseStore( store, 0 ); + } + pfx.pbData = (BYTE *)pfxdata; pfx.cbData = sizeof(pfxdata); store = PFXImportCertStore( &pfx, NULL, CRYPT_EXPORTABLE|CRYPT_USER_KEYSET|PKCS12_NO_PERSIST_KEY ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10198
From: Tatsuyuki Ishi <ishitatsuyuki@gmail.com> The gnutls_pkcs12_simple_parse man page tells you to verify the MAC before calling parse. Do the verification after import, which was where previously we would have called simple_parse. --- dlls/crypt32/unixlib.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/crypt32/unixlib.c b/dlls/crypt32/unixlib.c index 89be8b67ba3..5bffd6e6242 100644 --- a/dlls/crypt32/unixlib.c +++ b/dlls/crypt32/unixlib.c @@ -70,6 +70,7 @@ MAKE_FUNCPTR(gnutls_pkcs12_deinit); MAKE_FUNCPTR(gnutls_pkcs12_get_bag); MAKE_FUNCPTR(gnutls_pkcs12_import); MAKE_FUNCPTR(gnutls_pkcs12_init); +MAKE_FUNCPTR(gnutls_pkcs12_verify_mac); MAKE_FUNCPTR(gnutls_x509_crt_deinit); MAKE_FUNCPTR(gnutls_x509_crt_export); MAKE_FUNCPTR(gnutls_x509_crt_import); @@ -129,6 +130,7 @@ static NTSTATUS process_attach( void *args ) LOAD_FUNCPTR(gnutls_pkcs12_get_bag) LOAD_FUNCPTR(gnutls_pkcs12_import) LOAD_FUNCPTR(gnutls_pkcs12_init) + LOAD_FUNCPTR(gnutls_pkcs12_verify_mac) LOAD_FUNCPTR(gnutls_x509_crt_deinit) LOAD_FUNCPTR(gnutls_x509_crt_export) LOAD_FUNCPTR(gnutls_x509_crt_import) @@ -434,6 +436,7 @@ static NTSTATUS open_cert_store( void *args ) pfx_data.data = params->pfx->pbData; pfx_data.size = params->pfx->cbData; if ((ret = pgnutls_pkcs12_import( p12, &pfx_data, GNUTLS_X509_FMT_DER, 0 )) < 0) goto error; + if ((ret = pgnutls_pkcs12_verify_mac( p12, pwd ? pwd : "" )) < 0) goto error; status = parse_pkcs12_bags( p12, pwd ? pwd : "", &certs, &cert_count, &key ); if (status) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10198
Hans Leidekker (@hans) commented about dlls/crypt32/unixlib.c:
+ NTSTATUS status = STATUS_INVALID_PARAMETER; + + for (i = 0; ; i++) + { + gnutls_pkcs12_bag_t bag; + int count; + + if (pgnutls_pkcs12_bag_init( &bag ) < 0) goto error; + if (pgnutls_pkcs12_get_bag( p12, i, bag ) < 0) + { + pgnutls_pkcs12_bag_deinit( bag ); + break; + } + if (pgnutls_pkcs12_bag_get_type( bag, 0 ) == GNUTLS_BAG_ENCRYPTED + && pgnutls_pkcs12_bag_decrypt( bag, pwd ) < 0) + goto error; bag should be cleaned up here.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10198#note_130699
Looks good, thanks! -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10198#note_130700
participants (3)
-
Hans Leidekker (@hans) -
Tatsuyuki Ishi -
Tatsuyuki Ishi (@ishitatsuyuki)