3 * Copyright (c) 2018 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.
24 #include <arpa/inet.h>
29 #include <sys/random.h>
30 #include <sys/errno.h>
34 #define SRP_CRYPTO_MBEDTLS_INTERNAL
35 #include "srp-crypto.h"
40 srp_mbedtls_sha256_update_ret(mbedtls_sha256_context
*sha
, uint8_t *data
, size_t len
)
43 fprintf(stderr
, "data %lu: ", (unsigned long)len
);
44 for (i
= 0; i
< len
; i
++) {
45 fprintf(stderr
, "%02x", data
[i
]);
48 return mbedtls_sha256_update_ret(sha
, data
, len
);
52 srp_mbedtls_sha256_finish_ret(mbedtls_sha256_context
*sha
, uint8_t *hash
)
55 int status
= mbedtls_sha256_finish_ret(sha
, hash
);
56 fprintf(stderr
, "hash: ");
57 for (i
= 0; i
< ECDSA_SHA256_HASH_SIZE
; i
++) {
58 fprintf(stderr
, "%02x", hash
[i
]);
65 // Key is stored in an opaque data structure, for mbedtls this is an mbedtls_pk_context.
66 // Function to read a public key from a KEY record
67 // Function to validate a signature given some data and a public key (not required on client)
69 // Function to free a key
71 srp_keypair_free(srp_key_t
*key
)
73 mbedtls_pk_free(&key
->key
);
74 mbedtls_entropy_free(&key
->entropy
);
75 mbedtls_ctr_drbg_free(&key
->ctr
);
79 // Needed to see the RNG with good entropy data.
81 get_entropy(void *data
, unsigned char *output
, size_t len
, size_t *outlen
)
83 int result
= getentropy(output
, len
);
87 ERROR("getentropy returned %s", strerror(errno
));
88 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
;
98 srp_key_t
*key
= calloc(sizeof *key
, 1);
105 mbedtls_pk_init(&key
->key
);
106 mbedtls_entropy_init(&key
->entropy
);
107 if ((status
= mbedtls_entropy_add_source(&key
->entropy
, get_entropy
,
108 NULL
, 1, MBEDTLS_ENTROPY_SOURCE_STRONG
)) != 0) {
109 mbedtls_strerror(status
, errbuf
, sizeof errbuf
);
110 ERROR("mbedtls_entropy_add_source failed: %s", errbuf
);
111 } else if ((status
= mbedtls_ctr_drbg_seed(&key
->ctr
, mbedtls_entropy_func
, &key
->entropy
, NULL
, 0)) != 0) {
112 mbedtls_strerror(status
, errbuf
, sizeof errbuf
);
113 ERROR("mbedtls_ctr_drbg_seed failed: %s", errbuf
);
117 mbedtls_pk_free(&key
->key
);
118 mbedtls_entropy_free(&key
->entropy
);
123 // Function to read a keypair from a file
125 srp_load_keypair(const char *file
)
127 int fd
= open(file
, O_RDONLY
);
128 unsigned char buf
[256];
135 if (errno
!= ENOENT
) {
136 ERROR("Unable to open srp.key: %s", strerror(errno
));
142 // The key is of limited size, so there's no reason to get fancy.
143 rv
= read(fd
, buf
, sizeof buf
);
145 if (rv
== sizeof buf
) {
146 ERROR("key file is unreasonably large.");
150 key
= srp_key_setup();
155 if ((status
= mbedtls_pk_parse_key(&key
->key
, buf
, rv
, NULL
, 0)) != 0) {
156 mbedtls_strerror(status
, errbuf
, sizeof errbuf
);
157 ERROR("mbedtls_pk_parse_key failed: %s", errbuf
);
158 } else if (!mbedtls_pk_can_do(&key
->key
, MBEDTLS_PK_ECDSA
)) {
159 ERROR("%s does not contain a usable ECDSA key.", file
);
163 srp_keypair_free(key
);
167 // Function to generate a key
169 srp_generate_key(void)
173 srp_key_t
*key
= srp_key_setup();
174 const mbedtls_pk_info_t
*key_type
= mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY
);
176 if (key
== NULL
|| key_type
== NULL
) {
180 if ((status
= mbedtls_pk_setup(&key
->key
, key_type
)) != 0) {
181 mbedtls_strerror(status
, errbuf
, sizeof errbuf
);
182 ERROR("mbedtls_pk_setup failed: %s", errbuf
);
183 } else if ((status
= mbedtls_ecdsa_genkey(mbedtls_pk_ec(key
->key
), MBEDTLS_ECP_DP_SECP256R1
,
184 mbedtls_ctr_drbg_random
, &key
->ctr
)) != 0) {
185 mbedtls_strerror(status
, errbuf
, sizeof errbuf
);
186 ERROR("mbedtls_ecdsa_genkey failed: %s", errbuf
);
190 srp_keypair_free(key
);
194 // Function to write a keypair to a file
196 srp_write_key_to_file(const char *file
, srp_key_t
*key
)
199 unsigned char buf
[256];
204 len
= mbedtls_pk_write_key_der(&key
->key
, buf
, sizeof buf
);
206 mbedtls_strerror(len
, errbuf
, sizeof errbuf
);
207 ERROR("mbedtls_pk_write_key_der failed: %s", errbuf
);
214 fd
= open(file
, O_CREAT
| O_EXCL
| O_WRONLY
| O_DIRECT
, 0700);
216 ERROR("Unable to create srp.key: %s", strerror(errno
));
220 rv
= write(fd
, &buf
[sizeof buf
- len
], len
);
223 ERROR("key file write truncated.");
231 // Function to get the length of the public key
233 srp_pubkey_length(srp_key_t
*key
)
235 return ECDSA_KEY_SIZE
;
239 srp_key_algorithm(srp_key_t
*key
)
241 return dnssec_keytype_ecdsa
;
245 srp_signature_length(srp_key_t
*key
)
247 return ECDSA_KEY_SIZE
;
250 // Function to copy out the public key as binary data
252 srp_pubkey_copy(uint8_t *buf
, size_t max
, srp_key_t
*key
)
254 mbedtls_ecp_keypair
*ecp
= mbedtls_pk_ec(key
->key
);
258 if (max
< ECDSA_KEY_SIZE
) {
262 // Currently ECP only.
263 if ((status
= mbedtls_mpi_write_binary(&ecp
->Q
.X
, buf
, ECDSA_KEY_PART_SIZE
)) != 0 ||
264 (status
= mbedtls_mpi_write_binary(&ecp
->Q
.Y
, buf
+ ECDSA_KEY_PART_SIZE
, ECDSA_KEY_PART_SIZE
)) != 0) {
265 mbedtls_strerror(status
, errbuf
, sizeof errbuf
);
266 ERROR("mbedtls_mpi_write_binary: %s", errbuf
);
270 #ifdef MBEDTLS_PUBKEY_DUMP
272 fprintf(stderr
, "pubkey %d: ", ECDSA_KEY_SIZE
);
273 for (i
= 0; i
< ECDSA_KEY_SIZE
; i
++) {
274 fprintf(stderr
, "%02x", buf
[i
]);
279 return ECDSA_KEY_SIZE
;
282 // Function to generate a signature given some data and a private key
284 srp_sign(uint8_t *output
, size_t max
, uint8_t *message
, size_t msglen
, uint8_t *rr
, size_t rdlen
, srp_key_t
*key
)
287 unsigned char hash
[ECDSA_SHA256_HASH_SIZE
];
289 mbedtls_sha256_context sha
;
290 mbedtls_ecp_keypair
*ecp
= mbedtls_pk_ec(key
->key
);
293 if (max
< ECDSA_SHA256_SIG_SIZE
) {
294 ERROR("srp_sign: not enough space in output buffer (%lu) for signature (%d).",
295 (unsigned long)max
, ECDSA_SHA256_SIG_SIZE
);
299 mbedtls_sha256_init(&sha
);
300 memset(hash
, 0, sizeof hash
);
301 mbedtls_mpi_init(&r
);
302 mbedtls_mpi_init(&s
);
304 // Calculate the hash across first the SIG RR (minus the signature) and then the message
305 // up to but not including the SIG RR.
306 if ((status
= mbedtls_sha256_starts_ret(&sha
, 0)) != 0 ||
307 (status
= srp_mbedtls_sha256_update_ret(&sha
, rr
, rdlen
) != 0) ||
308 (status
= srp_mbedtls_sha256_update_ret(&sha
, message
, msglen
)) != 0 ||
309 (status
= srp_mbedtls_sha256_finish_ret(&sha
, hash
)) != 0) {
310 mbedtls_strerror(status
, errbuf
, sizeof errbuf
);
311 ERROR("mbedtls_sha_256 hash failed: %s", errbuf
);
315 status
= mbedtls_ecdsa_sign(&ecp
->grp
, &r
, &s
, &ecp
->d
, hash
, sizeof hash
,
316 mbedtls_ctr_drbg_random
, &key
->ctr
);
318 mbedtls_strerror(status
, errbuf
, sizeof errbuf
);
319 ERROR("mbedtls_ecdsa_sign failed: %s", errbuf
);
323 if ((status
= mbedtls_mpi_write_binary(&r
, output
, ECDSA_SHA256_SIG_PART_SIZE
)) != 0 ||
324 (status
= mbedtls_mpi_write_binary(&s
, output
+ ECDSA_SHA256_SIG_PART_SIZE
,
325 ECDSA_SHA256_SIG_PART_SIZE
)) != 0) {
326 mbedtls_strerror(status
, errbuf
, sizeof errbuf
);
327 ERROR("mbedtls_ecdsa_sign failed: %s", errbuf
);
336 // c-file-style: "bsd"
339 // indent-tabs-mode: nil