]> git.saurik.com Git - apple/mdnsresponder.git/blob - ServiceRegistration/sign-mbedtls.c
mDNSResponder-1310.40.42.tar.gz
[apple/mdnsresponder.git] / ServiceRegistration / sign-mbedtls.c
1 /* sign-mbedtls.c
2 *
3 * Copyright (c) 2018-2019 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 * DNS SIG(0) signature generation for DNSSD SRP using mbedtls.
18 *
19 * Functions required for loading, saving, and generating public/private keypairs, extracting the public key
20 * into KEY RR data, and computing signatures.
21 *
22 * This is the implementation for mbedtls, e.g. on Thread Devices, Linux, and OpenWRT.
23 */
24
25 #include <stdio.h>
26 #ifdef THREAD_DEVKIT_ADK
27 #include <openthread/random_noncrypto.h>
28 #include "HAPPlatformRandomNumber.h"
29 #else
30 #include <arpa/inet.h>
31 #ifdef LINUX_GETENTROPY
32 #define _GNU_SOURCE
33 #include <linux/random.h>
34 #include <sys/syscall.h>
35 #else
36 #include <sys/random.h>
37 #endif // LINUX_GETENTROPY
38 #endif // THREAD_DEVKIT_ADK
39 #include <string.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42 #include <fcntl.h>
43 #include <errno.h>
44
45 #include "srp.h"
46 #include "dns-msg.h"
47 #define SRP_CRYPTO_MBEDTLS_INTERNAL 1
48 #include "srp-crypto.h"
49 #include "dns_sd.h"
50
51 // For debugging
52 #ifdef DEBUG_SHA256
53 int
54 srp_mbedtls_sha256_update_ret(const char *thing_name,
55 mbedtls_sha256_context *sha, uint8_t *data, size_t len)
56 {
57 int i;
58 fprintf(stderr, "%s %lu: ", thing_name, (unsigned long)len);
59 if (len > 400) {
60 len = 400;
61 }
62
63 for (i = 0; i < len; i++) {
64 fprintf(stderr, "%02x", data[i]);
65 }
66 fputs("\n", stderr);
67 return mbedtls_sha256_update_ret(sha, data, len);
68 }
69
70 int
71 srp_mbedtls_sha256_finish_ret(mbedtls_sha256_context *sha, uint8_t *hash)
72 {
73 int i;
74 int status = mbedtls_sha256_finish_ret(sha, hash);
75 fprintf(stderr, "hash: ");
76 for (i = 0; i < ECDSA_SHA256_HASH_SIZE; i++) {
77 fprintf(stderr, "%02x", hash[i]);
78 }
79 fputs("\n", stderr);
80 return status;
81 }
82 #endif
83
84 // Key is stored in an opaque data structure, for mbedtls this is an mbedtls_pk_context.
85 // Function to read a public key from a KEY record
86 // Function to validate a signature given some data and a public key (not required on client)
87
88 // Function to free a key
89 void
90 srp_keypair_free(srp_key_t *key)
91 {
92 #ifndef EXCLUDE_CRYPTO
93 mbedtls_pk_free(&key->key);
94 #endif
95 free(key);
96 }
97
98 #ifndef EXCLUDE_CRYPTO
99 // Needed to seed the RNG with good entropy data.
100 static int
101 get_entropy(void *data, unsigned char *output, size_t len, size_t *outlen)
102 {
103 #ifdef THREAD_DEVKIT_ADK
104 HAPPlatformRandomNumberFill(output, len);
105 *outlen = len;
106 return 0;
107 #else
108 #ifdef LINUX_GETENTROPY
109 int result = syscall(SYS_getrandom, output, len, GRND_RANDOM);
110 #else
111 int result = getentropy(output, len);
112 #endif
113 (void)data;
114
115 if (result != 0) {
116 ERROR("getentropy returned %s", strerror(errno));
117 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
118 }
119 *outlen = len;
120 #endif // THREAD_DEVKIT_ADK
121 return 0;
122 }
123
124 // mbedtls on embedded devices seems to react poorly to multiple rng contexts, so we create just
125 // one and keep it around. It would be nice if this got fixed, but it's actually more efficient
126 // to have one context, so not something we need to fix.
127 typedef struct rng_state {
128 mbedtls_entropy_context entropy_context;
129 mbedtls_ctr_drbg_context rng_context;
130 char errbuf[64];
131 } rng_state_t;
132
133 static rng_state_t *rng_state;
134
135 bool
136 rng_state_fetch(void)
137 {
138 int status;
139
140 if (rng_state == NULL) {
141 rng_state = calloc(1, sizeof *rng_state);
142 if (rng_state == NULL) {
143 ERROR("srp_random16(): no memory for state.");
144 goto fail;
145 }
146
147 mbedtls_entropy_init(&rng_state->entropy_context);
148 status = mbedtls_entropy_add_source(&rng_state->entropy_context, get_entropy,
149 NULL, 1, MBEDTLS_ENTROPY_SOURCE_STRONG);
150 if (status != 0) {
151 mbedtls_strerror(status, rng_state->errbuf, sizeof rng_state->errbuf);
152 ERROR("mbedtls_entropy_add_source failed: %s", rng_state->errbuf);
153 goto fail;
154 }
155
156 mbedtls_ctr_drbg_init(&rng_state->rng_context);
157 status = mbedtls_ctr_drbg_seed(&rng_state->rng_context,
158 mbedtls_entropy_func, &rng_state->entropy_context, NULL, 0);
159
160 if (status != 0) {
161 mbedtls_strerror(status, rng_state->errbuf, sizeof rng_state->errbuf);
162 ERROR("mbedtls_ctr_drbg_seed failed: %s", rng_state->errbuf);
163 fail:
164 free(rng_state);
165 rng_state = NULL;
166 return false;
167 }
168 }
169 return true;
170 }
171 #endif // EXCLUDE_CRYPTO
172
173 static srp_key_t *
174 srp_key_setup(void)
175 {
176 srp_key_t *key = calloc(1, sizeof(*key));
177
178 if (key == NULL) {
179 return key;
180 }
181
182 #ifndef EXCLUDE_CRYPTO
183 mbedtls_pk_init(&key->key);
184 if (rng_state_fetch()) {
185 return key;
186 }
187 mbedtls_pk_free(&key->key);
188 free(key);
189 return NULL;
190 #else
191 return key;
192 #endif
193 }
194
195 uint16_t
196 srp_random16()
197 {
198 #ifdef EXCLUDE_CRYPTO
199 // Note that this is the wrong thing to return here and needs to be fixed.
200 return otRandomNonCryptoGetUint16();
201 #else
202 int status;
203 uint16_t ret;
204 char errbuf[64];
205 if (rng_state_fetch()) {
206 status = mbedtls_ctr_drbg_random(&rng_state->rng_context, (unsigned char *)&ret, sizeof ret);
207 if (status != 0) {
208 mbedtls_strerror(status, errbuf, sizeof errbuf);
209 ERROR("mbedtls_ctr_drbg_random failed: %s", errbuf);
210 return 0xffff;
211 }
212 return ret;
213 }
214 return 0xffff;
215 #endif
216 }
217
218 srp_key_t *
219 srp_load_key_from_buffer(const uint8_t *buffer, size_t length)
220 {
221 srp_key_t *key;
222 #ifndef EXCLUDE_CRYPTO
223 int status;
224 char errbuf[64];
225 #endif
226
227 key = srp_key_setup();
228 if (key == NULL) {
229 return NULL;
230 }
231
232 #ifndef EXCLUDE_CRYPTO
233 if ((status = mbedtls_pk_parse_key(&key->key, buffer, length, NULL, 0)) != 0) {
234 mbedtls_strerror(status, errbuf, sizeof errbuf);
235 ERROR("mbedtls_pk_parse_key failed: %s", errbuf);
236 } else if (!mbedtls_pk_can_do(&key->key, MBEDTLS_PK_ECDSA)) {
237 ERROR("Buffer does not contain a usable ECDSA key.");
238 } else {
239 return key;
240 }
241 #else
242 if (length == ECDSA_KEY_SIZE) {
243 memcpy(key->key, buffer, length);
244 return key;
245 }
246 #endif
247 srp_keypair_free(key);
248 return NULL;
249 }
250
251 // Function to generate a key
252 srp_key_t *
253 srp_generate_key(void)
254 {
255 srp_key_t *key;
256 #ifndef EXCLUDE_CRYPTO
257 int status;
258 char errbuf[64];
259 const mbedtls_pk_info_t *key_type;
260 #endif
261
262 INFO("srp_key_setup");
263 key = srp_key_setup();
264 if (key == NULL) {
265 ERROR("srp_key_setup() failed.");
266 return NULL;
267 }
268 #ifndef EXCLUDE_CRYPTO
269 key_type = mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY);
270 if (key_type == NULL) {
271 INFO("mbedtls_pk_info_from_type failed");
272 return NULL;
273 }
274
275 INFO("mbedtls_pk_setup");
276 if ((status = mbedtls_pk_setup(&key->key, key_type)) != 0) {
277 mbedtls_strerror(status, errbuf, sizeof errbuf);
278 ERROR("mbedtls_pk_setup failed: %s", errbuf);
279 } else {
280 INFO("mbedtls_pk_ecdsa_genkey");
281 if ((status = mbedtls_ecdsa_genkey(mbedtls_pk_ec(key->key), MBEDTLS_ECP_DP_SECP256R1,
282 mbedtls_ctr_drbg_random, &rng_state->rng_context)) != 0) {
283 mbedtls_strerror(status, errbuf, sizeof errbuf);
284 ERROR("mbedtls_ecdsa_genkey failed: %s", errbuf);
285 } else {
286 return key;
287 }
288 }
289 srp_keypair_free(key);
290 return NULL;
291 #else
292 HAPPlatformRandomNumberFill(key->key, sizeof key->key);
293 return key;
294 #endif
295 }
296
297 // Copy an srp_key_t into a buffer. Key is not necessarily aligned with the beginning of the
298 // buffer; the return value, if not NULL, is the beginning of the key. If NULL, the buffer wasn't
299 // big enough.
300 uint8_t *
301 srp_store_key_to_buffer(uint8_t *buffer, size_t *length, srp_key_t *key)
302 {
303 #ifdef EXCLUDE_CRYPTO
304 if (*length < ECDSA_KEY_SIZE) {
305 return NULL;
306 }
307 if (*length > sizeof key->key) {
308 *length = sizeof key->key;
309 }
310 memcpy(buffer, key->key, *length);
311 return buffer;
312 #else
313 size_t len = mbedtls_pk_write_key_der(&key->key, buffer, *length);
314 uint8_t *ret;
315 char errbuf[64];
316 if (len <= 0) {
317 mbedtls_strerror(len, errbuf, sizeof errbuf);
318 ERROR("mbedtls_pk_write_key_der failed: %s", errbuf);
319 return NULL;
320 }
321 ret = &buffer[*length - len];
322 *length = len;
323 return ret;
324 #endif
325 }
326
327 srp_key_t *
328 srp_get_key(const char *key_name, void *os_context)
329 {
330 uint8_t buf[256];
331 uint16_t buf_length;
332 uint8_t *key_bytes;
333 size_t keydata_length;
334 int err;
335 srp_key_t *key;
336
337 err = srp_load_key_data(os_context, key_name, buf, &buf_length, sizeof buf);
338 if (err == kDNSServiceErr_NoError) {
339 key = srp_load_key_from_buffer(buf, buf_length);
340 if (key == NULL) {
341 INFO("load key fail");
342 return NULL;
343 }
344 // Otherwise we have a key.
345 } else if (err == kDNSServiceErr_NoSuchKey) {
346 key = srp_generate_key();
347 if (key == NULL) {
348 INFO("gen key fail");
349 return NULL;
350 }
351 keydata_length = sizeof buf;
352 if ((key_bytes = srp_store_key_to_buffer(buf, &keydata_length, key)) == NULL) {
353 INFO("store key fail");
354 return NULL;
355 }
356 // Note that it's possible for key_bytes != buf.
357 err = srp_store_key_data(os_context, key_name, key_bytes, (uint16_t)keydata_length);
358 if (err != kDNSServiceErr_NoError) {
359 INFO("store key data fail");
360 return NULL;
361 }
362 } else {
363 INFO("srp_get_key: weird error %d", err);
364 return NULL;
365 }
366 return key;
367 }
368
369 // Function to get the length of the public key
370 size_t
371 srp_pubkey_length(srp_key_t *key)
372 {
373 return ECDSA_KEY_SIZE;
374 }
375
376 int
377 srp_key_algorithm(srp_key_t *key)
378 {
379 return dnssec_keytype_ecdsa;
380 }
381
382 size_t
383 srp_signature_length(srp_key_t *key)
384 {
385 return ECDSA_KEY_SIZE;
386 }
387
388 // Function to copy out the public key as binary data
389 int
390 srp_pubkey_copy(uint8_t *buf, size_t max, srp_key_t *key)
391 {
392 #ifndef EXCLUDE_CRYPTO
393 mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(key->key);
394 char errbuf[64];
395 int status;
396
397 if (max < ECDSA_KEY_SIZE) {
398 return 0;
399 }
400
401 // Currently ECP only.
402 if ((status = mbedtls_mpi_write_binary(&ecp->Q.X, buf, ECDSA_KEY_PART_SIZE)) != 0 ||
403 (status = mbedtls_mpi_write_binary(&ecp->Q.Y, buf + ECDSA_KEY_PART_SIZE, ECDSA_KEY_PART_SIZE)) != 0) {
404 mbedtls_strerror(status, errbuf, sizeof errbuf);
405 ERROR("mbedtls_mpi_write_binary: %s", errbuf);
406 return 0;
407 }
408 #else
409 if (max < ECDSA_KEY_SIZE) {
410 return 0;
411 }
412
413 memcpy(buf, key->key, ECDSA_KEY_SIZE);
414 return ECDSA_KEY_SIZE;
415 #endif // EXCLUDE_CRYPTO
416
417 #ifdef MBEDTLS_PUBKEY_DUMP
418 int i;
419 fprintf(stderr, "pubkey %d: ", ECDSA_KEY_SIZE);
420 for (i = 0; i < ECDSA_KEY_SIZE; i++) {
421 fprintf(stderr, "%02x", buf[i]);
422 }
423 putc('\n', stderr);
424 #endif // EXCLUDE_CRYPTO
425 return ECDSA_KEY_SIZE;
426 }
427
428 // Function to generate a signature given some data and a private key
429 int
430 srp_sign(uint8_t *output, size_t max, uint8_t *message, size_t msglen, uint8_t *rr, size_t rdlen, srp_key_t *key)
431 {
432 #ifdef EXCLUDE_CRYPTO
433 return 1;
434 #else
435 int success = 1;
436 int status;
437 unsigned char hash[ECDSA_SHA256_HASH_SIZE];
438 char errbuf[64];
439 mbedtls_sha256_context *sha;
440 uint8_t shabuf[16 + sizeof(*sha)];
441 uint32_t *sbp;
442 mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(key->key);
443 mbedtls_mpi r, s;
444
445 #ifdef THREAD_DEVKIT_ADK
446 int i;
447 INFO("srp_sign(output=%p max=%d message=%p msglen=%d rr=%p rdlen=%d)",
448 output, max, message, msglen, rr, rdlen);
449 #endif
450
451 if (max < ECDSA_SHA256_SIG_SIZE) {
452 ERROR("srp_sign: not enough space in output buffer (%lu) for signature (%d).",
453 (unsigned long)max, ECDSA_SHA256_SIG_SIZE);
454 return 0;
455 }
456
457 sbp = (uint32_t *)shabuf;
458 sha = (mbedtls_sha256_context *)sbp;
459 mbedtls_sha256_init(sha);
460 #ifdef THREAD_DEVKIT_ADK
461 for (i = 0; i < sizeof shabuf; i += 16) {
462 INFO("%03x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
463 i, shabuf[i], shabuf[i + 1], shabuf[i + 2], shabuf[i + 3], shabuf[i + 4], shabuf[i + 5], shabuf[i + 6],
464 shabuf[i + 7], shabuf[i + 8], shabuf[i + 9], shabuf[i + 10], shabuf[i + 11], shabuf[i + 12],
465 shabuf[i + 13], shabuf[i + 14], shabuf[i + 15]);
466 }
467 INFO("1 rdlen=%d", rdlen);
468 #endif
469 memset(hash, 0, sizeof hash);
470 mbedtls_mpi_init(&r);
471 mbedtls_mpi_init(&s);
472
473 // Calculate the hash across first the SIG RR (minus the signature) and then the message
474 // up to but not including the SIG RR.
475 status = mbedtls_sha256_starts_ret(sha, 0);
476 #ifdef THREAD_DEVKIT_ADK
477 INFO("5 rdlen=%d", rdlen);
478 #endif
479 if (status == 0) {
480 status = srp_mbedtls_sha256_update_ret("rr", sha, rr, rdlen);
481 }
482 if (status == 0) {
483 status = srp_mbedtls_sha256_update_ret("message", sha, message, msglen);
484 }
485 if (status == 0) {
486 status = srp_mbedtls_sha256_finish_ret(sha, hash);
487 }
488 if (status != 0) {
489 mbedtls_strerror(status, errbuf, sizeof errbuf);
490 ERROR("mbedtls_sha_256 hash failed: %s", errbuf);
491 success = 0;
492 goto cleanup;
493 }
494
495 status = mbedtls_ecdsa_sign(&ecp->grp, &r, &s, &ecp->d, hash, sizeof hash,
496 mbedtls_ctr_drbg_random, &rng_state->rng_context);
497 if (status != 0) {
498 mbedtls_strerror(status, errbuf, sizeof errbuf);
499 ERROR("mbedtls_ecdsa_sign failed: %s", errbuf);
500 success = 0;
501 goto cleanup;
502 }
503
504 if ((status = mbedtls_mpi_write_binary(&r, output, ECDSA_SHA256_SIG_PART_SIZE)) != 0 ||
505 (status = mbedtls_mpi_write_binary(&s, output + ECDSA_SHA256_SIG_PART_SIZE,
506 ECDSA_SHA256_SIG_PART_SIZE)) != 0) {
507 mbedtls_strerror(status, errbuf, sizeof errbuf);
508 ERROR("mbedtls_ecdsa_sign failed: %s", errbuf);
509 success = 0;
510 goto cleanup;
511 }
512 cleanup:
513 mbedtls_mpi_free(&r);
514 mbedtls_mpi_free(&s);
515 return success;
516 #endif
517 }
518
519 // Local Variables:
520 // mode: C
521 // tab-width: 4
522 // c-file-style: "bsd"
523 // c-basic-offset: 4
524 // fill-column: 108
525 // indent-tabs-mode: nil
526 // End: