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
srp_mbedtls_sha256_update_ret(const char * thing_name,mbedtls_sha256_context * sha,uint8_t * data,size_t len)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
srp_mbedtls_sha256_finish_ret(mbedtls_sha256_context * sha,uint8_t * hash)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
srp_keypair_free(srp_key_t * key)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
get_entropy(void * data,unsigned char * output,size_t len,size_t * outlen)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
rng_state_fetch(void)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 *
srp_key_setup(void)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
srp_random16()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 *
srp_load_key_from_buffer(const uint8_t * buffer,size_t length)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 *
srp_generate_key(void)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 *
srp_store_key_to_buffer(uint8_t * buffer,size_t * length,srp_key_t * key)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 *
srp_get_key(const char * key_name,void * os_context)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
srp_pubkey_length(srp_key_t * key)371 srp_pubkey_length(srp_key_t *key)
372 {
373     return ECDSA_KEY_SIZE;
374 }
375 
376 int
srp_key_algorithm(srp_key_t * key)377 srp_key_algorithm(srp_key_t *key)
378 {
379     return dnssec_keytype_ecdsa;
380 }
381 
382 size_t
srp_signature_length(srp_key_t * key)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
srp_pubkey_copy(uint8_t * buf,size_t max,srp_key_t * key)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
srp_sign(uint8_t * output,size_t max,uint8_t * message,size_t msglen,uint8_t * rr,size_t rdlen,srp_key_t * key)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:
527