summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2003-06-22 15:41:35 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2003-06-22 15:41:35 +0000
commitf4e57a2adcf02300f77e0dfd8fd2473ddf9b093b (patch)
tree2ceb32bc0e636cccb27306302d9a2c460c82a7cd
parentec25481a53e00bea061dac0d196193c241b884f1 (diff)
downloadgnutls-f4e57a2adcf02300f77e0dfd8fd2473ddf9b093b.tar.gz
Some additions to allow decrypting PKCS #5 encrypted data, with PKCS #12 schema OIDs.
-rw-r--r--lib/Makefile.am3
-rw-r--r--lib/pkix.asn5
-rw-r--r--lib/pkix_asn1_tab.c3
-rw-r--r--lib/x509/Makefile.am2
-rw-r--r--lib/x509/common.h3
-rw-r--r--lib/x509/pkcs12.h4
-rw-r--r--lib/x509/pkcs12_bag.c30
-rw-r--r--lib/x509/pkcs12_encr.c92
-rw-r--r--lib/x509/privkey_pkcs8.c1100
9 files changed, 886 insertions, 356 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 23016e8613..f261e7fb67 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -49,7 +49,8 @@ libgnutls_la_SOURCES = $(COBJECTS)
libgnutls_la_LIBADD = $(MINITASN1_OBJECTS) x509/dn.lo x509/crl.lo x509/common.lo \
x509/x509.lo x509/extensions.lo x509/compat.lo x509/verify.lo \
x509/mpi.lo x509/privkey.lo x509/pkcs7.lo x509/crq.lo x509/xml.lo x509/sign.lo \
- x509/pkcs5.lo x509/privkey_pkcs8.lo x509/pkcs12.lo x509/pkcs12_bag.lo
+ x509/pkcs5.lo x509/privkey_pkcs8.lo x509/pkcs12.lo x509/pkcs12_bag.lo \
+ x509/pkcs12_encr.lo
libgnutls_la_LDFLAGS = $(LIBASN1_LINK) $(LIBGCRYPT_LIBS) \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
diff --git a/lib/pkix.asn b/lib/pkix.asn
index 62d05de9a3..b8b90c51dd 100644
--- a/lib/pkix.asn
+++ b/lib/pkix.asn
@@ -1094,6 +1094,11 @@ pkcs-12-PFX ::= SEQUENCE {
macData pkcs-12-MacData OPTIONAL
}
+pkcs-12-PbeParams ::= SEQUENCE {
+ salt OCTET STRING,
+ iterations INTEGER
+}
+
pkcs-12-MacData ::= ANY
-- we don't use it
-- SEQUENCE {
diff --git a/lib/pkix_asn1_tab.c b/lib/pkix_asn1_tab.c
index cfe46a72ba..2ce535bc94 100644
--- a/lib/pkix_asn1_tab.c
+++ b/lib/pkix_asn1_tab.c
@@ -979,6 +979,9 @@ const ASN1_ARRAY_TYPE pkix_asn1_tab[]={
{"v3",1,"3"},
{"authSafe",1073741826,"pkcs-7-ContentInfo"},
{"macData",16386,"pkcs-12-MacData"},
+ {"pkcs-12-PbeParams",1610612741,0},
+ {"salt",1073741831,0},
+ {"iterations",3,0},
{"pkcs-12-MacData",1073741837,0},
{"pkcs-12-AuthenticatedSafe",1610612747,0},
{0,2,"pkcs-7-ContentInfo"},
diff --git a/lib/x509/Makefile.am b/lib/x509/Makefile.am
index f5730d938d..8e3696db04 100644
--- a/lib/x509/Makefile.am
+++ b/lib/x509/Makefile.am
@@ -9,7 +9,7 @@ noinst_LTLIBRARIES = libx509.la
COBJECTS = crl.c dn.c common.c x509.c extensions.c \
rfc2818_hostname.c verify.c mpi.c privkey.c pkcs7.c \
crq.c xml.c sign.c pkcs5.c privkey_pkcs8.c pkcs12.c \
- pkcs12_bag.c
+ pkcs12_bag.c pkcs12_encr.c
COMPAT_OBJECTS = compat.c
diff --git a/lib/x509/common.h b/lib/x509/common.h
index dc7007bb0d..f40480d377 100644
--- a/lib/x509/common.h
+++ b/lib/x509/common.h
@@ -48,3 +48,6 @@ int _gnutls_x509_export_int( ASN1_TYPE asn1_data,
int tmp_buf_size, unsigned char* output_data, int* output_data_size);
int _gnutls_x509_read_value( ASN1_TYPE c, const char* root, gnutls_datum *ret, int str);
+
+int _gnutls_x509_decrypt_pkcs7_encrypted_data( const gnutls_datum* data,
+ const char* password, gnutls_datum* dec);
diff --git a/lib/x509/pkcs12.h b/lib/x509/pkcs12.h
index 256c353560..272fbb4608 100644
--- a/lib/x509/pkcs12.h
+++ b/lib/x509/pkcs12.h
@@ -31,3 +31,7 @@ int gnutls_pkcs12_get_bag(gnutls_pkcs12 pkcs12,
int gnutls_pkcs12_bag_init(gnutls_pkcs12_bag * bag);
void gnutls_pkcs12_bag_deinit(gnutls_pkcs12_bag bag);
+
+int
+_pkcs12_string_to_key (int id, const char *salt, int salt_size, int iter, const char *pw,
+ int req_keylen, unsigned char *keybuf);
diff --git a/lib/x509/pkcs12_bag.c b/lib/x509/pkcs12_bag.c
index 9db5ee5a25..2c3f397ac0 100644
--- a/lib/x509/pkcs12_bag.c
+++ b/lib/x509/pkcs12_bag.c
@@ -95,5 +95,35 @@ int gnutls_pkcs12_bag_get_data(gnutls_pkcs12_bag bag, gnutls_datum* data)
return 0;
}
+/**
+ * gnutls_pkcs12_bag_decrypt - This function will decrypt an encrypted bag
+ * @bag: The bag
+ * @pass: The password used for encryption
+ *
+ * This function will return 0 on success.
+ *
+ **/
+int gnutls_pkcs12_bag_decrypt(gnutls_pkcs12_bag bag, const char* pass)
+{
+int ret;
+gnutls_datum dec;
+
+ ret = _gnutls_x509_decrypt_pkcs7_encrypted_data(
+ &bag->data, pass, &dec);
+
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ /* decryption succeeded */
+
+ _gnutls_free_datum( &bag->data);
+
+ bag->data = dec;
+
+ return 0;
+}
+
#endif /* ENABLE_PKI */
diff --git a/lib/x509/pkcs12_encr.c b/lib/x509/pkcs12_encr.c
new file mode 100644
index 0000000000..ec917978bf
--- /dev/null
+++ b/lib/x509/pkcs12_encr.c
@@ -0,0 +1,92 @@
+/* Taken from minip12
+ */
+
+#include <gcrypt.h>
+#include <gnutls_errors.h>
+
+int
+_pkcs12_string_to_key (int id, const char *salt, int salt_size, int iter, const char *pw,
+ int req_keylen, unsigned char *keybuf)
+{
+ int rc, i, j;
+ GcryMDHd md;
+ GcryMPI num_b1 = NULL;
+ int pwlen;
+ unsigned char hash[20], buf_b[64], buf_i[128], *p;
+ size_t cur_keylen;
+ size_t n;
+
+ cur_keylen = 0;
+ pwlen = strlen (pw);
+ if (pwlen > 63/2 || salt_size > 8)
+ {
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ /* Store salt and password in BUF_I */
+ p = buf_i;
+ for(i=0; i < 64; i++)
+ *p++ = salt [i%8];
+ for(i=j=0; i < 64; i += 2)
+ {
+ *p++ = 0;
+ *p++ = pw[j];
+ if (++j > pwlen) /* Note, that we include the trailing zero */
+ j = 0;
+ }
+
+ for (;;)
+ {
+ md = gcry_md_open (GCRY_MD_SHA1, 0);
+ if (!md)
+ {
+ return GNUTLS_E_DECRYPTION_FAILED;
+ }
+ for(i=0; i < 64; i++)
+ gcry_md_putc (md, id);
+ gcry_md_write (md, buf_i, 128);
+ memcpy (hash, gcry_md_read (md, 0), 20);
+ gcry_md_close (md);
+ for (i=1; i < iter; i++)
+ gcry_md_hash_buffer (GCRY_MD_SHA1, hash, hash, 20);
+
+ for (i=0; i < 20 && cur_keylen < req_keylen; i++)
+ keybuf[cur_keylen++] = hash[i];
+ if (cur_keylen == req_keylen)
+ {
+ gcry_mpi_release (num_b1);
+ return 0; /* ready */
+ }
+
+ /* need more bytes. */
+ for(i=0; i < 64; i++)
+ buf_b[i] = hash[i % 20];
+ n = 64;
+ rc = gcry_mpi_scan (&num_b1, GCRYMPI_FMT_USG, buf_b, &n);
+ if (rc)
+ {
+ return GNUTLS_E_DECRYPTION_FAILED;
+ }
+ gcry_mpi_add_ui (num_b1, num_b1, 1);
+ for (i=0; i < 128; i += 64)
+ {
+ GcryMPI num_ij;
+
+ n = 64;
+ rc = gcry_mpi_scan (&num_ij, GCRYMPI_FMT_USG, buf_i + i, &n);
+ if (rc)
+ {
+ return GNUTLS_E_DECRYPTION_FAILED;
+ }
+ gcry_mpi_add (num_ij, num_ij, num_b1);
+ gcry_mpi_clear_highbit (num_ij, 64*8);
+ n = 64;
+ rc = gcry_mpi_print (GCRYMPI_FMT_USG, buf_i + i, &n, num_ij);
+ if (rc)
+ {
+ return GNUTLS_E_DECRYPTION_FAILED;
+ }
+ gcry_mpi_release (num_ij);
+ }
+ }
+}
diff --git a/lib/x509/privkey_pkcs8.c b/lib/x509/privkey_pkcs8.c
index 9fc1809c7b..218bdba32c 100644
--- a/lib/x509/privkey_pkcs8.c
+++ b/lib/x509/privkey_pkcs8.c
@@ -33,6 +33,7 @@
#include <x509.h>
#include <dn.h>
#include <pkcs5.h>
+#include <pkcs12.h>
#include <privkey.h>
#include <extensions.h>
#include <mpi.h>
@@ -40,6 +41,11 @@
#include <gnutls_random.h>
#include <gnutls_num.h>
+typedef enum schema_id {
+ PBES2, /* the stuff in PKCS #5 */
+ PKCS12_3DES_SHA1 /* the fucking stuff in PKCS #12 */
+} schema_id;
+
#define PBES2_OID "1.2.840.113549.1.5.13"
#define PBKDF2_OID "1.2.840.113549.1.5.12"
#define DES_EDE3_CBC_OID "1.2.840.113549.3.7"
@@ -55,37 +61,66 @@ struct pbkdf2_params {
};
struct pbe_enc_params {
+ gnutls_cipher_algorithm cipher;
opaque iv[8];
int iv_size;
};
-static int generate_key( const char* password, unsigned int flags, struct pbkdf2_params* kdf_params,
- struct pbe_enc_params* enc_params, gnutls_datum * key);
-static int read_pbkdf2_params( ASN1_TYPE pbes2_asn, const gnutls_datum* der,
- struct pbkdf2_params* params);
-static int read_pbe_enc_params( ASN1_TYPE pbes2_asn, const gnutls_datum* der,
- struct pbe_enc_params* params);
-static int decrypt_data( ASN1_TYPE pkcs8_asn, const char* password,
- const struct pbkdf2_params* kdf_params, const struct pbe_enc_params *enc_params,
- gnutls_datum* decrypted_data);
-static ASN1_TYPE decode_private_key_info( const gnutls_datum* der, gnutls_x509_privkey pkey);
-static int write_pbe2_params( ASN1_TYPE pkcs8_asn, const struct pbkdf2_params* kdf_params,
- const struct pbe_enc_params* enc_params);
-static int encrypt_data( const gnutls_datum* plain,
- const struct pbe_enc_params *enc_params,
- gnutls_datum* key, gnutls_datum* encrypted);
+static int generate_key(const char *password, unsigned int flags,
+ struct pbkdf2_params *kdf_params,
+ struct pbe_enc_params *enc_params,
+ gnutls_datum * key);
+static int read_pbkdf2_params(ASN1_TYPE pbes2_asn,
+ const gnutls_datum * der,
+ struct pbkdf2_params *params);
+static int read_pbe_enc_params(ASN1_TYPE pbes2_asn,
+ const gnutls_datum * der,
+ struct pbe_enc_params *params);
+static int decrypt_data(schema_id, ASN1_TYPE pkcs8_asn, const char *root,
+ const char *password,
+ const struct pbkdf2_params *kdf_params,
+ const struct pbe_enc_params *enc_params,
+ gnutls_datum * decrypted_data);
+static ASN1_TYPE decode_private_key_info(const gnutls_datum * der,
+ gnutls_x509_privkey pkey);
+static int write_pbe2_params(ASN1_TYPE pkcs8_asn,
+ const struct pbkdf2_params *kdf_params,
+ const struct pbe_enc_params *enc_params);
+static int encrypt_data(const gnutls_datum * plain,
+ const struct pbe_enc_params *enc_params,
+ gnutls_datum * key, gnutls_datum * encrypted);
+
+static int read_pkcs12_kdf_params(ASN1_TYPE pbes2_asn,
+ struct pbkdf2_params *params);
#define PEM_PKCS8 "ENCRYPTED PRIVATE KEY"
#define PEM_UNENCRYPTED_PKCS8 "PRIVATE KEY"
+/* Returns a negative error code if the encryption schema in
+ * the OID is not supported. The schema ID is returned.
+ */
+inline static int check_schema(const char *oid)
+{
+
+ if (strcmp(oid, PBES2_OID) == 0)
+ return PBES2;
+
+ if (strcmp(oid, PBE_3DES_SHA1_OID) == 0)
+ return PKCS12_3DES_SHA1;
+
+ _gnutls_x509_log("PKCS encryption schema OID '%s' is unsupported.\n", oid);
+
+ return GNUTLS_E_UNKNOWN_CIPHER_TYPE;
+}
/*
* Encodes a PKCS #1 private key to a PKCS #8 private key
* info. The output will be allocated and stored into der. Also
* the ASN1_TYPE of private key info will be returned.
*/
-static int encode_to_private_key_info( gnutls_x509_privkey pkey, gnutls_datum* der,
- ASN1_TYPE *pkey_info)
+static int encode_to_private_key_info(gnutls_x509_privkey pkey,
+ gnutls_datum * der,
+ ASN1_TYPE * pkey_info)
{
int result, size;
opaque *data = NULL;
@@ -98,8 +133,8 @@ static int encode_to_private_key_info( gnutls_x509_privkey pkey, gnutls_datum* d
if ((result =
asn1_create_element(_gnutls_get_pkix(),
- "PKIX1.pkcs-8-PrivateKeyInfo", pkey_info
- )) != ASN1_SUCCESS) {
+ "PKIX1.pkcs-8-PrivateKeyInfo",
+ pkey_info)) != ASN1_SUCCESS) {
gnutls_assert();
result = _gnutls_asn2err(result);
goto error;
@@ -107,7 +142,7 @@ static int encode_to_private_key_info( gnutls_x509_privkey pkey, gnutls_datum* d
/* Write the version.
*/
- result = asn1_write_value( *pkey_info, "version", &null, 1);
+ result = asn1_write_value(*pkey_info, "version", &null, 1);
if (result != ASN1_SUCCESS) {
gnutls_assert();
result = _gnutls_asn2err(result);
@@ -117,14 +152,18 @@ static int encode_to_private_key_info( gnutls_x509_privkey pkey, gnutls_datum* d
/* write the privateKeyAlgorithm
* fields. (OID+NULL data)
*/
- result = asn1_write_value( *pkey_info, "privateKeyAlgorithm.algorithm", PKIX1_RSA_OID, 1);
+ result =
+ asn1_write_value(*pkey_info, "privateKeyAlgorithm.algorithm",
+ PKIX1_RSA_OID, 1);
if (result != ASN1_SUCCESS) {
gnutls_assert();
result = _gnutls_asn2err(result);
goto error;
}
- result = asn1_write_value( *pkey_info, "privateKeyAlgorithm.parameters", NULL, 0);
+ result =
+ asn1_write_value(*pkey_info, "privateKeyAlgorithm.parameters",
+ NULL, 0);
if (result != ASN1_SUCCESS) {
gnutls_assert();
result = _gnutls_asn2err(result);
@@ -133,29 +172,33 @@ static int encode_to_private_key_info( gnutls_x509_privkey pkey, gnutls_datum* d
/* Write the raw private key
*/
- result = gnutls_x509_privkey_export( pkey, GNUTLS_X509_FMT_DER, NULL, &size);
+ result =
+ gnutls_x509_privkey_export(pkey, GNUTLS_X509_FMT_DER, NULL,
+ &size);
if (result != GNUTLS_E_SHORT_MEMORY_BUFFER) {
gnutls_assert();
goto error;
}
- data = gnutls_alloca( size);
+ data = gnutls_alloca(size);
if (data == NULL) {
gnutls_assert();
result = GNUTLS_E_MEMORY_ERROR;
goto error;
}
-
- result = gnutls_x509_privkey_export( pkey, GNUTLS_X509_FMT_DER, data, &size);
+
+ result =
+ gnutls_x509_privkey_export(pkey, GNUTLS_X509_FMT_DER, data,
+ &size);
if (result < 0) {
gnutls_assert();
goto error;
}
- result = asn1_write_value( *pkey_info, "privateKey", data, size);
-
- gnutls_afree( data);
+ result = asn1_write_value(*pkey_info, "privateKey", data, size);
+
+ gnutls_afree(data);
data = NULL;
if (result != ASN1_SUCCESS) {
@@ -166,7 +209,7 @@ static int encode_to_private_key_info( gnutls_x509_privkey pkey, gnutls_datum* d
/* Append an empty Attributes field.
*/
- result = asn1_write_value( *pkey_info, "attributes", NULL, 0);
+ result = asn1_write_value(*pkey_info, "attributes", NULL, 0);
if (result != ASN1_SUCCESS) {
gnutls_assert();
result = _gnutls_asn2err(result);
@@ -176,7 +219,7 @@ static int encode_to_private_key_info( gnutls_x509_privkey pkey, gnutls_datum* d
/* DER Encode the generated private key info.
*/
size = 0;
- result = asn1_der_coding( *pkey_info, "", NULL, &size, NULL);
+ result = asn1_der_coding(*pkey_info, "", NULL, &size, NULL);
if (result != ASN1_MEM_ERROR) {
gnutls_assert();
result = _gnutls_asn2err(result);
@@ -186,13 +229,13 @@ static int encode_to_private_key_info( gnutls_x509_privkey pkey, gnutls_datum* d
/* allocate data for the der
*/
der->size = size;
- der->data = gnutls_malloc( size);
+ der->data = gnutls_malloc(size);
if (der->data == NULL) {
gnutls_assert();
return GNUTLS_E_MEMORY_ERROR;
}
- result = asn1_der_coding( *pkey_info, "", der->data, &size, NULL);
+ result = asn1_der_coding(*pkey_info, "", der->data, &size, NULL);
if (result != ASN1_SUCCESS) {
gnutls_assert();
result = _gnutls_asn2err(result);
@@ -201,22 +244,25 @@ static int encode_to_private_key_info( gnutls_x509_privkey pkey, gnutls_datum* d
return 0;
- error:
- asn1_delete_structure( pkey_info);
- if (data != NULL) { gnutls_afree(data); }
- return result;
+ error:
+ asn1_delete_structure(pkey_info);
+ if (data != NULL) {
+ gnutls_afree(data);
+ }
+ return result;
}
/* Converts a PKCS #8 private key info to
* a PKCS #8 EncryptedPrivateKeyInfo.
*/
-static ASN1_TYPE encode_to_pkcs8_key( const gnutls_datum *raw_key,
- const char* password, unsigned int flags)
+static ASN1_TYPE encode_to_pkcs8_key(const gnutls_datum * raw_key,
+ const char *password,
+ unsigned int flags)
{
int result;
- gnutls_datum key = {NULL, 0};
- gnutls_datum tmp = {NULL, 0};
+ gnutls_datum key = { NULL, 0 };
+ gnutls_datum tmp = { NULL, 0 };
ASN1_TYPE pkcs8_asn = ASN1_TYPE_EMPTY;
struct pbkdf2_params kdf_params;
struct pbe_enc_params enc_params;
@@ -224,15 +270,17 @@ static ASN1_TYPE encode_to_pkcs8_key( const gnutls_datum *raw_key,
if ((result =
asn1_create_element(_gnutls_get_pkix(),
- "PKIX1.pkcs-8-EncryptedPrivateKeyInfo", &pkcs8_asn
- )) != ASN1_SUCCESS) {
+ "PKIX1.pkcs-8-EncryptedPrivateKeyInfo",
+ &pkcs8_asn)) != ASN1_SUCCESS) {
gnutls_assert();
goto error;
}
/* Write the encryption schema OID
*/
- result = asn1_write_value( pkcs8_asn, "encryptionAlgorithm.algorithm", PBES2_OID, 1);
+ result =
+ asn1_write_value(pkcs8_asn, "encryptionAlgorithm.algorithm",
+ PBES2_OID, 1);
if (result != ASN1_SUCCESS) {
gnutls_assert();
goto error;
@@ -240,22 +288,23 @@ static ASN1_TYPE encode_to_pkcs8_key( const gnutls_datum *raw_key,
/* Generate a symmetric key.
*/
- result = generate_key( password, flags, &kdf_params, &enc_params, &key);
+ result =
+ generate_key(password, flags, &kdf_params, &enc_params, &key);
if (result < 0) {
gnutls_assert();
goto error;
}
- result = write_pbe2_params( pkcs8_asn, &kdf_params, &enc_params);
+ result = write_pbe2_params(pkcs8_asn, &kdf_params, &enc_params);
if (result < 0) {
gnutls_assert();
goto error;
}
- /* Parameters have been decoded. Now
- * decrypt the EncryptedData.
+ /* Parameters have been encoded. Now
+ * encrypt the Data.
*/
- result = encrypt_data( raw_key, &enc_params, &key, &tmp);
+ result = encrypt_data(raw_key, &enc_params, &key, &tmp);
if (result < 0) {
gnutls_assert();
goto error;
@@ -263,22 +312,24 @@ static ASN1_TYPE encode_to_pkcs8_key( const gnutls_datum *raw_key,
/* write the encrypted data.
*/
- result = asn1_write_value( pkcs8_asn, "encryptedData", tmp.data, tmp.size);
+ result =
+ asn1_write_value(pkcs8_asn, "encryptedData", tmp.data,
+ tmp.size);
if (result != ASN1_SUCCESS) {
gnutls_assert();
goto error;
}
-
- _gnutls_free_datum( &tmp);
- _gnutls_free_datum( &key);
+
+ _gnutls_free_datum(&tmp);
+ _gnutls_free_datum(&key);
return pkcs8_asn;
- error:
- _gnutls_free_datum( &key);
- _gnutls_free_datum( &tmp);
- asn1_delete_structure(&pkcs8_asn);
- return NULL;
+ error:
+ _gnutls_free_datum(&key);
+ _gnutls_free_datum(&tmp);
+ asn1_delete_structure(&pkcs8_asn);
+ return NULL;
}
@@ -305,59 +356,176 @@ static ASN1_TYPE encode_to_pkcs8_key( const gnutls_datum *raw_key,
* 0 on success.
*
**/
-int gnutls_x509_privkey_export_pkcs8( gnutls_x509_privkey key,
- gnutls_x509_crt_fmt format, const char* password, unsigned int flags,
- unsigned char* output_data, int* output_data_size)
+int gnutls_x509_privkey_export_pkcs8(gnutls_x509_privkey key,
+ gnutls_x509_crt_fmt format,
+ const char *password,
+ unsigned int flags,
+ unsigned char *output_data,
+ int *output_data_size)
{
-ASN1_TYPE pkcs8_asn, pkey_info;
-int ret;
-gnutls_datum tmp;
+ ASN1_TYPE pkcs8_asn, pkey_info;
+ int ret;
+ gnutls_datum tmp;
/* Get the private key info
*/
- ret = encode_to_private_key_info( key, &tmp, &pkey_info);
- if ( ret < 0) {
+ ret = encode_to_private_key_info(key, &tmp, &pkey_info);
+ if (ret < 0) {
gnutls_assert();
return ret;
}
if (!(flags & GNUTLS_PKCS8_PLAIN) || password == NULL) {
- asn1_delete_structure( &pkey_info); /* we don't need it */
+ asn1_delete_structure(&pkey_info); /* we don't need it */
- pkcs8_asn = encode_to_pkcs8_key( &tmp, password, flags);
- _gnutls_free_datum( &tmp);
+ pkcs8_asn = encode_to_pkcs8_key(&tmp, password, flags);
+ _gnutls_free_datum(&tmp);
if (pkcs8_asn == NULL) {
gnutls_assert();
return GNUTLS_E_ASN1_GENERIC_ERROR;
}
-
- ret = _gnutls_x509_export_int( pkcs8_asn, format, PEM_PKCS8, *output_data_size,
- output_data, output_data_size);
- asn1_delete_structure( &pkcs8_asn);
+ ret =
+ _gnutls_x509_export_int(pkcs8_asn, format, PEM_PKCS8,
+ *output_data_size, output_data,
+ output_data_size);
+
+ asn1_delete_structure(&pkcs8_asn);
} else {
- _gnutls_free_datum( &tmp);
+ _gnutls_free_datum(&tmp);
- ret = _gnutls_x509_export_int( pkey_info, format, PEM_UNENCRYPTED_PKCS8,
- *output_data_size, output_data, output_data_size);
-
- asn1_delete_structure( &pkey_info);
+ ret =
+ _gnutls_x509_export_int(pkey_info, format,
+ PEM_UNENCRYPTED_PKCS8,
+ *output_data_size, output_data,
+ output_data_size);
+
+ asn1_delete_structure(&pkey_info);
}
return ret;
}
+/* Read the parameters cipher, IV, salt etc using the given
+ * schema ID.
+ */
+static
+int read_pkcs_schema_params(schema_id schema, const char* password,
+ const opaque * data, int data_size,
+ struct pbkdf2_params *kdf_params,
+ struct pbe_enc_params *enc_params)
+{
+ ASN1_TYPE pbes2_asn = ASN1_TYPE_EMPTY;
+ int result;
+ gnutls_datum tmp;
+
+ switch (schema) {
+
+ case PBES2:
+
+ /* Now check the key derivation and the encryption
+ * functions.
+ */
+ if ((result =
+ asn1_create_element(_gnutls_get_pkix(),
+ "PKIX1.pkcs-5-PBES2-params",
+ &pbes2_asn)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto error;
+ }
+
+ /* Decode the parameters.
+ */
+ result =
+ asn1_der_decoding(&pbes2_asn,
+ data, data_size, NULL);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto error;
+ }
+
+ tmp.data = (opaque*)data;
+ tmp.size = data_size;
+
+ result = read_pbkdf2_params(pbes2_asn, &tmp, kdf_params);
+ if (result < 0) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto error;
+ }
+
+ result = read_pbe_enc_params(pbes2_asn, &tmp, enc_params);
+ if (result < 0) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto error;
+ }
+
+ asn1_delete_structure(&pbes2_asn);
+ return 0;
+ break;
+
+ case PKCS12_3DES_SHA1:
+ if ((result =
+ asn1_create_element(_gnutls_get_pkix(),
+ "PKIX1.pkcs-12-PbeParams",
+ &pbes2_asn)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto error;
+ }
+
+ /* Decode the parameters.
+ */
+ result =
+ asn1_der_decoding(&pbes2_asn,
+ data, data_size, NULL);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto error;
+ }
+
+ result = read_pkcs12_kdf_params(pbes2_asn, kdf_params);
+ if (result < 0) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto error;
+ }
+
+ enc_params->cipher = GNUTLS_CIPHER_3DES_CBC;
+ enc_params->iv_size = 8;
+ _pkcs12_string_to_key( 2/*IV*/, kdf_params->salt, kdf_params->salt_size,
+ kdf_params->iter_count, password, 8, enc_params->iv);
+
+ asn1_delete_structure(&pbes2_asn);
+
+ return 0;
+ break;
+
+ } /* switch */
+
+ return GNUTLS_E_UNKNOWN_CIPHER_TYPE;
+
+ error:
+ asn1_delete_structure(&pbes2_asn);
+ return result;
+}
+
/* Converts a PKCS #8 key to
* an internal structure (gnutls_private_key)
* (normally a PKCS #1 encoded RSA key)
*/
-static ASN1_TYPE decode_pkcs8_key( const gnutls_datum *raw_key,
- const char* password, gnutls_x509_privkey pkey)
+static ASN1_TYPE decode_pkcs8_key(const gnutls_datum * raw_key,
+ const char *password,
+ gnutls_x509_privkey pkey)
{
int result, len;
opaque enc_oid[64];
@@ -367,17 +535,19 @@ static ASN1_TYPE decode_pkcs8_key( const gnutls_datum *raw_key,
int params_start, params_end, params_len;
struct pbkdf2_params kdf_params;
struct pbe_enc_params enc_params;
-
+ schema_id schema;
if ((result =
asn1_create_element(_gnutls_get_pkix(),
- "PKIX1.pkcs-8-EncryptedPrivateKeyInfo", &pkcs8_asn
- )) != ASN1_SUCCESS) {
+ "PKIX1.pkcs-8-EncryptedPrivateKeyInfo",
+ &pkcs8_asn)) != ASN1_SUCCESS) {
gnutls_assert();
goto error;
}
- result = asn1_der_decoding(&pkcs8_asn, raw_key->data, raw_key->size, NULL);
+ result =
+ asn1_der_decoding(&pkcs8_asn, raw_key->data, raw_key->size,
+ NULL);
if (result != ASN1_SUCCESS) {
gnutls_assert();
goto error;
@@ -386,71 +556,46 @@ static ASN1_TYPE decode_pkcs8_key( const gnutls_datum *raw_key,
/* Check the encryption schema OID
*/
len = sizeof(enc_oid);
- result = asn1_read_value( pkcs8_asn, "encryptionAlgorithm.algorithm", enc_oid, &len);
+ result =
+ asn1_read_value(pkcs8_asn, "encryptionAlgorithm.algorithm",
+ enc_oid, &len);
if (result != ASN1_SUCCESS) {
gnutls_assert();
goto error;
}
- /* we only support PBES2
- */
- if (strcmp( enc_oid, PBES2_OID) != 0) {
+ if ((result = check_schema(enc_oid)) < 0) {
gnutls_assert();
- _gnutls_x509_log( "PKCS #8 encryption schema OID '%s' is unsupported.\n", enc_oid);
goto error;
}
+ schema = result;
+
/* Get the DER encoding of the parameters.
*/
- result = asn1_der_decoding_startEnd( pkcs8_asn, raw_key->data, raw_key->size,
- "encryptionAlgorithm.parameters", &params_start, &params_end);
+ result =
+ asn1_der_decoding_startEnd(pkcs8_asn, raw_key->data,
+ raw_key->size,
+ "encryptionAlgorithm.parameters",
+ &params_start, &params_end);
if (result != ASN1_SUCCESS) {
gnutls_assert();
goto error;
}
params_len = params_end - params_start + 1;
- /* Now check the key derivation and the encryption
- * functions.
- */
- if ((result =
- asn1_create_element(_gnutls_get_pkix(),
- "PKIX1.pkcs-5-PBES2-params", &pbes2_asn
- )) != ASN1_SUCCESS) {
- gnutls_assert();
- return NULL;
- }
-
- /* Decode the parameters.
- */
- result = asn1_der_decoding(&pbes2_asn, &raw_key->data[params_start], params_len, NULL);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- goto error;
- }
-
- tmp.data = &raw_key->data[params_start];
- tmp.size = params_len;
-
- result = read_pbkdf2_params( pbes2_asn, &tmp, &kdf_params);
- if (result < 0) {
- gnutls_assert();
- goto error;
- }
-
- result = read_pbe_enc_params( pbes2_asn, &tmp, &enc_params);
- if (result < 0) {
- gnutls_assert();
- goto error;
- }
-
- asn1_delete_structure( &pbes2_asn);
+ result =
+ read_pkcs_schema_params(schema, password,
+ &raw_key->data[params_start],
+ params_len, &kdf_params, &enc_params);
/* Parameters have been decoded. Now
* decrypt the EncryptedData.
*/
- result = decrypt_data( pkcs8_asn, password, &kdf_params, &enc_params, &tmp);
+ result =
+ decrypt_data(schema, pkcs8_asn, "encryptedData", password, &kdf_params,
+ &enc_params, &tmp);
if (result < 0) {
gnutls_assert();
goto error;
@@ -458,18 +603,19 @@ static ASN1_TYPE decode_pkcs8_key( const gnutls_datum *raw_key,
asn1_delete_structure(&pkcs8_asn);
- ret_asn = decode_private_key_info( &tmp, pkey);
- _gnutls_free_datum( &tmp);
+ ret_asn = decode_private_key_info(&tmp, pkey);
+ _gnutls_free_datum(&tmp);
return ret_asn;
- error:
- asn1_delete_structure(&pbes2_asn);
- asn1_delete_structure(&pkcs8_asn);
- return NULL;
+ error:
+ asn1_delete_structure(&pbes2_asn);
+ asn1_delete_structure(&pkcs8_asn);
+ return NULL;
}
-static ASN1_TYPE decode_private_key_info( const gnutls_datum* der, gnutls_x509_privkey pkey)
+static ASN1_TYPE decode_private_key_info(const gnutls_datum * der,
+ gnutls_x509_privkey pkey)
{
int result, len;
opaque oid[64], *data = NULL;
@@ -481,8 +627,8 @@ static ASN1_TYPE decode_private_key_info( const gnutls_datum* der, gnutls_x509_p
if ((result =
asn1_create_element(_gnutls_get_pkix(),
- "PKIX1.pkcs-8-PrivateKeyInfo", &pkcs8_asn
- )) != ASN1_SUCCESS) {
+ "PKIX1.pkcs-8-PrivateKeyInfo",
+ &pkcs8_asn)) != ASN1_SUCCESS) {
gnutls_assert();
goto error;
}
@@ -496,7 +642,9 @@ static ASN1_TYPE decode_private_key_info( const gnutls_datum* der, gnutls_x509_p
/* Check the private key algorithm OID
*/
len = sizeof(oid);
- result = asn1_read_value( pkcs8_asn, "privateKeyAlgorithm.algorithm", oid, &len);
+ result =
+ asn1_read_value(pkcs8_asn, "privateKeyAlgorithm.algorithm",
+ oid, &len);
if (result != ASN1_SUCCESS) {
gnutls_assert();
goto error;
@@ -504,54 +652,60 @@ static ASN1_TYPE decode_private_key_info( const gnutls_datum* der, gnutls_x509_p
/* we only support RSA private keys.
*/
- if (strcmp( oid, PKIX1_RSA_OID) != 0) {
+ if (strcmp(oid, PKIX1_RSA_OID) != 0) {
gnutls_assert();
- _gnutls_x509_log( "PKCS #8 private key OID '%s' is unsupported.\n", oid);
+ _gnutls_x509_log
+ ("PKCS #8 private key OID '%s' is unsupported.\n",
+ oid);
goto error;
}
/* Get the DER encoding of the actual private key.
*/
data_size = 0;
- result = asn1_read_value( pkcs8_asn, "privateKey", NULL, &data_size);
+ result =
+ asn1_read_value(pkcs8_asn, "privateKey", NULL, &data_size);
if (result != ASN1_MEM_ERROR) {
gnutls_assert();
result = _gnutls_asn2err(result);
goto error;
}
- data = gnutls_alloca( data_size);
+ data = gnutls_alloca(data_size);
if (data == NULL) {
gnutls_assert();
result = GNUTLS_E_MEMORY_ERROR;
goto error;
}
- result = asn1_read_value( pkcs8_asn, "privateKey", data, &data_size);
+ result =
+ asn1_read_value(pkcs8_asn, "privateKey", data, &data_size);
if (result != ASN1_SUCCESS) {
gnutls_assert();
result = _gnutls_asn2err(result);
goto error;
}
- asn1_delete_structure( &pkcs8_asn);
-
+ asn1_delete_structure(&pkcs8_asn);
+
tmp.data = data;
tmp.size = data_size;
-
+
pkey->pk_algorithm = GNUTLS_PK_RSA;
- ret_asn = _gnutls_privkey_decode_pkcs1_rsa_key( &tmp, pkey);
- if (ret_asn==NULL) {
+ ret_asn = _gnutls_privkey_decode_pkcs1_rsa_key(&tmp, pkey);
+ if (ret_asn == NULL) {
gnutls_assert();
}
-
+
return ret_asn;
- error:
- asn1_delete_structure( &pkcs8_asn);
- if (data != NULL) { gnutls_afree(data); }
- return NULL;
+ error:
+ asn1_delete_structure(&pkcs8_asn);
+ if (data != NULL) {
+ gnutls_afree(data);
+ }
+ return NULL;
}
@@ -574,8 +728,11 @@ static ASN1_TYPE decode_private_key_info( const gnutls_datum* der, gnutls_x509_p
* Returns 0 on success.
*
**/
-int gnutls_x509_privkey_import_pkcs8(gnutls_x509_privkey key, const gnutls_datum * data,
- gnutls_x509_crt_fmt format, const char * password, unsigned int flags)
+int gnutls_x509_privkey_import_pkcs8(gnutls_x509_privkey key,
+ const gnutls_datum * data,
+ gnutls_x509_crt_fmt format,
+ const char *password,
+ unsigned int flags)
{
int result = 0, need_free = 0;
gnutls_datum _data = { data->data, data->size };
@@ -590,34 +747,37 @@ int gnutls_x509_privkey_import_pkcs8(gnutls_x509_privkey key, const gnutls_datum
/* Try the first header
*/
- result = _gnutls_fbase64_decode(PEM_UNENCRYPTED_PKCS8, data->data, data->size,
- &out);
+ result =
+ _gnutls_fbase64_decode(PEM_UNENCRYPTED_PKCS8,
+ data->data, data->size, &out);
encrypted = 0;
-
- if (result < 0) { /* Try the encrypted header
- */
- result = _gnutls_fbase64_decode(PEM_PKCS8, data->data, data->size,
- &out);
+
+ if (result < 0) { /* Try the encrypted header
+ */
+ result =
+ _gnutls_fbase64_decode(PEM_PKCS8, data->data,
+ data->size, &out);
if (result <= 0) {
- if (result==0) result = GNUTLS_E_INTERNAL_ERROR;
+ if (result == 0)
+ result = GNUTLS_E_INTERNAL_ERROR;
gnutls_assert();
return result;
}
-
+
encrypted = 1;
}
_data.data = out;
_data.size = result;
-
+
need_free = 1;
}
if (flags & GNUTLS_PKCS8_PLAIN || password == NULL) {
- key->key = decode_private_key_info( &_data, key);
- } else { /* encrypted. */
- key->key = decode_pkcs8_key( &_data, password, key);
+ key->key = decode_private_key_info(&_data, key);
+ } else { /* encrypted. */
+ key->key = decode_pkcs8_key(&_data, password, key);
}
if (key->key == NULL) {
@@ -626,7 +786,8 @@ int gnutls_x509_privkey_import_pkcs8(gnutls_x509_privkey key, const gnutls_datum
goto cleanup;
}
- if (need_free) _gnutls_free_datum( &_data);
+ if (need_free)
+ _gnutls_free_datum(&_data);
/* The key has now been decoded.
*/
@@ -634,41 +795,49 @@ int gnutls_x509_privkey_import_pkcs8(gnutls_x509_privkey key, const gnutls_datum
return 0;
cleanup:
- key->pk_algorithm = GNUTLS_PK_UNKNOWN;
- if (need_free) _gnutls_free_datum( &_data);
+ key->pk_algorithm = GNUTLS_PK_UNKNOWN;
+ if (need_free)
+ _gnutls_free_datum(&_data);
return result;
}
/* Reads the PBKDF2 parameters.
*/
-static int read_pbkdf2_params( ASN1_TYPE pbes2_asn, const gnutls_datum* der,
- struct pbkdf2_params* params)
+static int read_pbkdf2_params(ASN1_TYPE pbes2_asn,
+ const gnutls_datum * der,
+ struct pbkdf2_params *params)
{
-int params_start, params_end;
-int params_len, len, result;
-ASN1_TYPE pbkdf2_asn = ASN1_TYPE_EMPTY;
-char oid[64];
+ int params_start, params_end;
+ int params_len, len, result;
+ ASN1_TYPE pbkdf2_asn = ASN1_TYPE_EMPTY;
+ char oid[64];
- memset( params, 0, sizeof(params));
+ memset(params, 0, sizeof(params));
/* Check the key derivation algorithm
*/
len = sizeof(oid);
- result = asn1_read_value( pbes2_asn, "keyDerivationFunc.algorithm", oid, &len);
+ result =
+ asn1_read_value(pbes2_asn, "keyDerivationFunc.algorithm", oid,
+ &len);
if (result != ASN1_SUCCESS) {
gnutls_assert();
return _gnutls_asn2err(result);
}
- _gnutls_hard_log( "keyDerivationFunc.algorithm: %s\n", oid);
-
- if (strcmp( oid, PBKDF2_OID) != 0) {
+ _gnutls_hard_log("keyDerivationFunc.algorithm: %s\n", oid);
+
+ if (strcmp(oid, PBKDF2_OID) != 0) {
gnutls_assert();
- _gnutls_x509_log( "PKCS #8 key derivation OID '%s' is unsupported.\n", oid);
+ _gnutls_x509_log
+ ("PKCS #8 key derivation OID '%s' is unsupported.\n",
+ oid);
return _gnutls_asn2err(result);
}
- result = asn1_der_decoding_startEnd( pbes2_asn, der->data, der->size,
- "keyDerivationFunc.parameters", &params_start, &params_end);
+ result =
+ asn1_der_decoding_startEnd(pbes2_asn, der->data, der->size,
+ "keyDerivationFunc.parameters",
+ &params_start, &params_end);
if (result != ASN1_SUCCESS) {
gnutls_assert();
return _gnutls_asn2err(result);
@@ -680,13 +849,15 @@ char oid[64];
*/
if ((result =
asn1_create_element(_gnutls_get_pkix(),
- "PKIX1.pkcs-5-PBKDF2-params", &pbkdf2_asn
- )) != ASN1_SUCCESS) {
+ "PKIX1.pkcs-5-PBKDF2-params",
+ &pbkdf2_asn)) != ASN1_SUCCESS) {
gnutls_assert();
return _gnutls_asn2err(result);
}
-
- result = asn1_der_decoding(&pbkdf2_asn, &der->data[params_start], params_len, NULL);
+
+ result =
+ asn1_der_decoding(&pbkdf2_asn, &der->data[params_start],
+ params_len, NULL);
if (result != ASN1_SUCCESS) {
gnutls_assert();
result = _gnutls_asn2err(result);
@@ -695,73 +866,146 @@ char oid[64];
/* read the salt */
params->salt_size = sizeof(params->salt);
- result = asn1_read_value( pbkdf2_asn, "salt.specified", params->salt, &params->salt_size);
+ result =
+ asn1_read_value(pbkdf2_asn, "salt.specified", params->salt,
+ &params->salt_size);
if (result != ASN1_SUCCESS) {
gnutls_assert();
result = _gnutls_asn2err(result);
goto error;
}
- _gnutls_hard_log( "salt.specified.size: %d\n", params->salt_size);
+ _gnutls_hard_log("salt.specified.size: %d\n", params->salt_size);
/* read the iteration count
*/
len = sizeof(oid);
- result = _gnutls_x509_read_ui( pbkdf2_asn, "iterationCount", oid, len, &params->iter_count);
+ result =
+ _gnutls_x509_read_ui(pbkdf2_asn, "iterationCount", oid, len,
+ &params->iter_count);
if (result != ASN1_SUCCESS) {
gnutls_assert();
goto error;
}
- _gnutls_hard_log( "iterationCount: %d\n", params->iter_count);
+ _gnutls_hard_log("iterationCount: %d\n", params->iter_count);
/* read the keylength, if it is set.
*/
len = sizeof(oid);
- result = _gnutls_x509_read_ui( pbkdf2_asn, "keyLength", oid, len, &params->key_size);
+ result =
+ _gnutls_x509_read_ui(pbkdf2_asn, "keyLength", oid, len,
+ &params->key_size);
if (result < 0) {
params->key_size = 0;
}
- _gnutls_hard_log( "keyLength: %d\n", params->key_size);
-
+ _gnutls_hard_log("keyLength: %d\n", params->key_size);
+
/* We don't read the PRF. We only use the default.
*/
return 0;
- error:
- asn1_delete_structure( &pbkdf2_asn);
- return result;
+ error:
+ asn1_delete_structure(&pbkdf2_asn);
+ return result;
}
-static int read_pbe_enc_params( ASN1_TYPE pbes2_asn, const gnutls_datum* der,
- struct pbe_enc_params* params)
+/* Reads the PBE parameters from PKCS-12 schemas (*&#%*&#% RSA).
+ */
+static int read_pkcs12_kdf_params(ASN1_TYPE pbes2_asn,
+ struct pbkdf2_params *params)
{
-int params_start, params_end;
-int params_len, len, result;
-ASN1_TYPE pbe_asn = ASN1_TYPE_EMPTY;
-char oid[64];
+ int len, result;
+ char oid[64];
+
+ memset(params, 0, sizeof(params));
+
+ /* read the salt */
+ params->salt_size = sizeof(params->salt);
+ result =
+ asn1_read_value(pbes2_asn, "salt", params->salt,
+ &params->salt_size);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto error;
+ }
+ _gnutls_hard_log("salt.size: %d\n", params->salt_size);
+
+ /* read the iteration count
+ */
+ len = sizeof(oid);
+ result =
+ _gnutls_x509_read_ui(pbes2_asn, "iterations", oid, len,
+ &params->iter_count);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ goto error;
+ }
+ _gnutls_hard_log("iterationCount: %d\n", params->iter_count);
- memset( params, 0, sizeof(params));
+ params->key_size = 0;
+
+ return 0;
+
+ error:
+ return result;
+
+}
+
+
+/* Converts an OID to a gnutls cipher type.
+ */
+inline
+ static int oid2cipher(const char *oid, gnutls_cipher_algorithm * algo)
+{
+
+ *algo = 0;
+
+ if (strcmp(oid, DES_EDE3_CBC_OID) == 0) {
+ *algo = GNUTLS_CIPHER_3DES_CBC;
+ return 0;
+ }
+
+ _gnutls_x509_log("PKCS #8 encryption OID '%s' is unsupported.\n",
+ oid);
+ return GNUTLS_E_UNKNOWN_CIPHER_TYPE;
+}
+
+
+static int read_pbe_enc_params(ASN1_TYPE pbes2_asn,
+ const gnutls_datum * der,
+ struct pbe_enc_params *params)
+{
+ int params_start, params_end;
+ int params_len, len, result;
+ ASN1_TYPE pbe_asn = ASN1_TYPE_EMPTY;
+ char oid[64];
+
+ memset(params, 0, sizeof(params));
/* Check the encryption algorithm
*/
len = sizeof(oid);
- result = asn1_read_value( pbes2_asn, "encryptionScheme.algorithm", oid, &len);
+ result =
+ asn1_read_value(pbes2_asn, "encryptionScheme.algorithm", oid,
+ &len);
if (result != ASN1_SUCCESS) {
gnutls_assert();
goto error;
}
- _gnutls_hard_log( "encryptionScheme.algorithm: %s\n", oid);
-
- if (strcmp( oid, DES_EDE3_CBC_OID) != 0) {
+ _gnutls_hard_log("encryptionScheme.algorithm: %s\n", oid);
+
+ if ((result = oid2cipher(oid, &params->cipher)) < 0) {
gnutls_assert();
- _gnutls_x509_log( "PKCS #8 encryption OID '%s' is unsupported.\n", oid);
goto error;
}
- result = asn1_der_decoding_startEnd( pbes2_asn, der->data, der->size,
- "encryptionScheme.parameters", &params_start, &params_end);
+ result =
+ asn1_der_decoding_startEnd(pbes2_asn, der->data, der->size,
+ "encryptionScheme.parameters",
+ &params_start, &params_end);
if (result != ASN1_SUCCESS) {
gnutls_assert();
return _gnutls_asn2err(result);
@@ -772,13 +1016,15 @@ char oid[64];
*/
if ((result =
asn1_create_element(_gnutls_get_pkix(),
- "PKIX1.pkcs-5-des-EDE3-CBC-params", &pbe_asn
- )) != ASN1_SUCCESS) {
+ "PKIX1.pkcs-5-des-EDE3-CBC-params",
+ &pbe_asn)) != ASN1_SUCCESS) {
gnutls_assert();
return _gnutls_asn2err(result);
}
-
- result = asn1_der_decoding(&pbe_asn, &der->data[params_start], params_len, NULL);
+
+ result =
+ asn1_der_decoding(&pbe_asn, &der->data[params_start],
+ params_len, NULL);
if (result != ASN1_SUCCESS) {
gnutls_assert();
result = _gnutls_asn2err(result);
@@ -787,47 +1033,50 @@ char oid[64];
/* read the IV */
params->iv_size = sizeof(params->iv);
- result = asn1_read_value( pbe_asn, "", params->iv, &params->iv_size);
+ result =
+ asn1_read_value(pbe_asn, "", params->iv, &params->iv_size);
if (result != ASN1_SUCCESS) {
gnutls_assert();
result = _gnutls_asn2err(result);
goto error;
}
- _gnutls_hard_log( "IV.size: %d\n", params->iv_size);
+ _gnutls_hard_log("IV.size: %d\n", params->iv_size);
return 0;
- error:
- asn1_delete_structure( &pbe_asn);
- return result;
+ error:
+ asn1_delete_structure(&pbe_asn);
+ return result;
}
-static int decrypt_data( ASN1_TYPE pkcs8_asn, const char* password,
- const struct pbkdf2_params *kdf_params, const struct pbe_enc_params *enc_params,
- gnutls_datum* decrypted_data)
+static int decrypt_data(schema_id schema, ASN1_TYPE pkcs8_asn, const char *root,
+ const char *password,
+ const struct pbkdf2_params *kdf_params,
+ const struct pbe_enc_params *enc_params,
+ gnutls_datum * decrypted_data)
{
-int result;
-int data_size;
-opaque* data=NULL, *key = NULL;
-gnutls_datum dkey, div;
-GNUTLS_CIPHER_HANDLE ch = NULL;
-int key_size;
+ int result;
+ int data_size;
+ opaque *data = NULL, *key = NULL;
+ gnutls_datum dkey, div;
+ GNUTLS_CIPHER_HANDLE ch = NULL;
+ int key_size;
data_size = 0;
- result = asn1_read_value( pkcs8_asn, "encryptedData", NULL, &data_size);
+ result = asn1_read_value(pkcs8_asn, root, NULL, &data_size);
if (result != ASN1_MEM_ERROR) {
gnutls_assert();
return _gnutls_asn2err(result);
}
- data = gnutls_malloc( data_size);
+ data = gnutls_malloc(data_size);
if (data == NULL) {
gnutls_assert();
return GNUTLS_E_MEMORY_ERROR;
}
- result = asn1_read_value( pkcs8_asn, "encryptedData", data, &data_size);
+ result = asn1_read_value(pkcs8_asn, root, data, &data_size);
if (result != ASN1_SUCCESS) {
gnutls_assert();
result = _gnutls_asn2err(result);
@@ -835,11 +1084,12 @@ int key_size;
}
if (kdf_params->key_size == 0) {
- key_size = gnutls_cipher_get_key_size( GNUTLS_CIPHER_3DES_CBC);
- } else key_size = kdf_params->key_size;
+ key_size = gnutls_cipher_get_key_size(enc_params->cipher);
+ } else
+ key_size = kdf_params->key_size;
- key = gnutls_alloca( key_size);
- if ( key == NULL) {
+ key = gnutls_alloca(key_size);
+ if (key == NULL) {
gnutls_assert();
result = GNUTLS_E_MEMORY_ERROR;
goto error;
@@ -847,26 +1097,39 @@ int key_size;
/* generate the key
*/
- result = _gnutls_pkcs5_pbkdf2( PKCS5_PRF_SHA1, password, strlen(password),
- kdf_params->salt, kdf_params->salt_size, kdf_params->iter_count,
- key_size, key);
+ if (schema == PBES2) {
+ result =
+ _gnutls_pkcs5_pbkdf2(PKCS5_PRF_SHA1, password,
+ strlen(password), kdf_params->salt,
+ kdf_params->salt_size,
+ kdf_params->iter_count, key_size, key);
- if (result != PKCS5_OK) {
- gnutls_assert();
- result = GNUTLS_E_DECRYPTION_FAILED;
- goto error;
+ if (result != PKCS5_OK) {
+ gnutls_assert();
+ result = GNUTLS_E_DECRYPTION_FAILED;
+ goto error;
+ }
+ } else {
+ result =
+ _pkcs12_string_to_key( 1/*KEY*/, kdf_params->salt, kdf_params->salt_size,
+ kdf_params->iter_count, password, key_size, key);
+
+ if (result < 0) {
+ gnutls_assert();
+ goto error;
+ }
}
/* do the decryption.
*/
dkey.data = key;
dkey.size = key_size;
-
- div.data = (opaque*) enc_params->iv;
+
+ div.data = (opaque *) enc_params->iv;
div.size = enc_params->iv_size;
- ch = _gnutls_cipher_init( GNUTLS_CIPHER_3DES_CBC, &dkey, &div);
+ ch = _gnutls_cipher_init(enc_params->cipher, &dkey, &div);
- gnutls_afree( key);
+ gnutls_afree(key);
key = NULL;
if (ch == NULL) {
@@ -874,97 +1137,103 @@ int key_size;
result = GNUTLS_E_DECRYPTION_FAILED;
goto error;
}
-
- result = _gnutls_cipher_decrypt( ch, data, data_size);
+
+ result = _gnutls_cipher_decrypt(ch, data, data_size);
if (result < 0) {
gnutls_assert();
goto error;
}
decrypted_data->data = data;
- decrypted_data->size = data_size - data[data_size-1];
+ decrypted_data->size = data_size - data[data_size - 1];
- _gnutls_cipher_deinit( ch);
+ _gnutls_cipher_deinit(ch);
return 0;
- error:
- gnutls_free(data);
- gnutls_afree(key);
- if (ch!=NULL)
- _gnutls_cipher_deinit( ch);
- return result;
+ error:
+ gnutls_free(data);
+ gnutls_afree(key);
+ if (ch != NULL)
+ _gnutls_cipher_deinit(ch);
+ return result;
}
/* Writes the PBKDF2 parameters.
*/
-static int write_pbkdf2_params( ASN1_TYPE pbes2_asn, const struct pbkdf2_params *kdf_params)
+static int write_pbkdf2_params(ASN1_TYPE pbes2_asn,
+ const struct pbkdf2_params *kdf_params)
{
-int result;
-ASN1_TYPE pbkdf2_asn = ASN1_TYPE_EMPTY;
-char tmp[64];
+ int result;
+ ASN1_TYPE pbkdf2_asn = ASN1_TYPE_EMPTY;
+ char tmp[64];
/* Write the key derivation algorithm
*/
- result = asn1_write_value( pbes2_asn, "keyDerivationFunc.algorithm", PBKDF2_OID, 1);
+ result =
+ asn1_write_value(pbes2_asn, "keyDerivationFunc.algorithm",
+ PBKDF2_OID, 1);
if (result != ASN1_SUCCESS) {
gnutls_assert();
return _gnutls_asn2err(result);
}
-
+
/* Now write the key derivation and the encryption
* functions.
*/
if ((result =
asn1_create_element(_gnutls_get_pkix(),
- "PKIX1.pkcs-5-PBKDF2-params", &pbkdf2_asn
- )) != ASN1_SUCCESS) {
+ "PKIX1.pkcs-5-PBKDF2-params",
+ &pbkdf2_asn)) != ASN1_SUCCESS) {
gnutls_assert();
return _gnutls_asn2err(result);
}
- result = asn1_write_value( pbkdf2_asn, "salt", "specified", 1);
+ result = asn1_write_value(pbkdf2_asn, "salt", "specified", 1);
if (result != ASN1_SUCCESS) {
gnutls_assert();
result = _gnutls_asn2err(result);
goto error;
}
-
+
/* write the salt
*/
- result = asn1_write_value( pbkdf2_asn, "salt.specified", kdf_params->salt, kdf_params->salt_size);
+ result =
+ asn1_write_value(pbkdf2_asn, "salt.specified",
+ kdf_params->salt, kdf_params->salt_size);
if (result != ASN1_SUCCESS) {
gnutls_assert();
result = _gnutls_asn2err(result);
goto error;
}
- _gnutls_hard_log( "salt.specified.size: %d\n", kdf_params->salt_size);
+ _gnutls_hard_log("salt.specified.size: %d\n",
+ kdf_params->salt_size);
/* write the iteration count
*/
- _gnutls_write_uint32( kdf_params->iter_count, tmp);
+ _gnutls_write_uint32(kdf_params->iter_count, tmp);
- result = asn1_write_value( pbkdf2_asn, "iterationCount", tmp, 4);
+ result = asn1_write_value(pbkdf2_asn, "iterationCount", tmp, 4);
if (result != ASN1_SUCCESS) {
gnutls_assert();
result = _gnutls_asn2err(result);
goto error;
}
- _gnutls_hard_log( "iterationCount: %d\n", kdf_params->iter_count);
+ _gnutls_hard_log("iterationCount: %d\n", kdf_params->iter_count);
/* write the keylength, if it is set.
*/
- result = asn1_write_value( pbkdf2_asn, "keyLength", NULL, 0);
+ result = asn1_write_value(pbkdf2_asn, "keyLength", NULL, 0);
if (result != ASN1_SUCCESS) {
gnutls_assert();
result = _gnutls_asn2err(result);
goto error;
}
-
+
/* We write an emptry prf.
*/
- result = asn1_write_value( pbkdf2_asn, "prf", NULL, 0);
+ result = asn1_write_value(pbkdf2_asn, "prf", NULL, 0);
if (result != ASN1_SUCCESS) {
gnutls_assert();
result = _gnutls_asn2err(result);
@@ -974,8 +1243,9 @@ char tmp[64];
/* now encode them an put the DER output
* in the keyDerivationFunc.parameters
*/
- result = _gnutls_x509_der_encode_and_copy( pbkdf2_asn, "",
- pbes2_asn, "keyDerivationFunc.parameters");
+ result = _gnutls_x509_der_encode_and_copy(pbkdf2_asn, "",
+ pbes2_asn,
+ "keyDerivationFunc.parameters");
if (result < 0) {
gnutls_assert();
goto error;
@@ -983,50 +1253,56 @@ char tmp[64];
return 0;
- error:
- asn1_delete_structure( &pbkdf2_asn);
- return result;
+ error:
+ asn1_delete_structure(&pbkdf2_asn);
+ return result;
}
-static int write_pbe_enc_params( ASN1_TYPE pbes2_asn, const struct pbe_enc_params* params)
+static int write_pbe_enc_params(ASN1_TYPE pbes2_asn,
+ const struct pbe_enc_params *params)
{
-int result;
-ASN1_TYPE pbe_asn = ASN1_TYPE_EMPTY;
+ int result;
+ ASN1_TYPE pbe_asn = ASN1_TYPE_EMPTY;
/* Write the encryption algorithm
*/
- result = asn1_write_value( pbes2_asn, "encryptionScheme.algorithm", DES_EDE3_CBC_OID, 1);
+ result =
+ asn1_write_value(pbes2_asn, "encryptionScheme.algorithm",
+ DES_EDE3_CBC_OID, 1);
if (result != ASN1_SUCCESS) {
gnutls_assert();
goto error;
}
- _gnutls_hard_log( "encryptionScheme.algorithm: %s\n", DES_EDE3_CBC_OID);
-
+ _gnutls_hard_log("encryptionScheme.algorithm: %s\n",
+ DES_EDE3_CBC_OID);
+
/* Now check the encryption parameters.
*/
if ((result =
asn1_create_element(_gnutls_get_pkix(),
- "PKIX1.pkcs-5-des-EDE3-CBC-params", &pbe_asn
- )) != ASN1_SUCCESS) {
+ "PKIX1.pkcs-5-des-EDE3-CBC-params",
+ &pbe_asn)) != ASN1_SUCCESS) {
gnutls_assert();
return _gnutls_asn2err(result);
}
-
+
/* read the salt */
- result = asn1_write_value( pbe_asn, "", params->iv, params->iv_size);
+ result =
+ asn1_write_value(pbe_asn, "", params->iv, params->iv_size);
if (result != ASN1_SUCCESS) {
gnutls_assert();
result = _gnutls_asn2err(result);
goto error;
}
- _gnutls_hard_log( "IV.size: %d\n", params->iv_size);
+ _gnutls_hard_log("IV.size: %d\n", params->iv_size);
/* now encode them an put the DER output
* in the encryptionScheme.parameters
*/
- result = _gnutls_x509_der_encode_and_copy( pbe_asn, "",
- pbes2_asn, "encryptionScheme.parameters");
+ result = _gnutls_x509_der_encode_and_copy(pbe_asn, "",
+ pbes2_asn,
+ "encryptionScheme.parameters");
if (result < 0) {
gnutls_assert();
goto error;
@@ -1034,38 +1310,46 @@ ASN1_TYPE pbe_asn = ASN1_TYPE_EMPTY;
return 0;
- error:
- asn1_delete_structure( &pbe_asn);
- return result;
+ error:
+ asn1_delete_structure(&pbe_asn);
+ return result;
}
/* Generates a key and also stores the key parameters.
*/
-static int generate_key( const char* password, unsigned int flags,
- struct pbkdf2_params* kdf_params,
- struct pbe_enc_params* enc_params, gnutls_datum * key)
+static int generate_key(const char *password, unsigned int flags,
+ struct pbkdf2_params *kdf_params,
+ struct pbe_enc_params *enc_params,
+ gnutls_datum * key)
{
-opaque rnd[2];
-int ret;
+ opaque rnd[2];
+ int ret;
/* We should use the flags here to use different
* encryption algorithms etc.
*/
- _gnutls_get_random( rnd, 2, GNUTLS_STRONG_RANDOM);
+ enc_params->cipher = GNUTLS_CIPHER_3DES_CBC; /* The default */
+
+ _gnutls_get_random(rnd, 2, GNUTLS_STRONG_RANDOM);
/* generate salt */
- kdf_params->salt_size = GMIN( sizeof( kdf_params->salt), (uint)(10 + (rnd[1] % 10)));
- _gnutls_get_random( kdf_params->salt, kdf_params->salt_size, GNUTLS_STRONG_RANDOM);
-
+ kdf_params->salt_size =
+ GMIN(sizeof(kdf_params->salt), (uint) (10 + (rnd[1] % 10)));
+ _gnutls_get_random(kdf_params->salt, kdf_params->salt_size,
+ GNUTLS_STRONG_RANDOM);
+
kdf_params->iter_count = 256 + rnd[0];
- key->size = kdf_params->key_size = gnutls_cipher_get_key_size( GNUTLS_CIPHER_3DES_CBC); /* for 3 DES */
+ key->size = kdf_params->key_size =
+ gnutls_cipher_get_key_size(enc_params->cipher);
- enc_params->iv_size = 8; /* ok for 3DES */
- _gnutls_get_random( enc_params->iv, enc_params->iv_size, GNUTLS_WEAK_RANDOM);
+ enc_params->iv_size =
+ _gnutls_cipher_get_iv_size(enc_params->cipher);
+ _gnutls_get_random(enc_params->iv, enc_params->iv_size,
+ GNUTLS_WEAK_RANDOM);
- key->data = gnutls_secure_malloc( key->size);
+ key->data = gnutls_secure_malloc(key->size);
if (key->data == NULL) {
gnutls_assert();
return GNUTLS_E_MEMORY_ERROR;
@@ -1073,14 +1357,16 @@ int ret;
/* now generate the key.
*/
- ret = _gnutls_pkcs5_pbkdf2 ( PKCS5_PRF_SHA1, password,
- strlen(password), kdf_params->salt, kdf_params->salt_size,
- kdf_params->iter_count, kdf_params->key_size, key->data);
+ ret = _gnutls_pkcs5_pbkdf2(PKCS5_PRF_SHA1, password,
+ strlen(password), kdf_params->salt,
+ kdf_params->salt_size,
+ kdf_params->iter_count,
+ kdf_params->key_size, key->data);
if (ret != PKCS5_OK) {
gnutls_assert();
return GNUTLS_E_ENCRYPTION_FAILED;
}
-
+
return 0;
}
@@ -1088,76 +1374,79 @@ int ret;
/* Encodes the parameters to be written in the encryptionAlgorithm.parameters
* part.
*/
-static int write_pbe2_params( ASN1_TYPE pkcs8_asn, const struct pbkdf2_params* kdf_params,
- const struct pbe_enc_params* enc_params)
+static int write_pbe2_params(ASN1_TYPE pkcs8_asn,
+ const struct pbkdf2_params *kdf_params,
+ const struct pbe_enc_params *enc_params)
{
-int result;
-ASN1_TYPE pbes2_asn = ASN1_TYPE_EMPTY;
+ int result;
+ ASN1_TYPE pbes2_asn = ASN1_TYPE_EMPTY;
if ((result =
asn1_create_element(_gnutls_get_pkix(),
- "PKIX1.pkcs-5-PBES2-params", &pbes2_asn
- )) != ASN1_SUCCESS) {
+ "PKIX1.pkcs-5-PBES2-params",
+ &pbes2_asn)) != ASN1_SUCCESS) {
gnutls_assert();
return _gnutls_asn2err(result);
}
- result = write_pbkdf2_params( pbes2_asn, kdf_params);
+ result = write_pbkdf2_params(pbes2_asn, kdf_params);
if (result < 0) {
gnutls_assert();
goto error;
}
- result = write_pbe_enc_params( pbes2_asn, enc_params);
+ result = write_pbe_enc_params(pbes2_asn, enc_params);
if (result < 0) {
gnutls_assert();
goto error;
}
- result = _gnutls_x509_der_encode_and_copy( pbes2_asn, "",
- pkcs8_asn, "encryptionAlgorithm.parameters");
+ result = _gnutls_x509_der_encode_and_copy(pbes2_asn, "",
+ pkcs8_asn,
+ "encryptionAlgorithm.parameters");
if (result < 0) {
gnutls_assert();
goto error;
}
- asn1_delete_structure( &pbes2_asn);
-
+ asn1_delete_structure(&pbes2_asn);
+
return 0;
- error:
- asn1_delete_structure( &pbes2_asn);
- return result;
+ error:
+ asn1_delete_structure(&pbes2_asn);
+ return result;
}
-static int encrypt_data( const gnutls_datum* plain,
- const struct pbe_enc_params *enc_params,
- gnutls_datum* key, gnutls_datum* encrypted)
+static int encrypt_data(const gnutls_datum * plain,
+ const struct pbe_enc_params *enc_params,
+ gnutls_datum * key, gnutls_datum * encrypted)
{
-int result;
-int data_size;
-opaque* data=NULL;
-gnutls_datum div;
-GNUTLS_CIPHER_HANDLE ch = NULL;
-opaque pad;
-
- data = gnutls_malloc( plain->size + 8);
+ int result;
+ int data_size;
+ opaque *data = NULL;
+ gnutls_datum div;
+ GNUTLS_CIPHER_HANDLE ch = NULL;
+ opaque pad;
+
+ data = gnutls_malloc(plain->size + 8);
if (data == NULL) {
gnutls_assert();
return GNUTLS_E_MEMORY_ERROR;
}
- memcpy( data, plain->data, plain->size);
- pad = 8 - (plain->size % 8);
- if ( pad == 0) pad = 8;
-
- memset( &data[plain->size], pad, pad);
+ memcpy(data, plain->data, plain->size);
+ pad = 8 - (plain->size % 8);
+ if (pad == 0)
+ pad = 8;
+
+ memset(&data[plain->size], pad, pad);
data_size = plain->size + pad;
- div.data = (opaque*) enc_params->iv;
+ div.data = (opaque *) enc_params->iv;
div.size = enc_params->iv_size;
- ch = _gnutls_cipher_init( GNUTLS_CIPHER_3DES_CBC, key, &div);
+ ch = _gnutls_cipher_init(enc_params->cipher, key, &div);
if (ch == GNUTLS_CIPHER_FAILED) {
gnutls_assert();
@@ -1165,7 +1454,7 @@ opaque pad;
goto error;
}
- result = _gnutls_cipher_encrypt( ch, data, data_size);
+ result = _gnutls_cipher_encrypt(ch, data, data_size);
if (result < 0) {
gnutls_assert();
goto error;
@@ -1174,15 +1463,118 @@ opaque pad;
encrypted->data = data;
encrypted->size = data_size;
- _gnutls_cipher_deinit( ch);
+ _gnutls_cipher_deinit(ch);
return 0;
- error:
- gnutls_free(data);
- if (ch!=NULL)
- _gnutls_cipher_deinit( ch);
- return result;
+ error:
+ gnutls_free(data);
+ if (ch != NULL)
+ _gnutls_cipher_deinit(ch);
+ return result;
}
+/* Decrypts a PKCS #7 encryptedData. The output is allocated
+ * and stored in dec.
+ */
+int _gnutls_x509_decrypt_pkcs7_encrypted_data(const gnutls_datum * data,
+ const char *password,
+ gnutls_datum * dec)
+{
+ int result, len;
+ opaque enc_oid[64];
+ gnutls_datum tmp;
+ ASN1_TYPE pbes2_asn = ASN1_TYPE_EMPTY, pkcs7_asn = ASN1_TYPE_EMPTY;
+ int params_start, params_end, params_len;
+ struct pbkdf2_params kdf_params;
+ struct pbe_enc_params enc_params;
+ schema_id schema;
+
+ if ((result =
+ asn1_create_element(_gnutls_get_pkix(),
+ "PKIX1.pkcs-7-EncryptedData",
+ &pkcs7_asn)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto error;
+ }
+
+ result =
+ asn1_der_decoding(&pkcs7_asn, data->data, data->size, NULL);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto error;
+ }
+
+ /* Check the encryption schema OID
+ */
+ len = sizeof(enc_oid);
+ result =
+ asn1_read_value(pkcs7_asn,
+ "encryptedContentInfo.contentEncryptionAlgorithm.algorithm",
+ enc_oid, &len);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto error;
+ }
+
+ /* we only support PBES2
+ */
+ if ((result = check_schema(enc_oid)) < 0) {
+ gnutls_assert();
+ goto error;
+ }
+ schema = result;
+
+ /* Get the DER encoding of the parameters.
+ */
+ result =
+ asn1_der_decoding_startEnd(pkcs7_asn, data->data, data->size,
+ "encryptedContentInfo.contentEncryptionAlgorithm.parameters",
+ &params_start, &params_end);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto error;
+ }
+ params_len = params_end - params_start + 1;
+
+ result =
+ read_pkcs_schema_params(schema, password,
+ &data->data[params_start],
+ params_len, &kdf_params, &enc_params);
+ if (result < ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto error;
+ }
+
+ /* Parameters have been decoded. Now
+ * decrypt the EncryptedData.
+ */
+
+ result =
+ decrypt_data(schema, pkcs7_asn,
+ "encryptedContentInfo.encryptedContent", password,
+ &kdf_params, &enc_params, &tmp);
+ if (result < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
+ asn1_delete_structure(&pkcs7_asn);
+
+ *dec = tmp;
+
+ return 0;
+
+ error:
+ asn1_delete_structure(&pbes2_asn);
+ asn1_delete_structure(&pkcs7_asn);
+ return result;
+}
+
+
#endif