---

 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


Reply via email to