Adding 'name' key types

Nicolas Williams
Fri, 29 Jun 2001 22:09:06 -0000

Here's a patch to OpenSSH + GSS patches that implements the below. I can
now put this in authorized_keys2 files:

ssh-ext-named:krb5 !someuser at SOMEREALM

It works well so far.

Cheers,

Nico

Index: 2_9_p2_w_gss_and_krb5.4/key.h
--- 2_9_p2_w_gss_and_krb5.4/key.h Tue, 26 Jun 2001 16:27:13 -0400 willian
(OpenSSH/j/7_key.h 1.2 644)
+++ 2_9_p2_w_gss_krb5_named_keys.1/key.h Fri, 29 Jun 2001 18:00:47 -0400 willian
(OpenSSH/j/7_key.h 1.3 644)
@@ -35,7 +35,8 @@
 	KEY_RSA,
 	KEY_DSA,
 	KEY_NULL,
-	KEY_UNSPEC
+	KEY_UNSPEC,
+	KEY_NAME
 };
 enum fp_type {
 	SSH_FP_SHA1,
@@ -49,6 +50,9 @@
 	int	type;
 	RSA	*rsa;
 	DSA	*dsa;
+	u_char	*name;
+	u_int	name_len;
+	char	*name_type;
 };

 Key	*key_new(int type);
Index: 2_9_p2_w_gss_and_krb5.4/key.c
--- 2_9_p2_w_gss_and_krb5.4/key.c Tue, 26 Jun 2001 16:27:13 -0400 willian
(OpenSSH/j/8_key.c 1.2 644)
+++ 2_9_p2_w_gss_krb5_named_keys.1/key.c Fri, 29 Jun 2001 18:00:47 -0400 willian
(OpenSSH/j/8_key.c 1.3 644)
@@ -56,6 +56,8 @@
 	k->type = type;
 	k->dsa = NULL;
 	k->rsa = NULL;
