All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Howells <dhowells@redhat.com>
To: herbert@gondor.apana.org.au, bfields@fieldses.org
Cc: dhowells@redhat.com, trond.myklebust@hammerspace.com,
	linux-crypto@vger.kernel.org, linux-afs@lists.infradead.org,
	linux-cifs@vger.kernel.org, linux-nfs@vger.kernel.org,
	linux-fsdevel@vger.kernel.org, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: [PATCH 18/18] rxgk: Support OpenAFS's rxgk implementation
Date: Thu, 12 Nov 2020 13:00:45 +0000	[thread overview]
Message-ID: <160518604546.2277919.883911770718886136.stgit@warthog.procyon.org.uk> (raw)
In-Reply-To: <160518586534.2277919.14475638653680231924.stgit@warthog.procyon.org.uk>


---

 net/rxrpc/ar-internal.h |    1 
 net/rxrpc/key.c         |  136 +++++++++++++++++++++++++++++++++++++++++++++++
 net/rxrpc/rxgk.c        |   25 +++++++++
 net/rxrpc/rxgk_app.c    |  135 +++++++++++++++++++++++++++++++++++++++++++++++
 net/rxrpc/rxgk_common.h |    2 +
 net/rxrpc/security.c    |    3 +
 6 files changed, 302 insertions(+)

diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index 3f2469714422..ed44ceeeab68 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -1070,6 +1070,7 @@ void rxrpc_peer_init_rtt(struct rxrpc_peer *);
 /*
  * rxgk.c
  */
