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 | |
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
-rw-r--r-- | PROTOCOL.krl | 16 | ||||
-rw-r--r-- | krl.c | 126 | ||||
-rw-r--r-- | krl.h | 6 | ||||
-rw-r--r-- | ssh-keygen.1 | 19 | ||||
-rw-r--r-- | ssh-keygen.c | 75 |
5 files changed, 193 insertions, 49 deletions
diff --git a/PROTOCOL.krl b/PROTOCOL.krl index f319bad21..115f80e5d 100644 --- a/PROTOCOL.krl +++ b/PROTOCOL.krl | |||
@@ -36,6 +36,7 @@ The available section types are: | |||
36 | #define KRL_SECTION_EXPLICIT_KEY 2 | 36 | #define KRL_SECTION_EXPLICIT_KEY 2 |
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 | #define KRL_SECTION_FINGERPRINT_SHA256 5 | ||
39 | 40 | ||
40 | 2. Certificate section | 41 | 2. Certificate section |
41 | 42 | ||
@@ -127,18 +128,19 @@ must be a raw key (i.e. not a certificate). | |||
127 | 128 | ||
128 | This section may appear multiple times. | 129 | This section may appear multiple times. |
129 | 130 | ||
130 | 4. SHA1 fingerprint sections | 131 | 4. SHA1/SHA256 fingerprint sections |
131 | 132 | ||
132 | These sections, identified as KRL_SECTION_FINGERPRINT_SHA1, revoke | 133 | These sections, identified as KRL_SECTION_FINGERPRINT_SHA1 and |
133 | plain keys (i.e. not certificates) by listing their SHA1 hashes: | 134 | KRL_SECTION_FINGERPRINT_SHA256, revoke plain keys (i.e. not |
135 | certificates) by listing their hashes: | ||
134 | 136 | ||
135 | string public_key_hash[0] | 137 | string public_key_hash[0] |
136 | .... | 138 | .... |
137 | 139 | ||
138 | This section must contain at least one "public_key_hash". The hash blob | 140 | This section must contain at least one "public_key_hash". The hash blob |
139 | is obtained by taking the SHA1 hash of the public key blob. Hashes in | 141 | is obtained by taking the SHA1 or SHA256 hash of the public key blob. |
140 | this section must appear in numeric order, treating each hash as a big- | 142 | Hashes in this section must appear in numeric order, treating each hash |
141 | endian integer. | 143 | as a big-endian integer. |
142 | 144 | ||
143 | This section may appear multiple times. | 145 | This section may appear multiple times. |
144 | 146 | ||
@@ -166,4 +168,4 @@ Implementations that retrieve KRLs over untrusted channels must verify | |||
166 | signatures. Signature sections are optional for KRLs distributed by | 168 | signatures. Signature sections are optional for KRLs distributed by |
167 | trusted means. | 169 | trusted means. |
168 | 170 | ||
169 | $OpenBSD: PROTOCOL.krl,v 1.4 2018/04/10 00:10:49 djm Exp $ | 171 | $OpenBSD: PROTOCOL.krl,v 1.5 2018/09/12 01:21:34 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.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)); |
@@ -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.h,v 1.5 2015/12/30 23:46:14 djm Exp $ */ | 17 | /* $OpenBSD: krl.h,v 1.6 2018/09/12 01:21:34 djm Exp $ */ |
18 | 18 | ||
19 | #ifndef _KRL_H | 19 | #ifndef _KRL_H |
20 | #define _KRL_H | 20 | #define _KRL_H |
@@ -29,6 +29,7 @@ | |||
29 | #define KRL_SECTION_EXPLICIT_KEY 2 | 29 | #define KRL_SECTION_EXPLICIT_KEY 2 |
30 | #define KRL_SECTION_FINGERPRINT_SHA1 3 | 30 | #define KRL_SECTION_FINGERPRINT_SHA1 3 |
31 | #define KRL_SECTION_SIGNATURE 4 | 31 | #define KRL_SECTION_SIGNATURE 4 |
32 | #define KRL_SECTION_FINGERPRINT_SHA256 5 | ||
32 | 33 | ||
33 | /* KRL_SECTION_CERTIFICATES subsection types */ | 34 | /* KRL_SECTION_CERTIFICATES subsection types */ |
34 | #define KRL_SECTION_CERT_SERIAL_LIST 0x20 | 35 | #define KRL_SECTION_CERT_SERIAL_LIST 0x20 |
@@ -51,7 +52,8 @@ int ssh_krl_revoke_cert_by_serial_range(struct ssh_krl *krl, | |||
51 | int ssh_krl_revoke_cert_by_key_id(struct ssh_krl *krl, | 52 | int ssh_krl_revoke_cert_by_key_id(struct ssh_krl *krl, |
52 | const struct sshkey *ca_key, const char *key_id); | 53 | const struct sshkey *ca_key, const char *key_id); |
53 | int ssh_krl_revoke_key_explicit(struct ssh_krl *krl, const struct sshkey *key); | 54 | int ssh_krl_revoke_key_explicit(struct ssh_krl *krl, const struct sshkey *key); |
54 | int ssh_krl_revoke_key_sha1(struct ssh_krl *krl, const struct sshkey *key); | 55 | int ssh_krl_revoke_key_sha1(struct ssh_krl *krl, const u_char *p, size_t len); |
56 | int ssh_krl_revoke_key_sha256(struct ssh_krl *krl, const u_char *p, size_t len); | ||
55 | int ssh_krl_revoke_key(struct ssh_krl *krl, const struct sshkey *key); | 57 | int ssh_krl_revoke_key(struct ssh_krl *krl, const struct sshkey *key); |
56 | int ssh_krl_to_blob(struct ssh_krl *krl, struct sshbuf *buf, | 58 | int ssh_krl_to_blob(struct ssh_krl *krl, struct sshbuf *buf, |
57 | const struct sshkey **sign_keys, u_int nsign_keys); | 59 | const struct sshkey **sign_keys, u_int nsign_keys); |
diff --git a/ssh-keygen.1 b/ssh-keygen.1 index dd6e7e5a8..d1aad6f20 100644 --- a/ssh-keygen.1 +++ b/ssh-keygen.1 | |||
@@ -1,4 +1,4 @@ | |||
1 | .\" $OpenBSD: ssh-keygen.1,v 1.148 2018/08/08 01:16:01 djm Exp $ | 1 | .\" $OpenBSD: ssh-keygen.1,v 1.149 2018/09/12 01:21:34 djm Exp $ |
2 | .\" | 2 | .\" |
3 | .\" Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | .\" Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | .\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | .\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -35,7 +35,7 @@ | |||
35 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 35 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
36 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 36 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
37 | .\" | 37 | .\" |
38 | .Dd $Mdocdate: August 8 2018 $ | 38 | .Dd $Mdocdate: September 12 2018 $ |
39 | .Dt SSH-KEYGEN 1 | 39 | .Dt SSH-KEYGEN 1 |
40 | .Os | 40 | .Os |
41 | .Sh NAME | 41 | .Sh NAME |
@@ -814,7 +814,20 @@ option. | |||
814 | Revokes the specified key. | 814 | Revokes the specified key. |
815 | If a certificate is listed, then it is revoked as a plain public key. | 815 | If a certificate is listed, then it is revoked as a plain public key. |
816 | .It Cm sha1 : Ar public_key | 816 | .It Cm sha1 : Ar public_key |
817 | Revokes the specified key by its SHA1 hash. | 817 | Revokes the specified key by including its SHA1 hash in the KRL. |
818 | .It Cm sha256 : Ar public_key | ||
819 | Revokes the specified key by including its SHA256 hash in the KRL. | ||
820 | KRLs that revoke keys by SHA256 hash are not supported by OpenSSH versions | ||
821 | prior to 7.9. | ||
822 | .It Cm hash : Ar fingerprint | ||
823 | Revokes a key using by fingerprint hash, as obtained from a | ||
824 | .Xr sshd 8 | ||
825 | authentication log message or the | ||
826 | .Nm | ||
827 | .Fl l | ||
828 | flag. | ||
829 | Only SHA256 fingerprints are supported here and resultant KRLs are | ||
830 | not supported by OpenSSH versions prior to 7.9. | ||
818 | .El | 831 | .El |
819 | .Pp | 832 | .Pp |
820 | KRLs may be updated using the | 833 | KRLs may be updated using the |
diff --git a/ssh-keygen.c b/ssh-keygen.c index 22860ad90..748ce37d7 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-keygen.c,v 1.319 2018/08/08 01:16:01 djm Exp $ */ | 1 | /* $OpenBSD: ssh-keygen.c,v 1.320 2018/09/12 01:21:34 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 |
@@ -2080,15 +2080,51 @@ load_krl(const char *path, struct ssh_krl **krlp) | |||
2080 | } | 2080 | } |
2081 | 2081 | ||
2082 | static void | 2082 | static void |
2083 | hash_to_blob(const char *cp, u_char **blobp, size_t *lenp, | ||
2084 | const char *file, u_long lnum) | ||
2085 | { | ||
2086 | char *tmp; | ||
2087 | size_t tlen; | ||
2088 | struct sshbuf *b; | ||
2089 | int r; | ||
2090 | |||
2091 | if (strncmp(cp, "SHA256:", 7) != 0) | ||
2092 | fatal("%s:%lu: unsupported hash algorithm", file, lnum); | ||
2093 | cp += 7; | ||
2094 | |||
2095 | /* | ||
2096 | * OpenSSH base64 hashes omit trailing '=' | ||
2097 | * characters; put them back for decode. | ||
2098 | */ | ||
2099 | tlen = strlen(cp); | ||
2100 | tmp = xmalloc(tlen + 4 + 1); | ||
2101 | strlcpy(tmp, cp, tlen + 1); | ||
2102 | while ((tlen % 4) != 0) { | ||
2103 | tmp[tlen++] = '='; | ||
2104 | tmp[tlen] = '\0'; | ||
2105 | } | ||
2106 | if ((b = sshbuf_new()) == NULL) | ||
2107 | fatal("%s: sshbuf_new failed", __func__); | ||
2108 | if ((r = sshbuf_b64tod(b, tmp)) != 0) | ||
2109 | fatal("%s:%lu: decode hash failed: %s", file, lnum, ssh_err(r)); | ||
2110 | free(tmp); | ||
2111 | *lenp = sshbuf_len(b); | ||
2112 | *blobp = xmalloc(*lenp); | ||
2113 | memcpy(*blobp, sshbuf_ptr(b), *lenp); | ||
2114 | sshbuf_free(b); | ||
2115 | } | ||
2116 | |||
2117 | static void | ||
2083 | update_krl_from_file(struct passwd *pw, const char *file, int wild_ca, | 2118 | update_krl_from_file(struct passwd *pw, const char *file, int wild_ca, |
2084 | const struct sshkey *ca, struct ssh_krl *krl) | 2119 | const struct sshkey *ca, struct ssh_krl *krl) |
2085 | { | 2120 | { |
2086 | struct sshkey *key = NULL; | 2121 | struct sshkey *key = NULL; |
2087 | u_long lnum = 0; | 2122 | u_long lnum = 0; |
2088 | char *path, *cp, *ep, *line = NULL; | 2123 | char *path, *cp, *ep, *line = NULL; |
2089 | size_t linesize = 0; | 2124 | u_char *blob = NULL; |
2125 | size_t blen = 0, linesize = 0; | ||
2090 | unsigned long long serial, serial2; | 2126 | unsigned long long serial, serial2; |
2091 | int i, was_explicit_key, was_sha1, r; | 2127 | int i, was_explicit_key, was_sha1, was_sha256, was_hash, r; |
2092 | FILE *krl_spec; | 2128 | FILE *krl_spec; |
2093 | 2129 | ||
2094 | path = tilde_expand_filename(file, pw->pw_uid); | 2130 | path = tilde_expand_filename(file, pw->pw_uid); |
@@ -2103,7 +2139,7 @@ update_krl_from_file(struct passwd *pw, const char *file, int wild_ca, | |||
2103 | printf("Revoking from %s\n", path); | 2139 | printf("Revoking from %s\n", path); |
2104 | while (getline(&line, &linesize, krl_spec) != -1) { | 2140 | while (getline(&line, &linesize, krl_spec) != -1) { |
2105 | lnum++; | 2141 | lnum++; |
2106 | was_explicit_key = was_sha1 = 0; | 2142 | was_explicit_key = was_sha1 = was_sha256 = was_hash = 0; |
2107 | cp = line + strspn(line, " \t"); | 2143 | cp = line + strspn(line, " \t"); |
2108 | /* Trim trailing space, comments and strip \n */ | 2144 | /* Trim trailing space, comments and strip \n */ |
2109 | for (i = 0, r = -1; cp[i] != '\0'; i++) { | 2145 | for (i = 0, r = -1; cp[i] != '\0'; i++) { |
@@ -2168,6 +2204,11 @@ update_krl_from_file(struct passwd *pw, const char *file, int wild_ca, | |||
2168 | cp = cp + strspn(cp, " \t"); | 2204 | cp = cp + strspn(cp, " \t"); |
2169 | if (ssh_krl_revoke_cert_by_key_id(krl, ca, cp) != 0) | 2205 | if (ssh_krl_revoke_cert_by_key_id(krl, ca, cp) != 0) |
2170 | fatal("%s: revoke key ID failed", __func__); | 2206 | fatal("%s: revoke key ID failed", __func__); |
2207 | } else if (strncasecmp(cp, "hash:", 5) == 0) { | ||
2208 | cp += 5; | ||
2209 | cp = cp + strspn(cp, " \t"); | ||
2210 | hash_to_blob(cp, &blob, &blen, file, lnum); | ||
2211 | r = ssh_krl_revoke_key_sha256(krl, blob, blen); | ||
2171 | } else { | 2212 | } else { |
2172 | if (strncasecmp(cp, "key:", 4) == 0) { | 2213 | if (strncasecmp(cp, "key:", 4) == 0) { |
2173 | cp += 4; | 2214 | cp += 4; |
@@ -2177,7 +2218,10 @@ update_krl_from_file(struct passwd *pw, const char *file, int wild_ca, | |||
2177 | cp += 5; | 2218 | cp += 5; |
2178 | cp = cp + strspn(cp, " \t"); | 2219 | cp = cp + strspn(cp, " \t"); |
2179 | was_sha1 = 1; | 2220 | was_sha1 = 1; |
2180 | } else { | 2221 | } else if (strncasecmp(cp, "sha256:", 7) == 0) { |
2222 | cp += 7; | ||
2223 | cp = cp + strspn(cp, " \t"); | ||
2224 | was_sha256 = 1; | ||
2181 | /* | 2225 | /* |
2182 | * Just try to process the line as a key. | 2226 | * Just try to process the line as a key. |
2183 | * Parsing will fail if it isn't. | 2227 | * Parsing will fail if it isn't. |
@@ -2190,13 +2234,28 @@ update_krl_from_file(struct passwd *pw, const char *file, int wild_ca, | |||
2190 | path, lnum, ssh_err(r)); | 2234 | path, lnum, ssh_err(r)); |
2191 | if (was_explicit_key) | 2235 | if (was_explicit_key) |
2192 | r = ssh_krl_revoke_key_explicit(krl, key); | 2236 | r = ssh_krl_revoke_key_explicit(krl, key); |
2193 | else if (was_sha1) | 2237 | else if (was_sha1) { |
2194 | r = ssh_krl_revoke_key_sha1(krl, key); | 2238 | if (sshkey_fingerprint_raw(key, |
2195 | else | 2239 | SSH_DIGEST_SHA1, &blob, &blen) != 0) { |
2240 | fatal("%s:%lu: fingerprint failed", | ||
2241 | file, lnum); | ||
2242 | } | ||
2243 | r = ssh_krl_revoke_key_sha1(krl, blob, blen); | ||
2244 | } else if (was_sha256) { | ||
2245 | if (sshkey_fingerprint_raw(key, | ||
2246 | SSH_DIGEST_SHA256, &blob, &blen) != 0) { | ||
2247 | fatal("%s:%lu: fingerprint failed", | ||
2248 | file, lnum); | ||
2249 | } | ||
2250 | r = ssh_krl_revoke_key_sha256(krl, blob, blen); | ||
2251 | } else | ||
2196 | r = ssh_krl_revoke_key(krl, key); | 2252 | r = ssh_krl_revoke_key(krl, key); |
2197 | if (r != 0) | 2253 | if (r != 0) |
2198 | fatal("%s: revoke key failed: %s", | 2254 | fatal("%s: revoke key failed: %s", |
2199 | __func__, ssh_err(r)); | 2255 | __func__, ssh_err(r)); |
2256 | freezero(blob, blen); | ||
2257 | blob = NULL; | ||
2258 | blen = 0; | ||
2200 | sshkey_free(key); | 2259 | sshkey_free(key); |
2201 | } | 2260 | } |
2202 | } | 2261 | } |