forked from osmocom/wireshark
Move RSA key loading and decryption functions to wsutil
Loading PEM and PKCS#11 keys was being done in static functions in packet-ssl-utils.c. These were moved to wsutil, with prototypes in a new <wsutil/rsa.h> header. This adds gnutls as optional dependency to wsutil. The RSA decryption helper was also moved and is now provided in <wsutil/wsgcrypt.h>. This allows more dissectors to access this functionality. Change-Id: I6cfbbf5203f2881c82bad721747834ccd76e2033 Reviewed-on: https://code.wireshark.org/review/21941 Reviewed-by: Peter Wu <peter@lekensteyn.nl> Petri-Dish: Peter Wu <peter@lekensteyn.nl> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Michael Mann <mmann78@netscape.net>
This commit is contained in:
parent
1b228df643
commit
502cc61711
|
@ -128,6 +128,11 @@ libwsutil.so.0 libwsutil0 #MINVER#
|
|||
report_read_failure@Base 1.12.0~rc1
|
||||
report_warning@Base 2.3.0
|
||||
report_write_failure@Base 1.12.0~rc1
|
||||
rsa_load_pem_key@Base 2.5.0
|
||||
rsa_load_pkcs12@Base 2.5.0
|
||||
rsa_decrypt_inplace@Base 2.5.0
|
||||
rsa_private_key_free@Base 2.5.0
|
||||
rsa_privkey_to_sexp@Base 2.5.0
|
||||
running_in_build_directory@Base 1.12.0~rc1
|
||||
running_with_special_privs@Base 1.10.0
|
||||
scan_plugins@Base 1.12.0~rc1
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
#include <wsutil/str_util.h>
|
||||
#include <wsutil/strtoi.h>
|
||||
#include <wsutil/utf8_entities.h>
|
||||
#include <wsutil/rsa.h>
|
||||
#include "packet-ssl-utils.h"
|
||||
#include "packet-dtls.h"
|
||||
|
||||
|
@ -252,7 +253,7 @@ dtls_parse_uat(void)
|
|||
|
||||
/* parse private keys string, load available keys and put them in key hash*/
|
||||
dtls_key_hash = g_hash_table_new_full(ssl_private_key_hash,
|
||||
ssl_private_key_equal, g_free, ssl_private_key_free);
|
||||
ssl_private_key_equal, g_free, rsa_private_key_free);
|
||||
|
||||
ssl_set_debug(dtls_debug_file_name);
|
||||
|
||||
|
|
|
@ -49,6 +49,8 @@
|
|||
#include <wsutil/report_message.h>
|
||||
#include <wsutil/pint.h>
|
||||
#include <wsutil/strtoi.h>
|
||||
#include <wsutil/wsgcrypt.h>
|
||||
#include <wsutil/rsa.h>
|
||||
#include <ws_version_info.h>
|
||||
#include "packet-ber.h"
|
||||
#include "packet-x509af.h"
|
||||
|
@ -2050,103 +2052,6 @@ ssl_cipher_cleanup(gcry_cipher_hd_t *cipher)
|
|||
gcry_cipher_close(*cipher);
|
||||
*cipher = NULL;
|
||||
}
|
||||
/* libgcrypt wrappers for Cipher state manipulation }}} */
|
||||
|
||||
#ifdef HAVE_LIBGNUTLS
|
||||
/* libgcrypt wrapper to decrypt using a RSA private key {{{ */
|
||||
/* decrypt data with private key. Store decrypted data directly into input
|
||||
* buffer */
|
||||
static int
|
||||
ssl_private_decrypt(const guint len, guchar* data, gcry_sexp_t pk)
|
||||
{
|
||||
gint rc = 0;
|
||||
size_t decr_len = 0, i = 0;
|
||||
gcry_sexp_t s_data = NULL, s_plain = NULL;
|
||||
gcry_mpi_t encr_mpi = NULL, text = NULL;
|
||||
|
||||
/* create mpi representation of encrypted data */
|
||||
rc = gcry_mpi_scan(&encr_mpi, GCRYMPI_FMT_USG, data, len, NULL);
|
||||
if (rc != 0 ) {
|
||||
ssl_debug_printf("pcry_private_decrypt: can't convert data to mpi (size %d):%s\n",
|
||||
len, gcry_strerror(rc));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* put the data into a simple list */
|
||||
rc = gcry_sexp_build(&s_data, NULL, "(enc-val(rsa(a%m)))", encr_mpi);
|
||||
if (rc != 0) {
|
||||
ssl_debug_printf("pcry_private_decrypt: can't build encr_sexp:%s\n",
|
||||
gcry_strerror(rc));
|
||||
decr_len = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* pass it to libgcrypt */
|
||||
rc = gcry_pk_decrypt(&s_plain, s_data, pk);
|
||||
if (rc != 0)
|
||||
{
|
||||
ssl_debug_printf("pcry_private_decrypt: can't decrypt key:%s\n",
|
||||
gcry_strerror(rc));
|
||||
decr_len = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* convert plain text sexp to mpi format */
|
||||
text = gcry_sexp_nth_mpi(s_plain, 0, 0);
|
||||
if (! text) {
|
||||
ssl_debug_printf("pcry_private_decrypt: can't convert sexp to mpi\n");
|
||||
decr_len = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* compute size requested for plaintext buffer */
|
||||
rc = gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &decr_len, text);
|
||||
if (rc != 0) {
|
||||
ssl_debug_printf("pcry_private_decrypt: can't compute decr size:%s\n",
|
||||
gcry_strerror(rc));
|
||||
decr_len = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* sanity check on out buffer */
|
||||
if (decr_len > len) {
|
||||
ssl_debug_printf("pcry_private_decrypt: decrypted data is too long ?!? (%" G_GSIZE_MODIFIER "u max %d)\n", decr_len, len);
|
||||
decr_len = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* write plain text to newly allocated buffer */
|
||||
rc = gcry_mpi_print(GCRYMPI_FMT_USG, data, len, &decr_len, text);
|
||||
if (rc != 0) {
|
||||
ssl_debug_printf("pcry_private_decrypt: can't print decr data to mpi (size %" G_GSIZE_MODIFIER "u):%s\n", decr_len, gcry_strerror(rc));
|
||||
decr_len = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ssl_print_data("decrypted_unstrip_pre_master", data, decr_len);
|
||||
|
||||
/* strip the padding*/
|
||||
rc = 0;
|
||||
for (i = 1; i < decr_len; i++) {
|
||||
if (data[i] == 0) {
|
||||
rc = (gint) i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ssl_debug_printf("pcry_private_decrypt: stripping %d bytes, decr_len %" G_GSIZE_MODIFIER "u\n", rc, decr_len);
|
||||
decr_len -= rc;
|
||||
memmove(data, data+rc, decr_len);
|
||||
|
||||
out:
|
||||
gcry_sexp_release(s_data);
|
||||
gcry_sexp_release(s_plain);
|
||||
gcry_mpi_release(encr_mpi);
|
||||
gcry_mpi_release(text);
|
||||
return (int) decr_len;
|
||||
} /* }}} */
|
||||
#endif /* HAVE_LIBGNUTLS */
|
||||
|
||||
|
||||
/* Digests, Ciphers and Cipher Suites registry {{{ */
|
||||
static const SslDigestAlgo digests[]={
|
||||
|
@ -3626,6 +3531,7 @@ ssl_decrypt_pre_master_secret(SslDecryptSession*ssl_session,
|
|||
StringInfo* encrypted_pre_master, gcry_sexp_t pk)
|
||||
{
|
||||
gint i;
|
||||
char *err;
|
||||
|
||||
if (!encrypted_pre_master)
|
||||
return FALSE;
|
||||
|
@ -3647,8 +3553,12 @@ ssl_decrypt_pre_master_secret(SslDecryptSession*ssl_session,
|
|||
/* with tls key loading will fail if not rsa type, so no need to check*/
|
||||
ssl_print_string("pre master encrypted",encrypted_pre_master);
|
||||
ssl_debug_printf("%s: RSA_private_decrypt\n", G_STRFUNC);
|
||||
i=ssl_private_decrypt(encrypted_pre_master->data_len,
|
||||
encrypted_pre_master->data, pk);
|
||||
i=rsa_decrypt_inplace(encrypted_pre_master->data_len,
|
||||
encrypted_pre_master->data, pk, TRUE, &err);
|
||||
if (i == 0) {
|
||||
ssl_debug_printf("rsa_decrypt_inplace: %s\n", err);
|
||||
g_free(err);
|
||||
}
|
||||
|
||||
if (i!=48) {
|
||||
ssl_debug_printf("%s wrong pre_master_secret length (%d, expected "
|
||||
|
@ -4257,307 +4167,8 @@ skip_mac:
|
|||
/* Record decryption glue based on security parameters }}} */
|
||||
|
||||
|
||||
|
||||
#if defined(HAVE_LIBGNUTLS)
|
||||
/* RSA private key file processing {{{ */
|
||||
#define RSA_PARS 6
|
||||
static gcry_sexp_t
|
||||
ssl_privkey_to_sexp(gnutls_x509_privkey_t priv_key)
|
||||
{
|
||||
gnutls_datum_t rsa_datum[RSA_PARS]; /* m, e, d, p, q, u */
|
||||
size_t tmp_size;
|
||||
gcry_error_t gret;
|
||||
gcry_sexp_t rsa_priv_key = NULL;
|
||||
gint i;
|
||||
gcry_mpi_t rsa_params[RSA_PARS];
|
||||
|
||||
/* RSA get parameter */
|
||||
if (gnutls_x509_privkey_export_rsa_raw(priv_key,
|
||||
&rsa_datum[0],
|
||||
&rsa_datum[1],
|
||||
&rsa_datum[2],
|
||||
&rsa_datum[3],
|
||||
&rsa_datum[4],
|
||||
&rsa_datum[5]) != 0) {
|
||||
ssl_debug_printf("ssl_load_key: can't export rsa param (is a rsa private key file ?!?)\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* convert each rsa parameter to mpi format*/
|
||||
for(i=0; i<RSA_PARS; i++) {
|
||||
gret = gcry_mpi_scan(&rsa_params[i], GCRYMPI_FMT_USG, rsa_datum[i].data, rsa_datum[i].size,&tmp_size);
|
||||
/* these buffers were allocated by gnutls_x509_privkey_export_rsa_raw() */
|
||||
g_free(rsa_datum[i].data);
|
||||
if (gret != 0) {
|
||||
ssl_debug_printf("ssl_load_key: can't convert m rsa param to int (size %d)\n", rsa_datum[i].size);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* libgcrypt expects p < q, and gnutls might not return it as such, depending on gnutls version and its crypto backend */
|
||||
if (gcry_mpi_cmp(rsa_params[3], rsa_params[4]) > 0)
|
||||
{
|
||||
ssl_debug_printf("ssl_load_key: swapping p and q parameters and recomputing u\n");
|
||||
/* p, q = q, p */
|
||||
gcry_mpi_swap(rsa_params[3], rsa_params[4]);
|
||||
/* due to swapping p and q, u = p^-1 mod p which happens to be needed. */
|
||||
}
|
||||
/* libgcrypt expects u = p^-1 mod q (for OpenPGP), but the u parameter
|
||||
* says u = q^-1 mod p. Recompute u = p^-1 mod q. Do this unconditionally as
|
||||
* at least GnuTLS 2.12.23 computes an invalid value. */
|
||||
gcry_mpi_invm(rsa_params[5], rsa_params[3], rsa_params[4]);
|
||||
|
||||
if (gcry_sexp_build( &rsa_priv_key, NULL,
|
||||
"(private-key(rsa((n%m)(e%m)(d%m)(p%m)(q%m)(u%m))))", rsa_params[0],
|
||||
rsa_params[1], rsa_params[2], rsa_params[3], rsa_params[4],
|
||||
rsa_params[5]) != 0) {
|
||||
ssl_debug_printf("ssl_load_key: can't build rsa private key s-exp\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i=0; i< 6; i++)
|
||||
gcry_mpi_release(rsa_params[i]);
|
||||
return rsa_priv_key;
|
||||
}
|
||||
|
||||
/** Load an RSA private key from specified file
|
||||
@param fp the file that contain the key data
|
||||
@return a pointer to the loaded key on success, or NULL */
|
||||
static gnutls_x509_privkey_t
|
||||
ssl_load_key(FILE* fp)
|
||||
{
|
||||
/* gnutls makes our work much harder, since we have to work internally with
|
||||
* s-exp formatted data, but PEM loader exports only in "gnutls_datum_t"
|
||||
* format, and a datum -> s-exp convertion function does not exist.
|
||||
*/
|
||||
gnutls_x509_privkey_t priv_key;
|
||||
gnutls_datum_t key;
|
||||
ws_statb64 statbuf;
|
||||
gint ret;
|
||||
guint bytes;
|
||||
|
||||
if (ws_fstat64(ws_fileno(fp), &statbuf) == -1) {
|
||||
ssl_debug_printf("ssl_load_key: can't ws_fstat64 file\n");
|
||||
return NULL;
|
||||
}
|
||||
if (S_ISDIR(statbuf.st_mode)) {
|
||||
ssl_debug_printf("ssl_load_key: file is a directory\n");
|
||||
errno = EISDIR;
|
||||
return NULL;
|
||||
}
|
||||
if (S_ISFIFO(statbuf.st_mode)) {
|
||||
ssl_debug_printf("ssl_load_key: file is a named pipe\n");
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if (!S_ISREG(statbuf.st_mode)) {
|
||||
ssl_debug_printf("ssl_load_key: file is not a regular file\n");
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
/* XXX - check for a too-big size */
|
||||
/* load all file contents into a datum buffer*/
|
||||
key.data = (unsigned char *)g_malloc((size_t)statbuf.st_size);
|
||||
key.size = (int)statbuf.st_size;
|
||||
bytes = (guint) fread(key.data, 1, key.size, fp);
|
||||
if (bytes < key.size) {
|
||||
ssl_debug_printf("ssl_load_key: can't read from file %d bytes, got %d\n",
|
||||
key.size, bytes);
|
||||
g_free(key.data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* init private key data*/
|
||||
gnutls_x509_privkey_init(&priv_key);
|
||||
|
||||
/* import PEM data*/
|
||||
if ((ret = gnutls_x509_privkey_import(priv_key, &key, GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS) {
|
||||
ssl_debug_printf("ssl_load_key: can't import pem data: %s\n", gnutls_strerror(ret));
|
||||
g_free(key.data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (gnutls_x509_privkey_get_pk_algorithm(priv_key) != GNUTLS_PK_RSA) {
|
||||
ssl_debug_printf("ssl_load_key: private key public key algorithm isn't RSA\n");
|
||||
g_free(key.data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_free(key.data);
|
||||
|
||||
return priv_key;
|
||||
}
|
||||
|
||||
static const char *
|
||||
BAGTYPE(gnutls_pkcs12_bag_type_t x) {
|
||||
switch (x) {
|
||||
case GNUTLS_BAG_EMPTY: return "Empty";
|
||||
case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY: return "PKCS#8 Encrypted key";
|
||||
case GNUTLS_BAG_PKCS8_KEY: return "PKCS#8 Key";
|
||||
case GNUTLS_BAG_CERTIFICATE: return "Certificate";
|
||||
case GNUTLS_BAG_CRL: return "CRL";
|
||||
case GNUTLS_BAG_ENCRYPTED: return "Encrypted";
|
||||
case GNUTLS_BAG_UNKNOWN: return "Unknown";
|
||||
default: return "<undefined>";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a RSA private key from a PKCS#12 file.
|
||||
* @param fp the file that contains the key data.
|
||||
* @param cert_passwd password to decrypt the PKCS#12 file.
|
||||
* @param[out] err error message upon failure; NULL upon success.
|
||||
* @return a pointer to the loaded key on success; NULL upon failure.
|
||||
*/
|
||||
static gnutls_x509_privkey_t
|
||||
ssl_load_pkcs12(FILE* fp, const gchar *cert_passwd, char** err) {
|
||||
|
||||
int i, j, ret;
|
||||
int rest;
|
||||
unsigned char *p;
|
||||
gnutls_datum_t data;
|
||||
gnutls_pkcs12_bag_t bag = NULL;
|
||||
gnutls_pkcs12_bag_type_t bag_type;
|
||||
size_t len;
|
||||
|
||||
gnutls_pkcs12_t ssl_p12 = NULL;
|
||||
gnutls_x509_privkey_t ssl_pkey = NULL;
|
||||
|
||||
gnutls_x509_privkey_t priv_key = NULL;
|
||||
*err = NULL;
|
||||
|
||||
rest = 4096;
|
||||
data.data = (unsigned char *)g_malloc(rest);
|
||||
data.size = rest;
|
||||
p = data.data;
|
||||
while ((len = fread(p, 1, rest, fp)) > 0) {
|
||||
p += len;
|
||||
rest -= (int) len;
|
||||
if (!rest) {
|
||||
rest = 1024;
|
||||
data.data = (unsigned char *)g_realloc(data.data, data.size + rest);
|
||||
p = data.data + data.size;
|
||||
data.size += rest;
|
||||
}
|
||||
}
|
||||
data.size -= rest;
|
||||
ssl_debug_printf("%d bytes read\n", data.size);
|
||||
if (!feof(fp)) {
|
||||
*err = g_strdup("Error during certificate reading.");
|
||||
ssl_debug_printf("%s\n", *err);
|
||||
g_free(data.data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = gnutls_pkcs12_init(&ssl_p12);
|
||||
if (ret < 0) {
|
||||
*err = g_strdup_printf("gnutls_pkcs12_init(&st_p12) - %s", gnutls_strerror(ret));
|
||||
ssl_debug_printf("%s\n", *err);
|
||||
g_free(data.data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* load PKCS#12 in DER or PEM format */
|
||||
ret = gnutls_pkcs12_import(ssl_p12, &data, GNUTLS_X509_FMT_DER, 0);
|
||||
if (ret < 0) {
|
||||
*err = g_strdup_printf("could not load PKCS#12 in DER format: %s", gnutls_strerror(ret));
|
||||
ssl_debug_printf("%s\n", *err);
|
||||
g_free(*err);
|
||||
|
||||
ret = gnutls_pkcs12_import(ssl_p12, &data, GNUTLS_X509_FMT_PEM, 0);
|
||||
if (ret < 0) {
|
||||
*err = g_strdup_printf("could not load PKCS#12 in PEM format: %s", gnutls_strerror(ret));
|
||||
ssl_debug_printf("%s\n", *err);
|
||||
} else {
|
||||
*err = NULL;
|
||||
}
|
||||
}
|
||||
g_free(data.data);
|
||||
if (ret < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssl_debug_printf( "PKCS#12 imported\n");
|
||||
|
||||
/* TODO: Use gnutls_pkcs12_simple_parse, since 3.1.0 (August 2012) */
|
||||
for (i=0; ; i++) {
|
||||
|
||||
ret = gnutls_pkcs12_bag_init(&bag);
|
||||
if (ret < 0) break;
|
||||
|
||||
ret = gnutls_pkcs12_get_bag(ssl_p12, i, bag);
|
||||
if (ret < 0) break;
|
||||
|
||||
for (j=0; j<gnutls_pkcs12_bag_get_count(bag); j++) {
|
||||
|
||||
ret = gnutls_pkcs12_bag_get_type(bag, j);
|
||||
if (ret < 0) goto done;
|
||||
bag_type = (gnutls_pkcs12_bag_type_t)ret;
|
||||
if (bag_type >= GNUTLS_BAG_UNKNOWN) goto done;
|
||||
ssl_debug_printf( "Bag %d/%d: %s\n", i, j, BAGTYPE(bag_type));
|
||||
if (bag_type == GNUTLS_BAG_ENCRYPTED) {
|
||||
ret = gnutls_pkcs12_bag_decrypt(bag, cert_passwd);
|
||||
if (ret == 0) {
|
||||
ret = gnutls_pkcs12_bag_get_type(bag, j);
|
||||
if (ret < 0) goto done;
|
||||
bag_type = (gnutls_pkcs12_bag_type_t)ret;
|
||||
if (bag_type >= GNUTLS_BAG_UNKNOWN) goto done;
|
||||
ssl_debug_printf( "Bag %d/%d decrypted: %s\n", i, j, BAGTYPE(bag_type));
|
||||
}
|
||||
}
|
||||
|
||||
ret = gnutls_pkcs12_bag_get_data(bag, j, &data);
|
||||
if (ret < 0) goto done;
|
||||
|
||||
switch (bag_type) {
|
||||
|
||||
case GNUTLS_BAG_PKCS8_KEY:
|
||||
case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY:
|
||||
|
||||
ret = gnutls_x509_privkey_init(&ssl_pkey);
|
||||
if (ret < 0) {
|
||||
*err = g_strdup_printf("gnutls_x509_privkey_init(&ssl_pkey) - %s", gnutls_strerror(ret));
|
||||
ssl_debug_printf("%s\n", *err);
|
||||
goto done;
|
||||
}
|
||||
ret = gnutls_x509_privkey_import_pkcs8(ssl_pkey, &data, GNUTLS_X509_FMT_DER, cert_passwd,
|
||||
(bag_type==GNUTLS_BAG_PKCS8_KEY) ? GNUTLS_PKCS_PLAIN : 0);
|
||||
if (ret < 0) {
|
||||
*err = g_strdup_printf("Can not decrypt private key - %s", gnutls_strerror(ret));
|
||||
ssl_debug_printf("%s\n", *err);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (gnutls_x509_privkey_get_pk_algorithm(ssl_pkey) != GNUTLS_PK_RSA) {
|
||||
*err = g_strdup("ssl_load_pkcs12: private key public key algorithm isn't RSA");
|
||||
ssl_debug_printf("%s\n", *err);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Private key found, return it. */
|
||||
priv_key = ssl_pkey;
|
||||
goto done;
|
||||
|
||||
default: ;
|
||||
}
|
||||
} /* j */
|
||||
if (bag) { gnutls_pkcs12_bag_deinit(bag); bag = NULL; }
|
||||
} /* i */
|
||||
|
||||
done:
|
||||
if (!priv_key && ssl_pkey)
|
||||
gnutls_x509_privkey_deinit(ssl_pkey);
|
||||
if (bag)
|
||||
gnutls_pkcs12_bag_deinit(bag);
|
||||
|
||||
return priv_key;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ssl_private_key_free(gpointer key)
|
||||
{
|
||||
gcry_sexp_release((gcry_sexp_t) key);
|
||||
}
|
||||
|
||||
static void
|
||||
ssl_find_private_key_by_pubkey(SslDecryptSession *ssl, GHashTable *key_hash,
|
||||
|
@ -4604,12 +4215,6 @@ end:
|
|||
}
|
||||
|
||||
/* RSA private key file processing }}} */
|
||||
|
||||
#else /* ! defined(HAVE_LIBGNUTLS) */
|
||||
void
|
||||
ssl_private_key_free(gpointer key _U_)
|
||||
{
|
||||
}
|
||||
#endif /* ! defined(HAVE_LIBGNUTLS) */
|
||||
|
||||
|
||||
|
@ -5024,6 +4629,7 @@ ssl_parse_key_list(const ssldecrypt_assoc_t *uats, GHashTable *key_hash, const c
|
|||
int ret;
|
||||
size_t key_id_len = 20;
|
||||
guchar *key_id = NULL;
|
||||
char *err = NULL;
|
||||
dissector_handle_t handle;
|
||||
/* try to load keys file first */
|
||||
fp = ws_fopen(uats->keyfile, "rb");
|
||||
|
@ -5033,10 +4639,13 @@ ssl_parse_key_list(const ssldecrypt_assoc_t *uats, GHashTable *key_hash, const c
|
|||
}
|
||||
|
||||
if ((gint)strlen(uats->password) == 0) {
|
||||
priv_key = ssl_load_key(fp);
|
||||
priv_key = rsa_load_pem_key(fp, &err);
|
||||
if (err) {
|
||||
ssl_debug_printf("%s\n", err);
|
||||
g_free(err);
|
||||
}
|
||||
} else {
|
||||
char *err = NULL;
|
||||
priv_key = ssl_load_pkcs12(fp, uats->password, &err);
|
||||
priv_key = rsa_load_pkcs12(fp, uats->password, &err);
|
||||
if (err) {
|
||||
report_failure("%s\n", err);
|
||||
g_free(err);
|
||||
|
@ -5058,8 +4667,10 @@ ssl_parse_key_list(const ssldecrypt_assoc_t *uats, GHashTable *key_hash, const c
|
|||
}
|
||||
ssl_print_data("KeyID", key_id, key_id_len);
|
||||
|
||||
private_key = ssl_privkey_to_sexp(priv_key);
|
||||
private_key = rsa_privkey_to_sexp(priv_key, &err);
|
||||
if (!private_key) {
|
||||
ssl_debug_printf("%s\n", err);
|
||||
g_free(err);
|
||||
report_failure("Can't extract private key parameters for %s", uats->keyfile);
|
||||
goto end;
|
||||
}
|
||||
|
@ -5742,7 +5353,7 @@ ssldecrypt_uat_fld_password_chk_cb(void *r _U_, const char *p _U_, guint len _U_
|
|||
fp = ws_fopen(f->keyfile, "rb");
|
||||
if (fp) {
|
||||
char *msg = NULL;
|
||||
gnutls_x509_privkey_t priv_key = ssl_load_pkcs12(fp, p, &msg);
|
||||
gnutls_x509_privkey_t priv_key = rsa_load_pkcs12(fp, p, &msg);
|
||||
if (!priv_key) {
|
||||
fclose(fp);
|
||||
*err = g_strdup_printf("Could not load PKCS#12 key file: %s", msg);
|
||||
|
|
|
@ -97,6 +97,7 @@
|
|||
#include <wsutil/utf8_entities.h>
|
||||
#include <wsutil/str_util.h>
|
||||
#include <wsutil/strtoi.h>
|
||||
#include <wsutil/rsa.h>
|
||||
#include "packet-tcp.h"
|
||||
#include "packet-x509af.h"
|
||||
#include "packet-ocsp.h"
|
||||
|
@ -409,7 +410,7 @@ ssl_parse_uat(void)
|
|||
}
|
||||
/* parse private keys string, load available keys and put them in key hash*/
|
||||
ssl_key_hash = g_hash_table_new_full(ssl_private_key_hash,
|
||||
ssl_private_key_equal, g_free, ssl_private_key_free);
|
||||
ssl_private_key_equal, g_free, rsa_private_key_free);
|
||||
|
||||
|
||||
if (nssldecrypt > 0) {
|
||||
|
|
|
@ -54,6 +54,7 @@ set(WSUTIL_COMMON_FILES
|
|||
os_version_info.c
|
||||
plugins.c
|
||||
privileges.c
|
||||
rsa.c
|
||||
sober128.c
|
||||
strnatcmp.c
|
||||
str_util.c
|
||||
|
@ -177,6 +178,7 @@ set(wsutil_LIBS
|
|||
${GCRYPT_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
${WIN_WSOCK32_LIBRARY}
|
||||
${GNUTLS_LIBRARIES}
|
||||
)
|
||||
IF(WIN32)
|
||||
set(wsutil_LIBS ${wsutil_LIBS} "iphlpapi.lib" "ws2_32.lib")
|
||||
|
|
|
@ -26,7 +26,8 @@ AM_CPPFLAGS = $(INCLUDEDIRS) $(WS_CPPFLAGS) -DWS_BUILD_DLL \
|
|||
-DEXTCAP_DIR=\"$(extcapdir)\" \
|
||||
-DPLUGIN_INSTALL_DIR=\"$(plugindir)\" \
|
||||
-DJSMN_STRICT \
|
||||
$(GLIB_CFLAGS) $(LIBGCRYPT_CFLAGS)
|
||||
$(GLIB_CFLAGS) $(LIBGCRYPT_CFLAGS) \
|
||||
$(LIBGNUTLS_CFLAGS)
|
||||
|
||||
# Optional headers for ABI checking
|
||||
wsutil_optional_abi_includes =
|
||||
|
@ -144,6 +145,7 @@ libwsutil_la_SOURCES = \
|
|||
plugins.c \
|
||||
privileges.c \
|
||||
report_message.c \
|
||||
rsa.c \
|
||||
sober128.c \
|
||||
str_util.c \
|
||||
strtoi.c \
|
||||
|
@ -174,6 +176,7 @@ libwsutil_la_LIBADD = \
|
|||
@COREFOUNDATION_FRAMEWORKS@ \
|
||||
@GLIB_LIBS@ \
|
||||
@LIBGCRYPT_LIBS@ \
|
||||
@LIBGNUTLS_LIBS@ \
|
||||
$(wsutil_optional_objects)
|
||||
|
||||
EXTRA_libwsutil_la_DEPENDENCIES = \
|
||||
|
@ -195,6 +198,7 @@ EXTRA_DIST = \
|
|||
inet_pton.c \
|
||||
popcount.c \
|
||||
popcount.h \
|
||||
rsa.h \
|
||||
strptime.c \
|
||||
strptime.h \
|
||||
win32-utils.c \
|
||||
|
|
|
@ -0,0 +1,338 @@
|
|||
/* rsa.c
|
||||
*
|
||||
* Functions for RSA private key reading and use
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@wireshark.org>
|
||||
* Copyright 2007 Gerald Combs
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "rsa.h"
|
||||
#include <glib.h>
|
||||
#include "filesystem.h"
|
||||
#include "file_util.h"
|
||||
#include "log.h"
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
#ifdef HAVE_LIBGNUTLS
|
||||
|
||||
#include <gnutls/abstract.h>
|
||||
#include <gnutls/pkcs12.h>
|
||||
|
||||
/* RSA private key file processing {{{ */
|
||||
#define RSA_PARS 6
|
||||
gcry_sexp_t
|
||||
rsa_privkey_to_sexp(gnutls_x509_privkey_t priv_key, char **err)
|
||||
{
|
||||
gnutls_datum_t rsa_datum[RSA_PARS]; /* m, e, d, p, q, u */
|
||||
size_t tmp_size;
|
||||
gcry_error_t gret;
|
||||
gcry_sexp_t rsa_priv_key = NULL;
|
||||
gint i;
|
||||
gcry_mpi_t rsa_params[RSA_PARS];
|
||||
*err = NULL;
|
||||
|
||||
/* RSA get parameter */
|
||||
if (gnutls_x509_privkey_export_rsa_raw(priv_key,
|
||||
&rsa_datum[0],
|
||||
&rsa_datum[1],
|
||||
&rsa_datum[2],
|
||||
&rsa_datum[3],
|
||||
&rsa_datum[4],
|
||||
&rsa_datum[5]) != 0) {
|
||||
*err = g_strdup("can't export rsa param (is a rsa private key file ?!?)");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* convert each rsa parameter to mpi format*/
|
||||
for(i=0; i<RSA_PARS; i++) {
|
||||
gret = gcry_mpi_scan(&rsa_params[i], GCRYMPI_FMT_USG, rsa_datum[i].data, rsa_datum[i].size,&tmp_size);
|
||||
/* these buffers were allocated by gnutls_x509_privkey_export_rsa_raw() */
|
||||
g_free(rsa_datum[i].data);
|
||||
if (gret != 0) {
|
||||
*err = g_strdup_printf("can't convert m rsa param to int (size %d)", rsa_datum[i].size);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* libgcrypt expects p < q, and gnutls might not return it as such, depending on gnutls version and its crypto backend */
|
||||
if (gcry_mpi_cmp(rsa_params[3], rsa_params[4]) > 0)
|
||||
{
|
||||
/* p, q = q, p */
|
||||
gcry_mpi_swap(rsa_params[3], rsa_params[4]);
|
||||
/* due to swapping p and q, u = p^-1 mod p which happens to be needed. */
|
||||
}
|
||||
/* libgcrypt expects u = p^-1 mod q (for OpenPGP), but the u parameter
|
||||
* says u = q^-1 mod p. Recompute u = p^-1 mod q. Do this unconditionally as
|
||||
* at least GnuTLS 2.12.23 computes an invalid value. */
|
||||
gcry_mpi_invm(rsa_params[5], rsa_params[3], rsa_params[4]);
|
||||
|
||||
if (gcry_sexp_build( &rsa_priv_key, NULL,
|
||||
"(private-key(rsa((n%m)(e%m)(d%m)(p%m)(q%m)(u%m))))", rsa_params[0],
|
||||
rsa_params[1], rsa_params[2], rsa_params[3], rsa_params[4],
|
||||
rsa_params[5]) != 0) {
|
||||
*err = g_strdup("can't build rsa private key s-exp");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i=0; i< 6; i++)
|
||||
gcry_mpi_release(rsa_params[i]);
|
||||
return rsa_priv_key;
|
||||
}
|
||||
|
||||
gnutls_x509_privkey_t
|
||||
rsa_load_pem_key(FILE *fp, char **err)
|
||||
{
|
||||
/* gnutls makes our work much harder, since we have to work internally with
|
||||
* s-exp formatted data, but PEM loader exports only in "gnutls_datum_t"
|
||||
* format, and a datum -> s-exp convertion function does not exist.
|
||||
*/
|
||||
gnutls_x509_privkey_t priv_key;
|
||||
gnutls_datum_t key;
|
||||
ws_statb64 statbuf;
|
||||
gint ret;
|
||||
guint bytes;
|
||||
*err = NULL;
|
||||
|
||||
if (ws_fstat64(ws_fileno(fp), &statbuf) == -1) {
|
||||
*err = g_strdup("can't ws_fstat64 file");
|
||||
return NULL;
|
||||
}
|
||||
if (S_ISDIR(statbuf.st_mode)) {
|
||||
*err = g_strdup("file is a directory");
|
||||
errno = EISDIR;
|
||||
return NULL;
|
||||
}
|
||||
if (S_ISFIFO(statbuf.st_mode)) {
|
||||
*err = g_strdup("file is a named pipe");
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if (!S_ISREG(statbuf.st_mode)) {
|
||||
*err = g_strdup("file is not a regular file");
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
/* XXX - check for a too-big size */
|
||||
/* load all file contents into a datum buffer*/
|
||||
key.data = (unsigned char *)g_malloc((size_t)statbuf.st_size);
|
||||
key.size = (int)statbuf.st_size;
|
||||
bytes = (guint) fread(key.data, 1, key.size, fp);
|
||||
if (bytes < key.size) {
|
||||
*err = g_strdup_printf("can't read from file %d bytes, got %d",
|
||||
key.size, bytes);
|
||||
g_free(key.data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* init private key data*/
|
||||
gnutls_x509_privkey_init(&priv_key);
|
||||
|
||||
/* import PEM data*/
|
||||
if ((ret = gnutls_x509_privkey_import(priv_key, &key, GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS) {
|
||||
*err = g_strdup_printf("can't import pem data: %s", gnutls_strerror(ret));
|
||||
g_free(key.data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (gnutls_x509_privkey_get_pk_algorithm(priv_key) != GNUTLS_PK_RSA) {
|
||||
*err = g_strdup("private key public key algorithm isn't RSA");
|
||||
g_free(key.data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_free(key.data);
|
||||
|
||||
return priv_key;
|
||||
}
|
||||
|
||||
static const char *
|
||||
BAGTYPE(gnutls_pkcs12_bag_type_t x) {
|
||||
switch (x) {
|
||||
case GNUTLS_BAG_EMPTY: return "Empty";
|
||||
case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY: return "PKCS#8 Encrypted key";
|
||||
case GNUTLS_BAG_PKCS8_KEY: return "PKCS#8 Key";
|
||||
case GNUTLS_BAG_CERTIFICATE: return "Certificate";
|
||||
case GNUTLS_BAG_CRL: return "CRL";
|
||||
case GNUTLS_BAG_ENCRYPTED: return "Encrypted";
|
||||
case GNUTLS_BAG_UNKNOWN: return "Unknown";
|
||||
default: return "<undefined>";
|
||||
}
|
||||
}
|
||||
|
||||
gnutls_x509_privkey_t
|
||||
rsa_load_pkcs12(FILE *fp, const gchar *cert_passwd, char **err)
|
||||
{
|
||||
int i, j, ret;
|
||||
int rest;
|
||||
unsigned char *p;
|
||||
gnutls_datum_t data;
|
||||
gnutls_pkcs12_bag_t bag = NULL;
|
||||
gnutls_pkcs12_bag_type_t bag_type;
|
||||
size_t len;
|
||||
|
||||
gnutls_pkcs12_t rsa_p12 = NULL;
|
||||
gnutls_x509_privkey_t rsa_pkey = NULL;
|
||||
|
||||
gnutls_x509_privkey_t priv_key = NULL;
|
||||
*err = NULL;
|
||||
|
||||
rest = 4096;
|
||||
data.data = (unsigned char *)g_malloc(rest);
|
||||
data.size = rest;
|
||||
p = data.data;
|
||||
while ((len = fread(p, 1, rest, fp)) > 0) {
|
||||
p += len;
|
||||
rest -= (int) len;
|
||||
if (!rest) {
|
||||
rest = 1024;
|
||||
data.data = (unsigned char *)g_realloc(data.data, data.size + rest);
|
||||
p = data.data + data.size;
|
||||
data.size += rest;
|
||||
}
|
||||
}
|
||||
data.size -= rest;
|
||||
if (!feof(fp)) {
|
||||
*err = g_strdup("Error during certificate reading.");
|
||||
g_free(data.data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = gnutls_pkcs12_init(&rsa_p12);
|
||||
if (ret < 0) {
|
||||
*err = g_strdup_printf("gnutls_pkcs12_init(&st_p12) - %s", gnutls_strerror(ret));
|
||||
g_free(data.data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* load PKCS#12 in DER or PEM format */
|
||||
ret = gnutls_pkcs12_import(rsa_p12, &data, GNUTLS_X509_FMT_DER, 0);
|
||||
if (ret < 0) {
|
||||
ret = gnutls_pkcs12_import(rsa_p12, &data, GNUTLS_X509_FMT_PEM, 0);
|
||||
if (ret < 0) {
|
||||
*err = g_strdup_printf("could not load PKCS#12 in DER or PEM format: %s", gnutls_strerror(ret));
|
||||
}
|
||||
}
|
||||
g_free(data.data);
|
||||
if (ret < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
g_log(NULL, G_LOG_LEVEL_INFO, "rsa_privkey_to_sexp: PKCS#12 imported\n");
|
||||
|
||||
/* TODO: Use gnutls_pkcs12_simple_parse, since 3.1.0 (August 2012) */
|
||||
for (i=0; ; i++) {
|
||||
|
||||
ret = gnutls_pkcs12_bag_init(&bag);
|
||||
if (ret < 0) break;
|
||||
|
||||
ret = gnutls_pkcs12_get_bag(rsa_p12, i, bag);
|
||||
if (ret < 0) break;
|
||||
|
||||
for (j=0; j<gnutls_pkcs12_bag_get_count(bag); j++) {
|
||||
|
||||
ret = gnutls_pkcs12_bag_get_type(bag, j);
|
||||
if (ret < 0) goto done;
|
||||
bag_type = (gnutls_pkcs12_bag_type_t)ret;
|
||||
if (bag_type >= GNUTLS_BAG_UNKNOWN) goto done;
|
||||
g_log(NULL, G_LOG_LEVEL_INFO, "Bag %d/%d: %s\n", i, j, BAGTYPE(bag_type));
|
||||
if (bag_type == GNUTLS_BAG_ENCRYPTED) {
|
||||
ret = gnutls_pkcs12_bag_decrypt(bag, cert_passwd);
|
||||
if (ret == 0) {
|
||||
ret = gnutls_pkcs12_bag_get_type(bag, j);
|
||||
if (ret < 0) goto done;
|
||||
bag_type = (gnutls_pkcs12_bag_type_t)ret;
|
||||
if (bag_type >= GNUTLS_BAG_UNKNOWN) goto done;
|
||||
g_log(NULL, G_LOG_LEVEL_INFO, "Bag %d/%d decrypted: %s\n", i, j, BAGTYPE(bag_type));
|
||||
}
|
||||
}
|
||||
|
||||
ret = gnutls_pkcs12_bag_get_data(bag, j, &data);
|
||||
if (ret < 0) goto done;
|
||||
|
||||
switch (bag_type) {
|
||||
|
||||
case GNUTLS_BAG_PKCS8_KEY:
|
||||
case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY:
|
||||
|
||||
ret = gnutls_x509_privkey_init(&rsa_pkey);
|
||||
if (ret < 0) {
|
||||
*err = g_strdup_printf("gnutls_x509_privkey_init(&rsa_pkey) - %s", gnutls_strerror(ret));
|
||||
goto done;
|
||||
}
|
||||
ret = gnutls_x509_privkey_import_pkcs8(rsa_pkey, &data, GNUTLS_X509_FMT_DER, cert_passwd,
|
||||
(bag_type==GNUTLS_BAG_PKCS8_KEY) ? GNUTLS_PKCS_PLAIN : 0);
|
||||
if (ret < 0) {
|
||||
*err = g_strdup_printf("Can not decrypt private key - %s", gnutls_strerror(ret));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (gnutls_x509_privkey_get_pk_algorithm(rsa_pkey) != GNUTLS_PK_RSA) {
|
||||
*err = g_strdup("private key public key algorithm isn't RSA");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Private key found, return it. */
|
||||
priv_key = rsa_pkey;
|
||||
goto done;
|
||||
break;
|
||||
|
||||
default: ;
|
||||
}
|
||||
} /* j */
|
||||
if (bag) { gnutls_pkcs12_bag_deinit(bag); bag = NULL; }
|
||||
} /* i */
|
||||
|
||||
done:
|
||||
if (!priv_key && rsa_pkey)
|
||||
gnutls_x509_privkey_deinit(rsa_pkey);
|
||||
if (bag)
|
||||
gnutls_pkcs12_bag_deinit(bag);
|
||||
|
||||
return priv_key;
|
||||
}
|
||||
|
||||
void
|
||||
rsa_private_key_free(gpointer key)
|
||||
{
|
||||
gcry_sexp_release((gcry_sexp_t) key);
|
||||
}
|
||||
|
||||
#else /* ! defined(HAVE_LIBGNUTLS) */
|
||||
|
||||
void
|
||||
rsa_private_key_free(gpointer key _U_)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* HAVE_LIBGNUTLS */
|
||||
|
||||
/*
|
||||
* Editor modelines - http://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=4 tabstop=8 expandtab:
|
||||
* :indentSize=4:tabSize=8:noTabs=true:
|
||||
*/
|
|
@ -0,0 +1,55 @@
|
|||
/* rsa.h
|
||||
*
|
||||
* Functions for RSA private key reading and use
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@wireshark.org>
|
||||
* Copyright 2007 Gerald Combs
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef __RSA_H__
|
||||
#define __RSA_H__
|
||||
|
||||
#include "ws_symbol_export.h"
|
||||
#include "wsgcrypt.h"
|
||||
|
||||
#ifdef HAVE_LIBGNUTLS
|
||||
#include <gnutls/abstract.h>
|
||||
WS_DLL_PUBLIC gcry_sexp_t rsa_privkey_to_sexp(gnutls_x509_privkey_t priv_key, char **err);
|
||||
|
||||
/**
|
||||
* Load an RSA private key from specified file
|
||||
* @param fp the file that contain the key data
|
||||
* @param [out] err error message upon failure; NULL upon success
|
||||
* @return a pointer to the loaded key on success, or NULL upon failure
|
||||
*/
|
||||
WS_DLL_PUBLIC gnutls_x509_privkey_t rsa_load_pem_key(FILE* fp, char **err);
|
||||
|
||||
/**
|
||||
* Load a RSA private key from a PKCS#12 file (DER or PEM format)
|
||||
* @param fp the file that contains the key data
|
||||
* @param cert_passwd password to decrypt the PKCS#12 file
|
||||
* @param [out] err error message upon failure; NULL upon success
|
||||
* @return a pointer to the loaded key on success; NULL upon failure
|
||||
*/
|
||||
WS_DLL_PUBLIC gnutls_x509_privkey_t rsa_load_pkcs12(FILE* fp, const char *cert_passwd, char** err);
|
||||
#endif
|
||||
|
||||
WS_DLL_PUBLIC void rsa_private_key_free(gpointer key);
|
||||
|
||||
|
||||
#endif /* __RSA_H__ */
|
|
@ -71,6 +71,92 @@ void crypt_des_ecb(guint8 *output, const guint8 *buffer, const guint8 *key56)
|
|||
gcry_cipher_close(handle);
|
||||
}
|
||||
|
||||
size_t rsa_decrypt_inplace(const guint len, guchar* data, gcry_sexp_t pk, gboolean pkcs1_padding, char **err)
|
||||
{
|
||||
gint rc = 0;
|
||||
size_t decr_len = 0, i = 0;
|
||||
gcry_sexp_t s_data = NULL, s_plain = NULL;
|
||||
gcry_mpi_t encr_mpi = NULL, text = NULL;
|
||||
|
||||
*err = NULL;
|
||||
|
||||
/* create mpi representation of encrypted data */
|
||||
rc = gcry_mpi_scan(&encr_mpi, GCRYMPI_FMT_USG, data, len, NULL);
|
||||
if (rc != 0 ) {
|
||||
*err = g_strdup_printf("can't convert data to mpi (size %d):%s", len, gcry_strerror(rc));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* put the data into a simple list */
|
||||
rc = gcry_sexp_build(&s_data, NULL, "(enc-val(rsa(a%m)))", encr_mpi);
|
||||
if (rc != 0) {
|
||||
*err = g_strdup_printf("can't build encr_sexp:%s", gcry_strerror(rc));
|
||||
decr_len = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* pass it to libgcrypt */
|
||||
rc = gcry_pk_decrypt(&s_plain, s_data, pk);
|
||||
if (rc != 0)
|
||||
{
|
||||
*err = g_strdup_printf("can't decrypt key:%s", gcry_strerror(rc));
|
||||
decr_len = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* convert plain text sexp to mpi format */
|
||||
text = gcry_sexp_nth_mpi(s_plain, 0, 0);
|
||||
if (! text) {
|
||||
*err = g_strdup("can't convert sexp to mpi");
|
||||
decr_len = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* compute size requested for plaintext buffer */
|
||||
rc = gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &decr_len, text);
|
||||
if (rc != 0) {
|
||||
*err = g_strdup_printf("can't compute decr size:%s", gcry_strerror(rc));
|
||||
decr_len = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* sanity check on out buffer */
|
||||
if (decr_len > len) {
|
||||
*err = g_strdup_printf("decrypted data is too long ?!? (%" G_GSIZE_MODIFIER "u max %d)", decr_len, len);
|
||||
decr_len = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* write plain text to newly allocated buffer */
|
||||
rc = gcry_mpi_print(GCRYMPI_FMT_USG, data, len, &decr_len, text);
|
||||
if (rc != 0) {
|
||||
*err = g_strdup_printf("can't print decr data to mpi (size %" G_GSIZE_MODIFIER "u):%s", decr_len, gcry_strerror(rc));
|
||||
decr_len = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pkcs1_padding) {
|
||||
/* strip the padding*/
|
||||
rc = 0;
|
||||
for (i = 1; i < decr_len; i++) {
|
||||
if (data[i] == 0) {
|
||||
rc = (gint) i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
decr_len -= rc;
|
||||
memmove(data, data+rc, decr_len);
|
||||
}
|
||||
|
||||
out:
|
||||
gcry_sexp_release(s_data);
|
||||
gcry_sexp_release(s_plain);
|
||||
gcry_mpi_release(encr_mpi);
|
||||
gcry_mpi_release(text);
|
||||
return decr_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines - http://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
|
|
|
@ -51,4 +51,8 @@ WS_DLL_PUBLIC gcry_error_t ws_hmac_buffer(int algo, void *digest, const void *bu
|
|||
64 bits as key, encrypted data is returned in OUTPUT which must be at least 8 bytes large */
|
||||
WS_DLL_PUBLIC void crypt_des_ecb(guint8 *output, const guint8 *buffer, const guint8 *key56);
|
||||
|
||||
/* Convenience function for RSA decryption. Returns decrypted length on success, 0 on failure */
|
||||
WS_DLL_PUBLIC size_t rsa_decrypt_inplace(const guint len, guchar* data, gcry_sexp_t pk, gboolean pkcs1_padding, char **err);
|
||||
|
||||
|
||||
#endif /* __WSGCRYPT_H__ */
|
||||
|
|
Loading…
Reference in New Issue