summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2012-12-03 00:52:08 +0100
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2012-12-06 08:58:41 +0100
commit434ea3aa21e01de4fe6422392c0c76a369b60ab1 (patch)
tree51b93b8b56b5f48b6eda8d4388876c8615b8347b
parentdd901da76d4e1453feec20abb5287f009a9a7701 (diff)
downloadgnutls-434ea3aa21e01de4fe6422392c0c76a369b60ab1.tar.gz
Import PKCS #12 keys
-rw-r--r--lib/gnutls_privkey.c4
-rw-r--r--lib/x509/pkcs12.c40
-rw-r--r--lib/x509/privkey.c50
-rw-r--r--tests/key-openssl.c13
-rw-r--r--tests/pkcs12_simple.c24
5 files changed, 107 insertions, 24 deletions
diff --git a/lib/gnutls_privkey.c b/lib/gnutls_privkey.c
index f718b7cf69..7a3fee6031 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 1344589d9d..dbaebc2ecc 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 820a69ff78..ca47fa7b0e 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 9d2ef9d460..02d174ed16 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 ad17c0e413..5da59ef154 100644
--- a/tests/pkcs12_simple.c
+++ b/tests/pkcs12_simple.c
@@ -30,6 +30,12 @@
#include <gnutls/x509.h>
#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<extras_size;i++)
gnutls_x509_crt_deinit(extras[i]);
gnutls_free(extras);
+
+ /* Try gnutls_x509_privkey_import2() */
+ ret = gnutls_x509_privkey_init(&pkey);
+ if (ret < 0)
+ fail ("gnutls_x509_privkey_init failed %d: %s\n", ret, gnutls_strerror (ret));
+
+ ret = gnutls_x509_privkey_import2(pkey, &data, GNUTLS_X509_FMT_DER, password, 0);
+ if (ret < 0)
+ fail ("gnutls_x509_privkey_import2 failed %d: %s\n", ret, gnutls_strerror (ret));
+ gnutls_x509_privkey_deinit(pkey);
+
+ free(file_data);
gnutls_global_deinit ();
}