+extern const struct rxrpc_security rxgk_openafs;
 extern const struct rxrpc_security rxgk_yfs;
 
 /*
diff --git a/net/rxrpc/key.c b/net/rxrpc/key.c
index b7f154701d97..3479ef285980 100644
--- a/net/rxrpc/key.c
+++ b/net/rxrpc/key.c
@@ -147,6 +147,135 @@ static time64_t rxrpc_s64_to_time64(s64 time_in_100ns)
 	return neg ? -tmp : tmp;
 }
 
+/*
+ * Parse an OpenAFS RxGK type XDR format token
+ * - the caller guarantees we have at least 4 words
+ *
+ * struct token_rxgk {
+ *	afs_int64	0 gk_viceid;
+ *	afs_int32	2 gk_enctype;
+ *	afs_int32	3 gk_level;
+ *	afs_uint32	4 gk_lifetime;
+ *	afs_uint32	5 gk_bytelife;
+ *	afs_int64	6 gk_expiration;
+ *	opaque		8 gk_token<AFSTOKEN_GK_TOK_MAX>;
+ *	opaque		9 gk_k0<AFSTOKEN_GK_TOK_MAX>;
+ * };
+ */
+static int rxrpc_preparse_xdr_rxgk(struct key_preparsed_payload *prep,
+				   size_t datalen,
+				   const __be32 *xdr, unsigned int toklen)
+{
+	struct rxrpc_key_token *token, **pptoken;
+	time64_t expiry;
+	size_t plen;
+	const __be32 *ticket, *key;
+	u32 tktlen, keylen;
+
+	_enter(",{%x,%x,%x,%x},%x",
+	       ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
+	       toklen);
+
+	if (toklen / 4 < 10)
+		goto reject;
+
+	ticket = xdr + 9;
+	tktlen = ntohl(ticket[-1]);
+	_debug("tktlen: %x", tktlen);
+	tktlen = round_up(tktlen, 4);
+	if (toklen < 10 * 4 + tktlen)
+		goto reject;
+
+	key = ticket + (tktlen / 4) + 1;
+	keylen = ntohl(key[-1]);
+	_debug("keylen: %x", keylen);
+	keylen = round_up(keylen, 4);
+	if (10 * 4 + tktlen + keylen != toklen) {
+		kleave(" = -EKEYREJECTED [%x!=%x, %x,%x]",
+		       10 * 4 + tktlen + keylen, toklen, tktlen, keylen);
+		goto reject;
+	}
+
+	plen = sizeof(*token) + sizeof(*token->rxgk) + tktlen + keylen;
+	prep->quotalen = datalen + plen;
+
+	plen -= sizeof(*token);
+	token = kzalloc(sizeof(*token), GFP_KERNEL);
+	if (!token)
+		goto nomem;
+
+	token->rxgk = kzalloc(sizeof(struct rxgk_key) + keylen, GFP_KERNEL);
+	if (!token->rxgk)
+		goto nomem_token;
+
+	token->security_index	= RXRPC_SECURITY_RXGK;
+	token->rxgk->begintime	= 0;
+	token->rxgk->endtime	= xdr_dec64(xdr + 6);
+	token->rxgk->level	= ntohl(xdr[3]);
+	if (token->rxgk->level > RXRPC_SECURITY_ENCRYPT)
+		goto reject_token;
+	token->rxgk->lifetime	= ntohl(xdr[4]);
+	token->rxgk->bytelife	= ntohl(xdr[5]);
+	token->rxgk->enctype	= ntohl(xdr[2]);
+	token->rxgk->key.len	= ntohl(key[-1]);
+	token->rxgk->key.data	= token->rxgk->_key;
+	token->rxgk->ticket.len = ntohl(ticket[-1]);
+
+	expiry = rxrpc_s64_to_time64(token->rxgk->endtime);
+	if (expiry < 0)
+		goto expired;
+	if (expiry < prep->expiry)
+		prep->expiry = expiry;
+
+	memcpy(token->rxgk->key.data, key, token->rxgk->key.len);
+
+	/* Pad the ticket so that we can use it directly in XDR */
+	token->rxgk->ticket.data = kzalloc(round_up(token->rxgk->ticket.len, 4),
+					   GFP_KERNEL);
+	if (!token->rxgk->ticket.data)
+		goto nomem_yrxgk;
+	memcpy(token->rxgk->ticket.data, ticket, token->rxgk->ticket.len);
+
+	_debug("SCIX: %u",	token->security_index);
+	_debug("LIFE: %llx",	token->rxgk->lifetime);
+	_debug("BYTE: %llx",	token->rxgk->bytelife);
+	_debug("ENC : %u",	token->rxgk->enctype);
+	_debug("LEVL: %u",	token->rxgk->level);
+	_debug("KLEN: %u",	token->rxgk->key.len);
+	_debug("TLEN: %u",	token->rxgk->ticket.len);
+	_debug("KEY0: %*phN",	token->rxgk->key.len, token->rxgk->key.data);
+	_debug("TICK: %*phN",
+	       min_t(u32, token->rxgk->ticket.len, 32), token->rxgk->ticket.data);
+
+	/* count the number of tokens attached */
+	prep->payload.data[1] = (void *)((unsigned long)prep->payload.data[1] + 1);
+
+	/* attach the data */
+	for (pptoken = (struct rxrpc_key_token **)&prep->payload.data[0];
+	     *pptoken;
+	     pptoken = &(*pptoken)->next)
+		continue;
+	*pptoken = token;
+
+	_leave(" = 0");
+	return 0;
+
+nomem_yrxgk:
+	kfree(token->rxgk);
+nomem_token:
+	kfree(token);
+nomem:
+	return -ENOMEM;
+reject_token:
+	kfree(token);
+reject:
+	return -EKEYREJECTED;
+expired:
+	kfree(token->rxgk);
+	kfree(token);
+	return -EKEYEXPIRED;
+}
+
 /*
  * Parse a YFS-RxGK type XDR format token
  * - the caller guarantees we have at least 4 words
@@ -380,6 +509,9 @@ static int rxrpc_preparse_xdr(struct key_preparsed_payload *prep)
 		case RXRPC_SECURITY_RXKAD:
 			ret2 = rxrpc_preparse_xdr_rxkad(prep, datalen, token, toklen);
 			break;
+		case RXRPC_SECURITY_RXGK:
+			ret2 = rxrpc_preparse_xdr_rxgk(prep, datalen, token, toklen);
+			break;
 		case RXRPC_SECURITY_YFS_RXGK:
 			ret2 = rxrpc_preparse_xdr_yfs_rxgk(prep, datalen, token, toklen);
 			break;
@@ -545,6 +677,7 @@ static void rxrpc_free_token_list(struct rxrpc_key_token *token)
 		case RXRPC_SECURITY_RXKAD:
 			kfree(token->kad);
 			break;
+		case RXRPC_SECURITY_RXGK:
 		case RXRPC_SECURITY_YFS_RXGK:
 			kfree(token->rxgk->ticket.data);
 			kfree(token->rxgk);
@@ -592,6 +725,9 @@ static void rxrpc_describe(const struct key *key, struct seq_file *m)
 		case RXRPC_SECURITY_RXKAD:
 			seq_puts(m, "ka");
 			break;
+		case RXRPC_SECURITY_RXGK:
+			seq_puts(m, "ogk");
+			break;
 		case RXRPC_SECURITY_YFS_RXGK:
 			seq_puts(m, "ygk");
 			break;
diff --git a/net/rxrpc/rxgk.c b/net/rxrpc/rxgk.c
index 0aa6da93b8d4..bad68d293ced 100644
--- a/net/rxrpc/rxgk.c
+++ b/net/rxrpc/rxgk.c
@@ -1181,6 +1181,31 @@ static void rxgk_exit(void)
 {
 }
 
+/*
+ * RxRPC OpenAFS GSSAPI-based security
+ */
+const struct rxrpc_security rxgk_openafs = {
+	.name				= "rxgk",
+	.security_index			= RXRPC_SECURITY_RXGK,
+	.no_key_abort			= RXGK_NOTAUTH,
+	.init				= rxgk_init,
+	.exit				= rxgk_exit,
+	.preparse_server_key		= rxgk_preparse_server_key,
+	.free_preparse_server_key	= rxgk_free_preparse_server_key,
+	.destroy_server_key		= rxgk_destroy_server_key,
+	.describe_server_key		= rxgk_describe_server_key,
+	.init_connection_security	= rxgk_init_connection_security,
+	.secure_packet			= rxgk_secure_packet,
+	.verify_packet			= rxgk_verify_packet,
+	.free_call_crypto		= rxgk_free_call_crypto,
+	.locate_data			= rxgk_locate_data,
+	.issue_challenge		= rxgk_issue_challenge,
+	.respond_to_challenge		= rxgk_respond_to_challenge,
+	.verify_response		= rxgk_verify_response,
+	.clear				= rxgk_clear,
+	.default_decode_ticket		= rxgk_openafs_decode_ticket,
+};
+
 /*
  * RxRPC YFS GSSAPI-based security
  */
