From: Denis Kenzior <denkenz@gmail.com>
To: ell@lists.01.org
Subject: Re: [PATCH 07/10] cipher: Add l_cipher_from_pkcs5_id
Date: Fri, 11 Aug 2017 11:55:18 -0500 [thread overview]
Message-ID: <83284742-6c95-af79-80cc-12e3bec8a77f@gmail.com> (raw)
In-Reply-To: <20170810231016.29445-7-andrew.zaborowski@intel.com>
[-- Attachment #1: Type: text/plain, Size: 8949 bytes --]
Hi Andrew,
On 08/10/2017 06:10 PM, Andrew Zaborowski wrote:
> Add a utility to parse all of the PKCS#5 DER-encoded encryption scheme
> information, use the right PBKDF function to calculate the key,
> create the appropriate l_cipher object type (if we support that PKCS#5
> cipher type) with that key and set the IV on the l_cipher object.
>
> We don't support any of the RC2 or RC5 based encryption schemes or
> those that use MD2, SHA512-224 or SHA512-256 for the hash, because
> there's no kernel support for those algorithms. OpenSSL can create
> RSA private keys encrypted with some of these algorithms but MD5+DES
> and DES3-EDE are the default and the popular algorithms. OpenSSL also
> supports camellia ciphers in those scenarios which we could add.
>
> Note that the caller still needs to add or remove the padding from the
> data encrypted or decrypted with the l_cipher object so technically this
> doesn't implement 100% of PKCS#5 PBES1 or PBES2.
> Thise code may be better moved to a separate file from cipher.c. If we
> do that then it could be wrapped in a separate object that would do the
> padding after calling the l_cipher operation, too, though the padding
> is really simple anway, may not be worth the overhead of another wrapper.
Another reason to move this is that I don't really want to expose it in
l_cipher. The right way for us to enable encrypted certificates is via
the keyctl API. Until then, we should stuff this into some private
file. Can we put this into asn1-private.[ch]?
> ---
> ell/cipher.c | 290 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ell/cipher.h | 4 +
> 2 files changed, 294 insertions(+)
>
<snip>
> +static struct l_cipher *cipher_from_pkcs5_pbes2_params(
> + const uint8_t *pbes2_params,
> + size_t pbes2_params_len,
> + const char *password)
> +{
> + uint8_t tag;
> + const uint8_t *kdf_sequence, *enc_sequence, *oid, *params,
> + *salt, *iter_count_buf, *key_len_buf, *prf_sequence;
> + size_t kdf_len, enc_len, params_len, salt_len, key_len, tmp_len;
> + unsigned int i, iter_count;
> + enum l_checksum_type prf_alg = L_CHECKSUM_NONE;
> + const struct pkcs5_enc_alg_oid *enc_scheme = NULL;
> + uint8_t derived_key[64];
> + struct l_cipher *cipher;
> +
> + /* RFC8018 section A.4 */
> +
> + kdf_sequence = der_find_elem(pbes2_params, pbes2_params_len, 0,
> + &tag, &kdf_len);
> + if (!kdf_sequence || tag != ASN1_ID_SEQUENCE)
> + return NULL;
> +
> + enc_sequence = der_find_elem(pbes2_params, pbes2_params_len, 1,
> + &tag, &enc_len);
> + if (!enc_sequence || tag != ASN1_ID_SEQUENCE)
> + return NULL;
> +
> + if (der_find_elem(pbes2_params, pbes2_params_len, 2, &tag, &tmp_len))
> + return NULL;
> +
> + /* RFC8018 section A.2 */
> +
> + oid = der_find_elem(kdf_sequence, kdf_len, 0, &tag, &tmp_len);
> + if (!oid || tag != ASN1_ID_OID)
> + return NULL;
> +
> + if (!asn1_oid_eq(&pkcs5_pbkdf2_oid, tmp_len, oid))
> + return NULL;
> +
> + params = der_find_elem(kdf_sequence, kdf_len, 1, &tag, ¶ms_len);
> + if (!params || tag != ASN1_ID_SEQUENCE)
> + return NULL;
> +
> + if (der_find_elem(kdf_sequence, kdf_len, 2, &tag, &tmp_len))
> + return NULL;
> +
> + salt = der_find_elem(params, params_len, 0, &tag, &salt_len);
> + if (!salt || tag != ASN1_ID_OCTET_STRING ||
> + salt_len < 1 || salt_len > 512)
> + return NULL;
> +
> + iter_count_buf = der_find_elem(params, params_len, 1, &tag, &tmp_len);
> + if (!iter_count_buf || tag != ASN1_ID_INTEGER ||
> + tmp_len < 1 || tmp_len > 4)
> + return NULL;
> +
> + iter_count = 0;
> + while (tmp_len--)
> + iter_count = (iter_count << 8) | *iter_count_buf++;
> +
> + key_len_buf = der_find_elem(params, params_len, 2, &tag, &tmp_len);
> + if (key_len_buf) {
> + if (tag != ASN1_ID_INTEGER || tmp_len != 1)
> + return NULL;
> +
> + key_len = 0;
> + while (tmp_len--)
> + key_len = (key_len << 8) | *key_len_buf++;
> + } else
> + key_len = 0;
> +
> + prf_sequence = der_find_elem(params, params_len, 3, &tag, &tmp_len);
> + if (prf_sequence) {
> + if (tag != ASN1_ID_SEQUENCE)
> + return NULL;
> +
> + oid = der_find_elem(prf_sequence, tmp_len, 0, &tag, &tmp_len);
> + if (!oid || tag != ASN1_ID_OID)
> + return NULL;
> +
> + for (i = 0; i < L_ARRAY_SIZE(pkcs5_digest_alg_oids); i++)
> + if (!asn1_oid_eq(&pkcs5_digest_alg_oids[i].oid,
> + tmp_len, oid))
> + prf_alg = pkcs5_digest_alg_oids[i].type;
> + if (prf_alg == L_CHECKSUM_NONE)
> + return NULL;
> + } else
> + prf_alg = L_CHECKSUM_SHA1;
> +
> + oid = der_find_elem(enc_sequence, enc_len, 0, &tag, &tmp_len);
> + if (!oid || tag != ASN1_ID_OID)
> + return NULL;
> +
> + for (i = 0; i < L_ARRAY_SIZE(pkcs5_enc_alg_oids); i++)
> + if (asn1_oid_eq(&pkcs5_enc_alg_oids[i].oid, tmp_len, oid)) {
> + enc_scheme = &pkcs5_enc_alg_oids[i];
> + break;
> + }
Our preference is to put {} around the enclosing for in this case.
item M1 here as well
> + if (!enc_scheme)
> + return NULL;
> +
> + params = der_find_elem(enc_sequence, enc_len, 1, &tag, ¶ms_len);
> + if (!params)
> + return NULL;
> +
> + /* RFC8018 section B.2 */
> +
> + /*
> + * Since we don't support RC2/RC5, all our PKCS#5 ciphers only
> + * have an obligatory OCTET STRING IV parameter and a fixed key
> + * length.
> + */
> + if (tag != ASN1_ID_OCTET_STRING || params_len != enc_scheme->iv_size)
> + return NULL;
> +
> + if (key_len && enc_scheme->key_size != key_len)
> + return NULL;
> + key_len = enc_scheme->key_size;
> +
> + if (der_find_elem(enc_sequence, enc_len, 2, &tag, &tmp_len))
> + return NULL;
> +
> + /* RFC8018 section 6.2 */
> +
> + if (!pkcs5_pbkdf2(prf_alg, password, salt, salt_len, iter_count,
> + key_len, derived_key))
> + return NULL;
> +
> + cipher = l_cipher_new(enc_scheme->cipher_type, derived_key, key_len);
> + if (!cipher)
> + return NULL;
> +
> + if (l_cipher_set_iv(cipher, params, enc_scheme->iv_size))
> + return cipher;
> +
> + l_cipher_free(cipher);
> + return NULL;
> +}
> +
> +LIB_EXPORT struct l_cipher *l_cipher_from_pkcs5_id(const uint8_t *id_asn1,
> + size_t id_asn1_len,
> + const char *password)
> +{
> + uint8_t tag;
> + const uint8_t *oid, *params, *salt, *iter_count_buf;
> + size_t oid_len, params_len, tmp_len;
> + unsigned int i, iter_count;
> + const struct pkcs5_pbes1_encryption_oid *pbes1_scheme = NULL;
> + uint8_t derived_key[16];
> + struct l_cipher *cipher;
> +
> + oid = der_find_elem(id_asn1, id_asn1_len, 0, &tag, &oid_len);
> + if (!oid || tag != ASN1_ID_OID)
> + return NULL;
> +
> + params = der_find_elem(id_asn1, id_asn1_len, 1, &tag, ¶ms_len);
> + if (!params || tag != ASN1_ID_SEQUENCE)
> + return NULL;
> +
> + if (der_find_elem(id_asn1, id_asn1_len, 2, &tag, &tmp_len))
> + return NULL;
> +
> + if (asn1_oid_eq(&pkcs5_pbes2_oid, oid_len, oid))
> + return cipher_from_pkcs5_pbes2_params(params, params_len,
> + password);
> +
> + /* RFC8018 section A.3 */
> +
> + for (i = 0; i < L_ARRAY_SIZE(pkcs5_pbes1_encryption_oids); i++)
> + if (asn1_oid_eq(&pkcs5_pbes1_encryption_oids[i].oid,
> + oid_len, oid)) {
> + pbes1_scheme = &pkcs5_pbes1_encryption_oids[i];
> + break;
> + }
{}s for the outer for here please. Item M1...
> + if (!pbes1_scheme)
> + return NULL;
> +
> + salt = der_find_elem(params, params_len, 0, &tag, &tmp_len);
> + if (!salt || tag != ASN1_ID_OCTET_STRING || tmp_len != 8)
> + return NULL;
> +
> + iter_count_buf = der_find_elem(params, params_len, 1, &tag, &tmp_len);
> + if (!iter_count_buf || tag != ASN1_ID_INTEGER ||
> + tmp_len < 1 || tmp_len > 4)
> + return NULL;
> +
> + iter_count = 0;
> + while (tmp_len--)
> + iter_count = (iter_count << 8) | *iter_count_buf++;
> +
> + if (der_find_elem(params, params_len, 2, &tag, &tmp_len))
> + return NULL;
> +
> + /* RFC8018 section 6.1 */
> +
> + if (!pkcs5_pbkdf1(pbes1_scheme->checksum_type,
> + password, salt, 8, iter_count, 16, derived_key))
> + return NULL;
> +
> + cipher = l_cipher_new(pbes1_scheme->cipher_type, derived_key + 0, 8);
> + if (!cipher)
> + return NULL;
> +
> + if (l_cipher_set_iv(cipher, derived_key + 8, 8))
> + return cipher;
> +
> + l_cipher_free(cipher);
> + return NULL;
> +}
> diff --git a/ell/cipher.h b/ell/cipher.h
> index d787f33..3c79aee 100644
> --- a/ell/cipher.h
> +++ b/ell/cipher.h
> @@ -41,6 +41,10 @@ enum l_cipher_type {
> struct l_cipher *l_cipher_new(enum l_cipher_type type,
> const void *key, size_t key_length);
>
> +struct l_cipher *l_cipher_from_pkcs5_id(const uint8_t *id_asn1,
> + size_t id_asn1_len,
> + const char *password);
> +
> void l_cipher_free(struct l_cipher *cipher);
>
> bool l_cipher_encrypt(struct l_cipher *cipher,
>
Regards,
-Denis
next prev parent reply other threads:[~2017-08-11 16:55 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-08-10 23:10 [PATCH 01/10] checksum: Add SHA224 checksum type Andrew Zaborowski
2017-08-10 23:10 ` [PATCH 02/10] cipher: Add DES-CBC cipher type Andrew Zaborowski
2017-08-11 16:08 ` Denis Kenzior
2017-08-10 23:10 ` [PATCH 03/10] tls: Move DER / ASN.1 related definitions to asn1-private.h Andrew Zaborowski
2017-08-11 16:17 ` Denis Kenzior
2017-08-12 0:08 ` Andrew Zaborowski
2017-08-10 23:10 ` [PATCH 04/10] tls: Report error if private key loading fails Andrew Zaborowski
2017-08-11 16:18 ` Denis Kenzior
2017-08-10 23:10 ` [PATCH 05/10] asn1: Use const pointers in ASN1 parsing utilities Andrew Zaborowski
2017-08-10 23:10 ` [PATCH 06/10][RFC] cipher: Implement PKCS#5 key derivation functions Andrew Zaborowski
2017-08-11 16:28 ` Denis Kenzior
2017-08-12 0:12 ` Andrew Zaborowski
2017-08-10 23:10 ` [PATCH 07/10] cipher: Add l_cipher_from_pkcs5_id Andrew Zaborowski
2017-08-11 16:55 ` Denis Kenzior [this message]
2017-08-12 0:17 ` Andrew Zaborowski
2017-08-12 0:30 ` Denis Kenzior
2017-08-12 0:40 ` Andrew Zaborowski
2017-08-12 0:42 ` Denis Kenzior
2017-08-10 23:10 ` [PATCH 08/10] pem: Support encrypted keys in l_pem_load_private_key Andrew Zaborowski
2017-08-11 20:23 ` Denis Kenzior
2017-08-12 0:30 ` Andrew Zaborowski
2017-08-12 0:40 ` Denis Kenzior
2017-08-12 0:45 ` Andrew Zaborowski
2017-08-12 0:49 ` Denis Kenzior
2017-08-10 23:10 ` [PATCH 09/10] unit: Update for l_pem_load_private_key() parameter change Andrew Zaborowski
2017-08-10 23:10 ` [PATCH 10/10] unit: Test loading encrypted private key PEM files Andrew Zaborowski
2017-08-11 20:26 ` Denis Kenzior
2017-08-11 16:07 ` [PATCH 01/10] checksum: Add SHA224 checksum type Denis Kenzior
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=83284742-6c95-af79-80cc-12e3bec8a77f@gmail.com \
--to=denkenz@gmail.com \
--cc=ell@lists.01.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.