Use of non-user readable (null password) private keys

Jim Knoble jmknoble at jmknoble.cx
Wed Mar 28 08:15:55 EST 2001


Circa 2001-Mar-27 21:09:10 +0100 dixit Piete Brooks:

: I want to be able to give `group' or `other' access to capabilities.
:
: I do not want ACLs.

This is certainly something you ought to be able to do if you know what
you're doing.

Attached is a patch against OpenSSH-2.5.2p2 which implements relaxed
restrictions on key permissions under the following conditions:

  (1) You build openssh with ALLOW_RELAXED_KEY_PERMISSIONS defined
      (e.g., 'env CFLAGS=-DALLOW_RELAXED_KEY_PERMISSIONS ./configure').

  (2) You call ssh with the (new) '-G' option if you want your key to
      be group-accessible (ssh allows the key to have permissions up to
      0770)

        or

      You call ssh with the (new) '-W' option if you want your key to
      be world-accessible (ssh allows the key to have permissions up to
      0775).

Platonic Questioning Session:

  Socrates: Why didn't you make a config-file option for this?

  Diogenes: I considered making a config-file option (for
            /etc/ssh/ssh_config bzw. ~/.ssh/config), but decided
            against it because i think the user should have to say
            "Yes, i do in fact know what i'm doing" to use this
            facility.

  Socrates: Why do i have to build with that stupid #define?

  Diogenes: So that you don't blame me for the holes in your foot.

  Socrates: Why didn't you make ssh emit a warning when the permissions
            are relaxed?

  Diogenes: OpenSSH doesn't have a suitable warning facility.  The
            closest available function is error(), which only makes
            output appear on stderr if ssh is called with '-v'
            (verbose).  This should probably be fixed so that the
            regular warning (without -G or -W) appears regardless of
            whether ssh has been asked to be verbose, so that the user
	    knows that ssh is going to ignore the key.  But fixing that
	    is beyond the scope of this patch.

  Socrates: Why does ssh ask me for my passphrase if it's ignoring my
            private key due to relaxed permissions?

  Diogenes: Because the granularity of information returned by
            authfile.c:load_private_key() is too coarse.
	    load_private_key() really ought to return a status
	    which separates failure due to ownership/permissions from
	    failure due to bad passphrase or whatnot.  But fixing that
	    is beyond the scope of this patch.

  Socrates: Why can't i pass a umask to ssh instead of choosing group
            or world access only?

  Diogenes: Good question.  I considered this, but it's more ammunition
	    for foot-shooting, and i think it requires more thought
	    than i've been able to give it.  Opinions from other folks
	    are welcome.  In the meantime, have some of this
	    great-tasting herbal tea.

  Socrates: Why did you forget to attach the patch to this message?
            Are you stupid or something?
  
  Diogenes: Have some more tea.

--
jim knoble | jmknoble at jmknoble.cx | http://www.jmknoble.cx/
-------------- next part --------------
--- ./authfile.c.orig-keyperms	Sun Mar  4 23:59:27 2001
+++ ./authfile.c	Tue Mar 27 16:44:18 2001
@@ -497,11 +497,12 @@
 
 int
 load_private_key(const char *filename, const char *passphrase, Key *key,
-    char **comment_return)
+    int allow_relaxed_key_permissions, char **comment_return)
 {
 	int fd;
 	int ret = 0;
 	struct stat st;
+	unsigned int mode_mask = 077;
 
 	fd = open(filename, O_RDONLY);
 	if (fd < 0)
@@ -511,9 +512,14 @@
 #ifdef HAVE_CYGWIN
 	if (check_ntsec(filename))
 #endif
+	if (1 == allow_relaxed_key_permissions) {
+	    mode_mask = 07;
+	} else if (2 == allow_relaxed_key_permissions) {
+	    mode_mask = 01;
+	}
 	if (fstat(fd, &st) < 0 ||
 	    (st.st_uid != 0 && getuid() != 0 && st.st_uid != getuid()) ||
-	    (st.st_mode & 077) != 0) {
+	    (st.st_mode & mode_mask) != 0) {
 		close(fd);
 		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
 		error("@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @");
--- ./ssh.c.orig-keyperms	Sun Mar 18 17:38:16 2001
+++ ./ssh.c	Tue Mar 27 16:44:04 2001
@@ -145,6 +145,11 @@
 /* Should we execute a command or invoke a subsystem? */
 int subsystem_flag = 0;
 
+#ifndef ALLOW_RELAXED_KEY_PERMISSIONS
+const
+#endif
+int allow_relaxed_key_permissions = 0;
+
 /* Prints a help message to the user.  This function never returns. */
 
 void
@@ -163,6 +168,10 @@
 	fprintf(stderr, "  -x          Disable X11 connection forwarding.\n");
 	fprintf(stderr, "  -i file     Identity for public key authentication "
 	    "(default: ~/.ssh/identity)\n");
+#ifdef ALLOW_RELAXED_KEY_PERMISSIONS
+	fprintf(stderr, "  -G          Allow private key to be group-accessible.\n");
+	fprintf(stderr, "  -W          Allow private key to be world-accessible.\n");
+#endif
 	fprintf(stderr, "  -t          Tty; allocate a tty even if command is given.\n");
 	fprintf(stderr, "  -T          Do not allocate a tty.\n");
 	fprintf(stderr, "  -v          Verbose; display verbose debugging messages.\n");
@@ -375,6 +384,14 @@
 				    SSH_MAX_IDENTITY_FILES);
 			options.identity_files[options.num_identity_files++] = xstrdup(optarg);
 			break;
+#ifdef ALLOW_RELAXED_KEY_PERMISSIONS
+		case 'G':
+			allow_relaxed_key_permissions = 1;
+			break;
+		case 'W':
+			allow_relaxed_key_permissions = 2;
+			break;
+#endif
 		case 't':
 			if (tty_flag)
 				force_tty_flag = 1;
@@ -635,7 +652,7 @@
 		host_private_key = RSA_new();
 		k.type = KEY_RSA1;
 		k.rsa = host_private_key;
-		if (load_private_key(_PATH_HOST_KEY_FILE, "", &k, NULL))
+		if (load_private_key(_PATH_HOST_KEY_FILE, "", &k, 0, NULL))
 			host_private_key_loaded = 1;
 	}
 	/*
--- ./ssh-keygen.c.orig-keyperms	Sun Mar 18 17:38:16 2001
+++ ./ssh-keygen.c	Tue Mar 27 16:44:04 2001
@@ -115,9 +115,9 @@
 try_load_key(char *filename, Key *k)
 {
 	int success = 1;
-	if (!load_private_key(filename, "", k, NULL)) {
+	if (!load_private_key(filename, "", k, 0, NULL)) {
 		char *pass = read_passphrase("Enter passphrase: ", 1);
-		if (!load_private_key(filename, pass, k, NULL)) {
+		if (!load_private_key(filename, pass, k, 0, NULL)) {
 			success = 0;
 		}
 		memset(pass, 0, strlen(pass));
@@ -454,12 +454,12 @@
 	}
 	/* Try to load the file with empty passphrase. */
 	private = key_new(type);
