File: tls1prf.hpp

package info (click to toggle)
openvpn3-client 25%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 19,276 kB
  • sloc: cpp: 190,085; python: 7,218; ansic: 1,866; sh: 1,361; java: 402; lisp: 81; makefile: 17
file content (133 lines) | stat: -rw-r--r-- 3,873 bytes parent folder | download
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