setupapi/tests: Remove win_9x checks.
[wine.git] / dlls / crypt32 / pfx.c
bloba51558558699139a8bda4c71b4d877a774842ba3
1 /*
2 * Copyright 2019 Hans Leidekker for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "config.h"
20 #include "wine/port.h"
22 #include <stdarg.h>
23 #ifdef SONAME_LIBGNUTLS
24 #include <gnutls/pkcs12.h>
25 #endif
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wincrypt.h"
30 #include "snmp.h"
32 #include "wine/debug.h"
33 #include "wine/heap.h"
34 #include "wine/library.h"
35 #include "wine/unicode.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
39 #ifdef SONAME_LIBGNUTLS
40 WINE_DECLARE_DEBUG_CHANNEL(winediag);
42 /* Not present in gnutls version < 3.0 */
43 int gnutls_pkcs12_simple_parse(gnutls_pkcs12_t p12, const char *password,
44 gnutls_x509_privkey_t *key, gnutls_x509_crt_t **chain, unsigned int *chain_len,
45 gnutls_x509_crt_t **extra_certs, unsigned int *extra_certs_len,
46 gnutls_x509_crl_t * crl, unsigned int flags);
48 int gnutls_x509_privkey_get_pk_algorithm2(gnutls_x509_privkey_t, unsigned int*);
50 static void *libgnutls_handle;
51 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
52 MAKE_FUNCPTR(gnutls_global_deinit);
53 MAKE_FUNCPTR(gnutls_global_init);
54 MAKE_FUNCPTR(gnutls_global_set_log_function);
55 MAKE_FUNCPTR(gnutls_global_set_log_level);
56 MAKE_FUNCPTR(gnutls_perror);
57 MAKE_FUNCPTR(gnutls_pkcs12_deinit);
58 MAKE_FUNCPTR(gnutls_pkcs12_import);
59 MAKE_FUNCPTR(gnutls_pkcs12_init);
60 MAKE_FUNCPTR(gnutls_pkcs12_simple_parse);
61 MAKE_FUNCPTR(gnutls_x509_crt_export);
62 MAKE_FUNCPTR(gnutls_x509_privkey_export_rsa_raw2);
63 MAKE_FUNCPTR(gnutls_x509_privkey_get_pk_algorithm2);
64 #undef MAKE_FUNCPTR
66 static void gnutls_log( int level, const char *msg )
68 TRACE( "<%d> %s", level, msg );
71 BOOL gnutls_initialize(void)
73 int ret;
75 if (!(libgnutls_handle = wine_dlopen( SONAME_LIBGNUTLS, RTLD_NOW, NULL, 0 )))
77 ERR_(winediag)( "failed to load libgnutls, no support for pfx import/export\n" );
78 return FALSE;
81 #define LOAD_FUNCPTR(f) \
82 if (!(p##f = wine_dlsym( libgnutls_handle, #f, NULL, 0 ))) \
83 { \
84 ERR( "failed to load %s\n", #f ); \
85 goto fail; \
88 LOAD_FUNCPTR(gnutls_global_deinit)
89 LOAD_FUNCPTR(gnutls_global_init)
90 LOAD_FUNCPTR(gnutls_global_set_log_function)
91 LOAD_FUNCPTR(gnutls_global_set_log_level)
92 LOAD_FUNCPTR(gnutls_perror)
93 LOAD_FUNCPTR(gnutls_pkcs12_deinit)
94 LOAD_FUNCPTR(gnutls_pkcs12_import)
95 LOAD_FUNCPTR(gnutls_pkcs12_init)
96 LOAD_FUNCPTR(gnutls_pkcs12_simple_parse)
97 LOAD_FUNCPTR(gnutls_x509_crt_export)
98 LOAD_FUNCPTR(gnutls_x509_privkey_export_rsa_raw2)
99 LOAD_FUNCPTR(gnutls_x509_privkey_get_pk_algorithm2)
100 #undef LOAD_FUNCPTR
102 if ((ret = pgnutls_global_init()) != GNUTLS_E_SUCCESS)
104 pgnutls_perror( ret );
105 goto fail;
108 if (TRACE_ON( crypt ))
110 pgnutls_global_set_log_level( 4 );
111 pgnutls_global_set_log_function( gnutls_log );
114 return TRUE;
116 fail:
117 wine_dlclose( libgnutls_handle, NULL, 0 );
118 libgnutls_handle = NULL;
119 return FALSE;
122 void gnutls_uninitialize(void)
124 pgnutls_global_deinit();
125 wine_dlclose( libgnutls_handle, NULL, 0 );
126 libgnutls_handle = NULL;
129 #define RSA_MAGIC_KEY ('R' | ('S' << 8) | ('A' << 16) | ('2' << 24))
130 #define RSA_PUBEXP 65537
132 static HCRYPTPROV import_key( gnutls_x509_privkey_t key, DWORD flags )
134 int i, ret;
135 unsigned int bitlen;
136 gnutls_datum_t m, e, d, p, q, u, e1, e2;
137 BLOBHEADER *hdr;
138 RSAPUBKEY *rsakey;
139 HCRYPTPROV prov = 0;
140 HCRYPTKEY cryptkey;
141 BYTE *buf, *src, *dst;
142 DWORD size;
144 if ((ret = pgnutls_x509_privkey_get_pk_algorithm2( key, &bitlen )) < 0)
146 pgnutls_perror( ret );
147 return 0;
150 if (ret != GNUTLS_PK_RSA)
152 FIXME( "key algorithm %u not supported\n", ret );
153 return 0;
156 if ((ret = pgnutls_x509_privkey_export_rsa_raw2( key, &m, &e, &d, &p, &q, &u, &e1, &e2 )) < 0)
158 pgnutls_perror( ret );
159 return 0;
162 size = sizeof(*hdr) + sizeof(*rsakey) + (bitlen * 9 / 16);
163 if (!(buf = heap_alloc( size ))) goto done;
165 hdr = (BLOBHEADER *)buf;
166 hdr->bType = PRIVATEKEYBLOB;
167 hdr->bVersion = CUR_BLOB_VERSION;
168 hdr->reserved = 0;
169 hdr->aiKeyAlg = CALG_RSA_KEYX;
171 rsakey = (RSAPUBKEY *)(hdr + 1);
172 rsakey->magic = RSA_MAGIC_KEY;
173 rsakey->bitlen = bitlen;
174 rsakey->pubexp = RSA_PUBEXP;
176 dst = (BYTE *)(rsakey + 1);
177 if (m.size == bitlen / 8 + 1 && !m.data[0]) src = m.data + 1;
178 else if (m.size != bitlen / 8) goto done;
179 else src = m.data;
180 for (i = bitlen / 8 - 1; i >= 0; i--) *dst++ = src[i];
182 if (p.size == bitlen / 16 + 1 && !p.data[0]) src = p.data + 1;
183 else if (p.size != bitlen / 16) goto done;
184 else src = p.data;
185 for (i = bitlen / 16 - 1; i >= 0; i--) *dst++ = src[i];
187 if (q.size == bitlen / 16 + 1 && !q.data[0]) src = q.data + 1;
188 else if (q.size != bitlen / 16) goto done;
189 else src = q.data;
190 for (i = bitlen / 16 - 1; i >= 0; i--) *dst++ = src[i];
192 if (e1.size == bitlen / 16 + 1 && !e1.data[0]) src = e1.data + 1;
193 else if (e1.size != bitlen / 16) goto done;
194 else src = e1.data;
195 for (i = bitlen / 16 - 1; i >= 0; i--) *dst++ = src[i];
197 if (e2.size == bitlen / 16 + 1 && !e2.data[0]) src = e2.data + 1;
198 else if (e2.size != bitlen / 16) goto done;
199 else src = e2.data;
200 for (i = bitlen / 16 - 1; i >= 0; i--) *dst++ = src[i];
202 if (u.size == bitlen / 16 + 1 && !u.data[0]) src = u.data + 1;
203 else if (u.size != bitlen / 16) goto done;
204 else src = u.data;
205 for (i = bitlen / 16 - 1; i >= 0; i--) *dst++ = src[i];
207 if (d.size == bitlen / 8 + 1 && !d.data[0]) src = d.data + 1;
208 else if (d.size != bitlen / 8) goto done;
209 else src = d.data;
210 for (i = bitlen / 8 - 1; i >= 0; i--) *dst++ = src[i];
212 if (!CryptAcquireContextW( &prov, NULL, MS_ENHANCED_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET ))
214 if (GetLastError() != NTE_EXISTS) goto done;
215 if (!CryptAcquireContextW( &prov, NULL, MS_ENHANCED_PROV_W, PROV_RSA_FULL, 0 ))
217 WARN( "CryptAcquireContextW failed %08x\n", GetLastError() );
218 goto done;
222 if (!CryptImportKey( prov, buf, size, 0, flags, &cryptkey ))
224 WARN( "CryptImportKey failed %08x\n", GetLastError() );
225 CryptReleaseContext( prov, 0 );
226 prov = 0;
228 else CryptDestroyKey( cryptkey );
230 done:
231 free( m.data );
232 free( e.data );
233 free( d.data );
234 free( p.data );
235 free( q.data );
236 free( u.data );
237 free( e1.data );
238 free( e2.data );
239 heap_free( buf );
240 return prov;
243 static char *password_to_ascii( const WCHAR *str )
245 char *ret;
246 unsigned int i = 0;
248 if (!(ret = heap_alloc( (strlenW(str) + 1) * sizeof(*ret) ))) return NULL;
249 while (*str)
251 if (*str > 0x7f) WARN( "password contains non-ascii characters\n" );
252 ret[i++] = *str++;
254 ret[i] = 0;
255 return ret;
258 #endif
260 HCERTSTORE WINAPI PFXImportCertStore( CRYPT_DATA_BLOB *pfx, const WCHAR *password, DWORD flags )
262 #ifdef SONAME_LIBGNUTLS
263 gnutls_pkcs12_t p12;
264 gnutls_datum_t pfx_data;
265 gnutls_x509_privkey_t key;
266 gnutls_x509_crt_t *chain;
267 unsigned int chain_len, i;
268 HCERTSTORE store = NULL;
269 CERT_KEY_CONTEXT key_ctx;
270 HCRYPTPROV prov = 0;
271 char *pwd = NULL;
272 int ret;
274 TRACE( "(%p, %p, %08x)\n", pfx, password, flags );
275 if (!pfx)
277 SetLastError( ERROR_INVALID_PARAMETER );
278 return NULL;
280 if (flags & ~(CRYPT_EXPORTABLE|CRYPT_USER_KEYSET|PKCS12_NO_PERSIST_KEY))
282 FIXME( "flags %08x not supported\n", flags );
283 return NULL;
285 if (password && !(pwd = password_to_ascii( password ))) return NULL;
287 if ((ret = pgnutls_pkcs12_init( &p12 )) < 0)
289 pgnutls_perror( ret );
290 goto error;
293 pfx_data.data = pfx->pbData;
294 pfx_data.size = pfx->cbData;
295 if ((ret = pgnutls_pkcs12_import( p12, &pfx_data, GNUTLS_X509_FMT_DER, 0 )) < 0)
297 pgnutls_perror( ret );
298 goto error;
301 if ((ret = pgnutls_pkcs12_simple_parse( p12, pwd ? pwd : "", &key, &chain, &chain_len, NULL, NULL, NULL, 0 )) < 0)
303 pgnutls_perror( ret );
304 goto error;
307 if (!(prov = import_key( key, flags & CRYPT_EXPORTABLE ))) goto error;
308 if (!(store = CertOpenStore( CERT_STORE_PROV_MEMORY, 0, 0, 0, NULL )))
310 WARN( "CertOpenStore failed %08x\n", GetLastError() );
311 goto error;
314 if (chain_len > 1) FIXME( "handle certificate chain\n" );
315 for (i = 0; i < chain_len; i++)
317 const void *ctx;
318 BYTE *crt_data;
319 size_t size = 0;
321 if ((ret = pgnutls_x509_crt_export( chain[i], GNUTLS_X509_FMT_DER, NULL, &size )) != GNUTLS_E_SHORT_MEMORY_BUFFER)
323 pgnutls_perror( ret );
324 goto error;
327 if (!(crt_data = heap_alloc( size ))) goto error;
328 if ((ret = pgnutls_x509_crt_export( chain[i], GNUTLS_X509_FMT_DER, crt_data, &size )) < 0)
330 pgnutls_perror( ret );
331 heap_free( crt_data );
332 goto error;
335 if (!(ctx = CertCreateContext( CERT_STORE_CERTIFICATE_CONTEXT, X509_ASN_ENCODING, crt_data, size, 0, NULL )))
337 WARN( "CertCreateContext failed %08x\n", GetLastError() );
338 heap_free( crt_data );
339 goto error;
341 heap_free( crt_data );
343 key_ctx.cbSize = sizeof(key_ctx);
344 key_ctx.hCryptProv = prov;
345 key_ctx.dwKeySpec = AT_KEYEXCHANGE;
346 if (!CertSetCertificateContextProperty( ctx, CERT_KEY_CONTEXT_PROP_ID, 0, &key_ctx ))
348 WARN( "CertSetCertificateContextProperty failed %08x\n", GetLastError() );
349 CertFreeCertificateContext( ctx );
350 goto error;
353 if (!CertAddCertificateContextToStore( store, ctx, CERT_STORE_ADD_ALWAYS, NULL ))
355 WARN( "CertAddCertificateContextToStore failed %08x\n", GetLastError() );
356 CertFreeCertificateContext( ctx );
357 goto error;
359 CertFreeCertificateContext( ctx );
362 pgnutls_pkcs12_deinit( p12 );
363 return store;
365 error:
366 CryptReleaseContext( prov, 0 );
367 CertCloseStore( store, 0 );
368 pgnutls_pkcs12_deinit( p12 );
369 heap_free( pwd );
370 return NULL;
372 #endif
373 FIXME( "(%p, %p, %08x)\n", pfx, password, flags );
374 return NULL;
377 BOOL WINAPI PFXVerifyPassword( CRYPT_DATA_BLOB *pfx, const WCHAR *password, DWORD flags )
379 FIXME( "(%p, %p, %08x): stub\n", pfx, password, flags );
380 return FALSE;
383 BOOL WINAPI PFXExportCertStore( HCERTSTORE store, CRYPT_DATA_BLOB *pfx, const WCHAR *password, DWORD flags )
385 return PFXExportCertStoreEx( store, pfx, password, NULL, flags );
388 BOOL WINAPI PFXExportCertStoreEx( HCERTSTORE store, CRYPT_DATA_BLOB *pfx, const WCHAR *password, void *reserved,
389 DWORD flags )
391 FIXME( "(%p, %p, %p, %p, %08x): stub\n", store, pfx, password, reserved, flags );
392 return FALSE;