1 /* secrets.c
2  * Secrets management and processing.
3  * Copyright 2018, Peter Wu <peter@lekensteyn.nl>
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * SPDX-License-Identifier: GPL-2.0-or-later
10  */
11 
12 #include "config.h"
13 
14 #define WS_LOG_DOMAIN LOG_DOMAIN_EPAN
15 
16 #include "secrets.h"
17 #include <wiretap/wtap.h>
18 #include <wsutil/glib-compat.h>
19 #include <wsutil/wslog.h>
20 
21 #include <string.h>
22 #ifdef HAVE_LIBGNUTLS
23 # include <gnutls/gnutls.h>
24 # include <gnutls/abstract.h>
25 # include <wsutil/wsgcrypt.h>
26 # include <wsutil/rsa.h>
27 # include <epan/uat.h>
28 # include <wsutil/report_message.h>
29 # include <wsutil/file_util.h>
30 # include <errno.h>
31 # if GNUTLS_VERSION_NUMBER < 0x030401
32 #   define GNUTLS_KEYID_USE_SHA1 0
33 # endif
34 #endif  /* HAVE_LIBGNUTLS */
35 
36 /** Maps guint32 secrets_type -> secrets_block_callback_t. */
37 static GHashTable *secrets_callbacks;
38 
39 #ifdef HAVE_LIBGNUTLS
40 /** Maps public key IDs (cert_key_id_t) -> gnutls_privkey_t.  */
41 static GHashTable *rsa_privkeys;
42 
43 typedef struct {
44     char *uri;              /**< User-supplied PKCS #11 URI for token or RSA private key file. */
45     char *password;         /**< User-supplied PKCS #11 PIN or RSA private key file password. */
46 } rsa_privkey_record_t;
47 
48 static uat_t *rsa_privkeys_uat;
49 static rsa_privkey_record_t *uat_rsa_privkeys;
50 static guint uat_num_rsa_privkeys;
51 
52 static void register_rsa_uats(void);
53 #endif  /* HAVE_LIBGNUTLS */
54 
55 #ifdef HAVE_GNUTLS_PKCS11
56 /** PINs for PKCS #11 keys in rsa_privkeys. Must be cleared after rsa_privkeys. */
57 static GSList *rsa_privkeys_pkcs11_pins;
58 
59 typedef struct {
60     char *library_path;     /**< PKCS #11 library path. */
61 } pkcs11_lib_record_t;
62 
63 static uat_t *pkcs11_libs_uat;
64 static pkcs11_lib_record_t *uat_pkcs11_libs;
65 static guint uat_num_pkcs11_libs;
66 #endif  /* HAVE_GNUTLS_PKCS11 */
67 
68 void
69 secrets_init(void)
70 {
71     secrets_callbacks = g_hash_table_new(g_direct_hash, g_direct_equal);
72 #ifdef HAVE_LIBGNUTLS
73     rsa_privkeys = privkey_hash_table_new();
74     register_rsa_uats();
75 #endif  /* HAVE_LIBGNUTLS */
76 }
77 
78 void
79 secrets_cleanup(void)
80 {
81     g_hash_table_destroy(secrets_callbacks);
82     secrets_callbacks = NULL;
83 #ifdef HAVE_LIBGNUTLS
84     g_hash_table_destroy(rsa_privkeys);
85     rsa_privkeys = NULL;
86 #ifdef HAVE_GNUTLS_PKCS11
87     g_slist_free_full(rsa_privkeys_pkcs11_pins, g_free);
88     rsa_privkeys_pkcs11_pins = NULL;
89 #endif  /* HAVE_GNUTLS_PKCS11 */
90 #endif  /* HAVE_LIBGNUTLS */
91 }
92 
93 void
94 secrets_register_type(guint32 secrets_type, secrets_block_callback_t cb)
95 {
96     g_hash_table_insert(secrets_callbacks, GUINT_TO_POINTER(secrets_type), (gpointer)cb);
97 }
98 
99 void
100 secrets_wtap_callback(guint32 secrets_type, const void *secrets, guint size)
101 {
102     secrets_block_callback_t cb = (secrets_block_callback_t)g_hash_table_lookup(
103             secrets_callbacks, GUINT_TO_POINTER(secrets_type));
104     if (cb) {
105         cb(secrets, size);
106     }
107 }
108 
109 #ifdef HAVE_LIBGNUTLS
110 static guint
111 key_id_hash(gconstpointer key)
112 {
113     const cert_key_id_t *key_id = (const cert_key_id_t *)key;
114     const guint32 *dw = (const guint32 *)key_id->key_id;
115 
116     /* The public key' SHA-1 hash (which maps to a private key) has a uniform
117      * distribution, hence simply xor'ing them should be sufficient. */
118     return dw[0] ^ dw[1] ^ dw[2] ^ dw[3] ^ dw[4];
119 }
120 
121 static gboolean
122 key_id_equal(gconstpointer a, gconstpointer b)
123 {
124     const cert_key_id_t *key_id_a = (const cert_key_id_t *)a;
125     const cert_key_id_t *key_id_b = (const cert_key_id_t *)b;
126 
127     return !memcmp(key_id_a, key_id_b, sizeof(*key_id_a));
128 }
129 
130 GHashTable *
131 privkey_hash_table_new(void)
132 {
133     return g_hash_table_new_full(key_id_hash, key_id_equal, g_free, (GDestroyNotify)gnutls_privkey_deinit);
134 }
135 
136 static void
137 rsa_privkey_add(const cert_key_id_t *key_id, gnutls_privkey_t pkey)
138 {
139     void *ht_key = g_memdup2(key_id->key_id, sizeof(cert_key_id_t));
140     const guint32 *dw = (const guint32 *)key_id->key_id;
141     g_hash_table_insert(rsa_privkeys, ht_key, pkey);
142     ws_debug("Adding RSA private, Key ID %08x%08x%08x%08x%08x", g_htonl(dw[0]),
143             g_htonl(dw[1]), g_htonl(dw[2]), g_htonl(dw[3]), g_htonl(dw[4]));
144 }
145 
146 #ifdef HAVE_GNUTLS_PKCS11
147 /** Provides a fixed PIN to the caller (or failure if the fixed PIN is NULL). */
148 static int
149 set_pin_callback(void *userdata, int attempt _U_,
150                  const char *token_url _U_, const char *token_label _U_,
151                  unsigned int flags, char *pin, size_t pin_max)
152 {
153     const char *fixed_pin = (const char *)userdata;
154     size_t fixed_pin_len = fixed_pin ? strlen(fixed_pin) : 0;
155 
156     /* Fail if the PIN was not provided, wrong or too long. */
157     if (!fixed_pin || (flags & GNUTLS_PIN_WRONG) || fixed_pin_len >= pin_max) {
158         return GNUTLS_E_PKCS11_PIN_ERROR;
159     }
160 
161     memcpy(pin, fixed_pin, fixed_pin_len + 1);
162     return 0;
163 }
164 
165 static GSList *
166 get_pkcs11_token_uris(void)
167 {
168     GSList *tokens = NULL;
169 
170     for (unsigned i = 0; ; i++) {
171         char *uri = NULL;
172         int flags;
173         int ret = gnutls_pkcs11_token_get_url(i, GNUTLS_PKCS11_URL_GENERIC, &uri);
174         if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
175             break;
176         }
177 
178         if (ret < 0) {
179             ws_debug("Failed to query token %u: %s\n", i, gnutls_strerror(ret));
180             break;
181         }
182 
183         ret = gnutls_pkcs11_token_get_flags(uri, &flags);
184         if (ret < 0) {
185             ws_debug("Failed to query token flags for %s: %s\n", uri, gnutls_strerror(ret));
186             gnutls_free(uri);
187             continue;
188         }
189 
190         // The "Trust module" is useless for decryption, so do not return it.
191         if ((flags & GNUTLS_PKCS11_TOKEN_TRUSTED)) {
192             gnutls_free(uri);
193             continue;
194         }
195 
196         tokens = g_slist_prepend(tokens, g_strdup(uri));
197         gnutls_free(uri);
198     }
199 
200     tokens = g_slist_reverse(tokens);
201 
202     return tokens;
203 }
204 
205 static gboolean
206 verify_pkcs11_token(const char *token_uri, const char *pin, gboolean *pin_needed, char **error)
207 {
208     gnutls_pkcs11_obj_t *list = NULL;
209     unsigned int nlist = 0;
210     int ret;
211 
212     /* Set PIN via a global callback since import_url can prompt for one. */
213     gnutls_pkcs11_set_pin_function(set_pin_callback, (void *)pin);
214 
215     /* This should ask for a PIN if needed. If no PIN is given,
216      * GNUTLS_E_PKCS11_PIN_ERROR (-303) is returned. */
217     ret = gnutls_pkcs11_obj_list_import_url4(&list, &nlist, token_uri,
218             GNUTLS_PKCS11_OBJ_FLAG_PRIVKEY|GNUTLS_PKCS11_OBJ_FLAG_LOGIN);
219     if (ret == 0) {
220         /* Do not care about the objects, we just wanted to know whether the
221          * token and PIN were valid. */
222         for (unsigned i = 0; i < nlist; i++) {
223             gnutls_pkcs11_obj_deinit(list[i]);
224         }
225         gnutls_free(list);
226     }
227 
228     /* Forget about the PIN. */
229     gnutls_pkcs11_set_pin_function(NULL, NULL);
230 
231     if (pin_needed) {
232         *pin_needed = ret == GNUTLS_E_PKCS11_PIN_ERROR;
233     }
234     if (ret != 0) {
235         if (error) {
236             *error = g_strdup(gnutls_strerror(ret));
237         }
238         return FALSE;
239     }
240     return TRUE;
241 }
242 
243 /**
244  * Load private RSA keys from a PKCS #11 token. Returns zero on success and a
245  * negative error code on failure.
246  */
247 static int
248 pkcs11_load_keys_from_token(const char *token_uri, const char *pin, char **err)
249 {
250     gnutls_pkcs11_obj_t *list = NULL;
251     unsigned int nlist = 0;
252     int ret;
253     /* An empty/NULL PIN means that none is necessary. */
254     char *fixed_pin = pin && pin[0] ? g_strdup(pin) : NULL;
255     gboolean pin_in_use = FALSE;
256 
257     /* Set PIN via a global callback since import_url can prompt for one. */
258     gnutls_pkcs11_set_pin_function(set_pin_callback, fixed_pin);
259 
260     /* This might already result in callback for the PIN. */
261     ret = gnutls_pkcs11_obj_list_import_url4(&list, &nlist, token_uri,
262             GNUTLS_PKCS11_OBJ_FLAG_PRIVKEY|GNUTLS_PKCS11_OBJ_FLAG_LOGIN);
263     if (ret < 0) {
264         *err = g_strdup_printf("Failed to iterate through objects for %s: %s", token_uri, gnutls_strerror(ret));
265         goto cleanup;
266     }
267 
268     for (unsigned j = 0; j < nlist; j++) {
269         char *obj_uri = NULL;
270         gnutls_privkey_t privkey = NULL;
271         gnutls_pubkey_t pubkey = NULL;
272         cert_key_id_t key_id;
273         size_t size;
274 
275         if (gnutls_pkcs11_obj_get_type(list[j]) != GNUTLS_PKCS11_OBJ_PRIVKEY) {
276             /* Should not happen since we requested private keys only. */
277             goto cont;
278         }
279 
280         ret = gnutls_pkcs11_obj_export_url(list[j], GNUTLS_PKCS11_URL_GENERIC, &obj_uri);
281         if (ret < 0) {
282             /* Should not happen either if the object is valid. */
283             goto cont;
284         }
285 
286         ret = gnutls_privkey_init(&privkey);
287         if (ret < 0) {
288             /* Out of memory? */
289             goto cont;
290         }
291 
292         /* Set the PIN to be used during decryption. */
293         gnutls_privkey_set_pin_function(privkey, set_pin_callback, fixed_pin);
294 
295         /* Can prompt for PIN. Can also invoke the token function set by
296          * gnutls_pkcs11_set_token_function (if not set, it will just fail
297          * immediately rather than retrying). */
298         ret = gnutls_privkey_import_url(privkey, obj_uri, 0);
299         if (ret < 0) {
300             /* Bad PIN or some other system error? */
301             ws_debug("Failed to import private key %s: %s", obj_uri, gnutls_strerror(ret));
302             goto cont;
303         }
304 
305         if (gnutls_privkey_get_pk_algorithm(privkey, NULL) != GNUTLS_PK_RSA) {
306             ws_debug("Skipping private key %s, not RSA.", obj_uri);
307             goto cont;
308         }
309 
310         ret = gnutls_pubkey_init(&pubkey);
311         if (ret < 0) {
312             /* Out of memory? */
313             goto cont;
314         }
315 
316         /* This requires GnuTLS 3.4.0 and will fail on older versions. */
317         ret = gnutls_pubkey_import_privkey(pubkey, privkey, 0, 0);
318         if (ret < 0) {
319             ws_debug("Failed to import public key %s: %s", obj_uri, gnutls_strerror(ret));
320             goto cont;
321         }
322 
323         size = sizeof(key_id);
324         ret = gnutls_pubkey_get_key_id(pubkey, GNUTLS_KEYID_USE_SHA1, key_id.key_id, &size);
325         if (ret < 0 || size != sizeof(key_id)) {
326             ws_debug("Failed to calculate Key ID for %s: %s", obj_uri, gnutls_strerror(ret));
327             goto cont;
328         }
329 
330         /* Remember the private key. */
331         rsa_privkey_add(&key_id, privkey);
332         privkey = NULL;
333         pin_in_use = TRUE;
334 
335 cont:
336         gnutls_privkey_deinit(privkey);
337         gnutls_pubkey_deinit(pubkey);
338         gnutls_free(obj_uri);
339         gnutls_pkcs11_obj_deinit(list[j]);
340     }
341     gnutls_free(list);
342     if (pin_in_use) {
343         /* Remember PINs such they can be freed later. */
344         rsa_privkeys_pkcs11_pins = g_slist_prepend(rsa_privkeys_pkcs11_pins, fixed_pin);
345         fixed_pin = NULL;
346     }
347     ret = 0;
348 
349 cleanup:
350     /* Forget about the PIN. */
351     gnutls_pkcs11_set_pin_function(NULL, NULL);
352     g_free(fixed_pin);
353     return ret;
354 }
355 
356 /** Load all libraries specified in a UAT. */
357 static void
358 uat_pkcs11_libs_load_all(void)
359 {
360     int ret;
361     GString *err = NULL;
362 
363     for (guint i = 0; i < uat_num_pkcs11_libs; i++) {
364         const pkcs11_lib_record_t *rec = &uat_pkcs11_libs[i];
365         const char *libname = rec->library_path;
366 #ifdef WIN32
367         // Work around a bug in p11-kit < 0.23.16 on Windows
368         HMODULE provider_lib = LoadLibraryA(libname);
369         if (! provider_lib || ! GetProcAddress(provider_lib, "C_GetFunctionList")) {
370             ret = GNUTLS_E_PKCS11_LOAD_ERROR;
371         } else {
372 #endif
373         /* Note: should return success for already loaded libraries.  */
374         ret = gnutls_pkcs11_add_provider(libname, NULL);
375 #ifdef WIN32
376         }
377         if (provider_lib) {
378             FreeLibrary(provider_lib);
379         }
380 #endif
381         if (ret) {
382             if (!err) {
383                 err = g_string_new("Error loading PKCS #11 libraries:");
384             }
385             g_string_append_printf(err, "\n%s: %s", libname, gnutls_strerror(ret));
386         }
387     }
388     if (err) {
389         report_failure("%s", err->str);
390         g_string_free(err, TRUE);
391     }
392 }
393 
394 UAT_FILENAME_CB_DEF(pkcs11_libs_uats, library_path, pkcs11_lib_record_t)
395 
396 static void *
397 uat_pkcs11_lib_copy_str_cb(void *dest, const void *source, size_t len _U_)
398 {
399     pkcs11_lib_record_t *d = (pkcs11_lib_record_t *)dest;
400     const pkcs11_lib_record_t *s = (const pkcs11_lib_record_t *)source;
401     d->library_path = g_strdup(s->library_path);
402     return dest;
403 }
404 
405 static void
406 uat_pkcs11_lib_free_str_cb(void *record)
407 {
408     pkcs11_lib_record_t *rec = (pkcs11_lib_record_t *)record;
409     g_free(rec->library_path);
410 }
411 #endif  /* HAVE_GNUTLS_PKCS11 */
412 
413 UAT_FILENAME_CB_DEF(rsa_privkeys_uats, uri, rsa_privkey_record_t)
414 UAT_CSTRING_CB_DEF(rsa_privkeys_uats, password, rsa_privkey_record_t)
415 
416 static void *
417 uat_rsa_privkey_copy_str_cb(void *dest, const void *source, size_t len _U_)
418 {
419     rsa_privkey_record_t *d = (rsa_privkey_record_t *)dest;
420     const rsa_privkey_record_t *s = (const rsa_privkey_record_t *)source;
421     d->uri = g_strdup(s->uri);
422     d->password = g_strdup(s->password);
423     return dest;
424 }
425 
426 static void
427 uat_rsa_privkey_free_str_cb(void *record)
428 {
429     rsa_privkey_record_t *rec = (rsa_privkey_record_t *)record;
430     g_free(rec->uri);
431     g_free(rec->password);
432 }
433 
434 static void
435 load_rsa_keyfile(const char *filename, const char *password, gboolean save_key, char **err)
436 {
437     gnutls_x509_privkey_t x509_priv_key;
438     gnutls_privkey_t privkey = NULL;
439     char *errmsg = NULL;
440     int ret;
441     cert_key_id_t key_id;
442     size_t size = sizeof(key_id);
443 
444     FILE *fp = ws_fopen(filename, "rb");
445     if (!fp) {
446         *err = g_strdup_printf("Error loading RSA key file %s: %s", filename, g_strerror(errno));
447         return;
448     }
449 
450     if (!password || !password[0]) {
451         x509_priv_key = rsa_load_pem_key(fp, &errmsg);
452     } else {
453         /* Assume encrypted PKCS #12 container. */
454         x509_priv_key = rsa_load_pkcs12(fp, password, &errmsg);
455     }
456     fclose(fp);
457     if (!x509_priv_key) {
458         *err = g_strdup_printf("Error loading RSA key file %s: %s", filename, errmsg);
459         g_free(errmsg);
460         return;
461     }
462 
463     gnutls_privkey_init(&privkey);
464     ret = gnutls_privkey_import_x509(privkey, x509_priv_key,
465             GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE|GNUTLS_PRIVKEY_IMPORT_COPY);
466     if (ret < 0) {
467         *err = g_strdup_printf("Error importing private key %s: %s", filename, gnutls_strerror(ret));
468         goto end;
469     }
470     ret = gnutls_x509_privkey_get_key_id(x509_priv_key, GNUTLS_KEYID_USE_SHA1, key_id.key_id, &size);
471     if (ret < 0 || size != sizeof(key_id)) {
472         *err = g_strdup_printf("Error calculating Key ID for %s: %s", filename, gnutls_strerror(ret));
473         goto end;
474     }
475 
476     /* Remember the private key. */
477     if (save_key) {
478         rsa_privkey_add(&key_id, privkey);
479         privkey = NULL;
480     }
481 
482 end:
483     gnutls_x509_privkey_deinit(x509_priv_key);
484     gnutls_privkey_deinit(privkey);
485 }
486 
487 static void
488 uat_rsa_privkeys_post_update(void)
489 {
490     /* Clear previous keys. */
491     g_hash_table_remove_all(rsa_privkeys);
492 #ifdef HAVE_GNUTLS_PKCS11
493     g_slist_free_full(rsa_privkeys_pkcs11_pins, g_free);
494     rsa_privkeys_pkcs11_pins = NULL;
495 #endif  /* HAVE_GNUTLS_PKCS11 */
496     GString *errors = NULL;
497 
498     for (guint i = 0; i < uat_num_rsa_privkeys; i++) {
499         const rsa_privkey_record_t *rec = &uat_rsa_privkeys[i];
500         const char *token_uri = rec->uri;
501         char *err = NULL;
502 
503         if (g_str_has_prefix(token_uri, "pkcs11:")) {
504 #ifdef HAVE_GNUTLS_PKCS11
505             pkcs11_load_keys_from_token(token_uri, rec->password, &err);
506 #endif  /* HAVE_GNUTLS_PKCS11 */
507         } else {
508             load_rsa_keyfile(token_uri, rec->password, TRUE, &err);
509         }
510         if (err) {
511             if (!errors) {
512                 errors = g_string_new("Error processing rsa_privkeys:");
513             }
514             g_string_append_c(errors, '\n');
515             g_string_append(errors, err);
516             g_free(err);
517         }
518     }
519     if (errors) {
520         report_failure("%s", errors->str);
521         g_string_free(errors, TRUE);
522     }
523 }
524 
525 GSList *
526 secrets_get_available_keys(void)
527 {
528     GSList *keys = NULL;
529 #ifdef HAVE_GNUTLS_PKCS11
530     keys = g_slist_concat(keys, get_pkcs11_token_uris());
531 #endif
532     return keys;
533 }
534 
535 gboolean
536 secrets_verify_key(const char *uri, const char *password, gboolean *need_password, char **error)
537 {
538     if (need_password) {
539         *need_password = FALSE;
540     }
541     if (error) {
542         *error = NULL;
543     }
544 
545     if (g_str_has_prefix(uri, "pkcs11:")) {
546 #ifdef HAVE_GNUTLS_PKCS11
547         return verify_pkcs11_token(uri, password, need_password, error);
548 #else
549         if (error) {
550             *error = g_strdup("PKCS #11 support is not available in this build");
551         }
552         return FALSE;
553 #endif
554     } else if (g_file_test(uri, G_FILE_TEST_IS_REGULAR)) {
555         gchar *err = NULL;
556         load_rsa_keyfile(uri, password, FALSE, &err);
557         if (need_password) {
558             // Assume that failure to load the key is due to password errors.
559             // This might not be correct, but fixing this needs more changes.
560             *need_password = err != NULL;
561         }
562         if (err) {
563             if (error) {
564                 *error = err;
565             } else {
566                 g_free(err);
567             }
568             return FALSE;
569         }
570         return TRUE;
571     } else {
572         if (error) {
573             *error = g_strdup("Unsupported key URI or path");
574         }
575         return FALSE;
576     }
577 }
578 
579 /**
580  * Register the UAT definitions such that settings can be loaded from file.
581  * Note: relies on uat_load_all to invoke the post_update_cb in order of
582  * registration below such that libraries are loaded *before* keys are read.
583  */
584 static void
585 register_rsa_uats(void)
586 {
587 #ifdef HAVE_GNUTLS_PKCS11
588     static uat_field_t uat_pkcs11_libs_fields[] = {
589         UAT_FLD_FILENAME_OTHER(pkcs11_libs_uats, library_path, "Library Path", NULL, "PKCS #11 provider library file"),
590         UAT_END_FIELDS
591     };
592     pkcs11_libs_uat = uat_new("PKCS #11 Provider Libraries",
593             sizeof(pkcs11_lib_record_t),
594             "pkcs11_libs",                  /* filename */
595             FALSE,                          /* from_profile */
596             &uat_pkcs11_libs,               /* data_ptr */
597             &uat_num_pkcs11_libs,           /* numitems_ptr */
598             0,                              /* does not directly affect dissection */
599             NULL,                           /* Help section (currently a wiki page) */
600             uat_pkcs11_lib_copy_str_cb,     /* copy_cb */
601             NULL,                           /* update_cb */
602             uat_pkcs11_lib_free_str_cb,     /* free_cb */
603             uat_pkcs11_libs_load_all,       /* post_update_cb */
604             NULL,                           /* reset_cb */
605             uat_pkcs11_libs_fields);
606 #endif  /* HAVE_GNUTLS_PKCS11 */
607 
608     static uat_field_t uat_rsa_privkeys_fields[] = {
609         UAT_FLD_FILENAME_OTHER(rsa_privkeys_uats, uri, "Keyfile or Token URI", NULL, "RSA Key File or PKCS #11 URI for token"),
610         UAT_FLD_FILENAME_OTHER(rsa_privkeys_uats, password, "Password", NULL, "RSA Key File password or PKCS #11 Token PIN"),
611         UAT_END_FIELDS
612     };
613     rsa_privkeys_uat = uat_new("RSA Private Keys",
614             sizeof(rsa_privkey_record_t),
615             "rsa_keys",                     /* filename */
616             FALSE,                          /* from_profile */
617             &uat_rsa_privkeys,              /* data_ptr */
618             &uat_num_rsa_privkeys,          /* numitems_ptr */
619             0,                              /* does not directly affect dissection */
620             NULL,                           /* Help section (currently a wiki page) */
621             uat_rsa_privkey_copy_str_cb,    /* copy_cb */
622             NULL,                           /* update_cb */
623             uat_rsa_privkey_free_str_cb,    /* free_cb */
624             uat_rsa_privkeys_post_update,   /* post_update_cb */
625             NULL,                           /* reset_cb */
626             uat_rsa_privkeys_fields);
627 }
628 
629 int
630 secrets_rsa_decrypt(const cert_key_id_t *key_id, const guint8 *encr, int encr_len, guint8 **out, int *out_len)
631 {
632     gboolean ret;
633     gnutls_datum_t ciphertext = { (guchar *)encr, encr_len };
634     gnutls_datum_t plain = { 0 };
635 
636     gnutls_privkey_t pkey = (gnutls_privkey_t)g_hash_table_lookup(rsa_privkeys, key_id->key_id);
637     if (!pkey) {
638         return GNUTLS_E_NO_CERTIFICATE_FOUND;
639     }
640 
641     ret = gnutls_privkey_decrypt_data(pkey, 0, &ciphertext, &plain);
642     if (ret == 0) {
643         *out = (guint8 *)g_memdup2(plain.data, plain.size);
644         *out_len = plain.size;
645         gnutls_free(plain.data);
646     }
647 
648     return ret;
649 }
650 #endif  /* HAVE_LIBGNUTLS */
651 
652 /*
653  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
654  *
655  * Local variables:
656  * c-basic-offset: 4
657  * tab-width: 8
658  * indent-tabs-mode: nil
659  * End:
660  *
661  * vi: set shiftwidth=4 tabstop=8 expandtab:
662  * :indentSize=4:tabSize=8:noTabs=true:
663  */
664