-	if (!load_private_key(identity_file, "", private, &comment)) {
+	if (!load_private_key(identity_file, "", private, 0, &comment)) {
 		if (identity_passphrase)
 			old_passphrase = xstrdup(identity_passphrase);
 		else
 			old_passphrase = read_passphrase("Enter old passphrase: ", 1);
-		if (!load_private_key(identity_file, old_passphrase, private, &comment)) {
+		if (!load_private_key(identity_file, old_passphrase, private, 0, &comment)) {
 			memset(old_passphrase, 0, strlen(old_passphrase));
 			xfree(old_passphrase);
 			printf("Bad passphrase.\n");
@@ -543,7 +543,7 @@
 	}
 
 	private = key_new(KEY_RSA1);
-	if (load_private_key(identity_file, "", private, &comment))
+	if (load_private_key(identity_file, "", private, 0, &comment))
 		passphrase = xstrdup("");
 	else {
 		if (identity_passphrase)
@@ -553,7 +553,7 @@
 		else
 			passphrase = read_passphrase("Enter passphrase: ", 1);
 		/* Try to load using the passphrase. */
-		if (!load_private_key(identity_file, passphrase, private, &comment)) {
+		if (!load_private_key(identity_file, passphrase, private, 0, &comment)) {
 			memset(passphrase, 0, strlen(passphrase));
 			xfree(passphrase);
 			printf("Bad passphrase.\n");
--- ./sshconnect1.c.orig-keyperms	Thu Mar  8 19:12:23 2001
+++ ./sshconnect1.c	Tue Mar 27 16:44:04 2001
@@ -51,6 +51,12 @@
 extern Options options;
 extern char *__progname;
 
+extern
+#ifndef ALLOW_RELAXED_KEY_PERMISSIONS
+    const
+#endif
+    int allow_relaxed_key_permissions;
+
 /*
  * Checks if the user has an authentication agent, and if so, tries to
  * authenticate using the agent.
@@ -257,7 +263,8 @@
 	 * Load the private key.  Try first with empty passphrase; if it
 	 * fails, ask for a passphrase.
 	 */
-	if (!load_private_key(authfile, "", private, NULL)) {
+	if (!load_private_key(authfile, "", private,
+			      allow_relaxed_key_permissions, NULL)) {
 		char buf[300];
 		snprintf(buf, sizeof buf, "Enter passphrase for RSA key '%.100s': ",
 		    comment);
@@ -270,7 +277,8 @@
 		}
 
 		/* Load the authentication file using the pasphrase. */
-		if (!load_private_key(authfile, passphrase, private, NULL)) {
+		if (!load_private_key(authfile, passphrase, private,
+				      allow_relaxed_key_permissions, NULL)) {
 			memset(passphrase, 0, strlen(passphrase));
 			xfree(passphrase);
 			error("Bad passphrase.");
--- ./sshconnect2.c.orig-keyperms	Mon Mar 12 23:57:59 2001
+++ ./sshconnect2.c	Tue Mar 27 16:44:04 2001
@@ -61,6 +61,12 @@
 extern char *server_version_string;
 extern Options options;
 
+extern
+#ifndef ALLOW_RELAXED_KEY_PERMISSIONS
+    const
+#endif
+    int allow_relaxed_key_permissions;
+
 /*
  * SSH2 key exchange
  */
@@ -906,7 +912,8 @@
 		return NULL;
 	}
 	private = key_new(KEY_UNSPEC);
-	if (!load_private_key(filename, "", private, NULL)) {
+	if (!load_private_key(filename, "", private,
+			      allow_relaxed_key_permissions, NULL)) {
 		if (options.batch_mode) {
 			key_free(private);
 			return NULL;
@@ -917,7 +924,8 @@
 			passphrase = read_passphrase(prompt, 0);
 			if (strcmp(passphrase, "") != 0) {
 				success = load_private_key(filename,
-				    passphrase, private, NULL);
+				    passphrase, private,
+				    allow_relaxed_key_permissions, NULL);
 				quit = 0;
 			} else {
 				debug2("no passphrase given, try next key");
--- ./sshd.c.orig-keyperms	Mon Mar 19 06:36:20 2001
+++ ./sshd.c	Tue Mar 27 16:44:04 2001
@@ -482,7 +482,7 @@
 
 	/* Ok, try key with empty passphrase */
 	private = key_new(type);
-	if (load_private_key(filename, "", private, NULL)) {
+	if (load_private_key(filename, "", private, 0, NULL)) {
 		debug("load_private_key_autodetect: type %d %s",
 		    private->type, key_type(private));
 		return private;
--- ./authfile.h.orig-keyperms	Sun Nov  5 20:39:34 2000
+++ ./authfile.h	Tue Mar 27 16:44:04 2001
@@ -46,6 +46,7 @@
  */
 int
 load_private_key(const char *filename, const char *passphrase,
-    Key * private_key, char **comment_return);
+    Key * private_key, int allow_relaxed_key_permissions,
+    char **comment_return);
 
 #endif
--- ./ssh-add.c.orig-keyperms	Mon Mar 12 23:57:59 2001
+++ ./ssh-add.c	Tue Mar 27 16:44:04 2001
@@ -172,7 +172,7 @@
 
 	/* At first, try empty passphrase */
 	private = key_new(type);
-	success = load_private_key(filename, "", private, &comment);
+	success = load_private_key(filename, "", private, 0, &comment);
 	if (!success) {
 		printf("Need passphrase for %.200s\n", filename);
 		if (!interactive && askpass == NULL) {
@@ -193,7 +193,7 @@
 				xfree(saved_comment);
 				return;
 			}
-			success = load_private_key(filename, pass, private, &comment);
+			success = load_private_key(filename, pass, private, 0, &comment);
 			memset(pass, 0, strlen(pass));
 			xfree(pass);
 			if (success)


More information about the openssh-unix-dev mailing list