Coverage Report

Created: 2022-08-24 06:25

/src/wolfssl-openssl-api/wolfcrypt/src/kdf.c
Line
Count
Source (jump to first uncovered line)
1
/* kdf.c
2
 *
3
 * Copyright (C) 2006-2022 wolfSSL Inc.
4
 *
5
 * This file is part of wolfSSL.
6
 *
7
 * wolfSSL is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * wolfSSL is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20
 */
21
22
23
#ifdef HAVE_CONFIG_H
24
    #include <config.h>
25
#endif
26
27
#include <wolfssl/wolfcrypt/wc_port.h>
28
#include <wolfssl/wolfcrypt/error-crypt.h>
29
#include <wolfssl/wolfcrypt/logging.h>
30
31
#ifndef NO_KDF
32
33
#if defined(HAVE_FIPS) && \
34
    defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 5)
35
36
    /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
37
    #define FIPS_NO_WRAPPERS
38
39
    #ifdef USE_WINDOWS_API
40
        #pragma code_seg(".fipsA$m")
41
        #pragma const_seg(".fipsB$m")
42
    #endif
43
#endif
44
45
46
#ifdef NO_INLINE
47
    #include <wolfssl/wolfcrypt/misc.h>
48
#else
49
    #define WOLFSSL_MISC_INCLUDED
50
    #include <wolfcrypt/src/misc.c>
51
#endif
52
53
#include <wolfssl/wolfcrypt/hmac.h>
54
#include <wolfssl/wolfcrypt/kdf.h>
55
56
57
#ifdef WOLFSSL_HAVE_PRF
58
59
#ifdef WOLFSSL_SHA512
60
0
    #define P_HASH_MAX_SIZE WC_SHA512_DIGEST_SIZE
61
#elif defined(WOLFSSL_SHA384)
62
    #define P_HASH_MAX_SIZE WC_SHA384_DIGEST_SIZE
63
#else
64
    #define P_HASH_MAX_SIZE WC_SHA256_DIGEST_SIZE
65
#endif
66
67
/* Pseudo Random Function for MD5, SHA-1, SHA-256, SHA-384, or SHA-512 */
68
int wc_PRF(byte* result, word32 resLen, const byte* secret,
69
                  word32 secLen, const byte* seed, word32 seedLen, int hash,
70
                  void* heap, int devId)
71
0
{
72
0
    word32 len = P_HASH_MAX_SIZE;
73
0
    word32 times;
74
0
    word32 lastLen;
75
0
    word32 lastTime;
76
0
    word32 i;
77
0
    word32 idx = 0;
78
0
    int    ret = 0;
79
0
#ifdef WOLFSSL_SMALL_STACK
80
0
    byte*  previous;
81
0
    byte*  current;
82
0
    Hmac*  hmac;
83
#else
84
    byte   previous[P_HASH_MAX_SIZE];  /* max size */
85
    byte   current[P_HASH_MAX_SIZE];   /* max size */
86
    Hmac   hmac[1];
87
#endif
88
89
0
#ifdef WOLFSSL_SMALL_STACK
90
0
    previous = (byte*)XMALLOC(P_HASH_MAX_SIZE, heap, DYNAMIC_TYPE_DIGEST);
91
0
    current  = (byte*)XMALLOC(P_HASH_MAX_SIZE, heap, DYNAMIC_TYPE_DIGEST);
92
0
    hmac     = (Hmac*)XMALLOC(sizeof(Hmac),    heap, DYNAMIC_TYPE_HMAC);
93
94
0
    if (previous == NULL || current == NULL || hmac == NULL) {
95
0
        if (previous) XFREE(previous, heap, DYNAMIC_TYPE_DIGEST);
96
0
        if (current)  XFREE(current,  heap, DYNAMIC_TYPE_DIGEST);
97
0
        if (hmac)     XFREE(hmac,     heap, DYNAMIC_TYPE_HMAC);
98
99
0
        return MEMORY_E;
100
0
    }
101
0
#endif
102
103
#ifdef WOLFSSL_CHECK_MEM_ZERO
104
    wc_MemZero_Add("wc_PRF previous", previous, P_HASH_MAX_SIZE);
105
    wc_MemZero_Add("wc_PRF current", current, P_HASH_MAX_SIZE);
106
    wc_MemZero_Add("wc_PRF hmac", hmac, sizeof(Hmac));
107
#endif
108
109
0
    switch (hash) {
110
0
    #ifndef NO_MD5
111
0
        case md5_mac:
112
0
            hash = WC_MD5;
113
0
            len  = WC_MD5_DIGEST_SIZE;
114
0
        break;
115
0
    #endif
116
117
0
    #ifndef NO_SHA256
118
0
        case sha256_mac:
119
0
            hash = WC_SHA256;
120
0
            len  = WC_SHA256_DIGEST_SIZE;
121
0
        break;
122
0
    #endif
123
124
0
    #ifdef WOLFSSL_SHA384
125
0
        case sha384_mac:
126
0
            hash = WC_SHA384;
127
0
            len  = WC_SHA384_DIGEST_SIZE;
128
0
        break;
129
0
    #endif
130
131
0
    #ifdef WOLFSSL_SHA512
132
0
        case sha512_mac:
133
0
            hash = WC_SHA512;
134
0
            len  = WC_SHA512_DIGEST_SIZE;
135
0
        break;
136
0
    #endif
137
138
0
    #ifndef NO_SHA
139
0
        case sha_mac:
140
0
            hash = WC_SHA;
141
0
            len  = WC_SHA_DIGEST_SIZE;
142
0
        break;
143
0
    #endif
144
0
        default:
145
0
        #ifdef WOLFSSL_SMALL_STACK
146
0
            if (previous) XFREE(previous, heap, DYNAMIC_TYPE_DIGEST);
147
0
            if (current)  XFREE(current,  heap, DYNAMIC_TYPE_DIGEST);
148
0
            if (hmac)     XFREE(hmac,     heap, DYNAMIC_TYPE_HMAC);
149
0
        #endif
150
0
            return HASH_TYPE_E;
151
0
    }
152
153
0
    times   = resLen / len;
154
0
    lastLen = resLen % len;
155
156
0
    if (lastLen)
157
0
        times += 1;
158
159
    /* times == 0 iif resLen == 0, but times == 0 abides clang static analyzer
160
       while resLen == 0 doesn't */
161
0
    if (times == 0)
162
0
        return BAD_FUNC_ARG;
163
164
0
    lastTime = times - 1;
165
166
0
    ret = wc_HmacInit(hmac, heap, devId);
167
0
    if (ret == 0) {
168
0
        ret = wc_HmacSetKey(hmac, hash, secret, secLen);
169
0
        if (ret == 0)
170
0
            ret = wc_HmacUpdate(hmac, seed, seedLen); /* A0 = seed */
171
0
        if (ret == 0)
172
0
            ret = wc_HmacFinal(hmac, previous);       /* A1 */
173
0
        if (ret == 0) {
174
0
            for (i = 0; i < times; i++) {
175
0
                ret = wc_HmacUpdate(hmac, previous, len);
176
0
                if (ret != 0)
177
0
                    break;
178
0
                ret = wc_HmacUpdate(hmac, seed, seedLen);
179
0
                if (ret != 0)
180
0
                    break;
181
0
                ret = wc_HmacFinal(hmac, current);
182
0
                if (ret != 0)
183
0
                    break;
184
185
0
                if ((i == lastTime) && lastLen)
186
0
                    XMEMCPY(&result[idx], current,
187
0
                                             min(lastLen, P_HASH_MAX_SIZE));
188
0
                else {
189
0
                    XMEMCPY(&result[idx], current, len);
190
0
                    idx += len;
191
0
                    ret = wc_HmacUpdate(hmac, previous, len);
192
0
                    if (ret != 0)
193
0
                        break;
194
0
                    ret = wc_HmacFinal(hmac, previous);
195
0
                    if (ret != 0)
196
0
                        break;
197
0
                }
198
0
            }
199
0
        }
200
0
        wc_HmacFree(hmac);
201
0
    }
202
203
0
    ForceZero(previous,  P_HASH_MAX_SIZE);
204
0
    ForceZero(current,   P_HASH_MAX_SIZE);
205
0
    ForceZero(hmac,      sizeof(Hmac));
206
207
0
#ifdef WOLFSSL_SMALL_STACK
208
0
    XFREE(previous, heap, DYNAMIC_TYPE_DIGEST);
209
0
    XFREE(current,  heap, DYNAMIC_TYPE_DIGEST);
210
0
    XFREE(hmac,     heap, DYNAMIC_TYPE_HMAC);
211
#elif defined(WOLFSSL_CHECK_MEM_ZERO)
212
    wc_MemZero_Check(previous, P_HASH_MAX_SIZE);
213
    wc_MemZero_Check(current,  P_HASH_MAX_SIZE);
214
    wc_MemZero_Check(hmac,     sizeof(Hmac));
215
#endif
216
217
0
    return ret;
218
0
}
219
#undef P_HASH_MAX_SIZE
220
221
/* compute PRF (pseudo random function) using SHA1 and MD5 for TLSv1 */
222
int wc_PRF_TLSv1(byte* digest, word32 digLen, const byte* secret,
223
           word32 secLen, const byte* label, word32 labLen,
224
           const byte* seed, word32 seedLen, void* heap, int devId)