+	k->name = NULL;
+	k->name_len = NULL;
 	switch (k->type) {
 	case KEY_RSA1:
 	case KEY_RSA:
@@ -72,6 +74,7 @@
 		dsa->pub_key = BN_new();
 		k->dsa = dsa;
 		break;
+	case KEY_NAME:
 	case KEY_UNSPEC:
 		break;
 	default:
@@ -119,6 +122,11 @@
 			DSA_free(k->dsa);
 		k->dsa = NULL;
 		break;
+	case KEY_NAME:
+		if (k->name != NULL)
+			xfree(k->name);
+		k->name_len = 0;
+		break;
 	case KEY_UNSPEC:
 		break;
 	default:
@@ -130,8 +138,9 @@
 int
 key_equal(Key *a, Key *b)
 {
-	if (a == NULL || b == NULL || a->type != b->type)
+	if (a == NULL || b == NULL || a->type != b->type) {
 		return 0;
+	}
 	switch (a->type) {
 	case KEY_RSA1:
 	case KEY_RSA:
@@ -146,6 +155,17 @@
 		    BN_cmp(a->dsa->g, b->dsa->g) == 0 &&
 		    BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
 		break;
+	case KEY_NAME:
+		if ((a->name_type == NULL && b->name_type == NULL) ||
+		    (a->name_type == b->name_type))
+			return (a->name_len == b->name_len) &&
+			    (memcmp(a->name, b->name, a->name_len) == 0);
+		if (a->name_type == NULL || b->name_type == NULL)
+			return 0;
+		if (strncmp(a->name_type, b->name_type, strlen(b->name_type)) == 0)
+			return (a->name_len == b->name_len) &&
+			    (memcmp(a->name, b->name, a->name_len) == 0);
+		break;
 	default:
 		fatal("key_equal: bad key type %d", a->type);
 		break;
@@ -160,7 +180,7 @@
 	EVP_MD_CTX ctx;
 	u_char *blob = NULL;
 	u_char *retval = NULL;
-	int len = 0;
+	u_int len = 0;
 	int nlen, elen;

 	*dgst_raw_length = 0;
@@ -363,11 +383,12 @@
 {
 	Key *k;
 	int success = -1;
-	char *cp, *space;
+	char *cp, *space, *name_type;
 	int len, n, type;
 	u_int bits;
-	u_char *blob;
+	u_char *blob = NULL;

+	name_type = NULL;
 	cp = *cpp;

 	switch(ret->type) {
@@ -390,6 +411,7 @@
 	case KEY_UNSPEC:
 	case KEY_RSA:
 	case KEY_DSA:
+	case KEY_NAME:
 		space = strchr(cp, ' ');
 		if (space == NULL) {
 			debug3("key_read: no space");
@@ -397,6 +419,17 @@
 		}
 		*space = '\0';
 		type = key_type_from_name(cp);
+		if (type == KEY_NAME) {
+			char * colon = NULL;
+
+			colon = strchr(cp, ':');
+
+			debug3("key_read: handling typed named key, %s, colon at %x", cp,
colon);
+			if (colon != NULL && *(++colon) != '\0') {
+				name_type = xstrdup(colon);
+			} else
+				name_type == NULL;
+		}
 		*space = ' ';
 		if (type == KEY_UNSPEC) {
 			debug3("key_read: no key found");
@@ -414,26 +447,60 @@
 			debug3("key_read: type mismatch");
 			return 0;
 		}
-		len = 2*strlen(cp);
-		blob = xmalloc(len);
-		n = uudecode(cp, blob, len);
-		if (n < 0) {
-			error("key_read: uudecode %s failed", cp);
-			return -1;
+		if (ret->type == KEY_NAME && *cp == '!') {
+			cp++;
+			space = strchr(cp, '\n');
+			if (space != NULL)
+				*space = '\0';
+			debug3("key_read: reading named key %s", cp);
+			k = key_new(ret->type);
+			k->name = (unsigned char *) xstrdup(cp);
+			k->name_len = strlen(cp);
+			k->name_type = name_type;
+			*space = '\n';
+		} else {
+			len = 2*strlen(cp);
+			blob = xmalloc(len);
+			n = uudecode(cp, blob, len);
+			if (n < 0) {
+				error("key_read: uudecode %s failed", cp);
+				return -1;
+			}
+			if (ret->type == KEY_NAME) {
+				debug3("key_read: reading uuencoded key %s", blob);
+				k = key_new(ret->type);
+				k->name = blob;
+				k->name_len = strlen(blob);
+				k->name_type = name_type;
+			}
+			else {
+				k = key_from_blob(blob, n);
+			}
 		}
-		k = key_from_blob(blob, n);
 		if (k == NULL) {
 			error("key_read: key_from_blob %s failed", cp);
 			return -1;
 		}
-		xfree(blob);
+		if (blob != NULL)
+			xfree(blob);
 		if (k->type != type) {
 			error("key_read: type mismatch: encoding error");
 			key_free(k);
 			return -1;
 		}
 /*XXXX*/
-		if (ret->type == KEY_RSA) {
+		if (ret->type == KEY_NAME) {
+			/*
+			if (ret->name != NULL)
+				xfree(ret->name);
+			 */
+			ret->name = k->name;
+			ret->name_len = k->name_len;
+			ret->name_type = k->name_type;
+			k->name = NULL;
+			k->name_len = 0;
+			success = 1;
+		} else if (ret->type == KEY_RSA) {
 			if (ret->rsa != NULL)
 				RSA_free(ret->rsa);
 			ret->rsa = k->rsa;
@@ -487,7 +554,7 @@
 		}
 	} else if ((key->type == KEY_DSA && key->dsa != NULL) ||
 	    (key->type == KEY_RSA && key->rsa != NULL)) {
-		int len, n;
+		u_int len, n;
 		u_char *blob, *uu;
 		key_to_blob(key, &blob, &len);
 		uu = xmalloc(2*len);
@@ -498,6 +565,19 @@
 		}
 		xfree(blob);
 		xfree(uu);
+	} else if (key->type == KEY_NAME && key->name != NULL &&
+		   key->name_len) {
+		int n;
+		u_char *blob, *uu;
+		uu = xmalloc(2*(key->name_len));
+		blob = xstrdup(key->name);
+		n = uuencode(blob, key->name_len, uu, key->name_len);
+		if (n > 0) {
+			fprintf(f, "%s %s", key_ssh_name(key), uu);
+			success = 1;
+		}
+		xfree(blob);
+		xfree(uu);
 	}
 	return success;
 }
@@ -514,6 +594,9 @@
 	case KEY_DSA:
 		return "DSA";
 		break;
+	case KEY_NAME:
+		return "Named";
+		break;
 	}
 	return "unknown";
 }
@@ -527,6 +610,9 @@
 	case KEY_DSA:
 		return "ssh-dss";
 		break;
+	case KEY_NAME:
+		return "ssh-ext-named";
+		break;
 	}
 	return "ssh-unknown";
 }
@@ -604,6 +690,11 @@
 		BN_copy(n->rsa->n, k->rsa->n);
 		BN_copy(n->rsa->e, k->rsa->e);
 		break;
+	case KEY_NAME:
+		n->name_len = k->name_len;
+		n->name = xmalloc(k->name_len);
+		memcpy(n->name, k->name, n->name_len);
+		break;
 	default:
 		fatal("key_from_private: unknown type %d", k->type);
 		break;
@@ -624,6 +715,11 @@
 		return KEY_RSA;
 	} else if (strcmp(name, "ssh-dss") == 0){
 		return KEY_DSA;
+	} else if (strcmp(name, "ssh-ext-named") == 0){
+		return KEY_NAME;
+	} else if (strncmp(name, "ssh-ext-named:",
strlen("ssh-ext-named:")) == 0){
+		debug3("key_type_from_name: got a typed named key type: %s", name);
+		return KEY_NAME;
 	} else if (strcmp(name, "null") == 0){
 		return KEY_NULL;
 	}
Index: 2_9_p2_w_gss_and_krb5.4/gss-serv.c
--- 2_9_p2_w_gss_and_krb5.4/gss-serv.c Tue, 26 Jun 2001 16:27:13 -0400 willian
(OpenSSH/l/25_gss-serv.c 1.1 644)
+++ 2_9_p2_w_gss_krb5_named_keys.1/gss-serv.c Fri, 29 Jun 2001 18:00:47 -0400
willian (OpenSSH/l/25_gss-serv.c 1.2 644)
@@ -124,27 +124,41 @@
  * Returns true if the user is OK to log in, otherwise returns 0
  */

+static char name_type_name[5] = "krb5";
+
 int
 ssh_gssapi_krb5_userok(char *name) {
 	krb5_principal princ;
-	int retval;
+	int retval, retval2;
+	Key k;

 	if (ssh_gssapi_krb5_init() == 0)
 		return 0;

+	k.type = KEY_NAME;
+	k.name = gssapi_client_name.value;
+	k.name_len = strlen(gssapi_client_name.value);
+	k.name_type = name_type_name;
+
+	debug3("ssh_gssapi_krb5_userok:");
+	debug3("ssh_gssapi_krb5_userok: %s", k.name_type);
+
 	if ((retval=krb5_parse_name(krb_context, gssapi_client_name.value,
 				    &princ))) {
 		log("krb5_parse_name(): %.100s",
 			krb5_get_err_text(krb_context,retval));
 		return 0;
 	}
+
+	retval2 = user_key_allowed(getpwnam(name), &k);
+
 	if (krb5_kuserok(krb_context, princ, name))
 		retval = 1;
 	else
 		retval = 0;

 	krb5_free_principal(krb_context, princ);
-	return retval;
+	return retval | retval2;
 }

 /* Make sure that this is called _after_ we've setuid to the user */


On Thu, Jun 28, 2001 at 04:57:14PM -0400, Nicolas Williams
wrote:
>
> Playing around with the [wonderful] GSS-API patches for OpenSSH [1] I
> noticed that there is a bit of functionality missing from
> OpenSSH/GSS-API, namely that authorized_keys2 has no meaning when using
> GSS authentication.
>
> Yes, ~/.k5login can be used to grant access to an account for
> applications that support Kerberos, as does OpenSSH with those GSS
> patches, but .k5login does not and cannot provide the
> from/command/environment and other useful options that SSH's
> authorized_keys2 file entries can.
>
> So, after looking around, especially in key.h and key.c and auth2.c, it
> occurred to me that a new key type could be added for dealing with named
> keys, that is, names which can be authenticated (e.g., certificate
> names, Kerberos principal names).
>
> The neat thing is that auth2.c:user_key_allowed() is key-type
> independent (so arguably it doesn't belong in auth2.c), and thus could
> be called from ssh_gssapi_userok() [instead of, or in addition to the
> GSS mechanism specific *userok() methods].
>
> The only questions, in my mind, are
>
>  - how to format key names for use in authorized_keys2?
>
>    I propose starting the key blob with 'name:' followed by a
possibly
>    null mechanism name, another ':' and the key name in question
>    (uuencoded so whitespace, non-ascii characters and so on can be
>    unambiguously present in key names).
>
>  - how to deal with generic names vs. mechanism specific names?
>
>    I.e., should an 'exported' GSS name be checked as a
'gss' key name
>    type? Or should it be checked against a name type specific to the
>    mechanism used to authenticate the client?
>
>    I think this should probably be optional behaviour.
>
>
> [1] http://www.sxw.org.uk/computing/patches/
>
>
> Thoughts? Flames?
>
> Nico
> --
>
> .
--

.

Visit our website at http://www.ubswarburg.com

This message contains confidential information and is intended only
for the individual named.  If you are not the named addressee you
should not disseminate, distribute or copy this e-mail.  Please
notify the sender immediately by e-mail if you have received this
e-mail by mistake and delete this e-mail from your system.

E-mail transmission cannot be guaranteed to be secure or error-free
as information could be intercepted, corrupted, lost, destroyed,
arrive late or incomplete, or contain viruses.  The sender therefore
does not accept liability for any errors or omissions in the contents
of this message which arise as a result of e-mail transmission.  If
verification is required please request a hard-copy version.  This
message is provided for informational purposes and should not be
construed as a solicitation or offer to buy or sell any securities or
related financial instruments.