X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fkdf%2Ftls1_prf.c;h=f5d2314681b31938615f5eedf3699165e5d82082;hp=374c6e49ec60af95bd2da01cbb47b63e793ac22f;hb=703170d4b9da1b3adc0e4d87719a5156080b2dca;hpb=aa291c62a7c227d94073c8cd4ce81aa6950d72d7 diff --git a/crypto/kdf/tls1_prf.c b/crypto/kdf/tls1_prf.c index 374c6e49ec..f5d2314681 100644 --- a/crypto/kdf/tls1_prf.c +++ b/crypto/kdf/tls1_prf.c @@ -1,67 +1,62 @@ /* - * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project - * 2016. + * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html */ -/* ==================================================================== - * Copyright (c) 2015 The OpenSSL Project. All rights reserved. + +/* + * Refer to "The TLS Protocol Version 1.0" Section 5 + * (https://tools.ietf.org/html/rfc2246#section-5) and + * "The Transport Layer Security (TLS) Protocol Version 1.2" Section 5 + * (https://tools.ietf.org/html/rfc5246#section-5). * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: + * For TLS v1.0 and TLS v1.1 the TLS PRF algorithm is given by: * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR + * P_SHA-1(S2, label + seed) * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. + * where P_MD5 and P_SHA-1 are defined by P_, below, and S1 and S2 are + * two halves of the secret (with the possibility of one shared byte, in the + * case where the length of the original secret is odd). S1 is taken from the + * first half of the secret, S2 from the second half. * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * For TLS v1.2 the TLS PRF algorithm is given by: * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * licensing@OpenSSL.org. + * PRF(secret, label, seed) = P_(secret, label + seed) * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. + * where hash is SHA-256 for all cipher suites defined in RFC 5246 as well as + * those published prior to TLS v1.2 while the TLS v1.2 protocol is in effect, + * unless defined otherwise by the cipher suite. * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * P_ is an expansion function that uses a single hash function to expand + * a secret and seed into an arbitrary quantity of output: * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== + * P_(secret, seed) = HMAC_(secret, A(1) + seed) + + * HMAC_(secret, A(2) + seed) + + * HMAC_(secret, A(3) + seed) + ... * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). + * where + indicates concatenation. P_ can be iterated as many times as + * is necessary to produce the required quantity of data. * + * A(i) is defined as: + * A(0) = seed + * A(i) = HMAC_(secret, A(i-1)) */ - #include +#include +#include #include "internal/cryptlib.h" -#include #include +#include +#include +#include #include "internal/evp_int.h" +#include "kdf_local.h" +static void kdf_tls1_prf_reset(EVP_KDF_IMPL *impl); static int tls1_prf_alg(const EVP_MD *md, const unsigned char *sec, size_t slen, const unsigned char *seed, size_t seed_len, @@ -69,9 +64,9 @@ static int tls1_prf_alg(const EVP_MD *md, #define TLS1_PRF_MAXBUF 1024 -/* TLS KDF pkey context structure */ +/* TLS KDF kdf context structure */ -typedef struct { +struct evp_kdf_impl_st { /* Digest to use for PRF */ const EVP_MD *md; /* Secret value to use for PRF */ @@ -80,194 +75,290 @@ typedef struct { /* Buffer of concatenated seed data */ unsigned char seed[TLS1_PRF_MAXBUF]; size_t seedlen; -} TLS1_PRF_PKEY_CTX; +}; -static int pkey_tls1_prf_init(EVP_PKEY_CTX *ctx) +static EVP_KDF_IMPL *kdf_tls1_prf_new(void) { - TLS1_PRF_PKEY_CTX *kctx; + EVP_KDF_IMPL *impl; - kctx = OPENSSL_zalloc(sizeof(*kctx)); - if (kctx == NULL) - return 0; - ctx->data = kctx; + if ((impl = OPENSSL_zalloc(sizeof(*impl))) == NULL) + KDFerr(KDF_F_KDF_TLS1_PRF_NEW, ERR_R_MALLOC_FAILURE); + return impl; +} - return 1; +static void kdf_tls1_prf_free(EVP_KDF_IMPL *impl) +{ + kdf_tls1_prf_reset(impl); + OPENSSL_free(impl); } -static void pkey_tls1_prf_cleanup(EVP_PKEY_CTX *ctx) +static void kdf_tls1_prf_reset(EVP_KDF_IMPL *impl) { - TLS1_PRF_PKEY_CTX *kctx = ctx->data; - OPENSSL_clear_free(kctx->sec, kctx->seclen); - OPENSSL_cleanse(kctx->seed, kctx->seedlen); - OPENSSL_free(kctx); + OPENSSL_clear_free(impl->sec, impl->seclen); + OPENSSL_cleanse(impl->seed, impl->seedlen); + memset(impl, 0, sizeof(*impl)); } -static int pkey_tls1_prf_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) +static int kdf_tls1_prf_ctrl(EVP_KDF_IMPL *impl, int cmd, va_list args) { - TLS1_PRF_PKEY_CTX *kctx = ctx->data; - switch (type) { - case EVP_PKEY_CTRL_TLS_MD: - kctx->md = p2; - return 1; + const unsigned char *p; + size_t len; + const EVP_MD *md; - case EVP_PKEY_CTRL_TLS_SECRET: - if (p1 < 0) + switch (cmd) { + case EVP_KDF_CTRL_SET_MD: + md = va_arg(args, const EVP_MD *); + if (md == NULL) return 0; - if (kctx->sec != NULL) - OPENSSL_clear_free(kctx->sec, kctx->seclen); - OPENSSL_cleanse(kctx->seed, kctx->seedlen); - kctx->seedlen = 0; - kctx->sec = OPENSSL_memdup(p2, p1); - if (kctx->sec == NULL) + + impl->md = md; + return 1; + + case EVP_KDF_CTRL_SET_TLS_SECRET: + p = va_arg(args, const unsigned char *); + len = va_arg(args, size_t); + OPENSSL_clear_free(impl->sec, impl->seclen); + impl->sec = OPENSSL_memdup(p, len); + if (impl->sec == NULL) return 0; - kctx->seclen = p1; + + impl->seclen = len; + return 1; + + case EVP_KDF_CTRL_RESET_TLS_SEED: + OPENSSL_cleanse(impl->seed, impl->seedlen); + impl->seedlen = 0; return 1; - case EVP_PKEY_CTRL_TLS_SEED: - if (p1 == 0 || p2 == NULL) + case EVP_KDF_CTRL_ADD_TLS_SEED: + p = va_arg(args, const unsigned char *); + len = va_arg(args, size_t); + if (len == 0 || p == NULL) return 1; - if (p1 < 0 || p1 > (int)(TLS1_PRF_MAXBUF - kctx->seedlen)) + + if (len > (TLS1_PRF_MAXBUF - impl->seedlen)) return 0; - memcpy(kctx->seed + kctx->seedlen, p2, p1); - kctx->seedlen += p1; + + memcpy(impl->seed + impl->seedlen, p, len); + impl->seedlen += len; return 1; default: return -2; - } } -static int pkey_tls1_prf_derive(EVP_PKEY_CTX *ctx, unsigned char *key, - size_t *keylen) +static int kdf_tls1_prf_ctrl_str(EVP_KDF_IMPL *impl, + const char *type, const char *value) { - TLS1_PRF_PKEY_CTX *kctx = ctx->data; - if (kctx->md == NULL || kctx->sec == NULL || kctx->seedlen == 0) + if (value == NULL) { + KDFerr(KDF_F_KDF_TLS1_PRF_CTRL_STR, KDF_R_VALUE_MISSING); return 0; - return tls1_prf_alg(kctx->md, kctx->sec, kctx->seclen, - kctx->seed, kctx->seedlen, - key, *keylen); -} - -const EVP_PKEY_METHOD tls1_prf_pkey_meth = { - EVP_PKEY_TLS1_PRF, - 0, - pkey_tls1_prf_init, - 0, - pkey_tls1_prf_cleanup, - - 0, 0, - 0, 0, + } + if (strcmp(type, "digest") == 0) + return kdf_md2ctrl(impl, kdf_tls1_prf_ctrl, EVP_KDF_CTRL_SET_MD, value); - 0, - 0, + if (strcmp(type, "secret") == 0) + return kdf_str2ctrl(impl, kdf_tls1_prf_ctrl, + EVP_KDF_CTRL_SET_TLS_SECRET, value); - 0, - 0, + if (strcmp(type, "hexsecret") == 0) + return kdf_hex2ctrl(impl, kdf_tls1_prf_ctrl, + EVP_KDF_CTRL_SET_TLS_SECRET, value); - 0, 0, + if (strcmp(type, "seed") == 0) + return kdf_str2ctrl(impl, kdf_tls1_prf_ctrl, EVP_KDF_CTRL_ADD_TLS_SEED, + value); - 0, 0, 0, 0, + if (strcmp(type, "hexseed") == 0) + return kdf_hex2ctrl(impl, kdf_tls1_prf_ctrl, EVP_KDF_CTRL_ADD_TLS_SEED, + value); - 0, 0, + return -2; +} - 0, 0, +static int kdf_tls1_prf_derive(EVP_KDF_IMPL *impl, unsigned char *key, + size_t keylen) +{ + if (impl->md == NULL) { + KDFerr(KDF_F_KDF_TLS1_PRF_DERIVE, KDF_R_MISSING_MESSAGE_DIGEST); + return 0; + } + if (impl->sec == NULL) { + KDFerr(KDF_F_KDF_TLS1_PRF_DERIVE, KDF_R_MISSING_SECRET); + return 0; + } + if (impl->seedlen == 0) { + KDFerr(KDF_F_KDF_TLS1_PRF_DERIVE, KDF_R_MISSING_SEED); + return 0; + } + return tls1_prf_alg(impl->md, impl->sec, impl->seclen, + impl->seed, impl->seedlen, + key, keylen); +} - 0, - pkey_tls1_prf_derive, - pkey_tls1_prf_ctrl, - 0 +const EVP_KDF tls1_prf_kdf_meth = { + EVP_KDF_TLS1_PRF, + kdf_tls1_prf_new, + kdf_tls1_prf_free, + kdf_tls1_prf_reset, + kdf_tls1_prf_ctrl, + kdf_tls1_prf_ctrl_str, + NULL, + kdf_tls1_prf_derive }; +/* + * Refer to "The TLS Protocol Version 1.0" Section 5 + * (https://tools.ietf.org/html/rfc2246#section-5) and + * "The Transport Layer Security (TLS) Protocol Version 1.2" Section 5 + * (https://tools.ietf.org/html/rfc5246#section-5). + * + * P_ is an expansion function that uses a single hash function to expand + * a secret and seed into an arbitrary quantity of output: + * + * P_(secret, seed) = HMAC_(secret, A(1) + seed) + + * HMAC_(secret, A(2) + seed) + + * HMAC_(secret, A(3) + seed) + ... + * + * where + indicates concatenation. P_ can be iterated as many times as + * is necessary to produce the required quantity of data. + * + * A(i) is defined as: + * A(0) = seed + * A(i) = HMAC_(secret, A(i-1)) + */ static int tls1_prf_P_hash(const EVP_MD *md, const unsigned char *sec, size_t sec_len, const unsigned char *seed, size_t seed_len, unsigned char *out, size_t olen) { - int chunk; - EVP_MD_CTX *ctx = NULL, *ctx_tmp = NULL, *ctx_init = NULL; - EVP_PKEY *mac_key = NULL; - unsigned char A1[EVP_MAX_MD_SIZE]; - size_t A1_len; + size_t chunk; + EVP_MAC *mac = NULL; + EVP_MAC_CTX *ctx = NULL, *ctx_Ai = NULL, *ctx_init = NULL; + unsigned char Ai[EVP_MAX_MD_SIZE]; + size_t Ai_len; int ret = 0; + OSSL_PARAM params[4]; + int mac_flags; + const char *mdname = EVP_MD_name(md); - chunk = EVP_MD_size(md); - OPENSSL_assert(chunk >= 0); - - ctx = EVP_MD_CTX_new(); - ctx_tmp = EVP_MD_CTX_new(); - ctx_init = EVP_MD_CTX_new(); - if (ctx == NULL || ctx_tmp == NULL || ctx_init == NULL) + mac = EVP_MAC_fetch(NULL, OSSL_MAC_NAME_HMAC, NULL); /* Implicit fetch */ + ctx_init = EVP_MAC_CTX_new(mac); + if (ctx_init == NULL) goto err; - EVP_MD_CTX_set_flags(ctx_init, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); - mac_key = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, sec, sec_len); - if (mac_key == NULL) + + /* TODO(3.0) rethink "flags", also see hmac.c in providers */ + mac_flags = EVP_MD_CTX_FLAG_NON_FIPS_ALLOW; + params[0] = OSSL_PARAM_construct_int(OSSL_MAC_PARAM_FLAGS, &mac_flags); + params[1] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, + (char *)mdname, + strlen(mdname) + 1); + params[2] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, + (void *)sec, sec_len); + params[3] = OSSL_PARAM_construct_end(); + if (!EVP_MAC_CTX_set_params(ctx_init, params)) goto err; - if (!EVP_DigestSignInit(ctx_init, NULL, md, NULL, mac_key)) + if (!EVP_MAC_init(ctx_init)) goto err; - if (!EVP_MD_CTX_copy_ex(ctx, ctx_init)) + chunk = EVP_MAC_size(ctx_init); + if (chunk == 0) goto err; - if (seed != NULL && !EVP_DigestSignUpdate(ctx, seed, seed_len)) + /* A(0) = seed */ + ctx_Ai = EVP_MAC_CTX_dup(ctx_init); + if (ctx_Ai == NULL) goto err; - if (!EVP_DigestSignFinal(ctx, A1, &A1_len)) + if (seed != NULL && !EVP_MAC_update(ctx_Ai, seed, seed_len)) goto err; for (;;) { - /* Reinit mac contexts */ - if (!EVP_MD_CTX_copy_ex(ctx, ctx_init)) - goto err; - if (!EVP_DigestSignUpdate(ctx, A1, A1_len)) + /* calc: A(i) = HMAC_(secret, A(i-1)) */ + if (!EVP_MAC_final(ctx_Ai, Ai, &Ai_len, sizeof(Ai))) goto err; - if (olen > (size_t)chunk && !EVP_MD_CTX_copy_ex(ctx_tmp, ctx)) + EVP_MAC_CTX_free(ctx_Ai); + ctx_Ai = NULL; + + /* calc next chunk: HMAC_(secret, A(i) + seed) */ + ctx = EVP_MAC_CTX_dup(ctx_init); + if (ctx == NULL) goto err; - if (seed && !EVP_DigestSignUpdate(ctx, seed, seed_len)) + if (!EVP_MAC_update(ctx, Ai, Ai_len)) goto err; - - if (olen > (size_t)chunk) { - size_t mac_len; - if (!EVP_DigestSignFinal(ctx, out, &mac_len)) + /* save state for calculating next A(i) value */ + if (olen > chunk) { + ctx_Ai = EVP_MAC_CTX_dup(ctx); + if (ctx_Ai == NULL) goto err; - out += mac_len; - olen -= mac_len; - /* calc the next A1 value */ - if (!EVP_DigestSignFinal(ctx_tmp, A1, &A1_len)) - goto err; - } else { /* last one */ - - if (!EVP_DigestSignFinal(ctx, A1, &A1_len)) + } + if (seed != NULL && !EVP_MAC_update(ctx, seed, seed_len)) + goto err; + if (olen <= chunk) { + /* last chunk - use Ai as temp bounce buffer */ + if (!EVP_MAC_final(ctx, Ai, &Ai_len, sizeof(Ai))) goto err; - memcpy(out, A1, olen); + memcpy(out, Ai, olen); break; } + if (!EVP_MAC_final(ctx, out, NULL, olen)) + goto err; + EVP_MAC_CTX_free(ctx); + ctx = NULL; + out += chunk; + olen -= chunk; } ret = 1; err: - EVP_PKEY_free(mac_key); - EVP_MD_CTX_free(ctx); - EVP_MD_CTX_free(ctx_tmp); - EVP_MD_CTX_free(ctx_init); - OPENSSL_cleanse(A1, sizeof(A1)); + EVP_MAC_CTX_free(ctx); + EVP_MAC_CTX_free(ctx_Ai); + EVP_MAC_CTX_free(ctx_init); + EVP_MAC_free(mac); + OPENSSL_cleanse(Ai, sizeof(Ai)); return ret; } +/* + * Refer to "The TLS Protocol Version 1.0" Section 5 + * (https://tools.ietf.org/html/rfc2246#section-5) and + * "The Transport Layer Security (TLS) Protocol Version 1.2" Section 5 + * (https://tools.ietf.org/html/rfc5246#section-5). + * + * For TLS v1.0 and TLS v1.1: + * + * PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR + * P_SHA-1(S2, label + seed) + * + * S1 is taken from the first half of the secret, S2 from the second half. + * + * L_S = length in bytes of secret; + * L_S1 = L_S2 = ceil(L_S / 2); + * + * For TLS v1.2: + * + * PRF(secret, label, seed) = P_(secret, label + seed) + */ static int tls1_prf_alg(const EVP_MD *md, const unsigned char *sec, size_t slen, const unsigned char *seed, size_t seed_len, unsigned char *out, size_t olen) { - if (EVP_MD_type(md) == NID_md5_sha1) { + /* TLS v1.0 and TLS v1.1 */ size_t i; unsigned char *tmp; - if (!tls1_prf_P_hash(EVP_md5(), sec, slen/2 + (slen & 1), - seed, seed_len, out, olen)) + /* calc: L_S1 = L_S2 = ceil(L_S / 2) */ + size_t L_S1 = (slen + 1) / 2; + size_t L_S2 = L_S1; + + if (!tls1_prf_P_hash(EVP_md5(), sec, L_S1, + seed, seed_len, out, olen)) return 0; - tmp = OPENSSL_malloc(olen); - if (tmp == NULL) + if ((tmp = OPENSSL_malloc(olen)) == NULL) { + KDFerr(KDF_F_TLS1_PRF_ALG, ERR_R_MALLOC_FAILURE); return 0; - if (!tls1_prf_P_hash(EVP_sha1(), sec + slen/2, slen/2 + (slen & 1), - seed, seed_len, tmp, olen)) { + } + if (!tls1_prf_P_hash(EVP_sha1(), sec + slen - L_S2, L_S2, + seed, seed_len, tmp, olen)) { OPENSSL_clear_free(tmp, olen); return 0; } @@ -276,6 +367,8 @@ static int tls1_prf_alg(const EVP_MD *md, OPENSSL_clear_free(tmp, olen); return 1; } + + /* TLS v1.2 */ if (!tls1_prf_P_hash(md, sec, slen, seed, seed_len, out, olen)) return 0;