/* Kerberos-based RxRPC security
*
* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/net.h>
#include <linux/skbuff.h>
#include <linux/udp.h>
#include <linux/crypto.h>
#include <linux/scatterlist.h>
#include <linux/ctype.h>
#include <linux/slab.h>
#include <net/sock.h>
#include <net/af_rxrpc.h>
#include <keys/rxrpc-type.h>
#define rxrpc_debug rxkad_debug
#include "ar-internal.h"
#define RXKAD_VERSION 2
#define MAXKRB5TICKETLEN 1024
#define RXKAD_TKT_TYPE_KERBEROS_V5 256
#define ANAME_SZ 40 /* size of authentication name */
#define INST_SZ 40 /* size of principal's instance */
#define REALM_SZ 40 /* size of principal's auth domain */
#define SNAME_SZ 40 /* size of service name */
unsigned rxrpc_debug;
module_param_named(debug, rxrpc_debug, uint, S_IWUSR | S_IRUGO);
MODULE_PARM_DESC(debug, "rxkad debugging mask");
struct rxkad_level1_hdr {
__be32 data_size; /* true data size (excluding padding) */
};
struct rxkad_level2_hdr {
__be32 data_size; /* true data size (excluding padding) */
__be32 checksum; /* decrypted data checksum */
};
MODULE_DESCRIPTION("RxRPC network protocol type-2 security (Kerberos 4)");
MODULE_AUTHOR("Red Hat, Inc.");
MODULE_LICENSE("GPL");
/*
* this holds a pinned cipher so that keventd doesn't get called by the cipher
* alloc routine, but since we have it to hand, we use it to decrypt RESPONSE
* packets
*/
static struct crypto_blkcipher *rxkad_ci;
static DEFINE_MUTEX(rxkad_ci_mutex);
/*
* initialise connection security
*/
static int rxkad_init_connection_security(struct rxrpc_connection *conn)
{
struct crypto_blkcipher *ci;
struct rxrpc_key_token *token;
int ret;
_enter("{%d},{%x}", conn->debug_id, key_serial(conn->key));
token = conn->key->payload.data;
conn->security_ix = token->security_index;
ci = crypto_alloc_blkcipher("pcbc(fcrypt)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(ci)) {
_debug("no cipher");
ret = PTR_ERR(ci);
goto error;
}
if (crypto_blkcipher_setkey(ci, token->kad->session_key,
sizeof(token->kad->session_key)) < 0)
BUG();
switch (conn->security_level) {
case RXRPC_SECURITY_PLAIN:
break;
case RXRPC_SECURITY_AUTH:
conn->size_align = 8;
conn->security_size = sizeof(struct rxkad_level1_hdr);
conn->header_size += sizeof(struct rxkad_level1_hdr);
break;
case RXRPC_SECURITY_ENCRYPT:
conn->size_align = 8;
conn->security_size = sizeof(struct rxkad_level2_hdr);
conn->header_size += sizeof(struct rxkad_level2_hdr);
break;
default:
ret = -EKEYREJECTED;
goto error;
}
conn->cipher = ci;
ret = 0;
error:
_leave(" = %d", ret);
return ret;
}
/*
* prime the encryption state with the invariant parts of a connection's
* description
*/
static void rxkad_prime_packet_security(struct rxrpc_connection *conn)
{
struct rxrpc_key_token *token;
struct blkcipher_desc desc;
struct scatterlist sg[2];
struct rxrpc_crypt iv;
struct {
__be32 x[4];
} tmpbuf __attribute__((aligned(16))); /* must all be in same page */
_enter("");
if (!conn->key)
return;
token = conn->key->payload.data;
memcpy(&iv, token->kad->session_key, sizeof(iv));
desc.tfm