upstream commit

permit KRLs that revoke certificates by serial number or
 key ID without scoping to a particular CA; ok markus@
This commit is contained in:
djm@openbsd.org 2015-01-30 01:10:33 +00:00 committed by Damien Miller
parent 7a2c368477
commit 669aee9943
3 changed files with 86 additions and 51 deletions

View File

@ -37,7 +37,7 @@ The available section types are:
#define KRL_SECTION_FINGERPRINT_SHA1 3 #define KRL_SECTION_FINGERPRINT_SHA1 3
#define KRL_SECTION_SIGNATURE 4 #define KRL_SECTION_SIGNATURE 4
3. Certificate serial section 2. Certificate section
These sections use type KRL_SECTION_CERTIFICATES to revoke certificates by These sections use type KRL_SECTION_CERTIFICATES to revoke certificates by
serial number or key ID. The consist of the CA key that issued the serial number or key ID. The consist of the CA key that issued the
@ -47,6 +47,11 @@ ignored.
string ca_key string ca_key
string reserved string reserved
Where "ca_key" is the standard SSH wire serialisation of the CA's
public key. Alternately, "ca_key" may be an empty string to indicate
the certificate section applies to all CAs (this is most useful when
revoking key IDs).
Followed by one or more sections: Followed by one or more sections:
byte cert_section_type byte cert_section_type
@ -161,4 +166,4 @@ Implementations that retrieve KRLs over untrusted channels must verify
signatures. Signature sections are optional for KRLs distributed by signatures. Signature sections are optional for KRLs distributed by
trusted means. trusted means.
$OpenBSD: PROTOCOL.krl,v 1.2 2013/01/18 00:24:58 djm Exp $ $OpenBSD: PROTOCOL.krl,v 1.3 2015/01/30 01:10:33 djm Exp $

102
krl.c
View File

