/*
* Copyright 2016-2021 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
*/
#include <stdlib.h>
#include "ssl_local.h"
#include "internal/ktls.h"
#include "record/record_local.h"
#include "internal/cryptlib.h"
#include <openssl/evp.h>
#include <openssl/kdf.h>
#include <openssl/core_names.h>
#define TLS13_MAX_LABEL_LEN 249
/* Always filled with zeros */
static const unsigned char default_zeros[EVP_MAX_MD_SIZE];
/*
* Given a |secret|; a |label| of length |labellen|; and |data| of length
* |datalen| (e.g. typically a hash of the handshake messages), derive a new
* secret |outlen| bytes long and store it in the location pointed to be |out|.
* The |data| value may be zero length. Any errors will be treated as fatal if
* |fatal| is set. Returns 1 on success 0 on failure.
*/
int tls13_hkdf_expand(SSL *s, const EVP_MD *md, const unsigned char *secret,
const unsigned char *label, size_t labellen,
const unsigned char *data, size_t datalen,
unsigned char *out, size_t outlen, int fatal)
{
#ifdef CHARSET_EBCDIC
static const unsigned char label_prefix[] = { 0x74, 0x6C, 0x73, 0x31, 0x33, 0x20, 0x00 };
#else
static const unsigned char label_prefix[] = "tls13 ";
#endif
EVP_KDF *kdf = EVP_KDF_fetch(s->ctx->libctx, OSSL_KDF_NAME_HKDF,
s->ctx->propq);
EVP_KDF_CTX *kctx;
OSSL_PARAM params[5], *p = params;
int mode = EVP_PKEY_HKDEF_MODE_EXPAND_ONLY;
const char *mdname = EVP_MD_name(md);
int ret;
size_t hkdflabellen;
size_t hashlen;
/*
* 2 bytes for length of derived secret + 1 byte for length of combined
* prefix and label + bytes for the label itself + 1 byte length of hash
* + bytes for the hash itself
*/
unsigned char hkdflabel[sizeof(uint16_t) + sizeof(uint8_t)
+ (sizeof(label_prefix) - 1) + TLS13_MAX_LABEL_LEN
+ 1 + EVP_MAX_MD_SIZE];
WPACKET pkt;
kctx = EVP_KDF_CTX_new(kdf);
EVP_KDF_free(kdf);
if (kctx == NULL)
return 0;
if (labellen > TLS13_MAX_LABEL_LEN) {
if (fatal) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
} else {
/*
* Probably we have been called from SSL_export_keying_material(),
* or SSL_export_keying_material_early().
*/
ERR_raise(ERR_LIB_SSL, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL);
}
EVP_KDF_CTX_free(kctx);
return 0;
}
hashlen = EVP_MD_size(md);
if (!WPACKET_init_static_len(&pkt, hkdflabel, sizeof(hkdflabel), 0)
|| !WPACKET_put_bytes_u16(&pkt, outlen)
|| !WPACKET_start_sub_packet_u8(&pkt)
|| !WPACKET_memcpy(&pkt, label_prefix, sizeof(label_prefix) - 1)
|| !WPACKET_memcpy(&pkt, label, labellen)
|| !WPACKET_close(&pkt)
|| !WPACKET_sub_memcpy_u8(&pkt, data, (data == NULL) ? 0 : datalen)
|| !WPACKET_get_total_written(&pkt, &hkdflabellen)
|| !WPACKET_finish(&pkt)) {
EVP_KDF_CTX_free(kctx);
WPACKET_cleanup(&pkt);
if (fatal)
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
else
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
*p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_MODE, &mode);
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
(char *)mdname, 0);
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY,
(unsigned char *)secret, hashlen);
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO,
hkdflabel, hkdflabellen);
*p++ = OSSL_PARAM_construct_end();
ret = EVP_KDF_derive(kctx, out, outlen, params) <= 0;
EVP_KDF_CTX_free(kctx);
if (ret != 0) {
if (fatal)
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
else
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
}