diff options
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | dns.c | 103 | ||||
-rw-r--r-- | dns.h | 15 | ||||
-rw-r--r-- | key.c | 5 | ||||
-rw-r--r-- | key.h | 5 | ||||
-rw-r--r-- | ssh-keygen.c | 4 |
6 files changed, 92 insertions, 44 deletions
@@ -16,6 +16,10 @@ | |||
16 | [mux.c] | 16 | [mux.c] |
17 | fix double-free in new session handler | 17 | fix double-free in new session handler |
18 | NB. Id sync only | 18 | NB. Id sync only |
19 | - djm@cvs.openbsd.org 2012/05/23 03:28:28 | ||
20 | [dns.c dns.h key.c key.h ssh-keygen.c] | ||
21 | add support for RFC6594 SSHFP DNS records for ECDSA key types. | ||
22 | patch from bugzilla-m67 AT nulld.me in bz#1978; ok + tweak markus@ | ||
19 | 23 | ||
20 | 20120519 | 24 | 20120519 |
21 | - (dtucker) [configure.ac] bz#2010: fix non-portable shell construct. Patch | 25 | - (dtucker) [configure.ac] bz#2010: fix non-portable shell construct. Patch |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: dns.c,v 1.27 2010/08/31 11:54:45 djm Exp $ */ | 1 | /* $OpenBSD: dns.c,v 1.28 2012/05/23 03:28:28 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2003 Wesley Griffin. All rights reserved. | 4 | * Copyright (c) 2003 Wesley Griffin. All rights reserved. |
@@ -78,27 +78,46 @@ dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type, | |||
78 | u_char **digest, u_int *digest_len, Key *key) | 78 | u_char **digest, u_int *digest_len, Key *key) |
79 | { | 79 | { |
80 | int success = 0; | 80 | int success = 0; |
81 | enum fp_type fp_type = 0; | ||
81 | 82 | ||
82 | switch (key->type) { | 83 | switch (key->type) { |
83 | case KEY_RSA: | 84 | case KEY_RSA: |
84 | *algorithm = SSHFP_KEY_RSA; | 85 | *algorithm = SSHFP_KEY_RSA; |
86 | if (!*digest_type) | ||
87 | *digest_type = SSHFP_HASH_SHA1; | ||
85 | break; | 88 | break; |
86 | case KEY_DSA: | 89 | case KEY_DSA: |
87 | *algorithm = SSHFP_KEY_DSA; | 90 | *algorithm = SSHFP_KEY_DSA; |
91 | if (!*digest_type) | ||
92 | *digest_type = SSHFP_HASH_SHA1; | ||
93 | break; | ||
94 | case KEY_ECDSA: | ||
95 | *algorithm = SSHFP_KEY_ECDSA; | ||
96 | if (!*digest_type) | ||
97 | *digest_type = SSHFP_HASH_SHA256; | ||
88 | break; | 98 | break; |
89 | /* XXX KEY_ECDSA */ | ||
90 | default: | 99 | default: |
91 | *algorithm = SSHFP_KEY_RESERVED; /* 0 */ | 100 | *algorithm = SSHFP_KEY_RESERVED; /* 0 */ |
101 | *digest_type = SSHFP_HASH_RESERVED; /* 0 */ | ||
102 | } | ||
103 | |||
104 | switch (*digest_type) { | ||
105 | case SSHFP_HASH_SHA1: | ||
106 | fp_type = SSH_FP_SHA1; | ||
107 | break; | ||
108 | case SSHFP_HASH_SHA256: | ||
109 | fp_type = SSH_FP_SHA256; | ||
110 | break; | ||
111 | default: | ||
112 | *digest_type = SSHFP_HASH_RESERVED; /* 0 */ | ||
92 | } | 113 | } |
93 | 114 | ||
94 | if (*algorithm) { | 115 | if (*algorithm && *digest_type) { |
95 | *digest_type = SSHFP_HASH_SHA1; | 116 | *digest = key_fingerprint_raw(key, fp_type, digest_len); |
96 | *digest = key_fingerprint_raw(key, SSH_FP_SHA1, digest_len); | ||
97 | if (*digest == NULL) | 117 | if (*digest == NULL) |
98 | fatal("dns_read_key: null from key_fingerprint_raw()"); | 118 | fatal("dns_read_key: null from key_fingerprint_raw()"); |
99 | success = 1; | 119 | success = 1; |
100 | } else { | 120 | } else { |
101 | *digest_type = SSHFP_HASH_RESERVED; | ||
102 | *digest = NULL; | 121 | *digest = NULL; |
103 | *digest_len = 0; | 122 | *digest_len = 0; |
104 | success = 0; | 123 | success = 0; |
@@ -180,7 +199,7 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address, | |||
180 | struct rrsetinfo *fingerprints = NULL; | 199 | struct rrsetinfo *fingerprints = NULL; |
181 | 200 | ||
182 | u_int8_t hostkey_algorithm; | 201 | u_int8_t hostkey_algorithm; |
183 | u_int8_t hostkey_digest_type; | 202 | u_int8_t hostkey_digest_type = SSHFP_HASH_RESERVED; |
184 | u_char *hostkey_digest; | 203 | u_char *hostkey_digest; |
185 | u_int hostkey_digest_len; | 204 | u_int hostkey_digest_len; |
186 | 205 | ||
@@ -216,7 +235,7 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address, | |||
216 | fingerprints->rri_nrdatas); | 235 | fingerprints->rri_nrdatas); |
217 | } | 236 | } |
218 | 237 | ||
219 | /* Initialize host key parameters */ | 238 | /* Initialize default host key parameters */ |
220 | if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type, | 239 | if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type, |
221 | &hostkey_digest, &hostkey_digest_len, hostkey)) { | 240 | &hostkey_digest, &hostkey_digest_len, hostkey)) { |
222 | error("Error calculating host key fingerprint."); | 241 | error("Error calculating host key fingerprint."); |
@@ -240,16 +259,27 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address, | |||
240 | continue; | 259 | continue; |
241 | } | 260 | } |
242 | 261 | ||
262 | if (hostkey_digest_type != dnskey_digest_type) { | ||
263 | hostkey_digest_type = dnskey_digest_type; | ||
264 | xfree(hostkey_digest); | ||
265 | |||
266 | /* Initialize host key parameters */ | ||
267 | if (!dns_read_key(&hostkey_algorithm, | ||
268 | &hostkey_digest_type, &hostkey_digest, | ||
269 | &hostkey_digest_len, hostkey)) { | ||
270 | error("Error calculating key fingerprint."); | ||
271 | freerrset(fingerprints); | ||
272 | return -1; | ||
273 | } | ||
274 | } | ||
275 | |||
243 | /* Check if the current key is the same as the given key */ | 276 | /* Check if the current key is the same as the given key */ |
244 | if (hostkey_algorithm == dnskey_algorithm && | 277 | if (hostkey_algorithm == dnskey_algorithm && |
245 | hostkey_digest_type == dnskey_digest_type) { | 278 | hostkey_digest_type == dnskey_digest_type) { |
246 | |||
247 | if (hostkey_digest_len == dnskey_digest_len && | 279 | if (hostkey_digest_len == dnskey_digest_len && |
248 | memcmp(hostkey_digest, dnskey_digest, | 280 | timingsafe_bcmp(hostkey_digest, dnskey_digest, |
249 | hostkey_digest_len) == 0) { | 281 | hostkey_digest_len) == 0) |
250 | |||
251 | *flags |= DNS_VERIFY_MATCH; | 282 | *flags |= DNS_VERIFY_MATCH; |
252 | } | ||
253 | } | 283 | } |
254 | xfree(dnskey_digest); | 284 | xfree(dnskey_digest); |
255 | } | 285 | } |
@@ -275,31 +305,36 @@ int | |||
275 | export_dns_rr(const char *hostname, Key *key, FILE *f, int generic) | 305 | export_dns_rr(const char *hostname, Key *key, FILE *f, int generic) |
276 | { | 306 | { |
277 | u_int8_t rdata_pubkey_algorithm = 0; | 307 | u_int8_t rdata_pubkey_algorithm = 0; |
278 | u_int8_t rdata_digest_type = SSHFP_HASH_SHA1; | 308 | u_int8_t rdata_digest_type = SSHFP_HASH_RESERVED; |
309 | u_int8_t dtype; | ||
279 | u_char *rdata_digest; | 310 | u_char *rdata_digest; |
280 | u_int rdata_digest_len; | 311 | u_int i, rdata_digest_len; |
281 | |||
282 | u_int i; | ||
283 | int success = 0; | 312 | int success = 0; |
284 | 313 | ||
285 | if (dns_read_key(&rdata_pubkey_algorithm, &rdata_digest_type, | 314 | for (dtype = SSHFP_HASH_SHA1; dtype < SSHFP_HASH_MAX; dtype++) { |
286 | &rdata_digest, &rdata_digest_len, key)) { | 315 | rdata_digest_type = dtype; |
287 | 316 | if (dns_read_key(&rdata_pubkey_algorithm, &rdata_digest_type, | |
288 | if (generic) | 317 | &rdata_digest, &rdata_digest_len, key)) { |
289 | fprintf(f, "%s IN TYPE%d \\# %d %02x %02x ", hostname, | 318 | if (generic) { |
290 | DNS_RDATATYPE_SSHFP, 2 + rdata_digest_len, | 319 | fprintf(f, "%s IN TYPE%d \\# %d %02x %02x ", |
291 | rdata_pubkey_algorithm, rdata_digest_type); | 320 | hostname, DNS_RDATATYPE_SSHFP, |
292 | else | 321 | 2 + rdata_digest_len, |
293 | fprintf(f, "%s IN SSHFP %d %d ", hostname, | 322 | rdata_pubkey_algorithm, rdata_digest_type); |
294 | rdata_pubkey_algorithm, rdata_digest_type); | 323 | } else { |
324 | fprintf(f, "%s IN SSHFP %d %d ", hostname, | ||
325 | rdata_pubkey_algorithm, rdata_digest_type); | ||
326 | } | ||
327 | for (i = 0; i < rdata_digest_len; i++) | ||
328 | fprintf(f, "%02x", rdata_digest[i]); | ||
329 | fprintf(f, "\n"); | ||
330 | xfree(rdata_digest); /* from key_fingerprint_raw() */ | ||
331 | success = 1; | ||
332 | } | ||
333 | } | ||
295 | 334 | ||
296 | for (i = 0; i < rdata_digest_len; i++) | 335 | /* No SSHFP record was generated at all */ |
297 | fprintf(f, "%02x", rdata_digest[i]); | 336 | if (success == 0) { |
298 | fprintf(f, "\n"); | 337 | error("%s: unsupported algorithm and/or digest_type", __func__); |
299 | xfree(rdata_digest); /* from key_fingerprint_raw() */ | ||
300 | success = 1; | ||
301 | } else { | ||
302 | error("export_dns_rr: unsupported algorithm"); | ||
303 | } | 338 | } |
304 | 339 | ||
305 | return success; | 340 | return success; |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: dns.h,v 1.11 2010/02/26 20:29:54 djm Exp $ */ | 1 | /* $OpenBSD: dns.h,v 1.12 2012/05/23 03:28:28 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2003 Wesley Griffin. All rights reserved. | 4 | * Copyright (c) 2003 Wesley Griffin. All rights reserved. |
@@ -29,14 +29,17 @@ | |||
29 | #define DNS_H | 29 | #define DNS_H |
30 | 30 | ||
31 | enum sshfp_types { | 31 | enum sshfp_types { |
32 | SSHFP_KEY_RESERVED, | 32 | SSHFP_KEY_RESERVED = 0, |
33 | SSHFP_KEY_RSA, | 33 | SSHFP_KEY_RSA = 1, |
34 | SSHFP_KEY_DSA | 34 | SSHFP_KEY_DSA = 2, |
35 | SSHFP_KEY_ECDSA = 3 | ||
35 | }; | 36 | }; |
36 | 37 | ||
37 | enum sshfp_hashes { | 38 | enum sshfp_hashes { |
38 | SSHFP_HASH_RESERVED, | 39 | SSHFP_HASH_RESERVED = 0, |
39 | SSHFP_HASH_SHA1 | 40 | SSHFP_HASH_SHA1 = 1, |
41 | SSHFP_HASH_SHA256 = 2, | ||
42 | SSHFP_HASH_MAX = 3 | ||
40 | }; | 43 | }; |
41 | 44 | ||
42 | #define DNS_RDATACLASS_IN 1 | 45 | #define DNS_RDATACLASS_IN 1 |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: key.c,v 1.98 2011/10/18 04:58:26 djm Exp $ */ | 1 | /* $OpenBSD: key.c,v 1.99 2012/05/23 03:28:28 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * read_bignum(): | 3 | * read_bignum(): |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -342,6 +342,9 @@ key_fingerprint_raw(Key *k, enum fp_type dgst_type, u_int *dgst_raw_length) | |||
342 | case SSH_FP_SHA1: | 342 | case SSH_FP_SHA1: |
343 | md = EVP_sha1(); | 343 | md = EVP_sha1(); |
344 | break; | 344 | break; |
345 | case SSH_FP_SHA256: | ||
346 | md = EVP_sha256(); | ||
347 | break; | ||
345 | default: | 348 | default: |
346 | fatal("key_fingerprint_raw: bad digest type %d", | 349 | fatal("key_fingerprint_raw: bad digest type %d", |
347 | dgst_type); | 350 | dgst_type); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: key.h,v 1.33 2010/10/28 11:22:09 djm Exp $ */ | 1 | /* $OpenBSD: key.h,v 1.34 2012/05/23 03:28:28 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. |
@@ -48,7 +48,8 @@ enum types { | |||
48 | }; | 48 | }; |
49 | enum fp_type { | 49 | enum fp_type { |
50 | SSH_FP_SHA1, | 50 | SSH_FP_SHA1, |
51 | SSH_FP_MD5 | 51 | SSH_FP_MD5, |
52 | SSH_FP_SHA256 | ||
52 | }; | 53 | }; |
53 | enum fp_rep { | 54 | enum fp_rep { |
54 | SSH_FP_HEX, | 55 | SSH_FP_HEX, |
diff --git a/ssh-keygen.c b/ssh-keygen.c index c5130c86e..9407321d5 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-keygen.c,v 1.213 2012/02/29 11:21:26 djm Exp $ */ | 1 | /* $OpenBSD: ssh-keygen.c,v 1.214 2012/05/23 03:28:28 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 |
@@ -2194,6 +2194,8 @@ main(int argc, char **argv) | |||
2194 | _PATH_HOST_RSA_KEY_FILE, rr_hostname); | 2194 | _PATH_HOST_RSA_KEY_FILE, rr_hostname); |
2195 | n += do_print_resource_record(pw, | 2195 | n += do_print_resource_record(pw, |
2196 | _PATH_HOST_DSA_KEY_FILE, rr_hostname); | 2196 | _PATH_HOST_DSA_KEY_FILE, rr_hostname); |
2197 | n += do_print_resource_record(pw, | ||
2198 | _PATH_HOST_ECDSA_KEY_FILE, rr_hostname); | ||
2197 | 2199 | ||
2198 | if (n == 0) | 2200 | if (n == 0) |
2199 | fatal("no keys found."); | 2201 | fatal("no keys found."); |