summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2010-03-04 21:53:35 +1100
committerDamien Miller <djm@mindrot.org>2010-03-04 21:53:35 +1100
commit1aed65eb27feec505997c98621bdf158f9ab8b99 (patch)
tree81c2d0b9aff3c2211388ba00cde544e0618750d2
parent2befbad9b3c8fc6e4e564c062870229bc722734c (diff)
- djm@cvs.openbsd.org 2010/03/04 10:36:03
[auth-rh-rsa.c auth-rsa.c auth.c auth.h auth2-hostbased.c auth2-pubkey.c] [authfile.c authfile.h hostfile.c hostfile.h servconf.c servconf.h] [ssh-keygen.c ssh.1 sshconnect.c sshd_config.5] Add a TrustedUserCAKeys option to sshd_config to specify CA keys that are trusted to authenticate users (in addition than doing it per-user in authorized_keys). Add a RevokedKeys option to sshd_config and a @revoked marker to known_hosts to allow keys to me revoked and banned for user or host authentication. feedback and ok markus@
-rw-r--r--ChangeLog13
-rw-r--r--auth-rh-rsa.c5
-rw-r--r--auth-rsa.c5
-rw-r--r--auth.c31
-rw-r--r--auth.h3
-rw-r--r--auth2-hostbased.c5
-rw-r--r--auth2-pubkey.c53
-rw-r--r--authfile.c64
-rw-r--r--authfile.h3
-rw-r--r--hostfile.c102
-rw-r--r--hostfile.h5
-rw-r--r--servconf.c19
-rw-r--r--servconf.h4
-rw-r--r--ssh-keygen.c2
-rw-r--r--ssh.120
-rw-r--r--sshconnect.c24
-rw-r--r--sshd_config.525
17 files changed, 343 insertions, 40 deletions
diff --git a/ChangeLog b/ChangeLog
index 0b5663ba4..07d4aeb05 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -22,6 +22,19 @@
22 [key.c] 22 [key.c]
23 use buffer_get_string_ptr_ret() where we are checking the return 23 use buffer_get_string_ptr_ret() where we are checking the return
24 value explicitly instead of the fatal()-causing buffer_get_string_ptr() 24 value explicitly instead of the fatal()-causing buffer_get_string_ptr()
25 - djm@cvs.openbsd.org 2010/03/04 10:36:03
26 [auth-rh-rsa.c auth-rsa.c auth.c auth.h auth2-hostbased.c auth2-pubkey.c]
27 [authfile.c authfile.h hostfile.c hostfile.h servconf.c servconf.h]
28 [ssh-keygen.c ssh.1 sshconnect.c sshd_config.5]
29 Add a TrustedUserCAKeys option to sshd_config to specify CA keys that
30 are trusted to authenticate users (in addition than doing it per-user
31 in authorized_keys).
32
33 Add a RevokedKeys option to sshd_config and a @revoked marker to
34 known_hosts to allow keys to me revoked and banned for user or host
35 authentication.
36
37 feedback and ok markus@
25 38
2620100303 3920100303
27 - (djm) [PROTOCOL.certkeys] Add RCS Ident 40 - (djm) [PROTOCOL.certkeys] Add RCS Ident
diff --git a/auth-rh-rsa.c b/auth-rh-rsa.c
index eca750275..b21a0f4a2 100644
--- a/auth-rh-rsa.c
+++ b/auth-rh-rsa.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth-rh-rsa.c,v 1.42 2006/08/03 03:34:41 deraadt Exp $ */ 1/* $OpenBSD: auth-rh-rsa.c,v 1.43 2010/03/04 10:36:03 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
@@ -44,6 +44,9 @@ auth_rhosts_rsa_key_allowed(struct passwd *pw, char *cuser, char *chost,
44{ 44{
45 HostStatus host_status; 45 HostStatus host_status;
46 46
47 if (auth_key_is_revoked(client_host_key))
48 return 0;
49
47 /* Check if we would accept it using rhosts authentication. */ 50 /* Check if we would accept it using rhosts authentication. */
48 if (!auth_rhosts(pw, cuser)) 51 if (!auth_rhosts(pw, cuser))
49 return 0; 52 return 0;
diff --git a/auth-rsa.c b/auth-rsa.c
index bf5462076..65571a890 100644
--- a/auth-rsa.c
+++ b/auth-rsa.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth-rsa.c,v 1.73 2008/07/02 12:03:51 dtucker Exp $ */ 1/* $OpenBSD: auth-rsa.c,v 1.74 2010/03/04 10:36:03 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
@@ -94,6 +94,9 @@ auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16])
94 MD5_CTX md; 94 MD5_CTX md;
95 int len; 95 int len;
96 96
97 if (auth_key_is_revoked(key))
98 return 0;
99
97 /* don't allow short keys */ 100 /* don't allow short keys */
98 if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { 101 if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
99 error("auth_rsa_verify_response: RSA modulus too small: %d < minimum %d bits", 102 error("auth_rsa_verify_response: RSA modulus too small: %d < minimum %d bits",
diff --git a/auth.c b/auth.c
index ab9c69fb8..e680efbcc 100644
--- a/auth.c
+++ b/auth.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth.c,v 1.84 2010/02/09 06:18:46 djm Exp $ */ 1/* $OpenBSD: auth.c,v 1.85 2010/03/04 10:36:03 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * 4 *
@@ -69,6 +69,7 @@
69#ifdef GSSAPI 69#ifdef GSSAPI
70#include "ssh-gss.h" 70#include "ssh-gss.h"
71#endif 71#endif
72#include "authfile.h"
72#include "monitor_wrap.h" 73#include "monitor_wrap.h"
73 74
74/* import */ 75/* import */
@@ -582,6 +583,34 @@ getpwnamallow(const char *user)
582 return (NULL); 583 return (NULL);
583} 584}
584 585
586/* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */
587int
588auth_key_is_revoked(Key *key)
589{
590 char *key_fp;
591
592 if (options.revoked_keys_file == NULL)
593 return 0;
594
595 switch (key_in_file(key, options.revoked_keys_file, 0)) {
596 case 0:
597 /* key not revoked */
598 return 0;
599 case -1:
600 /* Error opening revoked_keys_file: refuse all keys */
601 error("Revoked keys file is unreadable: refusing public key "
602 "authentication");
603 return 1;
604 case 1:
605 /* Key revoked */
606 key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
607 error("%s key %s is revoked", key_type(key), key_fp);
608 xfree(key_fp);
609 return 1;
610 }
611 fatal("key_in_file returned junk");
612}
613
585void 614void
586auth_debug_add(const char *fmt,...) 615auth_debug_add(const char *fmt,...)
587{ 616{
diff --git a/auth.h b/auth.h
index 117485ca9..a65b87dd1 100644
--- a/auth.h
+++ b/auth.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth.h,v 1.64 2010/02/26 20:29:54 djm Exp $ */ 1/* $OpenBSD: auth.h,v 1.65 2010/03/04 10:36:03 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2000 Markus Friedl. All rights reserved. 4 * Copyright (c) 2000 Markus Friedl. All rights reserved.
@@ -171,6 +171,7 @@ char *authorized_keys_file(struct passwd *);
171char *authorized_keys_file2(struct passwd *); 171char *authorized_keys_file2(struct passwd *);
172 172
173FILE *auth_openkeyfile(const char *, struct passwd *, int); 173FILE *auth_openkeyfile(const char *, struct passwd *, int);
174int auth_key_is_revoked(Key *);
174 175
175HostStatus 176HostStatus
176check_key_in_hostfiles(struct passwd *, Key *, const char *, 177check_key_in_hostfiles(struct passwd *, Key *, const char *,
diff --git a/auth2-hostbased.c b/auth2-hostbased.c
index 041051c53..721646520 100644
--- a/auth2-hostbased.c
+++ b/auth2-hostbased.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth2-hostbased.c,v 1.12 2008/07/17 08:51:07 djm Exp $ */ 1/* $OpenBSD: auth2-hostbased.c,v 1.13 2010/03/04 10:36:03 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * 4 *
@@ -145,6 +145,9 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
145 HostStatus host_status; 145 HostStatus host_status;
146 int len; 146 int len;
147 147
148 if (auth_key_is_revoked(key))
149 return 0;
150
148 resolvedname = get_canonical_hostname(options.use_dns); 151 resolvedname = get_canonical_hostname(options.use_dns);
149 ipaddr = get_remote_ipaddr(); 152 ipaddr = get_remote_ipaddr();
150 153
diff --git a/auth2-pubkey.c b/auth2-pubkey.c
index 66ca5266b..51aa77487 100644
--- a/auth2-pubkey.c
+++ b/auth2-pubkey.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth2-pubkey.c,v 1.20 2010/02/26 20:29:54 djm Exp $ */ 1/* $OpenBSD: auth2-pubkey.c,v 1.21 2010/03/04 10:36:03 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * 4 *
@@ -56,6 +56,7 @@
56#endif 56#endif
57#include "monitor_wrap.h" 57#include "monitor_wrap.h"
58#include "misc.h" 58#include "misc.h"
59#include "authfile.h"
59 60
60/* import */ 61/* import */
61extern ServerOptions options; 62extern ServerOptions options;
@@ -276,6 +277,47 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file)
276 return found_key; 277 return found_key;
277} 278}
278 279
280/* Authenticate a certificate key against TrustedUserCAKeys */
281static int
282user_cert_trusted_ca(struct passwd *pw, Key *key)
283{
284 char *key_fp, *ca_fp;
285 const char *reason;
286 int ret = 0;
287
288 if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL)
289 return 0;
290
291 key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
292 ca_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
293
294 if (key_in_file(key->cert->signature_key,
295 options.trusted_user_ca_keys, 1) != 1) {
296 debug2("%s: CA %s %s is not listed in %s", __func__,
297 key_type(key->cert->signature_key), ca_fp,
298 options.trusted_user_ca_keys);
299 goto out;
300 }
301 if (key_cert_check_authority(key, 0, 1, pw->pw_name, &reason) != 0) {
302 error("%s", reason);
303 auth_debug_add("%s", reason);
304 goto out;
305 }
306 if (auth_cert_constraints(&key->cert->constraints, pw) != 0)
307 goto out;
308
309 verbose("%s certificate %s allowed by trusted %s key %s",
310 key_type(key), key_fp, key_type(key->cert->signature_key), ca_fp);
311 ret = 1;
312
313 out:
314 if (key_fp != NULL)
315 xfree(key_fp);
316 if (ca_fp != NULL)
317 xfree(ca_fp);
318 return ret;
319}
320
279/* check whether given key is in .ssh/authorized_keys* */ 321/* check whether given key is in .ssh/authorized_keys* */
280int 322int
281user_key_allowed(struct passwd *pw, Key *key) 323user_key_allowed(struct passwd *pw, Key *key)
@@ -283,6 +325,15 @@ user_key_allowed(struct passwd *pw, Key *key)
283 int success; 325 int success;
284 char *file; 326 char *file;
285 327
328 if (auth_key_is_revoked(key))
329 return 0;
330 if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key))
331 return 0;
332
333 success = user_cert_trusted_ca(pw, key);
334 if (success)
335 return success;
336
286 file = authorized_keys_file(pw); 337 file = authorized_keys_file(pw);
287 success = user_key_allowed2(pw, key, file); 338 success = user_key_allowed2(pw, key, file);
288 xfree(file); 339 xfree(file);
diff --git a/authfile.c b/authfile.c
index 2c615709d..224c6aa80 100644
--- a/authfile.c
+++ b/authfile.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: authfile.c,v 1.79 2010/01/12 00:16:47 dtucker Exp $ */ 1/* $OpenBSD: authfile.c,v 1.80 2010/03/04 10:36:03 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
@@ -692,3 +692,65 @@ key_load_public(const char *filename, char **commentp)
692 key_free(pub); 692 key_free(pub);
693 return NULL; 693 return NULL;
694} 694}
695
696/*
697 * Returns 1 if the specified "key" is listed in the file "filename",
698 * 0 if the key is not listed or -1 on error.
699 * If strict_type is set then the key type must match exactly,
700 * otherwise a comparison that ignores certficiate data is performed.
701 */
702int
703key_in_file(Key *key, const char *filename, int strict_type)
704{
705 FILE *f;
706 char line[SSH_MAX_PUBKEY_BYTES];
707 char *cp;
708 u_long linenum = 0;
709 int ret = 0;
710 Key *pub;
711 int (*key_compare)(const Key *, const Key *) = strict_type ?
712 key_equal : key_equal_public;
713
714 if ((f = fopen(filename, "r")) == NULL) {
715 if (errno == ENOENT) {
716 debug("%s: keyfile \"%s\" missing", __func__, filename);
717 return 0;
718 } else {
719 error("%s: could not open keyfile \"%s\": %s", __func__,
720 filename, strerror(errno));
721 return -1;
722 }
723 }
724
725 while (read_keyfile_line(f, filename, line, sizeof(line),
726 &linenum) != -1) {
727 cp = line;
728
729 /* Skip leading whitespace. */
730 for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
731 ;
732
733 /* Skip comments and empty lines */
734 switch (*cp) {
735 case '#':
736 case '\n':
737 case '\0':
738 continue;
739 }
740
741 pub = key_new(KEY_UNSPEC);
742 if (key_read(pub, &cp) != 1) {
743 key_free(pub);
744 continue;
745 }
746 if (key_compare(key, pub)) {
747 ret = 1;
748 key_free(pub);
749 break;
750 }
751 key_free(pub);
752 }
753 fclose(f);
754 return ret;
755}
756
diff --git a/authfile.h b/authfile.h
index a6c74934d..6dfa478e7 100644
--- a/authfile.h
+++ b/authfile.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: authfile.h,v 1.13 2006/04/25 08:02:27 dtucker Exp $ */ 1/* $OpenBSD: authfile.h,v 1.14 2010/03/04 10:36:03 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -22,5 +22,6 @@ Key *key_load_private(const char *, const char *, char **);
22Key *key_load_private_type(int, const char *, const char *, char **, int *); 22Key *key_load_private_type(int, const char *, const char *, char **, int *);
23Key *key_load_private_pem(int, int, const char *, char **); 23Key *key_load_private_pem(int, int, const char *, char **);
24int key_perm_ok(int, const char *); 24int key_perm_ok(int, const char *);
25int key_in_file(Key *, const char *, int);
25 26
26#endif 27#endif
diff --git a/hostfile.c b/hostfile.c
index fc7f84c79..afab6dad1 100644
--- a/hostfile.c
+++ b/hostfile.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: hostfile.c,v 1.47 2010/02/26 20:29:54 djm Exp $ */ 1/* $OpenBSD: hostfile.c,v 1.48 2010/03/04 10:36:03 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
@@ -183,6 +183,41 @@ hostfile_check_key(int bits, const Key *key, const char *host, const char *filen
183 return 1; 183 return 1;
184} 184}
185 185
186static enum { MRK_ERROR, MRK_NONE, MRK_REVOKE, MRK_CA }
187check_markers(char **cpp)
188{
189 char marker[32], *sp, *cp = *cpp;
190 int ret = MRK_NONE;
191
192 while (*cp == '@') {
193 /* Only one marker is allowed */
194 if (ret != MRK_NONE)
195 return MRK_ERROR;
196 /* Markers are terminated by whitespace */
197 if ((sp = strchr(cp, ' ')) == NULL &&
198 (sp = strchr(cp, '\t')) == NULL)
199 return MRK_ERROR;
200 /* Extract marker for comparison */
201 if (sp <= cp + 1 || sp >= cp + sizeof(marker))
202 return MRK_ERROR;
203 memcpy(marker, cp, sp - cp);
204 marker[sp - cp] = '\0';
205 if (strcmp(marker, CA_MARKER) == 0)
206 ret = MRK_CA;
207 else if (strcmp(marker, REVOKE_MARKER) == 0)
208 ret = MRK_REVOKE;
209 else
210 return MRK_ERROR;
211
212 /* Skip past marker and any whitespace that follows it */
213 cp = sp;
214 for (; *cp == ' ' || *cp == '\t'; cp++)
215 ;
216 }
217 *cpp = cp;
218 return ret;
219}
220
186/* 221/*
187 * Checks whether the given host (which must be in all lowercase) is already 222 * Checks whether the given host (which must be in all lowercase) is already
188 * in the list of our known hosts. Returns HOST_OK if the host is known and 223 * in the list of our known hosts. Returns HOST_OK if the host is known and
@@ -195,17 +230,21 @@ hostfile_check_key(int bits, const Key *key, const char *host, const char *filen
195 230
196static HostStatus 231static HostStatus
197check_host_in_hostfile_by_key_or_type(const char *filename, 232check_host_in_hostfile_by_key_or_type(const char *filename,
198 const char *host, const Key *key, int keytype, Key *found, int *numret) 233 const char *host, const Key *key, int keytype, Key *found,
234 int want_revocation, int *numret)
199{ 235{
200 FILE *f; 236 FILE *f;
201 char line[8192]; 237 char line[8192];
202 int linenum = 0, want_cert = key_is_cert(key); 238 int want, have, linenum = 0, want_cert = key_is_cert(key);
203 u_int kbits; 239 u_int kbits;
204 char *cp, *cp2, *hashed_host; 240 char *cp, *cp2, *hashed_host;
205 HostStatus end_return; 241 HostStatus end_return;
206 242
207 debug3("check_host_in_hostfile: host %s filename %s", host, filename); 243 debug3("check_host_in_hostfile: host %s filename %s", host, filename);
208 244
245 if (want_revocation && (key == NULL || keytype != 0 || found != NULL))
246 fatal("%s: invalid arguments", __func__);
247
209 /* Open the file containing the list of known hosts. */ 248 /* Open the file containing the list of known hosts. */
210 f = fopen(filename, "r"); 249 f = fopen(filename, "r");
211 if (!f) 250 if (!f)
@@ -229,21 +268,18 @@ check_host_in_hostfile_by_key_or_type(const char *filename,
229 if (!*cp || *cp == '#' || *cp == '\n') 268 if (!*cp || *cp == '#' || *cp == '\n')
230 continue; 269 continue;
231 270
232 /* 271 if (want_revocation)
233 * Ignore CA keys when looking for raw keys. 272 want = MRK_REVOKE;
234 * Ignore raw keys when looking for CA keys. 273 else if (want_cert)
235 */ 274 want = MRK_CA;
236 if (strncasecmp(cp, CA_MARKER, sizeof(CA_MARKER) - 1) == 0 && 275 else
237 (cp[sizeof(CA_MARKER) - 1] == ' ' || 276 want = MRK_NONE;
238 cp[sizeof(CA_MARKER) - 1] == '\t')) { 277
239 if (want_cert) { 278 if ((have = check_markers(&cp)) == MRK_ERROR) {
240 /* Skip the marker and following whitespace */ 279 verbose("%s: invalid marker at %s:%d",
241 cp += sizeof(CA_MARKER); 280 __func__, filename, linenum);
242 for (; *cp == ' ' || *cp == '\t'; cp++) 281 continue;
243 ; 282 } else if (want != have)
244 } else
245 continue;
246 } else if (want_cert)
247 continue; 283 continue;
248 284
249 /* Find the end of the host name portion. */ 285 /* Find the end of the host name portion. */
@@ -267,6 +303,9 @@ check_host_in_hostfile_by_key_or_type(const char *filename,
267 /* Got a match. Skip host name. */ 303 /* Got a match. Skip host name. */
268 cp = cp2; 304 cp = cp2;
269 305
306 if (want_revocation)
307 found = key_new(KEY_UNSPEC);
308
270 /* 309 /*
271 * Extract the key from the line. This will skip any leading 310 * Extract the key from the line. This will skip any leading
272 * whitespace. Ignore badly formatted lines. 311 * whitespace. Ignore badly formatted lines.
@@ -289,6 +328,24 @@ check_host_in_hostfile_by_key_or_type(const char *filename,
289 if (!hostfile_check_key(kbits, found, host, filename, linenum)) 328 if (!hostfile_check_key(kbits, found, host, filename, linenum))
290 continue; 329 continue;
291 330
331 if (want_revocation) {
332 if (key_is_cert(key) &&
333 key_equal_public(key->cert->signature_key, found)) {
334 verbose("check_host_in_hostfile: revoked CA "
335 "line %d", linenum);
336 key_free(found);
337 return HOST_REVOKED;
338 }
339 if (key_equal_public(key, found)) {
340 verbose("check_host_in_hostfile: revoked key "
341 "line %d", linenum);
342 key_free(found);
343 return HOST_REVOKED;
344 }
345 key_free(found);
346 continue;
347 }
348
292 /* Check if the current key is the same as the given key. */ 349 /* Check if the current key is the same as the given key. */
293 if (want_cert && key_equal(key->cert->signature_key, found)) { 350 if (want_cert && key_equal(key->cert->signature_key, found)) {
294 /* Found CA cert for key */ 351 /* Found CA cert for key */
@@ -325,8 +382,11 @@ check_host_in_hostfile(const char *filename, const char *host, const Key *key,
325{ 382{
326 if (key == NULL) 383 if (key == NULL)
327 fatal("no key to look up"); 384 fatal("no key to look up");
328 return (check_host_in_hostfile_by_key_or_type(filename, host, key, 0, 385 if (check_host_in_hostfile_by_key_or_type(filename, host,
329 found, numret)); 386 key, 0, NULL, 1, NULL) == HOST_REVOKED)
387 return HOST_REVOKED;
388 return check_host_in_hostfile_by_key_or_type(filename, host, key, 0,
389 found, 0, numret);
330} 390}
331 391
332int 392int
@@ -334,7 +394,7 @@ lookup_key_in_hostfile_by_type(const char *filename, const char *host,
334 int keytype, Key *found, int *numret) 394 int keytype, Key *found, int *numret)
335{ 395{
336 return (check_host_in_hostfile_by_key_or_type(filename, host, NULL, 396 return (check_host_in_hostfile_by_key_or_type(filename, host, NULL,
337 keytype, found, numret) == HOST_FOUND); 397 keytype, found, 0, numret) == HOST_FOUND);
338} 398}
339 399
340/* 400/*
diff --git a/hostfile.h b/hostfile.h
index ebac1e4f1..1d460c1a9 100644
--- a/hostfile.h
+++ b/hostfile.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: hostfile.h,v 1.17 2010/02/26 20:29:54 djm Exp $ */ 1/* $OpenBSD: hostfile.h,v 1.18 2010/03/04 10:36:03 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -15,7 +15,7 @@
15#define HOSTFILE_H 15#define HOSTFILE_H
16 16
17typedef enum { 17typedef enum {
18 HOST_OK, HOST_NEW, HOST_CHANGED, HOST_FOUND 18 HOST_OK, HOST_NEW, HOST_CHANGED, HOST_REVOKED, HOST_FOUND
19} HostStatus; 19} HostStatus;
20 20
21int hostfile_read_key(char **, u_int *, Key *); 21int hostfile_read_key(char **, u_int *, Key *);
@@ -29,6 +29,7 @@ int lookup_key_in_hostfile_by_type(const char *, const char *,
29#define HASH_DELIM '|' 29#define HASH_DELIM '|'
30 30
31#define CA_MARKER "@cert-authority" 31#define CA_MARKER "@cert-authority"
32#define REVOKE_MARKER "@revoked"
32 33
33char *host_hash(const char *, const char *, u_int); 34char *host_hash(const char *, const char *, u_int);
34 35
diff --git a/servconf.c b/servconf.c
index 0a6cdb655..f9e2f2dfd 100644
--- a/servconf.c
+++ b/servconf.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: servconf.c,v 1.203 2010/02/26 20:29:54 djm Exp $ */ 1/* $OpenBSD: servconf.c,v 1.204 2010/03/04 10:36:03 djm Exp $ */
2/* 2/*
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 * All rights reserved 4 * All rights reserved
@@ -129,6 +129,8 @@ initialize_server_options(ServerOptions *options)
129 options->adm_forced_command = NULL; 129 options->adm_forced_command = NULL;
130 options->chroot_directory = NULL; 130 options->chroot_directory = NULL;
131 options->zero_knowledge_password_authentication = -1; 131 options->zero_knowledge_password_authentication = -1;
132 options->revoked_keys_file = NULL;
133 options->trusted_user_ca_keys = NULL;
132} 134}
133 135
134void 136void
@@ -308,6 +310,7 @@ typedef enum {
308 sMatch, sPermitOpen, sForceCommand, sChrootDirectory, 310 sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
309 sUsePrivilegeSeparation, sAllowAgentForwarding, 311 sUsePrivilegeSeparation, sAllowAgentForwarding,
310 sZeroKnowledgePasswordAuthentication, sHostCertificate, 312 sZeroKnowledgePasswordAuthentication, sHostCertificate,
313 sRevokedKeys, sTrustedUserCAKeys,
311 sDeprecated, sUnsupported 314 sDeprecated, sUnsupported
312} ServerOpCodes; 315} ServerOpCodes;
313 316
@@ -427,6 +430,8 @@ static struct {
427 { "forcecommand", sForceCommand, SSHCFG_ALL }, 430 { "forcecommand", sForceCommand, SSHCFG_ALL },
428 { "chrootdirectory", sChrootDirectory, SSHCFG_ALL }, 431 { "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
429 { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL }, 432 { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
433 { "revokedkeys", sRevokedKeys, SSHCFG_ALL },
434 { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
430 { NULL, sBadOption, 0 } 435 { NULL, sBadOption, 0 }
431}; 436};
432 437
@@ -1323,6 +1328,14 @@ process_server_config_line(ServerOptions *options, char *line,
1323 *charptr = xstrdup(arg); 1328 *charptr = xstrdup(arg);
1324 break; 1329 break;
1325 1330
1331 case sTrustedUserCAKeys:
1332 charptr = &options->trusted_user_ca_keys;
1333 goto parse_filename;
1334
1335 case sRevokedKeys:
1336 charptr = &options->revoked_keys_file;
1337 goto parse_filename;
1338
1326 case sDeprecated: 1339 case sDeprecated:
1327 logit("%s line %d: Deprecated option %s", 1340 logit("%s line %d: Deprecated option %s",
1328 filename, linenum, arg); 1341 filename, linenum, arg);
@@ -1437,6 +1450,8 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
1437 return; 1450 return;
1438 M_CP_STROPT(adm_forced_command); 1451 M_CP_STROPT(adm_forced_command);
1439 M_CP_STROPT(chroot_directory); 1452 M_CP_STROPT(chroot_directory);
1453 M_CP_STROPT(trusted_user_ca_keys);
1454 M_CP_STROPT(revoked_keys_file);
1440} 1455}
1441 1456
1442#undef M_CP_INTOPT 1457#undef M_CP_INTOPT
@@ -1656,6 +1671,8 @@ dump_config(ServerOptions *o)
1656 dump_cfg_string(sAuthorizedKeysFile2, o->authorized_keys_file2); 1671 dump_cfg_string(sAuthorizedKeysFile2, o->authorized_keys_file2);
1657 dump_cfg_string(sForceCommand, o->adm_forced_command); 1672 dump_cfg_string(sForceCommand, o->adm_forced_command);
1658 dump_cfg_string(sChrootDirectory, o->chroot_directory); 1673 dump_cfg_string(sChrootDirectory, o->chroot_directory);
1674 dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys);
1675 dump_cfg_string(sRevokedKeys, o->revoked_keys_file);
1659 1676
1660 /* string arguments requiring a lookup */ 1677 /* string arguments requiring a lookup */
1661 dump_cfg_string(sLogLevel, log_level_name(o->log_level)); 1678 dump_cfg_string(sLogLevel, log_level_name(o->log_level));
diff --git a/servconf.h b/servconf.h
index c5c9c6ecd..860009f9c 100644
--- a/servconf.h
+++ b/servconf.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: servconf.h,v 1.91 2010/02/26 20:29:54 djm Exp $ */ 1/* $OpenBSD: servconf.h,v 1.92 2010/03/04 10:36:03 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -154,6 +154,8 @@ typedef struct {
154 int num_permitted_opens; 154 int num_permitted_opens;
155 155
156 char *chroot_directory; 156 char *chroot_directory;
157 char *revoked_keys_file;
158 char *trusted_user_ca_keys;
157} ServerOptions; 159} ServerOptions;
158 160
159void initialize_server_options(ServerOptions *); 161void initialize_server_options(ServerOptions *);
diff --git a/ssh-keygen.c b/ssh-keygen.c
index f910dce38..c2120bbc1 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-keygen.c,v 1.180 2010/03/02 23:20:57 djm Exp $ */ 1/* $OpenBSD: ssh-keygen.c,v 1.181 2010/03/04 10:36:03 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
diff --git a/ssh.1 b/ssh.1
index 183dc277f..e8a4e5953 100644
--- a/ssh.1
+++ b/ssh.1
@@ -34,8 +34,8 @@
34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36.\" 36.\"
37.\" $OpenBSD: ssh.1,v 1.296 2010/02/26 22:09:28 jmc Exp $ 37.\" $OpenBSD: ssh.1,v 1.297 2010/03/04 10:36:03 djm Exp $
38.Dd $Mdocdate: February 26 2010 $ 38.Dd $Mdocdate: March 4 2010 $
39.Dt SSH 1 39.Dt SSH 1
40.Os 40.Os
41.Sh NAME 41.Sh NAME
@@ -1121,6 +1121,22 @@ See the
1121section of 1121section of
1122.Xr ssh-keygen 1 1122.Xr ssh-keygen 1
1123for more details. 1123for more details.
1124.Pp
1125Keys may be also be marked as revoked using the
1126.Dq @revoked
1127marker.
1128Revoked keys will always trigger a warning when encountered and the host
1129that presented them will be treated as untrusted.
1130For example:
1131.Pp
1132.Dl @revoked * ssh-rsa AAAAB5W...
1133.Pp
1134Revoking a key revokes it for direct use and as a certification authority.
1135Do not use both the
1136.Dq @cert-authority and
1137.Dq @revoked
1138markers on the same line.
1139.Pp
1124.Sh SSH-BASED VIRTUAL PRIVATE NETWORKS 1140.Sh SSH-BASED VIRTUAL PRIVATE NETWORKS
1125.Nm 1141.Nm
1126contains support for Virtual Private Network (VPN) tunnelling 1142contains support for Virtual Private Network (VPN) tunnelling
diff --git a/sshconnect.c b/sshconnect.c
index 35c2f49be..9de52224d 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshconnect.c,v 1.219 2010/02/26 20:29:54 djm Exp $ */ 1/* $OpenBSD: sshconnect.c,v 1.220 2010/03/04 10:36:03 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
@@ -859,6 +859,25 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
859 logit("Warning: Permanently added '%.200s' (%s) to the " 859 logit("Warning: Permanently added '%.200s' (%s) to the "
860 "list of known hosts.", hostp, type); 860 "list of known hosts.", hostp, type);
861 break; 861 break;
862 case HOST_REVOKED:
863 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
864 error("@ WARNING: REVOKED HOST KEY DETECTED! @");
865 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
866 error("The %s host key for %s is marked as revoked.", type, host);
867 error("This could mean that a stolen key is being used to");
868 error("impersonate this host.");
869
870 /*
871 * If strict host key checking is in use, the user will have
872 * to edit the key manually and we can only abort.
873 */
874 if (options.strict_host_key_checking) {
875 error("%s host key for %.200s was revoked and you have "
876 "requested strict checking.", type, host);
877 goto fail;
878 }
879 goto continue_unsafe;
880
862 case HOST_CHANGED: 881 case HOST_CHANGED:
863 if (want_cert) { 882 if (want_cert) {
864 /* 883 /*
@@ -908,6 +927,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
908 goto fail; 927 goto fail;
909 } 928 }
910 929
930 continue_unsafe:
911 /* 931 /*
912 * If strict host key checking has not been requested, allow 932 * If strict host key checking has not been requested, allow
913 * the connection but without MITM-able authentication or 933 * the connection but without MITM-able authentication or
@@ -1007,7 +1027,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
1007 return 0; 1027 return 0;
1008 1028
1009fail: 1029fail:
1010 if (want_cert) { 1030 if (want_cert && host_status != HOST_REVOKED) {
1011 /* 1031 /*
1012 * No matching certificate. Downgrade cert to raw key and 1032 * No matching certificate. Downgrade cert to raw key and
1013 * search normally. 1033 * search normally.
diff --git a/sshd_config.5 b/sshd_config.5
index 001114655..07e74e2b7 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -34,8 +34,8 @@
34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36.\" 36.\"
37.\" $OpenBSD: sshd_config.5,v 1.117 2010/02/26 20:29:54 djm Exp $ 37.\" $OpenBSD: sshd_config.5,v 1.118 2010/03/04 10:36:03 djm Exp $
38.Dd $Mdocdate: February 26 2010 $ 38.Dd $Mdocdate: March 4 2010 $
39.Dt SSHD_CONFIG 5 39.Dt SSHD_CONFIG 5
40.Os 40.Os
41.Sh NAME 41.Sh NAME
@@ -814,6 +814,11 @@ Specifies whether public key authentication is allowed.
814The default is 814The default is
815.Dq yes . 815.Dq yes .
816Note that this option applies to protocol version 2 only. 816Note that this option applies to protocol version 2 only.
817.It Cm RevokedKeys
818Specifies a list of revoked public keys.
819Keys listed in this file will be refused for public key authentication.
820Note that if this file is not readable, then public key authentication will
821be refused for all users.
817.It Cm RhostsRSAAuthentication 822.It Cm RhostsRSAAuthentication
818Specifies whether rhosts or /etc/hosts.equiv authentication together 823Specifies whether rhosts or /etc/hosts.equiv authentication together
819with successful RSA host authentication is allowed. 824with successful RSA host authentication is allowed.
@@ -889,6 +894,22 @@ This avoids infinitely hanging sessions.
889.Pp 894.Pp
890To disable TCP keepalive messages, the value should be set to 895To disable TCP keepalive messages, the value should be set to
891.Dq no . 896.Dq no .
897.It Cm TrustedUserCAKeys
898Specifies a file containing public keys of certificate authorities that are
899trusted sign user certificates for authentication.
900Keys are listed one per line, empty lines and comments starting with
901.Ql #
902are allowed.
903If a certificate is presented for authentication and has its signing CA key
904listed in this file, then it may be used for authentication for any user
905listed in the certificate's principals list.
906Note that certificates that lack a list of principals will not be permitted
907for authentication using
908.Cm TrustedUserCAKeys .
909For more details in certificates, please see the
910.Sx CERTIFICATES
911section in
912.Xr ssh-keygen 1 .
892.It Cm UseDNS 913.It Cm UseDNS
893Specifies whether 914Specifies whether
894.Xr sshd 8 915.Xr sshd 8