225
0
{
226
0
    int         ret  = 0;
227
0
    word32      half = (secLen + 1) / 2;
228
229
0
    const byte* md5_half;
230
0
    const byte* sha_half;
231
0
    byte*      md5_result;
232
0
#ifdef WOLFSSL_SMALL_STACK
233
0
    byte*      sha_result;
234
#else
235
    byte       sha_result[MAX_PRF_DIG];    /* digLen is real size */
236
#endif
237
0
#if !defined(WOLFSSL_ASYNC_CRYPT) || defined(WC_ASYNC_NO_HASH)
238
0
    byte       labelSeed[MAX_PRF_LABSEED];
239
#else
240
    WC_DECLARE_VAR(labelSeed, byte, MAX_PRF_LABSEED, heap);
241
    if (labelSeed == NULL)
242
        return MEMORY_E;
243
#endif
244
245
0
    if (half > MAX_PRF_HALF ||
246
0
        labLen + seedLen > MAX_PRF_LABSEED ||
247
0
        digLen > MAX_PRF_DIG)
248
0
    {
249
    #if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
250
        WC_FREE_VAR(labelSeed, heap);
251
    #endif
252
0
        return BUFFER_E;
253
0
    }
254
255
0
#ifdef WOLFSSL_SMALL_STACK
256
0
    sha_result = (byte*)XMALLOC(MAX_PRF_DIG, heap, DYNAMIC_TYPE_DIGEST);
257
0
    if (sha_result == NULL) {
258
    #if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
259
        WC_FREE_VAR(labelSeed, heap);
260
    #endif
261
0
        return MEMORY_E;
262
0
    }
263
0
#endif
264
265
0
    md5_half = secret;
266
0
    sha_half = secret + half - secLen % 2;
267
0
    md5_result = digest;
268
269
0
    XMEMCPY(labelSeed, label, labLen);
270
0
    XMEMCPY(labelSeed + labLen, seed, seedLen);
271
272
0
    if ((ret = wc_PRF(md5_result, digLen, md5_half, half, labelSeed,
273
0
                                labLen + seedLen, md5_mac, heap, devId)) == 0) {
274
0
        if ((ret = wc_PRF(sha_result, digLen, sha_half, half, labelSeed,
275
0
                                labLen + seedLen, sha_mac, heap, devId)) == 0) {
276
        #ifdef WOLFSSL_CHECK_MEM_ZERO
277
            wc_MemZero_Add("wc_PRF_TLSv1 sha_result", sha_result, digLen);
278
        #endif
279
            /* calculate XOR for TLSv1 PRF */
280
            /* md5 result is placed directly in digest */
281
0
            xorbuf(digest, sha_result, digLen);
282
0
            ForceZero(sha_result, digLen);
283
0
        }
284
0
    }
285
286
0
#ifdef WOLFSSL_SMALL_STACK
287
0
    XFREE(sha_result, heap, DYNAMIC_TYPE_DIGEST);
288
#elif defined(WOLFSSL_CHECK_MEM_ZERO)
289
    wc_MemZero_Check(sha_result, MAX_PRF_DIG);
290
#endif
291
292
#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
293
    WC_FREE_VAR(labelSeed, heap);
294
#endif
295
296
0
    return ret;
297
0
}
298
299
/* Wrapper for TLS 1.2 and TLSv1 cases to calculate PRF */
300
/* In TLS 1.2 case call straight thru to wc_PRF */
301
int wc_PRF_TLS(byte* digest, word32 digLen, const byte* secret, word32 secLen,
302
            const byte* label, word32 labLen, const byte* seed, word32 seedLen,
303
            int useAtLeastSha256, int hash_type, void* heap, int devId)
304
0
{
305
0
    int ret = 0;
306
307
0
    if (useAtLeastSha256) {
308
    #if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
309
        WC_DECLARE_VAR(labelSeed, byte, MAX_PRF_LABSEED, heap);
310
        if (labelSeed == NULL)
311
            return MEMORY_E;
312
    #else
313
0
        byte labelSeed[MAX_PRF_LABSEED];
314
0
    #endif
315
316
0
        if (labLen + seedLen > MAX_PRF_LABSEED)
317
0
            return BUFFER_E;
318
319
0
        XMEMCPY(labelSeed, label, labLen);
320
0
        XMEMCPY(labelSeed + labLen, seed, seedLen);
321
322
        /* If a cipher suite wants an algorithm better than sha256, it
323
         * should use better. */
324
0
        if (hash_type < sha256_mac || hash_type == blake2b_mac)
325
0
            hash_type = sha256_mac;
326
        /* compute PRF for MD5, SHA-1, SHA-256, or SHA-384 for TLSv1.2 PRF */
327
0
        ret = wc_PRF(digest, digLen, secret, secLen, labelSeed,
328
0
                     labLen + seedLen, hash_type, heap, devId);
329
330
    #if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
331
        WC_FREE_VAR(labelSeed, heap);
332
    #endif
333
0
    }
334
0
    else {
335
0
#ifndef NO_OLD_TLS
336
        /* compute TLSv1 PRF (pseudo random function using HMAC) */
337
0
        ret = wc_PRF_TLSv1(digest, digLen, secret, secLen, label, labLen, seed,
338
0
                          seedLen, heap, devId);
339
#else
340
        ret = BAD_FUNC_ARG;
341
#endif
342
0
    }
343
344
345
0
    return ret;
346
0
}
347
#endif /* WOLFSSL_HAVE_PRF */
348
349
350
#if defined(HAVE_HKDF) && !defined(NO_HMAC)
351
352
    /* Extract data using HMAC, salt and input.
353
     * RFC 5869 - HMAC-based Extract-and-Expand Key Derivation Function (HKDF)
354
     *
355
     * prk      The generated pseudorandom key.
356
     * salt     The salt.
357
     * saltLen  The length of the salt.
358
     * ikm      The input keying material.
359
     * ikmLen   The length of the input keying material.
360
     * digest   The type of digest to use.
361
     * returns 0 on success, otherwise failure.
362
     */
363
    int wc_Tls13_HKDF_Extract(byte* prk, const byte* salt, int saltLen,
364
                                 byte* ikm, int ikmLen, int digest)
365
0
    {
366
0
        int ret;
367
0
        int len = 0;
368
369
0
        switch (digest) {
370
0
            #ifndef NO_SHA256
371
0
            case WC_SHA256:
372
0
                len = WC_SHA256_DIGEST_SIZE;
373
0
                break;
374
0
            #endif
375
376
0
            #ifdef WOLFSSL_SHA384
377
0
            case WC_SHA384:
378
0
                len = WC_SHA384_DIGEST_SIZE;
379
0
                break;
380
0
            #endif
381
382
            #ifdef WOLFSSL_TLS13_SHA512
383
            case WC_SHA512:
384
                len = WC_SHA512_DIGEST_SIZE;
385
                break;
386
            #endif
387
0
            default:
388
0
                return BAD_FUNC_ARG;
389
0
        }
390
391
        /* When length is 0 then use zeroed data of digest length. */
392
0
        if (ikmLen == 0) {
393
0
            ikmLen = len;
394
0
            XMEMSET(ikm, 0, len);
395
0
        }
396
397
#ifdef WOLFSSL_DEBUG_TLS
398
        WOLFSSL_MSG("  Salt");
399
        WOLFSSL_BUFFER(salt, saltLen);
400
        WOLFSSL_MSG("  IKM");
401
        WOLFSSL_BUFFER(ikm, ikmLen);
402
#endif
403
404
0
        ret = wc_HKDF_Extract(digest, salt, saltLen, ikm, ikmLen, prk);
405
406
#ifdef WOLFSSL_DEBUG_TLS
407
        WOLFSSL_MSG("  PRK");
408
        WOLFSSL_BUFFER(prk, len);
409
#endif
410
411
0
        return ret;
412
0
    }
