diff options
author | djm@openbsd.org <djm@openbsd.org> | 2018-09-12 01:21:34 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2018-09-12 16:49:21 +1000 |
commit | 9405c6214f667be604a820c6823b27d0ea77937d (patch) | |
tree | 02a875b21e6a6f0d1432cc90ae515383b267b688 /krl.c | |
parent | 50e2687ee0941c0ea216d6ffea370ffd2c1f14b9 (diff) |
upstream: allow key revocation by SHA256 hash and allow ssh-keygen
to create KRLs using SHA256/base64 key fingerprints; ok markus@
OpenBSD-Commit-ID: a0590fd34e7f1141f2873ab3acc57442560e6a94
Diffstat (limited to 'krl.c')
-rw-r--r-- | krl.c | 126 |
1 files changed, 97 insertions, 29 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.41 2017/12/18 02:25:15 djm Exp $ */ | 17 | /* $OpenBSD: krl.c,v 1.42 2018/09/12 01:21:34 djm Exp $ */ |
18 | 18 | ||
19 | #include "includes.h" | 19 | #include "includes.h" |
20 | 20 | ||
@@ -96,6 +96,7 @@ struct ssh_krl { | |||
96 | char *comment; | 96 | char *comment; |
97 | struct revoked_blob_tree revoked_keys; | 97 | struct revoked_blob_tree revoked_keys; |
98 | struct revoked_blob_tree revoked_sha1s; | 98 | struct revoked_blob_tree revoked_sha1s; |
99 | struct revoked_blob_tree revoked_sha256s; | ||
99 | struct revoked_certs_list revoked_certs; | 100 | struct revoked_certs_list revoked_certs; |
100 | }; | 101 | }; |
101 | 102 | ||
@@ -136,6 +137,7 @@ ssh_krl_init(void) | |||
136 | return NULL; | 137 | return NULL; |
137 | RB_INIT(&krl->revoked_keys); | 138 | RB_INIT(&krl->revoked_keys); |
138 | RB_INIT(&krl->revoked_sha1s); | 139 | RB_INIT(&krl->revoked_sha1s); |
140 | RB_INIT(&krl->revoked_sha256s); | ||
139 | TAILQ_INIT(&krl->revoked_certs); | 141 | TAILQ_INIT(&krl->revoked_certs); |
140 | return krl; | 142 | return krl; |
141 | } | 143 | } |
@@ -178,6 +180,11 @@ ssh_krl_free(struct ssh_krl *krl) | |||
178 | free(rb->blob); | 180 | free(rb->blob); |
179 | free(rb); | 181 | free(rb); |
180 | } | 182 | } |
183 | RB_FOREACH_SAFE(rb, revoked_blob_tree, &krl->revoked_sha256s, trb) { | ||
184 | RB_REMOVE(revoked_blob_tree, &krl->revoked_sha256s, rb); | ||
185 | free(rb->blob); | ||
186 | free(rb); | ||
187 | } | ||
181 | TAILQ_FOREACH_SAFE(rc, &krl->revoked_certs, entry, trc) { | 188 | TAILQ_FOREACH_SAFE(rc, &krl->revoked_certs, entry, trc) { |
182 | TAILQ_REMOVE(&krl->revoked_certs, rc, entry); | 189 | TAILQ_REMOVE(&krl->revoked_certs, rc, entry); |
183 | revoked_certs_free(rc); | 190 | revoked_certs_free(rc); |
@@ -408,25 +415,47 @@ ssh_krl_revoke_key_explicit(struct ssh_krl *krl, const struct sshkey *key) | |||
408 | return revoke_blob(&krl->revoked_keys, blob, len); | 415 | return revoke_blob(&krl->revoked_keys, blob, len); |
409 | } | 416 | } |
410 | 417 | ||
411 | int | 418 | static int |
412 | ssh_krl_revoke_key_sha1(struct ssh_krl *krl, const struct sshkey *key) | 419 | revoke_by_hash(struct revoked_blob_tree *target, const u_char *p, size_t len) |
413 | { | 420 | { |
414 | u_char *blob; | 421 | u_char *blob; |
415 | size_t len; | ||
416 | int r; | 422 | int r; |
417 | 423 | ||
418 | debug3("%s: revoke type %s by sha1", __func__, sshkey_type(key)); | 424 | /* need to copy hash, as revoke_blob steals ownership */ |
419 | if ((r = sshkey_fingerprint_raw(key, SSH_DIGEST_SHA1, | 425 | if ((blob = malloc(len)) == NULL) |
420 | &blob, &len)) != 0) | 426 | return SSH_ERR_SYSTEM_ERROR; |
427 | memcpy(blob, p, len); | ||
428 | if ((r = revoke_blob(target, blob, len)) != 0) { | ||
429 | free(blob); | ||
421 | return r; | 430 | return r; |
422 | return revoke_blob(&krl->revoked_sha1s, blob, len); | 431 | } |
432 | return 0; | ||
433 | } | ||
434 | |||
435 | int | ||
436 | ssh_krl_revoke_key_sha1(struct ssh_krl *krl, const u_char *p, size_t len) | ||
437 | { | ||
438 | debug3("%s: revoke by sha1", __func__); | ||
439 | if (len != 20) | ||
440 | return SSH_ERR_INVALID_FORMAT; | ||
441 | return revoke_by_hash(&krl->revoked_sha1s, p, len); | ||
442 | } | ||
443 | |||
444 | int | ||
445 | ssh_krl_revoke_key_sha256(struct ssh_krl *krl, const u_char *p, size_t len) | ||
446 | { | ||
447 | debug3("%s: revoke by sha256", __func__); | ||
448 | if (len != 32) | ||
449 | return SSH_ERR_INVALID_FORMAT; | ||
450 | return revoke_by_hash(&krl->revoked_sha256s, p, len); | ||
423 | } | 451 | } |
424 | 452 | ||
425 | int | 453 | int |
426 | ssh_krl_revoke_key(struct ssh_krl *krl, const struct sshkey *key) | 454 | ssh_krl_revoke_key(struct ssh_krl *krl, const struct sshkey *key) |
427 | { | 455 | { |
456 | /* XXX replace with SHA256? */ | ||
428 | if (!sshkey_is_cert(key)) | 457 | if (!sshkey_is_cert(key)) |
429 | return ssh_krl_revoke_key_sha1(krl, key); | 458 | return ssh_krl_revoke_key_explicit(krl, key); |
430 | 459 | ||
431 | if (key->cert->serial == 0) { | 460 | if (key->cert->serial == 0) { |
432 | return ssh_krl_revoke_cert_by_key_id(krl, | 461 | return ssh_krl_revoke_cert_by_key_id(krl, |
@@ -762,6 +791,18 @@ ssh_krl_to_blob(struct ssh_krl *krl, struct sshbuf *buf, | |||
762 | (r = sshbuf_put_stringb(buf, sect)) != 0) | 791 | (r = sshbuf_put_stringb(buf, sect)) != 0) |
763 | goto out; | 792 | goto out; |
764 | } | 793 | } |
794 | sshbuf_reset(sect); | ||
795 | RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_sha256s) { | ||
796 | KRL_DBG(("%s: hash len %zu ", __func__, rb->len)); | ||
797 | if ((r = sshbuf_put_string(sect, rb->blob, rb->len)) != 0) | ||
798 | goto out; | ||
799 | } | ||
800 | if (sshbuf_len(sect) != 0) { | ||
801 | if ((r = sshbuf_put_u8(buf, | ||
802 | KRL_SECTION_FINGERPRINT_SHA256)) != 0 || | ||
803 | (r = sshbuf_put_stringb(buf, sect)) != 0) | ||
804 | goto out; | ||
805 | } | ||
765 | 806 | ||
766 | for (i = 0; i < nsign_keys; i++) { | 807 | for (i = 0; i < nsign_keys; i++) { |
767 | KRL_DBG(("%s: signature key %s", __func__, | 808 | KRL_DBG(("%s: signature key %s", __func__, |
@@ -914,6 +955,29 @@ parse_revoked_certs(struct sshbuf *buf, struct ssh_krl *krl) | |||
914 | return r; | 955 | return r; |
915 | } | 956 | } |
916 | 957 | ||
958 | static int | ||
959 | blob_section(struct sshbuf *sect, struct revoked_blob_tree *target_tree, | ||
960 | size_t expected_len) | ||
961 | { | ||
962 | u_char *rdata = NULL; | ||
963 | size_t rlen = 0; | ||
964 | int r; | ||
965 | |||
966 | while (sshbuf_len(sect) > 0) { | ||
967 | if ((r = sshbuf_get_string(sect, &rdata, &rlen)) != 0) | ||
968 | return r; | ||
969 | if (expected_len != 0 && rlen != expected_len) { | ||
970 | error("%s: bad length", __func__); | ||
971 | free(rdata); | ||
972 | return SSH_ERR_INVALID_FORMAT; | ||
973 | } | ||
974 | if ((r = revoke_blob(target_tree, rdata, rlen)) != 0) { | ||
975 | free(rdata); | ||
976 | return r; | ||
977 | } | ||
978 | } | ||
979 | return 0; | ||
980 | } | ||
917 | 981 | ||
918 | /* Attempt to parse a KRL, checking its signature (if any) with sign_ca_keys. */ | 982 | /* Attempt to parse a KRL, checking its signature (if any) with sign_ca_keys. */ |
919 | int | 983 | int |
@@ -925,9 +989,9 @@ ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp, | |||
925 | char timestamp[64]; | 989 | char timestamp[64]; |
926 | int r = SSH_ERR_INTERNAL_ERROR, sig_seen; | 990 | int r = SSH_ERR_INTERNAL_ERROR, sig_seen; |
927 | struct sshkey *key = NULL, **ca_used = NULL, **tmp_ca_used; | 991 | struct sshkey *key = NULL, **ca_used = NULL, **tmp_ca_used; |
928 | u_char type, *rdata = NULL; | 992 | u_char type; |
929 | const u_char *blob; | 993 | const u_char *blob; |
930 | size_t i, j, sig_off, sects_off, rlen, blen, nca_used; | 994 | size_t i, j, sig_off, sects_off, blen, nca_used; |
931 | u_int format_version; | 995 | u_int format_version; |
932 | 996 | ||
933 | nca_used = 0; | 997 | nca_used = 0; |
@@ -1068,24 +1132,19 @@ ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp, | |||
1068 | goto out; | 1132 | goto out; |
1069 | break; | 1133 | break; |
1070 | case KRL_SECTION_EXPLICIT_KEY: | 1134 | case KRL_SECTION_EXPLICIT_KEY: |
1135 | if ((r = blob_section(sect, | ||
1136 | &krl->revoked_keys, 0)) != 0) | ||
1137 | goto out; | ||
1138 | break; | ||
1071 | case KRL_SECTION_FINGERPRINT_SHA1: | 1139 | case KRL_SECTION_FINGERPRINT_SHA1: |
1072 | while (sshbuf_len(sect) > 0) { | 1140 | if ((r = blob_section(sect, |
1073 | if ((r = sshbuf_get_string(sect, | 1141 | &krl->revoked_sha1s, 20)) != 0) |
1074 | &rdata, &rlen)) != 0) | 1142 | goto out; |
1075 | goto out; | 1143 | break; |
1076 | if (type == KRL_SECTION_FINGERPRINT_SHA1 && | 1144 | case KRL_SECTION_FINGERPRINT_SHA256: |
1077 | rlen != 20) { | 1145 | if ((r = blob_section(sect, |
1078 | error("%s: bad SHA1 length", __func__); | 1146 | &krl->revoked_sha256s, 32)) != 0) |
1079 | r = SSH_ERR_INVALID_FORMAT; | 1147 | goto out; |
1080 | goto out; | ||
1081 | } | ||
1082 | if ((r = revoke_blob( | ||
1083 | type == KRL_SECTION_EXPLICIT_KEY ? | ||
1084 | &krl->revoked_keys : &krl->revoked_sha1s, | ||
1085 | rdata, rlen)) != 0) | ||
1086 | goto out; | ||
1087 | rdata = NULL; /* revoke_blob frees rdata */ | ||
1088 | } | ||
1089 | break; | 1148 | break; |
1090 | case KRL_SECTION_SIGNATURE: | 1149 | case KRL_SECTION_SIGNATURE: |
1091 | /* Handled above, but still need to stay in synch */ | 1150 | /* Handled above, but still need to stay in synch */ |
@@ -1150,7 +1209,6 @@ ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp, | |||
1150 | for (i = 0; i < nca_used; i++) | 1209 | for (i = 0; i < nca_used; i++) |
1151 | sshkey_free(ca_used[i]); | 1210 | sshkey_free(ca_used[i]); |
1152 | free(ca_used); | 1211 | free(ca_used); |
1153 | free(rdata); | ||
1154 | sshkey_free(key); | 1212 | sshkey_free(key); |
1155 | sshbuf_free(copy); | 1213 | sshbuf_free(copy); |
1156 | sshbuf_free(sect); | 1214 | sshbuf_free(sect); |
@@ -1210,6 +1268,16 @@ is_key_revoked(struct ssh_krl *krl, const struct sshkey *key) | |||
1210 | KRL_DBG(("%s: revoked by key SHA1", __func__)); | 1268 | KRL_DBG(("%s: revoked by key SHA1", __func__)); |
1211 | return SSH_ERR_KEY_REVOKED; | 1269 | return SSH_ERR_KEY_REVOKED; |
1212 | } | 1270 | } |
1271 | memset(&rb, 0, sizeof(rb)); | ||
1272 | if ((r = sshkey_fingerprint_raw(key, SSH_DIGEST_SHA256, | ||
1273 | &rb.blob, &rb.len)) != 0) | ||
1274 | return r; | ||
1275 | erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha256s, &rb); | ||
1276 | free(rb.blob); | ||
1277 | if (erb != NULL) { | ||
1278 | KRL_DBG(("%s: revoked by key SHA256", __func__)); | ||
1279 | return SSH_ERR_KEY_REVOKED; | ||
1280 | } | ||
1213 | 1281 | ||
1214 | /* Next, explicit keys */ | 1282 | /* Next, explicit keys */ |
1215 | memset(&rb, 0, sizeof(rb)); | 1283 | memset(&rb, 0, sizeof(rb)); |