diff options
-rw-r--r-- | lib/Makefile.am | 2 | ||||
-rw-r--r-- | lib/gnutls_state.c | 424 | ||||
-rw-r--r-- | lib/prf.c | 457 |
3 files changed, 458 insertions, 425 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index 9e5078d721..dfe08c8b18 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -83,7 +83,7 @@ COBJECTS = gnutls_range.c gnutls_record.c \ gnutls_pubkey.c locks.c gnutls_dtls.c system_override.c \ crypto-backend.c verify-tofu.c pin.c tpm.c fips.c \ safe-memfuncs.c inet_pton.c atfork.c atfork.h \ - system-keys.h urls.c urls.h + system-keys.h urls.c urls.h prf.c if WINDOWS COBJECTS += system-keys-win.c diff --git a/lib/gnutls_state.c b/lib/gnutls_state.c index 24f3ba8af0..940ea3f5ff 100644 --- a/lib/gnutls_state.c +++ b/lib/gnutls_state.c @@ -776,430 +776,6 @@ gnutls_handshake_set_private_extensions(gnutls_session_t session, session->internals.enable_private = allow; } -inline static int -_gnutls_cal_PRF_A(const mac_entry_st * me, - const void *secret, int secret_size, - const void *seed, int seed_size, void *result) -{ - int ret; - - ret = - _gnutls_mac_fast(me->id, secret, secret_size, seed, seed_size, - result); - if (ret < 0) - return gnutls_assert_val(ret); - - return 0; -} - -#define MAX_SEED_SIZE 200 - -/* Produces "total_bytes" bytes using the hash algorithm specified. - * (used in the PRF function) - */ -static int -P_hash(gnutls_mac_algorithm_t algorithm, - const uint8_t * secret, int secret_size, - const uint8_t * seed, int seed_size, int total_bytes, uint8_t * ret) -{ - - mac_hd_st td2; - int i, times, how, blocksize, A_size; - uint8_t final[MAX_HASH_SIZE], Atmp[MAX_SEED_SIZE]; - int output_bytes, result; - const mac_entry_st *me = mac_to_entry(algorithm); - - blocksize = _gnutls_mac_get_algo_len(me); - - if (seed_size > MAX_SEED_SIZE || total_bytes <= 0 || blocksize == 0) { - gnutls_assert(); - return GNUTLS_E_INTERNAL_ERROR; - } - - output_bytes = 0; - do { - output_bytes += blocksize; - } - while (output_bytes < total_bytes); - - /* calculate A(0) */ - - memcpy(Atmp, seed, seed_size); - A_size = seed_size; - - times = output_bytes / blocksize; - - for (i = 0; i < times; i++) { - result = _gnutls_mac_init(&td2, me, secret, secret_size); - if (result < 0) { - gnutls_assert(); - return result; - } - - /* here we calculate A(i+1) */ - if ((result = - _gnutls_cal_PRF_A(me, secret, secret_size, Atmp, - A_size, Atmp)) < 0) { - gnutls_assert(); - _gnutls_mac_deinit(&td2, final); - return result; - } - - A_size = blocksize; - - _gnutls_mac(&td2, Atmp, A_size); - _gnutls_mac(&td2, seed, seed_size); - _gnutls_mac_deinit(&td2, final); - - if ((1 + i) * blocksize < total_bytes) { - how = blocksize; - } else { - how = total_bytes - (i) * blocksize; - } - - if (how > 0) { - memcpy(&ret[i * blocksize], final, how); - } - } - - return 0; -} - -#define MAX_PRF_BYTES 200 - -/* This function operates as _gnutls_PRF(), but does not require - * a pointer to the current session. It takes the @mac algorithm - * explicitly. For legacy TLS/SSL sessions before TLS 1.2 the MAC - * must be set to %GNUTLS_MAC_UNKNOWN. - */ -static int -_gnutls_PRF_raw(gnutls_mac_algorithm_t mac, - const uint8_t * secret, unsigned int secret_size, - const char *label, int label_size, const uint8_t * seed, - int seed_size, int total_bytes, void *ret) -{ - int l_s, s_seed_size; - const uint8_t *s1, *s2; - uint8_t s_seed[MAX_SEED_SIZE]; - uint8_t o1[MAX_PRF_BYTES], o2[MAX_PRF_BYTES]; - int result; - - if (total_bytes > MAX_PRF_BYTES) { - gnutls_assert(); - return GNUTLS_E_INTERNAL_ERROR; - } - /* label+seed = s_seed */ - s_seed_size = seed_size + label_size; - - if (s_seed_size > MAX_SEED_SIZE) { - gnutls_assert(); - return GNUTLS_E_INTERNAL_ERROR; - } - - memcpy(s_seed, label, label_size); - memcpy(&s_seed[label_size], seed, seed_size); - - if (mac != GNUTLS_MAC_UNKNOWN) { - result = - P_hash(mac, secret, secret_size, - s_seed, s_seed_size, - total_bytes, ret); - if (result < 0) { - gnutls_assert(); - return result; - } - } else { - l_s = secret_size / 2; - - s1 = &secret[0]; - s2 = &secret[l_s]; - - if (secret_size % 2 != 0) { - l_s++; - } - - result = - P_hash(GNUTLS_MAC_MD5, s1, l_s, s_seed, s_seed_size, - total_bytes, o1); - if (result < 0) { - gnutls_assert(); - return result; - } - - result = - P_hash(GNUTLS_MAC_SHA1, s2, l_s, s_seed, s_seed_size, - total_bytes, o2); - if (result < 0) { - gnutls_assert(); - return result; - } - - memxor(o1, o2, total_bytes); - - memcpy(ret, o1, total_bytes); - } - - return 0; /* ok */ -} - -/* The PRF function expands a given secret - * needed by the TLS specification. ret must have a least total_bytes - * available. - */ -int -_gnutls_PRF(gnutls_session_t session, - const uint8_t * secret, unsigned int secret_size, - const char *label, int label_size, const uint8_t * seed, - int seed_size, int total_bytes, void *ret) -{ - const version_entry_st *ver = get_version(session); - - if (_gnutls_version_has_selectable_prf(ver)) { - return _gnutls_PRF_raw( - _gnutls_cipher_suite_get_prf(session->security_parameters.cipher_suite), - secret, secret_size, - label, label_size, - seed, seed_size, - total_bytes, - ret); - } else { - return _gnutls_PRF_raw( - GNUTLS_MAC_UNKNOWN, - secret, secret_size, - label, label_size, - seed, seed_size, - total_bytes, - ret); - } -} - -#ifdef ENABLE_FIPS140 -int -_gnutls_prf_raw(gnutls_mac_algorithm_t mac, - size_t master_size, const void *master, - size_t label_size, const char *label, - size_t seed_size, const char *seed, size_t outsize, - char *out); - -/*- - * _gnutls_prf_raw: - * @mac: the MAC algorithm to use, set to %GNUTLS_MAC_UNKNOWN for the TLS1.0 mac - * @master_size: length of the @master variable. - * @master: the master secret used in PRF computation - * @label_size: length of the @label variable. - * @label: label used in PRF computation, typically a short string. - * @seed_size: length of the @seed variable. - * @seed: optional extra data to seed the PRF with. - * @outsize: size of pre-allocated output buffer to hold the output. - * @out: pre-allocated buffer to hold the generated data. - * - * Apply the TLS Pseudo-Random-Function (PRF) on the master secret - * and the provided data. - * - * Returns: %GNUTLS_E_SUCCESS on success, or an error code. - -*/ -int -_gnutls_prf_raw(gnutls_mac_algorithm_t mac, - size_t master_size, const void *master, - size_t label_size, const char *label, - size_t seed_size, const char *seed, size_t outsize, - char *out) -{ - return _gnutls_PRF_raw(mac, - master, master_size, - label, label_size, - (uint8_t *) seed, seed_size, - outsize, out); - -} -#endif - -/** - * gnutls_prf_raw: - * @session: is a #gnutls_session_t type. - * @label_size: length of the @label variable. - * @label: label used in PRF computation, typically a short string. - * @seed_size: length of the @seed variable. - * @seed: optional extra data to seed the PRF with. - * @outsize: size of pre-allocated output buffer to hold the output. - * @out: pre-allocated buffer to hold the generated data. - * - * Apply the TLS Pseudo-Random-Function (PRF) on the master secret - * and the provided data. - * - * The @label variable usually contains a string denoting the purpose - * for the generated data. The @seed usually contains data such as the - * client and server random, perhaps together with some additional - * data that is added to guarantee uniqueness of the output for a - * particular purpose. - * - * Because the output is not guaranteed to be unique for a particular - * session unless @seed includes the client random and server random - * fields (the PRF would output the same data on another connection - * resumed from the first one), it is not recommended to use this - * function directly. The gnutls_prf() function seeds the PRF with the - * client and server random fields directly, and is recommended if you - * want to generate pseudo random data unique for each session. - * - * Returns: %GNUTLS_E_SUCCESS on success, or an error code. - **/ -int -gnutls_prf_raw(gnutls_session_t session, - size_t label_size, - const char *label, - size_t seed_size, const char *seed, size_t outsize, - char *out) -{ - int ret; - - ret = _gnutls_PRF(session, - session->security_parameters.master_secret, - GNUTLS_MASTER_SIZE, - label, - label_size, (uint8_t *) seed, seed_size, outsize, - out); - - return ret; -} - -/** - * gnutls_prf_rfc5705: - * @session: is a #gnutls_session_t type. - * @label_size: length of the @label variable. - * @label: label used in PRF computation, typically a short string. - * @context_size: length of the @extra variable. - * @context: optional extra data to seed the PRF with. - * @outsize: size of pre-allocated output buffer to hold the output. - * @out: pre-allocated buffer to hold the generated data. - * - * Applies the TLS Pseudo-Random-Function (PRF) on the master secret - * and the provided data, seeded with the client and server random fields, - * as specified in RFC5705. - * - * The @label variable usually contains a string denoting the purpose - * for the generated data. The @server_random_first indicates whether - * the client random field or the server random field should be first - * in the seed. Non-zero indicates that the server random field is first, - * 0 that the client random field is first. - * - * The @context variable can be used to add more data to the seed, after - * the random variables. It can be used to make sure the - * generated output is strongly connected to some additional data - * (e.g., a string used in user authentication). - * - * The output is placed in @out, which must be pre-allocated. - * - * Note that, to provide the RFC5705 context, the @contect variable - * must be non-null. - * - * Returns: %GNUTLS_E_SUCCESS on success, or an error code. - * - * Since: 3.4.4 - **/ -int -gnutls_prf_rfc5705(gnutls_session_t session, - size_t label_size, const char *label, - size_t context_size, const char *context, - size_t outsize, char *out) -{ - char *pctx = NULL; - int ret; - - if (context != NULL && context_size > 65535) { - gnutls_assert(); - return GNUTLS_E_INVALID_REQUEST; - } - - if (context != NULL) { - pctx = gnutls_malloc(context_size+2); - if (!pctx) { - gnutls_assert(); - return GNUTLS_E_MEMORY_ERROR; - } - - memcpy(pctx+2, context, context_size); - _gnutls_write_uint16(context_size, (void*)pctx); - context_size += 2; - } - - ret = gnutls_prf(session, label_size, label, 0, - context_size, pctx, outsize, out); - - gnutls_free(pctx); - return ret; -} - -/** - * gnutls_prf: - * @session: is a #gnutls_session_t type. - * @label_size: length of the @label variable. - * @label: label used in PRF computation, typically a short string. - * @server_random_first: non-zero if server random field should be first in seed - * @extra_size: length of the @extra variable. - * @extra: optional extra data to seed the PRF with. - * @outsize: size of pre-allocated output buffer to hold the output. - * @out: pre-allocated buffer to hold the generated data. - * - * Applies the TLS Pseudo-Random-Function (PRF) on the master secret - * and the provided data, seeded with the client and server random fields. - * For the key expansion specified in RFC5705 see gnutls_prf_rfc5705(). - * - * The @label variable usually contains a string denoting the purpose - * for the generated data. The @server_random_first indicates whether - * the client random field or the server random field should be first - * in the seed. Non-zero indicates that the server random field is first, - * 0 that the client random field is first. - * - * The @extra variable can be used to add more data to the seed, after - * the random variables. It can be used to make sure the - * generated output is strongly connected to some additional data - * (e.g., a string used in user authentication). - * - * The output is placed in @out, which must be pre-allocated. - * - * Returns: %GNUTLS_E_SUCCESS on success, or an error code. - **/ -int -gnutls_prf(gnutls_session_t session, - size_t label_size, - const char *label, - int server_random_first, - size_t extra_size, const char *extra, - size_t outsize, char *out) -{ - int ret; - uint8_t *seed; - size_t seedsize = 2 * GNUTLS_RANDOM_SIZE + extra_size; - - seed = gnutls_malloc(seedsize); - if (!seed) { - gnutls_assert(); - return GNUTLS_E_MEMORY_ERROR; - } - - memcpy(seed, server_random_first ? - session->security_parameters.server_random : - session->security_parameters.client_random, - GNUTLS_RANDOM_SIZE); - memcpy(seed + GNUTLS_RANDOM_SIZE, - server_random_first ? session->security_parameters. - client_random : session->security_parameters.server_random, - GNUTLS_RANDOM_SIZE); - - if (extra && extra_size) { - memcpy(seed + 2 * GNUTLS_RANDOM_SIZE, extra, extra_size); - } - - ret = - _gnutls_PRF(session, - session->security_parameters.master_secret, - GNUTLS_MASTER_SIZE, label, label_size, seed, - seedsize, outsize, out); - - gnutls_free(seed); - - return ret; -} /** * gnutls_session_is_resumed: diff --git a/lib/prf.c b/lib/prf.c new file mode 100644 index 0000000000..5b95511dc4 --- /dev/null +++ b/lib/prf.c @@ -0,0 +1,457 @@ +/* + * Copyright (C) 2002-2015 Free Software Foundation, Inc. + * Copyright (C) 2014-2015 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/> + * + */ + +/* Functions for the TLS PRF handling. + */ + +#include <gnutls_int.h> +#include <gnutls_errors.h> +#include <gnutls_num.h> +#include <gnutls_state.h> +#include <algorithms.h> + +#define MAX_PRF_BYTES 200 +#define MAX_SEED_SIZE 200 + +inline static int +_gnutls_cal_PRF_A(const mac_entry_st * me, + const void *secret, int secret_size, + const void *seed, int seed_size, void *result) +{ + int ret; + + ret = + _gnutls_mac_fast(me->id, secret, secret_size, seed, seed_size, + result); + if (ret < 0) + return gnutls_assert_val(ret); + + return 0; +} + +/* Produces "total_bytes" bytes using the hash algorithm specified. + * (used in the PRF function) + */ +static int +P_hash(gnutls_mac_algorithm_t algorithm, + const uint8_t * secret, int secret_size, + const uint8_t * seed, int seed_size, int total_bytes, uint8_t * ret) +{ + + mac_hd_st td2; + int i, times, how, blocksize, A_size; + uint8_t final[MAX_HASH_SIZE], Atmp[MAX_SEED_SIZE]; + int output_bytes, result; + const mac_entry_st *me = mac_to_entry(algorithm); + + blocksize = _gnutls_mac_get_algo_len(me); + + if (seed_size > MAX_SEED_SIZE || total_bytes <= 0 || blocksize == 0) { + gnutls_assert(); + return GNUTLS_E_INTERNAL_ERROR; + } + + output_bytes = 0; + do { + output_bytes += blocksize; + } + while (output_bytes < total_bytes); + + /* calculate A(0) */ + + memcpy(Atmp, seed, seed_size); + A_size = seed_size; + + times = output_bytes / blocksize; + + for (i = 0; i < times; i++) { + result = _gnutls_mac_init(&td2, me, secret, secret_size); + if (result < 0) { + gnutls_assert(); + return result; + } + + /* here we calculate A(i+1) */ + if ((result = + _gnutls_cal_PRF_A(me, secret, secret_size, Atmp, + A_size, Atmp)) < 0) { + gnutls_assert(); + _gnutls_mac_deinit(&td2, final); + return result; + } + + A_size = blocksize; + + _gnutls_mac(&td2, Atmp, A_size); + _gnutls_mac(&td2, seed, seed_size); + _gnutls_mac_deinit(&td2, final); + + if ((1 + i) * blocksize < total_bytes) { + how = blocksize; + } else { + how = total_bytes - (i) * blocksize; + } + + if (how > 0) { + memcpy(&ret[i * blocksize], final, how); + } + } + + return 0; +} + +/* This function operates as _gnutls_PRF(), but does not require + * a pointer to the current session. It takes the @mac algorithm + * explicitly. For legacy TLS/SSL sessions before TLS 1.2 the MAC + * must be set to %GNUTLS_MAC_UNKNOWN. + */ +static int +_gnutls_PRF_raw(gnutls_mac_algorithm_t mac, + const uint8_t * secret, unsigned int secret_size, + const char *label, int label_size, const uint8_t * seed, + int seed_size, int total_bytes, void *ret) +{ + int l_s, s_seed_size; + const uint8_t *s1, *s2; + uint8_t s_seed[MAX_SEED_SIZE]; + uint8_t o1[MAX_PRF_BYTES], o2[MAX_PRF_BYTES]; + int result; + + if (total_bytes > MAX_PRF_BYTES) { + gnutls_assert(); + return GNUTLS_E_INTERNAL_ERROR; + } + /* label+seed = s_seed */ + s_seed_size = seed_size + label_size; + + if (s_seed_size > MAX_SEED_SIZE) { + gnutls_assert(); + return GNUTLS_E_INTERNAL_ERROR; + } + + memcpy(s_seed, label, label_size); + memcpy(&s_seed[label_size], seed, seed_size); + + if (mac != GNUTLS_MAC_UNKNOWN) { + result = + P_hash(mac, secret, secret_size, + s_seed, s_seed_size, + total_bytes, ret); + if (result < 0) { + gnutls_assert(); + return result; + } + } else { + l_s = secret_size / 2; + + s1 = &secret[0]; + s2 = &secret[l_s]; + + if (secret_size % 2 != 0) { + l_s++; + } + + result = + P_hash(GNUTLS_MAC_MD5, s1, l_s, s_seed, s_seed_size, + total_bytes, o1); + if (result < 0) { + gnutls_assert(); + return result; + } + + result = + P_hash(GNUTLS_MAC_SHA1, s2, l_s, s_seed, s_seed_size, + total_bytes, o2); + if (result < 0) { + gnutls_assert(); + return result; + } + + memxor(o1, o2, total_bytes); + + memcpy(ret, o1, total_bytes); + } + + return 0; /* ok */ +} + + +/* The PRF function expands a given secret + * needed by the TLS specification. ret must have a least total_bytes + * available. + */ +int +_gnutls_PRF(gnutls_session_t session, + const uint8_t * secret, unsigned int secret_size, + const char *label, int label_size, const uint8_t * seed, + int seed_size, int total_bytes, void *ret) +{ + const version_entry_st *ver = get_version(session); + + if (_gnutls_version_has_selectable_prf(ver)) { + return _gnutls_PRF_raw( + _gnutls_cipher_suite_get_prf(session->security_parameters.cipher_suite), + secret, secret_size, + label, label_size, + seed, seed_size, + total_bytes, + ret); + } else { + return _gnutls_PRF_raw( + GNUTLS_MAC_UNKNOWN, + secret, secret_size, + label, label_size, + seed, seed_size, + total_bytes, + ret); + } +} + +#ifdef ENABLE_FIPS140 +int +_gnutls_prf_raw(gnutls_mac_algorithm_t mac, + size_t master_size, const void *master, + size_t label_size, const char *label, + size_t seed_size, const char *seed, size_t outsize, + char *out); + +/*- + * _gnutls_prf_raw: + * @mac: the MAC algorithm to use, set to %GNUTLS_MAC_UNKNOWN for the TLS1.0 mac + * @master_size: length of the @master variable. + * @master: the master secret used in PRF computation + * @label_size: length of the @label variable. + * @label: label used in PRF computation, typically a short string. + * @seed_size: length of the @seed variable. + * @seed: optional extra data to seed the PRF with. + * @outsize: size of pre-allocated output buffer to hold the output. + * @out: pre-allocated buffer to hold the generated data. + * + * Apply the TLS Pseudo-Random-Function (PRF) on the master secret + * and the provided data. + * + * Returns: %GNUTLS_E_SUCCESS on success, or an error code. + -*/ +int +_gnutls_prf_raw(gnutls_mac_algorithm_t mac, + size_t master_size, const void *master, + size_t label_size, const char *label, + size_t seed_size, const char *seed, size_t outsize, + char *out) +{ + return _gnutls_PRF_raw(mac, + master, master_size, + label, label_size, + (uint8_t *) seed, seed_size, + outsize, out); + +} +#endif + +/** + * gnutls_prf_raw: + * @session: is a #gnutls_session_t type. + * @label_size: length of the @label variable. + * @label: label used in PRF computation, typically a short string. + * @seed_size: length of the @seed variable. + * @seed: optional extra data to seed the PRF with. + * @outsize: size of pre-allocated output buffer to hold the output. + * @out: pre-allocated buffer to hold the generated data. + * + * Apply the TLS Pseudo-Random-Function (PRF) on the master secret + * and the provided data. + * + * The @label variable usually contains a string denoting the purpose + * for the generated data. The @seed usually contains data such as the + * client and server random, perhaps together with some additional + * data that is added to guarantee uniqueness of the output for a + * particular purpose. + * + * Because the output is not guaranteed to be unique for a particular + * session unless @seed includes the client random and server random + * fields (the PRF would output the same data on another connection + * resumed from the first one), it is not recommended to use this + * function directly. The gnutls_prf() function seeds the PRF with the + * client and server random fields directly, and is recommended if you + * want to generate pseudo random data unique for each session. + * + * Returns: %GNUTLS_E_SUCCESS on success, or an error code. + **/ +int +gnutls_prf_raw(gnutls_session_t session, + size_t label_size, + const char *label, + size_t seed_size, const char *seed, size_t outsize, + char *out) +{ + int ret; + + ret = _gnutls_PRF(session, + session->security_parameters.master_secret, + GNUTLS_MASTER_SIZE, + label, + label_size, (uint8_t *) seed, seed_size, outsize, + out); + + return ret; +} + +/** + * gnutls_prf_rfc5705: + * @session: is a #gnutls_session_t type. + * @label_size: length of the @label variable. + * @label: label used in PRF computation, typically a short string. + * @context_size: length of the @extra variable. + * @context: optional extra data to seed the PRF with. + * @outsize: size of pre-allocated output buffer to hold the output. + * @out: pre-allocated buffer to hold the generated data. + * + * Applies the TLS Pseudo-Random-Function (PRF) on the master secret + * and the provided data, seeded with the client and server random fields, + * as specified in RFC5705. + * + * The @label variable usually contains a string denoting the purpose + * for the generated data. The @server_random_first indicates whether + * the client random field or the server random field should be first + * in the seed. Non-zero indicates that the server random field is first, + * 0 that the client random field is first. + * + * The @context variable can be used to add more data to the seed, after + * the random variables. It can be used to make sure the + * generated output is strongly connected to some additional data + * (e.g., a string used in user authentication). + * + * The output is placed in @out, which must be pre-allocated. + * + * Note that, to provide the RFC5705 context, the @contect variable + * must be non-null. + * + * Returns: %GNUTLS_E_SUCCESS on success, or an error code. + * + * Since: 3.4.4 + **/ +int +gnutls_prf_rfc5705(gnutls_session_t session, + size_t label_size, const char *label, + size_t context_size, const char *context, + size_t outsize, char *out) +{ + char *pctx = NULL; + int ret; + + if (context != NULL && context_size > 65535) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + if (context != NULL) { + pctx = gnutls_malloc(context_size+2); + if (!pctx) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + memcpy(pctx+2, context, context_size); + _gnutls_write_uint16(context_size, (void*)pctx); + context_size += 2; + } + + ret = gnutls_prf(session, label_size, label, 0, + context_size, pctx, outsize, out); + + gnutls_free(pctx); + return ret; +} + +/** + * gnutls_prf: + * @session: is a #gnutls_session_t type. + * @label_size: length of the @label variable. + * @label: label used in PRF computation, typically a short string. + * @server_random_first: non-zero if server random field should be first in seed + * @extra_size: length of the @extra variable. + * @extra: optional extra data to seed the PRF with. + * @outsize: size of pre-allocated output buffer to hold the output. + * @out: pre-allocated buffer to hold the generated data. + * + * Applies the TLS Pseudo-Random-Function (PRF) on the master secret + * and the provided data, seeded with the client and server random fields. + * For the key expansion specified in RFC5705 see gnutls_prf_rfc5705(). + * + * The @label variable usually contains a string denoting the purpose + * for the generated data. The @server_random_first indicates whether + * the client random field or the server random field should be first + * in the seed. Non-zero indicates that the server random field is first, + * 0 that the client random field is first. + * + * The @extra variable can be used to add more data to the seed, after + * the random variables. It can be used to make sure the + * generated output is strongly connected to some additional data + * (e.g., a string used in user authentication). + * + * The output is placed in @out, which must be pre-allocated. + * + * Returns: %GNUTLS_E_SUCCESS on success, or an error code. + **/ +int +gnutls_prf(gnutls_session_t session, + size_t label_size, + const char *label, + int server_random_first, + size_t extra_size, const char *extra, + size_t outsize, char *out) +{ + int ret; + uint8_t *seed; + size_t seedsize = 2 * GNUTLS_RANDOM_SIZE + extra_size; + + seed = gnutls_malloc(seedsize); + if (!seed) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + memcpy(seed, server_random_first ? + session->security_parameters.server_random : + session->security_parameters.client_random, + GNUTLS_RANDOM_SIZE); + memcpy(seed + GNUTLS_RANDOM_SIZE, + server_random_first ? session->security_parameters. + client_random : session->security_parameters.server_random, + GNUTLS_RANDOM_SIZE); + + if (extra && extra_size) { + memcpy(seed + 2 * GNUTLS_RANDOM_SIZE, extra, extra_size); + } + + ret = + _gnutls_PRF(session, + session->security_parameters.master_secret, + GNUTLS_MASTER_SIZE, label, label_size, seed, + seedsize, outsize, out); + + gnutls_free(seed); + + return ret; +} + |