413
414
    /* Expand data using HMAC, salt and label and info.
415
     * TLS v1.3 defines this function.
416
     *
417
     * okm          The generated pseudorandom key - output key material.
418
     * okmLen       The length of generated pseudorandom key -
419
     *              output key material.
420
     * prk          The salt - pseudo-random key.
421
     * prkLen       The length of the salt - pseudo-random key.
422
     * protocol     The TLS protocol label.
423
     * protocolLen  The length of the TLS protocol label.
424
     * info         The information to expand.
425
     * infoLen      The length of the information.
426
     * digest       The type of digest to use.
427
     * returns 0 on success, otherwise failure.
428
     */
429
    int wc_Tls13_HKDF_Expand_Label(byte* okm, word32 okmLen,
430
                                 const byte* prk, word32 prkLen,
431
                                 const byte* protocol, word32 protocolLen,
432
                                 const byte* label, word32 labelLen,
433
                                 const byte* info, word32 infoLen,
434
                                 int digest)
435
0
    {
436
0
        int    ret = 0;
437
0
        int    idx = 0;
438
0
        byte   data[MAX_TLS13_HKDF_LABEL_SZ];
439
440
        /* Output length. */
441
0
        data[idx++] = (byte)(okmLen >> 8);
442
0
        data[idx++] = (byte)okmLen;
443
        /* Length of protocol | label. */
444
0
        data[idx++] = (byte)(protocolLen + labelLen);
445
        /* Protocol */
446
0
        XMEMCPY(&data[idx], protocol, protocolLen);
447
0
        idx += protocolLen;
448
        /* Label */
449
0
        XMEMCPY(&data[idx], label, labelLen);
450
0
        idx += labelLen;
451
        /* Length of hash of messages */
452
0
        data[idx++] = (byte)infoLen;
453
        /* Hash of messages */
454
0
        XMEMCPY(&data[idx], info, infoLen);
455
0
        idx += infoLen;
456
457
    #ifdef WOLFSSL_CHECK_MEM_ZERO
458
        wc_MemZero_Add("wc_Tls13_HKDF_Expand_Label data", data, idx);
459
    #endif
460
461
#ifdef WOLFSSL_DEBUG_TLS
462
        WOLFSSL_MSG("  PRK");
463
        WOLFSSL_BUFFER(prk, prkLen);
464
        WOLFSSL_MSG("  Info");
465
        WOLFSSL_BUFFER(data, idx);
466
        WOLFSSL_MSG_EX("  Digest %d", digest);
467
#endif
468
469
0
        ret = wc_HKDF_Expand(digest, prk, prkLen, data, idx, okm, okmLen);
470
471
#ifdef WOLFSSL_DEBUG_TLS
472
        WOLFSSL_MSG("  OKM");
473
        WOLFSSL_BUFFER(okm, okmLen);
474
#endif
475
476
0
        ForceZero(data, idx);
477
478
    #ifdef WOLFSSL_CHECK_MEM_ZERO
479
        wc_MemZero_Check(data, MAX_TLS13_HKDF_LABEL_SZ);
480
    #endif
481
0
        return ret;
482
0
    }
483
484
#endif /* HAVE_HKDF && !NO_HMAC */
485
486
487
#ifdef WOLFSSL_WOLFSSH
488
489
/* hash union */
490
typedef union {
491
#ifndef NO_MD5
492
    wc_Md5 md5;
493
#endif
494
#ifndef NO_SHA
495
    wc_Sha sha;
496
#endif
497
#ifdef WOLFSSL_SHA224
498
    wc_Sha224 sha224;
499
#endif
500
#ifndef NO_SHA256
501
    wc_Sha256 sha256;
502
#endif
503
#ifdef WOLFSSL_SHA384
504
    wc_Sha384 sha384;
505
#endif
506
#ifdef WOLFSSL_SHA512
507
    wc_Sha512 sha512;
508
#endif
509
#ifdef WOLFSSL_SHA3
510
    wc_Sha3 sha3;
511
#endif
512
} _hash;
513
514
static
515
int _HashInit(byte hashId, _hash* hash)
516
{
517
    int ret = BAD_FUNC_ARG;
518
519
    switch (hashId) {
520
    #ifndef NO_SHA
521
        case WC_SHA:
522
            ret = wc_InitSha(&hash->sha);
523
            break;
524
    #endif /* !NO_SHA */
525
526
    #ifndef NO_SHA256
527
        case WC_SHA256:
528
            ret = wc_InitSha256(&hash->sha256);
529
            break;
530
    #endif /* !NO_SHA256 */
531
532
    #ifdef WOLFSSL_SHA384
533
        case WC_SHA384:
534
            ret = wc_InitSha384(&hash->sha384);
535
            break;
536
    #endif /* WOLFSSL_SHA384 */
537
    #ifdef WOLFSSL_SHA512
538
        case WC_SHA512:
539
            ret = wc_InitSha512(&hash->sha512);
540
            break;
541
    #endif /* WOLFSSL_SHA512 */
542
    }
543
544
    return ret;
545
}
546
547
static
548
int _HashUpdate(byte hashId, _hash* hash,
549
        const byte* data, word32 dataSz)
