summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2016-08-25 17:27:16 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2016-08-25 17:42:41 +0200
commit532f38cca75608b0eba13f7b3844f35b6b4c573d (patch)
tree52e80a8e450630c8fc0221b10522548350992b74
parent594833d57dc35f1d36b6708f3f3ebd68422df1b3 (diff)
downloadgnutls-532f38cca75608b0eba13f7b3844f35b6b4c573d.tar.gz
pkcs8: cleaned up PKCS#8 decoding from common code with PKCS#7
-rw-r--r--lib/x509/Makefile.am1
-rw-r--r--lib/x509/pkcs12.c1
-rw-r--r--lib/x509/pkcs12_bag.c3
-rw-r--r--lib/x509/pkcs7-crypt.c1559
-rw-r--r--lib/x509/pkcs7_int.h124
-rw-r--r--lib/x509/privkey_pkcs8.c1576
-rw-r--r--lib/x509/privkey_pkcs8_pbes1.c1
-rw-r--r--lib/x509/x509_int.h60
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",
+ &params_start, &params_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",
+ &params_start, &params_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",
+ &params_start, &params_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,
+ &params->salt_size);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto error;
+ }
+ _gnutls_hard_log("salt.specified.size: %d\n", params->salt_size);
+
+ /* read the iteration count
+ */
+ result =
+ _gnutls_x509_read_uint(pbkdf2_asn, "iterationCount",
+ &params->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",
+ &params->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,
+ &params->salt_size);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto error;
+ }
+ _gnutls_hard_log("salt.size: %d\n", params->salt_size);
+
+ /* read the iteration count
+ */
+ result =
+ _gnutls_x509_read_uint(pasn, "iterations",
+ &params->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, &params->cipher)) < 0) {
+ gnutls_assert();
+ return result;
+ }
+
+ result =
+ asn1_der_decoding_startEnd(pasn, der->data, der->size,
+ "encryptionScheme.parameters",
+ &params_start, &params_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, &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);
+
+ 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",
- &params_start, &params_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,
- &params->salt_size);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- result = _gnutls_asn2err(result);
- goto error;
- }
- _gnutls_hard_log("salt.specified.size: %d\n", params->salt_size);
-
- /* read the iteration count
- */
- result =
- _gnutls_x509_read_uint(pbkdf2_asn, "iterationCount",
- &params->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",
- &params->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,
- &params->salt_size);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- result = _gnutls_asn2err(result);
- goto error;
- }
- _gnutls_hard_log("salt.size: %d\n", params->salt_size);
-
- /* read the iteration count
- */
- result =
- _gnutls_x509_read_uint(pbes2_asn, "iterations",
- &params->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, &params->cipher)) < 0) {
- gnutls_assert();
- return result;
- }
-
- result =
- asn1_der_decoding_startEnd(pbes2_asn, der->data, der->size,
- "encryptionScheme.parameters",
- &params_start, &params_end);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- return _gnutls_asn2err(result);
- }
- 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, &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);
-
- 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",
- &params_start, &params_end);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- result = _gnutls_asn2err(result);
- goto error;
- }
- params_len = params_end - params_start + 1;
-
- result =
- read_pkcs_schema_params(&schema, password,
- &data->data[params_start],
- params_len, &kdf_params, &enc_params);
- if (result < 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",
- &params_start, &params_end);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- result = _gnutls_asn2err(result);
- goto error;
- }
- params_len = params_end - params_start + 1;
-
- result =
- read_pkcs_schema_params(&schema, 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);