diff options
author | Niels Provos <provos@cvs.openbsd.org> | 1998-03-04 11:43:56 +0000 |
---|---|---|
committer | Niels Provos <provos@cvs.openbsd.org> | 1998-03-04 11:43:56 +0000 |
commit | 4be2eb12506cf065e68c51750f45f81ba3d63717 (patch) | |
tree | b4cb6a032a89a159e425ace730b3bda6a7b1c25f /sbin/ipsec/photurisd/kernel.c | |
parent | 8b1bb75ad56e072dc58c33715385fa7e439b2503 (diff) |
compliance with draft-simpson-photuris-18.txt, better packet structure
checking, better support for new esp and ah, documentation ...
Diffstat (limited to 'sbin/ipsec/photurisd/kernel.c')
-rw-r--r-- | sbin/ipsec/photurisd/kernel.c | 432 |
1 files changed, 320 insertions, 112 deletions
diff --git a/sbin/ipsec/photurisd/kernel.c b/sbin/ipsec/photurisd/kernel.c index 09d33c7116b..d36d287b580 100644 --- a/sbin/ipsec/photurisd/kernel.c +++ b/sbin/ipsec/photurisd/kernel.c @@ -29,7 +29,7 @@ */ #ifndef lint -static char rcsid[] = "$Id: kernel.c,v 1.4 1997/09/14 10:37:51 deraadt Exp $"; +static char rcsid[] = "$Id: kernel.c,v 1.5 1998/03/04 11:43:32 provos Exp $"; #endif #include <sys/param.h> @@ -73,13 +73,80 @@ static char rcsid[] = "$Id: kernel.c,v 1.4 1997/09/14 10:37:51 deraadt Exp $"; #include "config.h" #endif +#ifdef DEBUG +time_t now; + +#define kernel_debug(x) {time(&now); printf("%.24s", ctime(&now)); printf x;} +#else +#define kernel_debug(x) +#endif + static int sd; +typedef struct { + int photuris_id; + int kernel_id, flags; +} transform; + +/* + * Translation from Photuris Attributes to Kernel Transforms. + * For the actual ids see: draft-simpson-photuris-*.txt and + * draft-simpson-photuris-schemes-*.txt + */ + +transform xf[] = { + { 5, ALG_AUTH_MD5, XF_AUTH|AH_OLD}, + { 6, ALG_AUTH_SHA1, XF_AUTH|AH_OLD}, + { 8, ALG_ENC_DES, XF_ENC|ESP_OLD}, + {100, ALG_ENC_3DES, XF_ENC|ESP_NEW}, + {101, ALG_ENC_BLF, XF_ENC|ESP_NEW}, + {102, ALG_ENC_CAST, XF_ENC|ESP_NEW}, + {105, ALG_AUTH_MD5, XF_AUTH|AH_NEW|ESP_NEW}, + {106, ALG_AUTH_SHA1, XF_AUTH|AH_NEW|ESP_NEW}, + {107, ALG_AUTH_RMD160, XF_AUTH|AH_NEW|ESP_NEW}, +}; + +/* + * Translate a Photuris ID to an offset into a data structure for the + * corresponding Kernel transform. + * This makes is easier to write kernel modules for different IPSec + * implementations. + */ + +int +kernel_get_offset(int id) +{ + int i; + + for (i=sizeof(xf)/sizeof(transform)-1; i >= 0; i--) + if (xf[i].photuris_id == id) + return i; + + return -1; +} + +/* + * For ESP, we can specify an additional AH transform. + * Not all combinations are possible. + * Returns AT_ENC, when the ESP transform does not allow this AH. + * Returns AT_AUTH, when the AH transform does not work with ESP. + */ + +int +kernel_valid(int encoff, int authoff) +{ + if (xf[encoff].flags & ESP_OLD) + return AT_ENC; + if (!(xf[authoff].flags & ESP_NEW)) + return AT_AUTH; + return 0; +} + int init_kernel(void) { if ((sd = socket(AF_ENCAP, SOCK_RAW, AF_UNSPEC)) < 0) - crit_error(1, "socket() in init_kernel()"); + crit_error(1, "socket() for IPSec in init_kernel()"); return 1; } @@ -92,10 +159,8 @@ kernel_get_socket(void) int kernel_xf_set(struct encap_msghdr *em) { - if (write(sd, (char *)em, em->em_msglen) != em->em_msglen) { - log_error(1, "write() in kernel_xf_set()"); + if (write(sd, (char *)em, em->em_msglen) != em->em_msglen) return 0; - } return 1; } @@ -115,6 +180,8 @@ kernel_reserve_spi(char *srcaddress, int options) u_int32_t spi; int proto; + kernel_debug(("kernel_reserve_spi: %s\n", srcaddress)); + if ((options & (IPSEC_OPT_ENC|IPSEC_OPT_AUTH)) != (IPSEC_OPT_ENC|IPSEC_OPT_AUTH)) { switch(options & (IPSEC_OPT_ENC|IPSEC_OPT_AUTH)) { @@ -144,6 +211,8 @@ kernel_reserve_single_spi(char *srcaddress, u_int32_t spi, int proto) { struct encap_msghdr *em; + kernel_debug(("kernel_reserve_single_spi: %s, %08x\n", srcaddress, spi)); + bzero(buffer, EMT_ENABLESPI_FLEN); em = (struct encap_msghdr *)buffer; @@ -156,8 +225,10 @@ kernel_reserve_single_spi(char *srcaddress, u_int32_t spi, int proto) em->em_gen_dst.s_addr = inet_addr(srcaddress); em->em_gen_sproto = proto; - if (!kernel_xf_set(em)) + if (!kernel_xf_set(em)) { + log_error(1, "kernel_xf_set() in kernel_reserve_single_spi()"); return 0; + } if (!kernel_xf_read(em, EMT_RESERVESPI_FLEN)) return 0; @@ -166,88 +237,173 @@ kernel_reserve_single_spi(char *srcaddress, u_int32_t spi, int proto) } int -kernel_md5(char *srcaddress, char *dstaddress, u_int8_t *spi, u_int8_t *secret, - int tunnel) +kernel_ah(attrib_t *ob, struct spiob *SPI, u_int8_t *secrets) { struct encap_msghdr *em; - struct ah_old_xencap *xd; - int klen; + struct ah_old_xencap *xdo; + struct ah_new_xencap *xdn; - klen = MD5_KEYLEN/8; - - bzero(buffer, EMT_SETSPI_FLEN + 4 + klen); + if (!(xf[ob->koff].flags & XF_AUTH)) { + log_error(0, "%d is not an auth transform in kernel_ah()", ob->id); + return -1; + } em = (struct encap_msghdr *)buffer; + + if (xf[ob->koff].flags & AH_OLD) { + bzero(buffer, EMT_SETSPI_FLEN + 4 + ob->klen); + + em->em_msglen = EMT_SETSPI_FLEN + AH_OLD_XENCAP_LEN + ob->klen; + + em->em_alg = XF_OLD_AH; + + xdo = (struct ah_old_xencap *)(em->em_dat); + + xdo->amx_hash_algorithm = xf[ob->koff].kernel_id; + xdo->amx_keylen = ob->klen; - em->em_msglen = EMT_SETSPI_FLEN + AH_OLD_XENCAP_LEN + klen; + bcopy(secrets, xdo->amx_key, ob->klen); + + } else { + bzero(buffer, EMT_SETSPI_FLEN + AH_NEW_XENCAP_LEN + ob->klen); + + em->em_msglen = EMT_SETSPI_FLEN + AH_NEW_XENCAP_LEN + ob->klen; + + em->em_alg = XF_NEW_AH; + + xdn = (struct ah_new_xencap *)(em->em_dat); + + xdn->amx_hash_algorithm = xf[ob->koff].kernel_id; + xdn->amx_wnd = 16; + xdn->amx_keylen = ob->klen; + + bcopy(secrets, xdn->amx_key, ob->klen); + } + em->em_version = PFENCAP_VERSION_1; em->em_type = EMT_SETSPI; - em->em_spi = htonl((spi[0]<<24) + (spi[1]<<16) + - (spi[2]<<8) + spi[3]); - em->em_src.s_addr = inet_addr(srcaddress); - em->em_dst.s_addr = inet_addr(dstaddress); - - if (tunnel) { - em->em_osrc.s_addr = inet_addr(srcaddress); - em->em_odst.s_addr = inet_addr(dstaddress); + em->em_spi = htonl((SPI->SPI[0]<<24) + (SPI->SPI[1]<<16) + + (SPI->SPI[2]<<8) + SPI->SPI[3]); + em->em_src.s_addr = inet_addr(SPI->local_address); + em->em_dst.s_addr = inet_addr(SPI->flags & SPI_OWNER ? + SPI->local_address : SPI->address); + + if (SPI->flags & SPI_TUNNEL) { + em->em_osrc.s_addr = inet_addr(SPI->local_address); + em->em_odst.s_addr = inet_addr(SPI->flags & SPI_OWNER ? + SPI->local_address : SPI->address); } - - em->em_alg = XF_OLD_AH; em->em_sproto = IPPROTO_AH; - xd = (struct ah_old_xencap *)(em->em_dat); + kernel_debug(("kernel_ah: %08x.\n", em->em_spi)); - xd->amx_hash_algorithm = ALG_AUTH_MD5; - xd->amx_keylen = klen; - - bcopy(secret, xd->amx_key, klen); - - if (!kernel_xf_set(em)) + if (!kernel_xf_set(em)) { + log_error(1, "kernel_xf_set() in kernel_ah()"); return -1; - - return MD5_KEYLEN/8; + } + return ob->klen; } int -kernel_des(char *srcaddress, char *dstaddress, u_int8_t *spi, u_int8_t *secret, - int tunnel) +kernel_esp(attrib_t *ob, attrib_t *ob2, struct spiob *SPI, u_int8_t *secrets) { struct encap_msghdr *em; - struct esp_old_xencap *xd; + struct esp_old_xencap *xdo; + struct esp_new_xencap *xdn; + attrib_t *attenc, *attauth = NULL; + u_int8_t *sec1, *sec2 = NULL; + + if (ob->type & AT_AUTH) { + if (ob2 == NULL || ob2->type != AT_ENC) { + log_error(0, "No encryption after auth given in kernel_esp()"); + return -1; + } + attenc = ob2; + attauth = ob; + sec2 = secrets; + sec1 = secrets + ob->klen; + } else if (ob->type == AT_ENC) { + attenc = ob; + sec1 = secrets; + if (ob2 != NULL && (ob2->type & AT_AUTH)) { + attauth = ob2; + sec2 = secrets + ob->klen; + } + } else { + log_error(0, "No encryption transform given in kernel_esp()"); + return -1; + } - bzero(buffer, EMT_SETSPI_FLEN + ESP_OLD_XENCAP_LEN + 4 + 8); + if ((xf[attenc->koff].flags & ESP_OLD) && attauth != NULL) { + log_error(0, "Old ESP does not support AH in kernel_esp()"); + return -1; + } em = (struct encap_msghdr *)buffer; - - em->em_msglen = EMT_SETSPI_FLEN + ESP_OLD_XENCAP_LEN + 4 + 8; + + if (xf[attenc->koff].flags & ESP_OLD) { + bzero(buffer, EMT_SETSPI_FLEN + ESP_OLD_XENCAP_LEN +4+attenc->klen); + + em->em_msglen = EMT_SETSPI_FLEN + ESP_OLD_XENCAP_LEN +4+attenc->klen; + + em->em_alg = XF_OLD_ESP; + + xdo = (struct esp_old_xencap *)(em->em_dat); + + xdo->edx_enc_algorithm = ALG_ENC_DES; + xdo->edx_ivlen = 4; + xdo->edx_keylen = attenc->klen; + + bcopy(SPI->SPI, xdo->edx_data, 4); + bcopy(sec1, xdo->edx_data+4, attenc->klen); + } else { + bzero(buffer, EMT_SETSPI_FLEN + ESP_NEW_XENCAP_LEN + attenc->klen + + (attauth ? attauth->klen : 0)); + + em->em_msglen = EMT_SETSPI_FLEN + ESP_NEW_XENCAP_LEN + + attenc->klen + (attauth ? attauth->klen : 0); + + em->em_alg = XF_NEW_ESP; + + xdn = (struct esp_new_xencap *)(em->em_dat); + + xdn->edx_enc_algorithm = xf[attenc->koff].kernel_id; + xdn->edx_hash_algorithm = attauth ? xf[attauth->koff].kernel_id : 0; + xdn->edx_ivlen = 0; + xdn->edx_confkeylen = attenc->klen; + xdn->edx_authkeylen = attauth ? attauth->klen : 0; + xdn->edx_wnd = 16; + xdn->edx_flags = attauth ? ESP_NEW_FLAG_AUTH : 0; + + bcopy(sec1, xdn->edx_data, attenc->klen); + if (attauth != NULL) + bcopy(sec2, xdn->edx_data + attenc->klen, attauth->klen); + } + /* Common settings shared by ESP_OLD and ESP_NEW */ + em->em_version = PFENCAP_VERSION_1; em->em_type = EMT_SETSPI; - em->em_spi = htonl((spi[0]<<24) + (spi[1]<<16) + - (spi[2]<<8) + spi[3]); - em->em_src.s_addr = inet_addr(srcaddress); - em->em_dst.s_addr = inet_addr(dstaddress); + em->em_spi = htonl((SPI->SPI[0]<<24) + (SPI->SPI[1]<<16) + + (SPI->SPI[2]<<8) + SPI->SPI[3]); + em->em_src.s_addr = inet_addr(SPI->local_address); + em->em_dst.s_addr = inet_addr(SPI->flags & SPI_OWNER ? + SPI->local_address : SPI->address); + em->em_sproto = IPPROTO_ESP; - if (tunnel) { - em->em_osrc.s_addr = inet_addr(srcaddress); - em->em_odst.s_addr = inet_addr(dstaddress); + if (SPI->flags & SPI_TUNNEL) { + em->em_osrc.s_addr = inet_addr(SPI->local_address); + em->em_odst.s_addr = inet_addr(SPI->flags & SPI_OWNER ? + SPI->local_address : SPI->address); } - em->em_alg = XF_OLD_ESP; - em->em_sproto = IPPROTO_ESP; - - xd = (struct esp_old_xencap *)(em->em_dat); - - xd->edx_enc_algorithm = ALG_ENC_DES; - xd->edx_ivlen = 4; - xd->edx_keylen = 8; - - bcopy(spi, xd->edx_data, 4); - bcopy(secret, xd->edx_data + 8, 8); + kernel_debug(("kernel_esp: %08x\n", em->em_spi)); - if (!kernel_xf_set(em)) + if (!kernel_xf_set(em)) { + log_error(1, "kernel_xf_set() in kernel_esp()"); return -1; + } - return 8; + return attenc->klen + (attauth ? attauth->klen : 0); } /* Group an ESP SPI with an AH SPI */ @@ -260,6 +416,9 @@ kernel_group_spi(char *address, u_int8_t *spi) u_int32_t SPI; SPI = (spi[0]<<24) + (spi[1]<<16) + (spi[2]<<8) + spi[3]; + + kernel_debug(("kernel_group_spi: %s, %08x\n", address, SPI)); + addr = inet_addr(address); bzero(buffer, EMT_GRPSPIS_FLEN); @@ -277,8 +436,10 @@ kernel_group_spi(char *address, u_int8_t *spi) em->em_rel_dst2.s_addr = addr; em->em_rel_sproto2 = IPPROTO_AH; - if (!kernel_xf_set(em)) + if (!kernel_xf_set(em)) { + log_error(1, "kernel_xf_set() in kernel_group_spi()"); return -1; + } return 1; } @@ -293,6 +454,8 @@ kernel_enable_spi(in_addr_t isrc, in_addr_t ismask, SPI = (spi[0]<<24) + (spi[1]<<16) + (spi[2]<<8) + spi[3]; + kernel_debug(("kernel_enable_spi: %08x\n", SPI)); + bzero(buffer, EMT_ENABLESPI_FLEN); em = (struct encap_msghdr *)buffer; @@ -311,8 +474,10 @@ kernel_enable_spi(in_addr_t isrc, in_addr_t ismask, em->em_ena_sproto = proto; em->em_ena_flags = flags; - if (!kernel_xf_set(em)) + if (!kernel_xf_set(em)) { + log_error(1, "kernel_xf_set() in kernel_enable_spi()"); return -1; + } return 1; } @@ -327,6 +492,8 @@ kernel_disable_spi(in_addr_t isrc, in_addr_t ismask, SPI = (spi[0]<<24) + (spi[1]<<16) + (spi[2]<<8) + spi[3]; + kernel_debug(("kernel_disable_spi: %08x\n", SPI)); + bzero(buffer, EMT_DISABLESPI_FLEN); em = (struct encap_msghdr *)buffer; @@ -345,8 +512,10 @@ kernel_disable_spi(in_addr_t isrc, in_addr_t ismask, em->em_ena_sproto = proto; em->em_ena_flags = flags; - if (!kernel_xf_set(em)) +/* if (!kernel_xf_set(em) && errno != ENOENT) { + log_error(1, "kernel_xf_set() in kernel_disable_spi()"); return -1; + }*/ return 1; } @@ -368,8 +537,12 @@ kernel_delete_spi(char *address, u_int8_t *spi, int proto) em->em_gen_dst.s_addr = inet_addr(address); em->em_gen_sproto = proto; - if (!kernel_xf_set(em)) + kernel_debug(("kernel_delete_spi: %08x\n", em->em_gen_spi)); + + if (!kernel_xf_set(em)) { + log_error(1, "kernel_xf_set() in kernel_delete_spi()"); return -1; + } return 1; } @@ -381,7 +554,9 @@ kernel_insert_spi(struct spiob *SPI) u_int8_t *attributes; u_int16_t attribsize; u_int8_t *secrets; + attrib_t *attprop, *attprop2; int i, n, offset, proto = 0; + int phase = 0; spi = SPI->SPI; attributes = SPI->attributes; @@ -391,35 +566,51 @@ kernel_insert_spi(struct spiob *SPI) for(n=0, i=0; n<attribsize; n += attributes[n+1] + 2) { switch(attributes[n]) { case AT_AH_ATTRIB: + phase = AT_AH_ATTRIB; + break; case AT_ESP_ATTRIB: + phase = AT_ESP_ATTRIB; break; - case AT_MD5_KDP: - offset = kernel_md5(SPI->local_address, SPI->flags & SPI_OWNER ? - SPI->local_address : SPI->address, - spi, secrets, SPI->flags & SPI_TUNNEL); - if (offset == -1) + default: + if (phase == 0) { + log_error(0, "Unaligned attribute %d in kernel_insert_spi()", attributes[n]); return -1; - secrets += offset; - i++; - if (!proto) - proto = IPPROTO_AH; - break; - case AT_DES_CBC: - offset = kernel_des(SPI->local_address, SPI->flags & SPI_OWNER ? - SPI->local_address : SPI->address, - spi, secrets, SPI->flags & SPI_TUNNEL); - if (offset == -1) + } + if ((attprop = getattrib(attributes[n])) == NULL) { + log_error(0, "Unknown attribute %d in kernel_insert_spi()", + attributes[n]); return -1; - secrets += offset; - i++; - if (!proto) - proto = IPPROTO_ESP; - break; - default: - log_error(0, "Unknown attribute %d in kernel_insert_spi()", - attributes[n]); - return -1; + } + switch (phase) { + case AT_AH_ATTRIB: + offset = kernel_ah(attprop, SPI, secrets); + if (offset == -1) + return -1; + phase = 0; + secrets += offset; + i++; + if (!proto) + proto = IPPROTO_AH; + break; + case AT_ESP_ATTRIB: + offset = attributes[n+1] + 2; + attprop2 = NULL; + if (n+offset < attribsize) + attprop2 = getattrib(attributes[n+offset]); + if (attprop2 != NULL) + n += offset; + offset = kernel_esp(attprop, attprop2, SPI, secrets); + if (offset == -1) + return -1; + phase = 0; + secrets += offset; + i++; + if (!proto) + proto = IPPROTO_ESP; + break; + } } + } /* Group the SPIs for User */ @@ -448,6 +639,8 @@ int kernel_unlink_spi(struct spiob *ospi) { int n, proto = 0; + int phase = 0, offset; + attrib_t *attprop; u_int32_t spi; u_int8_t SPI[SPI_SIZE], *p; @@ -467,39 +660,54 @@ kernel_unlink_spi(struct spiob *ospi) SPI[3] = spi & 0xFF; switch(ospi->attributes[n]) { case AT_AH_ATTRIB: + phase = AT_AH_ATTRIB; + break; case AT_ESP_ATTRIB: + phase = AT_ESP_ATTRIB; break; - case AT_MD5_KDP: - if (!proto) { - proto = IPPROTO_AH; - if (!(ospi->flags & SPI_OWNER) && - kernel_disable_spi(ospi->isrc, ospi->ismask, - ospi->idst, ospi->idmask, - ospi->address, ospi->SPI, proto, - ENABLE_FLAG_LOCAL) == -1) - log_error(0, "kernel_disable_spi() in kernel_unlink_spi()"); + default: + if (phase == 0) { + log_error(0, "Unaligned attribute %d in kernel_unlink_spi()", ospi->attributes[n]); + return -1; + } + if ((attprop = getattrib(ospi->attributes[n])) == NULL) { + log_error(0, "Unknown attribute %d in kernel_unlink_spi()", + ospi->attributes[n]); + return -1; + } + switch (phase) { + case AT_AH_ATTRIB: + if (!proto) { + proto = IPPROTO_AH; + if (!(ospi->flags & SPI_OWNER) && + kernel_disable_spi(ospi->isrc, ospi->ismask, + ospi->idst, ospi->idmask, + ospi->address, ospi->SPI, proto, + ENABLE_FLAG_LOCAL) == -1) + log_error(0, "kernel_disable_spi() in kernel_unlink_spi()"); } if (kernel_delete_spi(p, SPI, IPPROTO_AH) == -1) log_error(0, "kernel_delete_spi() in kernel_unlink_spi()"); break; - case AT_DES_CBC: - if (!proto) { - proto = IPPROTO_ESP; - if (!(ospi->flags & SPI_OWNER) && - kernel_disable_spi(ospi->isrc, ospi->ismask, - ospi->idst, ospi->idmask, - ospi->address, ospi->SPI, proto, - ENABLE_FLAG_LOCAL) == -1) - log_error(0, "kernel_disable_spi() in kernel_unlink_spi()"); + case AT_ESP_ATTRIB: + if (!proto) { + proto = IPPROTO_ESP; + if (!(ospi->flags & SPI_OWNER) && + kernel_disable_spi(ospi->isrc, ospi->ismask, + ospi->idst, ospi->idmask, + ospi->address, ospi->SPI, proto, + ENABLE_FLAG_LOCAL) == -1) + log_error(0, "kernel_disable_spi() in kernel_unlink_spi()"); + } + if (kernel_delete_spi(p, SPI, IPPROTO_ESP) == -1) + log_error(0, "kernel_delete_spi() in kernel_unlink_spi()"); + offset = ospi->attributes[n+1] + 2; + if ((n + offset < ospi->attribsize) && + getattrib(ospi->attributes[n+offset]) != NULL) + n += offset; + break; } - if (kernel_delete_spi(p, SPI, IPPROTO_ESP) == -1) - log_error(0, "kernel_delete_spi() in kernel_unlink_spi()"); - break; - default: - log_error(0, "Unknown attribute %d in kernel_unlink_spi()", - ospi->attributes[n]); - return -1; } } |