550
{
551
    int ret = BAD_FUNC_ARG;
552
553
    switch (hashId) {
554
    #ifndef NO_SHA
555
        case WC_SHA:
556
            ret = wc_ShaUpdate(&hash->sha, data, dataSz);
557
            break;
558
    #endif /* !NO_SHA */
559
560
    #ifndef NO_SHA256
561
        case WC_SHA256:
562
            ret = wc_Sha256Update(&hash->sha256, data, dataSz);
563
            break;
564
    #endif /* !NO_SHA256 */
565
566
    #ifdef WOLFSSL_SHA384
567
        case WC_SHA384:
568
            ret = wc_Sha384Update(&hash->sha384, data, dataSz);
569
            break;
570
    #endif /* WOLFSSL_SHA384 */
571
    #ifdef WOLFSSL_SHA512
572
        case WC_SHA512:
573
            ret = wc_Sha512Update(&hash->sha512, data, dataSz);
574
            break;
575
    #endif /* WOLFSSL_SHA512 */
576
    }
577
578
    return ret;
579
}
580
581
static
582
int _HashFinal(byte hashId, _hash* hash, byte* digest)
583
{
584
    int ret = BAD_FUNC_ARG;
585
586
    switch (hashId) {
587
    #ifndef NO_SHA
588
        case WC_SHA:
589
            ret = wc_ShaFinal(&hash->sha, digest);
590
            break;
591
    #endif /* !NO_SHA */
592
593
    #ifndef NO_SHA256
594
        case WC_SHA256:
595
            ret = wc_Sha256Final(&hash->sha256, digest);
596
            break;
597
    #endif /* !NO_SHA256 */
598
599
    #ifdef WOLFSSL_SHA384
600
        case WC_SHA384:
601
            ret = wc_Sha384Final(&hash->sha384, digest);
602
            break;
603
    #endif /* WOLFSSL_SHA384 */
604
    #ifdef WOLFSSL_SHA512
605
        case WC_SHA512:
606
            ret = wc_Sha512Final(&hash->sha512, digest);
607
            break;
608
    #endif /* WOLFSSL_SHA512 */
609
    }
610
611
    return ret;
612
}
613
614
static
615
void _HashFree(byte hashId, _hash* hash)
616
{
617
    switch (hashId) {
618
    #ifndef NO_SHA
619
        case WC_SHA:
620
            wc_ShaFree(&hash->sha);
621
            break;
622
    #endif /* !NO_SHA */
623
624
    #ifndef NO_SHA256
625
        case WC_SHA256:
626
            wc_Sha256Free(&hash->sha256);
627
            break;
628
    #endif /* !NO_SHA256 */
629
630
    #ifdef WOLFSSL_SHA384
631
        case WC_SHA384:
632
            wc_Sha384Free(&hash->sha384);
633
            break;
634
    #endif /* WOLFSSL_SHA384 */
635
    #ifdef WOLFSSL_SHA512
636
        case WC_SHA512:
637
            wc_Sha512Free(&hash->sha512);
638
            break;
639
    #endif /* WOLFSSL_SHA512 */
640
    }
641
}
642
643
644
#define LENGTH_SZ 4
645
646
int wc_SSH_KDF(byte hashId, byte keyId, byte* key, word32 keySz,
647
        const byte* k, word32 kSz, const byte* h, word32 hSz,
648
        const byte* sessionId, word32 sessionIdSz)
