summaryrefslogtreecommitdiff
path: root/krl.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2015-01-30 01:10:33 +0000
committerDamien Miller <djm@mindrot.org>2015-01-30 12:17:07 +1100
commit669aee994348468af8b4b2ebd29b602cf2860b22 (patch)
tree47acfa09dd5b13cbab745b70c5cf2b7de3777f5a /krl.c
parent7a2c368477e26575d0866247d3313da4256cb2b5 (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.c102
1 files changed, 64 insertions, 38 deletions
diff --git a/krl.c b/krl.c
index 3fe29c8b1..4bbaa2080 100644
--- a/krl.c
+++ b/krl.c
@@ -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
163void 162void
@@ -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 */
1167static int
1168is_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 */
1158static int 1201static int
1159is_key_revoked(struct ssh_krl *krl, const struct sshkey *key) 1202is_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}