diff options
Diffstat (limited to 'krl.c')
-rw-r--r-- | krl.c | 845 |
1 files changed, 454 insertions, 391 deletions
@@ -14,12 +14,12 @@ | |||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | /* $OpenBSD: krl.c,v 1.17 2014/06/24 01:13:21 djm Exp $ */ | 17 | /* $OpenBSD: krl.c,v 1.31 2015/01/30 01:10:33 djm Exp $ */ |
18 | 18 | ||
19 | #include "includes.h" | 19 | #include "includes.h" |
20 | 20 | ||
21 | #include <sys/param.h> /* MIN */ | ||
21 | #include <sys/types.h> | 22 | #include <sys/types.h> |
22 | #include <sys/param.h> | ||
23 | #include <openbsd-compat/sys-tree.h> | 23 | #include <openbsd-compat/sys-tree.h> |
24 | #include <openbsd-compat/sys-queue.h> | 24 | #include <openbsd-compat/sys-queue.h> |
25 | 25 | ||
@@ -30,12 +30,14 @@ | |||
30 | #include <time.h> | 30 | #include <time.h> |
31 | #include <unistd.h> | 31 | #include <unistd.h> |
32 | 32 | ||
33 | #include "buffer.h" | 33 | #include "sshbuf.h" |
34 | #include "key.h" | 34 | #include "ssherr.h" |
35 | #include "sshkey.h" | ||
35 | #include "authfile.h" | 36 | #include "authfile.h" |
36 | #include "misc.h" | 37 | #include "misc.h" |
37 | #include "log.h" | 38 | #include "log.h" |
38 | #include "xmalloc.h" | 39 | #include "digest.h" |
40 | #include "bitmap.h" | ||
39 | 41 | ||
40 | #include "krl.h" | 42 | #include "krl.h" |
41 | 43 | ||
@@ -72,7 +74,7 @@ RB_GENERATE_STATIC(revoked_key_id_tree, revoked_key_id, tree_entry, key_id_cmp); | |||
72 | /* Tree of blobs (used for keys and fingerprints) */ | 74 | /* Tree of blobs (used for keys and fingerprints) */ |
73 | struct revoked_blob { | 75 | struct revoked_blob { |
74 | u_char *blob; | 76 | u_char *blob; |
75 | u_int len; | 77 | size_t len; |
76 | RB_ENTRY(revoked_blob) tree_entry; | 78 | RB_ENTRY(revoked_blob) tree_entry; |
77 | }; | 79 | }; |
78 | static int blob_cmp(struct revoked_blob *a, struct revoked_blob *b); | 80 | static int blob_cmp(struct revoked_blob *a, struct revoked_blob *b); |
@@ -81,7 +83,7 @@ RB_GENERATE_STATIC(revoked_blob_tree, revoked_blob, tree_entry, blob_cmp); | |||
81 | 83 | ||
82 | /* Tracks revoked certs for a single CA */ | 84 | /* Tracks revoked certs for a single CA */ |
83 | struct revoked_certs { | 85 | struct revoked_certs { |
84 | Key *ca_key; | 86 | struct sshkey *ca_key; |
85 | struct revoked_serial_tree revoked_serials; | 87 | struct revoked_serial_tree revoked_serials; |
86 | struct revoked_key_id_tree revoked_key_ids; | 88 | struct revoked_key_id_tree revoked_key_ids; |
87 | TAILQ_ENTRY(revoked_certs) entry; | 89 | TAILQ_ENTRY(revoked_certs) entry; |
@@ -154,8 +156,7 @@ revoked_certs_free(struct revoked_certs *rc) | |||
154 | free(rki->key_id); | 156 | free(rki->key_id); |
155 | free(rki); | 157 | free(rki); |
156 | } | 158 | } |
157 | if (rc->ca_key != NULL) | 159 | sshkey_free(rc->ca_key); |
158 | key_free(rc->ca_key); | ||
159 | } | 160 | } |
160 | 161 | ||
161 | void | 162 | void |
@@ -190,12 +191,13 @@ ssh_krl_set_version(struct ssh_krl *krl, u_int64_t version) | |||
190 | krl->krl_version = version; | 191 | krl->krl_version = version; |
191 | } | 192 | } |
192 | 193 | ||
193 | void | 194 | int |
194 | ssh_krl_set_comment(struct ssh_krl *krl, const char *comment) | 195 | ssh_krl_set_comment(struct ssh_krl *krl, const char *comment) |
195 | { | 196 | { |
196 | free(krl->comment); | 197 | free(krl->comment); |
197 | if ((krl->comment = strdup(comment)) == NULL) | 198 | if ((krl->comment = strdup(comment)) == NULL) |
198 | fatal("%s: strdup", __func__); | 199 | return SSH_ERR_ALLOC_FAIL; |
200 | return 0; | ||
199 | } | 201 | } |
200 | 202 | ||
201 | /* | 203 | /* |
@@ -203,14 +205,16 @@ ssh_krl_set_comment(struct ssh_krl *krl, const char *comment) | |||
203 | * create a new one in the tree if one did not exist already. | 205 | * create a new one in the tree if one did not exist already. |
204 | */ | 206 | */ |
205 | static int | 207 | static int |
206 | revoked_certs_for_ca_key(struct ssh_krl *krl, const Key *ca_key, | 208 | revoked_certs_for_ca_key(struct ssh_krl *krl, const struct sshkey *ca_key, |
207 | struct revoked_certs **rcp, int allow_create) | 209 | struct revoked_certs **rcp, int allow_create) |
208 | { | 210 | { |
209 | struct revoked_certs *rc; | 211 | struct revoked_certs *rc; |
212 | int r; | ||
210 | 213 | ||
211 | *rcp = NULL; | 214 | *rcp = NULL; |
212 | TAILQ_FOREACH(rc, &krl->revoked_certs, entry) { | 215 | TAILQ_FOREACH(rc, &krl->revoked_certs, entry) { |
213 | if (key_equal(rc->ca_key, ca_key)) { | 216 | if ((ca_key == NULL && rc->ca_key == NULL) || |
217 | sshkey_equal(rc->ca_key, ca_key)) { | ||
214 | *rcp = rc; | 218 | *rcp = rc; |
215 | return 0; | 219 | return 0; |
216 | } | 220 | } |
@@ -219,15 +223,18 @@ revoked_certs_for_ca_key(struct ssh_krl *krl, const Key *ca_key, | |||
219 | return 0; | 223 | return 0; |
220 | /* If this CA doesn't exist in the list then add it now */ | 224 | /* If this CA doesn't exist in the list then add it now */ |
221 | if ((rc = calloc(1, sizeof(*rc))) == NULL) | 225 | if ((rc = calloc(1, sizeof(*rc))) == NULL) |
222 | return -1; | 226 | return SSH_ERR_ALLOC_FAIL; |
223 | if ((rc->ca_key = key_from_private(ca_key)) == NULL) { | 227 | if (ca_key == NULL) |
228 | rc->ca_key = NULL; | ||
229 | else if ((r = sshkey_from_private(ca_key, &rc->ca_key)) != 0) { | ||
224 | free(rc); | 230 | free(rc); |
225 | return -1; | 231 | return r; |
226 | } | 232 | } |
227 | RB_INIT(&rc->revoked_serials); | 233 | RB_INIT(&rc->revoked_serials); |
228 | RB_INIT(&rc->revoked_key_ids); | 234 | RB_INIT(&rc->revoked_key_ids); |
229 | TAILQ_INSERT_TAIL(&krl->revoked_certs, rc, entry); | 235 | TAILQ_INSERT_TAIL(&krl->revoked_certs, rc, entry); |
230 | debug3("%s: new CA %s", __func__, key_type(ca_key)); | 236 | KRL_DBG(("%s: new CA %s", __func__, |
237 | ca_key == NULL ? "*" : sshkey_type(ca_key))); | ||
231 | *rcp = rc; | 238 | *rcp = rc; |
232 | return 0; | 239 | return 0; |
233 | } | 240 | } |
@@ -245,14 +252,14 @@ insert_serial_range(struct revoked_serial_tree *rt, u_int64_t lo, u_int64_t hi) | |||
245 | if (ers == NULL || serial_cmp(ers, &rs) != 0) { | 252 | if (ers == NULL || serial_cmp(ers, &rs) != 0) { |
246 | /* No entry matches. Just insert */ | 253 | /* No entry matches. Just insert */ |
247 | if ((irs = malloc(sizeof(rs))) == NULL) | 254 | if ((irs = malloc(sizeof(rs))) == NULL) |
248 | return -1; | 255 | return SSH_ERR_ALLOC_FAIL; |
249 | memcpy(irs, &rs, sizeof(*irs)); | 256 | memcpy(irs, &rs, sizeof(*irs)); |
250 | ers = RB_INSERT(revoked_serial_tree, rt, irs); | 257 | ers = RB_INSERT(revoked_serial_tree, rt, irs); |
251 | if (ers != NULL) { | 258 | if (ers != NULL) { |
252 | KRL_DBG(("%s: bad: ers != NULL", __func__)); | 259 | KRL_DBG(("%s: bad: ers != NULL", __func__)); |
253 | /* Shouldn't happen */ | 260 | /* Shouldn't happen */ |
254 | free(irs); | 261 | free(irs); |
255 | return -1; | 262 | return SSH_ERR_INTERNAL_ERROR; |
256 | } | 263 | } |
257 | ers = irs; | 264 | ers = irs; |
258 | } else { | 265 | } else { |
@@ -267,6 +274,7 @@ insert_serial_range(struct revoked_serial_tree *rt, u_int64_t lo, u_int64_t hi) | |||
267 | if (ers->hi < hi) | 274 | if (ers->hi < hi) |
268 | ers->hi = hi; | 275 | ers->hi = hi; |
269 | } | 276 | } |
277 | |||
270 | /* | 278 | /* |
271 | * The inserted or revised range might overlap or abut adjacent ones; | 279 | * The inserted or revised range might overlap or abut adjacent ones; |
272 | * coalesce as necessary. | 280 | * coalesce as necessary. |
@@ -305,40 +313,42 @@ insert_serial_range(struct revoked_serial_tree *rt, u_int64_t lo, u_int64_t hi) | |||
305 | } | 313 | } |
306 | 314 | ||
307 | int | 315 | int |
308 | ssh_krl_revoke_cert_by_serial(struct ssh_krl *krl, const Key *ca_key, | 316 | ssh_krl_revoke_cert_by_serial(struct ssh_krl *krl, const struct sshkey *ca_key, |
309 | u_int64_t serial) | 317 | u_int64_t serial) |
310 | { | 318 | { |
311 | return ssh_krl_revoke_cert_by_serial_range(krl, ca_key, serial, serial); | 319 | return ssh_krl_revoke_cert_by_serial_range(krl, ca_key, serial, serial); |
312 | } | 320 | } |
313 | 321 | ||
314 | int | 322 | int |
315 | ssh_krl_revoke_cert_by_serial_range(struct ssh_krl *krl, const Key *ca_key, | 323 | ssh_krl_revoke_cert_by_serial_range(struct ssh_krl *krl, |
316 | u_int64_t lo, u_int64_t hi) | 324 | const struct sshkey *ca_key, u_int64_t lo, u_int64_t hi) |
317 | { | 325 | { |
318 | struct revoked_certs *rc; | 326 | struct revoked_certs *rc; |
327 | int r; | ||
319 | 328 | ||
320 | if (lo > hi || lo == 0) | 329 | if (lo > hi || lo == 0) |
321 | return -1; | 330 | return SSH_ERR_INVALID_ARGUMENT; |
322 | if (revoked_certs_for_ca_key(krl, ca_key, &rc, 1) != 0) | 331 | if ((r = revoked_certs_for_ca_key(krl, ca_key, &rc, 1)) != 0) |
323 | return -1; | 332 | return r; |
324 | return insert_serial_range(&rc->revoked_serials, lo, hi); | 333 | return insert_serial_range(&rc->revoked_serials, lo, hi); |
325 | } | 334 | } |
326 | 335 | ||
327 | int | 336 | int |
328 | ssh_krl_revoke_cert_by_key_id(struct ssh_krl *krl, const Key *ca_key, | 337 | ssh_krl_revoke_cert_by_key_id(struct ssh_krl *krl, const struct sshkey *ca_key, |
329 | const char *key_id) | 338 | const char *key_id) |
330 | { | 339 | { |
331 | struct revoked_key_id *rki, *erki; | 340 | struct revoked_key_id *rki, *erki; |
332 | struct revoked_certs *rc; | 341 | struct revoked_certs *rc; |
342 | int r; | ||
333 | 343 | ||
334 | if (revoked_certs_for_ca_key(krl, ca_key, &rc, 1) != 0) | 344 | if ((r = revoked_certs_for_ca_key(krl, ca_key, &rc, 1)) != 0) |
335 | return -1; | 345 | return r; |
336 | 346 | ||
337 | debug3("%s: revoke %s", __func__, key_id); | 347 | KRL_DBG(("%s: revoke %s", __func__, key_id)); |
338 | if ((rki = calloc(1, sizeof(*rki))) == NULL || | 348 | if ((rki = calloc(1, sizeof(*rki))) == NULL || |
339 | (rki->key_id = strdup(key_id)) == NULL) { | 349 | (rki->key_id = strdup(key_id)) == NULL) { |
340 | free(rki); | 350 | free(rki); |
341 | fatal("%s: strdup", __func__); | 351 | return SSH_ERR_ALLOC_FAIL; |
342 | } | 352 | } |
343 | erki = RB_INSERT(revoked_key_id_tree, &rc->revoked_key_ids, rki); | 353 | erki = RB_INSERT(revoked_key_id_tree, &rc->revoked_key_ids, rki); |
344 | if (erki != NULL) { | 354 | if (erki != NULL) { |
@@ -350,33 +360,32 @@ ssh_krl_revoke_cert_by_key_id(struct ssh_krl *krl, const Key *ca_key, | |||
350 | 360 | ||
351 | /* Convert "key" to a public key blob without any certificate information */ | 361 | /* Convert "key" to a public key blob without any certificate information */ |
352 | static int | 362 | static int |
353 | plain_key_blob(const Key *key, u_char **blob, u_int *blen) | 363 | plain_key_blob(const struct sshkey *key, u_char **blob, size_t *blen) |
354 | { | 364 | { |
355 | Key *kcopy; | 365 | struct sshkey *kcopy; |
356 | int r; | 366 | int r; |
357 | 367 | ||
358 | if ((kcopy = key_from_private(key)) == NULL) | 368 | if ((r = sshkey_from_private(key, &kcopy)) != 0) |
359 | return -1; | 369 | return r; |
360 | if (key_is_cert(kcopy)) { | 370 | if (sshkey_is_cert(kcopy)) { |
361 | if (key_drop_cert(kcopy) != 0) { | 371 | if ((r = sshkey_drop_cert(kcopy)) != 0) { |
362 | error("%s: key_drop_cert", __func__); | 372 | sshkey_free(kcopy); |
363 | key_free(kcopy); | 373 | return r; |
364 | return -1; | ||
365 | } | 374 | } |
366 | } | 375 | } |
367 | r = key_to_blob(kcopy, blob, blen); | 376 | r = sshkey_to_blob(kcopy, blob, blen); |
368 | free(kcopy); | 377 | sshkey_free(kcopy); |
369 | return r; | 378 | return r; |
370 | } | 379 | } |
371 | 380 | ||
372 | /* Revoke a key blob. Ownership of blob is transferred to the tree */ | 381 | /* Revoke a key blob. Ownership of blob is transferred to the tree */ |
373 | static int | 382 | static int |
374 | revoke_blob(struct revoked_blob_tree *rbt, u_char *blob, u_int len) | 383 | revoke_blob(struct revoked_blob_tree *rbt, u_char *blob, size_t len) |
375 | { | 384 | { |
376 | struct revoked_blob *rb, *erb; | 385 | struct revoked_blob *rb, *erb; |
377 | 386 | ||
378 | if ((rb = calloc(1, sizeof(*rb))) == NULL) | 387 | if ((rb = calloc(1, sizeof(*rb))) == NULL) |
379 | return -1; | 388 | return SSH_ERR_ALLOC_FAIL; |
380 | rb->blob = blob; | 389 | rb->blob = blob; |
381 | rb->len = len; | 390 | rb->len = len; |
382 | erb = RB_INSERT(revoked_blob_tree, rbt, rb); | 391 | erb = RB_INSERT(revoked_blob_tree, rbt, rb); |
@@ -388,36 +397,39 @@ revoke_blob(struct revoked_blob_tree *rbt, u_char *blob, u_int len) | |||
388 | } | 397 | } |
389 | 398 | ||
390 | int | 399 | int |
391 | ssh_krl_revoke_key_explicit(struct ssh_krl *krl, const Key *key) | 400 | ssh_krl_revoke_key_explicit(struct ssh_krl *krl, const struct sshkey *key) |
392 | { | 401 | { |
393 | u_char *blob; | 402 | u_char *blob; |
394 | u_int len; | 403 | size_t len; |
404 | int r; | ||
395 | 405 | ||
396 | debug3("%s: revoke type %s", __func__, key_type(key)); | 406 | debug3("%s: revoke type %s", __func__, sshkey_type(key)); |
397 | if (plain_key_blob(key, &blob, &len) < 0) | 407 | if ((r = plain_key_blob(key, &blob, &len)) != 0) |
398 | return -1; | 408 | return r; |
399 | return revoke_blob(&krl->revoked_keys, blob, len); | 409 | return revoke_blob(&krl->revoked_keys, blob, len); |
400 | } | 410 | } |
401 | 411 | ||
402 | int | 412 | int |
403 | ssh_krl_revoke_key_sha1(struct ssh_krl *krl, const Key *key) | 413 | ssh_krl_revoke_key_sha1(struct ssh_krl *krl, const struct sshkey *key) |
404 | { | 414 | { |
405 | u_char *blob; | 415 | u_char *blob; |
406 | u_int len; | 416 | size_t len; |
417 | int r; | ||
407 | 418 | ||
408 | debug3("%s: revoke type %s by sha1", __func__, key_type(key)); | 419 | debug3("%s: revoke type %s by sha1", __func__, sshkey_type(key)); |
409 | if ((blob = key_fingerprint_raw(key, SSH_FP_SHA1, &len)) == NULL) | 420 | if ((r = sshkey_fingerprint_raw(key, SSH_DIGEST_SHA1, |
410 | return -1; | 421 | &blob, &len)) != 0) |
422 | return r; | ||
411 | return revoke_blob(&krl->revoked_sha1s, blob, len); | 423 | return revoke_blob(&krl->revoked_sha1s, blob, len); |
412 | } | 424 | } |
413 | 425 | ||
414 | int | 426 | int |
415 | ssh_krl_revoke_key(struct ssh_krl *krl, const Key *key) | 427 | ssh_krl_revoke_key(struct ssh_krl *krl, const struct sshkey *key) |
416 | { | 428 | { |
417 | if (!key_is_cert(key)) | 429 | if (!sshkey_is_cert(key)) |
418 | return ssh_krl_revoke_key_sha1(krl, key); | 430 | return ssh_krl_revoke_key_sha1(krl, key); |
419 | 431 | ||
420 | if (key_cert_is_legacy(key) || key->cert->serial == 0) { | 432 | if (sshkey_cert_is_legacy(key) || key->cert->serial == 0) { |
421 | return ssh_krl_revoke_cert_by_key_id(krl, | 433 | return ssh_krl_revoke_cert_by_key_id(krl, |
422 | key->cert->signature_key, | 434 | key->cert->signature_key, |
423 | key->cert->key_id); | 435 | key->cert->key_id); |
@@ -429,8 +441,8 @@ ssh_krl_revoke_key(struct ssh_krl *krl, const Key *key) | |||
429 | } | 441 | } |
430 | 442 | ||
431 | /* | 443 | /* |
432 | * Select a copact next section type to emit in a KRL based on the | 444 | * Select the most compact section type to emit next in a KRL based on |
433 | * current section type, the run length of contiguous revoked serial | 445 | * the current section type, the run length of contiguous revoked serial |
434 | * numbers and the gaps from the last and to the next revoked serial. | 446 | * numbers and the gaps from the last and to the next revoked serial. |
435 | * Applies a mostly-accurate bit cost model to select the section type | 447 | * Applies a mostly-accurate bit cost model to select the section type |
436 | * that will minimise the size of the resultant KRL. | 448 | * that will minimise the size of the resultant KRL. |
@@ -500,50 +512,69 @@ choose_next_state(int current_state, u_int64_t contig, int final, | |||
500 | *force_new_section = 1; | 512 | *force_new_section = 1; |
501 | cost = cost_bitmap_restart; | 513 | cost = cost_bitmap_restart; |
502 | } | 514 | } |
503 | debug3("%s: contig %llu last_gap %llu next_gap %llu final %d, costs:" | 515 | KRL_DBG(("%s: contig %llu last_gap %llu next_gap %llu final %d, costs:" |
504 | "list %llu range %llu bitmap %llu new bitmap %llu, " | 516 | "list %llu range %llu bitmap %llu new bitmap %llu, " |
505 | "selected 0x%02x%s", __func__, (long long unsigned)contig, | 517 | "selected 0x%02x%s", __func__, (long long unsigned)contig, |
506 | (long long unsigned)last_gap, (long long unsigned)next_gap, final, | 518 | (long long unsigned)last_gap, (long long unsigned)next_gap, final, |
507 | (long long unsigned)cost_list, (long long unsigned)cost_range, | 519 | (long long unsigned)cost_list, (long long unsigned)cost_range, |
508 | (long long unsigned)cost_bitmap, | 520 | (long long unsigned)cost_bitmap, |
509 | (long long unsigned)cost_bitmap_restart, new_state, | 521 | (long long unsigned)cost_bitmap_restart, new_state, |
510 | *force_new_section ? " restart" : ""); | 522 | *force_new_section ? " restart" : "")); |
511 | return new_state; | 523 | return new_state; |
512 | } | 524 | } |
513 | 525 | ||
526 | static int | ||
527 | put_bitmap(struct sshbuf *buf, struct bitmap *bitmap) | ||
528 | { | ||
529 | size_t len; | ||
530 | u_char *blob; | ||
531 | int r; | ||
532 | |||
533 | len = bitmap_nbytes(bitmap); | ||
534 | if ((blob = malloc(len)) == NULL) | ||
535 | return SSH_ERR_ALLOC_FAIL; | ||
536 | if (bitmap_to_string(bitmap, blob, len) != 0) { | ||
537 | free(blob); | ||
538 | return SSH_ERR_INTERNAL_ERROR; | ||
539 | } | ||
540 | r = sshbuf_put_bignum2_bytes(buf, blob, len); | ||
541 | free(blob); | ||
542 | return r; | ||
543 | } | ||
544 | |||
514 | /* Generate a KRL_SECTION_CERTIFICATES KRL section */ | 545 | /* Generate a KRL_SECTION_CERTIFICATES KRL section */ |
515 | static int | 546 | static int |
516 | revoked_certs_generate(struct revoked_certs *rc, Buffer *buf) | 547 | revoked_certs_generate(struct revoked_certs *rc, struct sshbuf *buf) |
517 | { | 548 | { |
518 | int final, force_new_sect, r = -1; | 549 | int final, force_new_sect, r = SSH_ERR_INTERNAL_ERROR; |
519 | u_int64_t i, contig, gap, last = 0, bitmap_start = 0; | 550 | u_int64_t i, contig, gap, last = 0, bitmap_start = 0; |
520 | struct revoked_serial *rs, *nrs; | 551 | struct revoked_serial *rs, *nrs; |
521 | struct revoked_key_id *rki; | 552 | struct revoked_key_id *rki; |
522 | int next_state, state = 0; | 553 | int next_state, state = 0; |
523 | Buffer sect; | 554 | struct sshbuf *sect; |
524 | u_char *kblob = NULL; | 555 | struct bitmap *bitmap = NULL; |
525 | u_int klen; | ||
526 | BIGNUM *bitmap = NULL; | ||
527 | |||
528 | /* Prepare CA scope key blob if we have one supplied */ | ||
529 | if (key_to_blob(rc->ca_key, &kblob, &klen) == 0) | ||
530 | return -1; | ||
531 | 556 | ||
532 | buffer_init(§); | 557 | if ((sect = sshbuf_new()) == NULL) |
558 | return SSH_ERR_ALLOC_FAIL; | ||
533 | 559 | ||
534 | /* Store the header */ | 560 | /* Store the header: optional CA scope key, reserved */ |
535 | buffer_put_string(buf, kblob, klen); | 561 | if (rc->ca_key == NULL) { |
536 | buffer_put_string(buf, NULL, 0); /* Reserved */ | 562 | if ((r = sshbuf_put_string(buf, NULL, 0)) != 0) |
537 | 563 | goto out; | |
538 | free(kblob); | 564 | } else { |
565 | if ((r = sshkey_puts(rc->ca_key, buf)) != 0) | ||
566 | goto out; | ||
567 | } | ||
568 | if ((r = sshbuf_put_string(buf, NULL, 0)) != 0) | ||
569 | goto out; | ||
539 | 570 | ||
540 | /* Store the revoked serials. */ | 571 | /* Store the revoked serials. */ |
541 | for (rs = RB_MIN(revoked_serial_tree, &rc->revoked_serials); | 572 | for (rs = RB_MIN(revoked_serial_tree, &rc->revoked_serials); |
542 | rs != NULL; | 573 | rs != NULL; |
543 | rs = RB_NEXT(revoked_serial_tree, &rc->revoked_serials, rs)) { | 574 | rs = RB_NEXT(revoked_serial_tree, &rc->revoked_serials, rs)) { |
544 | debug3("%s: serial %llu:%llu state 0x%02x", __func__, | 575 | KRL_DBG(("%s: serial %llu:%llu state 0x%02x", __func__, |
545 | (long long unsigned)rs->lo, (long long unsigned)rs->hi, | 576 | (long long unsigned)rs->lo, (long long unsigned)rs->hi, |
546 | state); | 577 | state)); |
547 | 578 | ||
548 | /* Check contiguous length and gap to next section (if any) */ | 579 | /* Check contiguous length and gap to next section (if any) */ |
549 | nrs = RB_NEXT(revoked_serial_tree, &rc->revoked_serials, rs); | 580 | nrs = RB_NEXT(revoked_serial_tree, &rc->revoked_serials, rs); |
@@ -561,37 +592,43 @@ revoked_certs_generate(struct revoked_certs *rc, Buffer *buf) | |||
561 | */ | 592 | */ |
562 | if (state != 0 && (force_new_sect || next_state != state || | 593 | if (state != 0 && (force_new_sect || next_state != state || |
563 | state == KRL_SECTION_CERT_SERIAL_RANGE)) { | 594 | state == KRL_SECTION_CERT_SERIAL_RANGE)) { |
564 | debug3("%s: finish state 0x%02x", __func__, state); | 595 | KRL_DBG(("%s: finish state 0x%02x", __func__, state)); |
565 | switch (state) { | 596 | switch (state) { |
566 | case KRL_SECTION_CERT_SERIAL_LIST: | 597 | case KRL_SECTION_CERT_SERIAL_LIST: |
567 | case KRL_SECTION_CERT_SERIAL_RANGE: | 598 | case KRL_SECTION_CERT_SERIAL_RANGE: |
568 | break; | 599 | break; |
569 | case KRL_SECTION_CERT_SERIAL_BITMAP: | 600 | case KRL_SECTION_CERT_SERIAL_BITMAP: |
570 | buffer_put_bignum2(§, bitmap); | 601 | if ((r = put_bitmap(sect, bitmap)) != 0) |
571 | BN_free(bitmap); | 602 | goto out; |
603 | bitmap_free(bitmap); | ||
572 | bitmap = NULL; | 604 | bitmap = NULL; |
573 | break; | 605 | break; |
574 | } | 606 | } |
575 | buffer_put_char(buf, state); | 607 | if ((r = sshbuf_put_u8(buf, state)) != 0 || |
576 | buffer_put_string(buf, | 608 | (r = sshbuf_put_stringb(buf, sect)) != 0) |
577 | buffer_ptr(§), buffer_len(§)); | 609 | goto out; |
578 | buffer_clear(§); | 610 | sshbuf_reset(sect); |
579 | } | 611 | } |
580 | 612 | ||
581 | /* If we are starting a new section then prepare it now */ | 613 | /* If we are starting a new section then prepare it now */ |
582 | if (next_state != state || force_new_sect) { | 614 | if (next_state != state || force_new_sect) { |
583 | debug3("%s: start state 0x%02x", __func__, next_state); | 615 | KRL_DBG(("%s: start state 0x%02x", __func__, |
616 | next_state)); | ||
584 | state = next_state; | 617 | state = next_state; |
585 | buffer_clear(§); | 618 | sshbuf_reset(sect); |
586 | switch (state) { | 619 | switch (state) { |
587 | case KRL_SECTION_CERT_SERIAL_LIST: | 620 | case KRL_SECTION_CERT_SERIAL_LIST: |
588 | case KRL_SECTION_CERT_SERIAL_RANGE: | 621 | case KRL_SECTION_CERT_SERIAL_RANGE: |
589 | break; | 622 | break; |
590 | case KRL_SECTION_CERT_SERIAL_BITMAP: | 623 | case KRL_SECTION_CERT_SERIAL_BITMAP: |
591 | if ((bitmap = BN_new()) == NULL) | 624 | if ((bitmap = bitmap_new()) == NULL) { |
625 | r = SSH_ERR_ALLOC_FAIL; | ||
592 | goto out; | 626 | goto out; |
627 | } | ||
593 | bitmap_start = rs->lo; | 628 | bitmap_start = rs->lo; |
594 | buffer_put_int64(§, bitmap_start); | 629 | if ((r = sshbuf_put_u64(sect, |
630 | bitmap_start)) != 0) | ||
631 | goto out; | ||
595 | break; | 632 | break; |
596 | } | 633 | } |
597 | } | 634 | } |
@@ -599,12 +636,15 @@ revoked_certs_generate(struct revoked_certs *rc, Buffer *buf) | |||
599 | /* Perform section-specific processing */ | 636 | /* Perform section-specific processing */ |
600 | switch (state) { | 637 | switch (state) { |
601 | case KRL_SECTION_CERT_SERIAL_LIST: | 638 | case KRL_SECTION_CERT_SERIAL_LIST: |
602 | for (i = 0; i < contig; i++) | 639 | for (i = 0; i < contig; i++) { |
603 | buffer_put_int64(§, rs->lo + i); | 640 | if ((r = sshbuf_put_u64(sect, rs->lo + i)) != 0) |
641 | goto out; | ||
642 | } | ||
604 | break; | 643 | break; |
605 | case KRL_SECTION_CERT_SERIAL_RANGE: | 644 | case KRL_SECTION_CERT_SERIAL_RANGE: |
606 | buffer_put_int64(§, rs->lo); | 645 | if ((r = sshbuf_put_u64(sect, rs->lo)) != 0 || |
607 | buffer_put_int64(§, rs->hi); | 646 | (r = sshbuf_put_u64(sect, rs->hi)) != 0) |
647 | goto out; | ||
608 | break; | 648 | break; |
609 | case KRL_SECTION_CERT_SERIAL_BITMAP: | 649 | case KRL_SECTION_CERT_SERIAL_BITMAP: |
610 | if (rs->lo - bitmap_start > INT_MAX) { | 650 | if (rs->lo - bitmap_start > INT_MAX) { |
@@ -612,9 +652,11 @@ revoked_certs_generate(struct revoked_certs *rc, Buffer *buf) | |||
612 | goto out; | 652 | goto out; |
613 | } | 653 | } |
614 | for (i = 0; i < contig; i++) { | 654 | for (i = 0; i < contig; i++) { |
615 | if (BN_set_bit(bitmap, | 655 | if (bitmap_set_bit(bitmap, |
616 | rs->lo + i - bitmap_start) != 1) | 656 | rs->lo + i - bitmap_start) != 0) { |
657 | r = SSH_ERR_ALLOC_FAIL; | ||
617 | goto out; | 658 | goto out; |
659 | } | ||
618 | } | 660 | } |
619 | break; | 661 | break; |
620 | } | 662 | } |
@@ -622,119 +664,125 @@ revoked_certs_generate(struct revoked_certs *rc, Buffer *buf) | |||
622 | } | 664 | } |
623 | /* Flush the remaining section, if any */ | 665 | /* Flush the remaining section, if any */ |
624 | if (state != 0) { | 666 | if (state != 0) { |
625 | debug3("%s: serial final flush for state 0x%02x", | 667 | KRL_DBG(("%s: serial final flush for state 0x%02x", |
626 | __func__, state); | 668 | __func__, state)); |
627 | switch (state) { | 669 | switch (state) { |
628 | case KRL_SECTION_CERT_SERIAL_LIST: | 670 | case KRL_SECTION_CERT_SERIAL_LIST: |
629 | case KRL_SECTION_CERT_SERIAL_RANGE: | 671 | case KRL_SECTION_CERT_SERIAL_RANGE: |
630 | break; | 672 | break; |
631 | case KRL_SECTION_CERT_SERIAL_BITMAP: | 673 | case KRL_SECTION_CERT_SERIAL_BITMAP: |
632 | buffer_put_bignum2(§, bitmap); | 674 | if ((r = put_bitmap(sect, bitmap)) != 0) |
633 | BN_free(bitmap); | 675 | goto out; |
676 | bitmap_free(bitmap); | ||
634 | bitmap = NULL; | 677 | bitmap = NULL; |
635 | break; | 678 | break; |
636 | } | 679 | } |
637 | buffer_put_char(buf, state); | 680 | if ((r = sshbuf_put_u8(buf, state)) != 0 || |
638 | buffer_put_string(buf, | 681 | (r = sshbuf_put_stringb(buf, sect)) != 0) |
639 | buffer_ptr(§), buffer_len(§)); | 682 | goto out; |
640 | } | 683 | } |
641 | debug3("%s: serial done ", __func__); | 684 | KRL_DBG(("%s: serial done ", __func__)); |
642 | 685 | ||
643 | /* Now output a section for any revocations by key ID */ | 686 | /* Now output a section for any revocations by key ID */ |
644 | buffer_clear(§); | 687 | sshbuf_reset(sect); |
645 | RB_FOREACH(rki, revoked_key_id_tree, &rc->revoked_key_ids) { | 688 | RB_FOREACH(rki, revoked_key_id_tree, &rc->revoked_key_ids) { |
646 | debug3("%s: key ID %s", __func__, rki->key_id); | 689 | KRL_DBG(("%s: key ID %s", __func__, rki->key_id)); |
647 | buffer_put_cstring(§, rki->key_id); | 690 | if ((r = sshbuf_put_cstring(sect, rki->key_id)) != 0) |
691 | goto out; | ||
648 | } | 692 | } |
649 | if (buffer_len(§) != 0) { | 693 | if (sshbuf_len(sect) != 0) { |
650 | buffer_put_char(buf, KRL_SECTION_CERT_KEY_ID); | 694 | if ((r = sshbuf_put_u8(buf, KRL_SECTION_CERT_KEY_ID)) != 0 || |
651 | buffer_put_string(buf, buffer_ptr(§), | 695 | (r = sshbuf_put_stringb(buf, sect)) != 0) |
652 | buffer_len(§)); | 696 | goto out; |
653 | } | 697 | } |
654 | r = 0; | 698 | r = 0; |
655 | out: | 699 | out: |
656 | if (bitmap != NULL) | 700 | bitmap_free(bitmap); |
657 | BN_free(bitmap); | 701 | sshbuf_free(sect); |
658 | buffer_free(§); | ||
659 | return r; | 702 | return r; |
660 | } | 703 | } |
661 | 704 | ||
662 | int | 705 | int |
663 | ssh_krl_to_blob(struct ssh_krl *krl, Buffer *buf, const Key **sign_keys, | 706 | ssh_krl_to_blob(struct ssh_krl *krl, struct sshbuf *buf, |
664 | u_int nsign_keys) | 707 | const struct sshkey **sign_keys, u_int nsign_keys) |
665 | { | 708 | { |
666 | int r = -1; | 709 | int r = SSH_ERR_INTERNAL_ERROR; |
667 | struct revoked_certs *rc; | 710 | struct revoked_certs *rc; |
668 | struct revoked_blob *rb; | 711 | struct revoked_blob *rb; |
669 | Buffer sect; | 712 | struct sshbuf *sect; |
670 | u_char *kblob = NULL, *sblob = NULL; | 713 | u_char *sblob = NULL; |
671 | u_int klen, slen, i; | 714 | size_t slen, i; |
672 | 715 | ||
673 | if (krl->generated_date == 0) | 716 | if (krl->generated_date == 0) |
674 | krl->generated_date = time(NULL); | 717 | krl->generated_date = time(NULL); |
675 | 718 | ||
676 | buffer_init(§); | 719 | if ((sect = sshbuf_new()) == NULL) |
720 | return SSH_ERR_ALLOC_FAIL; | ||
677 | 721 | ||
678 | /* Store the header */ | 722 | /* Store the header */ |
679 | buffer_append(buf, KRL_MAGIC, sizeof(KRL_MAGIC) - 1); | 723 | if ((r = sshbuf_put(buf, KRL_MAGIC, sizeof(KRL_MAGIC) - 1)) != 0 || |
680 | buffer_put_int(buf, KRL_FORMAT_VERSION); | 724 | (r = sshbuf_put_u32(buf, KRL_FORMAT_VERSION)) != 0 || |
681 | buffer_put_int64(buf, krl->krl_version); | 725 | (r = sshbuf_put_u64(buf, krl->krl_version)) != 0 || |
682 | buffer_put_int64(buf, krl->generated_date); | 726 | (r = sshbuf_put_u64(buf, krl->generated_date) != 0) || |
683 | buffer_put_int64(buf, krl->flags); | 727 | (r = sshbuf_put_u64(buf, krl->flags)) != 0 || |
684 | buffer_put_string(buf, NULL, 0); | 728 | (r = sshbuf_put_string(buf, NULL, 0)) != 0 || |
685 | buffer_put_cstring(buf, krl->comment ? krl->comment : ""); | 729 | (r = sshbuf_put_cstring(buf, krl->comment)) != 0) |
730 | goto out; | ||
686 | 731 | ||
687 | /* Store sections for revoked certificates */ | 732 | /* Store sections for revoked certificates */ |
688 | TAILQ_FOREACH(rc, &krl->revoked_certs, entry) { | 733 | TAILQ_FOREACH(rc, &krl->revoked_certs, entry) { |
689 | if (revoked_certs_generate(rc, §) != 0) | 734 | sshbuf_reset(sect); |
735 | if ((r = revoked_certs_generate(rc, sect)) != 0) | ||
736 | goto out; | ||
737 | if ((r = sshbuf_put_u8(buf, KRL_SECTION_CERTIFICATES)) != 0 || | ||
738 | (r = sshbuf_put_stringb(buf, sect)) != 0) | ||
690 | goto out; | 739 | goto out; |
691 | buffer_put_char(buf, KRL_SECTION_CERTIFICATES); | ||
692 | buffer_put_string(buf, buffer_ptr(§), | ||
693 | buffer_len(§)); | ||
694 | } | 740 | } |
695 | 741 | ||
696 | /* Finally, output sections for revocations by public key/hash */ | 742 | /* Finally, output sections for revocations by public key/hash */ |
697 | buffer_clear(§); | 743 | sshbuf_reset(sect); |
698 | RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_keys) { | 744 | RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_keys) { |
699 | debug3("%s: key len %u ", __func__, rb->len); | 745 | KRL_DBG(("%s: key len %zu ", __func__, rb->len)); |
700 | buffer_put_string(§, rb->blob, rb->len); | 746 | if ((r = sshbuf_put_string(sect, rb->blob, rb->len)) != 0) |
747 | goto out; | ||
701 | } | 748 | } |
702 | if (buffer_len(§) != 0) { | 749 | if (sshbuf_len(sect) != 0) { |
703 | buffer_put_char(buf, KRL_SECTION_EXPLICIT_KEY); | 750 | if ((r = sshbuf_put_u8(buf, KRL_SECTION_EXPLICIT_KEY)) != 0 || |
704 | buffer_put_string(buf, buffer_ptr(§), | 751 | (r = sshbuf_put_stringb(buf, sect)) != 0) |
705 | buffer_len(§)); | 752 | goto out; |
706 | } | 753 | } |
707 | buffer_clear(§); | 754 | sshbuf_reset(sect); |
708 | RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_sha1s) { | 755 | RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_sha1s) { |
709 | debug3("%s: hash len %u ", __func__, rb->len); | 756 | KRL_DBG(("%s: hash len %zu ", __func__, rb->len)); |
710 | buffer_put_string(§, rb->blob, rb->len); | 757 | if ((r = sshbuf_put_string(sect, rb->blob, rb->len)) != 0) |
758 | goto out; | ||
711 | } | 759 | } |
712 | if (buffer_len(§) != 0) { | 760 | if (sshbuf_len(sect) != 0) { |
713 | buffer_put_char(buf, KRL_SECTION_FINGERPRINT_SHA1); | 761 | if ((r = sshbuf_put_u8(buf, |
714 | buffer_put_string(buf, buffer_ptr(§), | 762 | KRL_SECTION_FINGERPRINT_SHA1)) != 0 || |
715 | buffer_len(§)); | 763 | (r = sshbuf_put_stringb(buf, sect)) != 0) |
764 | goto out; | ||
716 | } | 765 | } |
717 | 766 | ||
718 | for (i = 0; i < nsign_keys; i++) { | 767 | for (i = 0; i < nsign_keys; i++) { |
719 | if (key_to_blob(sign_keys[i], &kblob, &klen) == 0) | 768 | KRL_DBG(("%s: signature key %s", __func__, |
769 | sshkey_ssh_name(sign_keys[i]))); | ||
770 | if ((r = sshbuf_put_u8(buf, KRL_SECTION_SIGNATURE)) != 0 || | ||
771 | (r = sshkey_puts(sign_keys[i], buf)) != 0) | ||
720 | goto out; | 772 | goto out; |
721 | 773 | ||
722 | debug3("%s: signature key len %u", __func__, klen); | 774 | if ((r = sshkey_sign(sign_keys[i], &sblob, &slen, |
723 | buffer_put_char(buf, KRL_SECTION_SIGNATURE); | 775 | sshbuf_ptr(buf), sshbuf_len(buf), 0)) == -1) |
724 | buffer_put_string(buf, kblob, klen); | 776 | goto out; |
725 | 777 | KRL_DBG(("%s: signature sig len %zu", __func__, slen)); | |
726 | if (key_sign(sign_keys[i], &sblob, &slen, | 778 | if ((r = sshbuf_put_string(buf, sblob, slen)) != 0) |
727 | buffer_ptr(buf), buffer_len(buf)) == -1) | ||
728 | goto out; | 779 | goto out; |
729 | debug3("%s: signature sig len %u", __func__, slen); | ||
730 | buffer_put_string(buf, sblob, slen); | ||
731 | } | 780 | } |
732 | 781 | ||
733 | r = 0; | 782 | r = 0; |
734 | out: | 783 | out: |
735 | free(kblob); | ||
736 | free(sblob); | 784 | free(sblob); |
737 | buffer_free(§); | 785 | sshbuf_free(sect); |
738 | return r; | 786 | return r; |
739 | } | 787 | } |
740 | 788 | ||
@@ -746,194 +794,178 @@ format_timestamp(u_int64_t timestamp, char *ts, size_t nts) | |||
746 | 794 | ||
747 | t = timestamp; | 795 | t = timestamp; |
748 | tm = localtime(&t); | 796 | tm = localtime(&t); |
749 | *ts = '\0'; | 797 | if (tm == NULL) |
750 | strftime(ts, nts, "%Y%m%dT%H%M%S", tm); | 798 | strlcpy(ts, "<INVALID>", nts); |
799 | else { | ||
800 | *ts = '\0'; | ||
801 | strftime(ts, nts, "%Y%m%dT%H%M%S", tm); | ||
802 | } | ||
751 | } | 803 | } |
752 | 804 | ||
753 | static int | 805 | static int |
754 | parse_revoked_certs(Buffer *buf, struct ssh_krl *krl) | 806 | parse_revoked_certs(struct sshbuf *buf, struct ssh_krl *krl) |
755 | { | 807 | { |
756 | int ret = -1, nbits; | 808 | int r = SSH_ERR_INTERNAL_ERROR; |
757 | u_char type; | 809 | u_char type; |
758 | const u_char *blob; | 810 | const u_char *blob; |
759 | u_int blen; | 811 | size_t blen, nbits; |
760 | Buffer subsect; | 812 | struct sshbuf *subsect = NULL; |
761 | u_int64_t serial, serial_lo, serial_hi; | 813 | u_int64_t serial, serial_lo, serial_hi; |
762 | BIGNUM *bitmap = NULL; | 814 | struct bitmap *bitmap = NULL; |
763 | char *key_id = NULL; | 815 | char *key_id = NULL; |
764 | Key *ca_key = NULL; | 816 | struct sshkey *ca_key = NULL; |
765 | 817 | ||
766 | buffer_init(&subsect); | 818 | if ((subsect = sshbuf_new()) == NULL) |
819 | return SSH_ERR_ALLOC_FAIL; | ||
767 | 820 | ||
768 | if ((blob = buffer_get_string_ptr_ret(buf, &blen)) == NULL || | 821 | /* Header: key, reserved */ |
769 | buffer_get_string_ptr_ret(buf, NULL) == NULL) { /* reserved */ | 822 | if ((r = sshbuf_get_string_direct(buf, &blob, &blen)) != 0 || |
770 | error("%s: buffer error", __func__); | 823 | (r = sshbuf_skip_string(buf)) != 0) |
771 | goto out; | 824 | goto out; |
772 | } | 825 | if (blen != 0 && (r = sshkey_from_blob(blob, blen, &ca_key)) != 0) |
773 | if ((ca_key = key_from_blob(blob, blen)) == NULL) | ||
774 | goto out; | 826 | goto out; |
775 | 827 | ||
776 | while (buffer_len(buf) > 0) { | 828 | while (sshbuf_len(buf) > 0) { |
777 | if (buffer_get_char_ret(&type, buf) != 0 || | 829 | if (subsect != NULL) { |
778 | (blob = buffer_get_string_ptr_ret(buf, &blen)) == NULL) { | 830 | sshbuf_free(subsect); |
779 | error("%s: buffer error", __func__); | 831 | subsect = NULL; |
780 | goto out; | ||
781 | } | 832 | } |
782 | buffer_clear(&subsect); | 833 | if ((r = sshbuf_get_u8(buf, &type)) != 0 || |
783 | buffer_append(&subsect, blob, blen); | 834 | (r = sshbuf_froms(buf, &subsect)) != 0) |
784 | debug3("%s: subsection type 0x%02x", __func__, type); | 835 | goto out; |
785 | /* buffer_dump(&subsect); */ | 836 | KRL_DBG(("%s: subsection type 0x%02x", __func__, type)); |
837 | /* sshbuf_dump(subsect, stderr); */ | ||
786 | 838 | ||
787 | switch (type) { | 839 | switch (type) { |
788 | case KRL_SECTION_CERT_SERIAL_LIST: | 840 | case KRL_SECTION_CERT_SERIAL_LIST: |
789 | while (buffer_len(&subsect) > 0) { | 841 | while (sshbuf_len(subsect) > 0) { |
790 | if (buffer_get_int64_ret(&serial, | 842 | if ((r = sshbuf_get_u64(subsect, &serial)) != 0) |
791 | &subsect) != 0) { | ||
792 | error("%s: buffer error", __func__); | ||
793 | goto out; | 843 | goto out; |
794 | } | 844 | if ((r = ssh_krl_revoke_cert_by_serial(krl, |
795 | if (ssh_krl_revoke_cert_by_serial(krl, ca_key, | 845 | ca_key, serial)) != 0) |
796 | serial) != 0) { | ||
797 | error("%s: update failed", __func__); | ||
798 | goto out; | 846 | goto out; |
799 | } | ||
800 | } | 847 | } |
801 | break; | 848 | break; |
802 | case KRL_SECTION_CERT_SERIAL_RANGE: | 849 | case KRL_SECTION_CERT_SERIAL_RANGE: |
803 | if (buffer_get_int64_ret(&serial_lo, &subsect) != 0 || | 850 | if ((r = sshbuf_get_u64(subsect, &serial_lo)) != 0 || |
804 | buffer_get_int64_ret(&serial_hi, &subsect) != 0) { | 851 | (r = sshbuf_get_u64(subsect, &serial_hi)) != 0) |
805 | error("%s: buffer error", __func__); | ||
806 | goto out; | 852 | goto out; |
807 | } | 853 | if ((r = ssh_krl_revoke_cert_by_serial_range(krl, |
808 | if (ssh_krl_revoke_cert_by_serial_range(krl, ca_key, | 854 | ca_key, serial_lo, serial_hi)) != 0) |
809 | serial_lo, serial_hi) != 0) { | ||
810 | error("%s: update failed", __func__); | ||
811 | goto out; | 855 | goto out; |
812 | } | ||
813 | break; | 856 | break; |
814 | case KRL_SECTION_CERT_SERIAL_BITMAP: | 857 | case KRL_SECTION_CERT_SERIAL_BITMAP: |
815 | if ((bitmap = BN_new()) == NULL) { | 858 | if ((bitmap = bitmap_new()) == NULL) { |
816 | error("%s: BN_new", __func__); | 859 | r = SSH_ERR_ALLOC_FAIL; |
817 | goto out; | 860 | goto out; |
818 | } | 861 | } |
819 | if (buffer_get_int64_ret(&serial_lo, &subsect) != 0 || | 862 | if ((r = sshbuf_get_u64(subsect, &serial_lo)) != 0 || |
820 | buffer_get_bignum2_ret(&subsect, bitmap) != 0) { | 863 | (r = sshbuf_get_bignum2_bytes_direct(subsect, |
821 | error("%s: buffer error", __func__); | 864 | &blob, &blen)) != 0) |
822 | goto out; | 865 | goto out; |
823 | } | 866 | if (bitmap_from_string(bitmap, blob, blen) != 0) { |
824 | if ((nbits = BN_num_bits(bitmap)) < 0) { | 867 | r = SSH_ERR_INVALID_FORMAT; |
825 | error("%s: bitmap bits < 0", __func__); | ||
826 | goto out; | 868 | goto out; |
827 | } | 869 | } |
828 | for (serial = 0; serial < (u_int)nbits; serial++) { | 870 | nbits = bitmap_nbits(bitmap); |
871 | for (serial = 0; serial < (u_int64_t)nbits; serial++) { | ||
829 | if (serial > 0 && serial_lo + serial == 0) { | 872 | if (serial > 0 && serial_lo + serial == 0) { |
830 | error("%s: bitmap wraps u64", __func__); | 873 | error("%s: bitmap wraps u64", __func__); |
874 | r = SSH_ERR_INVALID_FORMAT; | ||
831 | goto out; | 875 | goto out; |
832 | } | 876 | } |
833 | if (!BN_is_bit_set(bitmap, serial)) | 877 | if (!bitmap_test_bit(bitmap, serial)) |
834 | continue; | 878 | continue; |
835 | if (ssh_krl_revoke_cert_by_serial(krl, ca_key, | 879 | if ((r = ssh_krl_revoke_cert_by_serial(krl, |
836 | serial_lo + serial) != 0) { | 880 | ca_key, serial_lo + serial)) != 0) |
837 | error("%s: update failed", __func__); | ||
838 | goto out; | 881 | goto out; |
839 | } | ||
840 | } | 882 | } |
841 | BN_free(bitmap); | 883 | bitmap_free(bitmap); |
842 | bitmap = NULL; | 884 | bitmap = NULL; |
843 | break; | 885 | break; |
844 | case KRL_SECTION_CERT_KEY_ID: | 886 | case KRL_SECTION_CERT_KEY_ID: |
845 | while (buffer_len(&subsect) > 0) { | 887 | while (sshbuf_len(subsect) > 0) { |
846 | if ((key_id = buffer_get_cstring_ret(&subsect, | 888 | if ((r = sshbuf_get_cstring(subsect, |
847 | NULL)) == NULL) { | 889 | &key_id, NULL)) != 0) |
848 | error("%s: buffer error", __func__); | ||
849 | goto out; | 890 | goto out; |
850 | } | 891 | if ((r = ssh_krl_revoke_cert_by_key_id(krl, |
851 | if (ssh_krl_revoke_cert_by_key_id(krl, ca_key, | 892 | ca_key, key_id)) != 0) |
852 | key_id) != 0) { | ||
853 | error("%s: update failed", __func__); | ||
854 | goto out; | 893 | goto out; |
855 | } | ||
856 | free(key_id); | 894 | free(key_id); |
857 | key_id = NULL; | 895 | key_id = NULL; |
858 | } | 896 | } |
859 | break; | 897 | break; |
860 | default: | 898 | default: |
861 | error("Unsupported KRL certificate section %u", type); | 899 | error("Unsupported KRL certificate section %u", type); |
900 | r = SSH_ERR_INVALID_FORMAT; | ||
862 | goto out; | 901 | goto out; |
863 | } | 902 | } |
864 | if (buffer_len(&subsect) > 0) { | 903 | if (sshbuf_len(subsect) > 0) { |
865 | error("KRL certificate section contains unparsed data"); | 904 | error("KRL certificate section contains unparsed data"); |
905 | r = SSH_ERR_INVALID_FORMAT; | ||
866 | goto out; | 906 | goto out; |
867 | } | 907 | } |
868 | } | 908 | } |
869 | 909 | ||
870 | ret = 0; | 910 | r = 0; |
871 | out: | 911 | out: |
872 | if (ca_key != NULL) | ||
873 | key_free(ca_key); | ||
874 | if (bitmap != NULL) | 912 | if (bitmap != NULL) |
875 | BN_free(bitmap); | 913 | bitmap_free(bitmap); |
876 | free(key_id); | 914 | free(key_id); |
877 | buffer_free(&subsect); | 915 | sshkey_free(ca_key); |
878 | return ret; | 916 | sshbuf_free(subsect); |
917 | return r; | ||
879 | } | 918 | } |
880 | 919 | ||
881 | 920 | ||
882 | /* Attempt to parse a KRL, checking its signature (if any) with sign_ca_keys. */ | 921 | /* Attempt to parse a KRL, checking its signature (if any) with sign_ca_keys. */ |
883 | int | 922 | int |
884 | ssh_krl_from_blob(Buffer *buf, struct ssh_krl **krlp, | 923 | ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp, |
885 | const Key **sign_ca_keys, u_int nsign_ca_keys) | 924 | const struct sshkey **sign_ca_keys, size_t nsign_ca_keys) |
886 | { | 925 | { |
887 | Buffer copy, sect; | 926 | struct sshbuf *copy = NULL, *sect = NULL; |
888 | struct ssh_krl *krl; | 927 | struct ssh_krl *krl = NULL; |
889 | char timestamp[64]; | 928 | char timestamp[64]; |
890 | int ret = -1, r, sig_seen; | 929 | int r = SSH_ERR_INTERNAL_ERROR, sig_seen; |
891 | Key *key = NULL, **ca_used = NULL; | 930 | struct sshkey *key = NULL, **ca_used = NULL, **tmp_ca_used; |
892 | u_char type, *rdata = NULL; | 931 | u_char type, *rdata = NULL; |
893 | const u_char *blob; | 932 | const u_char *blob; |
894 | u_int i, j, sig_off, sects_off, rlen, blen, format_version, nca_used; | 933 | size_t i, j, sig_off, sects_off, rlen, blen, nca_used; |
934 | u_int format_version; | ||
895 | 935 | ||
896 | nca_used = 0; | 936 | nca_used = 0; |
897 | *krlp = NULL; | 937 | *krlp = NULL; |
898 | if (buffer_len(buf) < sizeof(KRL_MAGIC) - 1 || | 938 | if (sshbuf_len(buf) < sizeof(KRL_MAGIC) - 1 || |
899 | memcmp(buffer_ptr(buf), KRL_MAGIC, sizeof(KRL_MAGIC) - 1) != 0) { | 939 | memcmp(sshbuf_ptr(buf), KRL_MAGIC, sizeof(KRL_MAGIC) - 1) != 0) { |
900 | debug3("%s: not a KRL", __func__); | 940 | debug3("%s: not a KRL", __func__); |
901 | /* | 941 | return SSH_ERR_KRL_BAD_MAGIC; |
902 | * Return success but a NULL *krlp here to signal that the | ||
903 | * file might be a simple list of keys. | ||
904 | */ | ||
905 | return 0; | ||
906 | } | 942 | } |
907 | 943 | ||
908 | /* Take a copy of the KRL buffer so we can verify its signature later */ | 944 | /* Take a copy of the KRL buffer so we can verify its signature later */ |
909 | buffer_init(©); | 945 | if ((copy = sshbuf_fromb(buf)) == NULL) { |
910 | buffer_append(©, buffer_ptr(buf), buffer_len(buf)); | 946 | r = SSH_ERR_ALLOC_FAIL; |
911 | 947 | goto out; | |
912 | buffer_init(§); | 948 | } |
913 | buffer_consume(©, sizeof(KRL_MAGIC) - 1); | 949 | if ((r = sshbuf_consume(copy, sizeof(KRL_MAGIC) - 1)) != 0) |
950 | goto out; | ||
914 | 951 | ||
915 | if ((krl = ssh_krl_init()) == NULL) { | 952 | if ((krl = ssh_krl_init()) == NULL) { |
916 | error("%s: alloc failed", __func__); | 953 | error("%s: alloc failed", __func__); |
917 | goto out; | 954 | goto out; |
918 | } | 955 | } |
919 | 956 | ||
920 | if (buffer_get_int_ret(&format_version, ©) != 0) { | 957 | if ((r = sshbuf_get_u32(copy, &format_version)) != 0) |
921 | error("%s: KRL truncated", __func__); | ||
922 | goto out; | 958 | goto out; |
923 | } | ||
924 | if (format_version != KRL_FORMAT_VERSION) { | 959 | if (format_version != KRL_FORMAT_VERSION) { |
925 | error("%s: KRL unsupported format version %u", | 960 | r = SSH_ERR_INVALID_FORMAT; |
926 | __func__, format_version); | ||
927 | goto out; | 961 | goto out; |
928 | } | 962 | } |
929 | if (buffer_get_int64_ret(&krl->krl_version, ©) != 0 || | 963 | if ((r = sshbuf_get_u64(copy, &krl->krl_version)) != 0 || |
930 | buffer_get_int64_ret(&krl->generated_date, ©) != 0 || | 964 | (r = sshbuf_get_u64(copy, &krl->generated_date)) != 0 || |
931 | buffer_get_int64_ret(&krl->flags, ©) != 0 || | 965 | (r = sshbuf_get_u64(copy, &krl->flags)) != 0 || |
932 | buffer_get_string_ptr_ret(©, NULL) == NULL || /* reserved */ | 966 | (r = sshbuf_skip_string(copy)) != 0 || |
933 | (krl->comment = buffer_get_cstring_ret(©, NULL)) == NULL) { | 967 | (r = sshbuf_get_cstring(copy, &krl->comment, NULL)) != 0) |
934 | error("%s: buffer error", __func__); | ||
935 | goto out; | 968 | goto out; |
936 | } | ||
937 | 969 | ||
938 | format_timestamp(krl->generated_date, timestamp, sizeof(timestamp)); | 970 | format_timestamp(krl->generated_date, timestamp, sizeof(timestamp)); |
939 | debug("KRL version %llu generated at %s%s%s", | 971 | debug("KRL version %llu generated at %s%s%s", |
@@ -945,18 +977,22 @@ ssh_krl_from_blob(Buffer *buf, struct ssh_krl **krlp, | |||
945 | * detailed parsing of data whose provenance is unverified. | 977 | * detailed parsing of data whose provenance is unverified. |
946 | */ | 978 | */ |
947 | sig_seen = 0; | 979 | sig_seen = 0; |
948 | sects_off = buffer_len(buf) - buffer_len(©); | 980 | if (sshbuf_len(buf) < sshbuf_len(copy)) { |
949 | while (buffer_len(©) > 0) { | 981 | /* Shouldn't happen */ |
950 | if (buffer_get_char_ret(&type, ©) != 0 || | 982 | r = SSH_ERR_INTERNAL_ERROR; |
951 | (blob = buffer_get_string_ptr_ret(©, &blen)) == NULL) { | 983 | goto out; |
952 | error("%s: buffer error", __func__); | 984 | } |
985 | sects_off = sshbuf_len(buf) - sshbuf_len(copy); | ||
986 | while (sshbuf_len(copy) > 0) { | ||
987 | if ((r = sshbuf_get_u8(copy, &type)) != 0 || | ||
988 | (r = sshbuf_get_string_direct(copy, &blob, &blen)) != 0) | ||
953 | goto out; | 989 | goto out; |
954 | } | 990 | KRL_DBG(("%s: first pass, section 0x%02x", __func__, type)); |
955 | debug3("%s: first pass, section 0x%02x", __func__, type); | ||
956 | if (type != KRL_SECTION_SIGNATURE) { | 991 | if (type != KRL_SECTION_SIGNATURE) { |
957 | if (sig_seen) { | 992 | if (sig_seen) { |
958 | error("KRL contains non-signature section " | 993 | error("KRL contains non-signature section " |
959 | "after signature"); | 994 | "after signature"); |
995 | r = SSH_ERR_INVALID_FORMAT; | ||
960 | goto out; | 996 | goto out; |
961 | } | 997 | } |
962 | /* Not interested for now. */ | 998 | /* Not interested for now. */ |
@@ -964,94 +1000,114 @@ ssh_krl_from_blob(Buffer *buf, struct ssh_krl **krlp, | |||
964 | } | 1000 | } |
965 | sig_seen = 1; | 1001 | sig_seen = 1; |
966 | /* First string component is the signing key */ | 1002 | /* First string component is the signing key */ |
967 | if ((key = key_from_blob(blob, blen)) == NULL) { | 1003 | if ((r = sshkey_from_blob(blob, blen, &key)) != 0) { |
968 | error("%s: invalid signature key", __func__); | 1004 | r = SSH_ERR_INVALID_FORMAT; |
1005 | goto out; | ||
1006 | } | ||
1007 | if (sshbuf_len(buf) < sshbuf_len(copy)) { | ||
1008 | /* Shouldn't happen */ | ||
1009 | r = SSH_ERR_INTERNAL_ERROR; | ||
969 | goto out; | 1010 | goto out; |
970 | } | 1011 | } |
971 | sig_off = buffer_len(buf) - buffer_len(©); | 1012 | sig_off = sshbuf_len(buf) - sshbuf_len(copy); |
972 | /* Second string component is the signature itself */ | 1013 | /* Second string component is the signature itself */ |
973 | if ((blob = buffer_get_string_ptr_ret(©, &blen)) == NULL) { | 1014 | if ((r = sshbuf_get_string_direct(copy, &blob, &blen)) != 0) { |
974 | error("%s: buffer error", __func__); | 1015 | r = SSH_ERR_INVALID_FORMAT; |
975 | goto out; | 1016 | goto out; |
976 | } | 1017 | } |
977 | /* Check signature over entire KRL up to this point */ | 1018 | /* Check signature over entire KRL up to this point */ |
978 | if (key_verify(key, blob, blen, | 1019 | if ((r = sshkey_verify(key, blob, blen, |
979 | buffer_ptr(buf), buffer_len(buf) - sig_off) != 1) { | 1020 | sshbuf_ptr(buf), sshbuf_len(buf) - sig_off, 0)) != 0) |
980 | error("bad signaure on KRL"); | ||
981 | goto out; | 1021 | goto out; |
982 | } | ||
983 | /* Check if this key has already signed this KRL */ | 1022 | /* Check if this key has already signed this KRL */ |
984 | for (i = 0; i < nca_used; i++) { | 1023 | for (i = 0; i < nca_used; i++) { |
985 | if (key_equal(ca_used[i], key)) { | 1024 | if (sshkey_equal(ca_used[i], key)) { |
986 | error("KRL signed more than once with " | 1025 | error("KRL signed more than once with " |
987 | "the same key"); | 1026 | "the same key"); |
1027 | r = SSH_ERR_INVALID_FORMAT; | ||
988 | goto out; | 1028 | goto out; |
989 | } | 1029 | } |
990 | } | 1030 | } |
991 | /* Record keys used to sign the KRL */ | 1031 | /* Record keys used to sign the KRL */ |
992 | ca_used = xrealloc(ca_used, nca_used + 1, sizeof(*ca_used)); | 1032 | tmp_ca_used = reallocarray(ca_used, nca_used + 1, |
1033 | sizeof(*ca_used)); | ||
1034 | if (tmp_ca_used == NULL) { | ||
1035 | r = SSH_ERR_ALLOC_FAIL; | ||
1036 | goto out; | ||
1037 | } | ||
1038 | ca_used = tmp_ca_used; | ||
993 | ca_used[nca_used++] = key; | 1039 | ca_used[nca_used++] = key; |
994 | key = NULL; | 1040 | key = NULL; |
995 | break; | 1041 | break; |
996 | } | 1042 | } |
997 | 1043 | ||
1044 | if (sshbuf_len(copy) != 0) { | ||
1045 | /* Shouldn't happen */ | ||
1046 | r = SSH_ERR_INTERNAL_ERROR; | ||
1047 | goto out; | ||
1048 | } | ||
1049 | |||
998 | /* | 1050 | /* |
999 | * 2nd pass: parse and load the KRL, skipping the header to the point | 1051 | * 2nd pass: parse and load the KRL, skipping the header to the point |
1000 | * where the section start. | 1052 | * where the section start. |
1001 | */ | 1053 | */ |
1002 | buffer_append(©, (u_char*)buffer_ptr(buf) + sects_off, | 1054 | sshbuf_free(copy); |
1003 | buffer_len(buf) - sects_off); | 1055 | if ((copy = sshbuf_fromb(buf)) == NULL) { |
1004 | while (buffer_len(©) > 0) { | 1056 | r = SSH_ERR_ALLOC_FAIL; |
1005 | if (buffer_get_char_ret(&type, ©) != 0 || | 1057 | goto out; |
1006 | (blob = buffer_get_string_ptr_ret(©, &blen)) == NULL) { | 1058 | } |
1007 | error("%s: buffer error", __func__); | 1059 | if ((r = sshbuf_consume(copy, sects_off)) != 0) |
1008 | goto out; | 1060 | goto out; |
1061 | while (sshbuf_len(copy) > 0) { | ||
1062 | if (sect != NULL) { | ||
1063 | sshbuf_free(sect); | ||
1064 | sect = NULL; | ||
1009 | } | 1065 | } |
1010 | debug3("%s: second pass, section 0x%02x", __func__, type); | 1066 | if ((r = sshbuf_get_u8(copy, &type)) != 0 || |
1011 | buffer_clear(§); | 1067 | (r = sshbuf_froms(copy, §)) != 0) |
1012 | buffer_append(§, blob, blen); | 1068 | goto out; |
1069 | KRL_DBG(("%s: second pass, section 0x%02x", __func__, type)); | ||
1013 | 1070 | ||
1014 | switch (type) { | 1071 | switch (type) { |
1015 | case KRL_SECTION_CERTIFICATES: | 1072 | case KRL_SECTION_CERTIFICATES: |
1016 | if ((r = parse_revoked_certs(§, krl)) != 0) | 1073 | if ((r = parse_revoked_certs(sect, krl)) != 0) |
1017 | goto out; | 1074 | goto out; |
1018 | break; | 1075 | break; |
1019 | case KRL_SECTION_EXPLICIT_KEY: | 1076 | case KRL_SECTION_EXPLICIT_KEY: |
1020 | case KRL_SECTION_FINGERPRINT_SHA1: | 1077 | case KRL_SECTION_FINGERPRINT_SHA1: |
1021 | while (buffer_len(§) > 0) { | 1078 | while (sshbuf_len(sect) > 0) { |
1022 | if ((rdata = buffer_get_string_ret(§, | 1079 | if ((r = sshbuf_get_string(sect, |
1023 | &rlen)) == NULL) { | 1080 | &rdata, &rlen)) != 0) |
1024 | error("%s: buffer error", __func__); | ||
1025 | goto out; | 1081 | goto out; |
1026 | } | ||
1027 | if (type == KRL_SECTION_FINGERPRINT_SHA1 && | 1082 | if (type == KRL_SECTION_FINGERPRINT_SHA1 && |
1028 | rlen != 20) { | 1083 | rlen != 20) { |
1029 | error("%s: bad SHA1 length", __func__); | 1084 | error("%s: bad SHA1 length", __func__); |
1085 | r = SSH_ERR_INVALID_FORMAT; | ||
1030 | goto out; | 1086 | goto out; |
1031 | } | 1087 | } |
1032 | if (revoke_blob( | 1088 | if ((r = revoke_blob( |
1033 | type == KRL_SECTION_EXPLICIT_KEY ? | 1089 | type == KRL_SECTION_EXPLICIT_KEY ? |
1034 | &krl->revoked_keys : &krl->revoked_sha1s, | 1090 | &krl->revoked_keys : &krl->revoked_sha1s, |
1035 | rdata, rlen) != 0) | 1091 | rdata, rlen)) != 0) |
1036 | goto out; | 1092 | goto out; |
1037 | rdata = NULL; /* revoke_blob frees blob */ | 1093 | rdata = NULL; /* revoke_blob frees rdata */ |
1038 | } | 1094 | } |
1039 | break; | 1095 | break; |
1040 | case KRL_SECTION_SIGNATURE: | 1096 | case KRL_SECTION_SIGNATURE: |
1041 | /* Handled above, but still need to stay in synch */ | 1097 | /* Handled above, but still need to stay in synch */ |
1042 | buffer_clear(§); | 1098 | sshbuf_reset(sect); |
1043 | if ((blob = buffer_get_string_ptr_ret(©, | 1099 | sect = NULL; |
1044 | &blen)) == NULL) { | 1100 | if ((r = sshbuf_skip_string(copy)) != 0) |
1045 | error("%s: buffer error", __func__); | ||
1046 | goto out; | 1101 | goto out; |
1047 | } | ||
1048 | break; | 1102 | break; |
1049 | default: | 1103 | default: |
1050 | error("Unsupported KRL section %u", type); | 1104 | error("Unsupported KRL section %u", type); |
1105 | r = SSH_ERR_INVALID_FORMAT; | ||
1051 | goto out; | 1106 | goto out; |
1052 | } | 1107 | } |
1053 | if (buffer_len(§) > 0) { | 1108 | if (sshbuf_len(sect) > 0) { |
1054 | error("KRL section contains unparsed data"); | 1109 | error("KRL section contains unparsed data"); |
1110 | r = SSH_ERR_INVALID_FORMAT; | ||
1055 | goto out; | 1111 | goto out; |
1056 | } | 1112 | } |
1057 | } | 1113 | } |
@@ -1062,12 +1118,13 @@ ssh_krl_from_blob(Buffer *buf, struct ssh_krl **krlp, | |||
1062 | if (ssh_krl_check_key(krl, ca_used[i]) == 0) | 1118 | if (ssh_krl_check_key(krl, ca_used[i]) == 0) |
1063 | sig_seen = 1; | 1119 | sig_seen = 1; |
1064 | else { | 1120 | else { |
1065 | key_free(ca_used[i]); | 1121 | sshkey_free(ca_used[i]); |
1066 | ca_used[i] = NULL; | 1122 | ca_used[i] = NULL; |
1067 | } | 1123 | } |
1068 | } | 1124 | } |
1069 | if (nca_used && !sig_seen) { | 1125 | if (nca_used && !sig_seen) { |
1070 | error("All keys used to sign KRL were revoked"); | 1126 | error("All keys used to sign KRL were revoked"); |
1127 | r = SSH_ERR_KEY_REVOKED; | ||
1071 | goto out; | 1128 | goto out; |
1072 | } | 1129 | } |
1073 | 1130 | ||
@@ -1078,163 +1135,169 @@ ssh_krl_from_blob(Buffer *buf, struct ssh_krl **krlp, | |||
1078 | for (j = 0; j < nca_used; j++) { | 1135 | for (j = 0; j < nca_used; j++) { |
1079 | if (ca_used[j] == NULL) | 1136 | if (ca_used[j] == NULL) |
1080 | continue; | 1137 | continue; |
1081 | if (key_equal(ca_used[j], sign_ca_keys[i])) { | 1138 | if (sshkey_equal(ca_used[j], sign_ca_keys[i])) { |
1082 | sig_seen = 1; | 1139 | sig_seen = 1; |
1083 | break; | 1140 | break; |
1084 | } | 1141 | } |
1085 | } | 1142 | } |
1086 | } | 1143 | } |
1087 | if (!sig_seen) { | 1144 | if (!sig_seen) { |
1145 | r = SSH_ERR_SIGNATURE_INVALID; | ||
1088 | error("KRL not signed with any trusted key"); | 1146 | error("KRL not signed with any trusted key"); |
1089 | goto out; | 1147 | goto out; |
1090 | } | 1148 | } |
1091 | } | 1149 | } |
1092 | 1150 | ||
1093 | *krlp = krl; | 1151 | *krlp = krl; |
1094 | ret = 0; | 1152 | r = 0; |
1095 | out: | 1153 | out: |
1096 | if (ret != 0) | 1154 | if (r != 0) |
1097 | ssh_krl_free(krl); | 1155 | ssh_krl_free(krl); |
1098 | for (i = 0; i < nca_used; i++) { | 1156 | for (i = 0; i < nca_used; i++) |
1099 | if (ca_used[i] != NULL) | 1157 | sshkey_free(ca_used[i]); |
1100 | key_free(ca_used[i]); | ||
1101 | } | ||
1102 | free(ca_used); | 1158 | free(ca_used); |
1103 | free(rdata); | 1159 | free(rdata); |
1104 | if (key != NULL) | 1160 | sshkey_free(key); |
1105 | key_free(key); | 1161 | sshbuf_free(copy); |
1106 | buffer_free(©); | 1162 | sshbuf_free(sect); |
1107 | buffer_free(§); | 1163 | return r; |
1108 | return ret; | ||
1109 | } | 1164 | } |
1110 | 1165 | ||
1111 | /* Checks whether a given key/cert is revoked. Does not check its CA */ | 1166 | /* Checks certificate serial number and key ID revocation */ |
1112 | static int | 1167 | static int |
1113 | is_key_revoked(struct ssh_krl *krl, const Key *key) | 1168 | is_cert_revoked(const struct sshkey *key, struct revoked_certs *rc) |
1114 | { | 1169 | { |
1115 | struct revoked_blob rb, *erb; | ||
1116 | struct revoked_serial rs, *ers; | 1170 | struct revoked_serial rs, *ers; |
1117 | struct revoked_key_id rki, *erki; | 1171 | struct revoked_key_id rki, *erki; |
1118 | struct revoked_certs *rc; | ||
1119 | |||
1120 | /* Check explicitly revoked hashes first */ | ||
1121 | memset(&rb, 0, sizeof(rb)); | ||
1122 | if ((rb.blob = key_fingerprint_raw(key, SSH_FP_SHA1, &rb.len)) == NULL) | ||
1123 | return -1; | ||
1124 | erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha1s, &rb); | ||
1125 | free(rb.blob); | ||
1126 | if (erb != NULL) { | ||
1127 | debug("%s: revoked by key SHA1", __func__); | ||
1128 | return -1; | ||
1129 | } | ||
1130 | |||
1131 | /* Next, explicit keys */ | ||
1132 | memset(&rb, 0, sizeof(rb)); | ||
1133 | if (plain_key_blob(key, &rb.blob, &rb.len) < 0) | ||
1134 | return -1; | ||
1135 | erb = RB_FIND(revoked_blob_tree, &krl->revoked_keys, &rb); | ||
1136 | free(rb.blob); | ||
1137 | if (erb != NULL) { | ||
1138 | debug("%s: revoked by explicit key", __func__); | ||
1139 | return -1; | ||
1140 | } | ||
1141 | |||
1142 | if (!key_is_cert(key)) | ||
1143 | return 0; | ||
1144 | |||
1145 | /* Check cert revocation */ | ||
1146 | if (revoked_certs_for_ca_key(krl, key->cert->signature_key, | ||
1147 | &rc, 0) != 0) | ||
1148 | return -1; | ||
1149 | if (rc == NULL) | ||
1150 | return 0; /* No entry for this CA */ | ||
1151 | 1172 | ||
1152 | /* Check revocation by cert key ID */ | 1173 | /* Check revocation by cert key ID */ |
1153 | memset(&rki, 0, sizeof(rki)); | 1174 | memset(&rki, 0, sizeof(rki)); |
1154 | rki.key_id = key->cert->key_id; | 1175 | rki.key_id = key->cert->key_id; |
1155 | erki = RB_FIND(revoked_key_id_tree, &rc->revoked_key_ids, &rki); | 1176 | erki = RB_FIND(revoked_key_id_tree, &rc->revoked_key_ids, &rki); |
1156 | if (erki != NULL) { | 1177 | if (erki != NULL) { |
1157 | debug("%s: revoked by key ID", __func__); | 1178 | KRL_DBG(("%s: revoked by key ID", __func__)); |
1158 | return -1; | 1179 | return SSH_ERR_KEY_REVOKED; |
1159 | } | 1180 | } |
1160 | 1181 | ||
1161 | /* | 1182 | /* |
1162 | * Legacy cert formats lack serial numbers. Zero serials numbers | 1183 | * Legacy cert formats lack serial numbers. Zero serials numbers |
1163 | * are ignored (it's the default when the CA doesn't specify one). | 1184 | * are ignored (it's the default when the CA doesn't specify one). |
1164 | */ | 1185 | */ |
1165 | if (key_cert_is_legacy(key) || key->cert->serial == 0) | 1186 | if (sshkey_cert_is_legacy(key) || key->cert->serial == 0) |
1166 | return 0; | 1187 | return 0; |
1167 | 1188 | ||
1168 | memset(&rs, 0, sizeof(rs)); | 1189 | memset(&rs, 0, sizeof(rs)); |
1169 | rs.lo = rs.hi = key->cert->serial; | 1190 | rs.lo = rs.hi = key->cert->serial; |
1170 | ers = RB_FIND(revoked_serial_tree, &rc->revoked_serials, &rs); | 1191 | ers = RB_FIND(revoked_serial_tree, &rc->revoked_serials, &rs); |
1171 | if (ers != NULL) { | 1192 | if (ers != NULL) { |
1172 | KRL_DBG(("%s: %llu matched %llu:%llu", __func__, | 1193 | KRL_DBG(("%s: revoked serial %llu matched %llu:%llu", __func__, |
1173 | key->cert->serial, ers->lo, ers->hi)); | 1194 | key->cert->serial, ers->lo, ers->hi)); |
1174 | debug("%s: revoked by serial", __func__); | 1195 | return SSH_ERR_KEY_REVOKED; |
1175 | return -1; | ||
1176 | } | 1196 | } |
1177 | KRL_DBG(("%s: %llu no match", __func__, key->cert->serial)); | 1197 | return 0; |
1198 | } | ||
1199 | |||
1200 | /* Checks whether a given key/cert is revoked. Does not check its CA */ | ||
1201 | static int | ||
1202 | is_key_revoked(struct ssh_krl *krl, const struct sshkey *key) | ||
1203 | { | ||
1204 | struct revoked_blob rb, *erb; | ||
1205 | struct revoked_certs *rc; | ||
1206 | int r; | ||
1207 | |||
1208 | /* Check explicitly revoked hashes first */ | ||
1209 | memset(&rb, 0, sizeof(rb)); | ||
1210 | if ((r = sshkey_fingerprint_raw(key, SSH_DIGEST_SHA1, | ||
1211 | &rb.blob, &rb.len)) != 0) | ||
1212 | return r; | ||
1213 | erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha1s, &rb); | ||
1214 | free(rb.blob); | ||
1215 | if (erb != NULL) { | ||
1216 | KRL_DBG(("%s: revoked by key SHA1", __func__)); | ||
1217 | return SSH_ERR_KEY_REVOKED; | ||
1218 | } | ||
1219 | |||
1220 | /* Next, explicit keys */ | ||
1221 | memset(&rb, 0, sizeof(rb)); | ||
1222 | if ((r = plain_key_blob(key, &rb.blob, &rb.len)) != 0) | ||
1223 | return r; | ||
1224 | erb = RB_FIND(revoked_blob_tree, &krl->revoked_keys, &rb); | ||
1225 | free(rb.blob); | ||
1226 | if (erb != NULL) { | ||
1227 | KRL_DBG(("%s: revoked by explicit key", __func__)); | ||
1228 | return SSH_ERR_KEY_REVOKED; | ||
1229 | } | ||
1230 | |||
1231 | if (!sshkey_is_cert(key)) | ||
1232 | return 0; | ||
1178 | 1233 | ||
1234 | /* Check cert revocation for the specified CA */ | ||
1235 | if ((r = revoked_certs_for_ca_key(krl, key->cert->signature_key, | ||
1236 | &rc, 0)) != 0) | ||
1237 | return r; | ||
1238 | if (rc != NULL) { | ||
1239 | if ((r = is_cert_revoked(key, rc)) != 0) | ||
1240 | return r; | ||
1241 | } | ||
1242 | /* Check cert revocation for the wildcard CA */ | ||
1243 | if ((r = revoked_certs_for_ca_key(krl, NULL, &rc, 0)) != 0) | ||
1244 | return r; | ||
1245 | if (rc != NULL) { | ||
1246 | if ((r = is_cert_revoked(key, rc)) != 0) | ||
1247 | return r; | ||
1248 | } | ||
1249 | |||
1250 | KRL_DBG(("%s: %llu no match", __func__, key->cert->serial)); | ||
1179 | return 0; | 1251 | return 0; |
1180 | } | 1252 | } |
1181 | 1253 | ||
1182 | int | 1254 | int |
1183 | ssh_krl_check_key(struct ssh_krl *krl, const Key *key) | 1255 | ssh_krl_check_key(struct ssh_krl *krl, const struct sshkey *key) |
1184 | { | 1256 | { |
1185 | int r; | 1257 | int r; |
1186 | 1258 | ||
1187 | debug2("%s: checking key", __func__); | 1259 | KRL_DBG(("%s: checking key", __func__)); |
1188 | if ((r = is_key_revoked(krl, key)) != 0) | 1260 | if ((r = is_key_revoked(krl, key)) != 0) |
1189 | return r; | 1261 | return r; |
1190 | if (key_is_cert(key)) { | 1262 | if (sshkey_is_cert(key)) { |
1191 | debug2("%s: checking CA key", __func__); | 1263 | debug2("%s: checking CA key", __func__); |
1192 | if ((r = is_key_revoked(krl, key->cert->signature_key)) != 0) | 1264 | if ((r = is_key_revoked(krl, key->cert->signature_key)) != 0) |
1193 | return r; | 1265 | return r; |
1194 | } | 1266 | } |
1195 | debug3("%s: key okay", __func__); | 1267 | KRL_DBG(("%s: key okay", __func__)); |
1196 | return 0; | 1268 | return 0; |
1197 | } | 1269 | } |
1198 | 1270 | ||
1199 | /* Returns 0 on success, -1 on error or key revoked, -2 if path is not a KRL */ | ||
1200 | int | 1271 | int |
1201 | ssh_krl_file_contains_key(const char *path, const Key *key) | 1272 | ssh_krl_file_contains_key(const char *path, const struct sshkey *key) |
1202 | { | 1273 | { |
1203 | Buffer krlbuf; | 1274 | struct sshbuf *krlbuf = NULL; |
1204 | struct ssh_krl *krl; | 1275 | struct ssh_krl *krl = NULL; |
1205 | int revoked, fd; | 1276 | int oerrno = 0, r, fd; |
1206 | 1277 | ||
1207 | if (path == NULL) | 1278 | if (path == NULL) |
1208 | return 0; | 1279 | return 0; |
1209 | 1280 | ||
1281 | if ((krlbuf = sshbuf_new()) == NULL) | ||
1282 | return SSH_ERR_ALLOC_FAIL; | ||
1210 | if ((fd = open(path, O_RDONLY)) == -1) { | 1283 | if ((fd = open(path, O_RDONLY)) == -1) { |
1211 | error("open %s: %s", path, strerror(errno)); | 1284 | r = SSH_ERR_SYSTEM_ERROR; |
1212 | error("Revoked keys file not accessible - refusing public key " | 1285 | oerrno = errno; |
1213 | "authentication"); | 1286 | goto out; |
1214 | return -1; | ||
1215 | } | ||
1216 | buffer_init(&krlbuf); | ||
1217 | if (!key_load_file(fd, path, &krlbuf)) { | ||
1218 | close(fd); | ||
1219 | buffer_free(&krlbuf); | ||
1220 | error("Revoked keys file not readable - refusing public key " | ||
1221 | "authentication"); | ||
1222 | return -1; | ||
1223 | } | ||
1224 | close(fd); | ||
1225 | if (ssh_krl_from_blob(&krlbuf, &krl, NULL, 0) != 0) { | ||
1226 | buffer_free(&krlbuf); | ||
1227 | error("Invalid KRL, refusing public key " | ||
1228 | "authentication"); | ||
1229 | return -1; | ||
1230 | } | 1287 | } |
1231 | buffer_free(&krlbuf); | 1288 | if ((r = sshkey_load_file(fd, krlbuf)) != 0) { |
1232 | if (krl == NULL) { | 1289 | oerrno = errno; |
1233 | debug3("%s: %s is not a KRL file", __func__, path); | 1290 | goto out; |
1234 | return -2; | ||
1235 | } | 1291 | } |
1292 | if ((r = ssh_krl_from_blob(krlbuf, &krl, NULL, 0)) != 0) | ||
1293 | goto out; | ||
1236 | debug2("%s: checking KRL %s", __func__, path); | 1294 | debug2("%s: checking KRL %s", __func__, path); |
1237 | revoked = ssh_krl_check_key(krl, key) != 0; | 1295 | r = ssh_krl_check_key(krl, key); |
1296 | out: | ||
1297 | close(fd); | ||
1298 | sshbuf_free(krlbuf); | ||
1238 | ssh_krl_free(krl); | 1299 | ssh_krl_free(krl); |
1239 | return revoked ? -1 : 0; | 1300 | if (r != 0) |
1301 | errno = oerrno; | ||
1302 | return r; | ||
1240 | } | 1303 | } |