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