2 * Secrets management and processing.
3 * Copyright 2018, Peter Wu <peter@lekensteyn.nl>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
14 #define WS_LOG_DOMAIN LOG_DOMAIN_EPAN
17 #include <wiretap/wtap.h>
18 #include <wsutil/glib-compat.h>
19 #include <wsutil/wslog.h>
23 # include <gnutls/gnutls.h>
24 # include <gnutls/abstract.h>
26 # include <wsutil/rsa.h>
27 # include <epan/uat.h>
28 # include <wsutil/report_message.h>
29 # include <wsutil/file_util.h>
31 #endif /* HAVE_LIBGNUTLS */
37 /** Maps uint32_t secrets_type -> secrets_block_callback_t. */
38 static GHashTable
*secrets_callbacks
;
41 /** Maps public key IDs (cert_key_id_t) -> gnutls_privkey_t. */
42 static GHashTable
*rsa_privkeys
;
45 char *uri
; /**< User-supplied PKCS #11 URI for token or RSA private key file. */
46 char *password
; /**< User-supplied PKCS #11 PIN or RSA private key file password. */
47 } rsa_privkey_record_t
;
49 static uat_t
*rsa_privkeys_uat
;
50 static rsa_privkey_record_t
*uat_rsa_privkeys
;
51 static unsigned uat_num_rsa_privkeys
;
53 static void register_rsa_uats(void);
54 #endif /* HAVE_LIBGNUTLS */
56 #ifdef HAVE_GNUTLS_PKCS11
57 /** PINs for PKCS #11 keys in rsa_privkeys. Must be cleared after rsa_privkeys. */
58 static GSList
*rsa_privkeys_pkcs11_pins
;
61 char *library_path
; /**< PKCS #11 library path. */
62 } pkcs11_lib_record_t
;
64 static uat_t
*pkcs11_libs_uat
;
65 static pkcs11_lib_record_t
*uat_pkcs11_libs
;
66 static unsigned uat_num_pkcs11_libs
;
67 #endif /* HAVE_GNUTLS_PKCS11 */
72 secrets_callbacks
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
74 rsa_privkeys
= privkey_hash_table_new();
76 #endif /* HAVE_LIBGNUTLS */
82 g_hash_table_destroy(secrets_callbacks
);
83 secrets_callbacks
= NULL
;
85 g_hash_table_destroy(rsa_privkeys
);
87 #ifdef HAVE_GNUTLS_PKCS11
88 g_slist_free_full(rsa_privkeys_pkcs11_pins
, g_free
);
89 rsa_privkeys_pkcs11_pins
= NULL
;
90 #endif /* HAVE_GNUTLS_PKCS11 */
91 #endif /* HAVE_LIBGNUTLS */
95 secrets_register_type(uint32_t secrets_type
, secrets_block_callback_t cb
)
97 g_hash_table_insert(secrets_callbacks
, GUINT_TO_POINTER(secrets_type
), (void *)cb
);
101 secrets_wtap_callback(uint32_t secrets_type
, const void *secrets
, unsigned size
)
103 secrets_block_callback_t cb
= (secrets_block_callback_t
)g_hash_table_lookup(
104 secrets_callbacks
, GUINT_TO_POINTER(secrets_type
));
110 #ifdef HAVE_LIBGNUTLS
112 key_id_hash(const void *key
)
114 const cert_key_id_t
*key_id
= (const cert_key_id_t
*)key
;
115 const uint32_t *dw
= (const uint32_t *)key_id
->key_id
;
117 /* The public key' SHA-1 hash (which maps to a private key) has a uniform
118 * distribution, hence simply xor'ing them should be sufficient. */
119 return dw
[0] ^ dw
[1] ^ dw
[2] ^ dw
[3] ^ dw
[4];
123 key_id_equal(const void *a
, const void *b
)
125 const cert_key_id_t
*key_id_a
= (const cert_key_id_t
*)a
;
126 const cert_key_id_t
*key_id_b
= (const cert_key_id_t
*)b
;
128 return !memcmp(key_id_a
, key_id_b
, sizeof(*key_id_a
));
132 privkey_hash_table_new(void)
134 return g_hash_table_new_full(key_id_hash
, key_id_equal
, g_free
, (GDestroyNotify
)gnutls_privkey_deinit
);
138 rsa_privkey_add(const cert_key_id_t
*key_id
, gnutls_privkey_t pkey
)
140 void *ht_key
= g_memdup2(key_id
->key_id
, sizeof(cert_key_id_t
));
141 const uint32_t *dw
= (const uint32_t *)key_id
->key_id
;
142 g_hash_table_insert(rsa_privkeys
, ht_key
, pkey
);
143 ws_debug("Adding RSA private, Key ID %08x%08x%08x%08x%08x", g_htonl(dw
[0]),
144 g_htonl(dw
[1]), g_htonl(dw
[2]), g_htonl(dw
[3]), g_htonl(dw
[4]));
147 #ifdef HAVE_GNUTLS_PKCS11
148 /** Provides a fixed PIN to the caller (or failure if the fixed PIN is NULL). */
150 set_pin_callback(void *userdata
, int attempt _U_
,
151 const char *token_url _U_
, const char *token_label _U_
,
152 unsigned int flags
, char *pin
, size_t pin_max
)
154 const char *fixed_pin
= (const char *)userdata
;
155 size_t fixed_pin_len
= fixed_pin
? strlen(fixed_pin
) : 0;
157 /* Fail if the PIN was not provided, wrong or too long. */
158 if (!fixed_pin
|| (flags
& GNUTLS_PIN_WRONG
) || fixed_pin_len
>= pin_max
) {
159 return GNUTLS_E_PKCS11_PIN_ERROR
;
162 memcpy(pin
, fixed_pin
, fixed_pin_len
+ 1);
167 get_pkcs11_token_uris(void)
169 GSList
*tokens
= NULL
;
171 for (unsigned i
= 0; ; i
++) {
174 int ret
= gnutls_pkcs11_token_get_url(i
, GNUTLS_PKCS11_URL_GENERIC
, &uri
);
175 if (ret
== GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
) {
180 ws_debug("Failed to query token %u: %s\n", i
, gnutls_strerror(ret
));
184 ret
= gnutls_pkcs11_token_get_flags(uri
, &flags
);
186 ws_debug("Failed to query token flags for %s: %s\n", uri
, gnutls_strerror(ret
));
191 // The "Trust module" is useless for decryption, so do not return it.
192 if ((flags
& GNUTLS_PKCS11_TOKEN_TRUSTED
)) {
197 tokens
= g_slist_prepend(tokens
, g_strdup(uri
));
201 tokens
= g_slist_reverse(tokens
);
207 verify_pkcs11_token(const char *token_uri
, const char *pin
, bool *pin_needed
, char **error
)
209 gnutls_pkcs11_obj_t
*list
= NULL
;
210 unsigned int nlist
= 0;
213 /* Set PIN via a global callback since import_url can prompt for one. */
214 gnutls_pkcs11_set_pin_function(set_pin_callback
, (void *)pin
);
216 /* This should ask for a PIN if needed. If no PIN is given,
217 * GNUTLS_E_PKCS11_PIN_ERROR (-303) is returned. */
218 ret
= gnutls_pkcs11_obj_list_import_url4(&list
, &nlist
, token_uri
,
219 GNUTLS_PKCS11_OBJ_FLAG_PRIVKEY
|GNUTLS_PKCS11_OBJ_FLAG_LOGIN
);
221 /* Do not care about the objects, we just wanted to know whether the
222 * token and PIN were valid. */
223 for (unsigned i
= 0; i
< nlist
; i
++) {
224 gnutls_pkcs11_obj_deinit(list
[i
]);
229 /* Forget about the PIN. */
230 gnutls_pkcs11_set_pin_function(NULL
, NULL
);
233 *pin_needed
= ret
== GNUTLS_E_PKCS11_PIN_ERROR
;
237 *error
= g_strdup(gnutls_strerror(ret
));
245 * Load private RSA keys from a PKCS #11 token. Returns zero on success and a
246 * negative error code on failure.
249 pkcs11_load_keys_from_token(const char *token_uri
, const char *pin
, char **err
)
251 gnutls_pkcs11_obj_t
*list
= NULL
;
252 unsigned int nlist
= 0;
254 /* An empty/NULL PIN means that none is necessary. */
255 char *fixed_pin
= pin
&& pin
[0] ? g_strdup(pin
) : NULL
;
256 bool pin_in_use
= false;
258 /* Set PIN via a global callback since import_url can prompt for one. */
259 gnutls_pkcs11_set_pin_function(set_pin_callback
, fixed_pin
);
261 /* This might already result in callback for the PIN. */
262 ret
= gnutls_pkcs11_obj_list_import_url4(&list
, &nlist
, token_uri
,
263 GNUTLS_PKCS11_OBJ_FLAG_PRIVKEY
|GNUTLS_PKCS11_OBJ_FLAG_LOGIN
);
265 *err
= ws_strdup_printf("Failed to iterate through objects for %s: %s", token_uri
, gnutls_strerror(ret
));
269 for (unsigned j
= 0; j
< nlist
; j
++) {
270 char *obj_uri
= NULL
;
271 gnutls_privkey_t privkey
= NULL
;
272 gnutls_pubkey_t pubkey
= NULL
;
273 cert_key_id_t key_id
;
276 if (gnutls_pkcs11_obj_get_type(list
[j
]) != GNUTLS_PKCS11_OBJ_PRIVKEY
) {
277 /* Should not happen since we requested private keys only. */
281 ret
= gnutls_pkcs11_obj_export_url(list
[j
], GNUTLS_PKCS11_URL_GENERIC
, &obj_uri
);
283 /* Should not happen either if the object is valid. */
287 ret
= gnutls_privkey_init(&privkey
);
293 /* Set the PIN to be used during decryption. */
294 gnutls_privkey_set_pin_function(privkey
, set_pin_callback
, fixed_pin
);
296 /* Can prompt for PIN. Can also invoke the token function set by
297 * gnutls_pkcs11_set_token_function (if not set, it will just fail
298 * immediately rather than retrying). */
299 ret
= gnutls_privkey_import_url(privkey
, obj_uri
, 0);
301 /* Bad PIN or some other system error? */
302 ws_debug("Failed to import private key %s: %s", obj_uri
, gnutls_strerror(ret
));
306 if (gnutls_privkey_get_pk_algorithm(privkey
, NULL
) != GNUTLS_PK_RSA
) {
307 ws_debug("Skipping private key %s, not RSA.", obj_uri
);
311 ret
= gnutls_pubkey_init(&pubkey
);
317 /* This requires GnuTLS 3.4.0 and will fail on older versions. */
318 ret
= gnutls_pubkey_import_privkey(pubkey
, privkey
, 0, 0);
320 ws_debug("Failed to import public key %s: %s", obj_uri
, gnutls_strerror(ret
));
324 size
= sizeof(key_id
);
325 ret
= gnutls_pubkey_get_key_id(pubkey
, GNUTLS_KEYID_USE_SHA1
, key_id
.key_id
, &size
);
326 if (ret
< 0 || size
!= sizeof(key_id
)) {
327 ws_debug("Failed to calculate Key ID for %s: %s", obj_uri
, gnutls_strerror(ret
));
331 /* Remember the private key. */
332 rsa_privkey_add(&key_id
, privkey
);
337 gnutls_privkey_deinit(privkey
);
338 gnutls_pubkey_deinit(pubkey
);
339 gnutls_free(obj_uri
);
340 gnutls_pkcs11_obj_deinit(list
[j
]);
344 /* Remember PINs such they can be freed later. */
345 rsa_privkeys_pkcs11_pins
= g_slist_prepend(rsa_privkeys_pkcs11_pins
, fixed_pin
);
351 /* Forget about the PIN. */
352 gnutls_pkcs11_set_pin_function(NULL
, NULL
);
357 /** Load all libraries specified in a UAT. */
359 uat_pkcs11_libs_load_all(void)
364 for (unsigned i
= 0; i
< uat_num_pkcs11_libs
; i
++) {
365 const pkcs11_lib_record_t
*rec
= &uat_pkcs11_libs
[i
];
366 const char *libname
= rec
->library_path
;
368 // Work around a bug in p11-kit < 0.23.16 on Windows
369 HMODULE provider_lib
= LoadLibraryA(libname
);
370 if (! provider_lib
|| ! GetProcAddress(provider_lib
, "C_GetFunctionList")) {
371 ret
= GNUTLS_E_PKCS11_LOAD_ERROR
;
374 /* Note: should return success for already loaded libraries. */
375 ret
= gnutls_pkcs11_add_provider(libname
, NULL
);
379 FreeLibrary(provider_lib
);
384 err
= g_string_new("Error loading PKCS #11 libraries:");
386 g_string_append_printf(err
, "\n%s: %s", libname
, gnutls_strerror(ret
));
390 report_failure("%s", err
->str
);
391 g_string_free(err
, TRUE
);
395 UAT_FILENAME_CB_DEF(pkcs11_libs_uats
, library_path
, pkcs11_lib_record_t
)
398 uat_pkcs11_lib_copy_str_cb(void *dest
, const void *source
, size_t len _U_
)
400 pkcs11_lib_record_t
*d
= (pkcs11_lib_record_t
*)dest
;
401 const pkcs11_lib_record_t
*s
= (const pkcs11_lib_record_t
*)source
;
402 d
->library_path
= g_strdup(s
->library_path
);
407 uat_pkcs11_lib_free_str_cb(void *record
)
409 pkcs11_lib_record_t
*rec
= (pkcs11_lib_record_t
*)record
;
410 g_free(rec
->library_path
);
412 #endif /* HAVE_GNUTLS_PKCS11 */
414 UAT_FILENAME_CB_DEF(rsa_privkeys_uats
, uri
, rsa_privkey_record_t
)
415 UAT_CSTRING_CB_DEF(rsa_privkeys_uats
, password
, rsa_privkey_record_t
)
418 uat_rsa_privkey_copy_str_cb(void *dest
, const void *source
, size_t len _U_
)
420 rsa_privkey_record_t
*d
= (rsa_privkey_record_t
*)dest
;
421 const rsa_privkey_record_t
*s
= (const rsa_privkey_record_t
*)source
;
422 d
->uri
= g_strdup(s
->uri
);
423 d
->password
= g_strdup(s
->password
);
428 uat_rsa_privkey_free_str_cb(void *record
)
430 rsa_privkey_record_t
*rec
= (rsa_privkey_record_t
*)record
;
432 g_free(rec
->password
);
436 load_rsa_keyfile(const char *filename
, const char *password
, bool save_key
, char **err
)
438 gnutls_x509_privkey_t x509_priv_key
;
439 gnutls_privkey_t privkey
= NULL
;
442 cert_key_id_t key_id
;
443 size_t size
= sizeof(key_id
);
445 FILE *fp
= ws_fopen(filename
, "rb");
447 *err
= ws_strdup_printf("Error loading RSA key file %s: %s", filename
, g_strerror(errno
));
451 if (!password
|| !password
[0]) {
452 x509_priv_key
= rsa_load_pem_key(fp
, &errmsg
);
454 /* Assume encrypted PKCS #12 container. */
455 x509_priv_key
= rsa_load_pkcs12(fp
, password
, &errmsg
);
458 if (!x509_priv_key
) {
459 *err
= ws_strdup_printf("Error loading RSA key file %s: %s", filename
, errmsg
);
464 gnutls_privkey_init(&privkey
);
465 ret
= gnutls_privkey_import_x509(privkey
, x509_priv_key
,
466 GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE
|GNUTLS_PRIVKEY_IMPORT_COPY
);
468 *err
= ws_strdup_printf("Error importing private key %s: %s", filename
, gnutls_strerror(ret
));
471 ret
= gnutls_x509_privkey_get_key_id(x509_priv_key
, GNUTLS_KEYID_USE_SHA1
, key_id
.key_id
, &size
);
472 if (ret
< 0 || size
!= sizeof(key_id
)) {
473 *err
= ws_strdup_printf("Error calculating Key ID for %s: %s", filename
, gnutls_strerror(ret
));
477 /* Remember the private key. */
479 rsa_privkey_add(&key_id
, privkey
);
484 gnutls_x509_privkey_deinit(x509_priv_key
);
485 gnutls_privkey_deinit(privkey
);
489 uat_rsa_privkeys_post_update(void)
491 /* Clear previous keys. */
492 g_hash_table_remove_all(rsa_privkeys
);
493 #ifdef HAVE_GNUTLS_PKCS11
494 g_slist_free_full(rsa_privkeys_pkcs11_pins
, g_free
);
495 rsa_privkeys_pkcs11_pins
= NULL
;
496 #endif /* HAVE_GNUTLS_PKCS11 */
497 GString
*errors
= NULL
;
499 for (unsigned i
= 0; i
< uat_num_rsa_privkeys
; i
++) {
500 const rsa_privkey_record_t
*rec
= &uat_rsa_privkeys
[i
];
501 const char *token_uri
= rec
->uri
;
504 if (g_str_has_prefix(token_uri
, "pkcs11:")) {
505 #ifdef HAVE_GNUTLS_PKCS11
506 pkcs11_load_keys_from_token(token_uri
, rec
->password
, &err
);
507 #endif /* HAVE_GNUTLS_PKCS11 */
509 load_rsa_keyfile(token_uri
, rec
->password
, true, &err
);
513 errors
= g_string_new("Error processing rsa_privkeys:");
515 g_string_append_c(errors
, '\n');
516 g_string_append(errors
, err
);
521 report_failure("%s", errors
->str
);
522 g_string_free(errors
, TRUE
);
527 secrets_get_available_keys(void)
530 #ifdef HAVE_GNUTLS_PKCS11
531 keys
= g_slist_concat(keys
, get_pkcs11_token_uris());
537 secrets_verify_key(const char *uri
, const char *password
, bool *need_password
, char **error
)
540 *need_password
= false;
546 if (g_str_has_prefix(uri
, "pkcs11:")) {
547 #ifdef HAVE_GNUTLS_PKCS11
548 return verify_pkcs11_token(uri
, password
, need_password
, error
);
551 *error
= g_strdup("PKCS #11 support is not available in this build");
555 } else if (g_file_test(uri
, G_FILE_TEST_IS_REGULAR
)) {
557 load_rsa_keyfile(uri
, password
, false, &err
);
559 // Assume that failure to load the key is due to password errors.
560 // This might not be correct, but fixing this needs more changes.
561 *need_password
= err
!= NULL
;
574 *error
= g_strdup("Unsupported key URI or path");
581 * Register the UAT definitions such that settings can be loaded from file.
582 * Note: relies on uat_load_all to invoke the post_update_cb in order of
583 * registration below such that libraries are loaded *before* keys are read.
586 register_rsa_uats(void)
588 #ifdef HAVE_GNUTLS_PKCS11
589 static uat_field_t uat_pkcs11_libs_fields
[] = {
590 UAT_FLD_FILENAME_OTHER(pkcs11_libs_uats
, library_path
, "Library Path", NULL
, "PKCS #11 provider library file"),
593 pkcs11_libs_uat
= uat_new("PKCS #11 Provider Libraries",
594 sizeof(pkcs11_lib_record_t
),
595 "pkcs11_libs", /* filename */
596 false, /* from_profile */
597 &uat_pkcs11_libs
, /* data_ptr */
598 &uat_num_pkcs11_libs
, /* numitems_ptr */
599 0, /* does not directly affect dissection */
600 NULL
, /* Help section (currently a wiki page) */
601 uat_pkcs11_lib_copy_str_cb
, /* copy_cb */
602 NULL
, /* update_cb */
603 uat_pkcs11_lib_free_str_cb
, /* free_cb */
604 uat_pkcs11_libs_load_all
, /* post_update_cb */
606 uat_pkcs11_libs_fields
);
607 #endif /* HAVE_GNUTLS_PKCS11 */
609 static uat_field_t uat_rsa_privkeys_fields
[] = {
610 UAT_FLD_FILENAME_OTHER(rsa_privkeys_uats
, uri
, "Keyfile or Token URI", NULL
, "RSA Key File or PKCS #11 URI for token"),
611 UAT_FLD_FILENAME_OTHER(rsa_privkeys_uats
, password
, "Password", NULL
, "RSA Key File password or PKCS #11 Token PIN"),
614 rsa_privkeys_uat
= uat_new("RSA Private Keys",
615 sizeof(rsa_privkey_record_t
),
616 "rsa_keys", /* filename */
617 false, /* from_profile */
618 &uat_rsa_privkeys
, /* data_ptr */
619 &uat_num_rsa_privkeys
, /* numitems_ptr */
620 0, /* does not directly affect dissection */
621 NULL
, /* Help section (currently a wiki page) */
622 uat_rsa_privkey_copy_str_cb
, /* copy_cb */
623 NULL
, /* update_cb */
624 uat_rsa_privkey_free_str_cb
, /* free_cb */
625 uat_rsa_privkeys_post_update
, /* post_update_cb */
627 uat_rsa_privkeys_fields
);
631 secrets_rsa_decrypt(const cert_key_id_t
*key_id
, const uint8_t *encr
, int encr_len
, uint8_t **out
, int *out_len
)
634 gnutls_datum_t ciphertext
= { (unsigned char *)encr
, encr_len
};
635 gnutls_datum_t plain
= { 0 };
637 gnutls_privkey_t pkey
= (gnutls_privkey_t
)g_hash_table_lookup(rsa_privkeys
, key_id
->key_id
);
639 return GNUTLS_E_NO_CERTIFICATE_FOUND
;
642 ret
= gnutls_privkey_decrypt_data(pkey
, 0, &ciphertext
, &plain
);
644 *out
= (uint8_t *)g_memdup2(plain
.data
, plain
.size
);
645 *out_len
= plain
.size
;
646 gnutls_free(plain
.data
);
651 #endif /* HAVE_LIBGNUTLS */
654 * Editor modelines - https://www.wireshark.org/tools/modelines.html
659 * indent-tabs-mode: nil
662 * vi: set shiftwidth=4 tabstop=8 expandtab:
663 * :indentSize=4:tabSize=8:noTabs=true: