Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/nss/lib/ssl/tls13hkdf.c
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * TLS 1.3 Protocol
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8
9
#include "keyhi.h"
10
#include "pk11func.h"
11
#include "secitem.h"
12
#include "ssl.h"
13
#include "sslt.h"
14
#include "sslerr.h"
15
#include "sslimpl.h"
16
17
/* This table contains the mapping between TLS hash identifiers and the
18
 * PKCS#11 identifiers */
19
static const struct {
20
    SSLHashType hash;
21
    CK_MECHANISM_TYPE pkcs11Mech;
22
    unsigned int hashSize;
23
} kTlsHkdfInfo[] = {
24
    { ssl_hash_none, 0, 0 },
25
    { ssl_hash_md5, 0, 0 },
26
    { ssl_hash_sha1, 0, 0 },
27
    { ssl_hash_sha224, 0 },
28
    { ssl_hash_sha256, CKM_NSS_HKDF_SHA256, 32 },
29
    { ssl_hash_sha384, CKM_NSS_HKDF_SHA384, 48 },
30
    { ssl_hash_sha512, CKM_NSS_HKDF_SHA512, 64 }
31
};
32
33
SECStatus
34
tls13_HkdfExtract(PK11SymKey *ikm1, PK11SymKey *ikm2in, SSLHashType baseHash,
35
                  PK11SymKey **prkp)
36
0
{
37
0
    CK_NSS_HKDFParams params;
38
0
    SECItem paramsi;
39
0
    SECStatus rv;
40
0
    SECItem *salt;
41
0
    PK11SymKey *prk;
42
0
    static const PRUint8 zeroKeyBuf[HASH_LENGTH_MAX];
43
0
    PK11SymKey *zeroKey = NULL;
44
0
    PK11SlotInfo *slot = NULL;
45
0
    PK11SymKey *ikm2;
46
0
47
0
    params.bExtract = CK_TRUE;
48
0
    params.bExpand = CK_FALSE;
49
0
    params.pInfo = NULL;
50
0
    params.ulInfoLen = 0UL;
51
0
52
0
    if (ikm1) {
53
0
        /* TODO(ekr@rtfm.com): This violates the PKCS#11 key boundary
54
0
         * but is imposed on us by the present HKDF interface. */
55
0
        rv = PK11_ExtractKeyValue(ikm1);
56
0
        if (rv != SECSuccess)
57
0
            return rv;
58
0
59
0
        salt = PK11_GetKeyData(ikm1);
60
0
        if (!salt)
61
0
            return SECFailure;
62
0
63
0
        params.pSalt = salt->data;
64
0
        params.ulSaltLen = salt->len;
65
0
        PORT_Assert(salt->len > 0);
66
0
    } else {
67
0
        /* Per documentation for CKM_NSS_HKDF_*:
68
0
         *
69
0
         *  If the optional salt is given, it is used; otherwise, the salt is
70
0
         *  set to a sequence of zeros equal in length to the HMAC output.
71
0
         */
72
0
        params.pSalt = NULL;
73
0
        params.ulSaltLen = 0UL;
74
0
    }
75
0
    paramsi.data = (unsigned char *)&params;
76
0
    paramsi.len = sizeof(params);
77
0
78
0
    PORT_Assert(kTlsHkdfInfo[baseHash].pkcs11Mech);
79
0
    PORT_Assert(kTlsHkdfInfo[baseHash].hashSize);
80
0
    PORT_Assert(kTlsHkdfInfo[baseHash].hash == baseHash);
81
0
82
0
    /* A zero ikm2 is a key of hash-length 0s. */
83
0
    if (!ikm2in) {
84
0
        SECItem zeroItem = {
85
0
            siBuffer,
86
0
            (unsigned char *)zeroKeyBuf,
87
0
            kTlsHkdfInfo[baseHash].hashSize
88
0
        };
89
0
        slot = PK11_GetInternalSlot();
90
0
        if (!slot) {
91
0
            return SECFailure;
92
0
        }
93
0
        zeroKey = PK11_ImportSymKey(slot,
94
0
                                    kTlsHkdfInfo[baseHash].pkcs11Mech,
95
0
                                    PK11_OriginUnwrap,
96
0
                                    CKA_DERIVE, &zeroItem, NULL);
97
0
        if (!zeroKey)
98
0
            return SECFailure;
99
0
        ikm2 = zeroKey;
100
0
    } else {
101
0
        ikm2 = ikm2in;
102
0
    }
103
0
    PORT_Assert(ikm2);
104
0
105
0
    PRINT_BUF(50, (NULL, "HKDF Extract: IKM1/Salt", params.pSalt, params.ulSaltLen));
106
0
    PRINT_KEY(50, (NULL, "HKDF Extract: IKM2", ikm2));
107
0
108
0
    prk = PK11_Derive(ikm2, kTlsHkdfInfo[baseHash].pkcs11Mech,
109
0
                      &paramsi, kTlsHkdfInfo[baseHash].pkcs11Mech,
110
0
                      CKA_DERIVE, kTlsHkdfInfo[baseHash].hashSize);
111
0
    if (zeroKey)
112
0
        PK11_FreeSymKey(zeroKey);
113
0
    if (slot)
114
0
        PK11_FreeSlot(slot);
115
0
    if (!prk)
116
0
        return SECFailure;
117
0
118
0
    PRINT_KEY(50, (NULL, "HKDF Extract", prk));
119
0
    *prkp = prk;
120
0
121
0
    return SECSuccess;
122
0
}
123
124
SECStatus
125
tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash,
126
                      const PRUint8 *handshakeHash, unsigned int handshakeHashLen,
127
                      const char *label, unsigned int labelLen,
128
                      CK_MECHANISM_TYPE algorithm, unsigned int keySize,
129
                      PK11SymKey **keyp)
130
0
{
131
0
    CK_NSS_HKDFParams params;
132
0
    SECItem paramsi = { siBuffer, NULL, 0 };
133
0
    /* Size of info array needs to be big enough to hold the maximum Prefix,
134
0
     * Label, plus HandshakeHash. If it's ever to small, the code will abort.
135
0
     */
136
0
    PRUint8 info[256];
137
0
    sslBuffer infoBuf = SSL_BUFFER(info);
138
0
    PK11SymKey *derived;
139
0
    SECStatus rv;
140
0
    const char *kLabelPrefix = "tls13 ";
141
0
    const unsigned int kLabelPrefixLen = strlen(kLabelPrefix);
142
0
143
0
    if (handshakeHash) {
144
0
        if (handshakeHashLen > 255) {
145
0
            PORT_Assert(0);
146
0
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
147
0
            return SECFailure;
148
0
        }
149
0
    } else {
150
0
        PORT_Assert(!handshakeHashLen);
151
0
    }
152
0
153
0
    /*
154
0
     *  [draft-ietf-tls-tls13-11] Section 7.1:
155
0
     *
156
0
     *  HKDF-Expand-Label(Secret, Label, HashValue, Length) =
157
0
     *       HKDF-Expand(Secret, HkdfLabel, Length)
158
0
     *
159
0
     *  Where HkdfLabel is specified as:
160
0
     *
161
0
     *  struct HkdfLabel {
162
0
     *    uint16 length;
163
0
     *    opaque label<9..255>;
164
0
     *    opaque hash_value<0..255>;
165
0
     *  };
166
0
     *
167
0
     *  Where:
168
0
     *  - HkdfLabel.length is Length
169
0
     *  - HkdfLabel.hash_value is HashValue.
170
0
     *  - HkdfLabel.label is "TLS 1.3, " + Label
171
0
     *
172
0
     */
173
0
    rv = sslBuffer_AppendNumber(&infoBuf, keySize, 2);
174
0
    if (rv != SECSuccess) {
175
0
        return SECFailure;
176
0
    }
177
0
    rv = sslBuffer_AppendNumber(&infoBuf, labelLen + kLabelPrefixLen, 1);
178
0
    if (rv != SECSuccess) {
179
0
        return SECFailure;
180
0
    }
181
0
    rv = sslBuffer_Append(&infoBuf, kLabelPrefix, kLabelPrefixLen);
182
0
    if (rv != SECSuccess) {
183
0
        return SECFailure;
184
0
    }
185
0
    rv = sslBuffer_Append(&infoBuf, label, labelLen);
186
0
    if (rv != SECSuccess) {
187
0
        return SECFailure;
188
0
    }
189
0
    rv = sslBuffer_AppendVariable(&infoBuf, handshakeHash, handshakeHashLen, 1);
190
0
    if (rv != SECSuccess) {
191
0
        return SECFailure;
192
0
    }
193
0
194
0
    params.bExtract = CK_FALSE;
195
0
    params.bExpand = CK_TRUE;
196
0
    params.pInfo = SSL_BUFFER_BASE(&infoBuf);
197
0
    params.ulInfoLen = SSL_BUFFER_LEN(&infoBuf);
198
0
    paramsi.data = (unsigned char *)&params;
199
0
    paramsi.len = sizeof(params);
200
0
201
0
    derived = PK11_DeriveWithFlags(prk, kTlsHkdfInfo[baseHash].pkcs11Mech,
202
0
                                   &paramsi, algorithm,
203
0
                                   CKA_DERIVE, keySize,
204
0
                                   CKF_SIGN | CKF_VERIFY);
205
0
    if (!derived)
206
0
        return SECFailure;
207
0
208
0
    *keyp = derived;
209
0
210
#ifdef TRACE
211
    if (ssl_trace >= 10) {
212
        /* Make sure the label is null terminated. */
213
        char labelStr[100];
214
        PORT_Memcpy(labelStr, label, labelLen);
215
        labelStr[labelLen] = 0;
216
        SSL_TRC(50, ("HKDF Expand: label='tls13 %s',requested length=%d",
217
                     labelStr, keySize));
218
    }
219
    PRINT_KEY(50, (NULL, "PRK", prk));
220
    PRINT_BUF(50, (NULL, "Hash", handshakeHash, handshakeHashLen));
221
    PRINT_BUF(50, (NULL, "Info", SSL_BUFFER_BASE(&infoBuf),
222
                   SSL_BUFFER_LEN(&infoBuf)));
223
    PRINT_KEY(50, (NULL, "Derived key", derived));
224
#endif
225
226
0
    return SECSuccess;
227
0
}
228
229
SECStatus
230
tls13_HkdfExpandLabelRaw(PK11SymKey *prk, SSLHashType baseHash,
231
                         const PRUint8 *handshakeHash, unsigned int handshakeHashLen,
232
                         const char *label, unsigned int labelLen,
233
                         unsigned char *output, unsigned int outputLen)
234
0
{
235
0
    PK11SymKey *derived = NULL;
236
0
    SECItem *rawkey;
237
0
    SECStatus rv;
238
0
239
0
    rv = tls13_HkdfExpandLabel(prk, baseHash, handshakeHash, handshakeHashLen,
240
0
                               label, labelLen,
241
0
                               kTlsHkdfInfo[baseHash].pkcs11Mech, outputLen,
242
0
                               &derived);
243
0
    if (rv != SECSuccess || !derived) {
244
0
        goto abort;
245
0
    }
246
0
247
0
    rv = PK11_ExtractKeyValue(derived);
248
0
    if (rv != SECSuccess) {
249
0
        goto abort;
250
0
    }
251
0
252
0
    rawkey = PK11_GetKeyData(derived);
253
0
    if (!rawkey) {
254
0
        goto abort;
255
0
    }
256
0
257
0
    PORT_Assert(rawkey->len == outputLen);
258
0
    memcpy(output, rawkey->data, outputLen);
259
0
    PK11_FreeSymKey(derived);
260
0
261
0
    return SECSuccess;
262
0
263
0
abort:
264
0
    if (derived) {
265
0
        PK11_FreeSymKey(derived);
266
0
    }
267
0
    PORT_SetError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE);
268
0
    return SECFailure;
269
0
}