diff options
-rw-r--r-- | PROTOCOL.krl | 9 | ||||
-rw-r--r-- | krl.c | 102 | ||||
-rw-r--r-- | ssh-keygen.c | 26 |
3 files changed, 86 insertions, 51 deletions
diff --git a/PROTOCOL.krl b/PROTOCOL.krl index e8caa4527..b9695107b 100644 --- a/PROTOCOL.krl +++ b/PROTOCOL.krl | |||
@@ -37,7 +37,7 @@ The available section types are: | |||
37 | #define KRL_SECTION_FINGERPRINT_SHA1 3 | 37 | #define KRL_SECTION_FINGERPRINT_SHA1 3 |
38 | #define KRL_SECTION_SIGNATURE 4 | 38 | #define KRL_SECTION_SIGNATURE 4 |
39 | 39 | ||
40 | 3. Certificate serial section | 40 | 2. Certificate section |
41 | 41 | ||
42 | These sections use type KRL_SECTION_CERTIFICATES to revoke certificates by | 42 | These sections use type KRL_SECTION_CERTIFICATES to revoke certificates by |
43 | serial number or key ID. The consist of the CA key that issued the | 43 | serial number or key ID. The consist of the CA key that issued the |
@@ -47,6 +47,11 @@ ignored. | |||
47 | string ca_key | 47 | string ca_key |
48 | string reserved | 48 | string reserved |
49 | 49 | ||
50 | Where "ca_key" is the standard SSH wire serialisation of the CA's | ||
51 | public key. Alternately, "ca_key" may be an empty string to indicate | ||
52 | the certificate section applies to all CAs (this is most useful when | ||
53 | revoking key IDs). | ||
54 | |||
50 | Followed by one or more sections: | 55 | Followed by one or more sections: |
51 | 56 | ||
52 | byte cert_section_type | 57 | byte cert_section_type |
@@ -161,4 +166,4 @@ Implementations that retrieve KRLs over untrusted channels must verify | |||
161 | signatures. Signature sections are optional for KRLs distributed by | 166 | signatures. Signature sections are optional for KRLs distributed by |
162 | trusted means. | 167 | trusted means. |
163 | 168 | ||
164 | $OpenBSD: PROTOCOL.krl,v 1.2 2013/01/18 00:24:58 djm Exp $ | 169 | $OpenBSD: PROTOCOL.krl,v 1.3 2015/01/30 01:10:33 djm Exp $ |
@@ -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 | } |
diff --git a/ssh-keygen.c b/ssh-keygen.c index b435498cb..2c6a56839 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-keygen.c,v 1.260 2015/01/30 00:59:19 djm Exp $ */ | 1 | /* $OpenBSD: ssh-keygen.c,v 1.261 2015/01/30 01:10:33 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -1973,7 +1973,7 @@ load_krl(const char *path, struct ssh_krl **krlp) | |||
1973 | } | 1973 | } |
1974 | 1974 | ||
1975 | static void | 1975 | static void |
1976 | update_krl_from_file(struct passwd *pw, const char *file, | 1976 | update_krl_from_file(struct passwd *pw, const char *file, int wild_ca, |
1977 | const struct sshkey *ca, struct ssh_krl *krl) | 1977 | const struct sshkey *ca, struct ssh_krl *krl) |
1978 | { | 1978 | { |
1979 | struct sshkey *key = NULL; | 1979 | struct sshkey *key = NULL; |
@@ -2015,7 +2015,7 @@ update_krl_from_file(struct passwd *pw, const char *file, | |||
2015 | if (*cp == '\0') | 2015 | if (*cp == '\0') |
2016 | continue; | 2016 | continue; |
2017 | if (strncasecmp(cp, "serial:", 7) == 0) { | 2017 | if (strncasecmp(cp, "serial:", 7) == 0) { |
2018 | if (ca == NULL) { | 2018 | if (ca == NULL && !wild_ca) { |
2019 | fatal("revoking certificates by serial number " | 2019 | fatal("revoking certificates by serial number " |
2020 | "requires specification of a CA key"); | 2020 | "requires specification of a CA key"); |
2021 | } | 2021 | } |
@@ -2052,7 +2052,7 @@ update_krl_from_file(struct passwd *pw, const char *file, | |||
2052 | __func__); | 2052 | __func__); |
2053 | } | 2053 | } |
2054 | } else if (strncasecmp(cp, "id:", 3) == 0) { | 2054 | } else if (strncasecmp(cp, "id:", 3) == 0) { |
2055 | if (ca == NULL) { | 2055 | if (ca == NULL && !wild_ca) { |
2056 | fatal("revoking certificates by key ID " | 2056 | fatal("revoking certificates by key ID " |
2057 | "requires specification of a CA key"); | 2057 | "requires specification of a CA key"); |
2058 | } | 2058 | } |
@@ -2103,7 +2103,7 @@ do_gen_krl(struct passwd *pw, int updating, int argc, char **argv) | |||
2103 | struct ssh_krl *krl; | 2103 | struct ssh_krl *krl; |
2104 | struct stat sb; | 2104 | struct stat sb; |
2105 | struct sshkey *ca = NULL; | 2105 | struct sshkey *ca = NULL; |
2106 | int fd, i, r; | 2106 | int fd, i, r, wild_ca = 0; |
2107 | char *tmp; | 2107 | char *tmp; |
2108 | struct sshbuf *kbuf; | 2108 | struct sshbuf *kbuf; |
2109 | 2109 | ||
@@ -2117,11 +2117,15 @@ do_gen_krl(struct passwd *pw, int updating, int argc, char **argv) | |||
2117 | fatal("KRL \"%s\" does not exist", identity_file); | 2117 | fatal("KRL \"%s\" does not exist", identity_file); |
2118 | } | 2118 | } |
2119 | if (ca_key_path != NULL) { | 2119 | if (ca_key_path != NULL) { |
2120 | tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); | 2120 | if (strcasecmp(ca_key_path, "none") == 0) |
2121 | if ((r = sshkey_load_public(tmp, &ca, NULL)) != 0) | 2121 | wild_ca = 1; |
2122 | fatal("Cannot load CA public key %s: %s", | 2122 | else { |
2123 | tmp, ssh_err(r)); | 2123 | tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); |
2124 | free(tmp); | 2124 | if ((r = sshkey_load_public(tmp, &ca, NULL)) != 0) |
2125 | fatal("Cannot load CA public key %s: %s", | ||
2126 | tmp, ssh_err(r)); | ||
2127 | free(tmp); | ||
2128 | } | ||
2125 | } | 2129 | } |
2126 | 2130 | ||
2127 | if (updating) | 2131 | if (updating) |
@@ -2135,7 +2139,7 @@ do_gen_krl(struct passwd *pw, int updating, int argc, char **argv) | |||
2135 | ssh_krl_set_comment(krl, identity_comment); | 2139 | ssh_krl_set_comment(krl, identity_comment); |
2136 | 2140 | ||
2137 | for (i = 0; i < argc; i++) | 2141 | for (i = 0; i < argc; i++) |
2138 | update_krl_from_file(pw, argv[i], ca, krl); | 2142 | update_krl_from_file(pw, argv[i], wild_ca, ca, krl); |
2139 | 2143 | ||
2140 | if ((kbuf = sshbuf_new()) == NULL) | 2144 | if ((kbuf = sshbuf_new()) == NULL) |
2141 | fatal("sshbuf_new failed"); | 2145 | fatal("sshbuf_new failed"); |