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