1 /*
2  *  HKDF implementation -- RFC 5869
3  *
4  *  Copyright The Mbed TLS Contributors
5  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6  */
7 #include "common.h"
8 
9 #if defined(MBEDTLS_HKDF_C)
10 
11 #include <string.h>
12 #include "mbedtls/hkdf.h"
13 #include "mbedtls/platform_util.h"
14 #include "mbedtls/error.h"
15 
mbedtls_hkdf(const mbedtls_md_info_t * md,const unsigned char * salt,size_t salt_len,const unsigned char * ikm,size_t ikm_len,const unsigned char * info,size_t info_len,unsigned char * okm,size_t okm_len)16 int mbedtls_hkdf(const mbedtls_md_info_t *md, const unsigned char *salt,
17                  size_t salt_len, const unsigned char *ikm, size_t ikm_len,
18                  const unsigned char *info, size_t info_len,
19                  unsigned char *okm, size_t okm_len)
20 {
21     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
22     unsigned char prk[MBEDTLS_MD_MAX_SIZE];
23 
24     ret = mbedtls_hkdf_extract(md, salt, salt_len, ikm, ikm_len, prk);
25 
26     if (ret == 0) {
27         ret = mbedtls_hkdf_expand(md, prk, mbedtls_md_get_size(md),
28                                   info, info_len, okm, okm_len);
29     }
30 
31     mbedtls_platform_zeroize(prk, sizeof(prk));
32 
33     return ret;
34 }
35 
mbedtls_hkdf_extract(const mbedtls_md_info_t * md,const unsigned char * salt,size_t salt_len,const unsigned char * ikm,size_t ikm_len,unsigned char * prk)36 int mbedtls_hkdf_extract(const mbedtls_md_info_t *md,
37                          const unsigned char *salt, size_t salt_len,
38                          const unsigned char *ikm, size_t ikm_len,
39                          unsigned char *prk)
40 {
41     unsigned char null_salt[MBEDTLS_MD_MAX_SIZE] = { '\0' };
42 
43     if (salt == NULL) {
44         size_t hash_len;
45 
46         if (salt_len != 0) {
47             return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
48         }
49 
50         hash_len = mbedtls_md_get_size(md);
51 
52         if (hash_len == 0) {
53             return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
54         }
55 
56         salt = null_salt;
57         salt_len = hash_len;
58     }
59 
60     return mbedtls_md_hmac(md, salt, salt_len, ikm, ikm_len, prk);
61 }
62 
mbedtls_hkdf_expand(const mbedtls_md_info_t * md,const unsigned char * prk,size_t prk_len,const unsigned char * info,size_t info_len,unsigned char * okm,size_t okm_len)63 int mbedtls_hkdf_expand(const mbedtls_md_info_t *md, const unsigned char *prk,
64                         size_t prk_len, const unsigned char *info,
65                         size_t info_len, unsigned char *okm, size_t okm_len)
66 {
67     size_t hash_len;
68     size_t where = 0;
69     size_t n;
70     size_t t_len = 0;
71     size_t i;
72     int ret = 0;
73     mbedtls_md_context_t ctx;
74     unsigned char t[MBEDTLS_MD_MAX_SIZE];
75 
76     if (okm == NULL) {
77         return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
78     }
79 
80     hash_len = mbedtls_md_get_size(md);
81 
82     if (prk_len < hash_len || hash_len == 0) {
83         return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
84     }
85 
86     if (info == NULL) {
87         info = (const unsigned char *) "";
88         info_len = 0;
89     }
90 
91     n = okm_len / hash_len;
92 
93     if (okm_len % hash_len != 0) {
94         n++;
95     }
96 
97     /*
98      * Per RFC 5869 Section 2.3, okm_len must not exceed
99      * 255 times the hash length
100      */
101     if (n > 255) {
102         return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
103     }
104 
105     mbedtls_md_init(&ctx);
106 
107     if ((ret = mbedtls_md_setup(&ctx, md, 1)) != 0) {
108         goto exit;
109     }
110 
111     memset(t, 0, hash_len);
112 
113     /*
114      * Compute T = T(1) | T(2) | T(3) | ... | T(N)
115      * Where T(N) is defined in RFC 5869 Section 2.3
116      */
117     for (i = 1; i <= n; i++) {
118         size_t num_to_copy;
119         unsigned char c = i & 0xff;
120 
121         ret = mbedtls_md_hmac_starts(&ctx, prk, prk_len);
122         if (ret != 0) {
123             goto exit;
124         }
125 
126         ret = mbedtls_md_hmac_update(&ctx, t, t_len);
127         if (ret != 0) {
128             goto exit;
129         }
130 
131         ret = mbedtls_md_hmac_update(&ctx, info, info_len);
132         if (ret != 0) {
133             goto exit;
134         }
135 
136         /* The constant concatenated to the end of each T(n) is a single octet.
137          * */
138         ret = mbedtls_md_hmac_update(&ctx, &c, 1);
139         if (ret != 0) {
140             goto exit;
141         }
142 
143         ret = mbedtls_md_hmac_finish(&ctx, t);
144         if (ret != 0) {
145             goto exit;
146         }
147 
148         num_to_copy = i != n ? hash_len : okm_len - where;
149         memcpy(okm + where, t, num_to_copy);
150         where += hash_len;
151         t_len = hash_len;
152     }
153 
154 exit:
155     mbedtls_md_free(&ctx);
156     mbedtls_platform_zeroize(t, sizeof(t));
157 
158     return ret;
159 }
160 
161 #endif /* MBEDTLS_HKDF_C */
162