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