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 char *env
= getenv("GNUTLS_DEBUG_LEVEL");
134 int level
= env
? atoi(env
) : 4;
135 pgnutls_global_set_log_level(level
);
136 pgnutls_global_set_log_function( gnutls_log
);
142 dlclose( libgnutls_handle
);
143 libgnutls_handle
= NULL
;
144 return STATUS_DLL_INIT_FAILED
;
147 static NTSTATUS
process_detach( void *args
)
149 pgnutls_global_deinit();
150 dlclose( libgnutls_handle
);
151 libgnutls_handle
= NULL
;
152 return STATUS_SUCCESS
;
154 #define RSA_MAGIC_KEY ('R' | ('S' << 8) | ('A' << 16) | ('2' << 24))
155 #define RSA_PUBEXP 65537
157 struct cert_store_data
160 gnutls_x509_privkey_t key
;
161 gnutls_x509_crt_t
*chain
;
162 unsigned int key_bitlen
;
163 unsigned int chain_len
;
166 static struct cert_store_data
*get_store_data( cert_store_data_t data
)
168 return (struct cert_store_data
*)(ULONG_PTR
)data
;
171 static NTSTATUS
import_store_key( void *args
)
173 struct import_store_key_params
*params
= args
;
174 struct cert_store_data
*data
= get_store_data( params
->data
);
176 unsigned int bitlen
= data
->key_bitlen
;
177 gnutls_datum_t m
, e
, d
, p
, q
, u
, e1
, e2
;
183 size
= sizeof(*hdr
) + sizeof(*rsakey
) + (bitlen
* 9 / 16);
184 if (!params
->buf
|| *params
->buf_size
< size
)
186 *params
->buf_size
= size
;
187 return STATUS_BUFFER_TOO_SMALL
;
190 if ((ret
= pgnutls_x509_privkey_export_rsa_raw2( data
->key
, &m
, &e
, &d
, &p
, &q
, &u
, &e1
, &e2
)) < 0)
192 pgnutls_perror( ret
);
193 return STATUS_INVALID_PARAMETER
;
197 hdr
->bType
= PRIVATEKEYBLOB
;
198 hdr
->bVersion
= CUR_BLOB_VERSION
;
200 hdr
->aiKeyAlg
= CALG_RSA_KEYX
;
202 rsakey
= (RSAPUBKEY
*)(hdr
+ 1);
203 rsakey
->magic
= RSA_MAGIC_KEY
;
204 rsakey
->bitlen
= bitlen
;
205 rsakey
->pubexp
= RSA_PUBEXP
;
207 dst
= (BYTE
*)(rsakey
+ 1);
208 if (m
.size
== bitlen
/ 8 + 1 && !m
.data
[0]) src
= m
.data
+ 1;
209 else if (m
.size
!= bitlen
/ 8) goto done
;
211 for (i
= bitlen
/ 8 - 1; i
>= 0; i
--) *dst
++ = src
[i
];
213 if (p
.size
== bitlen
/ 16 + 1 && !p
.data
[0]) src
= p
.data
+ 1;
214 else if (p
.size
!= bitlen
/ 16) goto done
;
216 for (i
= bitlen
/ 16 - 1; i
>= 0; i
--) *dst
++ = src
[i
];
218 if (q
.size
== bitlen
/ 16 + 1 && !q
.data
[0]) src
= q
.data
+ 1;
219 else if (q
.size
!= bitlen
/ 16) goto done
;
221 for (i
= bitlen
/ 16 - 1; i
>= 0; i
--) *dst
++ = src
[i
];
223 if (e1
.size
== bitlen
/ 16 + 1 && !e1
.data
[0]) src
= e1
.data
+ 1;
224 else if (e1
.size
!= bitlen
/ 16) goto done
;
226 for (i
= bitlen
/ 16 - 1; i
>= 0; i
--) *dst
++ = src
[i
];
228 if (e2
.size
== bitlen
/ 16 + 1 && !e2
.data
[0]) src
= e2
.data
+ 1;
229 else if (e2
.size
!= bitlen
/ 16) goto done
;
231 for (i
= bitlen
/ 16 - 1; i
>= 0; i
--) *dst
++ = src
[i
];
233 if (u
.size
== bitlen
/ 16 + 1 && !u
.data
[0]) src
= u
.data
+ 1;
234 else if (u
.size
!= bitlen
/ 16) goto done
;
236 for (i
= bitlen
/ 16 - 1; i
>= 0; i
--) *dst
++ = src
[i
];
238 if (d
.size
== bitlen
/ 8 + 1 && !d
.data
[0]) src
= d
.data
+ 1;
239 else if (d
.size
!= bitlen
/ 8) goto done
;
241 for (i
= bitlen
/ 8 - 1; i
>= 0; i
--) *dst
++ = src
[i
];
252 return STATUS_SUCCESS
;
255 static char *password_to_ascii( const WCHAR
*str
)
260 if (!(ret
= malloc( (lstrlenW(str
) + 1) * sizeof(*ret
) ))) return NULL
;
263 if (*str
> 0x7f) WARN( "password contains non-ascii characters\n" );
270 static NTSTATUS
open_cert_store( void *args
)
272 struct open_cert_store_params
*params
= args
;
274 gnutls_datum_t pfx_data
;
275 gnutls_x509_privkey_t key
;
276 gnutls_x509_crt_t
*chain
;
277 unsigned int chain_len
;
281 struct cert_store_data
*store_data
;
283 if (!libgnutls_handle
) return STATUS_DLL_NOT_FOUND
;
284 if (params
->password
&& !(pwd
= password_to_ascii( params
->password
))) return STATUS_NO_MEMORY
;
286 if ((ret
= pgnutls_pkcs12_init( &p12
)) < 0) goto error
;
288 pfx_data
.data
= params
->pfx
->pbData
;
289 pfx_data
.size
= params
->pfx
->cbData
;
290 if ((ret
= pgnutls_pkcs12_import( p12
, &pfx_data
, GNUTLS_X509_FMT_DER
, 0 )) < 0) goto error
;
292 if ((ret
= pgnutls_pkcs12_simple_parse( p12
, pwd
? pwd
: "", &key
, &chain
, &chain_len
, NULL
, NULL
, NULL
, 0 )) < 0)
295 if ((ret
= pgnutls_x509_privkey_get_pk_algorithm2( key
, &bitlen
)) < 0)
300 if (ret
!= GNUTLS_PK_RSA
)
302 FIXME( "key algorithm %u not supported\n", ret
);
303 pgnutls_pkcs12_deinit( p12
);
304 return STATUS_INVALID_PARAMETER
;
307 store_data
= malloc( sizeof(*store_data
) );
308 store_data
->p12
= p12
;
309 store_data
->key
= key
;
310 store_data
->chain
= chain
;
311 store_data
->key_bitlen
= bitlen
;
312 store_data
->chain_len
= chain_len
;
313 *params
->data_ret
= (ULONG_PTR
)store_data
;
314 return STATUS_SUCCESS
;
317 pgnutls_perror( ret
);
318 pgnutls_pkcs12_deinit( p12
);
320 return STATUS_INVALID_PARAMETER
;
323 static NTSTATUS
import_store_cert( void *args
)
325 struct import_store_cert_params
*params
= args
;
326 struct cert_store_data
*data
= get_store_data( params
->data
);
330 if (params
->index
>= data
->chain_len
) return STATUS_NO_MORE_ENTRIES
;
332 if ((ret
= pgnutls_x509_crt_export( data
->chain
[params
->index
], GNUTLS_X509_FMT_DER
, NULL
, &size
)) != GNUTLS_E_SHORT_MEMORY_BUFFER
)
333 return STATUS_INVALID_PARAMETER
;
335 if (!params
->buf
|| *params
->buf_size
< size
)
337 *params
->buf_size
= size
;
338 return STATUS_BUFFER_TOO_SMALL
;
340 if ((ret
= pgnutls_x509_crt_export( data
->chain
[params
->index
], GNUTLS_X509_FMT_DER
, params
->buf
, &size
)) < 0)
341 return STATUS_INVALID_PARAMETER
;
343 return STATUS_SUCCESS
;
346 static NTSTATUS
close_cert_store( void *args
)
348 struct close_cert_store_params
*params
= args
;
349 struct cert_store_data
*data
= get_store_data( params
->data
);
353 pgnutls_pkcs12_deinit( data
->p12
);
356 return STATUS_SUCCESS
;
359 #else /* SONAME_LIBGNUTLS */
361 static NTSTATUS
process_attach( void *args
) { return STATUS_SUCCESS
; }
362 static NTSTATUS
process_detach( void *args
) { return STATUS_SUCCESS
; }
363 static NTSTATUS
open_cert_store( void *args
) { return STATUS_DLL_NOT_FOUND
; }
364 static NTSTATUS
import_store_key( void *args
) { return STATUS_DLL_NOT_FOUND
; }
365 static NTSTATUS
import_store_cert( void *args
) { return STATUS_DLL_NOT_FOUND
; }
366 static NTSTATUS
close_cert_store( void *args
) { return STATUS_DLL_NOT_FOUND
; }
368 #endif /* SONAME_LIBGNUTLS */
377 static struct list root_cert_list
= LIST_INIT(root_cert_list
);
379 static BYTE
*add_cert( SIZE_T size
)
381 struct root_cert
*cert
= malloc( offsetof( struct root_cert
, data
[size
] ));
383 if (!cert
) return NULL
;
385 list_add_tail( &root_cert_list
, &cert
->entry
);
396 static inline void reset_buffer(struct DynamicBuffer
*buffer
)
399 if (buffer
->data
) buffer
->data
[0] = 0;
402 static void add_line_to_buffer(struct DynamicBuffer
*buffer
, LPCSTR line
)
404 if (buffer
->used
+ strlen(line
) + 1 > buffer
->allocated
)
406 DWORD new_size
= max( max( buffer
->allocated
* 2, 1024 ), buffer
->used
+ strlen(line
) + 1 );
407 void *ptr
= realloc( buffer
->data
, new_size
);
410 buffer
->allocated
= new_size
;
411 if (!buffer
->used
) buffer
->data
[0] = 0;
413 strcpy( buffer
->data
+ buffer
->used
, line
);
414 buffer
->used
+= strlen(line
);
417 #define BASE64_DECODE_PADDING 0x100
418 #define BASE64_DECODE_WHITESPACE 0x200
419 #define BASE64_DECODE_INVALID 0x300
421 static inline int decodeBase64Byte(char c
)
423 int ret
= BASE64_DECODE_INVALID
;
425 if (c
>= 'A' && c
<= 'Z')
427 else if (c
>= 'a' && c
<= 'z')
429 else if (c
>= '0' && c
<= '9')
436 ret
= BASE64_DECODE_PADDING
;
437 else if (c
== ' ' || c
== '\t' || c
== '\r' || c
== '\n')
438 ret
= BASE64_DECODE_WHITESPACE
;
442 static BOOL
base64_to_cert( const char *str
)
444 DWORD i
, valid
, out
, hasPadding
;
445 BYTE block
[4], *data
;
447 for (i
= valid
= out
= hasPadding
= 0; str
[i
]; i
++)
449 int d
= decodeBase64Byte( str
[i
] );
450 if (d
== BASE64_DECODE_INVALID
) return FALSE
;
451 if (d
== BASE64_DECODE_WHITESPACE
) continue;
453 /* When padding starts, data is not acceptable */
454 if (hasPadding
&& d
!= BASE64_DECODE_PADDING
) return FALSE
;
456 /* Padding after a full block (like "VVVV=") is ok and stops decoding */
457 if (d
== BASE64_DECODE_PADDING
&& (valid
& 3) == 0) break;
460 if (d
== BASE64_DECODE_PADDING
)
463 /* When padding reaches a full block, stop decoding */
464 if ((valid
& 3) == 0) break;
468 /* out is incremented in the 4-char block as follows: "1-23" */
469 if ((valid
& 3) != 2) out
++;
471 /* Fail if the block has bad padding; omitting padding is fine */
472 if ((valid
& 3) != 0 && hasPadding
) return FALSE
;
474 if (!(data
= add_cert( out
))) return FALSE
;
475 for (i
= valid
= out
= 0; str
[i
]; i
++)
477 int d
= decodeBase64Byte( str
[i
] );
478 if (d
== BASE64_DECODE_WHITESPACE
) continue;
479 if (d
== BASE64_DECODE_PADDING
) break;
480 block
[valid
& 3] = d
;
485 data
[out
++] = (block
[0] << 2);
488 data
[out
-1] = (block
[0] << 2) | (block
[1] >> 4);
491 data
[out
++] = (block
[1] << 4) | (block
[2] >> 2);
494 data
[out
++] = (block
[2] << 6) | (block
[3] >> 0);
501 /* Reads the file fd, and imports any certificates in it into store. */
502 static void import_certs_from_file( int fd
)
504 FILE *fp
= fdopen(fd
, "r");
506 BOOL in_cert
= FALSE
;
507 struct DynamicBuffer saved_cert
= { 0, 0, NULL
};
512 while (fgets(line
, sizeof(line
), fp
))
514 static const char header
[] = "-----BEGIN CERTIFICATE-----";
515 static const char trailer
[] = "-----END CERTIFICATE-----";
517 if (!strncmp(line
, header
, strlen(header
)))
519 TRACE("begin new certificate\n");
521 reset_buffer(&saved_cert
);
523 else if (!strncmp(line
, trailer
, strlen(trailer
)))
525 TRACE("end of certificate, adding cert\n");
527 if (base64_to_cert( saved_cert
.data
)) num_certs
++;
529 else if (in_cert
) add_line_to_buffer(&saved_cert
, line
);
531 free( saved_cert
.data
);
532 TRACE("Read %d certs\n", num_certs
);
536 static void import_certs_from_path(LPCSTR path
, BOOL allow_dir
);
538 static BOOL
check_buffer_resize(char **ptr_buf
, size_t *buf_size
, size_t check_size
)
540 if (check_size
> *buf_size
)
542 void *ptr
= realloc(*ptr_buf
, check_size
);
544 if (!ptr
) return FALSE
;
545 *buf_size
= check_size
;
551 /* Opens path, which must be a directory, and imports certificates from every
552 * file in the directory into store.
553 * Returns TRUE if any certificates were successfully imported.
555 static void import_certs_from_dir( LPCSTR path
)
562 size_t path_len
= strlen(path
), bufsize
= 0;
563 char *filebuf
= NULL
;
565 struct dirent
*entry
;
566 while ((entry
= readdir(dir
)))
568 if (strcmp(entry
->d_name
, ".") && strcmp(entry
->d_name
, ".."))
570 size_t name_len
= strlen(entry
->d_name
);
572 if (!check_buffer_resize(&filebuf
, &bufsize
, path_len
+ 1 + name_len
+ 1)) break;
573 snprintf(filebuf
, bufsize
, "%s/%s", path
, entry
->d_name
);
574 import_certs_from_path(filebuf
, FALSE
);
582 /* Opens path, which may be a file or a directory, and imports any certificates
583 * it finds into store.
584 * Returns TRUE if any certificates were successfully imported.
586 static void import_certs_from_path(LPCSTR path
, BOOL allow_dir
)
590 TRACE("(%s, %d)\n", debugstr_a(path
), allow_dir
);
592 fd
= open(path
, O_RDONLY
);
597 if (fstat(fd
, &st
) == 0)
599 if (S_ISREG(st
.st_mode
))
600 import_certs_from_file(fd
);
601 else if (S_ISDIR(st
.st_mode
))
604 import_certs_from_dir(path
);
606 WARN("%s is a directory and directories are disallowed\n",
610 ERR("%s: invalid file type\n", path
);
616 static const char * const CRYPT_knownLocations
[] = {
617 "/etc/ssl/certs/ca-certificates.crt",
619 "/etc/pki/tls/certs/ca-bundle.crt",
620 "/usr/share/ca-certificates/ca-bundle.crt",
621 "/usr/local/share/certs/",
622 "/etc/sfw/openssl/certs",
623 "/etc/security/cacerts", /* Android */
626 static void load_root_certs(void)
631 const SecTrustSettingsDomain domains
[] = {
632 kSecTrustSettingsDomainSystem
,
633 kSecTrustSettingsDomainAdmin
,
634 kSecTrustSettingsDomainUser
640 for (domain
= 0; domain
< ARRAY_SIZE(domains
); domain
++)
642 status
= SecTrustSettingsCopyCertificates(domains
[domain
], &certs
);
645 for (i
= 0; i
< CFArrayGetCount(certs
); i
++)
647 SecCertificateRef cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(certs
, i
);
649 if ((status
= SecItemExport(cert
, kSecFormatX509Cert
, 0, NULL
, &certData
)) == noErr
)
651 BYTE
*data
= add_cert( CFDataGetLength(certData
) );
652 if (data
) memcpy( data
, CFDataGetBytePtr(certData
), CFDataGetLength(certData
) );
656 WARN("could not export certificate %u to X509 format: 0x%08x\n", i
, (unsigned int)status
);
663 for (i
= 0; i
< ARRAY_SIZE(CRYPT_knownLocations
) && list_empty(&root_cert_list
); i
++)
664 import_certs_from_path( CRYPT_knownLocations
[i
], TRUE
);
667 static NTSTATUS
enum_root_certs( void *args
)
669 struct enum_root_certs_params
*params
= args
;
672 struct root_cert
*cert
;
674 if (!loaded
) load_root_certs();
677 if (!(ptr
= list_head( &root_cert_list
))) return STATUS_NO_MORE_ENTRIES
;
678 cert
= LIST_ENTRY( ptr
, struct root_cert
, entry
);
679 *params
->needed
= cert
->size
;
680 if (cert
->size
<= params
->size
)
682 memcpy( params
->buffer
, cert
->data
, cert
->size
);
683 list_remove( &cert
->entry
);
686 return STATUS_SUCCESS
;
689 const unixlib_entry_t __wine_unix_call_funcs
[] =
700 C_ASSERT( ARRAYSIZE(__wine_unix_call_funcs
) == unix_funcs_count
);
712 static NTSTATUS
wow64_open_cert_store( void *args
)
719 } const *params32
= args
;
721 const CRYPT_DATA_BLOB32
*pfx32
= ULongToPtr( params32
->pfx
);
722 CRYPT_DATA_BLOB pfx
= { pfx32
->cbData
, ULongToPtr( pfx32
->pbData
) };
723 struct open_cert_store_params params
=
726 ULongToPtr( params32
->password
),
727 ULongToPtr( params32
->data_ret
)
730 return open_cert_store( ¶ms
);
733 static NTSTATUS
wow64_import_store_key( void *args
)
737 cert_store_data_t data
;
740 } const *params32
= args
;
742 struct import_store_key_params params
=
745 ULongToPtr( params32
->buf
),
746 ULongToPtr( params32
->buf_size
)
749 return import_store_key( ¶ms
);
752 static NTSTATUS
wow64_import_store_cert( void *args
)
756 cert_store_data_t data
;
760 } const *params32
= args
;
762 struct import_store_cert_params params
=
766 ULongToPtr( params32
->buf
),
767 ULongToPtr( params32
->buf_size
)
770 return import_store_cert( ¶ms
);
773 static NTSTATUS
wow64_enum_root_certs( void *args
)
780 } const *params32
= args
;
782 struct enum_root_certs_params params
=
784 ULongToPtr( params32
->buffer
),
786 ULongToPtr( params32
->needed
)
789 return enum_root_certs( ¶ms
);
792 const unixlib_entry_t __wine_unix_call_wow64_funcs
[] =
796 wow64_open_cert_store
,
797 wow64_import_store_key
,
798 wow64_import_store_cert
,
800 wow64_enum_root_certs
,
803 C_ASSERT( ARRAYSIZE(__wine_unix_call_wow64_funcs
) == unix_funcs_count
);