blob: 0e9da59a9a9f9f1d09eb2784d64f29f762fd4857 [file] [log] [blame]
Thomas Fossati656864b2016-07-17 08:51:22 +01001/*
2 * HKDF implementation -- RFC 5869
3 *
4 * Copyright (C) 2016-2018, ARM Limited, All Rights Reserved
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 * This file is part of mbed TLS (https://tls.mbed.org)
20 */
Gilles Peskinedb09ef62020-06-03 01:43:33 +020021#include "common.h"
Thomas Fossati656864b2016-07-17 08:51:22 +010022
23#if defined(MBEDTLS_HKDF_C)
24
25#include <string.h>
26#include "mbedtls/hkdf.h"
27#include "mbedtls/platform_util.h"
Janos Follath24eed8d2019-11-22 13:21:35 +000028#include "mbedtls/error.h"
Thomas Fossati656864b2016-07-17 08:51:22 +010029
30int mbedtls_hkdf( const mbedtls_md_info_t *md, const unsigned char *salt,
31 size_t salt_len, const unsigned char *ikm, size_t ikm_len,
32 const unsigned char *info, size_t info_len,
33 unsigned char *okm, size_t okm_len )
34{
Janos Follath24eed8d2019-11-22 13:21:35 +000035 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Thomas Fossati656864b2016-07-17 08:51:22 +010036 unsigned char prk[MBEDTLS_MD_MAX_SIZE];
37
38 ret = mbedtls_hkdf_extract( md, salt, salt_len, ikm, ikm_len, prk );
39
40 if( ret == 0 )
41 {
42 ret = mbedtls_hkdf_expand( md, prk, mbedtls_md_get_size( md ),
43 info, info_len, okm, okm_len );
44 }
45
46 mbedtls_platform_zeroize( prk, sizeof( prk ) );
47
48 return( ret );
49}
50
51int mbedtls_hkdf_extract( const mbedtls_md_info_t *md,
52 const unsigned char *salt, size_t salt_len,
53 const unsigned char *ikm, size_t ikm_len,
54 unsigned char *prk )
55{
56 unsigned char null_salt[MBEDTLS_MD_MAX_SIZE] = { '\0' };
57
58 if( salt == NULL )
59 {
60 size_t hash_len;
61
Brian J Murrayca2ea4e2018-07-06 10:03:58 -070062 if( salt_len != 0 )
63 {
64 return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
65 }
66
Thomas Fossati656864b2016-07-17 08:51:22 +010067 hash_len = mbedtls_md_get_size( md );
68
69 if( hash_len == 0 )
70 {
71 return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
72 }
73
74 salt = null_salt;
75 salt_len = hash_len;
76 }
77
78 return( mbedtls_md_hmac( md, salt, salt_len, ikm, ikm_len, prk ) );
79}
80
81int mbedtls_hkdf_expand( const mbedtls_md_info_t *md, const unsigned char *prk,
82 size_t prk_len, const unsigned char *info,
83 size_t info_len, unsigned char *okm, size_t okm_len )
84{
85 size_t hash_len;
86 size_t where = 0;
87 size_t n;
88 size_t t_len = 0;
89 size_t i;
90 int ret = 0;
91 mbedtls_md_context_t ctx;
92 unsigned char t[MBEDTLS_MD_MAX_SIZE];
93
94 if( okm == NULL )
95 {
96 return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA );
97 }
98
99 hash_len = mbedtls_md_get_size( md );
100
101 if( prk_len < hash_len || hash_len == 0 )
102 {
103 return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA );
104 }
105
106 if( info == NULL )
107 {
108 info = (const unsigned char *) "";
109 info_len = 0;
110 }
111
112 n = okm_len / hash_len;
113
Gilles Peskine60d65162020-04-02 19:50:00 +0200114 if( okm_len % hash_len != 0 )
Thomas Fossati656864b2016-07-17 08:51:22 +0100115 {
116 n++;
117 }
118
Brian J Murraya61d1232018-07-06 10:02:39 -0700119 /*
120 * Per RFC 5869 Section 2.3, okm_len must not exceed
121 * 255 times the hash length
122 */
Thomas Fossati656864b2016-07-17 08:51:22 +0100123 if( n > 255 )
124 {
125 return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA );
126 }
127
128 mbedtls_md_init( &ctx );
129
Gilles Peskine60d65162020-04-02 19:50:00 +0200130 if( ( ret = mbedtls_md_setup( &ctx, md, 1 ) ) != 0 )
Thomas Fossati656864b2016-07-17 08:51:22 +0100131 {
132 goto exit;
133 }
134
Gilles Peskine3ab121a2020-04-02 19:51:05 +0200135 memset( t, 0, hash_len );
136
Brian J Murraya61d1232018-07-06 10:02:39 -0700137 /*
138 * Compute T = T(1) | T(2) | T(3) | ... | T(N)
139 * Where T(N) is defined in RFC 5869 Section 2.3
140 */
Thomas Fossati656864b2016-07-17 08:51:22 +0100141 for( i = 1; i <= n; i++ )
142 {
143 size_t num_to_copy;
144 unsigned char c = i & 0xff;
145
146 ret = mbedtls_md_hmac_starts( &ctx, prk, prk_len );
147 if( ret != 0 )
148 {
149 goto exit;
150 }
151
152 ret = mbedtls_md_hmac_update( &ctx, t, t_len );
153 if( ret != 0 )
154 {
155 goto exit;
156 }
157
158 ret = mbedtls_md_hmac_update( &ctx, info, info_len );
159 if( ret != 0 )
160 {
161 goto exit;
162 }
163
Brian J Murraya61d1232018-07-06 10:02:39 -0700164 /* The constant concatenated to the end of each T(n) is a single octet.
Thomas Fossati656864b2016-07-17 08:51:22 +0100165 * */
166 ret = mbedtls_md_hmac_update( &ctx, &c, 1 );
167 if( ret != 0 )
168 {
169 goto exit;
170 }
171
172 ret = mbedtls_md_hmac_finish( &ctx, t );
173 if( ret != 0 )
174 {
175 goto exit;
176 }
177
178 num_to_copy = i != n ? hash_len : okm_len - where;
179 memcpy( okm + where, t, num_to_copy );
180 where += hash_len;
181 t_len = hash_len;
182 }
183
184exit:
185 mbedtls_md_free( &ctx );
186 mbedtls_platform_zeroize( t, sizeof( t ) );
187
188 return( ret );
189}
190
191#endif /* MBEDTLS_HKDF_C */