649
{
650
    word32 blocks, remainder;
651
    _hash hash;
652
    enum wc_HashType enmhashId = (enum wc_HashType)hashId;
653
    byte kPad = 0;
654
    byte pad = 0;
655
    byte kSzFlat[LENGTH_SZ];
656
    int digestSz;
657
    int ret;
658
659
    if (key == NULL || keySz == 0 ||
660
        k == NULL || kSz == 0 ||
661
        h == NULL || hSz == 0 ||
662
        sessionId == NULL || sessionIdSz == 0) {
663
664
        return BAD_FUNC_ARG;
665
    }
666
667
    digestSz = wc_HmacSizeByType(enmhashId);
668
    if (digestSz < 0) {
669
        return BAD_FUNC_ARG;
670
    }
671
672
    if (k[0] & 0x80) kPad = 1;
673
    c32toa(kSz + kPad, kSzFlat);
674
675
    blocks = keySz / digestSz;
676
    remainder = keySz % digestSz;
677
678
    ret = _HashInit(enmhashId, &hash);
679
    if (ret == 0)
680
        ret = _HashUpdate(enmhashId, &hash, kSzFlat, LENGTH_SZ);
681
    if (ret == 0 && kPad)
682
        ret = _HashUpdate(enmhashId, &hash, &pad, 1);
683
    if (ret == 0)
684
        ret = _HashUpdate(enmhashId, &hash, k, kSz);
685
    if (ret == 0)
686
        ret = _HashUpdate(enmhashId, &hash, h, hSz);
687
    if (ret == 0)
688
        ret = _HashUpdate(enmhashId, &hash, &keyId, sizeof(keyId));
689
    if (ret == 0)
690
        ret = _HashUpdate(enmhashId, &hash, sessionId, sessionIdSz);
691
692
    if (ret == 0) {
693
        if (blocks == 0) {
694
            if (remainder > 0) {
695
                byte lastBlock[WC_MAX_DIGEST_SIZE];
696
                ret = _HashFinal(enmhashId, &hash, lastBlock);
697
                if (ret == 0)
698
                    XMEMCPY(key, lastBlock, remainder);
699
            }
700
        }
701
        else {
702
            word32 runningKeySz, curBlock;
703
704
            runningKeySz = digestSz;
705
            ret = _HashFinal(enmhashId, &hash, key);
706
707
            for (curBlock = 1; curBlock < blocks; curBlock++) {
708
                ret = _HashInit(enmhashId, &hash);
709
                if (ret != 0) break;
710
                ret = _HashUpdate(enmhashId, &hash, kSzFlat, LENGTH_SZ);
711
                if (ret != 0) break;
712
                if (kPad)
713
                    ret = _HashUpdate(enmhashId, &hash, &pad, 1);
714
                if (ret != 0) break;
715
                ret = _HashUpdate(enmhashId, &hash, k, kSz);
716
                if (ret != 0) break;
717
                ret = _HashUpdate(enmhashId, &hash, h, hSz);
718
                if (ret != 0) break;
719
                ret = _HashUpdate(enmhashId, &hash, key, runningKeySz);
720
                if (ret != 0) break;
721
                ret = _HashFinal(enmhashId, &hash, key + runningKeySz);
722
                if (ret != 0) break;
723
                runningKeySz += digestSz;
724
            }
725
726
            if (remainder > 0) {
727
                byte lastBlock[WC_MAX_DIGEST_SIZE];
728
                if (ret == 0)
729
                    ret = _HashInit(enmhashId, &hash);
730
                if (ret == 0)
731
                    ret = _HashUpdate(enmhashId, &hash, kSzFlat, LENGTH_SZ);
732
                if (ret == 0 && kPad)
733
                    ret = _HashUpdate(enmhashId, &hash, &pad, 1);
734
                if (ret == 0)
735
                    ret = _HashUpdate(enmhashId, &hash, k, kSz);
736
                if (ret == 0)
737
                    ret = _HashUpdate(enmhashId, &hash, h, hSz);
738
                if (ret == 0)
739
                    ret = _HashUpdate(enmhashId, &hash, key, runningKeySz);
740
                if (ret == 0)
741
                    ret = _HashFinal(enmhashId, &hash, lastBlock);
742
                if (ret == 0)
743
                    XMEMCPY(key + runningKeySz, lastBlock, remainder);
744
            }
745
        }
746
    }
747
748
    _HashFree(enmhashId, &hash);
749
750
    return ret;
751
}
752
753
#endif /* WOLFSSL_WOLFSSH */
754
755
#endif /* NO_KDF */