version 1.30, 2015/01/26 02:59:11 |
version 1.31, 2015/01/30 01:10:33 |
|
|
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 |
|
|
|
|
*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; |
} |
} |
|
|
/* 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; |
} |
} |
|
|
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. */ |
|
|
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) { |
|
|
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; |
|
|
|
|
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)); |
|
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; |
|
} |
} |
|
/* Check cert revocation for the wildcard CA */ |
/* |
if ((r = revoked_certs_for_ca_key(krl, NULL, &rc, 0)) != 0) |
* Legacy cert formats lack serial numbers. Zero serials numbers |
return r; |
* are ignored (it's the default when the CA doesn't specify one). |
if (rc != NULL) { |
*/ |
if ((r = is_cert_revoked(key, rc)) != 0) |
if (sshkey_cert_is_legacy(key) || key->cert->serial == 0) |
return r; |
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; |
} |
} |