sshsig.c revision 1.1.1.2 1 /*
2 * Copyright (c) 2019 Google LLC
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <stdarg.h>
20 #include <errno.h>
21 #include <string.h>
22 #include <unistd.h>
23
24 #include "authfd.h"
25 #include "authfile.h"
26 #include "log.h"
27 #include "misc.h"
28 #include "sshbuf.h"
29 #include "sshsig.h"
30 #include "ssherr.h"
31 #include "sshkey.h"
32 #include "match.h"
33 #include "digest.h"
34
35 #define SIG_VERSION 0x01
36 #define MAGIC_PREAMBLE "SSHSIG"
37 #define MAGIC_PREAMBLE_LEN (sizeof(MAGIC_PREAMBLE) - 1)
38 #define BEGIN_SIGNATURE "-----BEGIN SSH SIGNATURE-----\n"
39 #define END_SIGNATURE "-----END SSH SIGNATURE-----"
40 #define RSA_SIGN_ALG "rsa-sha2-512" /* XXX maybe make configurable */
41 #define RSA_SIGN_ALLOWED "rsa-sha2-512,rsa-sha2-256"
42 #define HASHALG_DEFAULT "sha512" /* XXX maybe make configurable */
43 #define HASHALG_ALLOWED "sha256,sha512"
44
45 int
46 sshsig_armor(const struct sshbuf *blob, struct sshbuf **out)
47 {
48 struct sshbuf *buf = NULL;
49 int r = SSH_ERR_INTERNAL_ERROR;
50
51 *out = NULL;
52
53 if ((buf = sshbuf_new()) == NULL) {
54 error("%s: sshbuf_new failed", __func__);
55 r = SSH_ERR_ALLOC_FAIL;
56 goto out;
57 }
58
59 if ((r = sshbuf_put(buf, BEGIN_SIGNATURE,
60 sizeof(BEGIN_SIGNATURE)-1)) != 0) {
61 error("%s: sshbuf_putf failed: %s", __func__, ssh_err(r));
62 goto out;
63 }
64
65 if ((r = sshbuf_dtob64(blob, buf, 1)) != 0) {
66 error("%s: Couldn't base64 encode signature blob: %s",
67 __func__, ssh_err(r));
68 goto out;
69 }
70
71 if ((r = sshbuf_put(buf, END_SIGNATURE,
72 sizeof(END_SIGNATURE)-1)) != 0 ||
73 (r = sshbuf_put_u8(buf, '\n')) != 0) {
74 error("%s: sshbuf_put failed: %s", __func__, ssh_err(r));
75 goto out;
76 }
77 /* success */
78 *out = buf;
79 buf = NULL; /* transferred */
80 r = 0;
81 out:
82 sshbuf_free(buf);
83 return r;
84 }
85
86 int
87 sshsig_dearmor(struct sshbuf *sig, struct sshbuf **out)
88 {
89 int r;
90 size_t eoffset = 0;
91 struct sshbuf *buf = NULL;
92 struct sshbuf *sbuf = NULL;
93 char *b64 = NULL;
94
95 if ((sbuf = sshbuf_fromb(sig)) == NULL) {
96 error("%s: sshbuf_fromb failed", __func__);
97 return SSH_ERR_ALLOC_FAIL;
98 }
99
100 if ((r = sshbuf_cmp(sbuf, 0,
101 BEGIN_SIGNATURE, sizeof(BEGIN_SIGNATURE)-1)) != 0) {
102 error("Couldn't parse signature: missing header");
103 goto done;
104 }
105
106 if ((r = sshbuf_consume(sbuf, sizeof(BEGIN_SIGNATURE)-1)) != 0) {
107 error("%s: sshbuf_consume failed: %s", __func__, ssh_err(r));
108 goto done;
109 }
110
111 if ((r = sshbuf_find(sbuf, 0, "\n" END_SIGNATURE,
112 sizeof("\n" END_SIGNATURE)-1, &eoffset)) != 0) {
113 error("Couldn't parse signature: missing footer");
114 goto done;
115 }
116
117 if ((r = sshbuf_consume_end(sbuf, sshbuf_len(sbuf)-eoffset)) != 0) {
118 error("%s: sshbuf_consume failed: %s", __func__, ssh_err(r));
119 goto done;
120 }
121
122 if ((b64 = sshbuf_dup_string(sbuf)) == NULL) {
123 error("%s: sshbuf_dup_string failed", __func__);
124 r = SSH_ERR_ALLOC_FAIL;
125 goto done;
126 }
127
128 if ((buf = sshbuf_new()) == NULL) {
129 error("%s: sshbuf_new() failed", __func__);
130 r = SSH_ERR_ALLOC_FAIL;
131 goto done;
132 }
133
134 if ((r = sshbuf_b64tod(buf, b64)) != 0) {
135 error("Couldn't decode signature: %s", ssh_err(r));
136 goto done;
137 }
138
139 /* success */
140 *out = buf;
141 r = 0;
142 buf = NULL; /* transferred */
143 done:
144 sshbuf_free(buf);
145 sshbuf_free(sbuf);
146 free(b64);
147 return r;
148 }
149
150 static int
151 sshsig_wrap_sign(struct sshkey *key, const char *hashalg,
152 const char *sk_provider, const struct sshbuf *h_message,
153 const char *sig_namespace, struct sshbuf **out,
154 sshsig_signer *signer, void *signer_ctx)
155 {
156 int r;
157 size_t slen = 0;
158 u_char *sig = NULL;
159 struct sshbuf *blob = NULL;
160 struct sshbuf *tosign = NULL;
161 const char *sign_alg = NULL;
162
163 if ((tosign = sshbuf_new()) == NULL ||
164 (blob = sshbuf_new()) == NULL) {
165 error("%s: sshbuf_new failed", __func__);
166 r = SSH_ERR_ALLOC_FAIL;
167 goto done;
168 }
169
170 if ((r = sshbuf_put(tosign, MAGIC_PREAMBLE, MAGIC_PREAMBLE_LEN)) != 0 ||
171 (r = sshbuf_put_cstring(tosign, sig_namespace)) != 0 ||
172 (r = sshbuf_put_string(tosign, NULL, 0)) != 0 || /* reserved */
173 (r = sshbuf_put_cstring(tosign, hashalg)) != 0 ||
174 (r = sshbuf_put_stringb(tosign, h_message)) != 0) {
175 error("Couldn't construct message to sign: %s", ssh_err(r));
176 goto done;
177 }
178
179 /* If using RSA keys then default to a good signature algorithm */
180 if (sshkey_type_plain(key->type) == KEY_RSA)
181 sign_alg = RSA_SIGN_ALG;
182
183 if (signer != NULL) {
184 if ((r = signer(key, &sig, &slen,
185 sshbuf_ptr(tosign), sshbuf_len(tosign),
186 sign_alg, sk_provider, 0, signer_ctx)) != 0) {
187 error("Couldn't sign message: %s", ssh_err(r));
188 goto done;
189 }
190 } else {
191 if ((r = sshkey_sign(key, &sig, &slen,
192 sshbuf_ptr(tosign), sshbuf_len(tosign),
193 sign_alg, sk_provider, 0)) != 0) {
194 error("Couldn't sign message: %s", ssh_err(r));
195 goto done;
196 }
197 }
198
199 if ((r = sshbuf_put(blob, MAGIC_PREAMBLE, MAGIC_PREAMBLE_LEN)) != 0 ||
200 (r = sshbuf_put_u32(blob, SIG_VERSION)) != 0 ||
201 (r = sshkey_puts(key, blob)) != 0 ||
202 (r = sshbuf_put_cstring(blob, sig_namespace)) != 0 ||
203 (r = sshbuf_put_string(blob, NULL, 0)) != 0 || /* reserved */
204 (r = sshbuf_put_cstring(blob, hashalg)) != 0 ||
205 (r = sshbuf_put_string(blob, sig, slen)) != 0) {
206 error("Couldn't populate blob: %s", ssh_err(r));
207 goto done;
208 }
209
210 *out = blob;
211 blob = NULL;
212 r = 0;
213 done:
214 free(sig);
215 sshbuf_free(blob);
216 sshbuf_free(tosign);
217 return r;
218 }
219
220 /* Check preamble and version. */
221 static int
222 sshsig_parse_preamble(struct sshbuf *buf)
223 {
224 int r = SSH_ERR_INTERNAL_ERROR;
225 uint32_t sversion;
226
227 if ((r = sshbuf_cmp(buf, 0, MAGIC_PREAMBLE, MAGIC_PREAMBLE_LEN)) != 0 ||
228 (r = sshbuf_consume(buf, (sizeof(MAGIC_PREAMBLE)-1))) != 0 ||
229 (r = sshbuf_get_u32(buf, &sversion)) != 0) {
230 error("Couldn't verify signature: invalid format");
231 return r;
232 }
233
234 if (sversion > SIG_VERSION) {
235 error("Signature version %lu is larger than supported "
236 "version %u", (unsigned long)sversion, SIG_VERSION);
237 return SSH_ERR_INVALID_FORMAT;
238 }
239 return 0;
240 }
241
242 static int
243 sshsig_check_hashalg(const char *hashalg)
244 {
245 if (hashalg == NULL ||
246 match_pattern_list(hashalg, HASHALG_ALLOWED, 0) == 1)
247 return 0;
248 error("%s: unsupported hash algorithm \"%.100s\"", __func__, hashalg);
249 return SSH_ERR_SIGN_ALG_UNSUPPORTED;
250 }
251
252 static int
253 sshsig_peek_hashalg(struct sshbuf *signature, char **hashalgp)
254 {
255 struct sshbuf *buf = NULL;
256 char *hashalg = NULL;
257 int r = SSH_ERR_INTERNAL_ERROR;
258
259 if (hashalgp != NULL)
260 *hashalgp = NULL;
261 if ((buf = sshbuf_fromb(signature)) == NULL)
262 return SSH_ERR_ALLOC_FAIL;
263 if ((r = sshsig_parse_preamble(buf)) != 0)
264 goto done;
265 if ((r = sshbuf_get_string_direct(buf, NULL, NULL)) != 0 ||
266 (r = sshbuf_get_string_direct(buf, NULL, NULL)) != 0 ||
267 (r = sshbuf_get_string(buf, NULL, NULL)) != 0 ||
268 (r = sshbuf_get_cstring(buf, &hashalg, NULL)) != 0 ||
269 (r = sshbuf_get_string_direct(buf, NULL, NULL)) != 0) {
270 error("Couldn't parse signature blob: %s", ssh_err(r));
271 goto done;
272 }
273
274 /* success */
275 r = 0;
276 *hashalgp = hashalg;
277 hashalg = NULL;
278 done:
279 free(hashalg);
280 sshbuf_free(buf);
281 return r;
282 }
283
284 static int
285 sshsig_wrap_verify(struct sshbuf *signature, const char *hashalg,
286 const struct sshbuf *h_message, const char *expect_namespace,
287 struct sshkey **sign_keyp, struct sshkey_sig_details **sig_details)
288 {
289 int r = SSH_ERR_INTERNAL_ERROR;
290 struct sshbuf *buf = NULL, *toverify = NULL;
291 struct sshkey *key = NULL;
292 const u_char *sig;
293 char *got_namespace = NULL, *sigtype = NULL, *sig_hashalg = NULL;
294 size_t siglen;
295
296 debug("%s: verify message length %zu", __func__, sshbuf_len(h_message));
297 if (sig_details != NULL)
298 *sig_details = NULL;
299 if (sign_keyp != NULL)
300 *sign_keyp = NULL;
301
302 if ((toverify = sshbuf_new()) == NULL) {
303 error("%s: sshbuf_new failed", __func__);
304 r = SSH_ERR_ALLOC_FAIL;
305 goto done;
306 }
307 if ((r = sshbuf_put(toverify, MAGIC_PREAMBLE,
308 MAGIC_PREAMBLE_LEN)) != 0 ||
309 (r = sshbuf_put_cstring(toverify, expect_namespace)) != 0 ||
310 (r = sshbuf_put_string(toverify, NULL, 0)) != 0 || /* reserved */
311 (r = sshbuf_put_cstring(toverify, hashalg)) != 0 ||
312 (r = sshbuf_put_stringb(toverify, h_message)) != 0) {
313 error("Couldn't construct message to verify: %s", ssh_err(r));
314 goto done;
315 }
316
317 if ((r = sshsig_parse_preamble(signature)) != 0)
318 goto done;
319
320 if ((r = sshkey_froms(signature, &key)) != 0 ||
321 (r = sshbuf_get_cstring(signature, &got_namespace, NULL)) != 0 ||
322 (r = sshbuf_get_string(signature, NULL, NULL)) != 0 ||
323 (r = sshbuf_get_cstring(signature, &sig_hashalg, NULL)) != 0 ||
324 (r = sshbuf_get_string_direct(signature, &sig, &siglen)) != 0) {
325 error("Couldn't parse signature blob: %s", ssh_err(r));
326 goto done;
327 }
328
329 if (sshbuf_len(signature) != 0) {
330 error("Signature contains trailing data");
331 r = SSH_ERR_INVALID_FORMAT;
332 goto done;
333 }
334
335 if (strcmp(expect_namespace, got_namespace) != 0) {
336 error("Couldn't verify signature: namespace does not match");
337 debug("%s: expected namespace \"%s\" received \"%s\"",
338 __func__, expect_namespace, got_namespace);
339 r = SSH_ERR_SIGNATURE_INVALID;
340 goto done;
341 }
342 if (strcmp(hashalg, sig_hashalg) != 0) {
343 error("Couldn't verify signature: hash algorithm mismatch");
344 debug("%s: expected algorithm \"%s\" received \"%s\"",
345 __func__, hashalg, sig_hashalg);
346 r = SSH_ERR_SIGNATURE_INVALID;
347 goto done;
348 }
349 /* Ensure that RSA keys use an acceptable signature algorithm */
350 if (sshkey_type_plain(key->type) == KEY_RSA) {
351 if ((r = sshkey_get_sigtype(sig, siglen, &sigtype)) != 0) {
352 error("Couldn't verify signature: unable to get "
353 "signature type: %s", ssh_err(r));
354 goto done;
355 }
356 if (match_pattern_list(sigtype, RSA_SIGN_ALLOWED, 0) != 1) {
357 error("Couldn't verify signature: unsupported RSA "
358 "signature algorithm %s", sigtype);
359 r = SSH_ERR_SIGN_ALG_UNSUPPORTED;
360 goto done;
361 }
362 }
363 if ((r = sshkey_verify(key, sig, siglen, sshbuf_ptr(toverify),
364 sshbuf_len(toverify), NULL, 0, sig_details)) != 0) {
365 error("Signature verification failed: %s", ssh_err(r));
366 goto done;
367 }
368
369 /* success */
370 r = 0;
371 if (sign_keyp != NULL) {
372 *sign_keyp = key;
373 key = NULL; /* transferred */
374 }
375 done:
376 free(got_namespace);
377 free(sigtype);
378 free(sig_hashalg);
379 sshbuf_free(buf);
380 sshbuf_free(toverify);
381 sshkey_free(key);
382 return r;
383 }
384
385 static int
386 hash_buffer(const struct sshbuf *m, const char *hashalg, struct sshbuf **bp)
387 {
388 char *hex, hash[SSH_DIGEST_MAX_LENGTH];
389 int alg, r = SSH_ERR_INTERNAL_ERROR;
390 struct sshbuf *b = NULL;
391
392 *bp = NULL;
393 memset(hash, 0, sizeof(hash));
394
395 if ((r = sshsig_check_hashalg(hashalg)) != 0)
396 return r;
397 if ((alg = ssh_digest_alg_by_name(hashalg)) == -1) {
398 error("%s: can't look up hash algorithm %s",
399 __func__, hashalg);
400 return SSH_ERR_INTERNAL_ERROR;
401 }
402 if ((r = ssh_digest_buffer(alg, m, hash, sizeof(hash))) != 0) {
403 error("%s: ssh_digest_buffer failed: %s", __func__, ssh_err(r));
404 return r;
405 }
406 if ((hex = tohex(hash, ssh_digest_bytes(alg))) != NULL) {
407 debug3("%s: final hash: %s", __func__, hex);
408 freezero(hex, strlen(hex));
409 }
410 if ((b = sshbuf_new()) == NULL) {
411 r = SSH_ERR_ALLOC_FAIL;
412 goto out;
413 }
414 if ((r = sshbuf_put(b, hash, ssh_digest_bytes(alg))) != 0) {
415 error("%s: sshbuf_put: %s", __func__, ssh_err(r));
416 goto out;
417 }
418 *bp = b;
419 b = NULL; /* transferred */
420 /* success */
421 r = 0;
422 out:
423 sshbuf_free(b);
424 explicit_bzero(hash, sizeof(hash));
425 return 0;
426 }
427
428 int
429 sshsig_signb(struct sshkey *key, const char *hashalg, const char *sk_provider,
430 const struct sshbuf *message, const char *sig_namespace,
431 struct sshbuf **out, sshsig_signer *signer, void *signer_ctx)
432 {
433 struct sshbuf *b = NULL;
434 int r = SSH_ERR_INTERNAL_ERROR;
435
436 if (hashalg == NULL)
437 hashalg = HASHALG_DEFAULT;
438 if (out != NULL)
439 *out = NULL;
440 if ((r = hash_buffer(message, hashalg, &b)) != 0) {
441 error("%s: hash_buffer failed: %s", __func__, ssh_err(r));
442 goto out;
443 }
444 if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, b,
445 sig_namespace, out, signer, signer_ctx)) != 0)
446 goto out;
447 /* success */
448 r = 0;
449 out:
450 sshbuf_free(b);
451 return r;
452 }
453
454 int
455 sshsig_verifyb(struct sshbuf *signature, const struct sshbuf *message,
456 const char *expect_namespace, struct sshkey **sign_keyp,
457 struct sshkey_sig_details **sig_details)
458 {
459 struct sshbuf *b = NULL;
460 int r = SSH_ERR_INTERNAL_ERROR;
461 char *hashalg = NULL;
462
463 if (sig_details != NULL)
464 *sig_details = NULL;
465 if (sign_keyp != NULL)
466 *sign_keyp = NULL;
467 if ((r = sshsig_peek_hashalg(signature, &hashalg)) != 0)
468 return r;
469 debug("%s: signature made with hash \"%s\"", __func__, hashalg);
470 if ((r = hash_buffer(message, hashalg, &b)) != 0) {
471 error("%s: hash_buffer failed: %s", __func__, ssh_err(r));
472 goto out;
473 }
474 if ((r = sshsig_wrap_verify(signature, hashalg, b, expect_namespace,
475 sign_keyp, sig_details)) != 0)
476 goto out;
477 /* success */
478 r = 0;
479 out:
480 sshbuf_free(b);
481 free(hashalg);
482 return r;
483 }
484
485 static int
486 hash_file(int fd, const char *hashalg, struct sshbuf **bp)
487 {
488 char *hex, rbuf[8192], hash[SSH_DIGEST_MAX_LENGTH];
489 ssize_t n, total = 0;
490 struct ssh_digest_ctx *ctx;
491 int alg, oerrno, r = SSH_ERR_INTERNAL_ERROR;
492 struct sshbuf *b = NULL;
493
494 *bp = NULL;
495 memset(hash, 0, sizeof(hash));
496
497 if ((r = sshsig_check_hashalg(hashalg)) != 0)
498 return r;
499 if ((alg = ssh_digest_alg_by_name(hashalg)) == -1) {
500 error("%s: can't look up hash algorithm %s",
501 __func__, hashalg);
502 return SSH_ERR_INTERNAL_ERROR;
503 }
504 if ((ctx = ssh_digest_start(alg)) == NULL) {
505 error("%s: ssh_digest_start failed", __func__);
506 return SSH_ERR_INTERNAL_ERROR;
507 }
508 for (;;) {
509 if ((n = read(fd, rbuf, sizeof(rbuf))) == -1) {
510 if (errno == EINTR || errno == EAGAIN)
511 continue;
512 oerrno = errno;
513 error("%s: read: %s", __func__, strerror(errno));
514 ssh_digest_free(ctx);
515 errno = oerrno;
516 r = SSH_ERR_SYSTEM_ERROR;
517 goto out;
518 } else if (n == 0) {
519 debug2("%s: hashed %zu bytes", __func__, total);
520 break; /* EOF */
521 }
522 total += (size_t)n;
523 if ((r = ssh_digest_update(ctx, rbuf, (size_t)n)) != 0) {
524 error("%s: ssh_digest_update: %s",
525 __func__, ssh_err(r));
526 goto out;
527 }
528 }
529 if ((r = ssh_digest_final(ctx, hash, sizeof(hash))) != 0) {
530 error("%s: ssh_digest_final: %s", __func__, ssh_err(r));
531 goto out;
532 }
533 if ((hex = tohex(hash, ssh_digest_bytes(alg))) != NULL) {
534 debug3("%s: final hash: %s", __func__, hex);
535 freezero(hex, strlen(hex));
536 }
537 if ((b = sshbuf_new()) == NULL) {
538 r = SSH_ERR_ALLOC_FAIL;
539 goto out;
540 }
541 if ((r = sshbuf_put(b, hash, ssh_digest_bytes(alg))) != 0) {
542 error("%s: sshbuf_put: %s", __func__, ssh_err(r));
543 goto out;
544 }
545 *bp = b;
546 b = NULL; /* transferred */
547 /* success */
548 r = 0;
549 out:
550 sshbuf_free(b);
551 ssh_digest_free(ctx);
552 explicit_bzero(hash, sizeof(hash));
553 return 0;
554 }
555
556 int
557 sshsig_sign_fd(struct sshkey *key, const char *hashalg, const char *sk_provider,
558 int fd, const char *sig_namespace, struct sshbuf **out,
559 sshsig_signer *signer, void *signer_ctx)
560 {
561 struct sshbuf *b = NULL;
562 int r = SSH_ERR_INTERNAL_ERROR;
563
564 if (hashalg == NULL)
565 hashalg = HASHALG_DEFAULT;
566 if (out != NULL)
567 *out = NULL;
568 if ((r = hash_file(fd, hashalg, &b)) != 0) {
569 error("%s: hash_file failed: %s", __func__, ssh_err(r));
570 return r;
571 }
572 if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, b,
573 sig_namespace, out, signer, signer_ctx)) != 0)
574 goto out;
575 /* success */
576 r = 0;
577 out:
578 sshbuf_free(b);
579 return r;
580 }
581
582 int
583 sshsig_verify_fd(struct sshbuf *signature, int fd,
584 const char *expect_namespace, struct sshkey **sign_keyp,
585 struct sshkey_sig_details **sig_details)
586 {
587 struct sshbuf *b = NULL;
588 int r = SSH_ERR_INTERNAL_ERROR;
589 char *hashalg = NULL;
590
591 if (sig_details != NULL)
592 *sig_details = NULL;
593 if (sign_keyp != NULL)
594 *sign_keyp = NULL;
595 if ((r = sshsig_peek_hashalg(signature, &hashalg)) != 0)
596 return r;
597 debug("%s: signature made with hash \"%s\"", __func__, hashalg);
598 if ((r = hash_file(fd, hashalg, &b)) != 0) {
599 error("%s: hash_file failed: %s", __func__, ssh_err(r));
600 goto out;
601 }
602 if ((r = sshsig_wrap_verify(signature, hashalg, b, expect_namespace,
603 sign_keyp, sig_details)) != 0)
604 goto out;
605 /* success */
606 r = 0;
607 out:
608 sshbuf_free(b);
609 free(hashalg);
610 return r;
611 }
612
613 struct sshsigopt {
614 int ca;
615 char *namespaces;
616 };
617
618 struct sshsigopt *
619 sshsigopt_parse(const char *opts, const char *path, u_long linenum,
620 const char **errstrp)
621 {
622 struct sshsigopt *ret;
623 int r;
624 const char *errstr = NULL;
625
626 if ((ret = calloc(1, sizeof(*ret))) == NULL)
627 return NULL;
628 if (opts == NULL || *opts == '\0')
629 return ret; /* Empty options yields empty options :) */
630
631 while (*opts && *opts != ' ' && *opts != '\t') {
632 /* flag options */
633 if ((r = opt_flag("cert-authority", 0, &opts)) != -1) {
634 ret->ca = 1;
635 } else if (opt_match(&opts, "namespaces")) {
636 if (ret->namespaces != NULL) {
637 errstr = "multiple \"namespaces\" clauses";
638 goto fail;
639 }
640 ret->namespaces = opt_dequote(&opts, &errstr);
641 if (ret->namespaces == NULL)
642 goto fail;
643 }
644 /*
645 * Skip the comma, and move to the next option
646 * (or break out if there are no more).
647 */
648 if (*opts == '\0' || *opts == ' ' || *opts == '\t')
649 break; /* End of options. */
650 /* Anything other than a comma is an unknown option */
651 if (*opts != ',') {
652 errstr = "unknown key option";
653 goto fail;
654 }
655 opts++;
656 if (*opts == '\0') {
657 errstr = "unexpected end-of-options";
658 goto fail;
659 }
660 }
661 /* success */
662 return ret;
663 fail:
664 if (errstrp != NULL)
665 *errstrp = errstr;
666 sshsigopt_free(ret);
667 return NULL;
668 }
669
670 void
671 sshsigopt_free(struct sshsigopt *opts)
672 {
673 if (opts == NULL)
674 return;
675 free(opts->namespaces);
676 free(opts);
677 }
678
679 static int
680 parse_principals_key_and_options(const char *path, u_long linenum, char *line,
681 const char *required_principal, char **principalsp, struct sshkey **keyp,
682 struct sshsigopt **sigoptsp)
683 {
684 char *opts = NULL, *tmp, *cp, *principals = NULL;
685 const char *reason = NULL;
686 struct sshsigopt *sigopts = NULL;
687 struct sshkey *key = NULL;
688 int r = SSH_ERR_INTERNAL_ERROR;
689
690 if (principalsp != NULL)
691 *principalsp = NULL;
692 if (sigoptsp != NULL)
693 *sigoptsp = NULL;
694 if (keyp != NULL)
695 *keyp = NULL;
696
697 cp = line;
698 cp = cp + strspn(cp, " \t"); /* skip leading whitespace */
699 if (*cp == '#' || *cp == '\0')
700 return SSH_ERR_KEY_NOT_FOUND; /* blank or all-comment line */
701
702 /* format: identity[,identity...] [option[,option...]] key */
703 if ((tmp = strdelimw(&cp)) == NULL) {
704 error("%s:%lu: invalid line", path, linenum);
705 r = SSH_ERR_INVALID_FORMAT;
706 goto out;
707 }
708 if ((principals = strdup(tmp)) == NULL) {
709 error("%s: strdup failed", __func__);
710 r = SSH_ERR_ALLOC_FAIL;
711 goto out;
712 }
713 /*
714 * Bail out early if we're looking for a particular principal and this
715 * line does not list it.
716 */
717 if (required_principal != NULL) {
718 if (match_pattern_list(required_principal,
719 principals, 0) != 1) {
720 /* principal didn't match */
721 r = SSH_ERR_KEY_NOT_FOUND;
722 goto out;
723 }
724 debug("%s: %s:%lu: matched principal \"%s\"",
725 __func__, path, linenum, required_principal);
726 }
727
728 if ((key = sshkey_new(KEY_UNSPEC)) == NULL) {
729 error("%s: sshkey_new failed", __func__);
730 r = SSH_ERR_ALLOC_FAIL;
731 goto out;
732 }
733 if (sshkey_read(key, &cp) != 0) {
734 /* no key? Check for options */
735 opts = cp;
736 if (sshkey_advance_past_options(&cp) != 0) {
737 error("%s:%lu: invalid options", path, linenum);
738 r = SSH_ERR_INVALID_FORMAT;
739 goto out;
740 }
741 *cp++ = '\0';
742 skip_space(&cp);
743 if (sshkey_read(key, &cp) != 0) {
744 error("%s:%lu: invalid key", path, linenum);
745 r = SSH_ERR_INVALID_FORMAT;
746 goto out;
747 }
748 }
749 debug3("%s:%lu: options %s", path, linenum, opts == NULL ? "" : opts);
750 if ((sigopts = sshsigopt_parse(opts, path, linenum, &reason)) == NULL) {
751 error("%s:%lu: bad options: %s", path, linenum, reason);
752 r = SSH_ERR_INVALID_FORMAT;
753 goto out;
754 }
755 /* success */
756 if (principalsp != NULL) {
757 *principalsp = principals;
758 principals = NULL; /* transferred */
759 }
760 if (sigoptsp != NULL) {
761 *sigoptsp = sigopts;
762 sigopts = NULL; /* transferred */
763 }
764 if (keyp != NULL) {
765 *keyp = key;
766 key = NULL; /* transferred */
767 }
768 r = 0;
769 out:
770 free(principals);
771 sshsigopt_free(sigopts);
772 sshkey_free(key);
773 return r;
774 }
775
776 static int
777 check_allowed_keys_line(const char *path, u_long linenum, char *line,
778 const struct sshkey *sign_key, const char *principal,
779 const char *sig_namespace)
780 {
781 struct sshkey *found_key = NULL;
782 int r, found = 0;
783 const char *reason = NULL;
784 struct sshsigopt *sigopts = NULL;
785
786 /* Parse the line */
787 if ((r = parse_principals_key_and_options(path, linenum, line,
788 principal, NULL, &found_key, &sigopts)) != 0) {
789 /* error already logged */
790 goto done;
791 }
792
793 /* Check whether options preclude the use of this key */
794 if (sigopts->namespaces != NULL &&
795 match_pattern_list(sig_namespace, sigopts->namespaces, 0) != 1) {
796 error("%s:%lu: key is not permitted for use in signature "
797 "namespace \"%s\"", path, linenum, sig_namespace);
798 goto done;
799 }
800
801 if (!sigopts->ca && sshkey_equal(found_key, sign_key)) {
802 /* Exact match of key */
803 debug("%s:%lu: matched key and principal", path, linenum);
804 /* success */
805 found = 1;
806 } else if (sigopts->ca && sshkey_is_cert(sign_key) &&
807 sshkey_equal_public(sign_key->cert->signature_key, found_key)) {
808 /* Match of certificate's CA key */
809 if ((r = sshkey_cert_check_authority(sign_key, 0, 1,
810 principal, &reason)) != 0) {
811 error("%s:%lu: certificate not authorized: %s",
812 path, linenum, reason);
813 goto done;
814 }
815 debug("%s:%lu: matched certificate CA key", path, linenum);
816 /* success */
817 found = 1;
818 } else {
819 /* Principal matched but key didn't */
820 goto done;
821 }
822 done:
823 sshkey_free(found_key);
824 sshsigopt_free(sigopts);
825 return found ? 0 : SSH_ERR_KEY_NOT_FOUND;
826 }
827
828 int
829 sshsig_check_allowed_keys(const char *path, const struct sshkey *sign_key,
830 const char *principal, const char *sig_namespace)
831 {
832 FILE *f = NULL;
833 char *line = NULL;
834 size_t linesize = 0;
835 u_long linenum = 0;
836 int r, oerrno;
837
838 /* Check key and principal against file */
839 if ((f = fopen(path, "r")) == NULL) {
840 oerrno = errno;
841 error("Unable to open allowed keys file \"%s\": %s",
842 path, strerror(errno));
843 errno = oerrno;
844 return SSH_ERR_SYSTEM_ERROR;
845 }
846
847 while (getline(&line, &linesize, f) != -1) {
848 linenum++;
849 r = check_allowed_keys_line(path, linenum, line, sign_key,
850 principal, sig_namespace);
851 free(line);
852 line = NULL;
853 if (r == SSH_ERR_KEY_NOT_FOUND)
854 continue;
855 else if (r == 0) {
856 /* success */
857 fclose(f);
858 return 0;
859 } else
860 break;
861 }
862 /* Either we hit an error parsing or we simply didn't find the key */
863 fclose(f);
864 free(line);
865 return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r;
866 }
867
868 static int
869 cert_filter_principals(const char *path, u_long linenum,
870 char **principalsp, const struct sshkey *cert)
871 {
872 char *cp, *oprincipals, *principals;
873 const char *reason;
874 struct sshbuf *nprincipals;
875 int r = SSH_ERR_INTERNAL_ERROR, success = 0;
876
877 oprincipals = principals = *principalsp;
878 *principalsp = NULL;
879
880 if ((nprincipals = sshbuf_new()) == NULL)
881 return SSH_ERR_ALLOC_FAIL;
882
883 while ((cp = strsep(&principals, ",")) != NULL && *cp != '\0') {
884 if (strcspn(cp, "!?*") != strlen(cp)) {
885 debug("%s:%lu: principal \"%s\" not authorized: "
886 "contains wildcards", path, linenum, cp);
887 continue;
888 }
889 /* Check against principals list in certificate */
890 if ((r = sshkey_cert_check_authority(cert, 0, 1,
891 cp, &reason)) != 0) {
892 debug("%s:%lu: principal \"%s\" not authorized: %s",
893 path, linenum, cp, reason);
894 continue;
895 }
896 if ((r = sshbuf_putf(nprincipals, "%s%s",
897 sshbuf_len(nprincipals) != 0 ? "," : "", cp)) != 0) {
898 error("%s: buffer error", __func__);
899 goto out;
900 }
901 }
902 if (sshbuf_len(nprincipals) == 0) {
903 error("%s:%lu: no valid principals found", path, linenum);
904 r = SSH_ERR_KEY_CERT_INVALID;
905 goto out;
906 }
907 if ((principals = sshbuf_dup_string(nprincipals)) == NULL) {
908 error("%s: buffer error", __func__);
909 goto out;
910 }
911 /* success */
912 success = 1;
913 *principalsp = principals;
914 out:
915 sshbuf_free(nprincipals);
916 free(oprincipals);
917 return success ? 0 : r;
918 }
919
920 static int
921 get_matching_principals_from_line(const char *path, u_long linenum, char *line,
922 const struct sshkey *sign_key, char **principalsp)
923 {
924 struct sshkey *found_key = NULL;
925 char *principals = NULL;
926 int r, found = 0;
927 struct sshsigopt *sigopts = NULL;
928
929 if (principalsp != NULL)
930 *principalsp = NULL;
931
932 /* Parse the line */
933 if ((r = parse_principals_key_and_options(path, linenum, line,
934 NULL, &principals, &found_key, &sigopts)) != 0) {
935 /* error already logged */
936 goto done;
937 }
938
939 if (!sigopts->ca && sshkey_equal(found_key, sign_key)) {
940 /* Exact match of key */
941 debug("%s:%lu: matched key", path, linenum);
942 /* success */
943 found = 1;
944 } else if (sigopts->ca && sshkey_is_cert(sign_key) &&
945 sshkey_equal_public(sign_key->cert->signature_key, found_key)) {
946 /* Remove principals listed in file but not allowed by cert */
947 if ((r = cert_filter_principals(path, linenum,
948 &principals, sign_key)) != 0) {
949 /* error already displayed */
950 debug("%s:%lu: cert_filter_principals: %s",
951 path, linenum, ssh_err(r));
952 goto done;
953 }
954 debug("%s:%lu: matched certificate CA key", path, linenum);
955 /* success */
956 found = 1;
957 } else {
958 /* Key didn't match */
959 goto done;
960 }
961 done:
962 if (found) {
963 *principalsp = principals;
964 principals = NULL; /* transferred */
965 }
966 free(principals);
967 sshkey_free(found_key);
968 sshsigopt_free(sigopts);
969 return found ? 0 : SSH_ERR_KEY_NOT_FOUND;
970 }
971
972 int
973 sshsig_find_principals(const char *path, const struct sshkey *sign_key,
974 char **principals)
975 {
976 FILE *f = NULL;
977 char *line = NULL;
978 size_t linesize = 0;
979 u_long linenum = 0;
980 int r, oerrno;
981
982 if ((f = fopen(path, "r")) == NULL) {
983 oerrno = errno;
984 error("Unable to open allowed keys file \"%s\": %s",
985 path, strerror(errno));
986 errno = oerrno;
987 return SSH_ERR_SYSTEM_ERROR;
988 }
989
990 while (getline(&line, &linesize, f) != -1) {
991 linenum++;
992 r = get_matching_principals_from_line(path, linenum, line,
993 sign_key, principals);
994 free(line);
995 line = NULL;
996 if (r == SSH_ERR_KEY_NOT_FOUND)
997 continue;
998 else if (r == 0) {
999 /* success */
1000 fclose(f);
1001 return 0;
1002 } else
1003 break;
1004 }
1005 free(line);
1006 /* Either we hit an error parsing or we simply didn't find the key */
1007 if (ferror(f) != 0) {
1008 oerrno = errno;
1009 fclose(f);
1010 error("Unable to read allowed keys file \"%s\": %s",
1011 path, strerror(errno));
1012 errno = oerrno;
1013 return SSH_ERR_SYSTEM_ERROR;
1014 }
1015 fclose(f);
1016 return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r;
1017 }
1018
1019 int
1020 sshsig_get_pubkey(struct sshbuf *signature, struct sshkey **pubkey)
1021 {
1022 struct sshkey *pk = NULL;
1023 int r = SSH_ERR_SIGNATURE_INVALID;
1024
1025 if (pubkey != NULL)
1026 *pubkey = NULL;
1027 if ((r = sshsig_parse_preamble(signature)) != 0)
1028 return r;
1029 if ((r = sshkey_froms(signature, &pk)) != 0)
1030 return r;
1031
1032 *pubkey = pk;
1033 pk = NULL;
1034 return 0;
1035 }
1036