diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2003-06-22 15:41:35 +0000 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2003-06-22 15:41:35 +0000 |
commit | f4e57a2adcf02300f77e0dfd8fd2473ddf9b093b (patch) | |
tree | 2ceb32bc0e636cccb27306302d9a2c460c82a7cd | |
parent | ec25481a53e00bea061dac0d196193c241b884f1 (diff) | |
download | gnutls-f4e57a2adcf02300f77e0dfd8fd2473ddf9b093b.tar.gz |
Some additions to allow decrypting PKCS #5 encrypted data, with PKCS #12 schema OIDs.
-rw-r--r-- | lib/Makefile.am | 3 | ||||
-rw-r--r-- | lib/pkix.asn | 5 | ||||
-rw-r--r-- | lib/pkix_asn1_tab.c | 3 | ||||
-rw-r--r-- | lib/x509/Makefile.am | 2 | ||||
-rw-r--r-- | lib/x509/common.h | 3 | ||||
-rw-r--r-- | lib/x509/pkcs12.h | 4 | ||||
-rw-r--r-- | lib/x509/pkcs12_bag.c | 30 | ||||
-rw-r--r-- | lib/x509/pkcs12_encr.c | 92 | ||||
-rw-r--r-- | lib/x509/privkey_pkcs8.c | 1100 |
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", ¶ms_start, ¶ms_end); + result = + asn1_der_decoding_startEnd(pkcs8_asn, raw_key->data, + raw_key->size, + "encryptionAlgorithm.parameters", + ¶ms_start, ¶ms_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", ¶ms_start, ¶ms_end); + result = + asn1_der_decoding_startEnd(pbes2_asn, der->data, der->size, + "keyDerivationFunc.parameters", + ¶ms_start, ¶ms_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, ¶ms->salt_size); + result = + asn1_read_value(pbkdf2_asn, "salt.specified", params->salt, + ¶ms->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, ¶ms->iter_count); + result = + _gnutls_x509_read_ui(pbkdf2_asn, "iterationCount", oid, len, + ¶ms->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, ¶ms->key_size); + result = + _gnutls_x509_read_ui(pbkdf2_asn, "keyLength", oid, len, + ¶ms->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, + ¶ms->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, + ¶ms->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, ¶ms->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", ¶ms_start, ¶ms_end); + result = + asn1_der_decoding_startEnd(pbes2_asn, der->data, der->size, + "encryptionScheme.parameters", + ¶ms_start, ¶ms_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, ¶ms->iv_size); + result = + asn1_read_value(pbe_asn, "", params->iv, ¶ms->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", + ¶ms_start, ¶ms_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 |