diff --git a/net/rxrpc/rxgk_app.c b/net/rxrpc/rxgk_app.c
index 895879f3acfb..8c35e3a88119 100644
--- a/net/rxrpc/rxgk_app.c
+++ b/net/rxrpc/rxgk_app.c
@@ -14,6 +14,141 @@
 #include "ar-internal.h"
 #include "rxgk_common.h"
 
+/*
+ * Decode a default-style OpenAFS ticket in a response and turn it into an
+ * rxrpc-type key.
+ *
+ * struct RXGK_Token {
+ *	afs_int32		enctype;
+ *	opaque			K0<>;
+ *	RXGK_Level		level;
+ *	afs_int32		lifetime;
+ *	afs_int32		bytelife;
+ *	rxgkTime		expirationtime;
+ *	struct RXGK_PrAuthName	identities<>;
+ * };
+ */
+int rxgk_openafs_decode_ticket(struct sk_buff *skb,
+			       unsigned int ticket_offset, unsigned int ticket_len,
+			       u32 *_abort_code,
+			       struct key **_key)
+{
+	struct rxrpc_key_token *token;
+	const struct cred *cred = current_cred(); // TODO - use socket creds
+	struct key *key;
+	size_t pre_ticket_len, payload_len;
+	unsigned int klen, enctype;
+	void *payload, *ticket;
+	__be32 *t, *p, *q, tmp[2];
+	int ret;
+
+	_enter("");
+
+	/* Get the session key length */
+	ret = skb_copy_bits(skb, ticket_offset, tmp, sizeof(tmp));
+	if (ret < 0)
+		goto error_out;
+	enctype = ntohl(tmp[0]);
+	klen = ntohl(tmp[1]);
+
+	if (klen > ticket_len - 8 * sizeof(__be32)) {
+		*_abort_code = RXGK_INCONSISTENCY;
+		return -EPROTO;
+	}
+
+	pre_ticket_len = ((5 + 10) * sizeof(__be32));
+	payload_len = pre_ticket_len + xdr_round_up(ticket_len) +
+		sizeof(__be32) + xdr_round_up(klen);
+
+	payload = kzalloc(payload_len, GFP_NOFS);
+	if (!payload)
+		return -ENOMEM;
+
+	/* We need to fill out the XDR form for a key payload that we can pass
+	 * to add_key().  Start by copying in the ticket so that we can parse
+	 * it.
+	 */
+	ticket = payload + pre_ticket_len;
+	ret = skb_copy_bits(skb, ticket_offset, ticket, ticket_len);
+	if (ret < 0)
+		goto error;
+
+	/* Fill out the form header. */
+	p = payload;
+	p[0] = htonl(0); /* Flags */
+	p[1] = htonl(1); /* len(cellname) */
+	p[2] = htonl(0x20000000); /* Cellname " " */
+	p[3] = htonl(1); /* #tokens */
+	p[4] = htonl(11 * sizeof(__be32) +
+		     xdr_round_up(klen) + xdr_round_up(ticket_len)); /* Token len */
+
+	/* Now fill in the body.  Most of this we can just scrape directly from
+	 * the ticket.
+	 */
+	t = ticket + sizeof(__be32) * 2 + xdr_round_up(klen);
+	q = payload + 5 * sizeof(__be32);
+	q[ 0] = htonl(RXRPC_SECURITY_RXGK);
+	q[ 1] = 0;		/* gk_viceid - msw */
+	q[ 2] = 0;		/* - lsw */
+	q[ 3] = htonl(enctype);	/* gkenctype - msw */
+	q[ 4] = t[0];		/* gk_level */
+	q[ 5] = t[1];		/* gk_lifetime */
+	q[ 6] = t[2];		/* gk_bytelife */
+	q[ 7] = t[3];		/* gk_expiration - msw */
+	q[ 8] = t[4];		/* - lsw */
+	q[ 9] = htonl(ticket_len); /* gk_token.length */
+
+	q += 10;
+	if (WARN_ON((unsigned long)q != (unsigned long)ticket)) {
+		kdebug("%lx %lx", (long)q, (long)ticket);
+		ret = -EIO;
+		goto error;
+	}
+
+	/* Ticket read in with skb_copy_bits above */
+	q += xdr_round_up(ticket_len) / 4;
+	q[0] = ntohl(klen);
+	q++;
+
+	memcpy(q, ticket + sizeof(__be32) * 2, klen);
+
+	q += xdr_round_up(klen) / 4;
+	if (WARN_ON((unsigned long)q - (unsigned long)payload != payload_len)) {
+		ret = -EIO;
+		goto error;
+	}
+
+	/* Now turn that into a key. */
+	key = key_alloc(&key_type_rxrpc, "x",
+			GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, 0, // TODO: Use socket owner
+			KEY_ALLOC_NOT_IN_QUOTA, NULL);
+	if (IS_ERR(key)) {
+		_leave(" = -ENOMEM [alloc %ld]", PTR_ERR(key));
+		goto error;
+	}
+
+	_debug("key %d", key_serial(key));
+
+	ret = key_instantiate_and_link(key, payload, payload_len, NULL, NULL);
+	if (ret < 0)
+		goto error_key;
+
+	token = key->payload.data[0];
+	token->no_leak_key = true;
+	*_key = key;
+	key = NULL;
+	ret = 0;
+	goto error;
+
+error_key:
+	key_put(key);
+error:
+	kfree_sensitive(payload);
+error_out:
+	_leave(" = %d", ret);
+	return ret;
+}
+
 /*
  * Decode a default-style YFS ticket in a response and turn it into an
  * rxrpc-type key.
diff --git a/net/rxrpc/rxgk_common.h b/net/rxrpc/rxgk_common.h
index 38473b13e67d..88278da64c6a 100644
--- a/net/rxrpc/rxgk_common.h
+++ b/net/rxrpc/rxgk_common.h
@@ -38,6 +38,8 @@ struct rxgk_context {
 /*
  * rxgk_app.c
  */
