Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2012 Damien Miller <djm@mindrot.org>
3 : : *
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.
7 : : *
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.
15 : : */
16 : :
17 : : /* $OpenBSD: krl.c,v 1.14 2014/01/31 16:39:19 tedu Exp $ */
18 : :
19 : : #include "includes.h"
20 : :
21 : : #include <sys/types.h>
22 : : #include <sys/param.h>
23 : : #include <openbsd-compat/sys-tree.h>
24 : : #include <openbsd-compat/sys-queue.h>
25 : :
26 : : #include <errno.h>
27 : : #include <fcntl.h>
28 : : #include <limits.h>
29 : : #include <string.h>
30 : : #include <time.h>
31 : : #include <unistd.h>
32 : :
33 : : #include "buffer.h"
34 : : #include "key.h"
35 : : #include "authfile.h"
36 : : #include "misc.h"
37 : : #include "log.h"
38 : : #include "xmalloc.h"
39 : :
40 : : #include "krl.h"
41 : :
42 : : /* #define DEBUG_KRL */
43 : : #ifdef DEBUG_KRL
44 : : # define KRL_DBG(x) debug3 x
45 : : #else
46 : : # define KRL_DBG(x)
47 : : #endif
48 : :
49 : : /*
50 : : * Trees of revoked serial numbers, key IDs and keys. This allows
51 : : * quick searching, querying and producing lists in canonical order.
52 : : */
53 : :
54 : : /* Tree of serial numbers. XXX make smarter: really need a real sparse bitmap */
55 : : struct revoked_serial {
56 : : u_int64_t lo, hi;
57 : : RB_ENTRY(revoked_serial) tree_entry;
58 : : };
59 : : static int serial_cmp(struct revoked_serial *a, struct revoked_serial *b);
60 : : RB_HEAD(revoked_serial_tree, revoked_serial);
61 [ + + ][ + + ]: 31543 : RB_GENERATE_STATIC(revoked_serial_tree, revoked_serial, tree_entry, serial_cmp);
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + - ]
[ + + ][ + - ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + - ][ + + ]
[ - + ][ + - ]
[ + - ][ - + ]
[ + - ][ - + ]
[ + - ][ + - ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + - ]
[ + + ][ + - ]
[ - + ][ # # ]
[ + + ][ - + ]
[ - + ][ # # ]
[ + - ][ - + ]
[ # # ][ # # ]
[ # # ][ # # ]
[ + - ][ + - ]
[ - + ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ - + ]
[ # # ][ + - ]
[ - + ][ + - ]
[ + - ][ - + ]
[ + - ][ - + ]
[ + + ][ + + ]
[ + + ][ - + ]
[ + - ][ - + ]
[ + + ][ + + ]
[ - + ][ + + ]
[ + + ]
62 : :
63 : : /* Tree of key IDs */
64 : : struct revoked_key_id {
65 : : char *key_id;
66 : : RB_ENTRY(revoked_key_id) tree_entry;
67 : : };
68 : : static int key_id_cmp(struct revoked_key_id *a, struct revoked_key_id *b);
69 : : RB_HEAD(revoked_key_id_tree, revoked_key_id);
70 [ + + ][ + + ]: 596734 : RB_GENERATE_STATIC(revoked_key_id_tree, revoked_key_id, tree_entry, key_id_cmp);
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + - ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ + + ][ + + ]
[ + - ][ + - ]
[ + - ][ + + ]
[ + - ][ + + ]
[ + - ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ - + ][ + - ]
[ - + ][ + - ]
[ - + ][ + - ]
[ + + ][ + + ]
[ + - ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + - ][ + + ]
[ + - ][ + - ]
[ + + ][ + - ]
[ + + ][ + + ]
[ + + ][ + + ]
[ - + ][ + - ]
[ - + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
71 : :
72 : : /* Tree of blobs (used for keys and fingerprints) */
73 : : struct revoked_blob {
74 : : u_char *blob;
75 : : u_int len;
76 : : RB_ENTRY(revoked_blob) tree_entry;
77 : : };
78 : : static int blob_cmp(struct revoked_blob *a, struct revoked_blob *b);
79 : : RB_HEAD(revoked_blob_tree, revoked_blob);
80 [ - + ][ + + ]: 15868 : RB_GENERATE_STATIC(revoked_blob_tree, revoked_blob, tree_entry, blob_cmp);
[ - + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + - ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ + + ][ + + ]
[ + - ][ + + ]
[ + - ][ + + ]
[ + - ][ - + ]
[ # # ][ + + ]
[ - + ][ - + ]
[ # # ][ + - ]
[ - + ][ # # ]
[ # # ][ # # ]
[ # # ][ + - ]
[ + - ][ - + ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ - + ][ # # ]
[ - + ][ # # ]
[ # # ][ # # ]
[ - + ][ + + ]
[ + - ][ + + ]
[ + + ][ + + ]
[ - + ][ + - ]
[ - + ][ + + ]
[ + + ][ - + ]
[ + + ][ + + ]
81 : :
82 : : /* Tracks revoked certs for a single CA */
83 : : struct revoked_certs {
84 : : Key *ca_key;
85 : : struct revoked_serial_tree revoked_serials;
86 : : struct revoked_key_id_tree revoked_key_ids;
87 : : TAILQ_ENTRY(revoked_certs) entry;
88 : : };
89 : : TAILQ_HEAD(revoked_certs_list, revoked_certs);
90 : :
91 : : struct ssh_krl {
92 : : u_int64_t krl_version;
93 : : u_int64_t generated_date;
94 : : u_int64_t flags;
95 : : char *comment;
96 : : struct revoked_blob_tree revoked_keys;
97 : : struct revoked_blob_tree revoked_sha1s;
98 : : struct revoked_certs_list revoked_certs;
99 : : };
100 : :
101 : : /* Return equal if a and b overlap */
102 : : static int
103 : : serial_cmp(struct revoked_serial *a, struct revoked_serial *b)
104 : : {
105 [ + - ][ + + ]: 6306 : if (a->hi >= b->lo && a->lo <= b->hi)
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + - ]
106 : : return 0;
107 [ + - ][ + + ]: 5946 : return a->lo < b->lo ? -1 : 1;
[ + + ][ + + ]
108 : : }
109 : :
110 : : static int
111 : : key_id_cmp(struct revoked_key_id *a, struct revoked_key_id *b)
112 : : {
113 : 298764 : return strcmp(a->key_id, b->key_id);
114 : : }
115 : :
116 : : static int
117 : 2475 : blob_cmp(struct revoked_blob *a, struct revoked_blob *b)
118 : : {
119 : : int r;
120 : :
121 [ - + ]: 2475 : if (a->len != b->len) {
122 [ # # ]: 0 : if ((r = memcmp(a->blob, b->blob, MIN(a->len, b->len))) != 0)
123 : : return r;
124 [ # # ]: 0 : return a->len > b->len ? 1 : -1;
125 : : } else
126 : 2475 : return memcmp(a->blob, b->blob, a->len);
127 : : }
128 : :
129 : : struct ssh_krl *
130 : 525 : ssh_krl_init(void)
131 : : {
132 : : struct ssh_krl *krl;
133 : :
134 [ + - ]: 525 : if ((krl = calloc(1, sizeof(*krl))) == NULL)
135 : : return NULL;
136 : 525 : RB_INIT(&krl->revoked_keys);
137 : 525 : RB_INIT(&krl->revoked_sha1s);
138 : 525 : TAILQ_INIT(&krl->revoked_certs);
139 : 525 : return krl;
140 : : }
141 : :
142 : : static void
143 : 172 : revoked_certs_free(struct revoked_certs *rc)
144 : : {
145 : : struct revoked_serial *rs, *trs;
146 : : struct revoked_key_id *rki, *trki;
147 : :
148 [ + + ]: 1247 : RB_FOREACH_SAFE(rs, revoked_serial_tree, &rc->revoked_serials, trs) {
149 : 1075 : RB_REMOVE(revoked_serial_tree, &rc->revoked_serials, rs);
150 : 1075 : free(rs);
151 : : }
152 [ + + ]: 22188 : RB_FOREACH_SAFE(rki, revoked_key_id_tree, &rc->revoked_key_ids, trki) {
153 : 22016 : RB_REMOVE(revoked_key_id_tree, &rc->revoked_key_ids, rki);
154 : 22016 : free(rki->key_id);
155 : 22016 : free(rki);
156 : : }
157 [ + - ]: 172 : if (rc->ca_key != NULL)
158 : 172 : key_free(rc->ca_key);
159 : 172 : }
160 : :
161 : : void
162 : 525 : ssh_krl_free(struct ssh_krl *krl)
163 : : {
164 : : struct revoked_blob *rb, *trb;
165 : : struct revoked_certs *rc, *trc;
166 : :
167 [ + - ]: 525 : if (krl == NULL)
168 : 525 : return;
169 : :
170 : 525 : free(krl->comment);
171 [ - + ]: 525 : RB_FOREACH_SAFE(rb, revoked_blob_tree, &krl->revoked_keys, trb) {
172 : 0 : RB_REMOVE(revoked_blob_tree, &krl->revoked_keys, rb);
173 : 0 : free(rb->blob);
174 : 0 : free(rb);
175 : : }
176 [ + + ]: 1374 : RB_FOREACH_SAFE(rb, revoked_blob_tree, &krl->revoked_sha1s, trb) {
177 : 849 : RB_REMOVE(revoked_blob_tree, &krl->revoked_sha1s, rb);
178 : 849 : free(rb->blob);
179 : 849 : free(rb);
180 : : }
181 [ + + ]: 697 : TAILQ_FOREACH_SAFE(rc, &krl->revoked_certs, entry, trc) {
182 [ - + ]: 172 : TAILQ_REMOVE(&krl->revoked_certs, rc, entry);
183 : 172 : revoked_certs_free(rc);
184 : : }
185 : : }
186 : :
187 : : void
188 : 0 : ssh_krl_set_version(struct ssh_krl *krl, u_int64_t version)
189 : : {
190 : 0 : krl->krl_version = version;
191 : 0 : }
192 : :
193 : : void
194 : 0 : ssh_krl_set_comment(struct ssh_krl *krl, const char *comment)
195 : : {
196 : 0 : free(krl->comment);
197 [ # # ]: 0 : if ((krl->comment = strdup(comment)) == NULL)
198 : 0 : fatal("%s: strdup", __func__);
199 : 0 : }
200 : :
201 : : /*
202 : : * Find the revoked_certs struct for a CA key. If allow_create is set then
203 : : * create a new one in the tree if one did not exist already.
204 : : */
205 : : static int
206 : 52204 : revoked_certs_for_ca_key(struct ssh_krl *krl, const Key *ca_key,
207 : : struct revoked_certs **rcp, int allow_create)
208 : : {
209 : : struct revoked_certs *rc;
210 : :
211 : 26102 : *rcp = NULL;
212 [ + + ]: 26102 : TAILQ_FOREACH(rc, &krl->revoked_certs, entry) {
213 [ + - ]: 25830 : if (key_equal(rc->ca_key, ca_key)) {
214 : 25830 : *rcp = rc;
215 : : return 0;
216 : : }
217 : : }
218 [ + + ]: 272 : if (!allow_create)
219 : : return 0;
220 : : /* If this CA doesn't exist in the list then add it now */
221 [ + - ]: 172 : if ((rc = calloc(1, sizeof(*rc))) == NULL)
222 : : return -1;
223 [ - + ]: 172 : if ((rc->ca_key = key_from_private(ca_key)) == NULL) {
224 : 0 : free(rc);
225 : : return -1;
226 : : }
227 : 172 : RB_INIT(&rc->revoked_serials);
228 : 172 : RB_INIT(&rc->revoked_key_ids);
229 : 172 : TAILQ_INSERT_TAIL(&krl->revoked_certs, rc, entry);
230 : 172 : debug3("%s: new CA %s", __func__, key_type(ca_key));
231 : 172 : *rcp = rc;
232 : : return 0;
233 : : }
234 : :
235 : : static int
236 : 1372 : insert_serial_range(struct revoked_serial_tree *rt, u_int64_t lo, u_int64_t hi)
237 : : {
238 : 352 : struct revoked_serial rs, *ers, *crs, *irs;
239 : :
240 : : KRL_DBG(("%s: insert %llu:%llu", __func__, lo, hi));
241 : : memset(&rs, 0, sizeof(rs));
242 : 1372 : rs.lo = lo;
243 : 1372 : rs.hi = hi;
244 : 1372 : ers = RB_NFIND(revoked_serial_tree, rt, &rs);
245 [ + + ][ + + ]: 1548 : if (ers == NULL || serial_cmp(ers, &rs) != 0) {
246 : : /* No entry matches. Just insert */
247 [ + - ]: 1210 : if ((irs = malloc(sizeof(rs))) == NULL)
248 : : return -1;
249 : : memcpy(irs, &rs, sizeof(*irs));
250 : 1210 : ers = RB_INSERT(revoked_serial_tree, rt, irs);
251 [ - + ]: 1210 : if (ers != NULL) {
252 : : KRL_DBG(("%s: bad: ers != NULL", __func__));
253 : : /* Shouldn't happen */
254 : 0 : free(irs);
255 : 0 : return -1;
256 : : }
257 : : ers = irs;
258 : : } else {
259 : : KRL_DBG(("%s: overlap found %llu:%llu", __func__,
260 : : ers->lo, ers->hi));
261 : : /*
262 : : * The inserted entry overlaps an existing one. Grow the
263 : : * existing entry.
264 : : */
265 [ - + ]: 162 : if (ers->lo > lo)
266 : 0 : ers->lo = lo;
267 [ + + ]: 162 : if (ers->hi < hi)
268 : 1372 : ers->hi = hi;
269 : : }
270 : : /*
271 : : * The inserted or revised range might overlap or abut adjacent ones;
272 : : * coalesce as necessary.
273 : : */
274 : :
275 : : /* Check predecessors */
276 [ + + ]: 1505 : while ((crs = RB_PREV(revoked_serial_tree, rt, ers)) != NULL) {
277 : : KRL_DBG(("%s: pred %llu:%llu", __func__, crs->lo, crs->hi));
278 [ + - ][ + + ]: 1505 : if (ers->lo != 0 && crs->hi < ers->lo - 1)
279 : : break;
280 : : /* This entry overlaps. */
281 [ + - ]: 133 : if (crs->lo < ers->lo) {
282 : 133 : ers->lo = crs->lo;
283 : : KRL_DBG(("%s: pred extend %llu:%llu", __func__,
284 : : ers->lo, ers->hi));
285 : : }
286 : 133 : RB_REMOVE(revoked_serial_tree, rt, crs);
287 : 133 : free(crs);
288 : : }
289 : : /* Check successors */
290 [ + + ]: 1374 : while ((crs = RB_NEXT(revoked_serial_tree, rt, ers)) != NULL) {
291 : : KRL_DBG(("%s: succ %llu:%llu", __func__, crs->lo, crs->hi));
292 [ + - ][ + + ]: 163 : if (ers->hi != (u_int64_t)-1 && crs->lo > ers->hi + 1)
293 : : break;
294 : : /* This entry overlaps. */
295 [ + - ]: 2 : if (crs->hi > ers->hi) {
296 : 2 : ers->hi = crs->hi;
297 : : KRL_DBG(("%s: succ extend %llu:%llu", __func__,
298 : : ers->lo, ers->hi));
299 : : }
300 : 2 : RB_REMOVE(revoked_serial_tree, rt, crs);
301 : 2 : free(crs);
302 : : }
303 : : KRL_DBG(("%s: done, final %llu:%llu", __func__, ers->lo, ers->hi));
304 : : return 0;
305 : : }
306 : :
307 : : int
308 : 0 : ssh_krl_revoke_cert_by_serial(struct ssh_krl *krl, const Key *ca_key,
309 : : u_int64_t serial)
310 : : {
311 : 1233 : return ssh_krl_revoke_cert_by_serial_range(krl, ca_key, serial, serial);
312 : : }
313 : :
314 : : int
315 : 1372 : ssh_krl_revoke_cert_by_serial_range(struct ssh_krl *krl, const Key *ca_key,
316 : : u_int64_t lo, u_int64_t hi)
317 : : {
318 : : struct revoked_certs *rc;
319 : :
320 [ + - ]: 1372 : if (lo > hi || lo == 0)
321 : : return -1;
322 [ + - ]: 1372 : if (revoked_certs_for_ca_key(krl, ca_key, &rc, 1) != 0)
323 : : return -1;
324 : 1372 : return insert_serial_range(&rc->revoked_serials, lo, hi);
325 : : }
326 : :
327 : : int
328 : 24576 : ssh_krl_revoke_cert_by_key_id(struct ssh_krl *krl, const Key *ca_key,
329 : : const char *key_id)
330 : : {
331 : : struct revoked_key_id *rki, *erki;
332 : : struct revoked_certs *rc;
333 : :
334 [ + - ]: 24576 : if (revoked_certs_for_ca_key(krl, ca_key, &rc, 1) != 0)
335 : : return -1;
336 : :
337 : 24576 : debug3("%s: revoke %s", __func__, key_id);
338 [ + - - + ]: 49152 : if ((rki = calloc(1, sizeof(*rki))) == NULL ||
339 : 24576 : (rki->key_id = strdup(key_id)) == NULL) {
340 : 0 : free(rki);
341 : 0 : fatal("%s: strdup", __func__);
342 : : }
343 : 24576 : erki = RB_INSERT(revoked_key_id_tree, &rc->revoked_key_ids, rki);
344 [ + + ]: 24576 : if (erki != NULL) {
345 : 2560 : free(rki->key_id);
346 : 2560 : free(rki);
347 : : }
348 : : return 0;
349 : : }
350 : :
351 : : /* Convert "key" to a public key blob without any certificate information */
352 : : static int
353 : 422 : plain_key_blob(const Key *key, u_char **blob, u_int *blen)
354 : : {
355 : : Key *kcopy;
356 : : int r;
357 : :
358 [ + - ]: 422 : if ((kcopy = key_from_private(key)) == NULL)
359 : : return -1;
360 [ + + ]: 422 : if (key_is_cert(kcopy)) {
361 [ - + ]: 154 : if (key_drop_cert(kcopy) != 0) {
362 : 0 : error("%s: key_drop_cert", __func__);
363 : 0 : key_free(kcopy);
364 : 0 : return -1;
365 : : }
366 : : }
367 : 422 : r = key_to_blob(kcopy, blob, blen);
368 : 422 : free(kcopy);
369 [ + - ]: 422 : return r == 0 ? -1 : 0;
370 : : }
371 : :
372 : : /* Revoke a key blob. Ownership of blob is transferred to the tree */
373 : : static int
374 : 944 : revoke_blob(struct revoked_blob_tree *rbt, u_char *blob, u_int len)
375 : : {
376 : : struct revoked_blob *rb, *erb;
377 : :
378 [ + - ]: 944 : if ((rb = calloc(1, sizeof(*rb))) == NULL)
379 : : return -1;
380 : 944 : rb->blob = blob;
381 : 944 : rb->len = len;
382 : 944 : erb = RB_INSERT(revoked_blob_tree, rbt, rb);
383 [ + + ]: 944 : if (erb != NULL) {
384 : 95 : free(rb->blob);
385 : 95 : free(rb);
386 : : }
387 : : return 0;
388 : : }
389 : :
390 : : int
391 : 0 : ssh_krl_revoke_key_explicit(struct ssh_krl *krl, const Key *key)
392 : : {
393 : : u_char *blob;
394 : : u_int len;
395 : :
396 : 0 : debug3("%s: revoke type %s", __func__, key_type(key));
397 [ # # ]: 0 : if (plain_key_blob(key, &blob, &len) != 0)
398 : : return -1;
399 : 0 : return revoke_blob(&krl->revoked_keys, blob, len);
400 : : }
401 : :
402 : : int
403 : 165 : ssh_krl_revoke_key_sha1(struct ssh_krl *krl, const Key *key)
404 : : {
405 : : u_char *blob;
406 : : u_int len;
407 : :
408 : 165 : debug3("%s: revoke type %s by sha1", __func__, key_type(key));
409 [ + - ]: 165 : if ((blob = key_fingerprint_raw(key, SSH_FP_SHA1, &len)) == NULL)
410 : : return -1;
411 : 165 : return revoke_blob(&krl->revoked_sha1s, blob, len);
412 : : }
413 : :
414 : : int
415 : 291 : ssh_krl_revoke_key(struct ssh_krl *krl, const Key *key)
416 : : {
417 [ + + ]: 291 : if (!key_is_cert(key))
418 : 165 : return ssh_krl_revoke_key_sha1(krl, key);
419 : :
420 [ + - ][ - + ]: 126 : if (key_cert_is_legacy(key) || key->cert->serial == 0) {
421 : 0 : return ssh_krl_revoke_cert_by_key_id(krl,
422 : 0 : key->cert->signature_key,
423 : 0 : key->cert->key_id);
424 : : } else {
425 : 126 : return ssh_krl_revoke_cert_by_serial(krl,
426 : 126 : key->cert->signature_key,
427 : : key->cert->serial);
428 : : }
429 : : }
430 : :
431 : : /*
432 : : * Select a copact next section type to emit in a KRL based on the
433 : : * current section type, the run length of contiguous revoked serial
434 : : * 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
436 : : * that will minimise the size of the resultant KRL.
437 : : */
438 : : static int
439 : 175 : choose_next_state(int current_state, u_int64_t contig, int final,
440 : : u_int64_t last_gap, u_int64_t next_gap, int *force_new_section)
441 : : {
442 : : int new_state;
443 : : u_int64_t cost, cost_list, cost_range, cost_bitmap, cost_bitmap_restart;
444 : :
445 : : /*
446 : : * Avoid unsigned overflows.
447 : : * The limits are high enough to avoid confusing the calculations.
448 : : */
449 : 175 : contig = MIN(contig, 1ULL<<31);
450 : 175 : last_gap = MIN(last_gap, 1ULL<<31);
451 : 175 : next_gap = MIN(next_gap, 1ULL<<31);
452 : :
453 : : /*
454 : : * Calculate the cost to switch from the current state to candidates.
455 : : * NB. range sections only ever contain a single range, so their
456 : : * switching cost is independent of the current_state.
457 : : */
458 : 175 : cost_list = cost_bitmap = cost_bitmap_restart = 0;
459 : 175 : cost_range = 8;
460 [ + + + - ]: 175 : switch (current_state) {
461 : : case KRL_SECTION_CERT_SERIAL_LIST:
462 : 14 : cost_bitmap_restart = cost_bitmap = 8 + 64;
463 : 14 : break;
464 : : case KRL_SECTION_CERT_SERIAL_BITMAP:
465 : 133 : cost_list = 8;
466 : 133 : cost_bitmap_restart = 8 + 64;
467 : 133 : break;
468 : : case KRL_SECTION_CERT_SERIAL_RANGE:
469 : : case 0:
470 : 28 : cost_bitmap_restart = cost_bitmap = 8 + 64;
471 : 28 : cost_list = 8;
472 : : }
473 : :
474 : : /* Estimate base cost in bits of each section type */
475 [ + + ]: 175 : cost_list += 64 * contig + (final ? 0 : 8+64);
476 [ + + ]: 175 : cost_range += (2 * 64) + (final ? 0 : 8+64);
477 [ + + ]: 175 : cost_bitmap += last_gap + contig + (final ? 0 : MIN(next_gap, 8+64));
478 [ + + ]: 175 : cost_bitmap_restart += contig + (final ? 0 : MIN(next_gap, 8+64));
479 : :
480 : : /* Convert to byte costs for actual comparison */
481 : 175 : cost_list = (cost_list + 7) / 8;
482 : 175 : cost_bitmap = (cost_bitmap + 7) / 8;
483 : 175 : cost_bitmap_restart = (cost_bitmap_restart + 7) / 8;
484 : 175 : cost_range = (cost_range + 7) / 8;
485 : :
486 : : /* Now pick the best choice */
487 : 175 : *force_new_section = 0;
488 : 175 : new_state = KRL_SECTION_CERT_SERIAL_BITMAP;
489 : 175 : cost = cost_bitmap;
490 [ + + ]: 175 : if (cost_range < cost) {
491 : 56 : new_state = KRL_SECTION_CERT_SERIAL_RANGE;
492 : 56 : cost = cost_range;
493 : : }
494 [ + + ]: 175 : if (cost_list < cost) {
495 : 49 : new_state = KRL_SECTION_CERT_SERIAL_LIST;
496 : 49 : cost = cost_list;
497 : : }
498 [ + + ]: 175 : if (cost_bitmap_restart < cost) {
499 : 14 : new_state = KRL_SECTION_CERT_SERIAL_BITMAP;
500 : 14 : *force_new_section = 1;
501 : 14 : cost = cost_bitmap_restart;
502 : : }
503 [ + + ]: 175 : debug3("%s: contig %llu last_gap %llu next_gap %llu final %d, costs:"
504 : : "list %llu range %llu bitmap %llu new bitmap %llu, "
505 : : "selected 0x%02x%s", __func__, (long long unsigned)contig,
506 : : (long long unsigned)last_gap, (long long unsigned)next_gap, final,
507 : : (long long unsigned)cost_list, (long long unsigned)cost_range,
508 : : (long long unsigned)cost_bitmap,
509 : : (long long unsigned)cost_bitmap_restart, new_state,
510 : 175 : *force_new_section ? " restart" : "");
511 : 175 : return new_state;
512 : : }
513 : :
514 : : /* Generate a KRL_SECTION_CERTIFICATES KRL section */
515 : : static int
516 : 28 : revoked_certs_generate(struct revoked_certs *rc, Buffer *buf)
517 : : {
518 : 28 : int final, force_new_sect, r = -1;
519 : 28 : u_int64_t i, contig, gap, last = 0, bitmap_start = 0;
520 : : struct revoked_serial *rs, *nrs;
521 : : struct revoked_key_id *rki;
522 : 28 : int next_state, state = 0;
523 : : Buffer sect;
524 : 28 : u_char *kblob = NULL;
525 : : u_int klen;
526 : 28 : BIGNUM *bitmap = NULL;
527 : :
528 : : /* Prepare CA scope key blob if we have one supplied */
529 [ + - ]: 28 : if (key_to_blob(rc->ca_key, &kblob, &klen) == 0)
530 : : return -1;
531 : :
532 : 28 : buffer_init(§);
533 : :
534 : : /* Store the header */
535 : 28 : buffer_put_string(buf, kblob, klen);
536 : 28 : buffer_put_string(buf, NULL, 0); /* Reserved */
537 : :
538 : 28 : free(kblob);
539 : :
540 : : /* Store the revoked serials. */
541 [ + + ]: 203 : for (rs = RB_MIN(revoked_serial_tree, &rc->revoked_serials);
542 : : rs != NULL;
543 : 175 : rs = RB_NEXT(revoked_serial_tree, &rc->revoked_serials, rs)) {
544 : 175 : debug3("%s: serial %llu:%llu state 0x%02x", __func__,
545 : 175 : (long long unsigned)rs->lo, (long long unsigned)rs->hi,
546 : : state);
547 : :
548 : : /* Check contiguous length and gap to next section (if any) */
549 : 175 : nrs = RB_NEXT(revoked_serial_tree, &rc->revoked_serials, rs);
550 : 175 : final = nrs == NULL;
551 [ + + ]: 175 : gap = nrs == NULL ? 0 : nrs->lo - rs->hi;
552 : 175 : contig = 1 + (rs->hi - rs->lo);
553 : :
554 : : /* Choose next state based on these */
555 [ + + ]: 175 : next_state = choose_next_state(state, contig, final,
556 : : state == 0 ? 0 : rs->lo - last, gap, &force_new_sect);
557 : :
558 : : /*
559 : : * If the current section is a range section or has a different
560 : : * type to the next section, then finish it off now.
561 : : */
562 [ + + ][ + + ]: 175 : if (state != 0 && (force_new_sect || next_state != state ||
[ + + ]
563 : 140 : state == KRL_SECTION_CERT_SERIAL_RANGE)) {
564 : 42 : debug3("%s: finish state 0x%02x", __func__, state);
565 [ + + ]: 42 : switch (state) {
566 : : case KRL_SECTION_CERT_SERIAL_LIST:
567 : : case KRL_SECTION_CERT_SERIAL_RANGE:
568 : : break;
569 : : case KRL_SECTION_CERT_SERIAL_BITMAP:
570 : 35 : buffer_put_bignum2(§, bitmap);
571 : 35 : BN_free(bitmap);
572 : 35 : bitmap = NULL;
573 : 35 : break;
574 : : }
575 : 42 : buffer_put_char(buf, state);
576 : 84 : buffer_put_string(buf,
577 : 42 : buffer_ptr(§), buffer_len(§));
578 : : }
579 : :
580 : : /* If we are starting a new section then prepare it now */
581 [ + + ][ + + ]: 175 : if (next_state != state || force_new_sect) {
582 : 63 : debug3("%s: start state 0x%02x", __func__, next_state);
583 : 63 : state = next_state;
584 : 63 : buffer_clear(§);
585 [ + + ]: 63 : switch (state) {
586 : : case KRL_SECTION_CERT_SERIAL_LIST:
587 : : case KRL_SECTION_CERT_SERIAL_RANGE:
588 : : break;
589 : : case KRL_SECTION_CERT_SERIAL_BITMAP:
590 [ + - ]: 35 : if ((bitmap = BN_new()) == NULL)
591 : : goto out;
592 : 35 : bitmap_start = rs->lo;
593 : 35 : buffer_put_int64(§, bitmap_start);
594 : 35 : break;
595 : : }
596 : : }
597 : :
598 : : /* Perform section-specific processing */
599 [ + + + - ]: 175 : switch (state) {
600 : : case KRL_SECTION_CERT_SERIAL_LIST:
601 [ + + ]: 70 : for (i = 0; i < contig; i++)
602 : 35 : buffer_put_int64(§, rs->lo + i);
603 : : break;
604 : : case KRL_SECTION_CERT_SERIAL_RANGE:
605 : 7 : buffer_put_int64(§, rs->lo);
606 : 7 : buffer_put_int64(§, rs->hi);
607 : 7 : break;
608 : : case KRL_SECTION_CERT_SERIAL_BITMAP:
609 [ + - ]: 133 : if (rs->lo - bitmap_start > INT_MAX) {
610 : 0 : error("%s: insane bitmap gap", __func__);
611 : 0 : goto out;
612 : : }
613 [ + + ]: 287 : for (i = 0; i < contig; i++) {
614 [ + - ]: 154 : if (BN_set_bit(bitmap,
615 : 154 : rs->lo + i - bitmap_start) != 1)
616 : : goto out;
617 : : }
618 : : break;
619 : : }
620 : 175 : last = rs->hi;
621 : : }
622 : : /* Flush the remaining section, if any */
623 [ + + ]: 28 : if (state != 0) {
624 : 21 : debug3("%s: serial final flush for state 0x%02x",
625 : : __func__, state);
626 [ - + ]: 21 : switch (state) {
627 : : case KRL_SECTION_CERT_SERIAL_LIST:
628 : : case KRL_SECTION_CERT_SERIAL_RANGE:
629 : : break;
630 : : case KRL_SECTION_CERT_SERIAL_BITMAP:
631 : 0 : buffer_put_bignum2(§, bitmap);
632 : 0 : BN_free(bitmap);
633 : 0 : bitmap = NULL;
634 : 0 : break;
635 : : }
636 : 21 : buffer_put_char(buf, state);
637 : 42 : buffer_put_string(buf,
638 : 21 : buffer_ptr(§), buffer_len(§));
639 : : }
640 : 28 : debug3("%s: serial done ", __func__);
641 : :
642 : : /* Now output a section for any revocations by key ID */
643 : 28 : buffer_clear(§);
644 [ + + ]: 3612 : RB_FOREACH(rki, revoked_key_id_tree, &rc->revoked_key_ids) {
645 : 3584 : debug3("%s: key ID %s", __func__, rki->key_id);
646 : 3584 : buffer_put_cstring(§, rki->key_id);
647 : : }
648 [ + + ]: 28 : if (buffer_len(§) != 0) {
649 : 7 : buffer_put_char(buf, KRL_SECTION_CERT_KEY_ID);
650 : 7 : buffer_put_string(buf, buffer_ptr(§),
651 : : buffer_len(§));
652 : : }
653 : : r = 0;
654 : : out:
655 [ - + ]: 28 : if (bitmap != NULL)
656 : 0 : BN_free(bitmap);
657 : 28 : buffer_free(§);
658 : 28 : return r;
659 : : }
660 : :
661 : : int
662 : 113 : ssh_krl_to_blob(struct ssh_krl *krl, Buffer *buf, const Key **sign_keys,
663 : : u_int nsign_keys)
664 : : {
665 : 113 : int r = -1;
666 : : struct revoked_certs *rc;
667 : : struct revoked_blob *rb;
668 : : Buffer sect;
669 : 113 : u_char *kblob = NULL, *sblob = NULL;
670 : : u_int klen, slen, i;
671 : :
672 [ + + ]: 113 : if (krl->generated_date == 0)
673 : 71 : krl->generated_date = time(NULL);
674 : :
675 : 113 : buffer_init(§);
676 : :
677 : : /* Store the header */
678 : 113 : buffer_append(buf, KRL_MAGIC, sizeof(KRL_MAGIC) - 1);
679 : 113 : buffer_put_int(buf, KRL_FORMAT_VERSION);
680 : 113 : buffer_put_int64(buf, krl->krl_version);
681 : 113 : buffer_put_int64(buf, krl->generated_date);
682 : 113 : buffer_put_int64(buf, krl->flags);
683 : 113 : buffer_put_string(buf, NULL, 0);
684 [ + + ]: 113 : buffer_put_cstring(buf, krl->comment ? krl->comment : "");
685 : :
686 : : /* Store sections for revoked certificates */
687 [ + + ]: 141 : TAILQ_FOREACH(rc, &krl->revoked_certs, entry) {
688 [ + - ]: 28 : if (revoked_certs_generate(rc, §) != 0)
689 : : goto out;
690 : 28 : buffer_put_char(buf, KRL_SECTION_CERTIFICATES);
691 : 28 : buffer_put_string(buf, buffer_ptr(§),
692 : : buffer_len(§));
693 : : }
694 : :
695 : : /* Finally, output sections for revocations by public key/hash */
696 : 113 : buffer_clear(§);
697 [ - + ]: 113 : RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_keys) {
698 : 0 : debug3("%s: key len %u ", __func__, rb->len);
699 : 0 : buffer_put_string(§, rb->blob, rb->len);
700 : : }
701 [ - + ]: 113 : if (buffer_len(§) != 0) {
702 : 0 : buffer_put_char(buf, KRL_SECTION_EXPLICIT_KEY);
703 : 0 : buffer_put_string(buf, buffer_ptr(§),
704 : : buffer_len(§));
705 : : }
706 : 113 : buffer_clear(§);
707 [ + + ]: 278 : RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_sha1s) {
708 : 165 : debug3("%s: hash len %u ", __func__, rb->len);
709 : 165 : buffer_put_string(§, rb->blob, rb->len);
710 : : }
711 [ + + ]: 113 : if (buffer_len(§) != 0) {
712 : 53 : buffer_put_char(buf, KRL_SECTION_FINGERPRINT_SHA1);
713 : 113 : buffer_put_string(buf, buffer_ptr(§),
714 : : buffer_len(§));
715 : : }
716 : :
717 [ - + ]: 113 : for (i = 0; i < nsign_keys; i++) {
718 [ # # ]: 0 : if (key_to_blob(sign_keys[i], &kblob, &klen) == 0)
719 : : goto out;
720 : :
721 : 0 : debug3("%s: signature key len %u", __func__, klen);
722 : 0 : buffer_put_char(buf, KRL_SECTION_SIGNATURE);
723 : 0 : buffer_put_string(buf, kblob, klen);
724 : :
725 [ # # ]: 0 : if (key_sign(sign_keys[i], &sblob, &slen,
726 : 0 : buffer_ptr(buf), buffer_len(buf)) == -1)
727 : : goto out;
728 : 0 : debug3("%s: signature sig len %u", __func__, slen);
729 : 0 : buffer_put_string(buf, sblob, slen);
730 : : }
731 : :
732 : : r = 0;
733 : : out:
734 : 113 : free(kblob);
735 : 113 : free(sblob);
736 : 113 : buffer_free(§);
737 : 113 : return r;
738 : : }
739 : :
740 : : static void
741 : 454 : format_timestamp(u_int64_t timestamp, char *ts, size_t nts)
742 : : {
743 : : time_t t;
744 : : struct tm *tm;
745 : :
746 : 454 : t = timestamp;
747 : 454 : tm = localtime(&t);
748 : 454 : *ts = '\0';
749 : 454 : strftime(ts, nts, "%Y%m%dT%H%M%S", tm);
750 : 454 : }
751 : :
752 : : static int
753 : 164 : parse_revoked_certs(Buffer *buf, struct ssh_krl *krl)
754 : : {
755 : 164 : int ret = -1, nbits;
756 : : u_char type, *blob;
757 : : u_int blen;
758 : : Buffer subsect;
759 : : u_int64_t serial, serial_lo, serial_hi;
760 : 164 : BIGNUM *bitmap = NULL;
761 : 164 : char *key_id = NULL;
762 : 164 : Key *ca_key = NULL;
763 : :
764 : 164 : buffer_init(&subsect);
765 : :
766 [ + - - + ]: 328 : if ((blob = buffer_get_string_ptr_ret(buf, &blen)) == NULL ||
767 : 164 : buffer_get_string_ptr_ret(buf, NULL) == NULL) { /* reserved */
768 : 0 : error("%s: buffer error", __func__);
769 : 0 : goto out;
770 : : }
771 [ + - ]: 164 : if ((ca_key = key_from_blob(blob, blen)) == NULL)
772 : : goto out;
773 : :
774 [ + + ]: 574 : while (buffer_len(buf) > 0) {
775 [ + - ][ - + ]: 410 : if (buffer_get_char_ret(&type, buf) != 0 ||
776 : : (blob = buffer_get_string_ptr_ret(buf, &blen)) == NULL) {
777 : 0 : error("%s: buffer error", __func__);
778 : 0 : goto out;
779 : : }
780 : 410 : buffer_clear(&subsect);
781 : 410 : buffer_append(&subsect, blob, blen);
782 : 410 : debug3("%s: subsection type 0x%02x", __func__, type);
783 : : /* buffer_dump(&subsect); */
784 : :
785 [ + + + + : 410 : switch (type) {
- ]
786 : : case KRL_SECTION_CERT_SERIAL_LIST:
787 [ + + ]: 328 : while (buffer_len(&subsect) > 0) {
788 [ - + ]: 205 : if (buffer_get_int64_ret(&serial,
789 : : &subsect) != 0) {
790 : 0 : error("%s: buffer error", __func__);
791 : 0 : goto out;
792 : : }
793 [ + - ]: 205 : if (ssh_krl_revoke_cert_by_serial(krl, ca_key,
794 : : serial) != 0) {
795 : 0 : error("%s: update failed", __func__);
796 : 123 : goto out;
797 : : }
798 : : }
799 : : break;
800 : : case KRL_SECTION_CERT_SERIAL_RANGE:
801 [ + - - + ]: 82 : if (buffer_get_int64_ret(&serial_lo, &subsect) != 0 ||
802 : 41 : buffer_get_int64_ret(&serial_hi, &subsect) != 0) {
803 : 0 : error("%s: buffer error", __func__);
804 : 0 : goto out;
805 : : }
806 [ - + ]: 41 : if (ssh_krl_revoke_cert_by_serial_range(krl, ca_key,
807 : : serial_lo, serial_hi) != 0) {
808 : 0 : error("%s: update failed", __func__);
809 : 0 : goto out;
810 : : }
811 : : break;
812 : : case KRL_SECTION_CERT_SERIAL_BITMAP:
813 [ - + ]: 205 : if ((bitmap = BN_new()) == NULL) {
814 : 0 : error("%s: BN_new", __func__);
815 : 0 : goto out;
816 : : }
817 [ + - - + ]: 410 : if (buffer_get_int64_ret(&serial_lo, &subsect) != 0 ||
818 : 205 : buffer_get_bignum2_ret(&subsect, bitmap) != 0) {
819 : 0 : error("%s: buffer error", __func__);
820 : 0 : goto out;
821 : : }
822 [ - + ]: 205 : if ((nbits = BN_num_bits(bitmap)) < 0) {
823 : 0 : error("%s: bitmap bits < 0", __func__);
824 : 0 : goto out;
825 : : }
826 [ + + ]: 8077 : for (serial = 0; serial < (u_int)nbits; serial++) {
827 [ + + ][ - + ]: 7872 : if (serial > 0 && serial_lo + serial == 0) {
828 : 0 : error("%s: bitmap wraps u64", __func__);
829 : 0 : goto out;
830 : : }
831 [ + + ]: 7872 : if (!BN_is_bit_set(bitmap, serial))
832 : 6970 : continue;
833 [ - + ]: 902 : if (ssh_krl_revoke_cert_by_serial(krl, ca_key,
834 : : serial_lo + serial) != 0) {
835 : 0 : error("%s: update failed", __func__);
836 : 0 : goto out;
837 : : }
838 : : }
839 : 205 : BN_free(bitmap);
840 : 205 : bitmap = NULL;
841 : 205 : break;
842 : : case KRL_SECTION_CERT_KEY_ID:
843 [ + + ]: 21033 : while (buffer_len(&subsect) > 0) {
844 [ - + ]: 20992 : if ((key_id = buffer_get_cstring_ret(&subsect,
845 : : NULL)) == NULL) {
846 : 0 : error("%s: buffer error", __func__);
847 : 0 : goto out;
848 : : }
849 [ - + ]: 20992 : if (ssh_krl_revoke_cert_by_key_id(krl, ca_key,
850 : : key_id) != 0) {
851 : 0 : error("%s: update failed", __func__);
852 : 0 : goto out;
853 : : }
854 : 20992 : free(key_id);
855 : 20992 : key_id = NULL;
856 : : }
857 : : break;
858 : : default:
859 : 0 : error("Unsupported KRL certificate section %u", type);
860 : 0 : goto out;
861 : : }
862 [ + - ]: 410 : if (buffer_len(&subsect) > 0) {
863 : 0 : error("KRL certificate section contains unparsed data");
864 : 164 : goto out;
865 : : }
866 : : }
867 : :
868 : : ret = 0;
869 : : out:
870 [ + - ]: 164 : if (ca_key != NULL)
871 : 164 : key_free(ca_key);
872 [ - + ]: 164 : if (bitmap != NULL)
873 : 0 : BN_free(bitmap);
874 : 164 : free(key_id);
875 : 164 : buffer_free(&subsect);
876 : 164 : return ret;
877 : : }
878 : :
879 : :
880 : : /* Attempt to parse a KRL, checking its signature (if any) with sign_ca_keys. */
881 : : int
882 : 454 : ssh_krl_from_blob(Buffer *buf, struct ssh_krl **krlp,
883 : : const Key **sign_ca_keys, u_int nsign_ca_keys)
884 : : {
885 : : Buffer copy, sect;
886 : : struct ssh_krl *krl;
887 : : char timestamp[64];
888 : 454 : int ret = -1, r, sig_seen;
889 : 454 : Key *key = NULL, **ca_used = NULL;
890 : 454 : u_char type, *blob, *rdata = NULL;
891 : : u_int i, j, sig_off, sects_off, rlen, blen, format_version, nca_used;
892 : :
893 : 454 : nca_used = 0;
894 : 454 : *krlp = NULL;
895 [ + - - + ]: 908 : if (buffer_len(buf) < sizeof(KRL_MAGIC) - 1 ||
896 : 454 : memcmp(buffer_ptr(buf), KRL_MAGIC, sizeof(KRL_MAGIC) - 1) != 0) {
897 : 0 : debug3("%s: not a KRL", __func__);
898 : : /*
899 : : * Return success but a NULL *krlp here to signal that the
900 : : * file might be a simple list of keys.
901 : : */
902 : 0 : return 0;
903 : : }
904 : :
905 : : /* Take a copy of the KRL buffer so we can verify its signature later */
906 : 454 : buffer_init(©);
907 : 454 : buffer_append(©, buffer_ptr(buf), buffer_len(buf));
908 : :
909 : 454 : buffer_init(§);
910 : 454 : buffer_consume(©, sizeof(KRL_MAGIC) - 1);
911 : :
912 [ - + ]: 454 : if ((krl = ssh_krl_init()) == NULL) {
913 : 0 : error("%s: alloc failed", __func__);
914 : 0 : goto out;
915 : : }
916 : :
917 [ - + ]: 454 : if (buffer_get_int_ret(&format_version, ©) != 0) {
918 : 0 : error("%s: KRL truncated", __func__);
919 : 0 : goto out;
920 : : }
921 [ - + ]: 454 : if (format_version != KRL_FORMAT_VERSION) {
922 : 0 : error("%s: KRL unsupported format version %u",
923 : : __func__, format_version);
924 : 0 : goto out;
925 : : }
926 [ + - + - ]: 908 : if (buffer_get_int64_ret(&krl->krl_version, ©) != 0 ||
927 [ + - ]: 908 : buffer_get_int64_ret(&krl->generated_date, ©) != 0 ||
928 [ + - ]: 908 : buffer_get_int64_ret(&krl->flags, ©) != 0 ||
929 [ - + ]: 908 : buffer_get_string_ptr_ret(©, NULL) == NULL || /* reserved */
930 : 454 : (krl->comment = buffer_get_cstring_ret(©, NULL)) == NULL) {
931 : 0 : error("%s: buffer error", __func__);
932 : 0 : goto out;
933 : : }
934 : :
935 : 454 : format_timestamp(krl->generated_date, timestamp, sizeof(timestamp));
936 [ + - ]: 454 : debug("KRL version %llu generated at %s%s%s",
937 : 454 : (long long unsigned)krl->krl_version, timestamp,
938 : 454 : *krl->comment ? ": " : "", krl->comment);
939 : :
940 : : /*
941 : : * 1st pass: verify signatures, if any. This is done to avoid
942 : : * detailed parsing of data whose provenance is unverified.
943 : : */
944 : 454 : sig_seen = 0;
945 : 454 : sects_off = buffer_len(buf) - buffer_len(©);
946 [ + + ]: 741 : while (buffer_len(©) > 0) {
947 [ + - ][ - + ]: 287 : if (buffer_get_char_ret(&type, ©) != 0 ||
948 : : (blob = buffer_get_string_ptr_ret(©, &blen)) == NULL) {
949 : 0 : error("%s: buffer error", __func__);
950 : 0 : goto out;
951 : : }
952 : 287 : debug3("%s: first pass, section 0x%02x", __func__, type);
953 [ + - ]: 287 : if (type != KRL_SECTION_SIGNATURE) {
954 : : if (sig_seen) {
955 : : error("KRL contains non-signature section "
956 : : "after signature");
957 : : goto out;
958 : : }
959 : : /* Not interested for now. */
960 : 287 : continue;
961 : : }
962 : 0 : sig_seen = 1;
963 : : /* First string component is the signing key */
964 [ # # ]: 0 : if ((key = key_from_blob(blob, blen)) == NULL) {
965 : 0 : error("%s: invalid signature key", __func__);
966 : 0 : goto out;
967 : : }
968 : 0 : sig_off = buffer_len(buf) - buffer_len(©);
969 : : /* Second string component is the signature itself */
970 [ # # ]: 0 : if ((blob = buffer_get_string_ptr_ret(©, &blen)) == NULL) {
971 : 0 : error("%s: buffer error", __func__);
972 : 0 : goto out;
973 : : }
974 : : /* Check signature over entire KRL up to this point */
975 [ # # ]: 0 : if (key_verify(key, blob, blen,
976 : 0 : buffer_ptr(buf), buffer_len(buf) - sig_off) != 1) {
977 : 0 : error("bad signaure on KRL");
978 : 0 : goto out;
979 : : }
980 : : /* Check if this key has already signed this KRL */
981 : : for (i = 0; i < nca_used; i++) {
982 : : if (key_equal(ca_used[i], key)) {
983 : : error("KRL signed more than once with "
984 : : "the same key");
985 : : goto out;
986 : : }
987 : : }
988 : : /* Record keys used to sign the KRL */
989 : 0 : ca_used = xrealloc(ca_used, nca_used + 1, sizeof(*ca_used));
990 : 0 : ca_used[nca_used++] = key;
991 : 0 : key = NULL;
992 : 0 : break;
993 : : }
994 : :
995 : : /*
996 : : * 2nd pass: parse and load the KRL, skipping the header to the point
997 : : * where the section start.
998 : : */
999 : 454 : buffer_append(©, (u_char*)buffer_ptr(buf) + sects_off,
1000 : 454 : buffer_len(buf) - sects_off);
1001 [ + + ]: 741 : while (buffer_len(©) > 0) {
1002 [ + - ][ - + ]: 287 : if (buffer_get_char_ret(&type, ©) != 0 ||
1003 : : (blob = buffer_get_string_ptr_ret(©, &blen)) == NULL) {
1004 : 0 : error("%s: buffer error", __func__);
1005 : 0 : goto out;
1006 : : }
1007 : 287 : debug3("%s: second pass, section 0x%02x", __func__, type);
1008 : 287 : buffer_clear(§);
1009 : 287 : buffer_append(§, blob, blen);
1010 : :
1011 [ + + - - ]: 287 : switch (type) {
1012 : : case KRL_SECTION_CERTIFICATES:
1013 [ + - ]: 164 : if ((r = parse_revoked_certs(§, krl)) != 0)
1014 : : goto out;
1015 : : break;
1016 : : case KRL_SECTION_EXPLICIT_KEY:
1017 : : case KRL_SECTION_FINGERPRINT_SHA1:
1018 [ + + ]: 902 : while (buffer_len(§) > 0) {
1019 [ - + ]: 779 : if ((rdata = buffer_get_string_ret(§,
1020 : : &rlen)) == NULL) {
1021 : 0 : error("%s: buffer error", __func__);
1022 : 0 : goto out;
1023 : : }
1024 [ + - ][ - + ]: 779 : if (type == KRL_SECTION_FINGERPRINT_SHA1 &&
1025 : 779 : rlen != 20) {
1026 : 0 : error("%s: bad SHA1 length", __func__);
1027 : 0 : goto out;
1028 : : }
1029 [ - + ][ + - ]: 902 : if (revoke_blob(
1030 : : type == KRL_SECTION_EXPLICIT_KEY ?
1031 : : &krl->revoked_keys : &krl->revoked_sha1s,
1032 : : rdata, rlen) != 0)
1033 : : goto out;
1034 : : rdata = NULL; /* revoke_blob frees blob */
1035 : : }
1036 : : break;
1037 : : case KRL_SECTION_SIGNATURE:
1038 : : /* Handled above, but still need to stay in synch */
1039 : 0 : buffer_clear(§);
1040 [ # # ]: 0 : if ((blob = buffer_get_string_ptr_ret(©,
1041 : : &blen)) == NULL) {
1042 : 0 : error("%s: buffer error", __func__);
1043 : 0 : goto out;
1044 : : }
1045 : : break;
1046 : : default:
1047 : 0 : error("Unsupported KRL section %u", type);
1048 : 0 : goto out;
1049 : : }
1050 [ - + ]: 287 : if (buffer_len(§) > 0) {
1051 : 0 : error("KRL section contains unparsed data");
1052 : 0 : goto out;
1053 : : }
1054 : : }
1055 : :
1056 : : /* Check that the key(s) used to sign the KRL weren't revoked */
1057 : : sig_seen = 0;
1058 [ - + ]: 454 : for (i = 0; i < nca_used; i++) {
1059 [ # # ]: 0 : if (ssh_krl_check_key(krl, ca_used[i]) == 0)
1060 : : sig_seen = 1;
1061 : : else {
1062 : 0 : key_free(ca_used[i]);
1063 : 0 : ca_used[i] = NULL;
1064 : : }
1065 : : }
1066 [ - + ]: 454 : if (nca_used && !sig_seen) {
1067 : 0 : error("All keys used to sign KRL were revoked");
1068 : 0 : goto out;
1069 : : }
1070 : :
1071 : : /* If we have CA keys, then verify that one was used to sign the KRL */
1072 [ - + ]: 454 : if (sig_seen && nsign_ca_keys != 0) {
1073 : : sig_seen = 0;
1074 [ # # ]: 0 : for (i = 0; !sig_seen && i < nsign_ca_keys; i++) {
1075 [ # # ]: 0 : for (j = 0; j < nca_used; j++) {
1076 [ # # ]: 0 : if (ca_used[j] == NULL)
1077 : 0 : continue;
1078 [ # # ]: 0 : if (key_equal(ca_used[j], sign_ca_keys[i])) {
1079 : : sig_seen = 1;
1080 : : break;
1081 : : }
1082 : : }
1083 : : }
1084 [ # # ]: 0 : if (!sig_seen) {
1085 : 0 : error("KRL not signed with any trusted key");
1086 : 0 : goto out;
1087 : : }
1088 : : }
1089 : :
1090 : 454 : *krlp = krl;
1091 : 454 : ret = 0;
1092 : : out:
1093 [ - + ]: 454 : if (ret != 0)
1094 : 454 : ssh_krl_free(krl);
1095 [ - + ]: 454 : for (i = 0; i < nca_used; i++) {
1096 [ # # ]: 0 : if (ca_used[i] != NULL)
1097 : 0 : key_free(ca_used[i]);
1098 : : }
1099 : 454 : free(ca_used);
1100 : 454 : free(rdata);
1101 [ - + ]: 454 : if (key != NULL)
1102 : 0 : key_free(key);
1103 : 454 : buffer_free(©);
1104 : 454 : buffer_free(§);
1105 : 454 : return ret;
1106 : : }
1107 : :
1108 : : /* Checks whether a given key/cert is revoked. Does not check its CA */
1109 : : static int
1110 : 512 : is_key_revoked(struct ssh_krl *krl, const Key *key)
1111 : : {
1112 : : struct revoked_blob rb, *erb;
1113 : : struct revoked_serial rs, *ers;
1114 : : struct revoked_key_id rki, *erki;
1115 : : struct revoked_certs *rc;
1116 : :
1117 : : /* Check explicitly revoked hashes first */
1118 : : memset(&rb, 0, sizeof(rb));
1119 [ + - ]: 512 : if ((rb.blob = key_fingerprint_raw(key, SSH_FP_SHA1, &rb.len)) == NULL)
1120 : : return -1;
1121 : 512 : erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha1s, &rb);
1122 : 512 : free(rb.blob);
1123 [ + + ]: 512 : if (erb != NULL) {
1124 : 90 : debug("%s: revoked by key SHA1", __func__);
1125 : 90 : return -1;
1126 : : }
1127 : :
1128 : : /* Next, explicit keys */
1129 : : memset(&rb, 0, sizeof(rb));
1130 [ + - ]: 422 : if (plain_key_blob(key, &rb.blob, &rb.len) != 0)
1131 : : return -1;
1132 : 422 : erb = RB_FIND(revoked_blob_tree, &krl->revoked_keys, &rb);
1133 : 422 : free(rb.blob);
1134 [ - + ]: 422 : if (erb != NULL) {
1135 : 0 : debug("%s: revoked by explicit key", __func__);
1136 : 0 : return -1;
1137 : : }
1138 : :
1139 [ + + ]: 422 : if (!key_is_cert(key))
1140 : : return 0;
1141 : :
1142 : : /* Check cert revocation */
1143 [ + - ]: 154 : if (revoked_certs_for_ca_key(krl, key->cert->signature_key,
1144 : : &rc, 0) != 0)
1145 : : return -1;
1146 [ + + ]: 154 : if (rc == NULL)
1147 : : return 0; /* No entry for this CA */
1148 : :
1149 : : /* Check revocation by cert key ID */
1150 : : memset(&rki, 0, sizeof(rki));
1151 : 54 : rki.key_id = key->cert->key_id;
1152 : 54 : erki = RB_FIND(revoked_key_id_tree, &rc->revoked_key_ids, &rki);
1153 [ + + ]: 54 : if (erki != NULL) {
1154 : 18 : debug("%s: revoked by key ID", __func__);
1155 : 18 : return -1;
1156 : : }
1157 : :
1158 : : /*
1159 : : * Legacy cert formats lack serial numbers. Zero serials numbers
1160 : : * are ignored (it's the default when the CA doesn't specify one).
1161 : : */
1162 [ + - ][ + - ]: 36 : if (key_cert_is_legacy(key) || key->cert->serial == 0)
1163 : : return 0;
1164 : :
1165 : : memset(&rs, 0, sizeof(rs));
1166 : 36 : rs.lo = rs.hi = key->cert->serial;
1167 : 36 : ers = RB_FIND(revoked_serial_tree, &rc->revoked_serials, &rs);
1168 [ + - ]: 36 : if (ers != NULL) {
1169 : : KRL_DBG(("%s: %llu matched %llu:%llu", __func__,
1170 : : key->cert->serial, ers->lo, ers->hi));
1171 : 36 : debug("%s: revoked by serial", __func__);
1172 : 36 : return -1;
1173 : : }
1174 : : KRL_DBG(("%s: %llu no match", __func__, key->cert->serial));
1175 : :
1176 : : return 0;
1177 : : }
1178 : :
1179 : : int
1180 : 412 : ssh_krl_check_key(struct ssh_krl *krl, const Key *key)
1181 : : {
1182 : : int r;
1183 : :
1184 : 412 : debug2("%s: checking key", __func__);
1185 [ + + ]: 412 : if ((r = is_key_revoked(krl, key)) != 0)
1186 : : return r;
1187 [ + + ]: 286 : if (key_is_cert(key)) {
1188 : 100 : debug2("%s: checking CA key", __func__);
1189 [ + + ]: 100 : if ((r = is_key_revoked(krl, key->cert->signature_key)) != 0)
1190 : : return r;
1191 : : }
1192 : 268 : debug3("%s: key okay", __func__);
1193 : 268 : return 0;
1194 : : }
1195 : :
1196 : : /* Returns 0 on success, -1 on error or key revoked, -2 if path is not a KRL */
1197 : : int
1198 : 160 : ssh_krl_file_contains_key(const char *path, const Key *key)
1199 : : {
1200 : : Buffer krlbuf;
1201 : : struct ssh_krl *krl;
1202 : : int revoked, fd;
1203 : :
1204 [ + - ]: 160 : if (path == NULL)
1205 : : return 0;
1206 : :
1207 [ - + ]: 160 : if ((fd = open(path, O_RDONLY)) == -1) {
1208 : 0 : error("open %s: %s", path, strerror(errno));
1209 : 0 : error("Revoked keys file not accessible - refusing public key "
1210 : : "authentication");
1211 : 0 : return -1;
1212 : : }
1213 : 160 : buffer_init(&krlbuf);
1214 [ - + ]: 160 : if (!key_load_file(fd, path, &krlbuf)) {
1215 : 0 : close(fd);
1216 : 0 : buffer_free(&krlbuf);
1217 : 0 : error("Revoked keys file not readable - refusing public key "
1218 : : "authentication");
1219 : 0 : return -1;
1220 : : }
1221 : 160 : close(fd);
1222 [ - + ]: 160 : if (ssh_krl_from_blob(&krlbuf, &krl, NULL, 0) != 0) {
1223 : 0 : buffer_free(&krlbuf);
1224 : 0 : error("Invalid KRL, refusing public key "
1225 : : "authentication");
1226 : 0 : return -1;
1227 : : }
1228 : 160 : buffer_free(&krlbuf);
1229 [ - + ]: 160 : if (krl == NULL) {
1230 : 0 : debug3("%s: %s is not a KRL file", __func__, path);
1231 : 0 : return -2;
1232 : : }
1233 : 160 : debug2("%s: checking KRL %s", __func__, path);
1234 : 160 : revoked = ssh_krl_check_key(krl, key) != 0;
1235 : 160 : ssh_krl_free(krl);
1236 [ + - ]: 160 : return revoked ? -1 : 0;
1237 : : }
|