mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
net/rxrpc: Use local FCrypt-PCBC implementation
Use the local implementation of FCrypt-PCBC instead of the crypto API one. This will allow the crypto API one to be removed. It also simplifies the code quite a bit. The local FCrypt-PCBC implementation is also significantly faster than the crypto API one, since the crypto API one had a lot of overhead. For example, benchmarking on an x86_64 CPU, I see that FCrypt-PCBC decryption throughput improved from 83 MB/s to 157 MB/s. (Meanwhile, AES-256-GCM decryption is 8064 MB/s on the same CPU. Clearly, anyone looking for good performance, or anything that is actually secure for that matter, needs to look elsewhere anyway.) Acked-by: David Howells <dhowells@redhat.com> Signed-off-by: Eric Biggers <ebiggers@kernel.org> Tested-by: Marc Dionne <marc.dionne@auristor.com> Link: https://patch.msgid.link/20260522050740.84561-3-ebiggers@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
f10e73dffd
commit
97b768514a
|
|
@ -60,7 +60,6 @@ config RXKAD
|
|||
select CRYPTO_MANAGER
|
||||
select CRYPTO_SKCIPHER
|
||||
select CRYPTO_PCBC
|
||||
select CRYPTO_FCRYPT
|
||||
help
|
||||
Provide kerberos 4 and AFS kaserver security handling for AF_RXRPC
|
||||
through the use of the key retention service.
|
||||
|
|
|
|||
|
|
@ -577,7 +577,7 @@ struct rxrpc_connection {
|
|||
const struct rxrpc_security *security; /* applied security module */
|
||||
union {
|
||||
struct {
|
||||
struct crypto_sync_skcipher *cipher; /* encryption handle */
|
||||
struct fcrypt_key *cipher; /* encryption key */
|
||||
struct rxrpc_crypt csum_iv; /* packet checksum base */
|
||||
u32 nonce; /* response re-use preventer */
|
||||
} rxkad;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <crypto/skcipher.h>
|
||||
#include <linux/fips.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
|
@ -30,6 +31,8 @@
|
|||
#define SNAME_SZ 40 /* size of service name */
|
||||
#define RXKAD_ALIGN 8
|
||||
|
||||
static const u8 zero_iv[FCRYPT_BSIZE];
|
||||
|
||||
struct rxkad_level1_hdr {
|
||||
__be32 data_size; /* true data size (excluding padding) */
|
||||
};
|
||||
|
|
@ -39,17 +42,8 @@ struct rxkad_level2_hdr {
|
|||
__be32 checksum; /* decrypted data checksum */
|
||||
};
|
||||
|
||||
static int rxkad_prime_packet_security(struct rxrpc_connection *conn,
|
||||
struct crypto_sync_skcipher *ci);
|
||||
|
||||
/*
|
||||
* 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_sync_skcipher *rxkad_ci;
|
||||
static struct skcipher_request *rxkad_ci_req;
|
||||
static DEFINE_MUTEX(rxkad_ci_mutex);
|
||||
static void rxkad_prime_packet_security(struct rxrpc_connection *conn,
|
||||
const struct fcrypt_key *cipher);
|
||||
|
||||
/*
|
||||
* Parse the information from a server key
|
||||
|
|
@ -100,23 +94,19 @@ static void rxkad_destroy_server_key(struct key *key)
|
|||
static int rxkad_init_connection_security(struct rxrpc_connection *conn,
|
||||
struct rxrpc_key_token *token)
|
||||
{
|
||||
struct crypto_sync_skcipher *ci;
|
||||
struct fcrypt_key *ci;
|
||||
int ret;
|
||||
|
||||
_enter("{%d},{%x}", conn->debug_id, key_serial(conn->key));
|
||||
|
||||
conn->security_ix = token->security_index;
|
||||
|
||||
ci = crypto_alloc_sync_skcipher("pcbc(fcrypt)", 0, 0);
|
||||
if (IS_ERR(ci)) {
|
||||
_debug("no cipher");
|
||||
ret = PTR_ERR(ci);
|
||||
ci = kmalloc_obj(*ci);
|
||||
if (!ci) {
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (crypto_sync_skcipher_setkey(ci, token->kad->session_key,
|
||||
sizeof(token->kad->session_key)) < 0)
|
||||
BUG();
|
||||
fcrypt_preparekey(ci, token->kad->session_key);
|
||||
|
||||
switch (conn->security_level) {
|
||||
case RXRPC_SECURITY_PLAIN:
|
||||
|
|
@ -125,18 +115,16 @@ static int rxkad_init_connection_security(struct rxrpc_connection *conn,
|
|||
break;
|
||||
default:
|
||||
ret = -EKEYREJECTED;
|
||||
goto error;
|
||||
goto error_ci;
|
||||
}
|
||||
|
||||
ret = rxkad_prime_packet_security(conn, ci);
|
||||
if (ret < 0)
|
||||
goto error_ci;
|
||||
rxkad_prime_packet_security(conn, ci);
|
||||
|
||||
conn->rxkad.cipher = ci;
|
||||
return 0;
|
||||
|
||||
error_ci:
|
||||
crypto_free_sync_skcipher(ci);
|
||||
kfree_sensitive(ci);
|
||||
error:
|
||||
_leave(" = %d", ret);
|
||||
return ret;
|
||||
|
|
@ -188,62 +176,28 @@ static struct rxrpc_txbuf *rxkad_alloc_txbuf(struct rxrpc_call *call, size_t rem
|
|||
* prime the encryption state with the invariant parts of a connection's
|
||||
* description
|
||||
*/
|
||||
static int rxkad_prime_packet_security(struct rxrpc_connection *conn,
|
||||
struct crypto_sync_skcipher *ci)
|
||||
static void rxkad_prime_packet_security(struct rxrpc_connection *conn,
|
||||
const struct fcrypt_key *cipher)
|
||||
{
|
||||
struct skcipher_request *req;
|
||||
struct rxrpc_key_token *token;
|
||||
struct scatterlist sg;
|
||||
struct rxrpc_crypt iv;
|
||||
__be32 *tmpbuf;
|
||||
size_t tmpsize = 4 * sizeof(__be32);
|
||||
int ret;
|
||||
__be32 tmpbuf[4];
|
||||
|
||||
_enter("");
|
||||
|
||||
if (!conn->key)
|
||||
return 0;
|
||||
|
||||
tmpbuf = kmalloc(tmpsize, GFP_KERNEL);
|
||||
if (!tmpbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
req = skcipher_request_alloc(&ci->base, GFP_NOFS);
|
||||
if (!req) {
|
||||
kfree(tmpbuf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return;
|
||||
token = conn->key->payload.data[0];
|
||||
memcpy(&iv, token->kad->session_key, sizeof(iv));
|
||||
|
||||
tmpbuf[0] = htonl(conn->proto.epoch);
|
||||
tmpbuf[1] = htonl(conn->proto.cid);
|
||||
tmpbuf[2] = 0;
|
||||
tmpbuf[3] = htonl(conn->security_ix);
|
||||
|
||||
sg_init_one(&sg, tmpbuf, tmpsize);
|
||||
skcipher_request_set_sync_tfm(req, ci);
|
||||
skcipher_request_set_callback(req, 0, NULL, NULL);
|
||||
skcipher_request_set_crypt(req, &sg, &sg, tmpsize, iv.x);
|
||||
ret = crypto_skcipher_encrypt(req);
|
||||
skcipher_request_free(req);
|
||||
|
||||
memcpy(&conn->rxkad.csum_iv, tmpbuf + 2, sizeof(conn->rxkad.csum_iv));
|
||||
kfree(tmpbuf);
|
||||
_leave(" = %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate and prepare the crypto request on a call. For any particular call,
|
||||
* this is called serially for the packets, so no lock should be necessary.
|
||||
*/
|
||||
static struct skcipher_request *rxkad_get_call_crypto(struct rxrpc_call *call)
|
||||
{
|
||||
struct crypto_skcipher *tfm = &call->conn->rxkad.cipher->base;
|
||||
|
||||
return skcipher_request_alloc(tfm, GFP_NOFS);
|
||||
static_assert(sizeof(tmpbuf) % FCRYPT_BSIZE == 0);
|
||||
fcrypt_pcbc_encrypt(cipher, /* iv= */ token->kad->session_key, tmpbuf,
|
||||
tmpbuf, sizeof(tmpbuf) / FCRYPT_BSIZE);
|
||||
memcpy(&conn->rxkad.csum_iv, &tmpbuf[2], sizeof(conn->rxkad.csum_iv));
|
||||
_leave("");
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -256,16 +210,12 @@ static void rxkad_free_call_crypto(struct rxrpc_call *call)
|
|||
/*
|
||||
* partially encrypt a packet (level 1 security)
|
||||
*/
|
||||
static int rxkad_secure_packet_auth(const struct rxrpc_call *call,
|
||||
struct rxrpc_txbuf *txb,
|
||||
struct skcipher_request *req)
|
||||
static void rxkad_secure_packet_auth(const struct rxrpc_call *call,
|
||||
struct rxrpc_txbuf *txb)
|
||||
{
|
||||
struct rxkad_level1_hdr *hdr = txb->data;
|
||||
struct rxrpc_crypt iv;
|
||||
struct scatterlist sg;
|
||||
size_t pad;
|
||||
u16 check;
|
||||
int ret;
|
||||
|
||||
_enter("");
|
||||
|
||||
|
|
@ -282,33 +232,20 @@ static int rxkad_secure_packet_auth(const struct rxrpc_call *call,
|
|||
}
|
||||
|
||||
/* start the encryption afresh */
|
||||
memset(&iv, 0, sizeof(iv));
|
||||
|
||||
sg_init_one(&sg, hdr, 8);
|
||||
skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
|
||||
skcipher_request_set_callback(req, 0, NULL, NULL);
|
||||
skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
|
||||
ret = crypto_skcipher_encrypt(req);
|
||||
skcipher_request_zero(req);
|
||||
|
||||
_leave(" = %d", ret);
|
||||
return ret;
|
||||
fcrypt_pcbc_encrypt(call->conn->rxkad.cipher, zero_iv, hdr, hdr, 1);
|
||||
_leave("");
|
||||
}
|
||||
|
||||
/*
|
||||
* wholly encrypt a packet (level 2 security)
|
||||
*/
|
||||
static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
|
||||
struct rxrpc_txbuf *txb,
|
||||
struct skcipher_request *req)
|
||||
static void rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
|
||||
struct rxrpc_txbuf *txb)
|
||||
{
|
||||
const struct rxrpc_key_token *token;
|
||||
struct rxkad_level2_hdr *rxkhdr = txb->data;
|
||||
struct rxrpc_crypt iv;
|
||||
struct scatterlist sg;
|
||||
size_t content, pad;
|
||||
u16 check;
|
||||
int ret;
|
||||
|
||||
_enter("");
|
||||
|
||||
|
|
@ -318,22 +255,18 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
|
|||
rxkhdr->checksum = 0;
|
||||
|
||||
content = sizeof(struct rxkad_level2_hdr) + txb->len;
|
||||
static_assert(RXKAD_ALIGN == FCRYPT_BSIZE);
|
||||
txb->pkt_len = round_up(content, RXKAD_ALIGN);
|
||||
pad = txb->pkt_len - content;
|
||||
if (pad)
|
||||
memset(txb->data + txb->offset, 0, pad);
|
||||
/* Now txb->pkt_len % FCRYPT_BSIZE == 0. */
|
||||
|
||||
/* encrypt from the session key */
|
||||
token = call->conn->key->payload.data[0];
|
||||
memcpy(&iv, token->kad->session_key, sizeof(iv));
|
||||
|
||||
sg_init_one(&sg, rxkhdr, txb->pkt_len);
|
||||
skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
|
||||
skcipher_request_set_callback(req, 0, NULL, NULL);
|
||||
skcipher_request_set_crypt(req, &sg, &sg, txb->pkt_len, iv.x);
|
||||
ret = crypto_skcipher_encrypt(req);
|
||||
skcipher_request_zero(req);
|
||||
return ret;
|
||||
fcrypt_pcbc_encrypt(call->conn->rxkad.cipher, token->kad->session_key,
|
||||
rxkhdr, rxkhdr, txb->pkt_len / FCRYPT_BSIZE);
|
||||
_leave("");
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -341,9 +274,6 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
|
|||
*/
|
||||
static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
|
||||
{
|
||||
struct skcipher_request *req;
|
||||
struct rxrpc_crypt iv;
|
||||
struct scatterlist sg;
|
||||
union {
|
||||
__be32 buf[2];
|
||||
} crypto __aligned(8);
|
||||
|
|
@ -361,27 +291,16 @@ static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
req = rxkad_get_call_crypto(call);
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
|
||||
/* continue encrypting from where we left off */
|
||||
memcpy(&iv, call->conn->rxkad.csum_iv.x, sizeof(iv));
|
||||
|
||||
/* calculate the security checksum */
|
||||
x = (call->cid & RXRPC_CHANNELMASK) << (32 - RXRPC_CIDSHIFT);
|
||||
x |= txb->seq & 0x3fffffff;
|
||||
crypto.buf[0] = htonl(call->call_id);
|
||||
crypto.buf[1] = htonl(x);
|
||||
|
||||
sg_init_one(&sg, crypto.buf, 8);
|
||||
skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
|
||||
skcipher_request_set_callback(req, 0, NULL, NULL);
|
||||
skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
|
||||
ret = crypto_skcipher_encrypt(req);
|
||||
skcipher_request_zero(req);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
/* continue encrypting from where we left off */
|
||||
fcrypt_pcbc_encrypt(call->conn->rxkad.cipher,
|
||||
call->conn->rxkad.csum_iv.x, crypto.buf, crypto.buf,
|
||||
1);
|
||||
|
||||
y = ntohl(crypto.buf[1]);
|
||||
y = (y >> 16) & 0xffff;
|
||||
|
|
@ -395,14 +314,16 @@ static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
|
|||
ret = 0;
|
||||
break;
|
||||
case RXRPC_SECURITY_AUTH:
|
||||
ret = rxkad_secure_packet_auth(call, txb, req);
|
||||
rxkad_secure_packet_auth(call, txb);
|
||||
if (txb->alloc_size == RXRPC_JUMBO_DATALEN)
|
||||
txb->jumboable = true;
|
||||
ret = 0;
|
||||
break;
|
||||
case RXRPC_SECURITY_ENCRYPT:
|
||||
ret = rxkad_secure_packet_encrypt(call, txb, req);
|
||||
rxkad_secure_packet_encrypt(call, txb);
|
||||
if (txb->alloc_size == RXRPC_JUMBO_DATALEN)
|
||||
txb->jumboable = true;
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
ret = -EPERM;
|
||||
|
|
@ -417,8 +338,6 @@ static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
|
|||
memset(p + txb->pkt_len, 0, gap);
|
||||
}
|
||||
|
||||
out:
|
||||
skcipher_request_free(req);
|
||||
_leave(" = %d [set %x]", ret, y);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -427,17 +346,13 @@ static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
|
|||
* decrypt partial encryption on a packet (level 1 security)
|
||||
*/
|
||||
static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
|
||||
rxrpc_seq_t seq,
|
||||
struct skcipher_request *req)
|
||||
rxrpc_seq_t seq)
|
||||
{
|
||||
struct rxkad_level1_hdr *sechdr;
|
||||
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
|
||||
struct rxrpc_crypt iv;
|
||||
struct scatterlist sg[1];
|
||||
void *data = call->rx_dec_buffer;
|
||||
u32 len = sp->len, data_size, buf;
|
||||
u16 check;
|
||||
int ret;
|
||||
|
||||
_enter("");
|
||||
|
||||
|
|
@ -445,21 +360,8 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
|
|||
return rxrpc_abort_eproto(call, skb, RXKADSEALEDINCON,
|
||||
rxkad_abort_1_short_header);
|
||||
|
||||
/* Decrypt the skbuff in-place. TODO: We really want to decrypt
|
||||
* directly into the target buffer.
|
||||
*/
|
||||
sg_init_one(sg, data, len);
|
||||
|
||||
/* start the decryption afresh */
|
||||
memset(&iv, 0, sizeof(iv));
|
||||
|
||||
skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
|
||||
skcipher_request_set_callback(req, 0, NULL, NULL);
|
||||
skcipher_request_set_crypt(req, sg, sg, 8, iv.x);
|
||||
ret = crypto_skcipher_decrypt(req);
|
||||
skcipher_request_zero(req);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/* Decrypt the first 8-byte block of the packet, using the zero IV. */
|
||||
fcrypt_pcbc_decrypt(call->conn->rxkad.cipher, zero_iv, data, data, 1);
|
||||
|
||||
/* Extract the decrypted packet length */
|
||||
sechdr = data;
|
||||
|
|
@ -488,18 +390,14 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
|
|||
* wholly decrypt a packet (level 2 security)
|
||||
*/
|
||||
static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
|
||||
rxrpc_seq_t seq,
|
||||
struct skcipher_request *req)
|
||||
rxrpc_seq_t seq)
|
||||
{
|
||||
const struct rxrpc_key_token *token;
|
||||
struct rxkad_level2_hdr *sechdr;
|
||||
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
|
||||
struct rxrpc_crypt iv;
|
||||
struct scatterlist sg[1];
|
||||
void *data = call->rx_dec_buffer;
|
||||
u32 len = sp->len, data_size, buf;
|
||||
u16 check;
|
||||
int ret;
|
||||
|
||||
_enter(",{%d}", len);
|
||||
|
||||
|
|
@ -510,26 +408,10 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
|
|||
/* Don't let the crypto algo see a misaligned length. */
|
||||
len = round_down(len, 8);
|
||||
|
||||
/* Decrypt in place in the call's decryption buffer. TODO: We really
|
||||
* want to decrypt directly into the target buffer.
|
||||
*/
|
||||
sg_init_one(sg, data, len);
|
||||
|
||||
/* decrypt from the session key */
|
||||
token = call->conn->key->payload.data[0];
|
||||
memcpy(&iv, token->kad->session_key, sizeof(iv));
|
||||
|
||||
skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
|
||||
skcipher_request_set_callback(req, 0, NULL, NULL);
|
||||
skcipher_request_set_crypt(req, sg, sg, len, iv.x);
|
||||
ret = crypto_skcipher_decrypt(req);
|
||||
skcipher_request_zero(req);
|
||||
if (ret < 0) {
|
||||
if (ret == -ENOMEM)
|
||||
return ret;
|
||||
return rxrpc_abort_eproto(call, skb, RXKADSEALEDINCON,
|
||||
rxkad_abort_2_crypto_unaligned);
|
||||
}
|
||||
fcrypt_pcbc_decrypt(call->conn->rxkad.cipher, token->kad->session_key,
|
||||
data, data, len / FCRYPT_BSIZE);
|
||||
|
||||
/* Extract the decrypted packet length */
|
||||
sechdr = data;
|
||||
|
|
@ -562,9 +444,6 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
|
|||
static int rxkad_verify_packet(struct rxrpc_call *call, struct sk_buff *skb)
|
||||
{
|
||||
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
|
||||
struct skcipher_request *req;
|
||||
struct rxrpc_crypt iv;
|
||||
struct scatterlist sg;
|
||||
union {
|
||||
__be32 buf[2];
|
||||
} crypto __aligned(8);
|
||||
|
|
@ -579,27 +458,16 @@ static int rxkad_verify_packet(struct rxrpc_call *call, struct sk_buff *skb)
|
|||
if (!call->conn->rxkad.cipher)
|
||||
return 0;
|
||||
|
||||
req = rxkad_get_call_crypto(call);
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
|
||||
/* continue encrypting from where we left off */
|
||||
memcpy(&iv, call->conn->rxkad.csum_iv.x, sizeof(iv));
|
||||
|
||||
/* validate the security checksum */
|
||||
x = (call->cid & RXRPC_CHANNELMASK) << (32 - RXRPC_CIDSHIFT);
|
||||
x |= seq & 0x3fffffff;
|
||||
crypto.buf[0] = htonl(call->call_id);
|
||||
crypto.buf[1] = htonl(x);
|
||||
|
||||
sg_init_one(&sg, crypto.buf, 8);
|
||||
skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
|
||||
skcipher_request_set_callback(req, 0, NULL, NULL);
|
||||
skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
|
||||
ret = crypto_skcipher_encrypt(req);
|
||||
skcipher_request_zero(req);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
/* continue encrypting from where we left off */
|
||||
fcrypt_pcbc_encrypt(call->conn->rxkad.cipher,
|
||||
call->conn->rxkad.csum_iv.x, crypto.buf, crypto.buf,
|
||||
1);
|
||||
|
||||
y = ntohl(crypto.buf[1]);
|
||||
cksum = (y >> 16) & 0xffff;
|
||||
|
|
@ -617,18 +485,16 @@ static int rxkad_verify_packet(struct rxrpc_call *call, struct sk_buff *skb)
|
|||
ret = 0;
|
||||
break;
|
||||
case RXRPC_SECURITY_AUTH:
|
||||
ret = rxkad_verify_packet_1(call, skb, seq, req);
|
||||
ret = rxkad_verify_packet_1(call, skb, seq);
|
||||
break;
|
||||
case RXRPC_SECURITY_ENCRYPT:
|
||||
ret = rxkad_verify_packet_2(call, skb, seq, req);
|
||||
ret = rxkad_verify_packet_2(call, skb, seq);
|
||||
break;
|
||||
default:
|
||||
ret = -ENOANO;
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
skcipher_request_free(req);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -712,41 +578,6 @@ static void rxkad_calc_response_checksum(struct rxkad_response *response)
|
|||
response->encrypted.checksum = htonl(csum);
|
||||
}
|
||||
|
||||
/*
|
||||
* encrypt the response packet
|
||||
*/
|
||||
static int rxkad_encrypt_response(struct rxrpc_connection *conn,
|
||||
struct sk_buff *response,
|
||||
const struct rxkad_key *s2)
|
||||
{
|
||||
struct skcipher_request *req;
|
||||
struct rxrpc_crypt iv;
|
||||
struct scatterlist sg[1];
|
||||
size_t encsize = sizeof(((struct rxkad_response *)0)->encrypted);
|
||||
int ret;
|
||||
|
||||
sg_init_table(sg, ARRAY_SIZE(sg));
|
||||
ret = skb_to_sgvec(response, sg,
|
||||
sizeof(struct rxrpc_wire_header) +
|
||||
offsetof(struct rxkad_response, encrypted), encsize);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
req = skcipher_request_alloc(&conn->rxkad.cipher->base, GFP_NOFS);
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
|
||||
/* continue encrypting from where we left off */
|
||||
memcpy(&iv, s2->session_key, sizeof(iv));
|
||||
|
||||
skcipher_request_set_sync_tfm(req, conn->rxkad.cipher);
|
||||
skcipher_request_set_callback(req, 0, NULL, NULL);
|
||||
skcipher_request_set_crypt(req, sg, sg, encsize, iv.x);
|
||||
ret = crypto_skcipher_encrypt(req);
|
||||
skcipher_request_free(req);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate a challenge packet.
|
||||
*/
|
||||
|
|
@ -846,6 +677,12 @@ int rxkad_insert_response_header(struct rxrpc_connection *conn,
|
|||
|
||||
rxkad_calc_response_checksum(&h.resp);
|
||||
|
||||
/* encrypt the response packet */
|
||||
static_assert(sizeof(h.resp.encrypted) % FCRYPT_BSIZE == 0);
|
||||
fcrypt_pcbc_encrypt(conn->rxkad.cipher, token->kad->session_key,
|
||||
&h.resp.encrypted, &h.resp.encrypted,
|
||||
sizeof(h.resp.encrypted) / FCRYPT_BSIZE);
|
||||
|
||||
ret = skb_store_bits(response, *offset, &h, sizeof(h));
|
||||
*offset += sizeof(h);
|
||||
return ret;
|
||||
|
|
@ -890,10 +727,6 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn,
|
|||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
ret = rxkad_encrypt_response(conn, response, token->kad);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
ret = skb_store_bits(response, offset, token->kad->ticket,
|
||||
token->kad->ticket_len);
|
||||
if (ret < 0)
|
||||
|
|
@ -1072,39 +905,22 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
|
|||
/*
|
||||
* decrypt the response packet
|
||||
*/
|
||||
static int rxkad_decrypt_response(struct rxrpc_connection *conn,
|
||||
struct rxkad_response *resp,
|
||||
const struct rxrpc_crypt *session_key)
|
||||
static void rxkad_decrypt_response(struct rxrpc_connection *conn,
|
||||
struct rxkad_response *resp,
|
||||
const struct rxrpc_crypt *session_key)
|
||||
{
|
||||
struct skcipher_request *req = rxkad_ci_req;
|
||||
struct scatterlist sg[1];
|
||||
struct rxrpc_crypt iv;
|
||||
int ret;
|
||||
struct fcrypt_key cipher;
|
||||
|
||||
_enter(",,%08x%08x",
|
||||
ntohl(session_key->n[0]), ntohl(session_key->n[1]));
|
||||
|
||||
mutex_lock(&rxkad_ci_mutex);
|
||||
ret = crypto_sync_skcipher_setkey(rxkad_ci, session_key->x,
|
||||
sizeof(*session_key));
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
|
||||
memcpy(&iv, session_key, sizeof(iv));
|
||||
|
||||
sg_init_table(sg, 1);
|
||||
sg_set_buf(sg, &resp->encrypted, sizeof(resp->encrypted));
|
||||
skcipher_request_set_sync_tfm(req, rxkad_ci);
|
||||
skcipher_request_set_callback(req, 0, NULL, NULL);
|
||||
skcipher_request_set_crypt(req, sg, sg, sizeof(resp->encrypted), iv.x);
|
||||
ret = crypto_skcipher_decrypt(req);
|
||||
skcipher_request_zero(req);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&rxkad_ci_mutex);
|
||||
fcrypt_preparekey(&cipher, session_key->x);
|
||||
|
||||
static_assert(sizeof(resp->encrypted) % FCRYPT_BSIZE == 0);
|
||||
fcrypt_pcbc_decrypt(&cipher, session_key->x, &resp->encrypted,
|
||||
&resp->encrypted,
|
||||
sizeof(resp->encrypted) / FCRYPT_BSIZE);
|
||||
_leave("");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1191,9 +1007,7 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
|
|||
|
||||
/* use the session key from inside the ticket to decrypt the
|
||||
* response */
|
||||
ret = rxkad_decrypt_response(conn, response, &session_key);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
rxkad_decrypt_response(conn, response, &session_key);
|
||||
|
||||
if (ntohl(response->encrypted.epoch) != conn->proto.epoch ||
|
||||
ntohl(response->encrypted.cid) != conn->proto.cid ||
|
||||
|
|
@ -1270,8 +1084,8 @@ static void rxkad_clear(struct rxrpc_connection *conn)
|
|||
{
|
||||
_enter("");
|
||||
|
||||
if (conn->rxkad.cipher)
|
||||
crypto_free_sync_skcipher(conn->rxkad.cipher);
|
||||
kfree_sensitive(conn->rxkad.cipher);
|
||||
conn->rxkad.cipher = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1279,26 +1093,11 @@ static void rxkad_clear(struct rxrpc_connection *conn)
|
|||
*/
|
||||
static int rxkad_init(void)
|
||||
{
|
||||
struct crypto_sync_skcipher *tfm;
|
||||
struct skcipher_request *req;
|
||||
|
||||
/* pin the cipher we need so that the crypto layer doesn't invoke
|
||||
* keventd to go get it */
|
||||
tfm = crypto_alloc_sync_skcipher("pcbc(fcrypt)", 0, 0);
|
||||
if (IS_ERR(tfm))
|
||||
return PTR_ERR(tfm);
|
||||
|
||||
req = skcipher_request_alloc(&tfm->base, GFP_KERNEL);
|
||||
if (!req)
|
||||
goto nomem_tfm;
|
||||
|
||||
rxkad_ci_req = req;
|
||||
rxkad_ci = tfm;
|
||||
if (fips_enabled) {
|
||||
pr_warn("rxkad support is disabled due to FIPS\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
return 0;
|
||||
|
||||
nomem_tfm:
|
||||
crypto_free_sync_skcipher(tfm);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1306,8 +1105,6 @@ static int rxkad_init(void)
|
|||
*/
|
||||
static void rxkad_exit(void)
|
||||
{
|
||||
crypto_free_sync_skcipher(rxkad_ci);
|
||||
skcipher_request_free(rxkad_ci_req);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user