Making KLIPS 1 asynchronous to support H/W crypto
Arthur van Leeuwen <[email protected]> Mon, 3 Mar 2003 15:44:06 +0100 (CET)
| Newsgroups | gmane.network.freeswan.devel |
|---|---|
| Message-ID | <[email protected]> |
Hello, in the search for the elusive hardware encryption for FreeS/WAN I have been trying to redo the Colubris hardware encryption patch for FreeS/WAN 1.91 with FreeS/WAN 2.00(-rc1). I decided to try and do it `the right way'. This involved basically making KLIPS 1 support asynchronous encryption operations, and then making the minimal changes necessary to offload the actual encryption to Martin Gadbois' cryptolib. The idea of making KLIPS 1 support asynchronous encryption is that of breaking up loops and basic blocks in which encryption can take place and allow re-entry from a callback. This is accomplished by keeping the decrypting function's state not on the stack but on the heap and passing pointers to it around. Fortunately, for ipsec_rcv in linux/net/ipsec/ipsec_rcv.c this is already partially done by encapsulating almost all necessary state in an ipsec_rcv_state struct. All that needs to be done is break the function at the correct place so that a callback can re-enter the decryption from an interrupt handler for a crypto-board and allocate the ipsec_rcv_state struct on the heap. Note that it isn't quite as easy, as the code *does* take locks, and these need to be released at appropriate times. For ipsec_start_xmit the situation is not that easy. It has not been refactored yet. The ipsec_start_xmit code is one huge function of some 1600 lines. The first 343 lines of these, up to the comment /* start encapsulation loop here XXX */ are not directly involved with encrypting. The next 1094 lines *are*. The last 132 lines are involved with actually sending the packet and cleaning up. Now, the 1094 lines that are directly involved with encrypting form 1 single loop. In this loop there is code that sets up the encryption steps and a loop that then does the actual encryption. This loop ought to be split off, so that entry into the loop can be done asynchronously. This means that every loop nesting level from the outer loop down to the actual encryption call needs to be factored out into a seperate function. The trouble is in a few issues: - what state does the loop keep, and what state should therefore be carried over the asynchronous call? - what locks does the loop hold and what locks can and can not be released over the asynchronous call? Accompanied are my patch to FreeS/WAN 2.00-rc1 (afaik it should also patch cleanly to 2.00-rc2, but I haven't tested that), and my version of the cryptolib that applies cleanly to a RedHat 2.4.18-24 kernel. (Took me a bit to figure out: Martin's cryptolib actually also supports synchronous encryption, so I first tried that, but most hardware doesn't, so it didn't actually work :), and KLIPS 1 is *monstrous* to say the very least. I think I can pinpoint at least 1 bug just by reading the code... I still need to verify that though.) Now, what I want to know: am I completely off the rocker on my assessment? Is this approach reasonable? Are there obvious pitfalls? I am concerned about possible information leaks due to for instance releasing the tdb_lock when asynchronously encrypting a transmit request: the ipsec_sa table may get modified in the meantime. Fortunately releasing the lock when encrypting upon receive seems to merely result in a spurious drop, and I don't feel the need to deal with those, higher level protocols as TCP can do that. IP doesn't guarantee reception of data anyway. Comments? Doei, Arthur. -- +- Arthur van Leeuwen, Systems Consultant, [email protected] -+ | X/OS Experts in Open Systems BV | | Kruislaan 419 Phone: +31 20 6938364 | | 1098 VA Amsterdam Fax: +31 20 6948204 |
freeswan-2.00-rc1-cryptolib.patch
(text/plain, 27.5 KB)
diff -Naur --exclude '*.swp' freeswan-2.00-rc1/linux/include/freeswan/ipsec_sa.h freeswan-2.00-rc1-cryptolib/linux/include/freeswan/ipsec_sa.h
--- freeswan-2.00-rc1/linux/include/freeswan/ipsec_sa.h Thu Jan 30 03:31:52 2003
+++ freeswan-2.00-rc1-cryptolib/linux/include/freeswan/ipsec_sa.h Fri Feb 28 11:28:16 2003
@@ -177,6 +177,18 @@
caddr_t ips_key_e; /* encryption key */
caddr_t ips_iv; /* Initialisation Vector */
+ /*** AVL XXX random and key data for cryptolib ***/
+#if 1
+#define IPSEC_SA_RANDOM_STRING_LEN 64
+ __u8 *ips_random_str; /* random numbers for iv */
+ __u8 ips_random_ctr; /* where we are in random string */
+
+ void *ips_key_raw_a; /* raw authentication key */
+ void *ips_key_raw_e; /* raw encryption key */
+ __u16 ips_key_raw_a_size;
+ __u16 ips_key_raw_e_size;
+#endif
+
struct ident ips_ident_s; /* identity src */
struct ident ips_ident_d; /* identity dst */
diff -Naur --exclude '*.swp' freeswan-2.00-rc1/linux/net/ipsec/ipsec_rcv.c freeswan-2.00-rc1-cryptolib/linux/net/ipsec/ipsec_rcv.c
--- freeswan-2.00-rc1/linux/net/ipsec/ipsec_rcv.c Fri Dec 13 21:58:03 2002
+++ freeswan-2.00-rc1-cryptolib/linux/net/ipsec/ipsec_rcv.c Fri Feb 28 11:22:18 2003
@@ -54,6 +54,8 @@
#include <asm/checksum.h>
#include <net/ip.h>
+#include <linux/if_crypto.h> /* cryptolib crypto offloading */
+
#include "freeswan/radij.h"
#include "freeswan/ipsec_encap.h"
#include "freeswan/ipsec_sa.h"
@@ -220,6 +222,8 @@
#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
enum ipsec_rcv_value {
+ IPSEC_RCV_PENDING=3,
+ IPSEC_RCV_CONTINUE=2,
IPSEC_RCV_LASTPROTO=1,
IPSEC_RCV_OK=0,
IPSEC_RCV_BADPROTO=-1,
@@ -262,6 +266,9 @@
__u8 *ictx;
int ictx_len;
int octx_len;
+ unsigned char * authenticator;
+ int replay;
+ struct crypto_request *cryptreq;
union {
struct {
struct esp *espp;
@@ -330,6 +337,48 @@
}
enum ipsec_rcv_value
+ipsec_rcv_esp_decrypt_bh(struct ipsec_rcv_state *irs);
+
+enum ipsec_rcv_value
+ipsec_rcv_decap_once_bh(struct ipsec_rcv_state *irs, enum ipsec_rcv_value bh_stat);
+
+int ipsec_rcv_bh(struct ipsec_rcv_state * irs, enum ipsec_rcv_value bh_stat);
+
+void ipsec_rcv_esp_decrypt_done(struct crypto_request *cryptreq) {
+ struct ipsec_rcv_state *irs = (struct ipsec_rcv_state *)cryptreq->priv;
+ struct crypto_operation *op;
+ enum ipsec_rcv_value retval;
+ int i;
+
+ for (op = &req->op; op != NULL; op=op->next) {
+ if (op->cmd & (CRYPT_MD5 | CRYPT_SHA)) {
+ for (i=0;i<(op->u.hash.reslen<AH_AMAX?op->u.hash.reslen:AH_AMAX);i++) {
+ irs->hash[i] = op->u.hash.result[i];
+ }
+ break;
+ }
+ }
+
+ /* We don't need the crypto request itself anymore, free it */
+ op = &req->op.next;
+ while (op!=NULL) {
+ struct crypto_operation *del;
+ del=op;
+ op=op->next;
+ kfree(del);
+ }
+ crypto_free_request(cryptreq);
+ irs->cryptreq=NULL;
+
+ /* Re-acquire the lock before going into bottom halves */
+ spin_lock(&tdb_lock);
+
+ retval = ipsec_rcv_esp_decrypt_bh(irs);
+ retval = ipsec_rcv_decap_once_bh(irs,retval);
+ ipsec_rcv_bh(irs,retval);
+}
+
+enum ipsec_rcv_value
ipsec_rcv_esp_decrypt_setup(struct ipsec_rcv_state *irs,
struct sk_buff *skb,
__u32 *replay,
@@ -365,24 +414,50 @@
SHA1_CTX sha1;
} tctx;
- aa = irs->authfuncs;
+ switch (irs->ipsp->ips_authalg) {
+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+ case AH_MD5:
+ irs->cryptreq = crypto_alloc_request(GFP_ATOMIC);
- /* copy the initialized keying material */
- memcpy(&tctx, irs->ictx, irs->ictx_len);
+ irs->cryptreq->inbuf = skb->data + irs->iphlen;
+ irs->cryptreq->inlen = skb->len - irs->iphlen;
+ irs->cryptreq->outbuf = irs->cryptreq->inbuf;
+ irs->cryptreq->outlen = irs->cryptreq->inlen;
+ irs->cryptreq->flags = CRYPT_DATA;
+ irs->cryptreq->priv = irs;
+ irs->cryptreq->callback = ipsec_rcv_esp_decrypt_done;
+
+ irs->cryptreq->op->cmd = CRYPT_DECODE | CRYPT_MD5 | CRYPT_HMAC | CRYPT_96;
+ irs->cryptreq->op->offset = 0;
+ irs->cryptreq->op->len = skb->len - irs->iphlen - irs->authlen;
+ memcpy(irs->cryptreq->u.hash.hmac_key,irs->ipsp->ips_key_raw_a,irs->ipsp->ips_key_raw_a_size);
+ irs->cryptreq->op->u.hash.hmac_key_len=irs->ipsp->ips_key_raw_a_size;
+ break;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
+ case AH_SHA:
+ aa = irs->authfuncs;
- (*aa->update)((void *)&tctx, (caddr_t)espp, irs->ilen);
+ /* copy the initialized keying material */
+ memcpy(&tctx, irs->ictx, irs->ictx_len);
- (*aa->final)(irs->hash, (void *)&tctx);
+ (*aa->update)((void *)&tctx, (caddr_t)espp, irs->ilen);
- memcpy(&tctx, irs->octx, irs->octx_len);
+ (*aa->final)(irs->hash, (void *)&tctx);
- (*aa->update)((void *)&tctx, irs->hash, AHMD596_ALEN);
- (*aa->final)(irs->hash, (void *)&tctx);
+ memcpy(&tctx, irs->octx, irs->octx_len);
+
+ (*aa->update)((void *)&tctx, irs->hash, AHMD596_ALEN);
+ (*aa->final)(irs->hash, (void *)&tctx);
+ break;
+#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
+ case AH_NONE:
+ break;
+ }
return IPSEC_RCV_OK;
}
-
enum ipsec_rcv_value
ipsec_rcv_esp_decrypt(struct ipsec_rcv_state *irs)
{
@@ -393,8 +468,9 @@
__u32 iv[2];
int pad = 0, padlen;
int badpad = 0;
- int i;
+ int i, err;
struct sk_buff *skb;
+ struct crypto_operation *op;
skb=irs->skb;
@@ -430,6 +506,36 @@
}
return IPSEC_RCV_3DES_BADBLOCKING;
}
+ if (irs->cryptreq == NULL) {
+ irs->cryptreq = crypto_alloc_request(GFP_ATOMIC);
+
+ irs->cryptreq->inbuf = skb->data + irs->iphlen;
+ irs->cryptreq->inlen = skb->len - irs->iphlen;
+ irs->cryptreq->outbuf = irs->cryptreq->inbuf;
+ irs->cryptreq->outlen = irs->cryptreq->inlen;
+ irs->cryptreq->flags = CRYPT_DATA;
+ irs->cryptreq->priv = irs;
+ irs->cryptreq->callback = ipsec_rcv_esp_decrypt_done;
+ op = &(irs->cryptreq->op);
+ } else {
+ irs->cryptreq->op->next = kmalloc(sizeof *op,GFP_ATOMIC);
+ op = irs->cryptreq->op->next;
+ if (op == NULL) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "memory allocation error (crypto op)\n");
+ return IPSEC_RCV_ESP_DECAPFAIL;
+ }
+ }
+
+ op->cmd = CRYPT_DECODE | CRYPT_3DES | CRYPT_CBC;
+ op->offset = esphlen;
+ op->len = skb->len - irs->iphlen - irs->authlen - esphlen;
+ memcpy(op->u.des.key, irs->ipsp->ips_key_raw_e,3*sizeof(des_cblock));
+ op->u.des.ivec=(des_cblock *)espp->esp_iv;
+ op->next = NULL;
+
+#if 0
des_ede3_cbc_encrypt((des_cblock *)idat,
(des_cblock *)idat,
irs->ilen,
@@ -437,9 +543,38 @@
((struct des_eks *)(ipsp->ips_key_e))[1].ks,
((struct des_eks *)(ipsp->ips_key_e))[2].ks,
(des_cblock *)iv, 0);
+#endif
+ err = crypto_execute(irs->cryptreq);
+ if (err == CRYPT_OK || err == CRYPT_READY) {
+ spin_unlock(&tdb_lock);
+ return (IPSEC_RCV_PENDING);
+ } else {
+ return (IPSEC_RCV_ESP_DECAPFAIL);
+ }
+
break;
}
+ return ipsec_rcv_esp_decrypt_bh(irs);
+}
+
+enum ipsec_rcv_value
+ipsec_rcv_esp_decrypt_bh(struct ipsec_rcv_state *irs)
+{
+ struct ipsec_sa *ipsp = irs->ipsp;
+ struct esp *espp = irs->protostuff.espstuff.espp;
+ int esphlen = sizeof(struct esp);
+ __u8 *idat; /* pointer to content to be decrypted/authenticated */
+ __u32 iv[2];
+ int pad = 0, padlen;
+ int badpad = 0;
+ int i;
+ struct sk_buff *skb;
+
+ skb=irs->skb;
+
+ idat = skb->data + irs->iphlen + esphlen;
+
rcv_dmp("postdecrypt", skb->data, skb->len);
irs->next_header = idat[irs->ilen - 1];
@@ -851,7 +986,6 @@
__u8 proto;
struct in_addr ipsaddr;
struct in_addr ipdaddr;
- int replay = 0; /* replay value in AH or ESP packet */
struct ipsec_sa* ipsnext = NULL; /* next SA towards inside of packet */
#ifdef INBOUND_POLICY_CHECK_eroute
struct sockaddr_encap matcher; /* eroute search key */
@@ -865,6 +999,8 @@
struct iphdr *ipp;
struct sk_buff *skb;
+ irs->replay = 0; /* replay value in AH or ESP packet */
+ irs->authenticator = NULL;
skb = irs->skb;
irs->len = skb->len;
dat = skb->data;
@@ -1092,7 +1228,6 @@
}
if(irs->authfuncs) {
- unsigned char *authenticator = NULL;
irs->ilen = irs->len - iphlen - irs->authlen;
if(irs->ilen <= 0) {
@@ -1109,14 +1244,14 @@
if(proto_funcs->setup_auth) {
enum ipsec_rcv_value retval
= (*proto_funcs->setup_auth)(irs, skb,
- &replay,
- &authenticator);
+ &(irs->replay),
+ &(irs->authenticator));
if(retval < 0) {
return retval;
}
}
- if(!authenticator) {
+ if(!(irs->authenticator)) {
irs->ipsp->ips_errs.ips_auth_errs += 1;
if(irs->stats) {
irs->stats->rx_dropped++;
@@ -1124,7 +1259,7 @@
return IPSEC_RCV_BADAUTH;
}
- if(!ipsec_checkreplaywindow(irs->ipsp, replay)) {
+ if(!ipsec_checkreplaywindow(irs->ipsp, irs->replay)) {
irs->ipsp->ips_errs.ips_replaywin_errs += 1;
KLIPS_PRINT(debug_rcv & DB_RX_REPLAY,
"klips_debug:ipsec_rcv: "
@@ -1152,7 +1287,35 @@
}
(*proto_funcs->calc_auth)(irs, skb);
- if (memcmp(irs->hash, authenticator, irs->authlen)) {
+ }
+
+ if(proto_funcs->decrypt) {
+ enum ipsec_rcv_value retval =
+ (*proto_funcs->decrypt)(irs);
+
+ if(retval != IPSEC_RCV_OK) {
+ return retval;
+ }
+ }
+
+ return ipsec_rcv_decap_once_bh(irs);
+}
+
+enum ipsec_rcv_value
+ipsec_rcv_decap_once_bh(struct ipsec_rcv_state *irs, enum ipsec_rcv_value bh_stat)
+{
+ struct in_addr ipsaddr;
+ struct in_addr ipdaddr;
+ struct ipsec_sa *ipsnext = NULL:
+ struct iphdr *ipp;
+ struct sk_buff *skb;
+
+ if(bh_stat != IPSEC_RCV_OK) {
+ return bh_stat;
+ }
+
+ if(irs->authfuncs) {
+ if (memcmp(irs->hash, irs->authenticator, irs->authlen)) {
irs->ipsp->ips_errs.ips_auth_errs += 1;
KLIPS_PRINT(debug_rcv & DB_RX_INAU,
"klips_debug:ipsec_rcv: "
@@ -1161,9 +1324,9 @@
ntohl(*(__u32*)&irs->hash[0]),
ntohl(*(__u32*)&irs->hash[4]),
ntohl(*(__u32*)&irs->hash[8]),
- ntohl(*(__u32*)authenticator),
- ntohl(*((__u32*)authenticator + 1)),
- ntohl(*((__u32*)authenticator + 2)));
+ ntohl(*(__u32*)irs->authenticator),
+ ntohl(*((__u32*)irs->authenticator + 1)),
+ ntohl(*((__u32*)irs->authenticator + 2)));
if(irs->stats) {
irs->stats->rx_dropped++;
}
@@ -1180,7 +1343,7 @@
memset(irs->hash, 0, irs->authlen);
/* If the sequence number == 0, expire SA, it had rolled */
- if(irs->ipsp->ips_replaywin && !replay /* !irs->ipsp->ips_replaywin_lastseq */) {
+ if(irs->ipsp->ips_replaywin && !(irs->replay) /* !irs->ipsp->ips_replaywin_lastseq */) {
ipsec_sa_delchain(irs->ipsp);
KLIPS_PRINT(debug_rcv,
"klips_debug:ipsec_rcv: "
@@ -1192,7 +1355,7 @@
}
/* now update the replay counter */
- if (!ipsec_updatereplaywindow(irs->ipsp, replay)) {
+ if (!ipsec_updatereplaywindow(irs->ipsp, irs->replay)) {
irs->ipsp->ips_errs.ips_replaywin_errs += 1;
KLIPS_PRINT(debug_rcv & DB_RX_REPLAY,
"klips_debug:ipsec_rcv: "
@@ -1204,16 +1367,6 @@
return IPSEC_RCV_REPLAYROLLED;
}
}
-
- if(proto_funcs->decrypt) {
- enum ipsec_rcv_value retval =
- (*proto_funcs->decrypt)(irs);
-
- if(retval != IPSEC_RCV_OK) {
- return retval;
- }
- }
-
/*
* Adjust pointers
*/
@@ -1244,7 +1397,7 @@
ipp->protocol = irs->next_header;
ipp->check = 0; /* NOTE: this will be included in checksum */
- ipp->check = ip_fast_csum((unsigned char *)dat, iphlen >> 2);
+ ipp->check = ip_fast_csum((unsigned char *)dat, (irs->iphlen) >> 2);
KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
"klips_debug:ipsec_rcv: "
@@ -1310,13 +1463,13 @@
irs->ipsp->ips_life.ipl_packets.ipl_count += 1;
#ifdef CONFIG_NETFILTER
- if(proto == IPPROTO_ESP || proto == IPPROTO_AH) {
+ if(irs->said.proto == IPPROTO_ESP || irs->said.proto == IPPROTO_AH) {
skb->nfmark = (skb->nfmark & (~(IPsecSAref2NFmark(IPSEC_SA_REF_MASK))))
| IPsecSAref2NFmark(IPsecSA2SAref(irs->ipsp));
KLIPS_PRINT(debug_rcv & DB_RX_PKTRX,
"klips_debug:ipsec_rcv: "
"%s SA sets skb->nfmark=0x%x.\n",
- proto == IPPROTO_ESP ? "ESP" : "AH",
+ irs->said.proto == IPPROTO_ESP ? "ESP" : "AH",
(unsigned)skb->nfmark);
}
#endif /* CONFIG_NETFILTER */
@@ -1324,7 +1477,6 @@
return IPSEC_RCV_OK;
}
-
int
#ifdef PROTO_HANDLER_SINGLE_PARM
ipsec_rcv(struct sk_buff *skb)
@@ -1365,12 +1517,18 @@
struct sockaddr_encap policy_eaddr;
struct sockaddr_encap policy_emask;
#endif /* INBOUND_POLICY_CHECK_eroute */
- struct ipsec_rcv_state irs;
+ struct ipsec_rcv_state * irs;
/* Don't unlink in the middle of a turnaround */
MOD_INC_USE_COUNT;
- memset(&irs, 0, sizeof(struct ipsec_rcv_state));
+ if ((irs = kmalloc(sizeof(struct ipsec_rcv_state,GFP_ATOMIC)))==NULL) {
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: "
+ "memory allocation error, dropping packet\n");
+ goto rcvleave;
+ }
+ memset(irs, 0, sizeof(struct ipsec_rcv_state));
if (skb == NULL) {
KLIPS_PRINT(debug_rcv,
@@ -1395,9 +1553,9 @@
#endif /* IPH_is_SKB_PULLED */
/* dev->hard_header_len is unreliable and should not be used */
- irs.hard_header_len = skb->mac.raw ? (skb->data - skb->mac.raw) : 0;
- if((irs.hard_header_len < 0) || (irs.hard_header_len > skb_headroom(skb)))
- irs.hard_header_len = 0;
+ irs->hard_header_len = skb->mac.raw ? (skb->data - skb->mac.raw) : 0;
+ if((irs->hard_header_len < 0) || (irs->hard_header_len > skb_headroom(skb)))
+ irs->hard_header_len = 0;
#ifdef NET_21
/* if skb was cloned (most likely due to a packet sniffer such as
@@ -1405,14 +1563,14 @@
a copy of our own to modify */
if(skb_cloned(skb)) {
/* include any mac header while copying.. */
- if(skb_headroom(skb) < irs.hard_header_len) {
+ if(skb_headroom(skb) < irs->hard_header_len) {
printk(KERN_WARNING "klips_error:ipsec_rcv: "
"tried to skb_push hhlen=%d, %d available. This should never happen, please report.\n",
- irs.hard_header_len,
+ irs->hard_header_len,
skb_headroom(skb));
goto rcvleave;
}
- skb_push(skb, irs.hard_header_len);
+ skb_push(skb, irs->hard_header_len);
if
#ifdef SKB_COW_NEW
(skb_cow(skb, skb_headroom(skb)) != 0)
@@ -1422,14 +1580,14 @@
{
goto rcvleave;
}
- if(skb->len < irs.hard_header_len) {
+ if(skb->len < irs->hard_header_len) {
printk(KERN_WARNING "klips_error:ipsec_rcv: "
"tried to skb_pull hhlen=%d, %d available. This should never happen, please report.\n",
- irs.hard_header_len,
+ irs->hard_header_len,
skb->len);
goto rcvleave;
}
- skb_pull(skb, irs.hard_header_len);
+ skb_pull(skb, irs->hard_header_len);
}
#endif /* NET_21 */
@@ -1448,10 +1606,10 @@
ipp = skb->nh.iph;
ipsaddr.s_addr = ipp->saddr;
- addrtoa(ipsaddr, 0, irs.ipsaddr_txt, sizeof(irs.ipsaddr_txt));
+ addrtoa(ipsaddr, 0, irs->ipsaddr_txt, sizeof(irs->ipsaddr_txt));
ipdaddr.s_addr = ipp->daddr;
- addrtoa(ipdaddr, 0, irs.ipdaddr_txt, sizeof(irs.ipdaddr_txt));
- irs.iphlen = ipp->ihl << 2;
+ addrtoa(ipdaddr, 0, irs->ipdaddr_txt, sizeof(irs->ipdaddr_txt));
+ irs->iphlen = ipp->ihl << 2;
KLIPS_PRINT(debug_rcv,
"klips_debug:ipsec_rcv: "
@@ -1549,8 +1707,6 @@
KLIPS_IP_PRINT(debug_rcv, ipp);
- /* begin decapsulating loop here */
-
/*
The spinlock is to prevent any other process from
accessing or deleting the ipsec_sa hash table or any of the
@@ -1563,21 +1719,81 @@
in KLIPS1 unless a volunteer contributes it, but will be
designed into KLIPS2.
*/
+
spin_lock(&tdb_lock);
/* set up for decap loop */
- irs.stats= stats;
- irs.ipp = ipp;
- irs.ipsp = NULL;
- irs.ilen = 0;
- irs.authlen=0;
- irs.authfuncs=NULL;
- irs.skb = skb;
+ irs->stats= stats;
+ irs->ipp = ipp;
+ irs->ipsp = NULL;
+ irs->ilen = 0;
+ irs->authlen=0;
+ irs->authfuncs=NULL;
+ irs->skb = skb;
+
+ return ipsec_rcv_bh(irs,IPSEC_RCV_CONTINUE);
+
+ rcvleave:
+ if(skb) {
+#ifdef NET_21
+ kfree_skb(skb);
+#else /* NET_21 */
+ kfree_skb(skb, FREE_WRITE);
+#endif /* NET_21 */
+ }
+
+ kfree(irs);
+
+ MOD_DEC_USE_COUNT;
+ return(0);
+}
+
+int
+ipsec_rcv_bh(struct ipsec_rcv_state * irs, enum ipsec_rcv_value bh_stat)
+{
+ struct sk_buf *skb = irs->skb
+ struct iphdr *ipp;
+ struct ipsec_sa *ipsp = NULL;
+ struct ipsec_sa *ipsnext = NULL;
+ struct net_device_stats *stats = irs->stats;
+ struct in_addr ipsaddr;
+ struct in_addr ipdaddr;
+#ifdef INBOUND_POLICY_CHECK_eroute
+ struct sockaddr_encap matcher; /* eroute search key */
+ struct eroute *er;
+ struct sa_id policy_said;
+ struct sockaddr_encap policy_eaddr;
+ struct sockaddr_encap policy_emask;
+#endif /* INBOUND_POLICY_CHECK_eroute */
+
+
+ /* begin decapsulating loop here */
+
+ if (bh_stat != IPSEC_RCV_OK && bh_stat != IPSEC_RCV_CONTINUE) {
+ spin_unlock(&tdb_lock);
+ KLIPS_PRINT(debug_rcv,
+ "klips_debug:ipsec_rcv: decap_once (async) failed: %d\n",
+ bh_stat);
+ goto rcvleave;
+ }
+
+ if( (irs->ipp->protocol != IPPROTO_ESP )
+ && (irs->ipp->protocol != IPPROTO_AH )
+#ifdef CONFIG_IPSEC_IPCOMP
+ && (irs->ipp->protocol != IPPROTO_COMP)
+#endif /* CONFIG_IPSEC_IPCOMP */
+ ) {
+ goto decapdone;
+ }
do {
int decap_stat;
- decap_stat = ipsec_rcv_decap_once(&irs);
+ decap_stat = ipsec_rcv_decap_once(irs);
+
+ if(decap_stat == IPSEC_RCV_PENDING) {
+ return(0);
+ }
if(decap_stat != IPSEC_RCV_OK) {
spin_unlock(&tdb_lock);
@@ -1588,18 +1804,20 @@
goto rcvleave;
}
/* end decapsulation loop here */
- } while( (irs.ipp->protocol == IPPROTO_ESP )
- || (irs.ipp->protocol == IPPROTO_AH )
+ } while( (irs->ipp->protocol == IPPROTO_ESP )
+ || (irs->ipp->protocol == IPPROTO_AH )
#ifdef CONFIG_IPSEC_IPCOMP
- || (irs.ipp->protocol == IPPROTO_COMP)
+ || (irs->ipp->protocol == IPPROTO_COMP)
#endif /* CONFIG_IPSEC_IPCOMP */
);
+ decapdone:
+
/* set up for decap loop */
- ipp =irs.ipp;
- ipsp =irs.ipsp;
+ ipp =irs->ipp;
+ ipsp =irs->ipsp;
ipsnext = ipsp->ips_inext;
- skb = irs.skb;
+ skb = irs->skb;
/* if there is an IPCOMP, but we don't have an IPPROTO_COMP,
* then we can just skip it
@@ -1618,13 +1836,13 @@
*/
if(ipsnext) {
ipsp = ipsnext;
- irs.sa_len = satoa(irs.said, 0, irs.sa, SATOA_BUF);
+ irs->sa_len = satoa(irs->said, 0, irs->sa, SATOA_BUF);
if(ipp->protocol != IPPROTO_IPIP) {
spin_unlock(&tdb_lock);
KLIPS_PRINT(debug_rcv,
"klips_debug:ipsec_rcv: "
"SA:%s, Hey! How did this get through? Dropped.\n",
- irs.sa_len ? irs.sa : " (error)");
+ irs->sa_len ? irs->sa : " (error)");
if(stats) {
stats->rx_dropped++;
}
@@ -1640,7 +1858,7 @@
"klips_debug:ipsec_rcv: "
"unexpected SA:%s after IPIP SA:%s\n",
sa_len2 ? sa2 : " (error)",
- irs.sa_len ? irs.sa : " (error)");
+ irs->sa_len ? irs->sa : " (error)");
if(stats) {
stats->rx_dropped++;
}
@@ -1651,8 +1869,8 @@
KLIPS_PRINT(debug_rcv,
"klips_debug:ipsec_rcv: "
"SA:%s, src=%s of pkt does not agree with expected SA source address policy.\n",
- irs.sa_len ? irs.sa : " (error)",
- irs.ipsaddr_txt);
+ irs->sa_len ? irs->sa : " (error)",
+ irs->ipsaddr_txt);
if(stats) {
stats->rx_dropped++;
}
@@ -1674,16 +1892,16 @@
ipsp->ips_life.ipl_usetime.ipl_last = jiffies / HZ;
ipsp->ips_life.ipl_packets.ipl_count += 1;
- if(skb->len < irs.iphlen) {
+ if(skb->len < irs->iphlen) {
spin_unlock(&tdb_lock);
printk(KERN_WARNING "klips_debug:ipsec_rcv: "
"tried to skb_pull iphlen=%d, %d available. This should never happen, please report.\n",
- irs.iphlen,
+ irs->iphlen,
(int)(skb->len));
goto rcvleave;
}
- skb_pull(skb, irs.iphlen);
+ skb_pull(skb, irs->iphlen);
#ifdef NET_21
ipp = (struct iphdr *)skb->nh.raw = skb->data;
@@ -1696,9 +1914,9 @@
memset(skb->proto_priv, 0, sizeof(struct options));
#endif /* NET_21 */
ipsaddr.s_addr = ipp->saddr;
- addrtoa(ipsaddr, 0, irs.ipsaddr_txt, sizeof(irs.ipsaddr_txt));
+ addrtoa(ipsaddr, 0, irs->ipsaddr_txt, sizeof(irs->ipsaddr_txt));
ipdaddr.s_addr = ipp->daddr;
- addrtoa(ipdaddr, 0, irs.ipdaddr_txt, sizeof(irs.ipdaddr_txt));
+ addrtoa(ipdaddr, 0, irs->ipdaddr_txt, sizeof(irs->ipdaddr_txt));
skb->protocol = htons(ETH_P_IP);
skb->ip_summed = 0;
@@ -1732,11 +1950,11 @@
KLIPS_PRINT(debug_rcv,
"klips_debug:ipsec_rcv: "
"SA:%s, inner tunnel policy [%s -> %s] does not agree with pkt contents [%s -> %s].\n",
- irs.sa_len ? irs.sa : " (error)",
+ irs->sa_len ? irs->sa : " (error)",
sflow_txt,
dflow_txt,
- irs.ipsaddr_txt,
- irs.ipdaddr_txt);
+ irs->ipsaddr_txt,
+ irs->ipdaddr_txt);
if(stats) {
stats->rx_dropped++;
}
@@ -1854,12 +2072,12 @@
skb->dst = NULL;
}
skb->pkt_type = PACKET_HOST;
- if(irs.hard_header_len &&
- (skb->mac.raw != (skb->data - irs.hard_header_len)) &&
- (irs.hard_header_len <= skb_headroom(skb))) {
+ if(irs->hard_header_len &&
+ (skb->mac.raw != (skb->data - irs->hard_header_len)) &&
+ (irs->hard_header_len <= skb_headroom(skb))) {
/* copy back original MAC header */
- memmove(skb->data - irs.hard_header_len, skb->mac.raw, irs.hard_header_len);
- skb->mac.raw = skb->data - irs.hard_header_len;
+ memmove(skb->data - irs->hard_header_len, skb->mac.raw, irs->hard_header_len);
+ skb->mac.raw = skb->data - irs->hard_header_len;
}
#endif /* NET_21 */
@@ -1906,6 +2124,8 @@
"netif_rx() called.\n");
netif_rx(skb);
+ kfree(irs);
+
MOD_DEC_USE_COUNT;
return(0);
@@ -1918,6 +2138,8 @@
#endif /* NET_21 */
}
+ kfree(irs);
+
MOD_DEC_USE_COUNT;
return(0);
}
diff -Naur --exclude '*.swp' freeswan-2.00-rc1/linux/net/ipsec/ipsec_sa.c freeswan-2.00-rc1-cryptolib/linux/net/ipsec/ipsec_sa.c
--- freeswan-2.00-rc1/linux/net/ipsec/ipsec_sa.c Thu Jan 30 03:32:22 2003
+++ freeswan-2.00-rc1-cryptolib/linux/net/ipsec/ipsec_sa.c Fri Feb 28 11:55:12 2003
@@ -999,6 +999,31 @@
kfree(ips->ips_ident_d.data);
}
ips->ips_ident_d.data = NULL;
+
+ /*** AVL FIXME hw crypto ***/
+#if 1
+ if(ips->ips_random_str != NULL) {
+ memset((caddr_t)(ips->ips_random_str),
+ 0,
+ IPSEC_SA_RANDOM_STRING_LEN);
+ kfree(ips->ips_random_str);
+ }
+ ips->ips_random_str = NULL;
+
+ if(ips->ips_key_raw_a != NULL) {
+ memset((caddr_t)(ips->ips_key_raw_a),
+ 0,
+ ips->ips_key_raw_a_size);
+ kfree(ips->ips_key_raw_a);
+ }
+
+ if(ips->ips_key_raw_e != NULL) {
+ memset((caddr_t)(ips->ips_key_raw_e),
+ 0,
+ ips->ips_key_raw_e_size);
+ kfree(ips->ips_key_raw_e);
+ }
+#endif
memset((caddr_t)ips, 0, sizeof(*ips));
kfree(ips);
diff -Naur --exclude '*.swp' freeswan-2.00-rc1/linux/net/ipsec/ipsec_tunnel.c freeswan-2.00-rc1-cryptolib/linux/net/ipsec/ipsec_tunnel.c
--- freeswan-2.00-rc1/linux/net/ipsec/ipsec_tunnel.c Fri Dec 6 03:24:02 2002
+++ freeswan-2.00-rc1-cryptolib/linux/net/ipsec/ipsec_tunnel.c Fri Feb 28 16:44:37 2003
@@ -684,6 +684,8 @@
* the eroute while we are using and updating it.
*/
spin_lock(&eroute_lock);
+
+ /*** AVL XXX allcation of crypt req here? ***/
er = ipsec_findroute(&matcher);
@@ -1570,6 +1572,8 @@
#ifdef CONFIG_IPSEC_ENC_3DES
case ESP_3DES:
#endif /* CONFIG_IPSEC_ENC_3DES */
+ /* AVL XXX will possibly work
+ * async now: see below */
iv[0] = *((__u32*)&(espp->esp_iv) ) =
((__u32*)(ipsp->ips_iv))[0];
iv[1] = *((__u32*)&(espp->esp_iv) + 1) =
@@ -1599,6 +1603,7 @@
switch(ipsp->ips_encalg) {
#ifdef CONFIG_IPSEC_ENC_3DES
case ESP_3DES:
+ /* AVL XXX BUILD ASYNC Crypto call */
des_ede3_cbc_encrypt((des_cblock *)idat,
(des_cblock *)idat,
ilen,
@@ -1620,6 +1625,7 @@
case ESP_3DES:
#endif /* CONFIG_IPSEC_ENC_3DES */
/* XXX update IV with the last 8 octets of the encryption */
+ /* AVL XXX This should be in BH */
#if KLIPS_IMPAIRMENT_ESPIV_CBC_ATTACK
((__u32*)(ipsp->ips_iv))[0] =
((__u32 *)(idat))[(ilen >> 2) - 2];
@@ -1639,6 +1645,7 @@
switch(ipsp->ips_authalg) {
#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
case AH_MD5:
+ /* AVL XXX Expand ASYNC Crypto call */
dmp("espp", (char*)espp, len - iphlen - authlen);
tctx.md5 = ((struct md5_ctx*)(ipsp->ips_key_a))->ictx;
dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5));
diff -Naur --exclude '*.swp' freeswan-2.00-rc1/linux/net/ipsec/pfkey_v2_parser.c freeswan-2.00-rc1-cryptolib/linux/net/ipsec/pfkey_v2_parser.c
--- freeswan-2.00-rc1/linux/net/ipsec/pfkey_v2_parser.c Thu Jan 30 03:32:44 2003
+++ freeswan-2.00-rc1-cryptolib/linux/net/ipsec/pfkey_v2_parser.c Fri Feb 28 11:43:03 2003
@@ -376,6 +376,14 @@
}
prng_bytes(&ipsec_prng, (char *)ipsp->ips_iv, EMT_ESPDES_IV_SZ);
ipsp->ips_iv_bits = ipsp->ips_iv_size * 8;
+ /*** AVL XXX tdb_random_str (ipsp->ips_random_str) ***/
+# if 1
+ if((ipsp->ips_random_str=(caddr_t) kmalloc(IPSEC_SA_RANDOM_STRING_LEN,GFP_ATOMIC)) == NULL) {
+ SENDERR(ENOMEM);
+ }
+ get_random_bytes((void *)ipsp->ips_random_str, IPSEC_SA_RANDOM_STRING_LEN);
+ ipsp->ips_random_ctr = 0;
+#endif
break;
# endif /* defined(CONFIG_IPSEC_ENC_3DES) */
case ESP_NONE:
@@ -402,6 +410,12 @@
/* save encryption key pointer */
ekp = ipsp->ips_key_e;
eks = ipsp->ips_key_e_size;
+ /*** AVL XXX ips_key_raw_e ***/
+#if 1
+ /* Remember raw key, before S/W processing */
+ ipsp->ips_key_raw_e = ekp;
+ ipsp->ips_key_raw_e_size = eks;
+#endif
KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
"klips_debug:pfkey_ipsec_sa_init: "
@@ -443,9 +457,9 @@
}
}
- /* paranoid */
- memset(ekp, 0, eks);
- kfree(ekp);
+ /* paranoid */ /*** AVL XXX we still need the data */
+/* memset(ekp, 0, eks);
+ kfree(ekp); */
break;
# endif /* CONFIG_IPSEC_ENC_3DES */
case ESP_NONE:
@@ -487,6 +501,11 @@
/* save the pointer to the key material */
akp = ipsp->ips_key_a;
aks = ipsp->ips_key_a_size;
+ /*** AVL XXX key_raw_a ***/
+#if 1
+ ipsp->ips_key_raw_a = akp;
+ ipsp->ips_key_raw_a_size = aks;
+#endif
KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
"klips_debug:pfkey_ipsec_sa_init: "
@@ -531,9 +550,9 @@
((__u32*)octx)[2],
((__u32*)octx)[3] );
# endif /* KLIPS_DIVULGE_HMAC_KEY */
- /* paranoid */
- memset(akp, 0, aks);
- kfree(akp);
+ /* paranoid */ /*** AVL XXX but we need this data! */
+/* memset(akp, 0, aks);
+ kfree(akp); */
break;
}
# endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
@@ -565,6 +584,11 @@
/* save the pointer to the key material */
akp = ipsp->ips_key_a;
aks = ipsp->ips_key_a_size;
+ /*** AVL XXX key_raw ***/
+#if 0
+ ipsp->ips_key_raw_a = akp;
+ ipsp->ips_key_raw_a_size = aks;
+#endif
KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
"klips_debug:pfkey_ipsec_sa_init: "
@@ -609,8 +633,10 @@
((__u32*)octx)[2],
((__u32*)octx)[3] );
# endif /* KLIPS_DIVULGE_HMAC_KEY */
- memset(akp, 0, aks);
+#if 0
+ memset(akp, 0, aks); /*** AVL XXX we still need this */
kfree(akp);
+#endif
break;
}
# endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
linux-2.4.18-cryptolib.patch
(text/plain, 520.3 KB) - not displayed