+int rxgk_openafs_decode_ticket(struct sk_buff *, unsigned int, unsigned int,
+			       u32 *, struct key **);
 int rxgk_yfs_decode_ticket(struct sk_buff *, unsigned int, unsigned int,
 			   u32 *, struct key **);
 int rxgk_extract_token(struct rxrpc_connection *,
diff --git a/net/rxrpc/security.c b/net/rxrpc/security.c
index 278a510b2956..dd11aa1aa137 100644
--- a/net/rxrpc/security.c
+++ b/net/rxrpc/security.c
@@ -20,6 +20,9 @@ static const struct rxrpc_security *rxrpc_security_types[] = {
 #ifdef CONFIG_RXKAD
 	[RXRPC_SECURITY_RXKAD]	= &rxkad,
 #endif
+#ifdef CONFIG_RXGK
+	[RXRPC_SECURITY_RXGK]	= &rxgk_openafs,
+#endif
 #ifdef CONFIG_RXGK
 	[RXRPC_SECURITY_YFS_RXGK] = &rxgk_yfs,
 #endif



  parent reply	other threads:[~2020-11-12 13:01 UTC|newest]

Thread overview: 57+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-12 12:57 [RFC][PATCH 00/18] crypto: Add generic Kerberos library David Howells
2020-11-12 12:57 ` [PATCH 01/18] crypto/krb5: Implement Kerberos crypto core David Howells
2020-11-12 12:58 ` [PATCH 02/18] crypto/krb5: Add some constants out of sunrpc headers David Howells
2020-11-12 12:58 ` [PATCH 03/18] crypto/krb5: Provide infrastructure and key derivation David Howells
2020-11-12 12:58 ` [PATCH 04/18] crypto/krb5: Implement the Kerberos5 rfc3961 " David Howells
2020-11-12 12:58 ` [PATCH 05/18] crypto/krb5: Implement the Kerberos5 rfc3961 encrypt and decrypt functions David Howells
2020-11-12 12:58 ` [PATCH 06/18] crypto/krb5: Implement the Kerberos5 rfc3961 get_mic and verify_mic David Howells
2020-11-12 12:58 ` [PATCH 07/18] crypto/krb5: Implement the AES enctypes from rfc3962 David Howells
2020-11-12 12:58 ` [PATCH 08/18] crypto/krb5: Implement crypto self-testing David Howells
2020-11-12 12:58 ` [PATCH 09/18] crypto/krb5: Implement the AES enctypes from rfc8009 David Howells
2020-11-12 12:59 ` [PATCH 10/18] crypto/krb5: Implement the AES encrypt/decrypt " David Howells
2020-11-12 12:59 ` [PATCH 11/18] crypto/krb5: Add the AES self-testing data " David Howells
2020-11-12 12:59 ` [PATCH 12/18] crypto/krb5: Implement the Camellia enctypes from rfc6803 David Howells
2020-11-12 12:59 ` [PATCH 13/18] rxrpc: Add the security index for yfs-rxgk David Howells
2020-11-12 12:59 ` [PATCH 14/18] rxrpc: Add YFS RxGK (GSSAPI) security class David Howells
2020-11-12 12:59 ` [PATCH 15/18] rxrpc: rxgk: Provide infrastructure and key derivation David Howells
2020-11-12 12:59 ` [PATCH 16/18] rxrpc: rxgk: Implement the yfs-rxgk security class (GSSAPI) David Howells
2020-11-12 13:00 ` [PATCH 17/18] rxrpc: rxgk: Implement connection rekeying David Howells
2020-11-12 13:00 ` David Howells [this message]
2020-11-12 13:44 ` [RFC][PATCH 00/18] crypto: Add generic Kerberos library David Howells
2020-11-12 14:36 ` Chuck Lever
2020-11-12 15:42 ` David Howells
2020-11-12 15:49   ` Chuck Lever
2020-11-12 16:54   ` David Howells
2020-11-12 21:07     ` Bruce Fields
2020-11-12 21:09       ` Chuck Lever
2020-11-12 18:37 ` J. Bruce Fields
2020-11-12 18:39   ` Chuck Lever
2020-11-26  6:33 ` Herbert Xu
2020-11-26  8:19 ` David Howells
2020-11-27  5:07   ` Herbert Xu
2020-12-01  8:44   ` David Howells
2020-12-01  8:46     ` Herbert Xu
2020-12-01  9:12     ` David Howells
2020-12-01 10:36       ` Herbert Xu
2020-12-04 14:59 ` Why the auxiliary cipher in gss_krb5_crypto.c? David Howells
2020-12-04 15:46   ` Bruce Fields
2020-12-04 16:05     ` Chuck Lever
2020-12-04 16:14     ` Bruce Fields
2020-12-04 16:01   ` David Howells
2020-12-04 16:03     ` Bruce Fields
2020-12-04 16:50     ` David Howells
2020-12-04 17:06       ` Ard Biesheuvel
2020-12-04 17:19       ` David Howells
2020-12-04 17:35         ` Ard Biesheuvel
2020-12-04 21:08           ` Herbert Xu
2020-12-07  8:24           ` David Howells
2020-12-07 12:01         ` David Howells
2020-12-07 13:08           ` Ard Biesheuvel
2020-12-07 14:15           ` David Howells
2020-12-08  8:27             ` Ard Biesheuvel
2020-12-08  9:18             ` David Howells
2020-12-04 18:13   ` Theodore Y. Ts'o
2020-12-08 13:25 ` David Howells
2020-12-08 14:04   ` Ard Biesheuvel
2020-12-08 14:13   ` David Howells
2020-12-08 14:02 ` David Howells

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=160518604546.2277919.883911770718886136.stgit@warthog.procyon.org.uk \
    --to=dhowells@redhat.com \
    --cc=bfields@fieldses.org \
    --cc=herbert@gondor.apana.org.au \
    --cc=linux-afs@lists.infradead.org \
    --cc=linux-cifs@vger.kernel.org \
    --cc=linux-crypto@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=trond.myklebust@hammerspace.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.