diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2016-08-25 17:27:16 +0200 |
---|---|---|
committer | GitLab <gitlab@gitlab.com> | 2016-08-26 08:53:35 +0000 |
commit | eeb6ba90ef12f4095c9fc9f3956fff26fd697039 (patch) | |
tree | 726e96752d9456121b9d21858f91c111160de289 | |
parent | b643e4fafa694695c67dacdda8cad5b7e588d5a7 (diff) | |
download | gnutls-eeb6ba90ef12f4095c9fc9f3956fff26fd697039.tar.gz |
pkcs8: cleaned up PKCS#8 decoding from common code with PKCS#7
-rw-r--r-- | lib/x509/Makefile.am | 1 | ||||
-rw-r--r-- | lib/x509/pkcs12.c | 1 | ||||
-rw-r--r-- | lib/x509/pkcs12_bag.c | 3 | ||||
-rw-r--r-- | lib/x509/pkcs7-crypt.c | 1559 | ||||
-rw-r--r-- | lib/x509/pkcs7_int.h | 124 | ||||
-rw-r--r-- | lib/x509/privkey_pkcs8.c | 1576 | ||||
-rw-r--r-- | lib/x509/privkey_pkcs8_pbes1.c | 1 | ||||
-rw-r--r-- | lib/x509/x509_int.h | 60 |
8 files changed, 1703 insertions, 1622 deletions
diff --git a/lib/x509/Makefile.am b/lib/x509/Makefile.am index 02af4d3d6e..dc7e827cb8 100644 --- a/lib/x509/Makefile.am +++ b/lib/x509/Makefile.am @@ -49,6 +49,7 @@ libgnutls_x509_la_SOURCES = \ pkcs12_encr.c \ pkcs7.c \ pkcs7-attrs.c \ + pkcs7-crypt.c pkcs7_int.h \ privkey.c \ privkey_pkcs8.c \ privkey_pkcs8_pbes1.c \ diff --git a/lib/x509/pkcs12.c b/lib/x509/pkcs12.c index 053df4543d..1591bb9623 100644 --- a/lib/x509/pkcs12.c +++ b/lib/x509/pkcs12.c @@ -34,6 +34,7 @@ #include <common.h> #include <x509_b64.h> #include "x509_int.h" +#include "pkcs7_int.h" #include <random.h> diff --git a/lib/x509/pkcs12_bag.c b/lib/x509/pkcs12_bag.c index 0f3bf5a7cf..26d2142ea0 100644 --- a/lib/x509/pkcs12_bag.c +++ b/lib/x509/pkcs12_bag.c @@ -31,6 +31,7 @@ #include "errors.h" #include <common.h> #include "x509_int.h" +#include "pkcs7_int.h" /** * gnutls_pkcs12_bag_init: @@ -810,7 +811,7 @@ gnutls_pkcs12_bag_enc_info(gnutls_pkcs12_bag_t bag, unsigned int *schema, unsign { int ret; struct pbkdf2_params kdf; - const struct pbes2_schema_st *p; + const struct pkcs_cipher_schema_st *p; if (bag == NULL) { gnutls_assert(); diff --git a/lib/x509/pkcs7-crypt.c b/lib/x509/pkcs7-crypt.c new file mode 100644 index 0000000000..e2c26d0edc --- /dev/null +++ b/lib/x509/pkcs7-crypt.c @@ -0,0 +1,1559 @@ +/* + * Copyright (C) 2003-2016 Free Software Foundation, Inc. + * Copyright (C) 2014-2016 Red Hat + * Copyright (C) 2014-2016 Nikos Mavrogiannopoulos + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +#include "gnutls_int.h" + +#include <datum.h> +#include <global.h> +#include "errors.h" +#include <common.h> +#include <x509.h> +#include <x509_b64.h> +#include "x509_int.h" +#include "pkcs7_int.h" +#include <algorithms.h> +#include <num.h> +#include <random.h> +#include <pk.h> +#include <nettle/pbkdf2.h> + +#define PBES1_DES_MD5_OID "1.2.840.113549.1.5.3" + +#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" +#define AES_128_CBC_OID "2.16.840.1.101.3.4.1.2" +#define AES_192_CBC_OID "2.16.840.1.101.3.4.1.22" +#define AES_256_CBC_OID "2.16.840.1.101.3.4.1.42" +#define DES_CBC_OID "1.3.14.3.2.7" + +/* oid_pbeWithSHAAnd3_KeyTripleDES_CBC */ +#define PKCS12_PBE_3DES_SHA1_OID "1.2.840.113549.1.12.1.3" +#define PKCS12_PBE_ARCFOUR_SHA1_OID "1.2.840.113549.1.12.1.1" +#define PKCS12_PBE_RC2_40_SHA1_OID "1.2.840.113549.1.12.1.6" + +static const struct pkcs_cipher_schema_st avail_pkcs_cipher_schemas[] = +{ + { + .schema = PBES1_DES_MD5, + .name = "PBES1-DES-CBC-MD5", + .flag = GNUTLS_PKCS_PBES1_DES_MD5, + .cipher = GNUTLS_CIPHER_DES_CBC, + .pbes2 = 0, + .cipher_oid = PBES1_DES_MD5_OID, + .write_oid = PBES1_DES_MD5_OID, + .desc = NULL, + .decrypt_only = 1 + }, + { + .schema = PBES2_3DES, + .name = "PBES2-3DES-CBC", + .flag = GNUTLS_PKCS_PBES2_3DES, + .cipher = GNUTLS_CIPHER_3DES_CBC, + .pbes2 = 1, + .cipher_oid = DES_EDE3_CBC_OID, + .write_oid = PBES2_OID, + .desc = "PKIX1.pkcs-5-des-EDE3-CBC-params", + .decrypt_only = 0 + }, + { + .schema = PBES2_DES, + .name = "PBES2-DES-CBC", + .flag = GNUTLS_PKCS_PBES2_DES, + .cipher = GNUTLS_CIPHER_DES_CBC, + .pbes2 = 1, + .cipher_oid = DES_CBC_OID, + .write_oid = PBES2_OID, + .desc = "PKIX1.pkcs-5-des-CBC-params", + .decrypt_only = 0 + }, + { + .schema = PBES2_AES_128, + .name = "PBES2-AES128-CBC", + .flag = GNUTLS_PKCS_PBES2_AES_128, + .cipher = GNUTLS_CIPHER_AES_128_CBC, + .pbes2 = 1, + .cipher_oid = AES_128_CBC_OID, + .write_oid = PBES2_OID, + .desc = "PKIX1.pkcs-5-aes128-CBC-params", + .decrypt_only = 0 + }, + { + .schema = PBES2_AES_192, + .name = "PBES2-AES192-CBC", + .flag = GNUTLS_PKCS_PBES2_AES_192, + .cipher = GNUTLS_CIPHER_AES_192_CBC, + .pbes2 = 1, + .cipher_oid = AES_192_CBC_OID, + .write_oid = PBES2_OID, + .desc = "PKIX1.pkcs-5-aes192-CBC-params", + .decrypt_only = 0 + }, + { + .schema = PBES2_AES_256, + .name = "PBES2-AES256-CBC", + .flag = GNUTLS_PKCS_PBES2_AES_256, + .cipher = GNUTLS_CIPHER_AES_256_CBC, + .pbes2 = 1, + .cipher_oid = AES_256_CBC_OID, + .write_oid = PBES2_OID, + .desc = "PKIX1.pkcs-5-aes256-CBC-params", + .decrypt_only = 0 + }, + { + .schema = PKCS12_ARCFOUR_SHA1, + .name = "PKCS12-ARCFOUR-SHA1", + .flag = GNUTLS_PKCS_PKCS12_ARCFOUR, + .cipher = GNUTLS_CIPHER_ARCFOUR, + .pbes2 = 0, + .cipher_oid = PKCS12_PBE_ARCFOUR_SHA1_OID, + .write_oid = PKCS12_PBE_ARCFOUR_SHA1_OID, + .desc = NULL, + .decrypt_only = 0 + }, + { + .schema = PKCS12_RC2_40_SHA1, + .name = "PKCS12-RC2-40-SHA1", + .flag = GNUTLS_PKCS_PKCS12_RC2_40, + .cipher = GNUTLS_CIPHER_RC2_40_CBC, + .pbes2 = 0, + .cipher_oid = PKCS12_PBE_RC2_40_SHA1_OID, + .write_oid = PKCS12_PBE_RC2_40_SHA1_OID, + .desc = NULL, + .decrypt_only = 0 + }, + { + .schema = PKCS12_3DES_SHA1, + .name = "PKCS12-3DES-SHA1", + .flag = GNUTLS_PKCS_PKCS12_3DES, + .cipher = GNUTLS_CIPHER_3DES_CBC, + .pbes2 = 0, + .cipher_oid = PKCS12_PBE_3DES_SHA1_OID, + .write_oid = PKCS12_PBE_3DES_SHA1_OID, + .desc = NULL, + .decrypt_only = 0 + }, + {0, 0, 0, 0, 0} +}; + +#define PBES2_SCHEMA_LOOP(b) { \ + const struct pkcs_cipher_schema_st * _p; \ + for (_p=avail_pkcs_cipher_schemas;_p->schema != 0;_p++) { b; } \ + } + +#define PBES2_SCHEMA_FIND_FROM_FLAGS(fl, what) \ + PBES2_SCHEMA_LOOP( if (_p->flag == GNUTLS_PKCS_CIPHER_MASK(fl)) { what; } ) + +int _gnutls_pkcs_flags_to_schema(unsigned int flags) +{ + PBES2_SCHEMA_FIND_FROM_FLAGS(flags, return _p->schema;); + + gnutls_assert(); + _gnutls_debug_log + ("Selecting default encryption PKCS12_3DES_SHA1 (flags: %u).\n", + flags); + return PKCS12_3DES_SHA1; +} + +/** + * gnutls_pkcs_schema_get_name: + * @schema: Holds the PKCS #12 or PBES2 schema (%gnutls_pkcs_encrypt_flags_t) + * + * This function will return a human readable description of the + * PKCS12 or PBES2 schema. + * + * Returns: a constrant string or %NULL on error. + * + * Since: 3.4.0 + */ +const char *gnutls_pkcs_schema_get_name(unsigned int schema) +{ + PBES2_SCHEMA_FIND_FROM_FLAGS(schema, return _p->name;); + return NULL; +} + + +/** + * gnutls_pkcs_schema_get_oid: + * @schema: Holds the PKCS #12 or PBES2 schema (%gnutls_pkcs_encrypt_flags_t) + * + * This function will return the object identifier of the + * PKCS12 or PBES2 schema. + * + * Returns: a constrant string or %NULL on error. + * + * Since: 3.4.0 + */ +const char *gnutls_pkcs_schema_get_oid(unsigned int schema) +{ + PBES2_SCHEMA_FIND_FROM_FLAGS(schema, return _p->cipher_oid;); + return NULL; +} + +static const struct pkcs_cipher_schema_st *algo_to_pbes2_cipher_schema(unsigned cipher) +{ + PBES2_SCHEMA_LOOP( + if (_p->cipher == cipher && _p->pbes2 != 0) { + return _p; + }); + + gnutls_assert(); + return NULL; +} + +/* Converts a PKCS#7 encryption schema OID to an internal + * schema_id or returns a negative value */ +int _gnutls_check_pkcs_cipher_schema(const char *oid) +{ + if (strcmp(oid, PBES2_OID) == 0) + return PBES2_GENERIC; /* PBES2 ciphers are under an umbrella OID */ + + PBES2_SCHEMA_LOOP(if (_p->pbes2 == 0 && strcmp(oid, _p->write_oid) == 0) {return _p->schema;}); + _gnutls_debug_log + ("PKCS #12 encryption schema OID '%s' is unsupported.\n", oid); + + return GNUTLS_E_UNKNOWN_CIPHER_TYPE; +} + +const struct pkcs_cipher_schema_st *_gnutls_pkcs_schema_get(schema_id schema) +{ + PBES2_SCHEMA_LOOP(if (schema == _p->schema) return _p;); + + gnutls_assert(); + return NULL; +} + +/* Converts an OID to a gnutls cipher type. + */ +static int +pbes2_cipher_oid_to_algo(const char *oid, gnutls_cipher_algorithm_t *algo) +{ + + *algo = 0; + PBES2_SCHEMA_LOOP(if (_p->pbes2 != 0 && strcmp(_p->cipher_oid, oid) == 0) { + *algo = _p->cipher; + return 0; + } + ); + + _gnutls_debug_log("PKCS #8 encryption OID '%s' is unsupported.\n", + oid); + return GNUTLS_E_UNKNOWN_CIPHER_TYPE; +} + + +/* Decrypts a PKCS #7 encryptedData. The output is allocated + * and stored in dec. + */ +int +_gnutls_pkcs7_decrypt_data(const gnutls_datum_t * data, + const char *password, gnutls_datum_t * dec) +{ + int result, len; + char enc_oid[MAX_OID_SIZE]; + gnutls_datum_t tmp; + ASN1_TYPE pasn = 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; + } + + if ((result = _gnutls_check_pkcs_cipher_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 = + _gnutls_read_pkcs_schema_params(&schema, password, + &data->data[params_start], + params_len, &kdf_params, &enc_params); + if (result < 0) { + gnutls_assert(); + goto error; + } + + /* Parameters have been decoded. Now + * decrypt the EncryptedData. + */ + + result = + _gnutls_pkcs_raw_decrypt_data(schema, pkcs7_asn, + "encryptedContentInfo.encryptedContent", password, + &kdf_params, &enc_params, &tmp); + if (result < 0) { + gnutls_assert(); + goto error; + } + + asn1_delete_structure2(&pkcs7_asn, ASN1_DELETE_FLAG_ZEROIZE); + + *dec = tmp; + + return 0; + + error: + asn1_delete_structure(&pasn); + asn1_delete_structure2(&pkcs7_asn, ASN1_DELETE_FLAG_ZEROIZE); + return result; +} + +int +_gnutls_pkcs7_data_enc_info(const gnutls_datum_t * data, const struct pkcs_cipher_schema_st **p, + struct pbkdf2_params *kdf_params, char **oid) +{ + int result, len; + char enc_oid[MAX_OID_SIZE]; + ASN1_TYPE pasn = ASN1_TYPE_EMPTY, pkcs7_asn = ASN1_TYPE_EMPTY; + int params_start, params_end, params_len; + 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; + } + + if (oid) { + *oid = gnutls_strdup(enc_oid); + } + + if ((result = _gnutls_check_pkcs_cipher_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 = + _gnutls_read_pkcs_schema_params(&schema, NULL, + &data->data[params_start], + params_len, kdf_params, &enc_params); + if (result < 0) { + gnutls_assert(); + goto error; + } + + *p = _gnutls_pkcs_schema_get(schema); + if (*p == NULL) { + gnutls_assert(); + result = GNUTLS_E_UNKNOWN_CIPHER_TYPE; + goto error; + } + + asn1_delete_structure2(&pkcs7_asn, ASN1_DELETE_FLAG_ZEROIZE); + + return 0; + + error: + asn1_delete_structure(&pasn); + asn1_delete_structure2(&pkcs7_asn, ASN1_DELETE_FLAG_ZEROIZE); + return result; +} + +/* Encrypts to a PKCS #7 encryptedData. The output is allocated + * and stored in enc. + */ +int +_gnutls_pkcs7_encrypt_data(schema_id schema, + const gnutls_datum_t * data, + const char *password, gnutls_datum_t * enc) +{ + int result; + gnutls_datum_t key = { NULL, 0 }; + gnutls_datum_t tmp = { NULL, 0 }; + ASN1_TYPE pkcs7_asn = ASN1_TYPE_EMPTY; + struct pbkdf2_params kdf_params; + struct pbe_enc_params enc_params; + const struct pkcs_cipher_schema_st *s; + + s = _gnutls_pkcs_schema_get(schema); + if (s == NULL || s->decrypt_only) { + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + } + + 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_write_value(pkcs7_asn, + "encryptedContentInfo.contentEncryptionAlgorithm.algorithm", + s->write_oid, 1); + + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + /* Generate a symmetric key. + */ + + result = + _gnutls_pkcs_generate_key(schema, password, &kdf_params, &enc_params, &key); + if (result < 0) { + gnutls_assert(); + goto error; + } + + result = _gnutls_pkcs_write_schema_params(schema, pkcs7_asn, + "encryptedContentInfo.contentEncryptionAlgorithm.parameters", + &kdf_params, &enc_params); + if (result < 0) { + gnutls_assert(); + goto error; + } + + /* Parameters have been encoded. Now + * encrypt the Data. + */ + result = _gnutls_pkcs_raw_encrypt_data(data, &enc_params, &key, &tmp); + if (result < 0) { + gnutls_assert(); + goto error; + } + + /* write the encrypted data. + */ + result = + asn1_write_value(pkcs7_asn, + "encryptedContentInfo.encryptedContent", + tmp.data, tmp.size); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + _gnutls_free_datum(&tmp); + _gnutls_free_key_datum(&key); + + /* Now write the rest of the pkcs-7 stuff. + */ + + result = _gnutls_x509_write_uint32(pkcs7_asn, "version", 0); + if (result < 0) { + gnutls_assert(); + goto error; + } + + result = + asn1_write_value(pkcs7_asn, "encryptedContentInfo.contentType", + DATA_OID, 1); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + result = asn1_write_value(pkcs7_asn, "unprotectedAttrs", NULL, 0); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + /* Now encode and copy the DER stuff. + */ + result = _gnutls_x509_der_encode(pkcs7_asn, "", enc, 0); + + asn1_delete_structure2(&pkcs7_asn, ASN1_DELETE_FLAG_ZEROIZE); + + if (result < 0) { + gnutls_assert(); + goto error; + } + + + error: + _gnutls_free_key_datum(&key); + _gnutls_free_datum(&tmp); + asn1_delete_structure2(&pkcs7_asn, ASN1_DELETE_FLAG_ZEROIZE); + return result; +} + +/* Reads the PBKDF2 parameters. + */ +static int +read_pbkdf2_params(ASN1_TYPE pasn, + const gnutls_datum_t * der, + struct pbkdf2_params *params) +{ + int params_start, params_end; + int params_len, len, result; + ASN1_TYPE pbkdf2_asn = ASN1_TYPE_EMPTY; + char oid[MAX_OID_SIZE]; + + memset(params, 0, sizeof(*params)); + + params->mac = GNUTLS_MAC_SHA1; + + /* Check the key derivation algorithm + */ + len = sizeof(oid); + result = + asn1_read_value(pasn, "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_assert(); + _gnutls_debug_log + ("PKCS #8 key derivation OID '%s' is unsupported.\n", + oid); + return _gnutls_asn2err(result); + } + + result = + asn1_der_decoding_startEnd(pasn, der->data, der->size, + "keyDerivationFunc.parameters", + ¶ms_start, ¶ms_end); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + 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-PBKDF2-params", + &pbkdf2_asn)) != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + result = + _asn1_strict_der_decode(&pbkdf2_asn, &der->data[params_start], + params_len, NULL); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + /* read the salt */ + params->salt_size = sizeof(params->salt); + 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); + + /* read the iteration count + */ + result = + _gnutls_x509_read_uint(pbkdf2_asn, "iterationCount", + ¶ms->iter_count); + if (result < 0) { + gnutls_assert(); + goto error; + } + _gnutls_hard_log("iterationCount: %d\n", params->iter_count); + + /* read the keylength, if it is set. + */ + result = + _gnutls_x509_read_uint(pbkdf2_asn, "keyLength", + ¶ms->key_size); + if (result < 0) { + params->key_size = 0; + } + _gnutls_hard_log("keyLength: %d\n", params->key_size); + + len = sizeof(oid); + result = + asn1_read_value(pbkdf2_asn, "prf.algorithm", + oid, &len); + if (result != ASN1_SUCCESS) { + /* use the default MAC */ + result = 0; + goto error; + } + + params->mac = gnutls_oid_to_mac(oid); + if (params->mac == GNUTLS_MAC_UNKNOWN) { + gnutls_assert(); + _gnutls_debug_log("Unsupported hash algorithm: %s\n", oid); + result = GNUTLS_E_UNKNOWN_HASH_ALGORITHM; + goto error; + } + + result = 0; + + error: + asn1_delete_structure(&pbkdf2_asn); + return result; + +} + +/* Reads the PBE parameters from PKCS-12 schemas (*&#%*&#% RSA). + */ +static int +read_pkcs12_kdf_params(ASN1_TYPE pasn, struct pbkdf2_params *params) +{ + int result; + + memset(params, 0, sizeof(*params)); + + /* read the salt */ + params->salt_size = sizeof(params->salt); + result = + asn1_read_value(pasn, "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 + */ + result = + _gnutls_x509_read_uint(pasn, "iterations", + ¶ms->iter_count); + if (result < 0) { + gnutls_assert(); + goto error; + } + _gnutls_hard_log("iterationCount: %d\n", params->iter_count); + + params->key_size = 0; + + return 0; + + error: + return result; + +} + +/* Writes the PBE parameters for PKCS-12 schemas. + */ +static int +write_pkcs12_kdf_params(ASN1_TYPE pasn, + const struct pbkdf2_params *kdf_params) +{ + int result; + + /* write the salt + */ + result = + asn1_write_value(pasn, "salt", + kdf_params->salt, kdf_params->salt_size); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + _gnutls_hard_log("salt.size: %d\n", kdf_params->salt_size); + + /* write the iteration count + */ + result = + _gnutls_x509_write_uint32(pasn, "iterations", + kdf_params->iter_count); + if (result < 0) { + gnutls_assert(); + goto error; + } + _gnutls_hard_log("iterationCount: %d\n", kdf_params->iter_count); + + return 0; + + error: + return result; + +} + +static int +read_pbes2_enc_params(ASN1_TYPE pasn, + const gnutls_datum_t * 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[MAX_OID_SIZE]; + const struct pkcs_cipher_schema_st *p; + + memset(params, 0, sizeof(*params)); + + /* Check the encryption algorithm + */ + len = sizeof(oid); + result = + asn1_read_value(pasn, "encryptionScheme.algorithm", oid, + &len); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + _gnutls_hard_log("encryptionScheme.algorithm: %s\n", oid); + + if ((result = pbes2_cipher_oid_to_algo(oid, ¶ms->cipher)) < 0) { + gnutls_assert(); + return result; + } + + result = + asn1_der_decoding_startEnd(pasn, der->data, der->size, + "encryptionScheme.parameters", + ¶ms_start, ¶ms_end); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + params_len = params_end - params_start + 1; + + /* Now check the encryption parameters. + */ + p = algo_to_pbes2_cipher_schema(params->cipher); + if (p == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + if ((result = + asn1_create_element(_gnutls_get_pkix(), + p->desc, &pbe_asn)) != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + result = + _asn1_strict_der_decode(&pbe_asn, &der->data[params_start], + params_len, NULL); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + /* read the IV */ + params->iv_size = sizeof(params->iv); + 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); + + result = 0; + + error: + asn1_delete_structure(&pbe_asn); + return result; +} + +/* Read the parameters cipher, IV, salt etc using the given + * schema ID. Initially the schema ID should have PBES2_GENERIC, for + * PBES2 schemas, and will be updated by this function for details. + */ +int +_gnutls_read_pkcs_schema_params(schema_id * schema, const char *password, + const uint8_t * data, int data_size, + struct pbkdf2_params *kdf_params, + struct pbe_enc_params *enc_params) +{ + ASN1_TYPE pasn = ASN1_TYPE_EMPTY; + int result; + gnutls_datum_t tmp; + const struct pkcs_cipher_schema_st *p; + + if (*schema == PBES2_GENERIC) { + /* Now check the key derivation and the encryption + * functions. + */ + if ((result = + asn1_create_element(_gnutls_get_pkix(), + "PKIX1.pkcs-5-PBES2-params", + &pasn)) != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + /* Decode the parameters. + */ + result = + _asn1_strict_der_decode(&pasn, data, data_size, NULL); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + tmp.data = (uint8_t *) data; + tmp.size = data_size; + + result = read_pbkdf2_params(pasn, &tmp, kdf_params); + if (result < 0) { + gnutls_assert(); + goto error; + } + + result = read_pbes2_enc_params(pasn, &tmp, enc_params); + if (result < 0) { + gnutls_assert(); + goto error; + } + + asn1_delete_structure2(&pasn, ASN1_DELETE_FLAG_ZEROIZE); + + p = algo_to_pbes2_cipher_schema(enc_params->cipher); + if (p == NULL) { + result = GNUTLS_E_INVALID_REQUEST; + gnutls_assert(); + goto error; + } + + *schema = p->schema; + return 0; + } else if (*schema == PBES1_DES_MD5) { + return _gnutls_read_pbkdf1_params(data, data_size, kdf_params, enc_params); + } else { /* PKCS #12 schema */ + memset(enc_params, 0, sizeof(*enc_params)); + + p = _gnutls_pkcs_schema_get(*schema); + if (p == NULL) { + gnutls_assert(); + result = GNUTLS_E_UNKNOWN_CIPHER_TYPE; + goto error; + } + enc_params->cipher = p->cipher; + enc_params->iv_size = gnutls_cipher_get_iv_size(p->cipher); + + if ((result = + asn1_create_element(_gnutls_get_pkix(), + "PKIX1.pkcs-12-PbeParams", + &pasn)) != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + /* Decode the parameters. + */ + result = + _asn1_strict_der_decode(&pasn, data, data_size, NULL); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + result = read_pkcs12_kdf_params(pasn, kdf_params); + if (result < 0) { + gnutls_assert(); + goto error; + } + + if (enc_params->iv_size) { + result = + _gnutls_pkcs12_string_to_key(mac_to_entry(GNUTLS_MAC_SHA1), + 2 /*IV*/, + kdf_params->salt, + kdf_params-> + salt_size, + kdf_params-> + iter_count, + password, + enc_params-> + iv_size, + enc_params->iv); + if (result < 0) { + gnutls_assert(); + goto error; + } + + } + + asn1_delete_structure(&pasn); + + return 0; + } /* switch */ + + error: + asn1_delete_structure(&pasn); + return result; +} + +int +_gnutls_pkcs_raw_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_t *decrypted_data) +{ + int result; + gnutls_datum_t enc = {NULL, 0}; + uint8_t *key = NULL; + gnutls_datum_t dkey, d_iv; + cipher_hd_st ch; + int ch_init = 0; + int key_size; + unsigned int pass_len = 0; + const struct pkcs_cipher_schema_st *p; + + if (password) + pass_len = strlen(password); + + result = _gnutls_x509_read_value(pkcs8_asn, root, &enc); + if (result < 0) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + if (schema == PBES1_DES_MD5) { + return _gnutls_decrypt_pbes1_des_md5_data(password, pass_len, + kdf_params, enc_params, + &enc, decrypted_data); + } + + if (kdf_params->key_size == 0) { + key_size = gnutls_cipher_get_key_size(enc_params->cipher); + } else + key_size = kdf_params->key_size; + + key = gnutls_malloc(key_size); + if (key == NULL) { + gnutls_assert(); + result = GNUTLS_E_MEMORY_ERROR; + goto error; + } + + /* generate the key + */ + p = _gnutls_pkcs_schema_get(schema); + if (p != NULL && p->pbes2 != 0) { /* PBES2 */ + if (kdf_params->mac == GNUTLS_MAC_SHA1) + pbkdf2_hmac_sha1(pass_len, (uint8_t*)password, + kdf_params->iter_count, + kdf_params->salt_size, kdf_params->salt, + key_size, key); + else if (kdf_params->mac == GNUTLS_MAC_SHA256) + pbkdf2_hmac_sha256(pass_len, (uint8_t*)password, + kdf_params->iter_count, + kdf_params->salt_size, kdf_params->salt, + key_size, key); + else return gnutls_assert_val(GNUTLS_E_UNKNOWN_HASH_ALGORITHM); + } else if (p != NULL) { /* PKCS 12 schema */ + result = + _gnutls_pkcs12_string_to_key(mac_to_entry(GNUTLS_MAC_SHA1), + 1 /*KEY*/, + kdf_params->salt, + kdf_params->salt_size, + kdf_params->iter_count, + password, key_size, key); + + if (result < 0) { + gnutls_assert(); + goto error; + } + } else { + gnutls_assert(); + result = GNUTLS_E_UNKNOWN_CIPHER_TYPE; + goto error; + } + + /* do the decryption. + */ + dkey.data = key; + dkey.size = key_size; + + d_iv.data = (uint8_t *) enc_params->iv; + d_iv.size = enc_params->iv_size; + result = + _gnutls_cipher_init(&ch, cipher_to_entry(enc_params->cipher), + &dkey, &d_iv, 0); + + gnutls_free(key); + key = NULL; + + if (result < 0) { + gnutls_assert(); + goto error; + } + + ch_init = 1; + + result = _gnutls_cipher_decrypt(&ch, enc.data, enc.size); + if (result < 0) { + gnutls_assert(); + goto error; + } + + decrypted_data->data = enc.data; + + if (gnutls_cipher_get_block_size(enc_params->cipher) != 1) + decrypted_data->size = enc.size - enc.data[enc.size - 1]; + else + decrypted_data->size = enc.size; + + _gnutls_cipher_deinit(&ch); + + return 0; + + error: + gnutls_free(enc.data); + gnutls_free(key); + if (ch_init != 0) + _gnutls_cipher_deinit(&ch); + return result; +} + + +/* Writes the PBKDF2 parameters. + */ +static int +write_pbkdf2_params(ASN1_TYPE pasn, + const struct pbkdf2_params *kdf_params) +{ + int result; + ASN1_TYPE pbkdf2_asn = ASN1_TYPE_EMPTY; + uint8_t tmp[MAX_OID_SIZE]; + + /* Write the key derivation algorithm + */ + result = + asn1_write_value(pasn, "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) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + 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); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + _gnutls_hard_log("salt.specified.size: %d\n", + kdf_params->salt_size); + + /* write the iteration count + */ + _gnutls_write_uint32(kdf_params->iter_count, tmp); + + 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); + + /* write the keylength, if it is set. + */ + 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); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + /* now encode them an put the DER output + * in the keyDerivationFunc.parameters + */ + result = _gnutls_x509_der_encode_and_copy(pbkdf2_asn, "", + pasn, + "keyDerivationFunc.parameters", + 0); + if (result < 0) { + gnutls_assert(); + goto error; + } + + return 0; + + error: + asn1_delete_structure(&pbkdf2_asn); + return result; + +} + + +static int +write_pbes2_enc_params(ASN1_TYPE pasn, + const struct pbe_enc_params *params) +{ + int result; + ASN1_TYPE pbe_asn = ASN1_TYPE_EMPTY; + const struct pkcs_cipher_schema_st *p; + + /* Write the encryption algorithm + */ + p = algo_to_pbes2_cipher_schema(params->cipher); + if (p == NULL || p->pbes2 == 0) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + result = + asn1_write_value(pasn, "encryptionScheme.algorithm", p->cipher_oid, + 1); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + goto error; + } + _gnutls_hard_log("encryptionScheme.algorithm: %s\n", p->cipher_oid); + + /* Now check the encryption parameters. + */ + if ((result = + asn1_create_element(_gnutls_get_pkix(), + p->desc, &pbe_asn)) != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + /* read the salt */ + 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); + + /* now encode them an put the DER output + * in the encryptionScheme.parameters + */ + result = _gnutls_x509_der_encode_and_copy(pbe_asn, "", + pasn, + "encryptionScheme.parameters", + 0); + if (result < 0) { + gnutls_assert(); + goto error; + } + + return 0; + + error: + asn1_delete_structure(&pbe_asn); + return result; + +} + +/* Generates a key and also stores the key parameters. + */ +int +_gnutls_pkcs_generate_key(schema_id schema, + const char *password, + struct pbkdf2_params *kdf_params, + struct pbe_enc_params *enc_params, gnutls_datum_t * key) +{ + unsigned char rnd[2]; + unsigned int pass_len = 0; + int ret; + const struct pkcs_cipher_schema_st *p; + + if (password) + pass_len = strlen(password); + + ret = _gnutls_rnd(GNUTLS_RND_RANDOM, rnd, 2); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + /* generate salt */ + kdf_params->salt_size = + MIN(sizeof(kdf_params->salt), (unsigned) (12 + (rnd[1] % 10))); + + p = _gnutls_pkcs_schema_get(schema); + if (p != NULL && p->pbes2 != 0) { /* PBES2 */ + enc_params->cipher = p->cipher; + } else if (p != NULL) { + /* non PBES2 algorithms */ + enc_params->cipher = p->cipher; + kdf_params->salt_size = 8; + } else { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + ret = _gnutls_rnd(GNUTLS_RND_RANDOM, kdf_params->salt, + kdf_params->salt_size); + if (ret < 0) { + gnutls_assert(); + return GNUTLS_E_RANDOM_FAILED; + } + + kdf_params->iter_count = 5*1024 + rnd[0]; + key->size = kdf_params->key_size = + gnutls_cipher_get_key_size(enc_params->cipher); + + enc_params->iv_size = + gnutls_cipher_get_iv_size(enc_params->cipher); + key->data = gnutls_malloc(key->size); + if (key->data == NULL) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + /* now generate the key. + */ + + if (p->pbes2 != 0) { + pbkdf2_hmac_sha1(pass_len, (uint8_t*)password, + kdf_params->iter_count, + kdf_params->salt_size, kdf_params->salt, + kdf_params->key_size, key->data); + + if (enc_params->iv_size) { + ret = _gnutls_rnd(GNUTLS_RND_NONCE, + enc_params->iv, + enc_params->iv_size); + if (ret < 0) { + gnutls_assert(); + return ret; + } + } + } else { /* PKCS 12 schema */ + ret = + _gnutls_pkcs12_string_to_key(mac_to_entry(GNUTLS_MAC_SHA1), + 1 /*KEY*/, + kdf_params->salt, + kdf_params->salt_size, + kdf_params->iter_count, + password, + kdf_params->key_size, + key->data); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + /* Now generate the IV + */ + if (enc_params->iv_size) { + ret = + _gnutls_pkcs12_string_to_key(mac_to_entry(GNUTLS_MAC_SHA1), + 2 /*IV*/, + kdf_params->salt, + kdf_params-> + salt_size, + kdf_params-> + iter_count, + password, + enc_params-> + iv_size, + enc_params->iv); + if (ret < 0) { + gnutls_assert(); + return ret; + } + } + } + + + return 0; +} + + +/* Encodes the parameters to be written in the encryptionAlgorithm.parameters + * part. + */ +int +_gnutls_pkcs_write_schema_params(schema_id schema, ASN1_TYPE pkcs8_asn, + const char *where, + const struct pbkdf2_params *kdf_params, + const struct pbe_enc_params *enc_params) +{ + int result; + ASN1_TYPE pasn = ASN1_TYPE_EMPTY; + const struct pkcs_cipher_schema_st *p; + + p = _gnutls_pkcs_schema_get(schema); + + if (p != NULL && p->pbes2 != 0) { /* PBES2 */ + if ((result = + asn1_create_element(_gnutls_get_pkix(), + "PKIX1.pkcs-5-PBES2-params", + &pasn)) != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + result = write_pbkdf2_params(pasn, kdf_params); + if (result < 0) { + gnutls_assert(); + goto error; + } + + result = write_pbes2_enc_params(pasn, enc_params); + if (result < 0) { + gnutls_assert(); + goto error; + } + + result = _gnutls_x509_der_encode_and_copy(pasn, "", + pkcs8_asn, where, + 0); + if (result < 0) { + gnutls_assert(); + goto error; + } + + asn1_delete_structure(&pasn); + + } else if (p != NULL) { /* PKCS #12 */ + + if ((result = + asn1_create_element(_gnutls_get_pkix(), + "PKIX1.pkcs-12-PbeParams", + &pasn)) != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + result = write_pkcs12_kdf_params(pasn, kdf_params); + if (result < 0) { + gnutls_assert(); + goto error; + } + + result = _gnutls_x509_der_encode_and_copy(pasn, "", + pkcs8_asn, where, + 0); + if (result < 0) { + gnutls_assert(); + goto error; + } + + asn1_delete_structure(&pasn); + } + + return 0; + + error: + asn1_delete_structure(&pasn); + return result; + +} + +int +_gnutls_pkcs_raw_encrypt_data(const gnutls_datum_t * plain, + const struct pbe_enc_params *enc_params, + gnutls_datum_t * key, gnutls_datum_t * encrypted) +{ + int result; + int data_size; + uint8_t *data = NULL; + gnutls_datum_t d_iv; + cipher_hd_st ch; + int ch_init = 0; + uint8_t pad, pad_size; + + pad_size = gnutls_cipher_get_block_size(enc_params->cipher); + + if (pad_size == 1) /* stream */ + pad_size = 0; + + data = gnutls_malloc(plain->size + pad_size); + if (data == NULL) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + memcpy(data, plain->data, plain->size); + + if (pad_size > 0) { + pad = pad_size - (plain->size % pad_size); + if (pad == 0) + pad = pad_size; + memset(&data[plain->size], pad, pad); + } else + pad = 0; + + data_size = plain->size + pad; + + d_iv.data = (uint8_t *) enc_params->iv; + d_iv.size = enc_params->iv_size; + result = + _gnutls_cipher_init(&ch, cipher_to_entry(enc_params->cipher), + key, &d_iv, 1); + + if (result < 0) { + gnutls_assert(); + goto error; + } + + ch_init = 1; + + result = _gnutls_cipher_encrypt(&ch, data, data_size); + if (result < 0) { + gnutls_assert(); + goto error; + } + + encrypted->data = data; + encrypted->size = data_size; + + _gnutls_cipher_deinit(&ch); + + return 0; + + error: + gnutls_free(data); + if (ch_init != 0) + _gnutls_cipher_deinit(&ch); + return result; +} + diff --git a/lib/x509/pkcs7_int.h b/lib/x509/pkcs7_int.h new file mode 100644 index 0000000000..57e72b96e5 --- /dev/null +++ b/lib/x509/pkcs7_int.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2003-2016 Free Software Foundation, Inc. + * Copyright (C) 2016 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef PKCS7_INT_H +#define PKCS7_INT_H + +#include <gnutls/x509.h> + +/* PKCS #7 + */ +#define DATA_OID "1.2.840.113549.1.7.1" +#define ENC_DATA_OID "1.2.840.113549.1.7.6" + + +typedef enum schema_id { + PBES2_GENERIC=1, /* when the algorithm is unknown, temporal use when reading only */ + PBES2_DES, /* the stuff in PKCS #5 */ + PBES2_3DES, + PBES2_AES_128, + PBES2_AES_192, + PBES2_AES_256, + PKCS12_3DES_SHA1, /* the stuff in PKCS #12 */ + PKCS12_ARCFOUR_SHA1, + PKCS12_RC2_40_SHA1, + PBES1_DES_MD5 /* openssl before 1.1.0 uses that by default */ +} schema_id; + +struct pkcs_cipher_schema_st { + unsigned int schema; + const char *name; + unsigned int flag; + unsigned int cipher; + unsigned pbes2; + const char *cipher_oid; + const char *write_oid; + const char *desc; + unsigned decrypt_only; +}; + +const struct pkcs_cipher_schema_st *_gnutls_pkcs_schema_get(schema_id schema); + +struct pbe_enc_params { + gnutls_cipher_algorithm_t cipher; + uint8_t iv[MAX_CIPHER_BLOCK_SIZE]; + int iv_size; +}; + +int +_gnutls_decrypt_pbes1_des_md5_data(const char *password, + unsigned password_len, + const struct pbkdf2_params *kdf_params, + const struct pbe_enc_params *enc_params, + gnutls_datum_t *encrypted_data, /* overwritten */ + gnutls_datum_t *decrypted_data); + +int _gnutls_check_pkcs_cipher_schema(const char *oid); + +int +_gnutls_pkcs_raw_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_t *decrypted_data); + +int +_gnutls_pkcs_raw_encrypt_data(const gnutls_datum_t * plain, + const struct pbe_enc_params *enc_params, + gnutls_datum_t * key, gnutls_datum_t * encrypted); + +int _gnutls_pkcs7_decrypt_data(const gnutls_datum_t * data, + const char *password, gnutls_datum_t * dec); + +int _gnutls_read_pbkdf1_params(const uint8_t * data, int data_size, + struct pbkdf2_params *kdf_params, + struct pbe_enc_params *enc_params); + +int +_gnutls_read_pkcs_schema_params(schema_id * schema, const char *password, + const uint8_t * data, int data_size, + struct pbkdf2_params *kdf_params, + struct pbe_enc_params *enc_params); + +int +_gnutls_pkcs_write_schema_params(schema_id schema, ASN1_TYPE pkcs8_asn, + const char *where, + const struct pbkdf2_params *kdf_params, + const struct pbe_enc_params *enc_params); + +int +_gnutls_pkcs_generate_key(schema_id schema, + const char *password, + struct pbkdf2_params *kdf_params, + struct pbe_enc_params *enc_params, gnutls_datum_t * key); + +int _gnutls_pkcs_flags_to_schema(unsigned int flags); +int _gnutls_pkcs7_encrypt_data(schema_id schema, + const gnutls_datum_t * data, + const char *password, gnutls_datum_t * enc); + +int +_gnutls_pkcs7_data_enc_info(const gnutls_datum_t * data, const struct pkcs_cipher_schema_st **p, + struct pbkdf2_params *kdf_params, char **oid); + +#endif diff --git a/lib/x509/privkey_pkcs8.c b/lib/x509/privkey_pkcs8.c index 1d8814cf53..bebc82afc4 100644 --- a/lib/x509/privkey_pkcs8.c +++ b/lib/x509/privkey_pkcs8.c @@ -31,6 +31,7 @@ #include <x509.h> #include <x509_b64.h> #include "x509_int.h" +#include "pkcs7_int.h" #include <algorithms.h> #include <num.h> #include <random.h> @@ -41,55 +42,12 @@ static int _decode_pkcs8_ecc_key(ASN1_TYPE pkcs8_asn, gnutls_x509_privkey_t pkey); static int pkcs8_key_info(const gnutls_datum_t * raw_key, - const struct pbes2_schema_st **p, + const struct pkcs_cipher_schema_st **p, struct pbkdf2_params *kdf_params, char **oid); -#define PBES1_DES_MD5_OID "1.2.840.113549.1.5.3" - -#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" -#define AES_128_CBC_OID "2.16.840.1.101.3.4.1.2" -#define AES_192_CBC_OID "2.16.840.1.101.3.4.1.22" -#define AES_256_CBC_OID "2.16.840.1.101.3.4.1.42" -#define DES_CBC_OID "1.3.14.3.2.7" - -/* oid_pbeWithSHAAnd3_KeyTripleDES_CBC */ -#define PKCS12_PBE_3DES_SHA1_OID "1.2.840.113549.1.12.1.3" -#define PKCS12_PBE_ARCFOUR_SHA1_OID "1.2.840.113549.1.12.1.1" -#define PKCS12_PBE_RC2_40_SHA1_OID "1.2.840.113549.1.12.1.6" - - -static int generate_key(schema_id schema, const char *password, - struct pbkdf2_params *kdf_params, - struct pbe_enc_params *enc_params, - gnutls_datum_t * key); -static int read_pbkdf2_params(ASN1_TYPE pbes2_asn, - const gnutls_datum_t * der, - struct pbkdf2_params *params); -static int read_pbe_enc_params(ASN1_TYPE pbes2_asn, - const gnutls_datum_t * 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_t * decrypted_data); static int decode_private_key_info(const gnutls_datum_t * der, gnutls_x509_privkey_t pkey); -static int write_schema_params(schema_id schema, ASN1_TYPE pkcs8_asn, - const char *where, - const struct pbkdf2_params *kdf_params, - const struct pbe_enc_params *enc_params); -static int encrypt_data(const gnutls_datum_t * plain, - const struct pbe_enc_params *enc_params, - gnutls_datum_t * key, gnutls_datum_t * encrypted); - -static int read_pkcs12_kdf_params(ASN1_TYPE pbes2_asn, - struct pbkdf2_params *params); -static int write_pkcs12_kdf_params(ASN1_TYPE pbes2_asn, - const struct pbkdf2_params *params); #define PEM_PKCS8 "ENCRYPTED PRIVATE KEY" #define PEM_UNENCRYPTED_PKCS8 "PRIVATE KEY" @@ -294,213 +252,6 @@ encode_to_private_key_info(gnutls_x509_privkey_t pkey, } -static const struct pbes2_schema_st avail_pbes2_schemas[] = -{ - { - .schema = PBES1_DES_MD5, - .name = "PBES1-DES-CBC-MD5", - .flag = GNUTLS_PKCS_PBES1_DES_MD5, - .cipher = GNUTLS_CIPHER_DES_CBC, - .pbes2 = 0, - .cipher_oid = PBES1_DES_MD5_OID, - .write_oid = PBES1_DES_MD5_OID, - .desc = NULL, - .decrypt_only = 1 - }, - { - .schema = PBES2_3DES, - .name = "PBES2-3DES-CBC", - .flag = GNUTLS_PKCS_PBES2_3DES, - .cipher = GNUTLS_CIPHER_3DES_CBC, - .pbes2 = 1, - .cipher_oid = DES_EDE3_CBC_OID, - .write_oid = PBES2_OID, - .desc = "PKIX1.pkcs-5-des-EDE3-CBC-params", - .decrypt_only = 0 - }, - { - .schema = PBES2_DES, - .name = "PBES2-DES-CBC", - .flag = GNUTLS_PKCS_PBES2_DES, - .cipher = GNUTLS_CIPHER_DES_CBC, - .pbes2 = 1, - .cipher_oid = DES_CBC_OID, - .write_oid = PBES2_OID, - .desc = "PKIX1.pkcs-5-des-CBC-params", - .decrypt_only = 0 - }, - { - .schema = PBES2_AES_128, - .name = "PBES2-AES128-CBC", - .flag = GNUTLS_PKCS_PBES2_AES_128, - .cipher = GNUTLS_CIPHER_AES_128_CBC, - .pbes2 = 1, - .cipher_oid = AES_128_CBC_OID, - .write_oid = PBES2_OID, - .desc = "PKIX1.pkcs-5-aes128-CBC-params", - .decrypt_only = 0 - }, - { - .schema = PBES2_AES_192, - .name = "PBES2-AES192-CBC", - .flag = GNUTLS_PKCS_PBES2_AES_192, - .cipher = GNUTLS_CIPHER_AES_192_CBC, - .pbes2 = 1, - .cipher_oid = AES_192_CBC_OID, - .write_oid = PBES2_OID, - .desc = "PKIX1.pkcs-5-aes192-CBC-params", - .decrypt_only = 0 - }, - { - .schema = PBES2_AES_256, - .name = "PBES2-AES256-CBC", - .flag = GNUTLS_PKCS_PBES2_AES_256, - .cipher = GNUTLS_CIPHER_AES_256_CBC, - .pbes2 = 1, - .cipher_oid = AES_256_CBC_OID, - .write_oid = PBES2_OID, - .desc = "PKIX1.pkcs-5-aes256-CBC-params", - .decrypt_only = 0 - }, - { - .schema = PKCS12_ARCFOUR_SHA1, - .name = "PKCS12-ARCFOUR-SHA1", - .flag = GNUTLS_PKCS_PKCS12_ARCFOUR, - .cipher = GNUTLS_CIPHER_ARCFOUR, - .pbes2 = 0, - .cipher_oid = PKCS12_PBE_ARCFOUR_SHA1_OID, - .write_oid = PKCS12_PBE_ARCFOUR_SHA1_OID, - .desc = NULL, - .decrypt_only = 0 - }, - { - .schema = PKCS12_RC2_40_SHA1, - .name = "PKCS12-RC2-40-SHA1", - .flag = GNUTLS_PKCS_PKCS12_RC2_40, - .cipher = GNUTLS_CIPHER_RC2_40_CBC, - .pbes2 = 0, - .cipher_oid = PKCS12_PBE_RC2_40_SHA1_OID, - .write_oid = PKCS12_PBE_RC2_40_SHA1_OID, - .desc = NULL, - .decrypt_only = 0 - }, - { - .schema = PKCS12_3DES_SHA1, - .name = "PKCS12-3DES-SHA1", - .flag = GNUTLS_PKCS_PKCS12_3DES, - .cipher = GNUTLS_CIPHER_3DES_CBC, - .pbes2 = 0, - .cipher_oid = PKCS12_PBE_3DES_SHA1_OID, - .write_oid = PKCS12_PBE_3DES_SHA1_OID, - .desc = NULL, - .decrypt_only = 0 - }, - {0, 0, 0, 0, 0} -}; - -#define PBES2_SCHEMA_LOOP(b) { \ - const struct pbes2_schema_st * _p; \ - for (_p=avail_pbes2_schemas;_p->schema != 0;_p++) { b; } \ - } - -#define PBES2_SCHEMA_FIND_FROM_FLAGS(fl, what) \ - PBES2_SCHEMA_LOOP( if (_p->flag == GNUTLS_PKCS_CIPHER_MASK(fl)) { what; } ) - -int _gnutls_pkcs_flags_to_schema(unsigned int flags) -{ - PBES2_SCHEMA_FIND_FROM_FLAGS(flags, return _p->schema;); - - gnutls_assert(); - _gnutls_debug_log - ("Selecting default encryption PKCS12_3DES_SHA1 (flags: %u).\n", - flags); - return PKCS12_3DES_SHA1; -} - -/** - * gnutls_pkcs_schema_get_name: - * @schema: Holds the PKCS #12 or PBES2 schema (%gnutls_pkcs_encrypt_flags_t) - * - * This function will return a human readable description of the - * PKCS12 or PBES2 schema. - * - * Returns: a constrant string or %NULL on error. - * - * Since: 3.4.0 - */ -const char *gnutls_pkcs_schema_get_name(unsigned int schema) -{ - PBES2_SCHEMA_FIND_FROM_FLAGS(schema, return _p->name;); - return NULL; -} - - -/** - * gnutls_pkcs_schema_get_oid: - * @schema: Holds the PKCS #12 or PBES2 schema (%gnutls_pkcs_encrypt_flags_t) - * - * This function will return the object identifier of the - * PKCS12 or PBES2 schema. - * - * Returns: a constrant string or %NULL on error. - * - * Since: 3.4.0 - */ -const char *gnutls_pkcs_schema_get_oid(unsigned int schema) -{ - PBES2_SCHEMA_FIND_FROM_FLAGS(schema, return _p->cipher_oid;); - return NULL; -} - -static const struct pbes2_schema_st *cipher_to_pbes2_schema(unsigned cipher) -{ - PBES2_SCHEMA_LOOP( - if (_p->cipher == cipher && _p->pbes2 != 0) { - return _p; - }); - - gnutls_assert(); - return NULL; -} - -static int check_pbes2_schema(const char *oid) -{ - if (strcmp(oid, PBES2_OID) == 0) - return PBES2_GENERIC; /* PBES2 ciphers are under an umbrella OID */ - - PBES2_SCHEMA_LOOP(if (_p->pbes2 == 0 && strcmp(oid, _p->write_oid) == 0) {return _p->schema;}); - _gnutls_debug_log - ("PKCS #12 encryption schema OID '%s' is unsupported.\n", oid); - - return GNUTLS_E_UNKNOWN_CIPHER_TYPE; -} - -static const struct pbes2_schema_st *pbes2_schema_get(schema_id schema) -{ - PBES2_SCHEMA_LOOP(if (schema == _p->schema) return _p;); - - gnutls_assert(); - return NULL; -} - -/* Converts an OID to a gnutls cipher type. - */ -static int -pbes2_cipher_oid_to_algo(const char *oid, gnutls_cipher_algorithm_t *algo) -{ - - *algo = 0; - PBES2_SCHEMA_LOOP(if (_p->pbes2 != 0 && strcmp(_p->cipher_oid, oid) == 0) { - *algo = _p->cipher; - return 0; - } - ); - - _gnutls_debug_log("PKCS #8 encryption OID '%s' is unsupported.\n", - oid); - return GNUTLS_E_UNKNOWN_CIPHER_TYPE; -} - /* Converts a PKCS #8 private key info to * a PKCS #8 EncryptedPrivateKeyInfo. */ @@ -514,9 +265,9 @@ encode_to_pkcs8_key(schema_id schema, const gnutls_datum_t * der_key, ASN1_TYPE pkcs8_asn = ASN1_TYPE_EMPTY; struct pbkdf2_params kdf_params; struct pbe_enc_params enc_params; - const struct pbes2_schema_st *s; + const struct pkcs_cipher_schema_st *s; - s = pbes2_schema_get(schema); + s = _gnutls_pkcs_schema_get(schema); if (s == NULL || s->decrypt_only) { return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); } @@ -545,14 +296,14 @@ encode_to_pkcs8_key(schema_id schema, const gnutls_datum_t * der_key, */ result = - generate_key(schema, password, &kdf_params, &enc_params, &key); + _gnutls_pkcs_generate_key(schema, password, &kdf_params, &enc_params, &key); if (result < 0) { gnutls_assert(); goto error; } result = - write_schema_params(schema, pkcs8_asn, + _gnutls_pkcs_write_schema_params(schema, pkcs8_asn, "encryptionAlgorithm.parameters", &kdf_params, &enc_params); if (result < 0) { @@ -563,7 +314,7 @@ encode_to_pkcs8_key(schema_id schema, const gnutls_datum_t * der_key, /* Parameters have been encoded. Now * encrypt the Data. */ - result = encrypt_data(der_key, &enc_params, &key, &tmp); + result = _gnutls_pkcs_raw_encrypt_data(der_key, &enc_params, &key, &tmp); if (result < 0) { gnutls_assert(); goto error; @@ -717,7 +468,7 @@ gnutls_pkcs8_info(const gnutls_datum_t * data, gnutls_x509_crt_fmt_t format, { int ret = 0, need_free = 0; gnutls_datum_t _data; - const struct pbes2_schema_st *p = NULL; + const struct pkcs_cipher_schema_st *p = NULL; struct pbkdf2_params kdf; if (oid) @@ -878,138 +629,6 @@ gnutls_x509_privkey_export2_pkcs8(gnutls_x509_privkey_t key, } -/* Read the parameters cipher, IV, salt etc using the given - * schema ID. Initially the schema ID should have PBES2_GENERIC, for - * PBES2 schemas, and will be updated by this function for details. - */ -static int -read_pkcs_schema_params(schema_id * schema, const char *password, - const uint8_t * 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_t tmp; - const struct pbes2_schema_st *p; - - if (*schema == PBES2_GENERIC) { - /* 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_strict_der_decode(&pbes2_asn, data, data_size, NULL); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - result = _gnutls_asn2err(result); - goto error; - } - - tmp.data = (uint8_t *) data; - tmp.size = data_size; - - 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_structure2(&pbes2_asn, ASN1_DELETE_FLAG_ZEROIZE); - - p = cipher_to_pbes2_schema(enc_params->cipher); - if (p == NULL) { - result = GNUTLS_E_INVALID_REQUEST; - gnutls_assert(); - goto error; - } - - *schema = p->schema; - return 0; - } else if (*schema == PBES1_DES_MD5) { - return _gnutls_read_pbkdf1_params(data, data_size, kdf_params, enc_params); - } else { /* PKCS #12 schema */ - memset(enc_params, 0, sizeof(*enc_params)); - - p = pbes2_schema_get(*schema); - if (p == NULL) { - gnutls_assert(); - result = GNUTLS_E_UNKNOWN_CIPHER_TYPE; - goto error; - } - enc_params->cipher = p->cipher; - enc_params->iv_size = gnutls_cipher_get_iv_size(p->cipher); - - 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_strict_der_decode(&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(); - goto error; - } - - if (enc_params->iv_size) { - result = - _gnutls_pkcs12_string_to_key(mac_to_entry(GNUTLS_MAC_SHA1), - 2 /*IV*/, - kdf_params->salt, - kdf_params-> - salt_size, - kdf_params-> - iter_count, - password, - enc_params-> - iv_size, - enc_params->iv); - if (result < 0) { - gnutls_assert(); - goto error; - } - - } - - asn1_delete_structure(&pbes2_asn); - - return 0; - } /* switch */ - - error: - asn1_delete_structure(&pbes2_asn); - return result; -} /* We've gotten this far. In the real world it's almost certain * that we're dealing with a good file, but wrong password. @@ -1037,7 +656,6 @@ static int pkcs8_key_decrypt(const gnutls_datum_t * raw_key, int result, len; char enc_oid[MAX_OID_SIZE]; gnutls_datum_t tmp; - ASN1_TYPE pbes2_asn = ASN1_TYPE_EMPTY; int params_start, params_end, params_len; struct pbkdf2_params kdf_params; struct pbe_enc_params enc_params; @@ -1054,7 +672,7 @@ static int pkcs8_key_decrypt(const gnutls_datum_t * raw_key, goto error; } - if ((result = check_pbes2_schema(enc_oid)) < 0) { + if ((result = _gnutls_check_pkcs_cipher_schema(enc_oid)) < 0) { gnutls_assert(); goto error; } @@ -1076,7 +694,7 @@ static int pkcs8_key_decrypt(const gnutls_datum_t * raw_key, params_len = params_end - params_start + 1; result = - read_pkcs_schema_params(&schema, password, + _gnutls_read_pkcs_schema_params(&schema, password, &raw_key->data[params_start], params_len, &kdf_params, &enc_params); @@ -1089,7 +707,7 @@ static int pkcs8_key_decrypt(const gnutls_datum_t * raw_key, * decrypt the EncryptedData. */ result = - decrypt_data(schema, pkcs8_asn, "encryptedData", password, + _gnutls_pkcs_raw_decrypt_data(schema, pkcs8_asn, "encryptedData", password, &kdf_params, &enc_params, &tmp); if (result < 0) { gnutls_assert(); @@ -1108,13 +726,12 @@ static int pkcs8_key_decrypt(const gnutls_datum_t * raw_key, return 0; error: - asn1_delete_structure(&pbes2_asn); return result; } static int pkcs8_key_info(const gnutls_datum_t * raw_key, - const struct pbes2_schema_st **p, + const struct pkcs_cipher_schema_st **p, struct pbkdf2_params *kdf_params, char **oid) { @@ -1159,7 +776,7 @@ int pkcs8_key_info(const gnutls_datum_t * raw_key, *oid = gnutls_strdup(enc_oid); } - if ((result = check_pbes2_schema(enc_oid)) < 0) { + if ((result = _gnutls_check_pkcs_cipher_schema(enc_oid)) < 0) { gnutls_assert(); goto error; } @@ -1181,7 +798,7 @@ int pkcs8_key_info(const gnutls_datum_t * raw_key, params_len = params_end - params_start + 1; result = - read_pkcs_schema_params(&schema, NULL, + _gnutls_read_pkcs_schema_params(&schema, NULL, &raw_key->data[params_start], params_len, kdf_params, &enc_params); @@ -1190,7 +807,7 @@ int pkcs8_key_info(const gnutls_datum_t * raw_key, goto error; } - *p = pbes2_schema_get(schema); + *p = _gnutls_pkcs_schema_get(schema); if (*p == NULL) { gnutls_assert(); result = GNUTLS_E_UNKNOWN_CIPHER_TYPE; @@ -1585,1166 +1202,3 @@ gnutls_x509_privkey_import_pkcs8(gnutls_x509_privkey_t key, return result; } -/* Reads the PBKDF2 parameters. - */ -static int -read_pbkdf2_params(ASN1_TYPE pbes2_asn, - const gnutls_datum_t * der, - struct pbkdf2_params *params) -{ - int params_start, params_end; - int params_len, len, result; - ASN1_TYPE pbkdf2_asn = ASN1_TYPE_EMPTY; - char oid[MAX_OID_SIZE]; - - memset(params, 0, sizeof(*params)); - - params->mac = GNUTLS_MAC_SHA1; - - /* Check the key derivation algorithm - */ - len = sizeof(oid); - 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_assert(); - _gnutls_debug_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); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - return _gnutls_asn2err(result); - } - 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-PBKDF2-params", - &pbkdf2_asn)) != ASN1_SUCCESS) { - gnutls_assert(); - return _gnutls_asn2err(result); - } - - result = - _asn1_strict_der_decode(&pbkdf2_asn, &der->data[params_start], - params_len, NULL); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - result = _gnutls_asn2err(result); - goto error; - } - - /* read the salt */ - params->salt_size = sizeof(params->salt); - 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); - - /* read the iteration count - */ - result = - _gnutls_x509_read_uint(pbkdf2_asn, "iterationCount", - ¶ms->iter_count); - if (result < 0) { - gnutls_assert(); - goto error; - } - _gnutls_hard_log("iterationCount: %d\n", params->iter_count); - - /* read the keylength, if it is set. - */ - result = - _gnutls_x509_read_uint(pbkdf2_asn, "keyLength", - ¶ms->key_size); - if (result < 0) { - params->key_size = 0; - } - _gnutls_hard_log("keyLength: %d\n", params->key_size); - - len = sizeof(oid); - result = - asn1_read_value(pbkdf2_asn, "prf.algorithm", - oid, &len); - if (result != ASN1_SUCCESS) { - /* use the default MAC */ - result = 0; - goto error; - } - - params->mac = gnutls_oid_to_mac(oid); - if (params->mac == GNUTLS_MAC_UNKNOWN) { - gnutls_assert(); - _gnutls_debug_log("Unsupported hash algorithm: %s\n", oid); - result = GNUTLS_E_UNKNOWN_HASH_ALGORITHM; - goto error; - } - - result = 0; - - error: - asn1_delete_structure(&pbkdf2_asn); - return result; - -} - -/* Reads the PBE parameters from PKCS-12 schemas (*&#%*&#% RSA). - */ -static int -read_pkcs12_kdf_params(ASN1_TYPE pbes2_asn, struct pbkdf2_params *params) -{ - int result; - - 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 - */ - result = - _gnutls_x509_read_uint(pbes2_asn, "iterations", - ¶ms->iter_count); - if (result < 0) { - gnutls_assert(); - goto error; - } - _gnutls_hard_log("iterationCount: %d\n", params->iter_count); - - params->key_size = 0; - - return 0; - - error: - return result; - -} - -/* Writes the PBE parameters for PKCS-12 schemas. - */ -static int -write_pkcs12_kdf_params(ASN1_TYPE pbes2_asn, - const struct pbkdf2_params *kdf_params) -{ - int result; - - /* write the salt - */ - result = - asn1_write_value(pbes2_asn, "salt", - kdf_params->salt, kdf_params->salt_size); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - result = _gnutls_asn2err(result); - goto error; - } - _gnutls_hard_log("salt.size: %d\n", kdf_params->salt_size); - - /* write the iteration count - */ - result = - _gnutls_x509_write_uint32(pbes2_asn, "iterations", - kdf_params->iter_count); - if (result < 0) { - gnutls_assert(); - goto error; - } - _gnutls_hard_log("iterationCount: %d\n", kdf_params->iter_count); - - return 0; - - error: - return result; - -} - - -static int -read_pbe_enc_params(ASN1_TYPE pbes2_asn, - const gnutls_datum_t * 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[MAX_OID_SIZE]; - const struct pbes2_schema_st *p; - - memset(params, 0, sizeof(*params)); - - /* Check the encryption algorithm - */ - len = sizeof(oid); - result = - asn1_read_value(pbes2_asn, "encryptionScheme.algorithm", oid, - &len); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - return _gnutls_asn2err(result); - } - _gnutls_hard_log("encryptionScheme.algorithm: %s\n", oid); - - if ((result = pbes2_cipher_oid_to_algo(oid, ¶ms->cipher)) < 0) { - gnutls_assert(); - return result; - } - - 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); - } - params_len = params_end - params_start + 1; - - /* Now check the encryption parameters. - */ - p = cipher_to_pbes2_schema(params->cipher); - if (p == NULL) { - gnutls_assert(); - return GNUTLS_E_INVALID_REQUEST; - } - - if ((result = - asn1_create_element(_gnutls_get_pkix(), - p->desc, &pbe_asn)) != ASN1_SUCCESS) { - gnutls_assert(); - return _gnutls_asn2err(result); - } - - result = - _asn1_strict_der_decode(&pbe_asn, &der->data[params_start], - params_len, NULL); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - result = _gnutls_asn2err(result); - goto error; - } - - /* read the IV */ - params->iv_size = sizeof(params->iv); - 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); - - result = 0; - - error: - asn1_delete_structure(&pbe_asn); - return result; -} - -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_t *decrypted_data) -{ - int result; - gnutls_datum_t enc = {NULL, 0}; - uint8_t *key = NULL; - gnutls_datum_t dkey, d_iv; - cipher_hd_st ch; - int ch_init = 0; - int key_size; - unsigned int pass_len = 0; - const struct pbes2_schema_st *p; - - if (password) - pass_len = strlen(password); - - result = _gnutls_x509_read_value(pkcs8_asn, root, &enc); - if (result < 0) { - gnutls_assert(); - return _gnutls_asn2err(result); - } - - if (schema == PBES1_DES_MD5) { - return _gnutls_decrypt_pbes1_des_md5_data(password, pass_len, - kdf_params, enc_params, - &enc, decrypted_data); - } - - if (kdf_params->key_size == 0) { - key_size = gnutls_cipher_get_key_size(enc_params->cipher); - } else - key_size = kdf_params->key_size; - - key = gnutls_malloc(key_size); - if (key == NULL) { - gnutls_assert(); - result = GNUTLS_E_MEMORY_ERROR; - goto error; - } - - /* generate the key - */ - p = pbes2_schema_get(schema); - if (p != NULL && p->pbes2 != 0) { /* PBES2 */ - if (kdf_params->mac == GNUTLS_MAC_SHA1) - pbkdf2_hmac_sha1(pass_len, (uint8_t*)password, - kdf_params->iter_count, - kdf_params->salt_size, kdf_params->salt, - key_size, key); - else if (kdf_params->mac == GNUTLS_MAC_SHA256) - pbkdf2_hmac_sha256(pass_len, (uint8_t*)password, - kdf_params->iter_count, - kdf_params->salt_size, kdf_params->salt, - key_size, key); - else return gnutls_assert_val(GNUTLS_E_UNKNOWN_HASH_ALGORITHM); - } else if (p != NULL) { /* PKCS 12 schema */ - result = - _gnutls_pkcs12_string_to_key(mac_to_entry(GNUTLS_MAC_SHA1), - 1 /*KEY*/, - kdf_params->salt, - kdf_params->salt_size, - kdf_params->iter_count, - password, key_size, key); - - if (result < 0) { - gnutls_assert(); - goto error; - } - } else { - gnutls_assert(); - result = GNUTLS_E_UNKNOWN_CIPHER_TYPE; - goto error; - } - - /* do the decryption. - */ - dkey.data = key; - dkey.size = key_size; - - d_iv.data = (uint8_t *) enc_params->iv; - d_iv.size = enc_params->iv_size; - result = - _gnutls_cipher_init(&ch, cipher_to_entry(enc_params->cipher), - &dkey, &d_iv, 0); - - gnutls_free(key); - key = NULL; - - if (result < 0) { - gnutls_assert(); - goto error; - } - - ch_init = 1; - - result = _gnutls_cipher_decrypt(&ch, enc.data, enc.size); - if (result < 0) { - gnutls_assert(); - goto error; - } - - decrypted_data->data = enc.data; - - if (gnutls_cipher_get_block_size(enc_params->cipher) != 1) - decrypted_data->size = enc.size - enc.data[enc.size - 1]; - else - decrypted_data->size = enc.size; - - _gnutls_cipher_deinit(&ch); - - return 0; - - error: - gnutls_free(enc.data); - gnutls_free(key); - if (ch_init != 0) - _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) -{ - int result; - ASN1_TYPE pbkdf2_asn = ASN1_TYPE_EMPTY; - uint8_t tmp[MAX_OID_SIZE]; - - /* Write the key derivation algorithm - */ - 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) { - gnutls_assert(); - return _gnutls_asn2err(result); - } - - 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); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - result = _gnutls_asn2err(result); - goto error; - } - _gnutls_hard_log("salt.specified.size: %d\n", - kdf_params->salt_size); - - /* write the iteration count - */ - _gnutls_write_uint32(kdf_params->iter_count, tmp); - - 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); - - /* write the keylength, if it is set. - */ - 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); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - result = _gnutls_asn2err(result); - goto error; - } - - /* 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", - 0); - if (result < 0) { - gnutls_assert(); - goto error; - } - - return 0; - - error: - asn1_delete_structure(&pbkdf2_asn); - return result; - -} - - -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; - const struct pbes2_schema_st *p; - - /* Write the encryption algorithm - */ - p = cipher_to_pbes2_schema(params->cipher); - if (p == NULL || p->pbes2 == 0) { - gnutls_assert(); - return GNUTLS_E_INVALID_REQUEST; - } - - result = - asn1_write_value(pbes2_asn, "encryptionScheme.algorithm", p->cipher_oid, - 1); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - goto error; - } - _gnutls_hard_log("encryptionScheme.algorithm: %s\n", p->cipher_oid); - - /* Now check the encryption parameters. - */ - if ((result = - asn1_create_element(_gnutls_get_pkix(), - p->desc, &pbe_asn)) != ASN1_SUCCESS) { - gnutls_assert(); - return _gnutls_asn2err(result); - } - - /* read the salt */ - 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); - - /* 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", - 0); - if (result < 0) { - gnutls_assert(); - goto error; - } - - return 0; - - error: - asn1_delete_structure(&pbe_asn); - return result; - -} - -/* Generates a key and also stores the key parameters. - */ -static int -generate_key(schema_id schema, - const char *password, - struct pbkdf2_params *kdf_params, - struct pbe_enc_params *enc_params, gnutls_datum_t * key) -{ - unsigned char rnd[2]; - unsigned int pass_len = 0; - int ret; - const struct pbes2_schema_st *p; - - if (password) - pass_len = strlen(password); - - ret = _gnutls_rnd(GNUTLS_RND_RANDOM, rnd, 2); - if (ret < 0) { - gnutls_assert(); - return ret; - } - - /* generate salt */ - kdf_params->salt_size = - MIN(sizeof(kdf_params->salt), (unsigned) (12 + (rnd[1] % 10))); - - p = pbes2_schema_get(schema); - if (p != NULL && p->pbes2 != 0) { /* PBES2 */ - enc_params->cipher = p->cipher; - } else if (p != NULL) { - /* non PBES2 algorithms */ - enc_params->cipher = p->cipher; - kdf_params->salt_size = 8; - } else { - gnutls_assert(); - return GNUTLS_E_INVALID_REQUEST; - } - - ret = _gnutls_rnd(GNUTLS_RND_RANDOM, kdf_params->salt, - kdf_params->salt_size); - if (ret < 0) { - gnutls_assert(); - return GNUTLS_E_RANDOM_FAILED; - } - - kdf_params->iter_count = 5*1024 + rnd[0]; - key->size = kdf_params->key_size = - gnutls_cipher_get_key_size(enc_params->cipher); - - enc_params->iv_size = - gnutls_cipher_get_iv_size(enc_params->cipher); - key->data = gnutls_malloc(key->size); - if (key->data == NULL) { - gnutls_assert(); - return GNUTLS_E_MEMORY_ERROR; - } - - /* now generate the key. - */ - - if (p->pbes2 != 0) { - pbkdf2_hmac_sha1(pass_len, (uint8_t*)password, - kdf_params->iter_count, - kdf_params->salt_size, kdf_params->salt, - kdf_params->key_size, key->data); - - if (enc_params->iv_size) { - ret = _gnutls_rnd(GNUTLS_RND_NONCE, - enc_params->iv, - enc_params->iv_size); - if (ret < 0) { - gnutls_assert(); - return ret; - } - } - } else { /* PKCS 12 schema */ - ret = - _gnutls_pkcs12_string_to_key(mac_to_entry(GNUTLS_MAC_SHA1), - 1 /*KEY*/, - kdf_params->salt, - kdf_params->salt_size, - kdf_params->iter_count, - password, - kdf_params->key_size, - key->data); - if (ret < 0) { - gnutls_assert(); - return ret; - } - - /* Now generate the IV - */ - if (enc_params->iv_size) { - ret = - _gnutls_pkcs12_string_to_key(mac_to_entry(GNUTLS_MAC_SHA1), - 2 /*IV*/, - kdf_params->salt, - kdf_params-> - salt_size, - kdf_params-> - iter_count, - password, - enc_params-> - iv_size, - enc_params->iv); - if (ret < 0) { - gnutls_assert(); - return ret; - } - } - } - - - return 0; -} - - -/* Encodes the parameters to be written in the encryptionAlgorithm.parameters - * part. - */ -static int -write_schema_params(schema_id schema, ASN1_TYPE pkcs8_asn, - const char *where, - const struct pbkdf2_params *kdf_params, - const struct pbe_enc_params *enc_params) -{ - int result; - ASN1_TYPE pbes2_asn = ASN1_TYPE_EMPTY; - const struct pbes2_schema_st *p; - - p = pbes2_schema_get(schema); - - if (p != NULL && p->pbes2 != 0) { /* PBES2 */ - if ((result = - asn1_create_element(_gnutls_get_pkix(), - "PKIX1.pkcs-5-PBES2-params", - &pbes2_asn)) != ASN1_SUCCESS) { - gnutls_assert(); - return _gnutls_asn2err(result); - } - - result = write_pbkdf2_params(pbes2_asn, kdf_params); - if (result < 0) { - gnutls_assert(); - goto error; - } - - 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, where, - 0); - if (result < 0) { - gnutls_assert(); - goto error; - } - - asn1_delete_structure(&pbes2_asn); - - } else if (p != NULL) { /* PKCS #12 */ - - if ((result = - asn1_create_element(_gnutls_get_pkix(), - "PKIX1.pkcs-12-PbeParams", - &pbes2_asn)) != ASN1_SUCCESS) { - gnutls_assert(); - result = _gnutls_asn2err(result); - goto error; - } - - result = write_pkcs12_kdf_params(pbes2_asn, kdf_params); - if (result < 0) { - gnutls_assert(); - goto error; - } - - result = _gnutls_x509_der_encode_and_copy(pbes2_asn, "", - pkcs8_asn, where, - 0); - if (result < 0) { - gnutls_assert(); - goto error; - } - - asn1_delete_structure(&pbes2_asn); - } - - return 0; - - error: - asn1_delete_structure(&pbes2_asn); - return result; - -} - -static int -encrypt_data(const gnutls_datum_t * plain, - const struct pbe_enc_params *enc_params, - gnutls_datum_t * key, gnutls_datum_t * encrypted) -{ - int result; - int data_size; - uint8_t *data = NULL; - gnutls_datum_t d_iv; - cipher_hd_st ch; - int ch_init = 0; - uint8_t pad, pad_size; - - pad_size = gnutls_cipher_get_block_size(enc_params->cipher); - - if (pad_size == 1) /* stream */ - pad_size = 0; - - data = gnutls_malloc(plain->size + pad_size); - if (data == NULL) { - gnutls_assert(); - return GNUTLS_E_MEMORY_ERROR; - } - - memcpy(data, plain->data, plain->size); - - if (pad_size > 0) { - pad = pad_size - (plain->size % pad_size); - if (pad == 0) - pad = pad_size; - memset(&data[plain->size], pad, pad); - } else - pad = 0; - - data_size = plain->size + pad; - - d_iv.data = (uint8_t *) enc_params->iv; - d_iv.size = enc_params->iv_size; - result = - _gnutls_cipher_init(&ch, cipher_to_entry(enc_params->cipher), - key, &d_iv, 1); - - if (result < 0) { - gnutls_assert(); - goto error; - } - - ch_init = 1; - - result = _gnutls_cipher_encrypt(&ch, data, data_size); - if (result < 0) { - gnutls_assert(); - goto error; - } - - encrypted->data = data; - encrypted->size = data_size; - - _gnutls_cipher_deinit(&ch); - - return 0; - - error: - gnutls_free(data); - if (ch_init != 0) - _gnutls_cipher_deinit(&ch); - return result; -} - -/* Decrypts a PKCS #7 encryptedData. The output is allocated - * and stored in dec. - */ -int -_gnutls_pkcs7_decrypt_data(const gnutls_datum_t * data, - const char *password, gnutls_datum_t * dec) -{ - int result, len; - char enc_oid[MAX_OID_SIZE]; - gnutls_datum_t 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; - } - - if ((result = check_pbes2_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 < 0) { - gnutls_assert(); - 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_structure2(&pkcs7_asn, ASN1_DELETE_FLAG_ZEROIZE); - - *dec = tmp; - - return 0; - - error: - asn1_delete_structure(&pbes2_asn); - asn1_delete_structure2(&pkcs7_asn, ASN1_DELETE_FLAG_ZEROIZE); - return result; -} - -int -_gnutls_pkcs7_data_enc_info(const gnutls_datum_t * data, const struct pbes2_schema_st **p, - struct pbkdf2_params *kdf_params, char **oid) -{ - int result, len; - char enc_oid[MAX_OID_SIZE]; - ASN1_TYPE pbes2_asn = ASN1_TYPE_EMPTY, pkcs7_asn = ASN1_TYPE_EMPTY; - int params_start, params_end, params_len; - 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; - } - - if (oid) { - *oid = gnutls_strdup(enc_oid); - } - - if ((result = check_pbes2_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, NULL, - &data->data[params_start], - params_len, kdf_params, &enc_params); - if (result < ASN1_SUCCESS) { - gnutls_assert(); - result = _gnutls_asn2err(result); - goto error; - } - - *p = pbes2_schema_get(schema); - if (*p == NULL) { - gnutls_assert(); - result = GNUTLS_E_UNKNOWN_CIPHER_TYPE; - goto error; - } - - - asn1_delete_structure2(&pkcs7_asn, ASN1_DELETE_FLAG_ZEROIZE); - - return 0; - - error: - asn1_delete_structure(&pbes2_asn); - asn1_delete_structure2(&pkcs7_asn, ASN1_DELETE_FLAG_ZEROIZE); - return result; -} - -/* Encrypts to a PKCS #7 encryptedData. The output is allocated - * and stored in enc. - */ -int -_gnutls_pkcs7_encrypt_data(schema_id schema, - const gnutls_datum_t * data, - const char *password, gnutls_datum_t * enc) -{ - int result; - gnutls_datum_t key = { NULL, 0 }; - gnutls_datum_t tmp = { NULL, 0 }; - ASN1_TYPE pkcs7_asn = ASN1_TYPE_EMPTY; - struct pbkdf2_params kdf_params; - struct pbe_enc_params enc_params; - const struct pbes2_schema_st *s; - - s = pbes2_schema_get(schema); - if (s == NULL || s->decrypt_only) { - return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); - } - - 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_write_value(pkcs7_asn, - "encryptedContentInfo.contentEncryptionAlgorithm.algorithm", - s->write_oid, 1); - - if (result != ASN1_SUCCESS) { - gnutls_assert(); - result = _gnutls_asn2err(result); - goto error; - } - - /* Generate a symmetric key. - */ - - result = - generate_key(schema, password, &kdf_params, &enc_params, &key); - if (result < 0) { - gnutls_assert(); - goto error; - } - - result = write_schema_params(schema, pkcs7_asn, - "encryptedContentInfo.contentEncryptionAlgorithm.parameters", - &kdf_params, &enc_params); - if (result < 0) { - gnutls_assert(); - goto error; - } - - /* Parameters have been encoded. Now - * encrypt the Data. - */ - result = encrypt_data(data, &enc_params, &key, &tmp); - if (result < 0) { - gnutls_assert(); - goto error; - } - - /* write the encrypted data. - */ - result = - asn1_write_value(pkcs7_asn, - "encryptedContentInfo.encryptedContent", - tmp.data, tmp.size); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - result = _gnutls_asn2err(result); - goto error; - } - - _gnutls_free_datum(&tmp); - _gnutls_free_key_datum(&key); - - /* Now write the rest of the pkcs-7 stuff. - */ - - result = _gnutls_x509_write_uint32(pkcs7_asn, "version", 0); - if (result < 0) { - gnutls_assert(); - goto error; - } - - result = - asn1_write_value(pkcs7_asn, "encryptedContentInfo.contentType", - DATA_OID, 1); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - result = _gnutls_asn2err(result); - goto error; - } - - result = asn1_write_value(pkcs7_asn, "unprotectedAttrs", NULL, 0); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - result = _gnutls_asn2err(result); - goto error; - } - - /* Now encode and copy the DER stuff. - */ - result = _gnutls_x509_der_encode(pkcs7_asn, "", enc, 0); - - asn1_delete_structure2(&pkcs7_asn, ASN1_DELETE_FLAG_ZEROIZE); - - if (result < 0) { - gnutls_assert(); - goto error; - } - - - error: - _gnutls_free_key_datum(&key); - _gnutls_free_datum(&tmp); - asn1_delete_structure2(&pkcs7_asn, ASN1_DELETE_FLAG_ZEROIZE); - return result; -} diff --git a/lib/x509/privkey_pkcs8_pbes1.c b/lib/x509/privkey_pkcs8_pbes1.c index 928439653c..d621851365 100644 --- a/lib/x509/privkey_pkcs8_pbes1.c +++ b/lib/x509/privkey_pkcs8_pbes1.c @@ -29,6 +29,7 @@ #include <x509.h> #include <x509_b64.h> #include "x509_int.h" +#include "pkcs7_int.h" #include <algorithms.h> #include <nettle/md5.h> diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h index 2a8c0cd971..906ec81bae 100644 --- a/lib/x509/x509_int.h +++ b/lib/x509/x509_int.h @@ -369,11 +369,6 @@ typedef struct gnutls_pkcs12_bag_int { #define BAG_CRL "1.2.840.113549.1.12.10.1.4" #define BAG_SECRET "1.2.840.113549.1.12.10.1.5" -/* PKCS #7 - */ -#define DATA_OID "1.2.840.113549.1.7.1" -#define ENC_DATA_OID "1.2.840.113549.1.7.6" - /* Bag attributes */ #define FRIENDLY_NAME_OID "1.2.840.113549.1.9.20" @@ -386,61 +381,6 @@ _gnutls_pkcs12_string_to_key(const mac_entry_st * me, const char *pw, unsigned int req_keylen, uint8_t * keybuf); -int _gnutls_pkcs7_decrypt_data(const gnutls_datum_t * data, - const char *password, gnutls_datum_t * dec); - -typedef enum schema_id { - PBES2_GENERIC=1, /* when the algorithm is unknown, temporal use when reading only */ - PBES2_DES, /* the stuff in PKCS #5 */ - PBES2_3DES, - PBES2_AES_128, - PBES2_AES_192, - PBES2_AES_256, - PKCS12_3DES_SHA1, /* the stuff in PKCS #12 */ - PKCS12_ARCFOUR_SHA1, - PKCS12_RC2_40_SHA1, - PBES1_DES_MD5 /* openssl before 1.1.0 uses that by default */ -} schema_id; - - -struct pbes2_schema_st { - unsigned int schema; - const char *name; - unsigned int flag; - unsigned int cipher; - unsigned pbes2; - const char *cipher_oid; - const char *write_oid; - const char *desc; - unsigned decrypt_only; -}; - -struct pbe_enc_params { - gnutls_cipher_algorithm_t cipher; - uint8_t iv[MAX_CIPHER_BLOCK_SIZE]; - int iv_size; -}; - -int _gnutls_read_pbkdf1_params(const uint8_t * data, int data_size, - struct pbkdf2_params *kdf_params, - struct pbe_enc_params *enc_params); - -int -_gnutls_decrypt_pbes1_des_md5_data(const char *password, - unsigned password_len, - const struct pbkdf2_params *kdf_params, - const struct pbe_enc_params *enc_params, - gnutls_datum_t *encrypted_data, /* overwritten */ - gnutls_datum_t *decrypted_data); - -int _gnutls_pkcs_flags_to_schema(unsigned int flags); -int _gnutls_pkcs7_encrypt_data(schema_id schema, - const gnutls_datum_t * data, - const char *password, gnutls_datum_t * enc); - -int -_gnutls_pkcs7_data_enc_info(const gnutls_datum_t * data, const struct pbes2_schema_st **p, - struct pbkdf2_params *kdf_params, char **oid); int _pkcs12_decode_safe_contents(const gnutls_datum_t * content, gnutls_pkcs12_bag_t bag); |