/* * Copyright (C) 2017 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 * */ /* Functions for the TLS PRF handling. */ #if HAVE_CONFIG_H # include #endif #include #include #include #include #include #include "int/tls1-prf.h" #include #include /* The RFC2246 P_hash() function. The mac_ctx is expected to * be initialized and key set to be the secret key. */ static void P_hash( void *mac_ctx, nettle_hash_update_func *update, nettle_hash_digest_func *digest, size_t digest_size, size_t seed_size, const uint8_t *seed, size_t dst_length, uint8_t *dst) { uint8_t Atmp[MAX_HASH_SIZE]; ssize_t left; unsigned started = 0; /* round up */ left = dst_length; while(left > 0) { if (started == 0) { /* A(0) */ update(mac_ctx, seed_size, seed); started = 1; } else { update(mac_ctx, digest_size, Atmp); } digest(mac_ctx, digest_size, Atmp); /* store A(i) */ update(mac_ctx, digest_size, Atmp); /* hash A(i) */ update(mac_ctx, seed_size, seed); /* hash seed */ if (left < (ssize_t)digest_size) digest_size = left; digest(mac_ctx, digest_size, dst); left -= digest_size; dst += digest_size; } return; } int tls10_prf(size_t secret_size, const uint8_t *secret, size_t label_size, const char *label, size_t seed_size, const uint8_t *seed, size_t length, uint8_t *dst) { int l_s, cseed_size = seed_size + label_size; const uint8_t *s1, *s2; struct hmac_md5_ctx md5_ctx; struct hmac_sha1_ctx sha1_ctx; uint8_t o1[MAX_PRF_BYTES]; uint8_t cseed[MAX_SEED_SIZE]; if (cseed_size > MAX_SEED_SIZE || length > MAX_PRF_BYTES) return 0; memcpy(cseed, label, label_size); memcpy(&cseed[label_size], seed, seed_size); l_s = secret_size / 2; s1 = &secret[0]; s2 = &secret[l_s]; if (secret_size % 2 != 0) { l_s++; } hmac_md5_set_key(&md5_ctx, l_s, s1); P_hash(&md5_ctx, (nettle_hash_update_func*)hmac_md5_update, (nettle_hash_digest_func*)hmac_md5_digest, MD5_DIGEST_SIZE, cseed_size, cseed, length, o1); hmac_sha1_set_key(&sha1_ctx, l_s, s2); P_hash(&sha1_ctx, (nettle_hash_update_func*)hmac_sha1_update, (nettle_hash_digest_func*)hmac_sha1_digest, SHA1_DIGEST_SIZE, cseed_size, cseed, length, dst); memxor(dst, o1, length); return 1; } /*- * tls12_prf: * @mac_ctx: a MAC context initialized with key being the secret * @update: a MAC update function * @digest: a MAC digest function * @digest_size: the MAC output size * @label_size: the size of the label * @label: the label to apply * @seed_size: the seed size * @seed: the seed * @length: size of desired PRF output * @dst: the location to store output * * The TLS 1.2 Pseudo-Random-Function (PRF). * * Returns: zero on failure, non zero on success. -*/ int tls12_prf(void *mac_ctx, nettle_hash_update_func *update, nettle_hash_digest_func *digest, size_t digest_size, size_t label_size, const char *label, size_t seed_size, const uint8_t *seed, size_t length, uint8_t *dst) { size_t cseed_size = seed_size + label_size; uint8_t cseed[MAX_SEED_SIZE]; if (cseed_size > MAX_SEED_SIZE) return 0; memcpy(cseed, label, label_size); memcpy(&cseed[label_size], seed, seed_size); P_hash(mac_ctx, update, digest, digest_size, cseed_size, cseed, length, dst); return 1; }