@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
/* $OpenBSD: krl.c,v 1.30 2015/01/26 02:59:11 djm Exp $ */ /* $OpenBSD: krl.c,v 1.31 2015/01/30 01:10:33 djm Exp $ */
#include "includes.h" #include "includes.h"
@ -156,8 +156,7 @@ revoked_certs_free(struct revoked_certs *rc)
free(rki->key_id); free(rki->key_id);
free(rki); free(rki);
} }
if (rc->ca_key != NULL) sshkey_free(rc->ca_key);
sshkey_free(rc->ca_key);
} }
void void
@ -214,7 +213,8 @@ revoked_certs_for_ca_key(struct ssh_krl *krl, const struct sshkey *ca_key,
*rcp = NULL; *rcp = NULL;
TAILQ_FOREACH(rc, &krl->revoked_certs, entry) { TAILQ_FOREACH(rc, &krl->revoked_certs, entry) {
if (sshkey_equal(rc->ca_key, ca_key)) { if ((ca_key == NULL && rc->ca_key == NULL) ||
sshkey_equal(rc->ca_key, ca_key)) {
*rcp = rc; *rcp = rc;
return 0; return 0;
} }
@ -224,14 +224,17 @@ revoked_certs_for_ca_key(struct ssh_krl *krl, const struct sshkey *ca_key,
/* If this CA doesn't exist in the list then add it now */ /* If this CA doesn't exist in the list then add it now */
if ((rc = calloc(1, sizeof(*rc))) == NULL) if ((rc = calloc(1, sizeof(*rc))) == NULL)
return SSH_ERR_ALLOC_FAIL; return SSH_ERR_ALLOC_FAIL;
if ((r = sshkey_from_private(ca_key, &rc->ca_key)) != 0) { if (ca_key == NULL)
rc->ca_key = NULL;
else if ((r = sshkey_from_private(ca_key, &rc->ca_key)) != 0) {
free(rc); free(rc);
return r; return r;
} }
RB_INIT(&rc->revoked_serials); RB_INIT(&rc->revoked_serials);
RB_INIT(&rc->revoked_key_ids); RB_INIT(&rc->revoked_key_ids);
TAILQ_INSERT_TAIL(&krl->revoked_certs, rc, entry); TAILQ_INSERT_TAIL(&krl->revoked_certs, rc, entry);
KRL_DBG(("%s: new CA %s", __func__, sshkey_type(ca_key))); KRL_DBG(("%s: new CA %s", __func__,
ca_key == NULL ? "*" : sshkey_type(ca_key)));
*rcp = rc; *rcp = rc;
return 0; return 0;
} }
@ -554,9 +557,15 @@ revoked_certs_generate(struct revoked_certs *rc, struct sshbuf *buf)
if ((sect = sshbuf_new()) == NULL) if ((sect = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL; return SSH_ERR_ALLOC_FAIL;
/* Store the header: CA scope key, reserved */ /* Store the header: optional CA scope key, reserved */
if ((r = sshkey_puts(rc->ca_key, buf)) != 0 || if (rc->ca_key == NULL) {
(r = sshbuf_put_string(buf, NULL, 0)) != 0) if ((r = sshbuf_put_string(buf, NULL, 0)) != 0)
goto out;
} else {
if ((r = sshkey_puts(rc->ca_key, buf)) != 0)
goto out;
}
if ((r = sshbuf_put_string(buf, NULL, 0)) != 0)
goto out; goto out;
/* Store the revoked serials. */ /* Store the revoked serials. */
@ -813,7 +822,7 @@ parse_revoked_certs(struct sshbuf *buf, struct ssh_krl *krl)
if ((r = sshbuf_get_string_direct(buf, &blob, &blen)) != 0 || if ((r = sshbuf_get_string_direct(buf, &blob, &blen)) != 0 ||
(r = sshbuf_skip_string(buf)) != 0) (r = sshbuf_skip_string(buf)) != 0)
goto out; goto out;
if ((r = sshkey_from_blob(blob, blen, &ca_key)) != 0) if (blen != 0 && (r = sshkey_from_blob(blob, blen, &ca_key)) != 0)
goto out; goto out;
while (sshbuf_len(buf) > 0) { while (sshbuf_len(buf) > 0) {
@ -1154,13 +1163,45 @@ ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp,
return r; return r;
} }
/* Checks certificate serial number and key ID revocation */
static int
is_cert_revoked(const struct sshkey *key, struct revoked_certs *rc)
{
struct revoked_serial rs, *ers;
struct revoked_key_id rki, *erki;
/* Check revocation by cert key ID */
memset(&rki, 0, sizeof(rki));
rki.key_id = key->cert->key_id;
erki = RB_FIND(revoked_key_id_tree, &rc->revoked_key_ids, &rki);
if (erki != NULL) {
KRL_DBG(("%s: revoked by key ID", __func__));
return SSH_ERR_KEY_REVOKED;
}
/*
* Legacy cert formats lack serial numbers. Zero serials numbers
* are ignored (it's the default when the CA doesn't specify one).
*/
if (sshkey_cert_is_legacy(key) || key->cert->serial == 0)
return 0;
memset(&rs, 0, sizeof(rs));
rs.lo = rs.hi = key->cert->serial;
ers = RB_FIND(revoked_serial_tree, &rc->revoked_serials, &rs);
if (ers != NULL) {
KRL_DBG(("%s: revoked serial %llu matched %llu:%llu", __func__,
key->cert->serial, ers->lo, ers->hi));
return SSH_ERR_KEY_REVOKED;
}
return 0;
}
/* Checks whether a given key/cert is revoked. Does not check its CA */ /* Checks whether a given key/cert is revoked. Does not check its CA */
static int static int
is_key_revoked(struct ssh_krl *krl, const struct sshkey *key) is_key_revoked(struct ssh_krl *krl, const struct sshkey *key)
{ {
struct revoked_blob rb, *erb; struct revoked_blob rb, *erb;
struct revoked_serial rs, *ers;
struct revoked_key_id rki, *erki;
struct revoked_certs *rc; struct revoked_certs *rc;
int r; int r;
@ -1190,37 +1231,22 @@ is_key_revoked(struct ssh_krl *krl, const struct sshkey *key)
if (!sshkey_is_cert(key)) if (!sshkey_is_cert(key))
return 0; return 0;
/* Check cert revocation */ /* Check cert revocation for the specified CA */
if ((r = revoked_certs_for_ca_key(krl, key->cert->signature_key, if ((r = revoked_certs_for_ca_key(krl, key->cert->signature_key,
&rc, 0)) != 0) &rc, 0)) != 0)
return r; return r;
if (rc == NULL) if (rc != NULL) {
return 0; /* No entry for this CA */ if ((r = is_cert_revoked(key, rc)) != 0)
return r;
/* Check revocation by cert key ID */ }
memset(&rki, 0, sizeof(rki)); /* Check cert revocation for the wildcard CA */
rki.key_id = key->cert->key_id; if ((r = revoked_certs_for_ca_key(krl, NULL, &rc, 0)) != 0)
erki = RB_FIND(revoked_key_id_tree, &rc->revoked_key_ids, &rki); return r;
if (erki != NULL) { if (rc != NULL) {
KRL_DBG(("%s: revoked by key ID", __func__)); if ((r = is_cert_revoked(key, rc)) != 0)
return SSH_ERR_KEY_REVOKED; return r;
} }
/*
* Legacy cert formats lack serial numbers. Zero serials numbers
* are ignored (it's the default when the CA doesn't specify one).
*/
if (sshkey_cert_is_legacy(key) || key->cert->serial == 0)
return 0;
memset(&rs, 0, sizeof(rs));
rs.lo = rs.hi = key->cert->serial;
ers = RB_FIND(revoked_serial_tree, &rc->revoked_serials, &rs);
if (ers != NULL) {
KRL_DBG(("%s: revoked serial %llu matched %llu:%llu", __func__,
key->cert->serial, ers->lo, ers->hi));
return SSH_ERR_KEY_REVOKED;
}
KRL_DBG(("%s: %llu no match", __func__, key->cert->serial)); KRL_DBG(("%s: %llu no match", __func__, key->cert->serial));
return 0; return 0;
} }

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-keygen.c,v 1.260 2015/01/30 00:59:19 djm Exp $ */ /* $OpenBSD: ssh-keygen.c,v 1.261 2015/01/30 01:10:33 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -1973,7 +1973,7 @@ load_krl(const char *path, struct ssh_krl **krlp)
} }
static void static void
update_krl_from_file(struct passwd *pw, const char *file, update_krl_from_file(struct passwd *pw, const char *file, int wild_ca,
const struct sshkey *ca, struct ssh_krl *krl) const struct sshkey *ca, struct ssh_krl *krl)
{ {
struct sshkey *key = NULL; struct sshkey *key = NULL;
@ -2015,7 +2015,7 @@ update_krl_from_file(struct passwd *pw, const char *file,
if (*cp == '\0') if (*cp == '\0')
continue; continue;
if (strncasecmp(cp, "serial:", 7) == 0) { if (strncasecmp(cp, "serial:", 7) == 0) {
if (ca == NULL) { if (ca == NULL && !wild_ca) {
fatal("revoking certificates by serial number " fatal("revoking certificates by serial number "
"requires specification of a CA key"); "requires specification of a CA key");
} }
@ -2052,7 +2052,7 @@ update_krl_from_file(struct passwd *pw, const char *file,
__func__); __func__);
} }
} else if (strncasecmp(cp, "id:", 3) == 0) { } else if (strncasecmp(cp, "id:", 3) == 0) {
if (ca == NULL) { if (ca == NULL && !wild_ca) {
fatal("revoking certificates by key ID " fatal("revoking certificates by key ID "
"requires specification of a CA key"); "requires specification of a CA key");
} }
@ -2103,7 +2103,7 @@ do_gen_krl(struct passwd *pw, int updating, int argc, char **argv)
struct ssh_krl *krl; struct ssh_krl *krl;
struct stat sb; struct stat sb;
struct sshkey *ca = NULL; struct sshkey *ca = NULL;
int fd, i, r; int fd, i, r, wild_ca = 0;
char *tmp; char *tmp;
struct sshbuf *kbuf; struct sshbuf *kbuf;
@ -2117,11 +2117,15 @@ do_gen_krl(struct passwd *pw, int updating, int argc, char **argv)
fatal("KRL \"%s\" does not exist", identity_file); fatal("KRL \"%s\" does not exist", identity_file);
} }
if (ca_key_path != NULL) { if (ca_key_path != NULL) {
tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); if (strcasecmp(ca_key_path, "none") == 0)
if ((r = sshkey_load_public(tmp, &ca, NULL)) != 0) wild_ca = 1;
fatal("Cannot load CA public key %s: %s", else {
tmp, ssh_err(r)); tmp = tilde_expand_filename(ca_key_path, pw->pw_uid);
free(tmp); if ((r = sshkey_load_public(tmp, &ca, NULL)) != 0)
fatal("Cannot load CA public key %s: %s",
tmp, ssh_err(r));
free(tmp);
}
} }
if (updating) if (updating)
@ -2135,7 +2139,7 @@ do_gen_krl(struct passwd *pw, int updating, int argc, char **argv)
ssh_krl_set_comment(krl, identity_comment); ssh_krl_set_comment(krl, identity_comment);
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++)
update_krl_from_file(pw, argv[i], ca, krl); update_krl_from_file(pw, argv[i], wild_ca, ca, krl);
if ((kbuf = sshbuf_new()) == NULL) if ((kbuf = sshbuf_new()) == NULL)
fatal("sshbuf_new failed"); fatal("sshbuf_new failed");