linux-cifs.vger.kernel.org archive mirror
 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).