1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012- OpenVPN Inc.
//
// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
//
#pragma once
#include <mbedtls/ssl.h>
namespace openvpn::MbedTLSCrypto {
class TLS1PRF
{
public:
#ifdef HAVE_MBEDTLS_SSL_TLS_PRF
/* mbedtls-2.18.0 to mbed TLS 3.0 */
static bool PRF(unsigned char *label,
const size_t label_len,
const unsigned char *sec,
const size_t slen,
unsigned char *output,
const size_t olen)
{
return mbedtls_ssl_tls_prf(MBEDTLS_SSL_TLS_PRF_TLS1, sec,
slen, "", label, label_len, output,
olen));
}
#else
/*
* Use the TLS PRF function for generating data channel keys.
* This code is adapted from the OpenSSL library.
*
* TLS generates keys as such:
*
* master_secret[48] = PRF(pre_master_secret[48], "master secret",
* ClientHello.random[32] + ServerHello.random[32])
*
* key_block[] = PRF(SecurityParameters.master_secret[48],
* "key expansion",
* SecurityParameters.server_random[32] +
* SecurityParameters.client_random[32]);
*
* Notes:
*
* (1) key_block contains a full set of 4 keys.
* (2) The pre-master secret is generated by the client.
*/
public:
static bool PRF(unsigned char *label,
const size_t label_len,
const unsigned char *sec,
const size_t slen,
unsigned char *out1,
const size_t olen)
{
size_t len, i;
const unsigned char *S1, *S2;
unsigned char *out2;
out2 = new unsigned char[olen];
len = slen / 2;
S1 = sec;
S2 = &(sec[len]);
len += (slen & 1); /* add for odd, make longer */
hash(CryptoAlgs::MD5, S1, len, label, label_len, out1, olen);
hash(CryptoAlgs::SHA1, S2, len, label, label_len, out2, olen);
for (i = 0; i < olen; i++)
out1[i] ^= out2[i];
std::memset(out2, 0, olen);
delete[] out2;
return true;
}
private:
static void hash(const CryptoAlgs::Type md,
const unsigned char *sec,
const size_t sec_len,
const unsigned char *seed,
const size_t seed_len,
unsigned char *out,
size_t olen)
{
size_t j;
unsigned char A1[HMACContext::MAX_HMAC_SIZE];
size_t A1_len;
HMACContext ctx;
HMACContext ctx_tmp;
const size_t chunk = CryptoAlgs::size(md);
ctx.init(md, sec, sec_len);
ctx_tmp.init(md, sec, sec_len);
ctx.update(seed, seed_len);
A1_len = ctx.final(A1);
for (;;)
{
ctx.reset();
ctx_tmp.reset();
ctx.update(A1, A1_len);
ctx_tmp.update(A1, A1_len);
ctx.update(seed, seed_len);
if (olen > chunk)
{
j = ctx.final(out);
out += j;
olen -= j;
A1_len = ctx_tmp.final(A1); /* calc the next A1 value */
}
else /* last one */
{
A1_len = ctx.final(A1);
memcpy(out, A1, olen);
break;
}
}
std::memset(A1, 0, sizeof(A1));
}
#endif
};
} // namespace openvpn::MbedTLSCrypto
|