diff options
author | djm@openbsd.org <djm@openbsd.org> | 2015-01-30 01:10:33 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2015-01-30 12:17:07 +1100 |
commit | 669aee994348468af8b4b2ebd29b602cf2860b22 (patch) | |
tree | 47acfa09dd5b13cbab745b70c5cf2b7de3777f5a /krl.c | |
parent | 7a2c368477e26575d0866247d3313da4256cb2b5 (diff) |
upstream commit
permit KRLs that revoke certificates by serial number or
key ID without scoping to a particular CA; ok markus@
Diffstat (limited to 'krl.c')
-rw-r--r-- | krl.c | 102 |
1 files changed, 64 insertions, 38 deletions
@@ -14,7 +14,7 @@ | |||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | /* $OpenBSD: krl.c,v 1.30 2015/01/26 02:59:11 djm Exp $ */ | 17 | /* $OpenBSD: krl.c,v 1.31 2015/01/30 01:10:33 djm Exp $ */ |
18 | 18 | ||
19 | #include "includes.h" | 19 | #include "includes.h" |
20 | 20 | ||
@@ -156,8 +156,7 @@ revoked_certs_free(struct revoked_certs *rc) | |||
156 | free(rki->key_id); | 156 | free(rki->key_id); |
157 | free(rki); | 157 | free(rki); |
158 | } | 158 | } |
159 | if (rc->ca_key != NULL) | 159 | sshkey_free(rc->ca_key); |
160 | sshkey_free(rc->ca_key); | ||
161 | } | 160 | } |
162 | 161 | ||
163 | void | 162 | void |
@@ -214,7 +213,8 @@ revoked_certs_for_ca_key(struct ssh_krl *krl, const struct sshkey *ca_key, | |||
214 | 213 | ||
215 | *rcp = NULL; | 214 | *rcp = NULL; |
216 | TAILQ_FOREACH(rc, &krl->revoked_certs, entry) { | 215 | TAILQ_FOREACH(rc, &krl->revoked_certs, entry) { |
217 | if (sshkey_equal(rc->ca_key, ca_key)) { | 216 | if ((ca_key == NULL && rc->ca_key == NULL) || |
217 | sshkey_equal(rc->ca_key, ca_key)) { | ||
218 | *rcp = rc; | 218 | *rcp = rc; |
219 | return 0; | 219 | return 0; |
220 | } | 220 | } |
@@ -224,14 +224,17 @@ revoked_certs_for_ca_key(struct ssh_krl *krl, const struct sshkey *ca_key, | |||
224 | /* If this CA doesn't exist in the list then add it now */ | 224 | /* If this CA doesn't exist in the list then add it now */ |
225 | if ((rc = calloc(1, sizeof(*rc))) == NULL) | 225 | if ((rc = calloc(1, sizeof(*rc))) == NULL) |
226 | return SSH_ERR_ALLOC_FAIL; | 226 | return SSH_ERR_ALLOC_FAIL; |
227 | if ((r = sshkey_from_private(ca_key, &rc->ca_key)) != 0) { | 227 | if (ca_key == NULL) |
228 | rc->ca_key = NULL; | ||
229 | else if ((r = sshkey_from_private(ca_key, &rc->ca_key)) != 0) { | ||
228 | free(rc); | 230 | free(rc); |
229 | return r; | 231 | return r; |
230 | } | 232 | } |
231 | RB_INIT(&rc->revoked_serials); | 233 | RB_INIT(&rc->revoked_serials); |
232 | RB_INIT(&rc->revoked_key_ids); | 234 | RB_INIT(&rc->revoked_key_ids); |
233 | TAILQ_INSERT_TAIL(&krl->revoked_certs, rc, entry); | 235 | TAILQ_INSERT_TAIL(&krl->revoked_certs, rc, entry); |
234 | KRL_DBG(("%s: new CA %s", __func__, sshkey_type(ca_key))); | 236 | KRL_DBG(("%s: new CA %s", __func__, |
237 | ca_key == NULL ? "*" : sshkey_type(ca_key))); | ||
235 | *rcp = rc; | 238 | *rcp = rc; |
236 | return 0; | 239 | return 0; |
237 | } | 240 | } |
@@ -554,9 +557,15 @@ revoked_certs_generate(struct revoked_certs *rc, struct sshbuf *buf) | |||
554 | if ((sect = sshbuf_new()) == NULL) | 557 | if ((sect = sshbuf_new()) == NULL) |
555 | return SSH_ERR_ALLOC_FAIL; | 558 | return SSH_ERR_ALLOC_FAIL; |
556 | 559 | ||
557 | /* Store the header: CA scope key, reserved */ | 560 | /* Store the header: optional CA scope key, reserved */ |
558 | if ((r = sshkey_puts(rc->ca_key, buf)) != 0 || | 561 | if (rc->ca_key == NULL) { |
559 | (r = sshbuf_put_string(buf, NULL, 0)) != 0) | 562 | if ((r = sshbuf_put_string(buf, NULL, 0)) != 0) |
563 | goto out; | ||
564 | } else { | ||
565 | if ((r = sshkey_puts(rc->ca_key, buf)) != 0) | ||
566 | goto out; | ||
567 | } | ||
568 | if ((r = sshbuf_put_string(buf, NULL, 0)) != 0) | ||
560 | goto out; | 569 | goto out; |
561 | 570 | ||
562 | /* Store the revoked serials. */ | 571 | /* Store the revoked serials. */ |
@@ -813,7 +822,7 @@ parse_revoked_certs(struct sshbuf *buf, struct ssh_krl *krl) | |||
813 | if ((r = sshbuf_get_string_direct(buf, &blob, &blen)) != 0 || | 822 | if ((r = sshbuf_get_string_direct(buf, &blob, &blen)) != 0 || |
814 | (r = sshbuf_skip_string(buf)) != 0) | 823 | (r = sshbuf_skip_string(buf)) != 0) |
815 | goto out; | 824 | goto out; |
816 | if ((r = sshkey_from_blob(blob, blen, &ca_key)) != 0) | 825 | if (blen != 0 && (r = sshkey_from_blob(blob, blen, &ca_key)) != 0) |
817 | goto out; | 826 | goto out; |
818 | 827 | ||
819 | while (sshbuf_len(buf) > 0) { | 828 | while (sshbuf_len(buf) > 0) { |
@@ -1154,13 +1163,45 @@ ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp, | |||
1154 | return r; | 1163 | return r; |
1155 | } | 1164 | } |
1156 | 1165 | ||
1166 | /* Checks certificate serial number and key ID revocation */ | ||
1167 | static int | ||
1168 | is_cert_revoked(const struct sshkey *key, struct revoked_certs *rc) | ||
1169 | { | ||
1170 | struct revoked_serial rs, *ers; | ||
1171 | struct revoked_key_id rki, *erki; | ||
1172 | |||
1173 | /* Check revocation by cert key ID */ | ||
1174 | memset(&rki, 0, sizeof(rki)); | ||
1175 | rki.key_id = key->cert->key_id; | ||
1176 | erki = RB_FIND(revoked_key_id_tree, &rc->revoked_key_ids, &rki); | ||
1177 | if (erki != NULL) { | ||
1178 | KRL_DBG(("%s: revoked by key ID", __func__)); | ||
1179 | return SSH_ERR_KEY_REVOKED; | ||
1180 | } | ||
1181 | |||
1182 | /* | ||
1183 | * Legacy cert formats lack serial numbers. Zero serials numbers | ||
1184 | * are ignored (it's the default when the CA doesn't specify one). | ||
1185 | */ | ||
1186 | if (sshkey_cert_is_legacy(key) || key->cert->serial == 0) | ||
1187 | return 0; | ||
1188 | |||
1189 | memset(&rs, 0, sizeof(rs)); | ||
1190 | rs.lo = rs.hi = key->cert->serial; | ||
1191 | ers = RB_FIND(revoked_serial_tree, &rc->revoked_serials, &rs); | ||
1192 | if (ers != NULL) { | ||
1193 | KRL_DBG(("%s: revoked serial %llu matched %llu:%llu", __func__, | ||
1194 | key->cert->serial, ers->lo, ers->hi)); | ||
1195 | return SSH_ERR_KEY_REVOKED; | ||
1196 | } | ||
1197 | return 0; | ||
1198 | } | ||
1199 | |||
1157 | /* Checks whether a given key/cert is revoked. Does not check its CA */ | 1200 | /* Checks whether a given key/cert is revoked. Does not check its CA */ |
1158 | static int | 1201 | static int |
1159 | is_key_revoked(struct ssh_krl *krl, const struct sshkey *key) | 1202 | is_key_revoked(struct ssh_krl *krl, const struct sshkey *key) |
1160 | { | 1203 | { |
1161 | struct revoked_blob rb, *erb; | 1204 | struct revoked_blob rb, *erb; |
1162 | struct revoked_serial rs, *ers; | ||
1163 | struct revoked_key_id rki, *erki; | ||
1164 | struct revoked_certs *rc; | 1205 | struct revoked_certs *rc; |
1165 | int r; | 1206 | int r; |
1166 | 1207 | ||
@@ -1190,37 +1231,22 @@ is_key_revoked(struct ssh_krl *krl, const struct sshkey *key) | |||
1190 | if (!sshkey_is_cert(key)) | 1231 | if (!sshkey_is_cert(key)) |
1191 | return 0; | 1232 | return 0; |
1192 | 1233 | ||
1193 | /* Check cert revocation */ | 1234 | /* Check cert revocation for the specified CA */ |
1194 | if ((r = revoked_certs_for_ca_key(krl, key->cert->signature_key, | 1235 | if ((r = revoked_certs_for_ca_key(krl, key->cert->signature_key, |
1195 | &rc, 0)) != 0) | 1236 | &rc, 0)) != 0) |
1196 | return r; | 1237 | return r; |
1197 | if (rc == NULL) | 1238 | if (rc != NULL) { |
1198 | return 0; /* No entry for this CA */ | 1239 | if ((r = is_cert_revoked(key, rc)) != 0) |
1199 | 1240 | return r; | |
1200 | /* Check revocation by cert key ID */ | ||
1201 | memset(&rki, 0, sizeof(rki)); | ||
1202 | rki.key_id = key->cert->key_id; | ||
1203 | erki = RB_FIND(revoked_key_id_tree, &rc->revoked_key_ids, &rki); | ||
1204 | if (erki != NULL) { | ||
1205 | KRL_DBG(("%s: revoked by key ID", __func__)); | ||
1206 | return SSH_ERR_KEY_REVOKED; | ||
1207 | } | 1241 | } |
1208 | 1242 | /* Check cert revocation for the wildcard CA */ | |
1209 | /* | 1243 | if ((r = revoked_certs_for_ca_key(krl, NULL, &rc, 0)) != 0) |
1210 | * Legacy cert formats lack serial numbers. Zero serials numbers | 1244 | return r; |
1211 | * are ignored (it's the default when the CA doesn't specify one). | 1245 | if (rc != NULL) { |
1212 | */ | 1246 | if ((r = is_cert_revoked(key, rc)) != 0) |
1213 | if (sshkey_cert_is_legacy(key) || key->cert->serial == 0) | 1247 | return r; |
1214 | return 0; | ||
1215 | |||
1216 | memset(&rs, 0, sizeof(rs)); | ||
1217 | rs.lo = rs.hi = key->cert->serial; | ||
1218 | ers = RB_FIND(revoked_serial_tree, &rc->revoked_serials, &rs); | ||
1219 | if (ers != NULL) { | ||
1220 | KRL_DBG(("%s: revoked serial %llu matched %llu:%llu", __func__, | ||
1221 | key->cert->serial, ers->lo, ers->hi)); | ||
1222 | return SSH_ERR_KEY_REVOKED; | ||
1223 | } | 1248 | } |
1249 | |||
1224 | KRL_DBG(("%s: %llu no match", __func__, key->cert->serial)); | 1250 | KRL_DBG(("%s: %llu no match", __func__, key->cert->serial)); |
1225 | return 0; | 1251 | return 0; |
1226 | } | 1252 | } |