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
33 #include <Security/Security.h>
35 #ifdef SONAME_LIBGNUTLS
36 #include <gnutls/pkcs12.h>
40 #define WIN32_NO_STATUS
45 #include "crypt32_private.h"
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(crypt
);
50 #ifdef SONAME_LIBGNUTLS
52 WINE_DECLARE_DEBUG_CHANNEL(winediag
);
54 /* Not present in gnutls version < 3.0 */
55 int gnutls_pkcs12_simple_parse(gnutls_pkcs12_t p12
, const char *password
,
56 gnutls_x509_privkey_t
*key
, gnutls_x509_crt_t
**chain
, unsigned int *chain_len
,
57 gnutls_x509_crt_t
**extra_certs
, unsigned int *extra_certs_len
,
58 gnutls_x509_crl_t
* crl
, unsigned int flags
);
60 int gnutls_x509_privkey_get_pk_algorithm2(gnutls_x509_privkey_t
, unsigned int*);
62 static void *libgnutls_handle
;
63 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
64 MAKE_FUNCPTR(gnutls_global_deinit
);
65 MAKE_FUNCPTR(gnutls_global_init
);
66 MAKE_FUNCPTR(gnutls_global_set_log_function
);
67 MAKE_FUNCPTR(gnutls_global_set_log_level
);
68 MAKE_FUNCPTR(gnutls_perror
);
69 MAKE_FUNCPTR(gnutls_pkcs12_deinit
);
70 MAKE_FUNCPTR(gnutls_pkcs12_import
);
71 MAKE_FUNCPTR(gnutls_pkcs12_init
);
72 MAKE_FUNCPTR(gnutls_pkcs12_simple_parse
);
73 MAKE_FUNCPTR(gnutls_x509_crt_export
);
74 MAKE_FUNCPTR(gnutls_x509_privkey_export_rsa_raw2
);
75 MAKE_FUNCPTR(gnutls_x509_privkey_get_pk_algorithm2
);
78 static void gnutls_log( int level
, const char *msg
)
80 TRACE( "<%d> %s", level
, msg
);
83 static NTSTATUS
process_attach( void *args
)
88 if ((env_str
= getenv("GNUTLS_SYSTEM_PRIORITY_FILE")))
90 WARN("GNUTLS_SYSTEM_PRIORITY_FILE is %s.\n", debugstr_a(env_str
));
94 WARN("Setting GNUTLS_SYSTEM_PRIORITY_FILE to \"/dev/null\".\n");
95 setenv("GNUTLS_SYSTEM_PRIORITY_FILE", "/dev/null", 0);
98 if (!(libgnutls_handle
= dlopen( SONAME_LIBGNUTLS
, RTLD_NOW
)))
100 ERR_(winediag
)( "failed to load libgnutls, no support for pfx import/export\n" );
101 return STATUS_DLL_NOT_FOUND
;
104 #define LOAD_FUNCPTR(f) \
105 if (!(p##f = dlsym( libgnutls_handle, #f ))) \
107 ERR( "failed to load %s\n", #f ); \
111 LOAD_FUNCPTR(gnutls_global_deinit
)
112 LOAD_FUNCPTR(gnutls_global_init
)
113 LOAD_FUNCPTR(gnutls_global_set_log_function
)
114 LOAD_FUNCPTR(gnutls_global_set_log_level
)
115 LOAD_FUNCPTR(gnutls_perror
)
116 LOAD_FUNCPTR(gnutls_pkcs12_deinit
)
117 LOAD_FUNCPTR(gnutls_pkcs12_import
)
118 LOAD_FUNCPTR(gnutls_pkcs12_init
)
119 LOAD_FUNCPTR(gnutls_pkcs12_simple_parse
)
120 LOAD_FUNCPTR(gnutls_x509_crt_export
)
121 LOAD_FUNCPTR(gnutls_x509_privkey_export_rsa_raw2
)
122 LOAD_FUNCPTR(gnutls_x509_privkey_get_pk_algorithm2
)
125 if ((ret
= pgnutls_global_init()) != GNUTLS_E_SUCCESS
)
127 pgnutls_perror( ret
);
131 if (TRACE_ON( crypt
))
133 pgnutls_global_set_log_level( 4 );
134 pgnutls_global_set_log_function( gnutls_log
);
140 dlclose( libgnutls_handle
);
141 libgnutls_handle
= NULL
;
142 return STATUS_DLL_INIT_FAILED
;
145 static NTSTATUS
process_detach( void *args
)
147 pgnutls_global_deinit();
148 dlclose( libgnutls_handle
);
149 libgnutls_handle
= NULL
;
150 return STATUS_SUCCESS
;
152 #define RSA_MAGIC_KEY ('R' | ('S' << 8) | ('A' << 16) | ('2' << 24))
153 #define RSA_PUBEXP 65537
155 struct cert_store_data
158 gnutls_x509_privkey_t key
;
159 gnutls_x509_crt_t
*chain
;
160 unsigned int key_bitlen
;
161 unsigned int chain_len
;
164 static struct cert_store_data
*get_store_data( cert_store_data_t data
)
166 return (struct cert_store_data
*)(ULONG_PTR
)data
;
169 static NTSTATUS
import_store_key( void *args
)
171 struct import_store_key_params
*params
= args
;
172 struct cert_store_data
*data
= get_store_data( params
->data
);
174 unsigned int bitlen
= data
->key_bitlen
;
175 gnutls_datum_t m
, e
, d
, p
, q
, u
, e1
, e2
;
181 size
= sizeof(*hdr
) + sizeof(*rsakey
) + (bitlen
* 9 / 16);
182 if (!params
->buf
|| *params
->buf_size
< size
)
184 *params
->buf_size
= size
;
185 return STATUS_BUFFER_TOO_SMALL
;
188 if ((ret
= pgnutls_x509_privkey_export_rsa_raw2( data
->key
, &m
, &e
, &d
, &p
, &q
, &u
, &e1
, &e2
)) < 0)
190 pgnutls_perror( ret
);
191 return STATUS_INVALID_PARAMETER
;
195 hdr
->bType
= PRIVATEKEYBLOB
;
196 hdr
->bVersion
= CUR_BLOB_VERSION
;
198 hdr
->aiKeyAlg
= CALG_RSA_KEYX
;
200 rsakey
= (RSAPUBKEY
*)(hdr
+ 1);
201 rsakey
->magic
= RSA_MAGIC_KEY
;
202 rsakey
->bitlen
= bitlen
;
203 rsakey
->pubexp
= RSA_PUBEXP
;
205 dst
= (BYTE
*)(rsakey
+ 1);
206 if (m
.size
== bitlen
/ 8 + 1 && !m
.data
[0]) src
= m
.data
+ 1;
207 else if (m
.size
!= bitlen
/ 8) goto done
;
209 for (i
= bitlen
/ 8 - 1; i
>= 0; i
--) *dst
++ = src
[i
];
211 if (p
.size
== bitlen
/ 16 + 1 && !p
.data
[0]) src
= p
.data
+ 1;
212 else if (p
.size
!= bitlen
/ 16) goto done
;
214 for (i
= bitlen
/ 16 - 1; i
>= 0; i
--) *dst
++ = src
[i
];
216 if (q
.size
== bitlen
/ 16 + 1 && !q
.data
[0]) src
= q
.data
+ 1;
217 else if (q
.size
!= bitlen
/ 16) goto done
;
219 for (i
= bitlen
/ 16 - 1; i
>= 0; i
--) *dst
++ = src
[i
];
221 if (e1
.size
== bitlen
/ 16 + 1 && !e1
.data
[0]) src
= e1
.data
+ 1;
222 else if (e1
.size
!= bitlen
/ 16) goto done
;
224 for (i
= bitlen
/ 16 - 1; i
>= 0; i
--) *dst
++ = src
[i
];
226 if (e2
.size
== bitlen
/ 16 + 1 && !e2
.data
[0]) src
= e2
.data
+ 1;
227 else if (e2
.size
!= bitlen
/ 16) goto done
;
229 for (i
= bitlen
/ 16 - 1; i
>= 0; i
--) *dst
++ = src
[i
];
231 if (u
.size
== bitlen
/ 16 + 1 && !u
.data
[0]) src
= u
.data
+ 1;
232 else if (u
.size
!= bitlen
/ 16) goto done
;
234 for (i
= bitlen
/ 16 - 1; i
>= 0; i
--) *dst
++ = src
[i
];
236 if (d
.size
== bitlen
/ 8 + 1 && !d
.data
[0]) src
= d
.data
+ 1;
237 else if (d
.size
!= bitlen
/ 8) goto done
;
239 for (i
= bitlen
/ 8 - 1; i
>= 0; i
--) *dst
++ = src
[i
];
250 return STATUS_SUCCESS
;
253 static char *password_to_ascii( const WCHAR
*str
)
258 if (!(ret
= malloc( (lstrlenW(str
) + 1) * sizeof(*ret
) ))) return NULL
;
261 if (*str
> 0x7f) WARN( "password contains non-ascii characters\n" );
268 static NTSTATUS
open_cert_store( void *args
)
270 struct open_cert_store_params
*params
= args
;
272 gnutls_datum_t pfx_data
;
273 gnutls_x509_privkey_t key
;
274 gnutls_x509_crt_t
*chain
;
275 unsigned int chain_len
;
279 struct cert_store_data
*store_data
;
281 if (!libgnutls_handle
) return STATUS_DLL_NOT_FOUND
;
282 if (params
->password
&& !(pwd
= password_to_ascii( params
->password
))) return STATUS_NO_MEMORY
;
284 if ((ret
= pgnutls_pkcs12_init( &p12
)) < 0) goto error
;
286 pfx_data
.data
= params
->pfx
->pbData
;
287 pfx_data
.size
= params
->pfx
->cbData
;
288 if ((ret
= pgnutls_pkcs12_import( p12
, &pfx_data
, GNUTLS_X509_FMT_DER
, 0 )) < 0) goto error
;
290 if ((ret
= pgnutls_pkcs12_simple_parse( p12
, pwd
? pwd
: "", &key
, &chain
, &chain_len
, NULL
, NULL
, NULL
, 0 )) < 0)
293 if ((ret
= pgnutls_x509_privkey_get_pk_algorithm2( key
, &bitlen
)) < 0)
298 if (ret
!= GNUTLS_PK_RSA
)
300 FIXME( "key algorithm %u not supported\n", ret
);
301 pgnutls_pkcs12_deinit( p12
);
302 return STATUS_INVALID_PARAMETER
;
305 store_data
= malloc( sizeof(*store_data
) );
306 store_data
->p12
= p12
;
307 store_data
->key
= key
;
308 store_data
->chain
= chain
;
309 store_data
->key_bitlen
= bitlen
;
310 store_data
->chain_len
= chain_len
;
311 *params
->data_ret
= (ULONG_PTR
)store_data
;
312 return STATUS_SUCCESS
;
315 pgnutls_perror( ret
);
316 pgnutls_pkcs12_deinit( p12
);
318 return STATUS_INVALID_PARAMETER
;
321 static NTSTATUS
import_store_cert( void *args
)
323 struct import_store_cert_params
*params
= args
;
324 struct cert_store_data
*data
= get_store_data( params
->data
);
328 if (params
->index
>= data
->chain_len
) return STATUS_NO_MORE_ENTRIES
;
330 if ((ret
= pgnutls_x509_crt_export( data
->chain
[params
->index
], GNUTLS_X509_FMT_DER
, NULL
, &size
)) != GNUTLS_E_SHORT_MEMORY_BUFFER
)
331 return STATUS_INVALID_PARAMETER
;
333 if (!params
->buf
|| *params
->buf_size
< size
)
335 *params
->buf_size
= size
;
336 return STATUS_BUFFER_TOO_SMALL
;
338 if ((ret
= pgnutls_x509_crt_export( data
->chain
[params
->index
], GNUTLS_X509_FMT_DER
, params
->buf
, &size
)) < 0)
339 return STATUS_INVALID_PARAMETER
;
341 return STATUS_SUCCESS
;
344 static NTSTATUS
close_cert_store( void *args
)
346 struct close_cert_store_params
*params
= args
;
347 struct cert_store_data
*data
= get_store_data( params
->data
);
351 pgnutls_pkcs12_deinit( data
->p12
);
354 return STATUS_SUCCESS
;
357 #else /* SONAME_LIBGNUTLS */
359 static NTSTATUS
process_attach( void *args
) { return STATUS_SUCCESS
; }
360 static NTSTATUS
process_detach( void *args
) { return STATUS_SUCCESS
; }
361 static NTSTATUS
open_cert_store( void *args
) { return STATUS_DLL_NOT_FOUND
; }
362 static NTSTATUS
import_store_key( void *args
) { return STATUS_DLL_NOT_FOUND
; }
363 static NTSTATUS
import_store_cert( void *args
) { return STATUS_DLL_NOT_FOUND
; }
364 static NTSTATUS
close_cert_store( void *args
) { return STATUS_DLL_NOT_FOUND
; }
366 #endif /* SONAME_LIBGNUTLS */
375 static struct list root_cert_list
= LIST_INIT(root_cert_list
);
377 static BYTE
*add_cert( SIZE_T size
)
379 struct root_cert
*cert
= malloc( offsetof( struct root_cert
, data
[size
] ));
381 if (!cert
) return NULL
;
383 list_add_tail( &root_cert_list
, &cert
->entry
);
394 static inline void reset_buffer(struct DynamicBuffer
*buffer
)
397 if (buffer
->data
) buffer
->data
[0] = 0;
400 static void add_line_to_buffer(struct DynamicBuffer
*buffer
, LPCSTR line
)
402 if (buffer
->used
+ strlen(line
) + 1 > buffer
->allocated
)
404 DWORD new_size
= max( max( buffer
->allocated
* 2, 1024 ), buffer
->used
+ strlen(line
) + 1 );
405 void *ptr
= realloc( buffer
->data
, new_size
);
408 buffer
->allocated
= new_size
;
409 if (!buffer
->used
) buffer
->data
[0] = 0;
411 strcpy( buffer
->data
+ buffer
->used
, line
);
412 buffer
->used
+= strlen(line
);
415 #define BASE64_DECODE_PADDING 0x100
416 #define BASE64_DECODE_WHITESPACE 0x200
417 #define BASE64_DECODE_INVALID 0x300
419 static inline int decodeBase64Byte(char c
)
421 int ret
= BASE64_DECODE_INVALID
;
423 if (c
>= 'A' && c
<= 'Z')
425 else if (c
>= 'a' && c
<= 'z')
427 else if (c
>= '0' && c
<= '9')
434 ret
= BASE64_DECODE_PADDING
;
435 else if (c
== ' ' || c
== '\t' || c
== '\r' || c
== '\n')
436 ret
= BASE64_DECODE_WHITESPACE
;
440 static BOOL
base64_to_cert( const char *str
)
442 DWORD i
, valid
, out
, hasPadding
;
443 BYTE block
[4], *data
;
445 for (i
= valid
= out
= hasPadding
= 0; str
[i
]; i
++)
447 int d
= decodeBase64Byte( str
[i
] );
448 if (d
== BASE64_DECODE_INVALID
) return FALSE
;
449 if (d
== BASE64_DECODE_WHITESPACE
) continue;
451 /* When padding starts, data is not acceptable */
452 if (hasPadding
&& d
!= BASE64_DECODE_PADDING
) return FALSE
;
454 /* Padding after a full block (like "VVVV=") is ok and stops decoding */
455 if (d
== BASE64_DECODE_PADDING
&& (valid
& 3) == 0) break;
458 if (d
== BASE64_DECODE_PADDING
)
461 /* When padding reaches a full block, stop decoding */
462 if ((valid
& 3) == 0) break;
466 /* out is incremented in the 4-char block as follows: "1-23" */
467 if ((valid
& 3) != 2) out
++;
469 /* Fail if the block has bad padding; omitting padding is fine */
470 if ((valid
& 3) != 0 && hasPadding
) return FALSE
;
472 if (!(data
= add_cert( out
))) return FALSE
;
473 for (i
= valid
= out
= 0; str
[i
]; i
++)
475 int d
= decodeBase64Byte( str
[i
] );
476 if (d
== BASE64_DECODE_WHITESPACE
) continue;
477 if (d
== BASE64_DECODE_PADDING
) break;
478 block
[valid
& 3] = d
;
483 data
[out
++] = (block
[0] << 2);
486 data
[out
-1] = (block
[0] << 2) | (block
[1] >> 4);
489 data
[out
++] = (block
[1] << 4) | (block
[2] >> 2);
492 data
[out
++] = (block
[2] << 6) | (block
[3] >> 0);
499 /* Reads the file fd, and imports any certificates in it into store. */
500 static void import_certs_from_file( int fd
)
502 FILE *fp
= fdopen(fd
, "r");
504 BOOL in_cert
= FALSE
;
505 struct DynamicBuffer saved_cert
= { 0, 0, NULL
};
510 while (fgets(line
, sizeof(line
), fp
))
512 static const char header
[] = "-----BEGIN CERTIFICATE-----";
513 static const char trailer
[] = "-----END CERTIFICATE-----";
515 if (!strncmp(line
, header
, strlen(header
)))
517 TRACE("begin new certificate\n");
519 reset_buffer(&saved_cert
);
521 else if (!strncmp(line
, trailer
, strlen(trailer
)))
523 TRACE("end of certificate, adding cert\n");
525 if (base64_to_cert( saved_cert
.data
)) num_certs
++;
527 else if (in_cert
) add_line_to_buffer(&saved_cert
, line
);
529 free( saved_cert
.data
);
530 TRACE("Read %d certs\n", num_certs
);
534 static void import_certs_from_path(LPCSTR path
, BOOL allow_dir
);
536 static BOOL
check_buffer_resize(char **ptr_buf
, size_t *buf_size
, size_t check_size
)
538 if (check_size
> *buf_size
)
540 void *ptr
= realloc(*ptr_buf
, check_size
);
542 if (!ptr
) return FALSE
;
543 *buf_size
= check_size
;
549 /* Opens path, which must be a directory, and imports certificates from every
550 * file in the directory into store.
551 * Returns TRUE if any certificates were successfully imported.
553 static void import_certs_from_dir( LPCSTR path
)
560 size_t path_len
= strlen(path
), bufsize
= 0;
561 char *filebuf
= NULL
;
563 struct dirent
*entry
;
564 while ((entry
= readdir(dir
)))
566 if (strcmp(entry
->d_name
, ".") && strcmp(entry
->d_name
, ".."))
568 size_t name_len
= strlen(entry
->d_name
);
570 if (!check_buffer_resize(&filebuf
, &bufsize
, path_len
+ 1 + name_len
+ 1)) break;
571 snprintf(filebuf
, bufsize
, "%s/%s", path
, entry
->d_name
);
572 import_certs_from_path(filebuf
, FALSE
);
580 /* Opens path, which may be a file or a directory, and imports any certificates
581 * it finds into store.
582 * Returns TRUE if any certificates were successfully imported.
584 static void import_certs_from_path(LPCSTR path
, BOOL allow_dir
)
588 TRACE("(%s, %d)\n", debugstr_a(path
), allow_dir
);
590 fd
= open(path
, O_RDONLY
);
595 if (fstat(fd
, &st
) == 0)
597 if (S_ISREG(st
.st_mode
))
598 import_certs_from_file(fd
);
599 else if (S_ISDIR(st
.st_mode
))
602 import_certs_from_dir(path
);
604 WARN("%s is a directory and directories are disallowed\n",
608 ERR("%s: invalid file type\n", path
);
614 static const char * const CRYPT_knownLocations
[] = {
615 "/etc/ssl/certs/ca-certificates.crt",
617 "/etc/pki/tls/certs/ca-bundle.crt",
618 "/usr/share/ca-certificates/ca-bundle.crt",
619 "/usr/local/share/certs/",
620 "/etc/sfw/openssl/certs",
621 "/etc/security/cacerts", /* Android */
624 static void load_root_certs(void)
629 const SecTrustSettingsDomain domains
[] = {
630 kSecTrustSettingsDomainSystem
,
631 kSecTrustSettingsDomainAdmin
,
632 kSecTrustSettingsDomainUser
638 for (domain
= 0; domain
< ARRAY_SIZE(domains
); domain
++)
640 status
= SecTrustSettingsCopyCertificates(domains
[domain
], &certs
);
643 for (i
= 0; i
< CFArrayGetCount(certs
); i
++)
645 SecCertificateRef cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(certs
, i
);
647 if ((status
= SecItemExport(cert
, kSecFormatX509Cert
, 0, NULL
, &certData
)) == noErr
)
649 BYTE
*data
= add_cert( CFDataGetLength(certData
) );
650 if (data
) memcpy( data
, CFDataGetBytePtr(certData
), CFDataGetLength(certData
) );
654 WARN("could not export certificate %u to X509 format: 0x%08x\n", i
, (unsigned int)status
);
661 for (i
= 0; i
< ARRAY_SIZE(CRYPT_knownLocations
) && list_empty(&root_cert_list
); i
++)
662 import_certs_from_path( CRYPT_knownLocations
[i
], TRUE
);
665 static NTSTATUS
enum_root_certs( void *args
)
667 struct enum_root_certs_params
*params
= args
;
670 struct root_cert
*cert
;
672 if (!loaded
) load_root_certs();
675 if (!(ptr
= list_head( &root_cert_list
))) return STATUS_NO_MORE_ENTRIES
;
676 cert
= LIST_ENTRY( ptr
, struct root_cert
, entry
);
677 *params
->needed
= cert
->size
;
678 if (cert
->size
<= params
->size
)
680 memcpy( params
->buffer
, cert
->data
, cert
->size
);
681 list_remove( &cert
->entry
);
684 return STATUS_SUCCESS
;
687 const unixlib_entry_t __wine_unix_call_funcs
[] =
708 static NTSTATUS
wow64_open_cert_store( void *args
)
715 } const *params32
= args
;
717 const CRYPT_DATA_BLOB32
*pfx32
= ULongToPtr( params32
->pfx
);
718 CRYPT_DATA_BLOB pfx
= { pfx32
->cbData
, ULongToPtr( pfx32
->pbData
) };
719 struct open_cert_store_params params
=
722 ULongToPtr( params32
->password
),
723 ULongToPtr( params32
->data_ret
)
726 return open_cert_store( ¶ms
);
729 static NTSTATUS
wow64_import_store_key( void *args
)
733 cert_store_data_t data
;
736 } const *params32
= args
;
738 struct import_store_key_params params
=
741 ULongToPtr( params32
->buf
),
742 ULongToPtr( params32
->buf_size
)
745 return import_store_key( ¶ms
);
748 static NTSTATUS
wow64_import_store_cert( void *args
)
752 cert_store_data_t data
;
756 } const *params32
= args
;
758 struct import_store_cert_params params
=
762 ULongToPtr( params32
->buf
),
763 ULongToPtr( params32
->buf_size
)
766 return import_store_cert( ¶ms
);
769 static NTSTATUS
wow64_enum_root_certs( void *args
)
776 } const *params32
= args
;
778 struct enum_root_certs_params params
=
780 ULongToPtr( params32
->buffer
),
782 ULongToPtr( params32
->needed
)
785 return enum_root_certs( ¶ms
);
788 const unixlib_entry_t __wine_unix_call_wow64_funcs
[] =
792 wow64_open_cert_store
,
793 wow64_import_store_key
,
794 wow64_import_store_cert
,
796 wow64_enum_root_certs
,