1 /* Copyright (c) (2014-2019,2021) Apple Inc. All rights reserved.
2 *
3 * corecrypto is licensed under Apple Inc.’s Internal Use License Agreement (which
4 * is contained in the License.txt file distributed with corecrypto) and only to
5 * people who accept that license. IMPORTANT: Any license rights granted to you by
6 * Apple Inc. (if any) are limited to internal use within your organization only on
7 * devices and computers you own or control, for the sole purpose of verifying the
8 * security characteristics and correct functioning of the Apple Software. You may
9 * not, directly or indirectly, redistribute the Apple Software or any portions thereof.
10 *
11 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
12 *
13 * This file contains Original Code and/or Modifications of Original Code
14 * as defined in and that are subject to the Apple Public Source License
15 * Version 2.0 (the 'License'). You may not use this file except in
16 * compliance with the License. The rights granted to you under the License
17 * may not be used to create, or enable the creation or redistribution of,
18 * unlawful or unlicensed copies of an Apple operating system, or to
19 * circumvent, violate, or enable the circumvention or violation of, any
20 * terms of an Apple operating system software license agreement.
21 *
22 * Please obtain a copy of the License at
23 * http://www.opensource.apple.com/apsl/ and read it before using this file.
24 *
25 * The Original Code and all software distributed under the License are
26 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
27 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
28 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
29 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
30 * Please see the License for the specific language governing rights and
31 * limitations under the License.
32 *
33 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
34 */
35
36 #include "cc_internal.h"
37 #include <stdbool.h>
38
39 #include <corecrypto/cc_priv.h>
40 #include <corecrypto/ccdrbg.h>
41 #include <corecrypto/cchmac.h>
42 #include <corecrypto/ccsha2.h>
43 #include "cc_macros.h"
44
45 // This HMAC DRBG is described in:
46
47 // NIST SP 800-90A Rev. 1
48 // Recommendation for Random Number Generation Using Deterministic Random Bit Generators
49 // June 2015
50
51 // See in particular:
52 // - 9 DRBG Mechanism Functions
53 // - 10.1.2 HMAC_DRBG
54 // - B.2 HMAC_DRBGExample
55
56 #define NISTHMAC_MAX_OUTPUT_SIZE MAX_DIGEST_OUTPUT_SIZE
57
58 #define MIN_REQ_ENTROPY(di) ((di)->output_size / 2)
59
60 struct ccdrbg_nisthmac_state {
61 const struct ccdrbg_nisthmac_custom *custom;
62 uint8_t key[NISTHMAC_MAX_OUTPUT_SIZE];
63 uint8_t V[NISTHMAC_MAX_OUTPUT_SIZE];
64 uint64_t reseed_counter;
65 };
66
67 #define DRBG_NISTHMAC_DEBUG 0
68
69 #if DRBG_NISTHMAC_DEBUG
70 #include "cc_debug.h"
71
72 static void
dump_state(const char * label,struct ccdrbg_nisthmac_state * drbg_ctx)73 dump_state(const char *label, struct ccdrbg_nisthmac_state *drbg_ctx)
74 {
75 size_t outlen = drbg_ctx->custom->di->output_size;
76
77 cc_print(label, outlen, drbg_ctx->key);
78 cc_print(label, outlen, drbg_ctx->V);
79 }
80 #endif
81
82 // See NIST SP 800-90A, Rev. 1, 9.4
83 static void
done(struct ccdrbg_state * ctx)84 done(struct ccdrbg_state *ctx)
85 {
86 cc_clear(sizeof(struct ccdrbg_nisthmac_state), ctx);
87 }
88
89 // See NIST SP 800-90A, Rev. 1, 10.1.2.2
90 static void
update(struct ccdrbg_state * ctx,unsigned ndata,...)91 update(struct ccdrbg_state *ctx, unsigned ndata, ...)
92 {
93 struct ccdrbg_nisthmac_state *drbg_ctx = (struct ccdrbg_nisthmac_state *)ctx;
94 const struct ccdigest_info *info = drbg_ctx->custom->di;
95 size_t outlen = info->output_size;
96 size_t data_nbytes = 0;
97 va_list args;
98
99 cchmac_di_decl(info, hmac_ctx);
100
101 for (uint8_t b = 0; b < 2; b += 1) {
102 cchmac_init(info, hmac_ctx, outlen, drbg_ctx->key);
103
104 cchmac_update(info, hmac_ctx, outlen, drbg_ctx->V);
105
106 cchmac_update(info, hmac_ctx, sizeof(b), &b);
107
108 va_start(args, ndata);
109
110 for (unsigned i = 0; i < ndata; i += 1) {
111 size_t nbytes = va_arg(args, size_t);
112 const void *buf = va_arg(args, const void *);
113
114 cchmac_update(info, hmac_ctx, nbytes, buf);
115
116 data_nbytes += nbytes;
117 }
118
119 va_end(args);
120
121 cchmac_final(info, hmac_ctx, drbg_ctx->key);
122
123 cchmac(info, outlen, drbg_ctx->key, outlen, drbg_ctx->V, drbg_ctx->V);
124
125 if (data_nbytes == 0) {
126 break;
127 }
128 }
129
130 cchmac_di_clear(info, hmac_ctx);
131 }
132
133 static bool
entropy_isvalid(size_t entropy_nbytes,const struct ccdigest_info * info)134 entropy_isvalid(size_t entropy_nbytes, const struct ccdigest_info *info)
135 {
136 return (entropy_nbytes <= CCDRBG_MAX_ENTROPY_SIZE) && (entropy_nbytes >= MIN_REQ_ENTROPY(info));
137 }
138
139 // See NIST SP 800-90A, Rev. 1, 9.1 and 10.1.2.3
140 static int
init(const struct ccdrbg_info * info,struct ccdrbg_state * ctx,size_t entropy_nbytes,const void * entropy,size_t nonce_nbytes,const void * nonce,size_t ps_nbytes,const void * ps)141 init(const struct ccdrbg_info *info,
142 struct ccdrbg_state *ctx,
143 size_t entropy_nbytes,
144 const void *entropy,
145 size_t nonce_nbytes,
146 const void *nonce,
147 size_t ps_nbytes,
148 const void *ps)
149 {
150 struct ccdrbg_nisthmac_state *drbg_ctx = (struct ccdrbg_nisthmac_state *)ctx;
151 drbg_ctx->custom = info->custom;
152 const struct ccdigest_info *digest_info = drbg_ctx->custom->di;
153 size_t outlen = digest_info->output_size;
154
155 int status = CCDRBG_STATUS_PARAM_ERROR;
156 cc_require(outlen <= NISTHMAC_MAX_OUTPUT_SIZE, out);
157 cc_require(entropy_isvalid(entropy_nbytes, digest_info), out);
158 cc_require(ps_nbytes <= CCDRBG_MAX_PSINPUT_SIZE, out);
159
160 status = CCDRBG_STATUS_OK;
161
162 cc_memset(drbg_ctx->key, 0, outlen);
163 cc_memset(drbg_ctx->V, 1, outlen);
164
165 update(ctx, 3, entropy_nbytes, entropy, nonce_nbytes, nonce, ps_nbytes, ps);
166
167 drbg_ctx->reseed_counter = 1;
168
169 out:
170 return status;
171 }
172
173 static bool
add_isvalid(size_t add_nbytes)174 add_isvalid(size_t add_nbytes)
175 {
176 return add_nbytes <= CCDRBG_MAX_ADDITIONALINPUT_SIZE;
177 }
178
179 // See NIST SP 800-90A, Rev. 1, 9.2 and 10.1.2.4
180 static int
reseed(struct ccdrbg_state * ctx,size_t entropy_nbytes,const void * entropy,size_t add_nbytes,const void * add)181 reseed(struct ccdrbg_state *ctx, size_t entropy_nbytes, const void *entropy, size_t add_nbytes, const void *add)
182 {
183 struct ccdrbg_nisthmac_state *drbg_ctx = (struct ccdrbg_nisthmac_state *)ctx;
184 const struct ccdigest_info *digest_info = drbg_ctx->custom->di;
185
186 int status = CCDRBG_STATUS_PARAM_ERROR;
187 cc_require(entropy_isvalid(entropy_nbytes, digest_info), out);
188 cc_require(add_isvalid(add_nbytes), out);
189
190 status = CCDRBG_STATUS_OK;
191
192 update(ctx, 2, entropy_nbytes, entropy, add_nbytes, add);
193
194 drbg_ctx->reseed_counter = 1;
195
196 out:
197 return status;
198 }
199
200 // See NIST SP 800-90A, Rev. 1, 9.3 and 10.1.2.5
201 static int
generate(struct ccdrbg_state * ctx,size_t out_nbytes,void * out,size_t add_nbytes,const void * add)202 generate(struct ccdrbg_state *ctx, size_t out_nbytes, void *out, size_t add_nbytes, const void *add)
203 {
204 struct ccdrbg_nisthmac_state *drbg_ctx = (struct ccdrbg_nisthmac_state *)ctx;
205 const struct ccdigest_info *info = drbg_ctx->custom->di;
206 size_t outlen = info->output_size;
207
208 int status = CCDRBG_STATUS_PARAM_ERROR;
209 cc_require(out_nbytes <= CCDRBG_MAX_REQUEST_SIZE, out);
210 cc_require(add_isvalid(add_nbytes), out);
211
212 status = CCDRBG_STATUS_NEED_RESEED;
213 cc_require(drbg_ctx->reseed_counter <= CCDRBG_RESEED_INTERVAL || !drbg_ctx->custom->strictFIPS, out);
214
215 status = CCDRBG_STATUS_OK;
216
217 if (add_nbytes > 0) {
218 update(ctx, 1, add_nbytes, add);
219 }
220
221 uint8_t *out_bytes = out;
222 uint8_t Vprev[NISTHMAC_MAX_OUTPUT_SIZE];
223
224 while (out_nbytes > 0) {
225 cc_memcpy(Vprev, drbg_ctx->V, outlen);
226 cchmac(info, outlen, drbg_ctx->key, outlen, drbg_ctx->V, drbg_ctx->V);
227
228 // See FIPS 140-2, 4.9.2 Conditional Tests
229 if (cc_cmp_safe(outlen, Vprev, drbg_ctx->V) == 0) {
230 done(ctx);
231 status = CCDRBG_STATUS_ABORT;
232 cc_try_abort(NULL);
233 goto out;
234 }
235
236 size_t n = CC_MIN(out_nbytes, outlen);
237 cc_memcpy(out_bytes, drbg_ctx->V, n);
238
239 out_bytes += n;
240 out_nbytes -= n;
241 }
242
243 update(ctx, 1, add_nbytes, add);
244
245 drbg_ctx->reseed_counter += 1;
246
247 out:
248 cc_clear(outlen, Vprev);
249 return status;
250 }
251
252 void
ccdrbg_factory_nisthmac(struct ccdrbg_info * info,const struct ccdrbg_nisthmac_custom * custom)253 ccdrbg_factory_nisthmac(struct ccdrbg_info *info, const struct ccdrbg_nisthmac_custom *custom)
254 {
255 CC_ENSURE_DIT_ENABLED
256
257 info->size = sizeof(struct ccdrbg_nisthmac_state) + sizeof(struct ccdrbg_nisthmac_custom);
258 info->init = init;
259 info->generate = generate;
260 info->reseed = reseed;
261 info->done = done;
262 info->custom = custom;
263 };
264