xref: /optee_os/lib/libmbedtls/mbedtls/library/hmac_drbg.c (revision 7901324d9530594155991c8b283023d567741cc7)
1817466cbSJens Wiklander /*
2817466cbSJens Wiklander  *  HMAC_DRBG implementation (NIST SP 800-90)
3817466cbSJens Wiklander  *
4*7901324dSJerome Forissier  *  Copyright The Mbed TLS Contributors
5*7901324dSJerome Forissier  *  SPDX-License-Identifier: Apache-2.0
6817466cbSJens Wiklander  *
7817466cbSJens Wiklander  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8817466cbSJens Wiklander  *  not use this file except in compliance with the License.
9817466cbSJens Wiklander  *  You may obtain a copy of the License at
10817466cbSJens Wiklander  *
11817466cbSJens Wiklander  *  http://www.apache.org/licenses/LICENSE-2.0
12817466cbSJens Wiklander  *
13817466cbSJens Wiklander  *  Unless required by applicable law or agreed to in writing, software
14817466cbSJens Wiklander  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15817466cbSJens Wiklander  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16817466cbSJens Wiklander  *  See the License for the specific language governing permissions and
17817466cbSJens Wiklander  *  limitations under the License.
18817466cbSJens Wiklander  */
19817466cbSJens Wiklander 
20817466cbSJens Wiklander /*
21817466cbSJens Wiklander  *  The NIST SP 800-90A DRBGs are described in the following publication.
22817466cbSJens Wiklander  *  http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf
23817466cbSJens Wiklander  *  References below are based on rev. 1 (January 2012).
24817466cbSJens Wiklander  */
25817466cbSJens Wiklander 
26*7901324dSJerome Forissier #include "common.h"
27817466cbSJens Wiklander 
28817466cbSJens Wiklander #if defined(MBEDTLS_HMAC_DRBG_C)
29817466cbSJens Wiklander 
30817466cbSJens Wiklander #include "mbedtls/hmac_drbg.h"
313d3b0591SJens Wiklander #include "mbedtls/platform_util.h"
3211fa71b9SJerome Forissier #include "mbedtls/error.h"
33817466cbSJens Wiklander 
34817466cbSJens Wiklander #include <string.h>
35817466cbSJens Wiklander 
36817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO)
37817466cbSJens Wiklander #include <stdio.h>
38817466cbSJens Wiklander #endif
39817466cbSJens Wiklander 
40817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
41817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C)
42817466cbSJens Wiklander #include "mbedtls/platform.h"
43817466cbSJens Wiklander #else
44817466cbSJens Wiklander #include <stdio.h>
45817466cbSJens Wiklander #define mbedtls_printf printf
46817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */
47817466cbSJens Wiklander #endif /* MBEDTLS_PLATFORM_C */
48817466cbSJens Wiklander 
49817466cbSJens Wiklander /*
50817466cbSJens Wiklander  * HMAC_DRBG context initialization
51817466cbSJens Wiklander  */
52817466cbSJens Wiklander void mbedtls_hmac_drbg_init( mbedtls_hmac_drbg_context *ctx )
53817466cbSJens Wiklander {
54817466cbSJens Wiklander     memset( ctx, 0, sizeof( mbedtls_hmac_drbg_context ) );
55817466cbSJens Wiklander 
56*7901324dSJerome Forissier     ctx->reseed_interval = MBEDTLS_HMAC_DRBG_RESEED_INTERVAL;
57817466cbSJens Wiklander }
58817466cbSJens Wiklander 
59817466cbSJens Wiklander /*
60817466cbSJens Wiklander  * HMAC_DRBG update, using optional additional data (10.1.2.2)
61817466cbSJens Wiklander  */
623d3b0591SJens Wiklander int mbedtls_hmac_drbg_update_ret( mbedtls_hmac_drbg_context *ctx,
633d3b0591SJens Wiklander                                   const unsigned char *additional,
643d3b0591SJens Wiklander                                   size_t add_len )
65817466cbSJens Wiklander {
66817466cbSJens Wiklander     size_t md_len = mbedtls_md_get_size( ctx->md_ctx.md_info );
67817466cbSJens Wiklander     unsigned char rounds = ( additional != NULL && add_len != 0 ) ? 2 : 1;
68817466cbSJens Wiklander     unsigned char sep[1];
69817466cbSJens Wiklander     unsigned char K[MBEDTLS_MD_MAX_SIZE];
7011fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_MD_BAD_INPUT_DATA;
71817466cbSJens Wiklander 
72817466cbSJens Wiklander     for( sep[0] = 0; sep[0] < rounds; sep[0]++ )
73817466cbSJens Wiklander     {
74817466cbSJens Wiklander         /* Step 1 or 4 */
753d3b0591SJens Wiklander         if( ( ret = mbedtls_md_hmac_reset( &ctx->md_ctx ) ) != 0 )
763d3b0591SJens Wiklander             goto exit;
773d3b0591SJens Wiklander         if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx,
783d3b0591SJens Wiklander                                             ctx->V, md_len ) ) != 0 )
793d3b0591SJens Wiklander             goto exit;
803d3b0591SJens Wiklander         if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx,
813d3b0591SJens Wiklander                                             sep, 1 ) ) != 0 )
823d3b0591SJens Wiklander             goto exit;
83817466cbSJens Wiklander         if( rounds == 2 )
843d3b0591SJens Wiklander         {
853d3b0591SJens Wiklander             if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx,
863d3b0591SJens Wiklander                                                 additional, add_len ) ) != 0 )
873d3b0591SJens Wiklander             goto exit;
883d3b0591SJens Wiklander         }
893d3b0591SJens Wiklander         if( ( ret = mbedtls_md_hmac_finish( &ctx->md_ctx, K ) ) != 0 )
903d3b0591SJens Wiklander             goto exit;
91817466cbSJens Wiklander 
92817466cbSJens Wiklander         /* Step 2 or 5 */
933d3b0591SJens Wiklander         if( ( ret = mbedtls_md_hmac_starts( &ctx->md_ctx, K, md_len ) ) != 0 )
943d3b0591SJens Wiklander             goto exit;
953d3b0591SJens Wiklander         if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx,
963d3b0591SJens Wiklander                                             ctx->V, md_len ) ) != 0 )
973d3b0591SJens Wiklander             goto exit;
983d3b0591SJens Wiklander         if( ( ret = mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ) ) != 0 )
993d3b0591SJens Wiklander             goto exit;
100817466cbSJens Wiklander     }
1013d3b0591SJens Wiklander 
1023d3b0591SJens Wiklander exit:
1033d3b0591SJens Wiklander     mbedtls_platform_zeroize( K, sizeof( K ) );
1043d3b0591SJens Wiklander     return( ret );
105817466cbSJens Wiklander }
106817466cbSJens Wiklander 
1073d3b0591SJens Wiklander #if !defined(MBEDTLS_DEPRECATED_REMOVED)
1083d3b0591SJens Wiklander void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx,
1093d3b0591SJens Wiklander                                const unsigned char *additional,
1103d3b0591SJens Wiklander                                size_t add_len )
1113d3b0591SJens Wiklander {
1123d3b0591SJens Wiklander     (void) mbedtls_hmac_drbg_update_ret( ctx, additional, add_len );
1133d3b0591SJens Wiklander }
1143d3b0591SJens Wiklander #endif /* MBEDTLS_DEPRECATED_REMOVED */
1153d3b0591SJens Wiklander 
116817466cbSJens Wiklander /*
117817466cbSJens Wiklander  * Simplified HMAC_DRBG initialisation (for use with deterministic ECDSA)
118817466cbSJens Wiklander  */
119817466cbSJens Wiklander int mbedtls_hmac_drbg_seed_buf( mbedtls_hmac_drbg_context *ctx,
120817466cbSJens Wiklander                         const mbedtls_md_info_t * md_info,
121817466cbSJens Wiklander                         const unsigned char *data, size_t data_len )
122817466cbSJens Wiklander {
12311fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
124817466cbSJens Wiklander 
125817466cbSJens Wiklander     if( ( ret = mbedtls_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 )
126817466cbSJens Wiklander         return( ret );
127817466cbSJens Wiklander 
128*7901324dSJerome Forissier #if defined(MBEDTLS_THREADING_C)
129*7901324dSJerome Forissier     mbedtls_mutex_init( &ctx->mutex );
130*7901324dSJerome Forissier #endif
131*7901324dSJerome Forissier 
132817466cbSJens Wiklander     /*
133817466cbSJens Wiklander      * Set initial working state.
134817466cbSJens Wiklander      * Use the V memory location, which is currently all 0, to initialize the
135817466cbSJens Wiklander      * MD context with an all-zero key. Then set V to its initial value.
136817466cbSJens Wiklander      */
1373d3b0591SJens Wiklander     if( ( ret = mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V,
1383d3b0591SJens Wiklander                                         mbedtls_md_get_size( md_info ) ) ) != 0 )
1393d3b0591SJens Wiklander         return( ret );
140817466cbSJens Wiklander     memset( ctx->V, 0x01, mbedtls_md_get_size( md_info ) );
141817466cbSJens Wiklander 
1423d3b0591SJens Wiklander     if( ( ret = mbedtls_hmac_drbg_update_ret( ctx, data, data_len ) ) != 0 )
1433d3b0591SJens Wiklander         return( ret );
144817466cbSJens Wiklander 
145817466cbSJens Wiklander     return( 0 );
146817466cbSJens Wiklander }
147817466cbSJens Wiklander 
148817466cbSJens Wiklander /*
1495b25c76aSJerome Forissier  * Internal function used both for seeding and reseeding the DRBG.
1505b25c76aSJerome Forissier  * Comments starting with arabic numbers refer to section 10.1.2.4
1515b25c76aSJerome Forissier  * of SP800-90A, while roman numbers refer to section 9.2.
152817466cbSJens Wiklander  */
1535b25c76aSJerome Forissier static int hmac_drbg_reseed_core( mbedtls_hmac_drbg_context *ctx,
1545b25c76aSJerome Forissier                                   const unsigned char *additional, size_t len,
1555b25c76aSJerome Forissier                                   int use_nonce )
156817466cbSJens Wiklander {
157817466cbSJens Wiklander     unsigned char seed[MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT];
1585b25c76aSJerome Forissier     size_t seedlen = 0;
15911fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
160817466cbSJens Wiklander 
1615b25c76aSJerome Forissier     {
1625b25c76aSJerome Forissier         size_t total_entropy_len;
1635b25c76aSJerome Forissier 
1645b25c76aSJerome Forissier         if( use_nonce == 0 )
1655b25c76aSJerome Forissier             total_entropy_len = ctx->entropy_len;
1665b25c76aSJerome Forissier         else
1675b25c76aSJerome Forissier             total_entropy_len = ctx->entropy_len * 3 / 2;
1685b25c76aSJerome Forissier 
169817466cbSJens Wiklander         /* III. Check input length */
170817466cbSJens Wiklander         if( len > MBEDTLS_HMAC_DRBG_MAX_INPUT ||
1715b25c76aSJerome Forissier             total_entropy_len + len > MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT )
172817466cbSJens Wiklander         {
173817466cbSJens Wiklander             return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG );
174817466cbSJens Wiklander         }
1755b25c76aSJerome Forissier     }
176817466cbSJens Wiklander 
177817466cbSJens Wiklander     memset( seed, 0, MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT );
178817466cbSJens Wiklander 
179817466cbSJens Wiklander     /* IV. Gather entropy_len bytes of entropy for the seed */
1803d3b0591SJens Wiklander     if( ( ret = ctx->f_entropy( ctx->p_entropy,
1813d3b0591SJens Wiklander                                 seed, ctx->entropy_len ) ) != 0 )
1825b25c76aSJerome Forissier     {
183817466cbSJens Wiklander         return( MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED );
1845b25c76aSJerome Forissier     }
1855b25c76aSJerome Forissier     seedlen += ctx->entropy_len;
186817466cbSJens Wiklander 
1875b25c76aSJerome Forissier     /* For initial seeding, allow adding of nonce generated
1885b25c76aSJerome Forissier      * from the entropy source. See Sect 8.6.7 in SP800-90A. */
1895b25c76aSJerome Forissier     if( use_nonce )
1905b25c76aSJerome Forissier     {
1915b25c76aSJerome Forissier         /* Note: We don't merge the two calls to f_entropy() in order
1925b25c76aSJerome Forissier          *       to avoid requesting too much entropy from f_entropy()
1935b25c76aSJerome Forissier          *       at once. Specifically, if the underlying digest is not
1945b25c76aSJerome Forissier          *       SHA-1, 3 / 2 * entropy_len is at least 36 Bytes, which
1955b25c76aSJerome Forissier          *       is larger than the maximum of 32 Bytes that our own
1965b25c76aSJerome Forissier          *       entropy source implementation can emit in a single
1975b25c76aSJerome Forissier          *       call in configurations disabling SHA-512. */
1985b25c76aSJerome Forissier         if( ( ret = ctx->f_entropy( ctx->p_entropy,
1995b25c76aSJerome Forissier                                     seed + seedlen,
2005b25c76aSJerome Forissier                                     ctx->entropy_len / 2 ) ) != 0 )
2015b25c76aSJerome Forissier         {
2025b25c76aSJerome Forissier             return( MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED );
2035b25c76aSJerome Forissier         }
2045b25c76aSJerome Forissier 
2055b25c76aSJerome Forissier         seedlen += ctx->entropy_len / 2;
2065b25c76aSJerome Forissier     }
2075b25c76aSJerome Forissier 
208817466cbSJens Wiklander 
209817466cbSJens Wiklander     /* 1. Concatenate entropy and additional data if any */
210817466cbSJens Wiklander     if( additional != NULL && len != 0 )
211817466cbSJens Wiklander     {
212817466cbSJens Wiklander         memcpy( seed + seedlen, additional, len );
213817466cbSJens Wiklander         seedlen += len;
214817466cbSJens Wiklander     }
215817466cbSJens Wiklander 
216817466cbSJens Wiklander     /* 2. Update state */
2173d3b0591SJens Wiklander     if( ( ret = mbedtls_hmac_drbg_update_ret( ctx, seed, seedlen ) ) != 0 )
2183d3b0591SJens Wiklander         goto exit;
219817466cbSJens Wiklander 
220817466cbSJens Wiklander     /* 3. Reset reseed_counter */
221817466cbSJens Wiklander     ctx->reseed_counter = 1;
222817466cbSJens Wiklander 
2233d3b0591SJens Wiklander exit:
224817466cbSJens Wiklander     /* 4. Done */
2253d3b0591SJens Wiklander     mbedtls_platform_zeroize( seed, seedlen );
2263d3b0591SJens Wiklander     return( ret );
227817466cbSJens Wiklander }
228817466cbSJens Wiklander 
229817466cbSJens Wiklander /*
2305b25c76aSJerome Forissier  * HMAC_DRBG reseeding: 10.1.2.4 + 9.2
2315b25c76aSJerome Forissier  */
2325b25c76aSJerome Forissier int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx,
2335b25c76aSJerome Forissier                       const unsigned char *additional, size_t len )
2345b25c76aSJerome Forissier {
2355b25c76aSJerome Forissier     return( hmac_drbg_reseed_core( ctx, additional, len, 0 ) );
2365b25c76aSJerome Forissier }
2375b25c76aSJerome Forissier 
2385b25c76aSJerome Forissier /*
239817466cbSJens Wiklander  * HMAC_DRBG initialisation (10.1.2.3 + 9.1)
2405b25c76aSJerome Forissier  *
2415b25c76aSJerome Forissier  * The nonce is not passed as a separate parameter but extracted
2425b25c76aSJerome Forissier  * from the entropy source as suggested in 8.6.7.
243817466cbSJens Wiklander  */
244817466cbSJens Wiklander int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx,
245817466cbSJens Wiklander                     const mbedtls_md_info_t * md_info,
246817466cbSJens Wiklander                     int (*f_entropy)(void *, unsigned char *, size_t),
247817466cbSJens Wiklander                     void *p_entropy,
248817466cbSJens Wiklander                     const unsigned char *custom,
249817466cbSJens Wiklander                     size_t len )
250817466cbSJens Wiklander {
25111fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
2525b25c76aSJerome Forissier     size_t md_size;
253817466cbSJens Wiklander 
254817466cbSJens Wiklander     if( ( ret = mbedtls_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 )
255817466cbSJens Wiklander         return( ret );
256817466cbSJens Wiklander 
257*7901324dSJerome Forissier     /* The mutex is initialized iff the md context is set up. */
258*7901324dSJerome Forissier #if defined(MBEDTLS_THREADING_C)
259*7901324dSJerome Forissier     mbedtls_mutex_init( &ctx->mutex );
260*7901324dSJerome Forissier #endif
261*7901324dSJerome Forissier 
262817466cbSJens Wiklander     md_size = mbedtls_md_get_size( md_info );
263817466cbSJens Wiklander 
264817466cbSJens Wiklander     /*
265817466cbSJens Wiklander      * Set initial working state.
266817466cbSJens Wiklander      * Use the V memory location, which is currently all 0, to initialize the
267817466cbSJens Wiklander      * MD context with an all-zero key. Then set V to its initial value.
268817466cbSJens Wiklander      */
2693d3b0591SJens Wiklander     if( ( ret = mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, md_size ) ) != 0 )
2703d3b0591SJens Wiklander         return( ret );
271817466cbSJens Wiklander     memset( ctx->V, 0x01, md_size );
272817466cbSJens Wiklander 
273817466cbSJens Wiklander     ctx->f_entropy = f_entropy;
274817466cbSJens Wiklander     ctx->p_entropy = p_entropy;
275817466cbSJens Wiklander 
2765b25c76aSJerome Forissier     if( ctx->entropy_len == 0 )
2775b25c76aSJerome Forissier     {
278817466cbSJens Wiklander         /*
279817466cbSJens Wiklander          * See SP800-57 5.6.1 (p. 65-66) for the security strength provided by
280817466cbSJens Wiklander          * each hash function, then according to SP800-90A rev1 10.1 table 2,
281817466cbSJens Wiklander          * min_entropy_len (in bits) is security_strength.
282817466cbSJens Wiklander          *
283817466cbSJens Wiklander          * (This also matches the sizes used in the NIST test vectors.)
284817466cbSJens Wiklander          */
2855b25c76aSJerome Forissier         ctx->entropy_len = md_size <= 20 ? 16 : /* 160-bits hash -> 128 bits */
286817466cbSJens Wiklander                            md_size <= 28 ? 24 : /* 224-bits hash -> 192 bits */
287817466cbSJens Wiklander                            32;  /* better (256+) -> 256 bits */
2885b25c76aSJerome Forissier     }
289817466cbSJens Wiklander 
2905b25c76aSJerome Forissier     if( ( ret = hmac_drbg_reseed_core( ctx, custom, len,
2915b25c76aSJerome Forissier                                        1 /* add nonce */ ) ) != 0 )
2925b25c76aSJerome Forissier     {
293817466cbSJens Wiklander         return( ret );
2945b25c76aSJerome Forissier     }
295817466cbSJens Wiklander 
296817466cbSJens Wiklander     return( 0 );
297817466cbSJens Wiklander }
298817466cbSJens Wiklander 
299817466cbSJens Wiklander /*
300817466cbSJens Wiklander  * Set prediction resistance
301817466cbSJens Wiklander  */
302817466cbSJens Wiklander void mbedtls_hmac_drbg_set_prediction_resistance( mbedtls_hmac_drbg_context *ctx,
303817466cbSJens Wiklander                                           int resistance )
304817466cbSJens Wiklander {
305817466cbSJens Wiklander     ctx->prediction_resistance = resistance;
306817466cbSJens Wiklander }
307817466cbSJens Wiklander 
308817466cbSJens Wiklander /*
3095b25c76aSJerome Forissier  * Set entropy length grabbed for seeding
310817466cbSJens Wiklander  */
311817466cbSJens Wiklander void mbedtls_hmac_drbg_set_entropy_len( mbedtls_hmac_drbg_context *ctx, size_t len )
312817466cbSJens Wiklander {
313817466cbSJens Wiklander     ctx->entropy_len = len;
314817466cbSJens Wiklander }
315817466cbSJens Wiklander 
316817466cbSJens Wiklander /*
317817466cbSJens Wiklander  * Set reseed interval
318817466cbSJens Wiklander  */
319817466cbSJens Wiklander void mbedtls_hmac_drbg_set_reseed_interval( mbedtls_hmac_drbg_context *ctx, int interval )
320817466cbSJens Wiklander {
321817466cbSJens Wiklander     ctx->reseed_interval = interval;
322817466cbSJens Wiklander }
323817466cbSJens Wiklander 
324817466cbSJens Wiklander /*
325817466cbSJens Wiklander  * HMAC_DRBG random function with optional additional data:
326817466cbSJens Wiklander  * 10.1.2.5 (arabic) + 9.3 (Roman)
327817466cbSJens Wiklander  */
328817466cbSJens Wiklander int mbedtls_hmac_drbg_random_with_add( void *p_rng,
329817466cbSJens Wiklander                                unsigned char *output, size_t out_len,
330817466cbSJens Wiklander                                const unsigned char *additional, size_t add_len )
331817466cbSJens Wiklander {
33211fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
333817466cbSJens Wiklander     mbedtls_hmac_drbg_context *ctx = (mbedtls_hmac_drbg_context *) p_rng;
334817466cbSJens Wiklander     size_t md_len = mbedtls_md_get_size( ctx->md_ctx.md_info );
335817466cbSJens Wiklander     size_t left = out_len;
336817466cbSJens Wiklander     unsigned char *out = output;
337817466cbSJens Wiklander 
338817466cbSJens Wiklander     /* II. Check request length */
339817466cbSJens Wiklander     if( out_len > MBEDTLS_HMAC_DRBG_MAX_REQUEST )
340817466cbSJens Wiklander         return( MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG );
341817466cbSJens Wiklander 
342817466cbSJens Wiklander     /* III. Check input length */
343817466cbSJens Wiklander     if( add_len > MBEDTLS_HMAC_DRBG_MAX_INPUT )
344817466cbSJens Wiklander         return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG );
345817466cbSJens Wiklander 
346817466cbSJens Wiklander     /* 1. (aka VII and IX) Check reseed counter and PR */
347817466cbSJens Wiklander     if( ctx->f_entropy != NULL && /* For no-reseeding instances */
348817466cbSJens Wiklander         ( ctx->prediction_resistance == MBEDTLS_HMAC_DRBG_PR_ON ||
349817466cbSJens Wiklander           ctx->reseed_counter > ctx->reseed_interval ) )
350817466cbSJens Wiklander     {
351817466cbSJens Wiklander         if( ( ret = mbedtls_hmac_drbg_reseed( ctx, additional, add_len ) ) != 0 )
352817466cbSJens Wiklander             return( ret );
353817466cbSJens Wiklander 
354817466cbSJens Wiklander         add_len = 0; /* VII.4 */
355817466cbSJens Wiklander     }
356817466cbSJens Wiklander 
357817466cbSJens Wiklander     /* 2. Use additional data if any */
358817466cbSJens Wiklander     if( additional != NULL && add_len != 0 )
3593d3b0591SJens Wiklander     {
3603d3b0591SJens Wiklander         if( ( ret = mbedtls_hmac_drbg_update_ret( ctx,
3613d3b0591SJens Wiklander                                                   additional, add_len ) ) != 0 )
3623d3b0591SJens Wiklander             goto exit;
3633d3b0591SJens Wiklander     }
364817466cbSJens Wiklander 
365817466cbSJens Wiklander     /* 3, 4, 5. Generate bytes */
366817466cbSJens Wiklander     while( left != 0 )
367817466cbSJens Wiklander     {
368817466cbSJens Wiklander         size_t use_len = left > md_len ? md_len : left;
369817466cbSJens Wiklander 
3703d3b0591SJens Wiklander         if( ( ret = mbedtls_md_hmac_reset( &ctx->md_ctx ) ) != 0 )
3713d3b0591SJens Wiklander             goto exit;
3723d3b0591SJens Wiklander         if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx,
3733d3b0591SJens Wiklander                                             ctx->V, md_len ) ) != 0 )
3743d3b0591SJens Wiklander             goto exit;
3753d3b0591SJens Wiklander         if( ( ret = mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ) ) != 0 )
3763d3b0591SJens Wiklander             goto exit;
377817466cbSJens Wiklander 
378817466cbSJens Wiklander         memcpy( out, ctx->V, use_len );
379817466cbSJens Wiklander         out += use_len;
380817466cbSJens Wiklander         left -= use_len;
381817466cbSJens Wiklander     }
382817466cbSJens Wiklander 
383817466cbSJens Wiklander     /* 6. Update */
3843d3b0591SJens Wiklander     if( ( ret = mbedtls_hmac_drbg_update_ret( ctx,
3853d3b0591SJens Wiklander                                               additional, add_len ) ) != 0 )
3863d3b0591SJens Wiklander         goto exit;
387817466cbSJens Wiklander 
388817466cbSJens Wiklander     /* 7. Update reseed counter */
389817466cbSJens Wiklander     ctx->reseed_counter++;
390817466cbSJens Wiklander 
3913d3b0591SJens Wiklander exit:
392817466cbSJens Wiklander     /* 8. Done */
3933d3b0591SJens Wiklander     return( ret );
394817466cbSJens Wiklander }
395817466cbSJens Wiklander 
396817466cbSJens Wiklander /*
397817466cbSJens Wiklander  * HMAC_DRBG random function
398817466cbSJens Wiklander  */
399817466cbSJens Wiklander int mbedtls_hmac_drbg_random( void *p_rng, unsigned char *output, size_t out_len )
400817466cbSJens Wiklander {
40111fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
402817466cbSJens Wiklander     mbedtls_hmac_drbg_context *ctx = (mbedtls_hmac_drbg_context *) p_rng;
403817466cbSJens Wiklander 
404817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C)
405817466cbSJens Wiklander     if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
406817466cbSJens Wiklander         return( ret );
407817466cbSJens Wiklander #endif
408817466cbSJens Wiklander 
409817466cbSJens Wiklander     ret = mbedtls_hmac_drbg_random_with_add( ctx, output, out_len, NULL, 0 );
410817466cbSJens Wiklander 
411817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C)
412817466cbSJens Wiklander     if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
413817466cbSJens Wiklander         return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
414817466cbSJens Wiklander #endif
415817466cbSJens Wiklander 
416817466cbSJens Wiklander     return( ret );
417817466cbSJens Wiklander }
418817466cbSJens Wiklander 
419817466cbSJens Wiklander /*
420*7901324dSJerome Forissier  *  This function resets HMAC_DRBG context to the state immediately
421*7901324dSJerome Forissier  *  after initial call of mbedtls_hmac_drbg_init().
422817466cbSJens Wiklander  */
423817466cbSJens Wiklander void mbedtls_hmac_drbg_free( mbedtls_hmac_drbg_context *ctx )
424817466cbSJens Wiklander {
425817466cbSJens Wiklander     if( ctx == NULL )
426817466cbSJens Wiklander         return;
427817466cbSJens Wiklander 
428817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C)
429*7901324dSJerome Forissier     /* The mutex is initialized iff the md context is set up. */
430*7901324dSJerome Forissier     if( ctx->md_ctx.md_info != NULL )
431817466cbSJens Wiklander         mbedtls_mutex_free( &ctx->mutex );
432817466cbSJens Wiklander #endif
433817466cbSJens Wiklander     mbedtls_md_free( &ctx->md_ctx );
4343d3b0591SJens Wiklander     mbedtls_platform_zeroize( ctx, sizeof( mbedtls_hmac_drbg_context ) );
435*7901324dSJerome Forissier     ctx->reseed_interval = MBEDTLS_HMAC_DRBG_RESEED_INTERVAL;
436817466cbSJens Wiklander }
437817466cbSJens Wiklander 
438817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO)
439817466cbSJens Wiklander int mbedtls_hmac_drbg_write_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path )
440817466cbSJens Wiklander {
44111fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
442817466cbSJens Wiklander     FILE *f;
443817466cbSJens Wiklander     unsigned char buf[ MBEDTLS_HMAC_DRBG_MAX_INPUT ];
444817466cbSJens Wiklander 
445817466cbSJens Wiklander     if( ( f = fopen( path, "wb" ) ) == NULL )
446817466cbSJens Wiklander         return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR );
447817466cbSJens Wiklander 
448817466cbSJens Wiklander     if( ( ret = mbedtls_hmac_drbg_random( ctx, buf, sizeof( buf ) ) ) != 0 )
449817466cbSJens Wiklander         goto exit;
450817466cbSJens Wiklander 
451817466cbSJens Wiklander     if( fwrite( buf, 1, sizeof( buf ), f ) != sizeof( buf ) )
452817466cbSJens Wiklander     {
453817466cbSJens Wiklander         ret = MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR;
454817466cbSJens Wiklander         goto exit;
455817466cbSJens Wiklander     }
456817466cbSJens Wiklander 
457817466cbSJens Wiklander     ret = 0;
458817466cbSJens Wiklander 
459817466cbSJens Wiklander exit:
460817466cbSJens Wiklander     fclose( f );
4613d3b0591SJens Wiklander     mbedtls_platform_zeroize( buf, sizeof( buf ) );
4623d3b0591SJens Wiklander 
463817466cbSJens Wiklander     return( ret );
464817466cbSJens Wiklander }
465817466cbSJens Wiklander 
466817466cbSJens Wiklander int mbedtls_hmac_drbg_update_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path )
467817466cbSJens Wiklander {
4683d3b0591SJens Wiklander     int ret = 0;
4693d3b0591SJens Wiklander     FILE *f = NULL;
470817466cbSJens Wiklander     size_t n;
471817466cbSJens Wiklander     unsigned char buf[ MBEDTLS_HMAC_DRBG_MAX_INPUT ];
4723d3b0591SJens Wiklander     unsigned char c;
473817466cbSJens Wiklander 
474817466cbSJens Wiklander     if( ( f = fopen( path, "rb" ) ) == NULL )
475817466cbSJens Wiklander         return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR );
476817466cbSJens Wiklander 
4773d3b0591SJens Wiklander     n = fread( buf, 1, sizeof( buf ), f );
4783d3b0591SJens Wiklander     if( fread( &c, 1, 1, f ) != 0 )
479817466cbSJens Wiklander     {
4803d3b0591SJens Wiklander         ret = MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG;
4813d3b0591SJens Wiklander         goto exit;
482817466cbSJens Wiklander     }
4833d3b0591SJens Wiklander     if( n == 0 || ferror( f ) )
484817466cbSJens Wiklander     {
4853d3b0591SJens Wiklander         ret = MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR;
4863d3b0591SJens Wiklander         goto exit;
487817466cbSJens Wiklander     }
488817466cbSJens Wiklander     fclose( f );
4893d3b0591SJens Wiklander     f = NULL;
490817466cbSJens Wiklander 
4913d3b0591SJens Wiklander     ret = mbedtls_hmac_drbg_update_ret( ctx, buf, n );
492817466cbSJens Wiklander 
4933d3b0591SJens Wiklander exit:
4943d3b0591SJens Wiklander     mbedtls_platform_zeroize( buf, sizeof( buf ) );
4953d3b0591SJens Wiklander     if( f != NULL )
4963d3b0591SJens Wiklander         fclose( f );
4973d3b0591SJens Wiklander     if( ret != 0 )
4983d3b0591SJens Wiklander         return( ret );
499817466cbSJens Wiklander     return( mbedtls_hmac_drbg_write_seed_file( ctx, path ) );
500817466cbSJens Wiklander }
501817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */
502817466cbSJens Wiklander 
503817466cbSJens Wiklander 
504817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
505817466cbSJens Wiklander 
506817466cbSJens Wiklander #if !defined(MBEDTLS_SHA1_C)
507817466cbSJens Wiklander /* Dummy checkup routine */
508817466cbSJens Wiklander int mbedtls_hmac_drbg_self_test( int verbose )
509817466cbSJens Wiklander {
510817466cbSJens Wiklander     (void) verbose;
511817466cbSJens Wiklander     return( 0 );
512817466cbSJens Wiklander }
513817466cbSJens Wiklander #else
514817466cbSJens Wiklander 
515817466cbSJens Wiklander #define OUTPUT_LEN  80
516817466cbSJens Wiklander 
517817466cbSJens Wiklander /* From a NIST PR=true test vector */
518817466cbSJens Wiklander static const unsigned char entropy_pr[] = {
519817466cbSJens Wiklander     0xa0, 0xc9, 0xab, 0x58, 0xf1, 0xe2, 0xe5, 0xa4, 0xde, 0x3e, 0xbd, 0x4f,
520817466cbSJens Wiklander     0xf7, 0x3e, 0x9c, 0x5b, 0x64, 0xef, 0xd8, 0xca, 0x02, 0x8c, 0xf8, 0x11,
521817466cbSJens Wiklander     0x48, 0xa5, 0x84, 0xfe, 0x69, 0xab, 0x5a, 0xee, 0x42, 0xaa, 0x4d, 0x42,
522817466cbSJens Wiklander     0x17, 0x60, 0x99, 0xd4, 0x5e, 0x13, 0x97, 0xdc, 0x40, 0x4d, 0x86, 0xa3,
523817466cbSJens Wiklander     0x7b, 0xf5, 0x59, 0x54, 0x75, 0x69, 0x51, 0xe4 };
524817466cbSJens Wiklander static const unsigned char result_pr[OUTPUT_LEN] = {
525817466cbSJens Wiklander     0x9a, 0x00, 0xa2, 0xd0, 0x0e, 0xd5, 0x9b, 0xfe, 0x31, 0xec, 0xb1, 0x39,
526817466cbSJens Wiklander     0x9b, 0x60, 0x81, 0x48, 0xd1, 0x96, 0x9d, 0x25, 0x0d, 0x3c, 0x1e, 0x94,
527817466cbSJens Wiklander     0x10, 0x10, 0x98, 0x12, 0x93, 0x25, 0xca, 0xb8, 0xfc, 0xcc, 0x2d, 0x54,
528817466cbSJens Wiklander     0x73, 0x19, 0x70, 0xc0, 0x10, 0x7a, 0xa4, 0x89, 0x25, 0x19, 0x95, 0x5e,
529817466cbSJens Wiklander     0x4b, 0xc6, 0x00, 0x1d, 0x7f, 0x4e, 0x6a, 0x2b, 0xf8, 0xa3, 0x01, 0xab,
530817466cbSJens Wiklander     0x46, 0x05, 0x5c, 0x09, 0xa6, 0x71, 0x88, 0xf1, 0xa7, 0x40, 0xee, 0xf3,
531817466cbSJens Wiklander     0xe1, 0x5c, 0x02, 0x9b, 0x44, 0xaf, 0x03, 0x44 };
532817466cbSJens Wiklander 
533817466cbSJens Wiklander /* From a NIST PR=false test vector */
534817466cbSJens Wiklander static const unsigned char entropy_nopr[] = {
535817466cbSJens Wiklander     0x79, 0x34, 0x9b, 0xbf, 0x7c, 0xdd, 0xa5, 0x79, 0x95, 0x57, 0x86, 0x66,
536817466cbSJens Wiklander     0x21, 0xc9, 0x13, 0x83, 0x11, 0x46, 0x73, 0x3a, 0xbf, 0x8c, 0x35, 0xc8,
537817466cbSJens Wiklander     0xc7, 0x21, 0x5b, 0x5b, 0x96, 0xc4, 0x8e, 0x9b, 0x33, 0x8c, 0x74, 0xe3,
538817466cbSJens Wiklander     0xe9, 0x9d, 0xfe, 0xdf };
539817466cbSJens Wiklander static const unsigned char result_nopr[OUTPUT_LEN] = {
540817466cbSJens Wiklander     0xc6, 0xa1, 0x6a, 0xb8, 0xd4, 0x20, 0x70, 0x6f, 0x0f, 0x34, 0xab, 0x7f,
541817466cbSJens Wiklander     0xec, 0x5a, 0xdc, 0xa9, 0xd8, 0xca, 0x3a, 0x13, 0x3e, 0x15, 0x9c, 0xa6,
542817466cbSJens Wiklander     0xac, 0x43, 0xc6, 0xf8, 0xa2, 0xbe, 0x22, 0x83, 0x4a, 0x4c, 0x0a, 0x0a,
543817466cbSJens Wiklander     0xff, 0xb1, 0x0d, 0x71, 0x94, 0xf1, 0xc1, 0xa5, 0xcf, 0x73, 0x22, 0xec,
544817466cbSJens Wiklander     0x1a, 0xe0, 0x96, 0x4e, 0xd4, 0xbf, 0x12, 0x27, 0x46, 0xe0, 0x87, 0xfd,
545817466cbSJens Wiklander     0xb5, 0xb3, 0xe9, 0x1b, 0x34, 0x93, 0xd5, 0xbb, 0x98, 0xfa, 0xed, 0x49,
546817466cbSJens Wiklander     0xe8, 0x5f, 0x13, 0x0f, 0xc8, 0xa4, 0x59, 0xb7 };
547817466cbSJens Wiklander 
548817466cbSJens Wiklander /* "Entropy" from buffer */
549817466cbSJens Wiklander static size_t test_offset;
550817466cbSJens Wiklander static int hmac_drbg_self_test_entropy( void *data,
551817466cbSJens Wiklander                                         unsigned char *buf, size_t len )
552817466cbSJens Wiklander {
553817466cbSJens Wiklander     const unsigned char *p = data;
554817466cbSJens Wiklander     memcpy( buf, p + test_offset, len );
555817466cbSJens Wiklander     test_offset += len;
556817466cbSJens Wiklander     return( 0 );
557817466cbSJens Wiklander }
558817466cbSJens Wiklander 
559817466cbSJens Wiklander #define CHK( c )    if( (c) != 0 )                          \
560817466cbSJens Wiklander                     {                                       \
561817466cbSJens Wiklander                         if( verbose != 0 )                  \
562817466cbSJens Wiklander                             mbedtls_printf( "failed\n" );  \
563817466cbSJens Wiklander                         return( 1 );                        \
564817466cbSJens Wiklander                     }
565817466cbSJens Wiklander 
566817466cbSJens Wiklander /*
567817466cbSJens Wiklander  * Checkup routine for HMAC_DRBG with SHA-1
568817466cbSJens Wiklander  */
569817466cbSJens Wiklander int mbedtls_hmac_drbg_self_test( int verbose )
570817466cbSJens Wiklander {
571817466cbSJens Wiklander     mbedtls_hmac_drbg_context ctx;
572817466cbSJens Wiklander     unsigned char buf[OUTPUT_LEN];
573817466cbSJens Wiklander     const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 );
574817466cbSJens Wiklander 
575817466cbSJens Wiklander     mbedtls_hmac_drbg_init( &ctx );
576817466cbSJens Wiklander 
577817466cbSJens Wiklander     /*
578817466cbSJens Wiklander      * PR = True
579817466cbSJens Wiklander      */
580817466cbSJens Wiklander     if( verbose != 0 )
581817466cbSJens Wiklander         mbedtls_printf( "  HMAC_DRBG (PR = True) : " );
582817466cbSJens Wiklander 
583817466cbSJens Wiklander     test_offset = 0;
584817466cbSJens Wiklander     CHK( mbedtls_hmac_drbg_seed( &ctx, md_info,
585817466cbSJens Wiklander                          hmac_drbg_self_test_entropy, (void *) entropy_pr,
586817466cbSJens Wiklander                          NULL, 0 ) );
587817466cbSJens Wiklander     mbedtls_hmac_drbg_set_prediction_resistance( &ctx, MBEDTLS_HMAC_DRBG_PR_ON );
588817466cbSJens Wiklander     CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) );
589817466cbSJens Wiklander     CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) );
590817466cbSJens Wiklander     CHK( memcmp( buf, result_pr, OUTPUT_LEN ) );
591817466cbSJens Wiklander     mbedtls_hmac_drbg_free( &ctx );
592817466cbSJens Wiklander 
593817466cbSJens Wiklander     mbedtls_hmac_drbg_free( &ctx );
594817466cbSJens Wiklander 
595817466cbSJens Wiklander     if( verbose != 0 )
596817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
597817466cbSJens Wiklander 
598817466cbSJens Wiklander     /*
599817466cbSJens Wiklander      * PR = False
600817466cbSJens Wiklander      */
601817466cbSJens Wiklander     if( verbose != 0 )
602817466cbSJens Wiklander         mbedtls_printf( "  HMAC_DRBG (PR = False) : " );
603817466cbSJens Wiklander 
604817466cbSJens Wiklander     mbedtls_hmac_drbg_init( &ctx );
605817466cbSJens Wiklander 
606817466cbSJens Wiklander     test_offset = 0;
607817466cbSJens Wiklander     CHK( mbedtls_hmac_drbg_seed( &ctx, md_info,
608817466cbSJens Wiklander                          hmac_drbg_self_test_entropy, (void *) entropy_nopr,
609817466cbSJens Wiklander                          NULL, 0 ) );
610817466cbSJens Wiklander     CHK( mbedtls_hmac_drbg_reseed( &ctx, NULL, 0 ) );
611817466cbSJens Wiklander     CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) );
612817466cbSJens Wiklander     CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) );
613817466cbSJens Wiklander     CHK( memcmp( buf, result_nopr, OUTPUT_LEN ) );
614817466cbSJens Wiklander     mbedtls_hmac_drbg_free( &ctx );
615817466cbSJens Wiklander 
616817466cbSJens Wiklander     mbedtls_hmac_drbg_free( &ctx );
617817466cbSJens Wiklander 
618817466cbSJens Wiklander     if( verbose != 0 )
619817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
620817466cbSJens Wiklander 
621817466cbSJens Wiklander     if( verbose != 0 )
622817466cbSJens Wiklander         mbedtls_printf( "\n" );
623817466cbSJens Wiklander 
624817466cbSJens Wiklander     return( 0 );
625817466cbSJens Wiklander }
626817466cbSJens Wiklander #endif /* MBEDTLS_SHA1_C */
627817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */
628817466cbSJens Wiklander 
629817466cbSJens Wiklander #endif /* MBEDTLS_HMAC_DRBG_C */
630