]> git.saurik.com Git - apple/mdnsresponder.git/blob - ServiceRegistration/sign-mbedtls.c
mDNSResponder-1096.100.3.tar.gz
[apple/mdnsresponder.git] / ServiceRegistration / sign-mbedtls.c
1 /* sign.c
2 *
3 * Copyright (c) 2018 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
23 #include <stdio.h>
24 #include <arpa/inet.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <sys/random.h>
30 #include <sys/errno.h>
31
32 #include "srp.h"
33 #include "dns-msg.h"
34 #define SRP_CRYPTO_MBEDTLS_INTERNAL
35 #include "srp-crypto.h"
36
37 // For debugging
38 #ifdef DEBUG_SHA256
39 int
40 srp_mbedtls_sha256_update_ret(mbedtls_sha256_context *sha, uint8_t *data, size_t len)
41 {
42 int i;
43 fprintf(stderr, "data %lu: ", (unsigned long)len);
44 for (i = 0; i < len; i++) {
45 fprintf(stderr, "%02x", data[i]);
46 }
47 fputs("\n", stderr);
48 return mbedtls_sha256_update_ret(sha, data, len);
49 }
50
51 int
52 srp_mbedtls_sha256_finish_ret(mbedtls_sha256_context *sha, uint8_t *hash)
53 {
54 int i;
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]);
59 }
60 fputs("\n", stderr);
61 return status;
62 }
63 #endif
64
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)
68
69 // Function to free a key
70 void
71 srp_keypair_free(srp_key_t *key)
72 {
73 mbedtls_pk_free(&key->key);
74 mbedtls_entropy_free(&key->entropy);
75 mbedtls_ctr_drbg_free(&key->ctr);
76 free(key);
77 }
78
79 // Needed to see the RNG with good entropy data.
80 static int
81 get_entropy(void *data, unsigned char *output, size_t len, size_t *outlen)
82 {
83 int result = getentropy(output, len);
84 (void)data;
85
86 if (result != 0) {
87 ERROR("getentropy returned %s", strerror(errno));
88 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
89 }
90 *outlen = len;
91 return 0;
92 }
93
94 static srp_key_t *
95 srp_key_setup(void)
96 {
97 int status;
98 srp_key_t *key = calloc(sizeof *key, 1);
99 char errbuf[64];
100
101 if (key == NULL) {
102 return key;
103 }
104
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);
114 } else {
115 return key;
116 }
117 mbedtls_pk_free(&key->key);
118 mbedtls_entropy_free(&key->entropy);
119 free(key);
120 return NULL;
121 }
122
123 // Function to read a keypair from a file
124 srp_key_t *
125 srp_load_keypair(const char *file)
126 {
127 int fd = open(file, O_RDONLY);
128 unsigned char buf[256];
129 ssize_t rv;
130 srp_key_t *key;
131 int status;
132 char errbuf[64];
133
134 if (fd < 0) {
135 if (errno != ENOENT) {
136 ERROR("Unable to open srp.key: %s", strerror(errno));
137 return NULL;
138 }
139 return NULL;
140 }
141
142 // The key is of limited size, so there's no reason to get fancy.
143 rv = read(fd, buf, sizeof buf);
144 close(fd);
145 if (rv == sizeof buf) {
146 ERROR("key file is unreasonably large.");
147 return NULL;
148 }
149
150 key = srp_key_setup();
151 if (key == NULL) {
152 return NULL;
153 }
154
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);
160 } else {
161 return key;
162 }
163 srp_keypair_free(key);
164 return NULL;
165 }
166
167 // Function to generate a key
168 srp_key_t *
169 srp_generate_key(void)
170 {
171 int status;
172 char errbuf[64];
173 srp_key_t *key = srp_key_setup();
174 const mbedtls_pk_info_t *key_type = mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY);
175
176 if (key == NULL || key_type == NULL) {
177 return NULL;
178 }
179
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);
187 } else {
188 return key;
189 }
190 srp_keypair_free(key);
191 return NULL;
192 }
193
194 // Function to write a keypair to a file
195 int
196 srp_write_key_to_file(const char *file, srp_key_t *key)
197 {
198 int fd;
199 unsigned char buf[256];
200 ssize_t rv;
201 int len;
202 char errbuf[64];
203
204 len = mbedtls_pk_write_key_der(&key->key, buf, sizeof buf);
205 if (len <= 0) {
206 mbedtls_strerror(len, errbuf, sizeof errbuf);
207 ERROR("mbedtls_pk_write_key_der failed: %s", errbuf);
208 return 0;
209 }
210
211 #ifndef O_DIRECT
212 #define O_DIRECT 0
213 #endif
214 fd = open(file, O_CREAT | O_EXCL | O_WRONLY | O_DIRECT, 0700);
215 if (fd < 0) {
216 ERROR("Unable to create srp.key: %s", strerror(errno));
217 return 0;
218 }
219
220 rv = write(fd, &buf[sizeof buf - len], len);
221 close(fd);
222 if (rv != len) {
223 ERROR("key file write truncated.");
224 unlink(file);
225 return 0;
226 }
227
228 return 1;
229 }
230
231 // Function to get the length of the public key
232 size_t
233 srp_pubkey_length(srp_key_t *key)
234 {
235 return ECDSA_KEY_SIZE;
236 }
237
238 int
239 srp_key_algorithm(srp_key_t *key)
240 {
241 return dnssec_keytype_ecdsa;
242 }
243
244 size_t
245 srp_signature_length(srp_key_t *key)
246 {
247 return ECDSA_KEY_SIZE;
248 }
249
250 // Function to copy out the public key as binary data
251 int
252 srp_pubkey_copy(uint8_t *buf, size_t max, srp_key_t *key)
253 {
254 mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(key->key);
255 char errbuf[64];
256 int status;
257
258 if (max < ECDSA_KEY_SIZE) {
259 return 0;
260 }
261
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);
267 return 0;
268 }
269
270 #ifdef MBEDTLS_PUBKEY_DUMP
271 int i;
272 fprintf(stderr, "pubkey %d: ", ECDSA_KEY_SIZE);
273 for (i = 0; i < ECDSA_KEY_SIZE; i++) {
274 fprintf(stderr, "%02x", buf[i]);
275 }
276 putc('\n', stderr);
277 #endif
278
279 return ECDSA_KEY_SIZE;
280 }
281
282 // Function to generate a signature given some data and a private key
283 int
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)
285 {
286 int status;
287 unsigned char hash[ECDSA_SHA256_HASH_SIZE];
288 char errbuf[64];
289 mbedtls_sha256_context sha;
290 mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(key->key);
291 mbedtls_mpi r, s;
292
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);
296 return 0;
297 }
298
299 mbedtls_sha256_init(&sha);
300 memset(hash, 0, sizeof hash);
301 mbedtls_mpi_init(&r);
302 mbedtls_mpi_init(&s);
303
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);
312 return 0;
313 }
314
315 status = mbedtls_ecdsa_sign(&ecp->grp, &r, &s, &ecp->d, hash, sizeof hash,
316 mbedtls_ctr_drbg_random, &key->ctr);
317 if (status != 0) {
318 mbedtls_strerror(status, errbuf, sizeof errbuf);
319 ERROR("mbedtls_ecdsa_sign failed: %s", errbuf);
320 return 0;
321 }
322
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);
328 return 0;
329 }
330 return 1;
331 }
332
333 // Local Variables:
334 // mode: C
335 // tab-width: 4
336 // c-file-style: "bsd"
337 // c-basic-offset: 4
338 // fill-column: 108
339 // indent-tabs-mode: nil
340 // End: