3 * Copyright (c) 2018-2019 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * DNS SIG(0) signature generation for DNSSD SRP using mbedtls.
19 * Functions required for loading, saving, and generating public/private keypairs, extracting the public key
20 * into KEY RR data, and computing signatures.
22 * This is the implementation for mbedtls, e.g. on Thread Devices, Linux, and OpenWRT.
26 #ifdef THREAD_DEVKIT_ADK
27 #include <openthread/random_noncrypto.h>
28 #include "HAPPlatformRandomNumber.h"
30 #include <arpa/inet.h>
31 #ifdef LINUX_GETENTROPY
33 #include <linux/random.h>
34 #include <sys/syscall.h>
36 #include <sys/random.h>
37 #endif // LINUX_GETENTROPY
38 #endif // THREAD_DEVKIT_ADK
47 #define SRP_CRYPTO_MBEDTLS_INTERNAL 1
48 #include "srp-crypto.h"
54 srp_mbedtls_sha256_update_ret(const char *thing_name
,
55 mbedtls_sha256_context
*sha
, uint8_t *data
, size_t len
)
58 fprintf(stderr
, "%s %lu: ", thing_name
, (unsigned long)len
);
63 for (i
= 0; i
< len
; i
++) {
64 fprintf(stderr
, "%02x", data
[i
]);
67 return mbedtls_sha256_update_ret(sha
, data
, len
);
71 srp_mbedtls_sha256_finish_ret(mbedtls_sha256_context
*sha
, uint8_t *hash
)
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
]);
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)
88 // Function to free a key
90 srp_keypair_free(srp_key_t
*key
)
92 #ifndef EXCLUDE_CRYPTO
93 mbedtls_pk_free(&key
->key
);
98 #ifndef EXCLUDE_CRYPTO
99 // Needed to seed the RNG with good entropy data.
101 get_entropy(void *data
, unsigned char *output
, size_t len
, size_t *outlen
)
103 #ifdef THREAD_DEVKIT_ADK
104 HAPPlatformRandomNumberFill(output
, len
);
108 #ifdef LINUX_GETENTROPY
109 int result
= syscall(SYS_getrandom
, output
, len
, GRND_RANDOM
);
111 int result
= getentropy(output
, len
);
116 ERROR("getentropy returned %s", strerror(errno
));
117 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
;
120 #endif // THREAD_DEVKIT_ADK
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
;
133 static rng_state_t
*rng_state
;
136 rng_state_fetch(void)
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.");
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
);
151 mbedtls_strerror(status
, rng_state
->errbuf
, sizeof rng_state
->errbuf
);
152 ERROR("mbedtls_entropy_add_source failed: %s", rng_state
->errbuf
);
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);
161 mbedtls_strerror(status
, rng_state
->errbuf
, sizeof rng_state
->errbuf
);
162 ERROR("mbedtls_ctr_drbg_seed failed: %s", rng_state
->errbuf
);
171 #endif // EXCLUDE_CRYPTO
176 srp_key_t
*key
= calloc(1, sizeof(*key
));
182 #ifndef EXCLUDE_CRYPTO
183 mbedtls_pk_init(&key
->key
);
184 if (rng_state_fetch()) {
187 mbedtls_pk_free(&key
->key
);
198 #ifdef EXCLUDE_CRYPTO
199 // Note that this is the wrong thing to return here and needs to be fixed.
200 return otRandomNonCryptoGetUint16();
205 if (rng_state_fetch()) {
206 status
= mbedtls_ctr_drbg_random(&rng_state
->rng_context
, (unsigned char *)&ret
, sizeof ret
);
208 mbedtls_strerror(status
, errbuf
, sizeof errbuf
);
209 ERROR("mbedtls_ctr_drbg_random failed: %s", errbuf
);
219 srp_load_key_from_buffer(const uint8_t *buffer
, size_t length
)
222 #ifndef EXCLUDE_CRYPTO
227 key
= srp_key_setup();
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.");
242 if (length
== ECDSA_KEY_SIZE
) {
243 memcpy(key
->key
, buffer
, length
);
247 srp_keypair_free(key
);
251 // Function to generate a key
253 srp_generate_key(void)
256 #ifndef EXCLUDE_CRYPTO
259 const mbedtls_pk_info_t
*key_type
;
262 INFO("srp_key_setup");
263 key
= srp_key_setup();
265 ERROR("srp_key_setup() failed.");
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");
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
);
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
);
289 srp_keypair_free(key
);
292 HAPPlatformRandomNumberFill(key
->key
, sizeof key
->key
);
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
301 srp_store_key_to_buffer(uint8_t *buffer
, size_t *length
, srp_key_t
*key
)
303 #ifdef EXCLUDE_CRYPTO
304 if (*length
< ECDSA_KEY_SIZE
) {
307 if (*length
> sizeof key
->key
) {
308 *length
= sizeof key
->key
;
310 memcpy(buffer
, key
->key
, *length
);
313 size_t len
= mbedtls_pk_write_key_der(&key
->key
, buffer
, *length
);
317 mbedtls_strerror(len
, errbuf
, sizeof errbuf
);
318 ERROR("mbedtls_pk_write_key_der failed: %s", errbuf
);
321 ret
= &buffer
[*length
- len
];
328 srp_get_key(const char *key_name
, void *os_context
)
333 size_t keydata_length
;
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
);
341 INFO("load key fail");
344 // Otherwise we have a key.
345 } else if (err
== kDNSServiceErr_NoSuchKey
) {
346 key
= srp_generate_key();
348 INFO("gen key fail");
351 keydata_length
= sizeof buf
;
352 if ((key_bytes
= srp_store_key_to_buffer(buf
, &keydata_length
, key
)) == NULL
) {
353 INFO("store key fail");
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");
363 INFO("srp_get_key: weird error %d", err
);
369 // Function to get the length of the public key
371 srp_pubkey_length(srp_key_t
*key
)
373 return ECDSA_KEY_SIZE
;
377 srp_key_algorithm(srp_key_t
*key
)
379 return dnssec_keytype_ecdsa
;
383 srp_signature_length(srp_key_t
*key
)
385 return ECDSA_KEY_SIZE
;
388 // Function to copy out the public key as binary data
390 srp_pubkey_copy(uint8_t *buf
, size_t max
, srp_key_t
*key
)
392 #ifndef EXCLUDE_CRYPTO
393 mbedtls_ecp_keypair
*ecp
= mbedtls_pk_ec(key
->key
);
397 if (max
< ECDSA_KEY_SIZE
) {
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
);
409 if (max
< ECDSA_KEY_SIZE
) {
413 memcpy(buf
, key
->key
, ECDSA_KEY_SIZE
);
414 return ECDSA_KEY_SIZE
;
415 #endif // EXCLUDE_CRYPTO
417 #ifdef MBEDTLS_PUBKEY_DUMP
419 fprintf(stderr
, "pubkey %d: ", ECDSA_KEY_SIZE
);
420 for (i
= 0; i
< ECDSA_KEY_SIZE
; i
++) {
421 fprintf(stderr
, "%02x", buf
[i
]);
424 #endif // EXCLUDE_CRYPTO
425 return ECDSA_KEY_SIZE
;
428 // Function to generate a signature given some data and a private 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
)
432 #ifdef EXCLUDE_CRYPTO
437 unsigned char hash
[ECDSA_SHA256_HASH_SIZE
];
439 mbedtls_sha256_context
*sha
;
440 uint8_t shabuf
[16 + sizeof(*sha
)];
442 mbedtls_ecp_keypair
*ecp
= mbedtls_pk_ec(key
->key
);
445 #ifdef THREAD_DEVKIT_ADK
447 INFO("srp_sign(output=%p max=%d message=%p msglen=%d rr=%p rdlen=%d)",
448 output
, max
, message
, msglen
, rr
, rdlen
);
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
);
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]);
467 INFO("1 rdlen=%d", rdlen
);
469 memset(hash
, 0, sizeof hash
);
470 mbedtls_mpi_init(&r
);
471 mbedtls_mpi_init(&s
);
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
);
480 status
= srp_mbedtls_sha256_update_ret("rr", sha
, rr
, rdlen
);
483 status
= srp_mbedtls_sha256_update_ret("message", sha
, message
, msglen
);
486 status
= srp_mbedtls_sha256_finish_ret(sha
, hash
);
489 mbedtls_strerror(status
, errbuf
, sizeof errbuf
);
490 ERROR("mbedtls_sha_256 hash failed: %s", errbuf
);
495 status
= mbedtls_ecdsa_sign(&ecp
->grp
, &r
, &s
, &ecp
->d
, hash
, sizeof hash
,
496 mbedtls_ctr_drbg_random
, &rng_state
->rng_context
);
498 mbedtls_strerror(status
, errbuf
, sizeof errbuf
);
499 ERROR("mbedtls_ecdsa_sign failed: %s", errbuf
);
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
);
513 mbedtls_mpi_free(&r
);
514 mbedtls_mpi_free(&s
);
522 // c-file-style: "bsd"
525 // indent-tabs-mode: nil