2 * Copyright (c) 2012 Damien Miller <djm@mindrot.org>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 /* $OpenBSD: krl.c,v 1.40 2017/05/31 09:15:42 deraadt Exp $ */
21 #include <sys/types.h>
22 #include <openbsd-compat/sys-tree.h>
23 #include <openbsd-compat/sys-queue.h>
43 /* #define DEBUG_KRL */
45 # define KRL_DBG(x) debug3 x
51 * Trees of revoked serial numbers, key IDs and keys. This allows
52 * quick searching, querying and producing lists in canonical order.
55 /* Tree of serial numbers. XXX make smarter: really need a real sparse bitmap */
56 struct revoked_serial
{
58 RB_ENTRY(revoked_serial
) tree_entry
;
60 static int serial_cmp(struct revoked_serial
*a
, struct revoked_serial
*b
);
61 RB_HEAD(revoked_serial_tree
, revoked_serial
);
62 RB_GENERATE_STATIC(revoked_serial_tree
, revoked_serial
, tree_entry
, serial_cmp
);
65 struct revoked_key_id
{
67 RB_ENTRY(revoked_key_id
) tree_entry
;
69 static int key_id_cmp(struct revoked_key_id
*a
, struct revoked_key_id
*b
);
70 RB_HEAD(revoked_key_id_tree
, revoked_key_id
);
71 RB_GENERATE_STATIC(revoked_key_id_tree
, revoked_key_id
, tree_entry
, key_id_cmp
);
73 /* Tree of blobs (used for keys and fingerprints) */
77 RB_ENTRY(revoked_blob
) tree_entry
;
79 static int blob_cmp(struct revoked_blob
*a
, struct revoked_blob
*b
);
80 RB_HEAD(revoked_blob_tree
, revoked_blob
);
81 RB_GENERATE_STATIC(revoked_blob_tree
, revoked_blob
, tree_entry
, blob_cmp
);
83 /* Tracks revoked certs for a single CA */
84 struct revoked_certs
{
85 struct sshkey
*ca_key
;
86 struct revoked_serial_tree revoked_serials
;
87 struct revoked_key_id_tree revoked_key_ids
;
88 TAILQ_ENTRY(revoked_certs
) entry
;
90 TAILQ_HEAD(revoked_certs_list
, revoked_certs
);
93 u_int64_t krl_version
;
94 u_int64_t generated_date
;
97 struct revoked_blob_tree revoked_keys
;
98 struct revoked_blob_tree revoked_sha1s
;
99 struct revoked_certs_list revoked_certs
;
102 /* Return equal if a and b overlap */
104 serial_cmp(struct revoked_serial
*a
, struct revoked_serial
*b
)
106 if (a
->hi
>= b
->lo
&& a
->lo
<= b
->hi
)
108 return a
->lo
< b
->lo
? -1 : 1;
112 key_id_cmp(struct revoked_key_id
*a
, struct revoked_key_id
*b
)
114 return strcmp(a
->key_id
, b
->key_id
);
118 blob_cmp(struct revoked_blob
*a
, struct revoked_blob
*b
)
122 if (a
->len
!= b
->len
) {
123 if ((r
= memcmp(a
->blob
, b
->blob
, MINIMUM(a
->len
, b
->len
))) != 0)
125 return a
->len
> b
->len
? 1 : -1;
127 return memcmp(a
->blob
, b
->blob
, a
->len
);
135 if ((krl
= calloc(1, sizeof(*krl
))) == NULL
)
137 RB_INIT(&krl
->revoked_keys
);
138 RB_INIT(&krl
->revoked_sha1s
);
139 TAILQ_INIT(&krl
->revoked_certs
);
144 revoked_certs_free(struct revoked_certs
*rc
)
146 struct revoked_serial
*rs
, *trs
;
147 struct revoked_key_id
*rki
, *trki
;
149 RB_FOREACH_SAFE(rs
, revoked_serial_tree
, &rc
->revoked_serials
, trs
) {
150 RB_REMOVE(revoked_serial_tree
, &rc
->revoked_serials
, rs
);
153 RB_FOREACH_SAFE(rki
, revoked_key_id_tree
, &rc
->revoked_key_ids
, trki
) {
154 RB_REMOVE(revoked_key_id_tree
, &rc
->revoked_key_ids
, rki
);
158 sshkey_free(rc
->ca_key
);
162 ssh_krl_free(struct ssh_krl
*krl
)
164 struct revoked_blob
*rb
, *trb
;
165 struct revoked_certs
*rc
, *trc
;
171 RB_FOREACH_SAFE(rb
, revoked_blob_tree
, &krl
->revoked_keys
, trb
) {
172 RB_REMOVE(revoked_blob_tree
, &krl
->revoked_keys
, rb
);
176 RB_FOREACH_SAFE(rb
, revoked_blob_tree
, &krl
->revoked_sha1s
, trb
) {
177 RB_REMOVE(revoked_blob_tree
, &krl
->revoked_sha1s
, rb
);
181 TAILQ_FOREACH_SAFE(rc
, &krl
->revoked_certs
, entry
, trc
) {
182 TAILQ_REMOVE(&krl
->revoked_certs
, rc
, entry
);
183 revoked_certs_free(rc
);
188 ssh_krl_set_version(struct ssh_krl
*krl
, u_int64_t version
)
190 krl
->krl_version
= version
;
194 ssh_krl_set_comment(struct ssh_krl
*krl
, const char *comment
)
197 if ((krl
->comment
= strdup(comment
)) == NULL
)
198 return SSH_ERR_ALLOC_FAIL
;
203 * Find the revoked_certs struct for a CA key. If allow_create is set then
204 * create a new one in the tree if one did not exist already.
207 revoked_certs_for_ca_key(struct ssh_krl
*krl
, const struct sshkey
*ca_key
,
208 struct revoked_certs
**rcp
, int allow_create
)
210 struct revoked_certs
*rc
;
214 TAILQ_FOREACH(rc
, &krl
->revoked_certs
, entry
) {
215 if ((ca_key
== NULL
&& rc
->ca_key
== NULL
) ||
216 sshkey_equal(rc
->ca_key
, ca_key
)) {
223 /* If this CA doesn't exist in the list then add it now */
224 if ((rc
= calloc(1, sizeof(*rc
))) == NULL
)
225 return SSH_ERR_ALLOC_FAIL
;
228 else if ((r
= sshkey_from_private(ca_key
, &rc
->ca_key
)) != 0) {
232 RB_INIT(&rc
->revoked_serials
);
233 RB_INIT(&rc
->revoked_key_ids
);
234 TAILQ_INSERT_TAIL(&krl
->revoked_certs
, rc
, entry
);
235 KRL_DBG(("%s: new CA %s", __func__
,
236 ca_key
== NULL
? "*" : sshkey_type(ca_key
)));
242 insert_serial_range(struct revoked_serial_tree
*rt
, u_int64_t lo
, u_int64_t hi
)
244 struct revoked_serial rs
, *ers
, *crs
, *irs
;
246 KRL_DBG(("%s: insert %llu:%llu", __func__
, lo
, hi
));
247 memset(&rs
, 0, sizeof(rs
));
250 ers
= RB_NFIND(revoked_serial_tree
, rt
, &rs
);
251 if (ers
== NULL
|| serial_cmp(ers
, &rs
) != 0) {
252 /* No entry matches. Just insert */
253 if ((irs
= malloc(sizeof(rs
))) == NULL
)
254 return SSH_ERR_ALLOC_FAIL
;
255 memcpy(irs
, &rs
, sizeof(*irs
));
256 ers
= RB_INSERT(revoked_serial_tree
, rt
, irs
);
258 KRL_DBG(("%s: bad: ers != NULL", __func__
));
259 /* Shouldn't happen */
261 return SSH_ERR_INTERNAL_ERROR
;
265 KRL_DBG(("%s: overlap found %llu:%llu", __func__
,
268 * The inserted entry overlaps an existing one. Grow the
278 * The inserted or revised range might overlap or abut adjacent ones;
279 * coalesce as necessary.
282 /* Check predecessors */
283 while ((crs
= RB_PREV(revoked_serial_tree
, rt
, ers
)) != NULL
) {
284 KRL_DBG(("%s: pred %llu:%llu", __func__
, crs
->lo
, crs
->hi
));
285 if (ers
->lo
!= 0 && crs
->hi
< ers
->lo
- 1)
287 /* This entry overlaps. */
288 if (crs
->lo
< ers
->lo
) {
290 KRL_DBG(("%s: pred extend %llu:%llu", __func__
,
293 RB_REMOVE(revoked_serial_tree
, rt
, crs
);
296 /* Check successors */
297 while ((crs
= RB_NEXT(revoked_serial_tree
, rt
, ers
)) != NULL
) {
298 KRL_DBG(("%s: succ %llu:%llu", __func__
, crs
->lo
, crs
->hi
));
299 if (ers
->hi
!= (u_int64_t
)-1 && crs
->lo
> ers
->hi
+ 1)
301 /* This entry overlaps. */
302 if (crs
->hi
> ers
->hi
) {
304 KRL_DBG(("%s: succ extend %llu:%llu", __func__
,
307 RB_REMOVE(revoked_serial_tree
, rt
, crs
);
310 KRL_DBG(("%s: done, final %llu:%llu", __func__
, ers
->lo
, ers
->hi
));
315 ssh_krl_revoke_cert_by_serial(struct ssh_krl
*krl
, const struct sshkey
*ca_key
,
318 return ssh_krl_revoke_cert_by_serial_range(krl
, ca_key
, serial
, serial
);
322 ssh_krl_revoke_cert_by_serial_range(struct ssh_krl
*krl
,
323 const struct sshkey
*ca_key
, u_int64_t lo
, u_int64_t hi
)
325 struct revoked_certs
*rc
;
328 if (lo
> hi
|| lo
== 0)
329 return SSH_ERR_INVALID_ARGUMENT
;
330 if ((r
= revoked_certs_for_ca_key(krl
, ca_key
, &rc
, 1)) != 0)
332 return insert_serial_range(&rc
->revoked_serials
, lo
, hi
);
336 ssh_krl_revoke_cert_by_key_id(struct ssh_krl
*krl
, const struct sshkey
*ca_key
,
339 struct revoked_key_id
*rki
, *erki
;
340 struct revoked_certs
*rc
;
343 if ((r
= revoked_certs_for_ca_key(krl
, ca_key
, &rc
, 1)) != 0)
346 KRL_DBG(("%s: revoke %s", __func__
, key_id
));
347 if ((rki
= calloc(1, sizeof(*rki
))) == NULL
||
348 (rki
->key_id
= strdup(key_id
)) == NULL
) {
350 return SSH_ERR_ALLOC_FAIL
;
352 erki
= RB_INSERT(revoked_key_id_tree
, &rc
->revoked_key_ids
, rki
);
360 /* Convert "key" to a public key blob without any certificate information */
362 plain_key_blob(const struct sshkey
*key
, u_char
**blob
, size_t *blen
)
364 struct sshkey
*kcopy
;
367 if ((r
= sshkey_from_private(key
, &kcopy
)) != 0)
369 if (sshkey_is_cert(kcopy
)) {
370 if ((r
= sshkey_drop_cert(kcopy
)) != 0) {
375 r
= sshkey_to_blob(kcopy
, blob
, blen
);
380 /* Revoke a key blob. Ownership of blob is transferred to the tree */
382 revoke_blob(struct revoked_blob_tree
*rbt
, u_char
*blob
, size_t len
)
384 struct revoked_blob
*rb
, *erb
;
386 if ((rb
= calloc(1, sizeof(*rb
))) == NULL
)
387 return SSH_ERR_ALLOC_FAIL
;
390 erb
= RB_INSERT(revoked_blob_tree
, rbt
, rb
);
399 ssh_krl_revoke_key_explicit(struct ssh_krl
*krl
, const struct sshkey
*key
)
405 debug3("%s: revoke type %s", __func__
, sshkey_type(key
));
406 if ((r
= plain_key_blob(key
, &blob
, &len
)) != 0)
408 return revoke_blob(&krl
->revoked_keys
, blob
, len
);
412 ssh_krl_revoke_key_sha1(struct ssh_krl
*krl
, const struct sshkey
*key
)
418 debug3("%s: revoke type %s by sha1", __func__
, sshkey_type(key
));
419 if ((r
= sshkey_fingerprint_raw(key
, SSH_DIGEST_SHA1
,
422 return revoke_blob(&krl
->revoked_sha1s
, blob
, len
);
426 ssh_krl_revoke_key(struct ssh_krl
*krl
, const struct sshkey
*key
)
428 if (!sshkey_is_cert(key
))
429 return ssh_krl_revoke_key_sha1(krl
, key
);
431 if (key
->cert
->serial
== 0) {
432 return ssh_krl_revoke_cert_by_key_id(krl
,
433 key
->cert
->signature_key
,
436 return ssh_krl_revoke_cert_by_serial(krl
,
437 key
->cert
->signature_key
,
443 * Select the most compact section type to emit next in a KRL based on
444 * the current section type, the run length of contiguous revoked serial
445 * numbers and the gaps from the last and to the next revoked serial.
446 * Applies a mostly-accurate bit cost model to select the section type
447 * that will minimise the size of the resultant KRL.
450 choose_next_state(int current_state
, u_int64_t contig
, int final
,
451 u_int64_t last_gap
, u_int64_t next_gap
, int *force_new_section
)
454 u_int64_t cost
, cost_list
, cost_range
, cost_bitmap
, cost_bitmap_restart
;
457 * Avoid unsigned overflows.
458 * The limits are high enough to avoid confusing the calculations.
460 contig
= MINIMUM(contig
, 1ULL<<31);
461 last_gap
= MINIMUM(last_gap
, 1ULL<<31);
462 next_gap
= MINIMUM(next_gap
, 1ULL<<31);
465 * Calculate the cost to switch from the current state to candidates.
466 * NB. range sections only ever contain a single range, so their
467 * switching cost is independent of the current_state.
469 cost_list
= cost_bitmap
= cost_bitmap_restart
= 0;
471 switch (current_state
) {
472 case KRL_SECTION_CERT_SERIAL_LIST
:
473 cost_bitmap_restart
= cost_bitmap
= 8 + 64;
475 case KRL_SECTION_CERT_SERIAL_BITMAP
:
477 cost_bitmap_restart
= 8 + 64;
479 case KRL_SECTION_CERT_SERIAL_RANGE
:
481 cost_bitmap_restart
= cost_bitmap
= 8 + 64;
485 /* Estimate base cost in bits of each section type */
486 cost_list
+= 64 * contig
+ (final
? 0 : 8+64);
487 cost_range
+= (2 * 64) + (final
? 0 : 8+64);
488 cost_bitmap
+= last_gap
+ contig
+ (final
? 0 : MINIMUM(next_gap
, 8+64));
489 cost_bitmap_restart
+= contig
+ (final
? 0 : MINIMUM(next_gap
, 8+64));
491 /* Convert to byte costs for actual comparison */
492 cost_list
= (cost_list
+ 7) / 8;
493 cost_bitmap
= (cost_bitmap
+ 7) / 8;
494 cost_bitmap_restart
= (cost_bitmap_restart
+ 7) / 8;
495 cost_range
= (cost_range
+ 7) / 8;
497 /* Now pick the best choice */
498 *force_new_section
= 0;
499 new_state
= KRL_SECTION_CERT_SERIAL_BITMAP
;
501 if (cost_range
< cost
) {
502 new_state
= KRL_SECTION_CERT_SERIAL_RANGE
;
505 if (cost_list
< cost
) {
506 new_state
= KRL_SECTION_CERT_SERIAL_LIST
;
509 if (cost_bitmap_restart
< cost
) {
510 new_state
= KRL_SECTION_CERT_SERIAL_BITMAP
;
511 *force_new_section
= 1;
512 cost
= cost_bitmap_restart
;
514 KRL_DBG(("%s: contig %llu last_gap %llu next_gap %llu final %d, costs:"
515 "list %llu range %llu bitmap %llu new bitmap %llu, "
516 "selected 0x%02x%s", __func__
, (long long unsigned)contig
,
517 (long long unsigned)last_gap
, (long long unsigned)next_gap
, final
,
518 (long long unsigned)cost_list
, (long long unsigned)cost_range
,
519 (long long unsigned)cost_bitmap
,
520 (long long unsigned)cost_bitmap_restart
, new_state
,
521 *force_new_section
? " restart" : ""));
526 put_bitmap(struct sshbuf
*buf
, struct bitmap
*bitmap
)
532 len
= bitmap_nbytes(bitmap
);
533 if ((blob
= malloc(len
)) == NULL
)
534 return SSH_ERR_ALLOC_FAIL
;
535 if (bitmap_to_string(bitmap
, blob
, len
) != 0) {
537 return SSH_ERR_INTERNAL_ERROR
;
539 r
= sshbuf_put_bignum2_bytes(buf
, blob
, len
);
544 /* Generate a KRL_SECTION_CERTIFICATES KRL section */
546 revoked_certs_generate(struct revoked_certs
*rc
, struct sshbuf
*buf
)
548 int final
, force_new_sect
, r
= SSH_ERR_INTERNAL_ERROR
;
549 u_int64_t i
, contig
, gap
, last
= 0, bitmap_start
= 0;
550 struct revoked_serial
*rs
, *nrs
;
551 struct revoked_key_id
*rki
;
552 int next_state
, state
= 0;
554 struct bitmap
*bitmap
= NULL
;
556 if ((sect
= sshbuf_new()) == NULL
)
557 return SSH_ERR_ALLOC_FAIL
;
559 /* Store the header: optional CA scope key, reserved */
560 if (rc
->ca_key
== NULL
) {
561 if ((r
= sshbuf_put_string(buf
, NULL
, 0)) != 0)
564 if ((r
= sshkey_puts(rc
->ca_key
, buf
)) != 0)
567 if ((r
= sshbuf_put_string(buf
, NULL
, 0)) != 0)
570 /* Store the revoked serials. */
571 for (rs
= RB_MIN(revoked_serial_tree
, &rc
->revoked_serials
);
573 rs
= RB_NEXT(revoked_serial_tree
, &rc
->revoked_serials
, rs
)) {
574 KRL_DBG(("%s: serial %llu:%llu state 0x%02x", __func__
,
575 (long long unsigned)rs
->lo
, (long long unsigned)rs
->hi
,
578 /* Check contiguous length and gap to next section (if any) */
579 nrs
= RB_NEXT(revoked_serial_tree
, &rc
->revoked_serials
, rs
);
581 gap
= nrs
== NULL
? 0 : nrs
->lo
- rs
->hi
;
582 contig
= 1 + (rs
->hi
- rs
->lo
);
584 /* Choose next state based on these */
585 next_state
= choose_next_state(state
, contig
, final
,
586 state
== 0 ? 0 : rs
->lo
- last
, gap
, &force_new_sect
);
589 * If the current section is a range section or has a different
590 * type to the next section, then finish it off now.
592 if (state
!= 0 && (force_new_sect
|| next_state
!= state
||
593 state
== KRL_SECTION_CERT_SERIAL_RANGE
)) {
594 KRL_DBG(("%s: finish state 0x%02x", __func__
, state
));
596 case KRL_SECTION_CERT_SERIAL_LIST
:
597 case KRL_SECTION_CERT_SERIAL_RANGE
:
599 case KRL_SECTION_CERT_SERIAL_BITMAP
:
600 if ((r
= put_bitmap(sect
, bitmap
)) != 0)
606 if ((r
= sshbuf_put_u8(buf
, state
)) != 0 ||
607 (r
= sshbuf_put_stringb(buf
, sect
)) != 0)
612 /* If we are starting a new section then prepare it now */
613 if (next_state
!= state
|| force_new_sect
) {
614 KRL_DBG(("%s: start state 0x%02x", __func__
,
619 case KRL_SECTION_CERT_SERIAL_LIST
:
620 case KRL_SECTION_CERT_SERIAL_RANGE
:
622 case KRL_SECTION_CERT_SERIAL_BITMAP
:
623 if ((bitmap
= bitmap_new()) == NULL
) {
624 r
= SSH_ERR_ALLOC_FAIL
;
627 bitmap_start
= rs
->lo
;
628 if ((r
= sshbuf_put_u64(sect
,
635 /* Perform section-specific processing */
637 case KRL_SECTION_CERT_SERIAL_LIST
:
638 for (i
= 0; i
< contig
; i
++) {
639 if ((r
= sshbuf_put_u64(sect
, rs
->lo
+ i
)) != 0)
643 case KRL_SECTION_CERT_SERIAL_RANGE
:
644 if ((r
= sshbuf_put_u64(sect
, rs
->lo
)) != 0 ||
645 (r
= sshbuf_put_u64(sect
, rs
->hi
)) != 0)
648 case KRL_SECTION_CERT_SERIAL_BITMAP
:
649 if (rs
->lo
- bitmap_start
> INT_MAX
) {
650 error("%s: insane bitmap gap", __func__
);
653 for (i
= 0; i
< contig
; i
++) {
654 if (bitmap_set_bit(bitmap
,
655 rs
->lo
+ i
- bitmap_start
) != 0) {
656 r
= SSH_ERR_ALLOC_FAIL
;
664 /* Flush the remaining section, if any */
666 KRL_DBG(("%s: serial final flush for state 0x%02x",
669 case KRL_SECTION_CERT_SERIAL_LIST
:
670 case KRL_SECTION_CERT_SERIAL_RANGE
:
672 case KRL_SECTION_CERT_SERIAL_BITMAP
:
673 if ((r
= put_bitmap(sect
, bitmap
)) != 0)
679 if ((r
= sshbuf_put_u8(buf
, state
)) != 0 ||
680 (r
= sshbuf_put_stringb(buf
, sect
)) != 0)
683 KRL_DBG(("%s: serial done ", __func__
));
685 /* Now output a section for any revocations by key ID */
687 RB_FOREACH(rki
, revoked_key_id_tree
, &rc
->revoked_key_ids
) {
688 KRL_DBG(("%s: key ID %s", __func__
, rki
->key_id
));
689 if ((r
= sshbuf_put_cstring(sect
, rki
->key_id
)) != 0)
692 if (sshbuf_len(sect
) != 0) {
693 if ((r
= sshbuf_put_u8(buf
, KRL_SECTION_CERT_KEY_ID
)) != 0 ||
694 (r
= sshbuf_put_stringb(buf
, sect
)) != 0)
705 ssh_krl_to_blob(struct ssh_krl
*krl
, struct sshbuf
*buf
,
706 const struct sshkey
**sign_keys
, u_int nsign_keys
)
708 int r
= SSH_ERR_INTERNAL_ERROR
;
709 struct revoked_certs
*rc
;
710 struct revoked_blob
*rb
;
712 u_char
*sblob
= NULL
;
715 if (krl
->generated_date
== 0)
716 krl
->generated_date
= time(NULL
);
718 if ((sect
= sshbuf_new()) == NULL
)
719 return SSH_ERR_ALLOC_FAIL
;
721 /* Store the header */
722 if ((r
= sshbuf_put(buf
, KRL_MAGIC
, sizeof(KRL_MAGIC
) - 1)) != 0 ||
723 (r
= sshbuf_put_u32(buf
, KRL_FORMAT_VERSION
)) != 0 ||
724 (r
= sshbuf_put_u64(buf
, krl
->krl_version
)) != 0 ||
725 (r
= sshbuf_put_u64(buf
, krl
->generated_date
)) != 0 ||
726 (r
= sshbuf_put_u64(buf
, krl
->flags
)) != 0 ||
727 (r
= sshbuf_put_string(buf
, NULL
, 0)) != 0 ||
728 (r
= sshbuf_put_cstring(buf
, krl
->comment
)) != 0)
731 /* Store sections for revoked certificates */
732 TAILQ_FOREACH(rc
, &krl
->revoked_certs
, entry
) {
734 if ((r
= revoked_certs_generate(rc
, sect
)) != 0)
736 if ((r
= sshbuf_put_u8(buf
, KRL_SECTION_CERTIFICATES
)) != 0 ||
737 (r
= sshbuf_put_stringb(buf
, sect
)) != 0)
741 /* Finally, output sections for revocations by public key/hash */
743 RB_FOREACH(rb
, revoked_blob_tree
, &krl
->revoked_keys
) {
744 KRL_DBG(("%s: key len %zu ", __func__
, rb
->len
));
745 if ((r
= sshbuf_put_string(sect
, rb
->blob
, rb
->len
)) != 0)
748 if (sshbuf_len(sect
) != 0) {
749 if ((r
= sshbuf_put_u8(buf
, KRL_SECTION_EXPLICIT_KEY
)) != 0 ||
750 (r
= sshbuf_put_stringb(buf
, sect
)) != 0)
754 RB_FOREACH(rb
, revoked_blob_tree
, &krl
->revoked_sha1s
) {
755 KRL_DBG(("%s: hash len %zu ", __func__
, rb
->len
));
756 if ((r
= sshbuf_put_string(sect
, rb
->blob
, rb
->len
)) != 0)
759 if (sshbuf_len(sect
) != 0) {
760 if ((r
= sshbuf_put_u8(buf
,
761 KRL_SECTION_FINGERPRINT_SHA1
)) != 0 ||
762 (r
= sshbuf_put_stringb(buf
, sect
)) != 0)
766 for (i
= 0; i
< nsign_keys
; i
++) {
767 KRL_DBG(("%s: signature key %s", __func__
,
768 sshkey_ssh_name(sign_keys
[i
])));
769 if ((r
= sshbuf_put_u8(buf
, KRL_SECTION_SIGNATURE
)) != 0 ||
770 (r
= sshkey_puts(sign_keys
[i
], buf
)) != 0)
773 if ((r
= sshkey_sign(sign_keys
[i
], &sblob
, &slen
,
774 sshbuf_ptr(buf
), sshbuf_len(buf
), NULL
, 0)) != 0)
776 KRL_DBG(("%s: signature sig len %zu", __func__
, slen
));
777 if ((r
= sshbuf_put_string(buf
, sblob
, slen
)) != 0)
789 format_timestamp(u_int64_t timestamp
, char *ts
, size_t nts
)
797 strlcpy(ts
, "<INVALID>", nts
);
800 strftime(ts
, nts
, "%Y%m%dT%H%M%S", tm
);
805 parse_revoked_certs(struct sshbuf
*buf
, struct ssh_krl
*krl
)
807 int r
= SSH_ERR_INTERNAL_ERROR
;
811 struct sshbuf
*subsect
= NULL
;
812 u_int64_t serial
, serial_lo
, serial_hi
;
813 struct bitmap
*bitmap
= NULL
;
815 struct sshkey
*ca_key
= NULL
;
817 if ((subsect
= sshbuf_new()) == NULL
)
818 return SSH_ERR_ALLOC_FAIL
;
820 /* Header: key, reserved */
821 if ((r
= sshbuf_get_string_direct(buf
, &blob
, &blen
)) != 0 ||
822 (r
= sshbuf_skip_string(buf
)) != 0)
824 if (blen
!= 0 && (r
= sshkey_from_blob(blob
, blen
, &ca_key
)) != 0)
827 while (sshbuf_len(buf
) > 0) {
828 sshbuf_free(subsect
);
830 if ((r
= sshbuf_get_u8(buf
, &type
)) != 0 ||
831 (r
= sshbuf_froms(buf
, &subsect
)) != 0)
833 KRL_DBG(("%s: subsection type 0x%02x", __func__
, type
));
834 /* sshbuf_dump(subsect, stderr); */
837 case KRL_SECTION_CERT_SERIAL_LIST
:
838 while (sshbuf_len(subsect
) > 0) {
839 if ((r
= sshbuf_get_u64(subsect
, &serial
)) != 0)
841 if ((r
= ssh_krl_revoke_cert_by_serial(krl
,
842 ca_key
, serial
)) != 0)
846 case KRL_SECTION_CERT_SERIAL_RANGE
:
847 if ((r
= sshbuf_get_u64(subsect
, &serial_lo
)) != 0 ||
848 (r
= sshbuf_get_u64(subsect
, &serial_hi
)) != 0)
850 if ((r
= ssh_krl_revoke_cert_by_serial_range(krl
,
851 ca_key
, serial_lo
, serial_hi
)) != 0)
854 case KRL_SECTION_CERT_SERIAL_BITMAP
:
855 if ((bitmap
= bitmap_new()) == NULL
) {
856 r
= SSH_ERR_ALLOC_FAIL
;
859 if ((r
= sshbuf_get_u64(subsect
, &serial_lo
)) != 0 ||
860 (r
= sshbuf_get_bignum2_bytes_direct(subsect
,
863 if (bitmap_from_string(bitmap
, blob
, blen
) != 0) {
864 r
= SSH_ERR_INVALID_FORMAT
;
867 nbits
= bitmap_nbits(bitmap
);
868 for (serial
= 0; serial
< (u_int64_t
)nbits
; serial
++) {
869 if (serial
> 0 && serial_lo
+ serial
== 0) {
870 error("%s: bitmap wraps u64", __func__
);
871 r
= SSH_ERR_INVALID_FORMAT
;
874 if (!bitmap_test_bit(bitmap
, serial
))
876 if ((r
= ssh_krl_revoke_cert_by_serial(krl
,
877 ca_key
, serial_lo
+ serial
)) != 0)
883 case KRL_SECTION_CERT_KEY_ID
:
884 while (sshbuf_len(subsect
) > 0) {
885 if ((r
= sshbuf_get_cstring(subsect
,
886 &key_id
, NULL
)) != 0)
888 if ((r
= ssh_krl_revoke_cert_by_key_id(krl
,
889 ca_key
, key_id
)) != 0)
896 error("Unsupported KRL certificate section %u", type
);
897 r
= SSH_ERR_INVALID_FORMAT
;
900 if (sshbuf_len(subsect
) > 0) {
901 error("KRL certificate section contains unparsed data");
902 r
= SSH_ERR_INVALID_FORMAT
;
913 sshbuf_free(subsect
);
918 /* Attempt to parse a KRL, checking its signature (if any) with sign_ca_keys. */
920 ssh_krl_from_blob(struct sshbuf
*buf
, struct ssh_krl
**krlp
,
921 const struct sshkey
**sign_ca_keys
, size_t nsign_ca_keys
)
923 struct sshbuf
*copy
= NULL
, *sect
= NULL
;
924 struct ssh_krl
*krl
= NULL
;
926 int r
= SSH_ERR_INTERNAL_ERROR
, sig_seen
;
927 struct sshkey
*key
= NULL
, **ca_used
= NULL
, **tmp_ca_used
;
928 u_char type
, *rdata
= NULL
;
930 size_t i
, j
, sig_off
, sects_off
, rlen
, blen
, nca_used
;
931 u_int format_version
;
935 if (sshbuf_len(buf
) < sizeof(KRL_MAGIC
) - 1 ||
936 memcmp(sshbuf_ptr(buf
), KRL_MAGIC
, sizeof(KRL_MAGIC
) - 1) != 0) {
937 debug3("%s: not a KRL", __func__
);
938 return SSH_ERR_KRL_BAD_MAGIC
;
941 /* Take a copy of the KRL buffer so we can verify its signature later */
942 if ((copy
= sshbuf_fromb(buf
)) == NULL
) {
943 r
= SSH_ERR_ALLOC_FAIL
;
946 if ((r
= sshbuf_consume(copy
, sizeof(KRL_MAGIC
) - 1)) != 0)
949 if ((krl
= ssh_krl_init()) == NULL
) {
950 error("%s: alloc failed", __func__
);
954 if ((r
= sshbuf_get_u32(copy
, &format_version
)) != 0)
956 if (format_version
!= KRL_FORMAT_VERSION
) {
957 r
= SSH_ERR_INVALID_FORMAT
;
960 if ((r
= sshbuf_get_u64(copy
, &krl
->krl_version
)) != 0 ||
961 (r
= sshbuf_get_u64(copy
, &krl
->generated_date
)) != 0 ||
962 (r
= sshbuf_get_u64(copy
, &krl
->flags
)) != 0 ||
963 (r
= sshbuf_skip_string(copy
)) != 0 ||
964 (r
= sshbuf_get_cstring(copy
, &krl
->comment
, NULL
)) != 0)
967 format_timestamp(krl
->generated_date
, timestamp
, sizeof(timestamp
));
968 debug("KRL version %llu generated at %s%s%s",
969 (long long unsigned)krl
->krl_version
, timestamp
,
970 *krl
->comment
? ": " : "", krl
->comment
);
973 * 1st pass: verify signatures, if any. This is done to avoid
974 * detailed parsing of data whose provenance is unverified.
977 if (sshbuf_len(buf
) < sshbuf_len(copy
)) {
978 /* Shouldn't happen */
979 r
= SSH_ERR_INTERNAL_ERROR
;
982 sects_off
= sshbuf_len(buf
) - sshbuf_len(copy
);
983 while (sshbuf_len(copy
) > 0) {
984 if ((r
= sshbuf_get_u8(copy
, &type
)) != 0 ||
985 (r
= sshbuf_get_string_direct(copy
, &blob
, &blen
)) != 0)
987 KRL_DBG(("%s: first pass, section 0x%02x", __func__
, type
));
988 if (type
!= KRL_SECTION_SIGNATURE
) {
990 error("KRL contains non-signature section "
992 r
= SSH_ERR_INVALID_FORMAT
;
995 /* Not interested for now. */
999 /* First string component is the signing key */
1000 if ((r
= sshkey_from_blob(blob
, blen
, &key
)) != 0) {
1001 r
= SSH_ERR_INVALID_FORMAT
;
1004 if (sshbuf_len(buf
) < sshbuf_len(copy
)) {
1005 /* Shouldn't happen */
1006 r
= SSH_ERR_INTERNAL_ERROR
;
1009 sig_off
= sshbuf_len(buf
) - sshbuf_len(copy
);
1010 /* Second string component is the signature itself */
1011 if ((r
= sshbuf_get_string_direct(copy
, &blob
, &blen
)) != 0) {
1012 r
= SSH_ERR_INVALID_FORMAT
;
1015 /* Check signature over entire KRL up to this point */
1016 if ((r
= sshkey_verify(key
, blob
, blen
,
1017 sshbuf_ptr(buf
), sig_off
, 0)) != 0)
1019 /* Check if this key has already signed this KRL */
1020 for (i
= 0; i
< nca_used
; i
++) {
1021 if (sshkey_equal(ca_used
[i
], key
)) {
1022 error("KRL signed more than once with "
1024 r
= SSH_ERR_INVALID_FORMAT
;
1028 /* Record keys used to sign the KRL */
1029 tmp_ca_used
= recallocarray(ca_used
, nca_used
, nca_used
+ 1,
1031 if (tmp_ca_used
== NULL
) {
1032 r
= SSH_ERR_ALLOC_FAIL
;
1035 ca_used
= tmp_ca_used
;
1036 ca_used
[nca_used
++] = key
;
1040 if (sshbuf_len(copy
) != 0) {
1041 /* Shouldn't happen */
1042 r
= SSH_ERR_INTERNAL_ERROR
;
1047 * 2nd pass: parse and load the KRL, skipping the header to the point
1048 * where the section start.
1051 if ((copy
= sshbuf_fromb(buf
)) == NULL
) {
1052 r
= SSH_ERR_ALLOC_FAIL
;
1055 if ((r
= sshbuf_consume(copy
, sects_off
)) != 0)
1057 while (sshbuf_len(copy
) > 0) {
1060 if ((r
= sshbuf_get_u8(copy
, &type
)) != 0 ||
1061 (r
= sshbuf_froms(copy
, §
)) != 0)
1063 KRL_DBG(("%s: second pass, section 0x%02x", __func__
, type
));
1066 case KRL_SECTION_CERTIFICATES
:
1067 if ((r
= parse_revoked_certs(sect
, krl
)) != 0)
1070 case KRL_SECTION_EXPLICIT_KEY
:
1071 case KRL_SECTION_FINGERPRINT_SHA1
:
1072 while (sshbuf_len(sect
) > 0) {
1073 if ((r
= sshbuf_get_string(sect
,
1074 &rdata
, &rlen
)) != 0)
1076 if (type
== KRL_SECTION_FINGERPRINT_SHA1
&&
1078 error("%s: bad SHA1 length", __func__
);
1079 r
= SSH_ERR_INVALID_FORMAT
;
1082 if ((r
= revoke_blob(
1083 type
== KRL_SECTION_EXPLICIT_KEY
?
1084 &krl
->revoked_keys
: &krl
->revoked_sha1s
,
1087 rdata
= NULL
; /* revoke_blob frees rdata */
1090 case KRL_SECTION_SIGNATURE
:
1091 /* Handled above, but still need to stay in synch */
1094 if ((r
= sshbuf_skip_string(copy
)) != 0)
1098 error("Unsupported KRL section %u", type
);
1099 r
= SSH_ERR_INVALID_FORMAT
;
1102 if (sect
!= NULL
&& sshbuf_len(sect
) > 0) {
1103 error("KRL section contains unparsed data");
1104 r
= SSH_ERR_INVALID_FORMAT
;
1109 /* Check that the key(s) used to sign the KRL weren't revoked */
1111 for (i
= 0; i
< nca_used
; i
++) {
1112 if (ssh_krl_check_key(krl
, ca_used
[i
]) == 0)
1115 sshkey_free(ca_used
[i
]);
1119 if (nca_used
&& !sig_seen
) {
1120 error("All keys used to sign KRL were revoked");
1121 r
= SSH_ERR_KEY_REVOKED
;
1125 /* If we have CA keys, then verify that one was used to sign the KRL */
1126 if (sig_seen
&& nsign_ca_keys
!= 0) {
1128 for (i
= 0; !sig_seen
&& i
< nsign_ca_keys
; i
++) {
1129 for (j
= 0; j
< nca_used
; j
++) {
1130 if (ca_used
[j
] == NULL
)
1132 if (sshkey_equal(ca_used
[j
], sign_ca_keys
[i
])) {
1139 r
= SSH_ERR_SIGNATURE_INVALID
;
1140 error("KRL not signed with any trusted key");
1150 for (i
= 0; i
< nca_used
; i
++)
1151 sshkey_free(ca_used
[i
]);
1160 /* Checks certificate serial number and key ID revocation */
1162 is_cert_revoked(const struct sshkey
*key
, struct revoked_certs
*rc
)
1164 struct revoked_serial rs
, *ers
;
1165 struct revoked_key_id rki
, *erki
;
1167 /* Check revocation by cert key ID */
1168 memset(&rki
, 0, sizeof(rki
));
1169 rki
.key_id
= key
->cert
->key_id
;
1170 erki
= RB_FIND(revoked_key_id_tree
, &rc
->revoked_key_ids
, &rki
);
1172 KRL_DBG(("%s: revoked by key ID", __func__
));
1173 return SSH_ERR_KEY_REVOKED
;
1177 * Zero serials numbers are ignored (it's the default when the
1178 * CA doesn't specify one).
1180 if (key
->cert
->serial
== 0)
1183 memset(&rs
, 0, sizeof(rs
));
1184 rs
.lo
= rs
.hi
= key
->cert
->serial
;
1185 ers
= RB_FIND(revoked_serial_tree
, &rc
->revoked_serials
, &rs
);
1187 KRL_DBG(("%s: revoked serial %llu matched %llu:%llu", __func__
,
1188 key
->cert
->serial
, ers
->lo
, ers
->hi
));
1189 return SSH_ERR_KEY_REVOKED
;
1194 /* Checks whether a given key/cert is revoked. Does not check its CA */
1196 is_key_revoked(struct ssh_krl
*krl
, const struct sshkey
*key
)
1198 struct revoked_blob rb
, *erb
;
1199 struct revoked_certs
*rc
;
1202 /* Check explicitly revoked hashes first */
1203 memset(&rb
, 0, sizeof(rb
));
1204 if ((r
= sshkey_fingerprint_raw(key
, SSH_DIGEST_SHA1
,
1205 &rb
.blob
, &rb
.len
)) != 0)
1207 erb
= RB_FIND(revoked_blob_tree
, &krl
->revoked_sha1s
, &rb
);
1210 KRL_DBG(("%s: revoked by key SHA1", __func__
));
1211 return SSH_ERR_KEY_REVOKED
;
1214 /* Next, explicit keys */
1215 memset(&rb
, 0, sizeof(rb
));
1216 if ((r
= plain_key_blob(key
, &rb
.blob
, &rb
.len
)) != 0)
1218 erb
= RB_FIND(revoked_blob_tree
, &krl
->revoked_keys
, &rb
);
1221 KRL_DBG(("%s: revoked by explicit key", __func__
));
1222 return SSH_ERR_KEY_REVOKED
;
1225 if (!sshkey_is_cert(key
))
1228 /* Check cert revocation for the specified CA */
1229 if ((r
= revoked_certs_for_ca_key(krl
, key
->cert
->signature_key
,
1233 if ((r
= is_cert_revoked(key
, rc
)) != 0)
1236 /* Check cert revocation for the wildcard CA */
1237 if ((r
= revoked_certs_for_ca_key(krl
, NULL
, &rc
, 0)) != 0)
1240 if ((r
= is_cert_revoked(key
, rc
)) != 0)
1244 KRL_DBG(("%s: %llu no match", __func__
, key
->cert
->serial
));
1249 ssh_krl_check_key(struct ssh_krl
*krl
, const struct sshkey
*key
)
1253 KRL_DBG(("%s: checking key", __func__
));
1254 if ((r
= is_key_revoked(krl
, key
)) != 0)
1256 if (sshkey_is_cert(key
)) {
1257 debug2("%s: checking CA key", __func__
);
1258 if ((r
= is_key_revoked(krl
, key
->cert
->signature_key
)) != 0)
1261 KRL_DBG(("%s: key okay", __func__
));
1266 ssh_krl_file_contains_key(const char *path
, const struct sshkey
*key
)
1268 struct sshbuf
*krlbuf
= NULL
;
1269 struct ssh_krl
*krl
= NULL
;
1270 int oerrno
= 0, r
, fd
;
1275 if ((krlbuf
= sshbuf_new()) == NULL
)
1276 return SSH_ERR_ALLOC_FAIL
;
1277 if ((fd
= open(path
, O_RDONLY
)) == -1) {
1278 r
= SSH_ERR_SYSTEM_ERROR
;
1282 if ((r
= sshkey_load_file(fd
, krlbuf
)) != 0) {
1286 if ((r
= ssh_krl_from_blob(krlbuf
, &krl
, NULL
, 0)) != 0)
1288 debug2("%s: checking KRL %s", __func__
, path
);
1289 r
= ssh_krl_check_key(krl
, key
);
1293 sshbuf_free(krlbuf
);