From 434ea3aa21e01de4fe6422392c0c76a369b60ab1 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Mon, 3 Dec 2012 00:52:08 +0100 Subject: [PATCH] Import PKCS #12 keys --- lib/gnutls_privkey.c | 4 ++-- lib/x509/pkcs12.c | 40 +++++++++++++++++++++++----------------- lib/x509/privkey.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++--- tests/key-openssl.c | 13 +++++++++++++ tests/pkcs12_simple.c | 24 ++++++++++++++++++++++-- 5 files changed, 107 insertions(+), 24 deletions(-) diff --git a/lib/gnutls_privkey.c b/lib/gnutls_privkey.c index f718b7cf6..7a3fee603 100644 --- a/lib/gnutls_privkey.c +++ b/lib/gnutls_privkey.c @@ -905,8 +905,8 @@ gnutls_privkey_decrypt_data (gnutls_privkey_t key, * This function will import the given private key to the abstract * #gnutls_privkey_t structure. * - * The supported formats are typical X.509, PKCS #8 and the openssl - * format. + * The supported formats are basic unencrypted key, PKCS #8, PKCS #12, + * and the openssl format. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. diff --git a/lib/x509/pkcs12.c b/lib/x509/pkcs12.c index 1344589d9..dbaebc2ec 100644 --- a/lib/x509/pkcs12.c +++ b/lib/x509/pkcs12.c @@ -1385,13 +1385,13 @@ skip: * @p12: the PKCS#12 blob. * @password: optional password used to decrypt PKCS#12 blob, bags and keys. * @key: a structure to store the parsed private key. - * @chain: the corresponding to key certificate chain - * @chain_len: will be updated with the number of additional + * @chain: the corresponding to key certificate chain (may be %NULL) + * @chain_len: will be updated with the number of additional (may be %NULL) * @extra_certs: optional pointer to receive an array of additional - * certificates found in the PKCS#12 blob. + * certificates found in the PKCS#12 blob (may be %NULL). * @extra_certs_len: will be updated with the number of additional - * certs. - * @crl: an optional structure to store the parsed CRL. + * certs (may be %NULL). + * @crl: an optional structure to store the parsed CRL (may be %NULL). * @flags: should be zero or one of GNUTLS_PKCS12_SP_* * * This function parses a PKCS#12 blob in @p12blob and extracts the @@ -1718,7 +1718,7 @@ gnutls_pkcs12_simple_parse (gnutls_pkcs12_t p12, } else { - if (_chain_len == 0) + if (chain && _chain_len == 0) { _chain = gnutls_malloc (sizeof(_chain[0]) * (++_chain_len)); if (!_chain) @@ -1773,17 +1773,20 @@ gnutls_pkcs12_simple_parse (gnutls_pkcs12_t p12, gnutls_pkcs12_bag_deinit (bag); } - if (_chain_len != 1) + if (chain != NULL) { - ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; - goto done; - } + if (_chain_len != 1) + { + ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + goto done; + } - ret = make_chain(&_chain, &_chain_len, &_extra_certs, &_extra_certs_len, flags); - if (ret < 0) - { - gnutls_assert(); - goto done; + ret = make_chain(&_chain, &_chain_len, &_extra_certs, &_extra_certs_len, flags); + if (ret < 0) + { + gnutls_assert(); + goto done; + } } ret = 0; @@ -1829,8 +1832,11 @@ done: gnutls_free(_extra_certs); } - *chain = _chain; - *chain_len = _chain_len; + if (chain != NULL) + { + *chain = _chain; + *chain_len = _chain_len; + } return ret; } diff --git a/lib/x509/privkey.c b/lib/x509/privkey.c index 820a69ff7..ca47fa7b0 100644 --- a/lib/x509/privkey.c +++ b/lib/x509/privkey.c @@ -558,6 +558,49 @@ failover: return result; } +static int import_pkcs12_privkey (gnutls_x509_privkey_t key, + const gnutls_datum_t * data, + gnutls_x509_crt_fmt_t format, + const char* password, unsigned int flags) +{ +int ret; +gnutls_pkcs12_t p12; +gnutls_x509_privkey_t newkey; + + ret = gnutls_pkcs12_init(&p12); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = gnutls_pkcs12_import(p12, data, format, flags); + if (ret < 0) + { + gnutls_assert(); + goto fail; + } + + ret = gnutls_pkcs12_simple_parse (p12, password, &newkey, NULL, NULL, NULL, NULL, NULL, 0); + if (ret < 0) + { + gnutls_assert(); + goto fail; + } + + ret = gnutls_x509_privkey_cpy (key, newkey); + gnutls_x509_privkey_deinit (newkey); + if (ret < 0) + { + gnutls_assert(); + goto fail; + } + + ret = 0; +fail: + + gnutls_pkcs12_deinit(p12); + + return ret; +} + /** * gnutls_x509_privkey_import2: * @key: The structure to store the parsed key @@ -570,8 +613,8 @@ failover: * the native #gnutls_x509_privkey_t format, irrespective of the * input format. The input format is auto-detected. * - * The supported formats are typical X.509, PKCS #8 and the openssl - * format. + * The supported formats are basic unencrypted key, PKCS #8, PKCS #12, + * and the openssl format. * * If the provided key is encrypted but no password was given, then * %GNUTLS_E_DECRYPTION_FAILED is returned. @@ -601,7 +644,8 @@ gnutls_x509_privkey_import2 (gnutls_x509_privkey_t key, ret = gnutls_x509_privkey_import_pkcs8(key, data, format, password, flags); if (ret < 0) { - if (format == GNUTLS_X509_FMT_PEM) + ret = import_pkcs12_privkey(key, data, format, password, flags); + if (ret < 0 && format == GNUTLS_X509_FMT_PEM) { int err; err = gnutls_x509_privkey_import_openssl(key, data, password); diff --git a/tests/key-openssl.c b/tests/key-openssl.c index 9d2ef9d46..02d174ed1 100644 --- a/tests/key-openssl.c +++ b/tests/key-openssl.c @@ -106,8 +106,21 @@ doit (void) { fail ("gnutls_x509_privkey_import_openssl (key2): %s\n", gnutls_strerror(ret)) ; } + gnutls_x509_privkey_deinit (pkey); + ret = gnutls_x509_privkey_init (&pkey); + if (ret < 0) + fail ("gnutls_x509_privkey_init: %d\n", ret); + + key.data = (void*)key1; + key.size = sizeof(key1); + ret = gnutls_x509_privkey_import2 (pkey, &key, GNUTLS_X509_FMT_PEM, "123456", 0); + if (ret < 0) + { + fail ("gnutls_x509_privkey_import2: %s\n", gnutls_strerror(ret)) ; + } + gnutls_x509_privkey_deinit (pkey); gnutls_global_deinit (); } diff --git a/tests/pkcs12_simple.c b/tests/pkcs12_simple.c index ad17c0e41..5da59ef15 100644 --- a/tests/pkcs12_simple.c +++ b/tests/pkcs12_simple.c @@ -30,6 +30,12 @@ #include #include "utils.h" +static void +tls_log_func (int level, const char *str) +{ + fprintf (stderr, "<%d>| %s", level, str); +} + void doit (void) { @@ -47,6 +53,10 @@ doit (void) if (ret < 0) fail ("gnutls_global_init failed %d\n", ret); + gnutls_global_set_log_function (tls_log_func); + if (debug) + gnutls_global_set_log_level (2); + ret = gnutls_pkcs12_init(&pkcs12); if (ret < 0) fail ("initialization failed: %s\n", gnutls_strerror(ret)); @@ -70,8 +80,6 @@ doit (void) if (ret < 0) fail ("pkcs12_import failed %d: %s\n", ret, gnutls_strerror (ret)); - free(file_data); - if (debug) success ("Read file OK\n"); @@ -116,6 +124,18 @@ doit (void) for (i=0;i