diff --git a/.gitignore b/.gitignore index d372f53..c47bf85 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ +SOURCES/ikev1_dsa.fax.bz2 +SOURCES/ikev1_psk.fax.bz2 +SOURCES/ikev2.fax.bz2 SOURCES/libreswan-3.12.tar.gz diff --git a/.libreswan.metadata b/.libreswan.metadata index effea6f..3e211e5 100644 --- a/.libreswan.metadata +++ b/.libreswan.metadata @@ -1 +1,4 @@ +b35cd50b8bc0a08b9c07713bf19c72d53bfe66bb SOURCES/ikev1_dsa.fax.bz2 +861d97bf488f9e296cad8c43ab72f111a5b1a848 SOURCES/ikev1_psk.fax.bz2 +fcaf77f3deae3d8e99cdb3b1f8abea63167a0633 SOURCES/ikev2.fax.bz2 bca50e25b044df1b9fc4b732be38b28c25216674 SOURCES/libreswan-3.12.tar.gz diff --git a/SOURCES/libreswan-3.12-1170018-netlink-label.patch b/SOURCES/libreswan-3.12-1170018-netlink-label.patch new file mode 100644 index 0000000..2b11cae --- /dev/null +++ b/SOURCES/libreswan-3.12-1170018-netlink-label.patch @@ -0,0 +1,124 @@ +diff -Naur libreswan-3.12-orig/programs/pluto/kernel_netlink.c libreswan-3.12/programs/pluto/kernel_netlink.c +--- libreswan-3.12-orig/programs/pluto/kernel_netlink.c 2015-02-26 22:02:15.641000000 -0600 ++++ libreswan-3.12/programs/pluto/kernel_netlink.c 2015-02-26 22:04:29.990000000 -0600 +@@ -426,7 +426,7 @@ + struct { + struct nlmsghdr n; + struct nlmsgerr e; +- char data[1024]; ++ char data[MAX_NETLINK_DATA_SIZE]; + } rsp; + size_t len; + ssize_t r; +@@ -547,7 +547,7 @@ + struct { + struct nlmsghdr n; + struct nlmsgerr e; +- char data[1024]; ++ char data[MAX_NETLINK_DATA_SIZE]; + } rsp; + int error; + +@@ -610,7 +610,7 @@ + struct xfrm_userpolicy_info p; + struct xfrm_userpolicy_id id; + } u; +- char data[1024]; ++ char data[MAX_NETLINK_DATA_SIZE]; + } req; + int shift; + int dir; +@@ -907,7 +907,7 @@ + struct { + struct nlmsghdr n; + struct xfrm_usersa_info p; +- char data[1024]; ++ char data[MAX_NETLINK_DATA_SIZE]; + } req; + struct rtattr *attr; + const struct aead_alg *aead; +@@ -1233,7 +1233,7 @@ + struct { + struct nlmsghdr n; + struct xfrm_usersa_id id; +- char data[1024]; ++ char data[MAX_NETLINK_DATA_SIZE]; + } req; + + zero(&req); +@@ -1513,7 +1513,7 @@ + struct { + struct nlmsghdr n; + struct xfrm_userpolicy_info pol; +- char data[1024]; ++ char data[MAX_NETLINK_DATA_SIZE]; + } rsp; + + if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*upe))) { +@@ -1569,7 +1569,7 @@ + { + struct { + struct nlmsghdr n; +- char data[1024]; ++ char data[MAX_NETLINK_DATA_SIZE]; + } rsp; + ssize_t r; + struct sockaddr_nl addr; +@@ -1650,7 +1650,7 @@ + struct nlmsgerr e; + struct xfrm_usersa_info sa; + } u; +- char data[1024]; ++ char data[MAX_NETLINK_DATA_SIZE]; + } rsp; + static bool get_cpi_bug = FALSE; /* sticky after failure */ + +@@ -2235,7 +2235,7 @@ + struct { + struct nlmsghdr n; + struct xfrm_usersa_info info; +- char data[1024]; ++ char data[MAX_NETLINK_DATA_SIZE]; + } rsp; + + zero(&req); +diff -Naur libreswan-3.12-orig/programs/pluto/kernel_netlink.h libreswan-3.12/programs/pluto/kernel_netlink.h +--- libreswan-3.12-orig/programs/pluto/kernel_netlink.h 2014-11-06 21:52:50.000000000 -0600 ++++ libreswan-3.12/programs/pluto/kernel_netlink.h 2015-02-26 22:02:44.521000000 -0600 +@@ -15,4 +15,13 @@ + + #if defined(linux) && defined(NETKEY_SUPPORT) + extern const struct kernel_ops netkey_kernel_ops; ++/* ++ * The socket buffer is used to queue netlink messages between sender and ++ * receiver. The size of these buffers specifies the maximum size you will be ++ * able to write() to a netlink socket, i.e. it will indirectly define the ++ * maximum message size. The default is 32KiB. For now we picked a somewhat ++ * arbitrary maximum of 8192 for the data portion to accomdate large selinux ++ * IPsec labels (see rhbz#1154784) ++ */ ++#define MAX_NETLINK_DATA_SIZE 8192 + #endif +diff -Naur libreswan-3.12-orig/programs/pluto/state.h libreswan-3.12/programs/pluto/state.h +--- libreswan-3.12-orig/programs/pluto/state.h 2015-02-26 22:02:15.658000000 -0600 ++++ libreswan-3.12/programs/pluto/state.h 2015-02-26 22:02:44.521000000 -0600 +@@ -195,10 +195,16 @@ + }; + + #ifdef HAVE_LABELED_IPSEC +-/* security label length should not exceed 256 in most cases, +- * (discussed with kernel and selinux people). ++/* ++ * While security label length usually does not exceed 256, ++ * there have been requests (rhbz#1154784) for using larger ++ * labels. The maximum label size is PAGE_SIZE (4096 on a ++ * x86_64, but 64kb on ppc64). However, this label has to fit ++ * inside a netlink message whose maximum size is 32KiB. ++ * For now we picked the somewhat arbitrary size of 4096. + */ +-#define MAX_SECCTX_LEN 257 /* including '\0'*/ ++#define MAX_SECCTX_LEN 4096 /* including '\0'*/ ++ + struct xfrm_user_sec_ctx_ike { + u_int16_t len; + u_int16_t exttype; diff --git a/SOURCES/libreswan-3.12-1182224-bsi-random.patch b/SOURCES/libreswan-3.12-1182224-bsi-random.patch new file mode 100644 index 0000000..7810a7b --- /dev/null +++ b/SOURCES/libreswan-3.12-1182224-bsi-random.patch @@ -0,0 +1,571 @@ +diff -Naur libreswan-3.12-orig/include/ipsecconf/keywords.h libreswan-3.12/include/ipsecconf/keywords.h +--- libreswan-3.12-orig/include/ipsecconf/keywords.h 2015-02-26 21:24:52.037000000 -0600 ++++ libreswan-3.12/include/ipsecconf/keywords.h 2015-02-26 21:25:39.297000000 -0600 +@@ -83,6 +83,7 @@ + KBF_STRICTCRLPOLICY, + KBF_SEND_CA, + KBF_NATIKEPORT, ++ KBF_SEEDBITS, + KBF_KEEPALIVE, + KBF_PLUTORESTARTONCRASH, + KBF_CRLCHECKINTERVAL, +diff -Naur libreswan-3.12-orig/lib/libipsecconf/confread.c libreswan-3.12/lib/libipsecconf/confread.c +--- libreswan-3.12-orig/lib/libipsecconf/confread.c 2015-02-26 21:24:52.038000000 -0600 ++++ libreswan-3.12/lib/libipsecconf/confread.c 2015-02-26 21:25:39.297000000 -0600 +@@ -98,6 +98,10 @@ + + cfg->setup.options[KBF_KEEPALIVE] = 0; /* config setup */ + cfg->setup.options[KBF_NATIKEPORT] = NAT_IKE_UDP_PORT; ++ ++ /* Don't inflict BSI requirements on everyone */ ++ cfg->setup.options[KBF_SEEDBITS] = 0; ++ + #ifdef HAVE_LABELED_IPSEC + cfg->setup.options[KBF_SECCTX] = SECCTX; + #endif +diff -Naur libreswan-3.12-orig/lib/libipsecconf/keywords.c libreswan-3.12/lib/libipsecconf/keywords.c +--- libreswan-3.12-orig/lib/libipsecconf/keywords.c 2015-02-26 21:24:52.038000000 -0600 ++++ libreswan-3.12/lib/libipsecconf/keywords.c 2015-02-26 21:25:39.298000000 -0600 +@@ -369,6 +369,7 @@ + { "virtual-private", kv_config, kt_string, KSF_VIRTUALPRIVATE, NOT_ENUM }, + { "nat_ikeport", kv_config | kv_alias, kt_number, KBF_NATIKEPORT, NOT_ENUM }, /* obsolete _ */ + { "nat-ikeport", kv_config, kt_number, KBF_NATIKEPORT, NOT_ENUM }, ++ { "seedbits", kv_config, kt_number, KBF_SEEDBITS, NOT_ENUM }, + { "keep_alive", kv_config | kv_alias, kt_number, KBF_KEEPALIVE, NOT_ENUM }, /* obsolete _ */ + { "keep-alive", kv_config, kt_number, KBF_KEEPALIVE, NOT_ENUM }, + { "nat_traversal", kv_config, kt_obsolete_quiet, KBF_WARNIGNORE, NOT_ENUM }, +diff -Naur libreswan-3.12-orig/programs/configs/d.ipsec.conf/order.txt libreswan-3.12/programs/configs/d.ipsec.conf/order.txt +--- libreswan-3.12-orig/programs/configs/d.ipsec.conf/order.txt 2015-02-26 21:24:52.040000000 -0600 ++++ libreswan-3.12/programs/configs/d.ipsec.conf/order.txt 2015-02-26 21:25:39.298000000 -0600 +@@ -89,6 +89,7 @@ + d.ipsec.conf/myvendorid.xml + d.ipsec.conf/oe.xml + d.ipsec.conf/nhelpers.xml ++d.ipsec.conf/seedbits.xml + d.ipsec.conf/secctx-attr-value.xml + d.ipsec.conf/plutofork.xml + d.ipsec.conf/crlcheckinterval.xml +diff -Naur libreswan-3.12-orig/programs/configs/d.ipsec.conf/seedbits.xml libreswan-3.12/programs/configs/d.ipsec.conf/seedbits.xml +--- libreswan-3.12-orig/programs/configs/d.ipsec.conf/seedbits.xml 1969-12-31 18:00:00.000000000 -0600 ++++ libreswan-3.12/programs/configs/d.ipsec.conf/seedbits.xml 2015-02-26 21:25:39.299000000 -0600 +@@ -0,0 +1,15 @@ ++ ++ seedbits ++ ++ ++Pluto uses the NSS crypto library as its random source. Some government ++Three Letter Agencies require that pluto reads additional bits from /dev/random ++and feed these into the NSS RNG before drawing random from the NSS library, ++despite the NSS library itself already seeding its internal state. This ++process can block pluto for an extended time during startup, depending on ++the entropy of the system. Therefor, the default is to not perform this ++redundant seeding. If specifying a value, it is recommended to specify at ++least 460 bits (for FIPS) or 440 bits (for BSI). ++ ++ ++ +diff -Naur libreswan-3.12-orig/programs/pluto/pluto.8 libreswan-3.12/programs/pluto/pluto.8 +--- libreswan-3.12-orig/programs/pluto/pluto.8 2014-11-06 21:52:50.000000000 -0600 ++++ libreswan-3.12/programs/pluto/pluto.8 2015-02-26 21:25:39.299000000 -0600 +@@ -2,12 +2,12 @@ + .\" Title: IPSEC_PLUTO + .\" Author: Paul Wouters + .\" Generator: DocBook XSL Stylesheets v1.78.1 +-.\" Date: 10/22/2014 ++.\" Date: 01/14/2015 + .\" Manual: Executable programs + .\" Source: libreswan + .\" Language: English + .\" +-.TH "IPSEC_PLUTO" "8" "10/22/2014" "libreswan" "Executable programs" ++.TH "IPSEC_PLUTO" "8" "01/14/2015" "libreswan" "Executable programs" + .\" ----------------------------------------------------------------- + .\" * Define some portability stuff + .\" ----------------------------------------------------------------- +@@ -31,7 +31,7 @@ + pluto \- ipsec whack : IPsec IKE keying daemon and control interface + .SH "SYNOPSIS" + .HP \w'\fBipsec\fR\ 'u +-\fBipsec\fR \fIpluto\fR [\-\-help] [\-\-version] [\-\-leak\-detective] [\-\-config\ \fIfilename\fR] [\-\-vendorid\ \fIVID\fR] [\-\-nofork] [\-\-stderrlog] [\-\-\-\-plutostderrlogtime] [\-\-logfile\ \fIfilename\fR] [\-\-use\-klips] [\-\-use\-mast] [\-\-use\-netkey] [\-\-use\-nostack] [\-\-uniqueids] [\-\-virtual\-private\ \fInetwork_list\fR] [\-\-keep\-alive\ \fIdelay_sec\fR] [\-\-force\-busy] [\-\-nocrsend] [\-\-strictcrlpolicy] [\-\-crlcheckinterval] [\-\-interface\ \fIinterfacename\fR] [\-\-listen\ \fIipaddr\fR] [\-\-ikeport\ \fIportnumber\fR] [\-\-natikeport\ \fIportnumber\fR] [\-\-ctlbase\ \fIpath\fR] [\-\-secretsfile\ \fIsecrets\-file\fR] [\-\-adns\ \fIpathname\fR] [\-\-nhelpers\ \fInumber\fR] [\-\-perpeerlog] [\-\-perpeerlogbase\ \fIdirname\fR] [\-\-ipsecdir\ \fIdirname\fR] [\-\-coredir\ \fIdirname\fR] [\-\-statsbin\ \fIfilename\fR] [\-\-secctx\-attr\-value\ \fInumber\fR] ++\fBipsec\fR \fIpluto\fR [\-\-help] [\-\-version] [\-\-leak\-detective] [\-\-config\ \fIfilename\fR] [\-\-vendorid\ \fIVID\fR] [\-\-nofork] [\-\-stderrlog] [\-\-\-\-plutostderrlogtime] [\-\-logfile\ \fIfilename\fR] [\-\-use\-klips] [\-\-use\-mast] [\-\-use\-netkey] [\-\-use\-nostack] [\-\-uniqueids] [\-\-virtual\-private\ \fInetwork_list\fR] [\-\-keep\-alive\ \fIdelay_sec\fR] [\-\-force\-busy] [\-\-nocrsend] [\-\-strictcrlpolicy] [\-\-crlcheckinterval] [\-\-interface\ \fIinterfacename\fR] [\-\-listen\ \fIipaddr\fR] [\-\-ikeport\ \fIportnumber\fR] [\-\-natikeport\ \fIportnumber\fR] [\-\-ctlbase\ \fIpath\fR] [\-\-secretsfile\ \fIsecrets\-file\fR] [\-\-adns\ \fIpathname\fR] [\-\-nhelpers\ \fInumber\fR] [\-\-seedbits\ \fInumbits\fR] [\-\-perpeerlog] [\-\-perpeerlogbase\ \fIdirname\fR] [\-\-ipsecdir\ \fIdirname\fR] [\-\-coredir\ \fIdirname\fR] [\-\-statsbin\ \fIfilename\fR] [\-\-secctx\-attr\-value\ \fInumber\fR] + .HP \w'\fBipsec\fR\ 'u + \fBipsec\fR \fIwhack\fR [\-\-help] [\-\-version] + .HP \w'\fBipsec\fR\ 'u +@@ -317,6 +317,10 @@ + \fI\-1\fR + tells pluto to perform the above calculation\&. Any other value forces the number to that amount\&. + .PP ++Pluto uses the NSS crypto library as its random source\&. Some government Three Letter Agency requires that pluto reads 440 bits from /dev/random and feed this into the NSS RNG before drawing random from the NSS library, despite the NSS library itself already seeding its internal state\&. As this process can block pluto for an extended time, the default is to not perform this redundant seeding\&. The ++\fB\-\-seedbits\fR ++option can be used to specify the number of bits that will be pulled from /dev/random and seeded into the NSS RNG\&. This can also be accomplished by specifying seedbits in the "config setup" section of ipsec\&.conf\&. This option should not be used by most people\&. ++.PP + \fBpluto\fR + attempts to create a lockfile with the name + /var/run/pluto/pluto\&.pid\&. If the lockfile cannot be created, +diff -Naur libreswan-3.12-orig/programs/pluto/pluto.8.xml libreswan-3.12/programs/pluto/pluto.8.xml +--- libreswan-3.12-orig/programs/pluto/pluto.8.xml 2014-11-06 21:52:50.000000000 -0600 ++++ libreswan-3.12/programs/pluto/pluto.8.xml 2015-02-26 21:25:39.300000000 -0600 +@@ -57,6 +57,7 @@ + --secretsfile secrets-file + --adns pathname + --nhelpers number ++ --seedbits numbits + --perpeerlog + --perpeerlogbase dirname + --ipsecdir dirname +@@ -984,6 +985,18 @@ + -1 tells pluto to perform the above + calculation. Any other value forces the number to that amount. + ++ Pluto uses the NSS crypto library as its random source. Some ++ government Three Letter Agency requires that pluto reads 440 bits ++ from /dev/random and feed this into the NSS RNG before drawing ++ random from the NSS library, despite the NSS library itself ++ already seeding its internal state. As this process can block ++ pluto for an extended time, the default is to not perform this ++ redundant seeding. The --seedbits ++ option can be used to specify the number of bits that will be ++ pulled from /dev/random and seeded into the NSS RNG. This can ++ also be accomplished by specifying seedbits in the "config setup" ++ section of ipsec.conf. This option should not be used by most people. ++ + pluto attempts to create a lockfile + with the name /var/run/pluto/pluto.pid. If the + lockfile cannot be created, pluto exits - +diff -Naur libreswan-3.12-orig/programs/pluto/plutomain.c libreswan-3.12/programs/pluto/plutomain.c +--- libreswan-3.12-orig/programs/pluto/plutomain.c 2015-02-26 21:24:52.012000000 -0600 ++++ libreswan-3.12/programs/pluto/plutomain.c 2015-02-26 21:25:39.301000000 -0600 +@@ -111,6 +111,7 @@ + /* pulled from main for show_setup_plutomain() */ + static const struct lsw_conf_options *oco; + static char *coredir; ++static int pluto_nss_seedbits; + static int nhelpers = -1; + + libreswan_passert_fail_t libreswan_passert_fail = passert_fail; +@@ -314,6 +315,49 @@ + *target = strdup(value); + } + ++/* ++ * This function MUST NOT be used for anything else! ++ * It is used to seed the NSS PRNG based on --seedbits pluto argument ++ * or the seedbits= * config setup option in ipsec.conf. ++ * Everything else that needs random MUST use get_rnd_bytes() ++ * This function MUST NOT be changed to use /dev/urandom. ++ */ ++static void get_bsi_random(size_t nbytes, unsigned char *buf) ++{ ++ size_t ndone; ++ int dev; ++ ssize_t got; ++ const char *device = "/dev/random"; ++ ++ dev = open(device, 0); ++ if (dev < 0) { ++ loglog(RC_LOG_SERIOUS, "could not open %s (%s)\n", ++ device, strerror(errno)); ++ exit_pluto(6); ++ } ++ ++ ndone = 0; ++ DBG(DBG_CONTROL,DBG_log("need %d bits random for extra seeding of the NSS PRNG", ++ (int) nbytes * BITS_PER_BYTE)); ++ ++ while (ndone < nbytes) { ++ got = read(dev, buf + ndone, nbytes - ndone); ++ if (got < 0) { ++ loglog(RC_LOG_SERIOUS,"read error on %s (%s)\n", ++ device, strerror(errno)); ++ exit_pluto(6); ++ } ++ if (got == 0) { ++ loglog(RC_LOG_SERIOUS,"EOF on %s!?!\n", device); ++ exit_pluto(6); ++ } ++ ndone += got; ++ } ++ close(dev); ++ DBG(DBG_CONTROL,DBG_log("read %ld bytes from /dev/random for NSS PRNG", ++ nbytes)); ++} ++ + static void pluto_init_nss(char *confddir) + { + SECStatus nss_init_status; +@@ -328,6 +372,23 @@ + libreswan_log("NSS Initialized"); + PK11_SetPasswordFunc(getNSSPassword); + } ++ ++ /* ++ * This exists purely to make the BSI happy. ++ * We do not infliect this on other users ++ */ ++ if (pluto_nss_seedbits != 0) { ++ SECStatus rv; ++ int seedbytes = BYTES_FOR_BITS(pluto_nss_seedbits); ++ unsigned char *buf = alloc_bytes(seedbytes,"TLA seedmix"); ++ ++ get_bsi_random(seedbytes, buf); /* much TLA, very blocking */ ++ rv = PK11_RandomUpdate(buf, seedbytes); ++ libreswan_log("seeded %d bytes into the NSS PRNG", seedbytes); ++ passert(rv == SECSuccess); ++ zero(&buf); ++ pfree(buf); ++ } + } + + /* by default the CRL policy is lenient */ +@@ -417,6 +478,7 @@ + { "virtual_private\0_", required_argument, NULL, '6' }, /* _ */ + { "virtual-private\0", required_argument, NULL, '6' }, + { "nhelpers\0", required_argument, NULL, 'j' }, ++ { "seedbits\0", required_argument, NULL, 'c' }, + #ifdef HAVE_LABELED_IPSEC + { "secctx_attr_value\0_", required_argument, NULL, 'w' }, /* _ */ + { "secctx-attr-value\0", required_argument, NULL, 'w' }, +@@ -692,6 +754,14 @@ + nhelpers = u; + } + continue; ++ case 'c': /* --seedbits */ ++ pluto_nss_seedbits = atoi(optarg); ++ if (pluto_nss_seedbits == 0) { ++ printf("pluto: seedbits must be an integer > 0"); ++ /* not exit_pluto because we are not initialized yet */ ++ exit(6); ++ } ++ continue; + + #ifdef HAVE_LABELED_IPSEC + case 'w': /* --secctx-attr-value */ +@@ -969,6 +1039,7 @@ + } + } + ++ pluto_nss_seedbits = cfg->setup.options[KBF_SEEDBITS]; + pluto_nat_port = + cfg->setup.options[KBF_NATIKEPORT]; + keep_alive = cfg->setup.options[KBF_KEEPALIVE]; +@@ -1473,3 +1544,4 @@ + whack_log(RC_COMMENT, "secctx-attr-value="); + #endif + } ++ +diff -Naur libreswan-3.12-orig/programs/rsasigkey/Makefile libreswan-3.12/programs/rsasigkey/Makefile +--- libreswan-3.12-orig/programs/rsasigkey/Makefile 2014-11-06 21:52:50.000000000 -0600 ++++ libreswan-3.12/programs/rsasigkey/Makefile 2015-02-26 21:25:39.301000000 -0600 +@@ -16,7 +16,7 @@ + include ${LIBRESWANSRCDIR}/Makefile.inc + + PROGRAM=rsasigkey +-LIBS=${LIBRESWANLIB} -lgmp ++LIBS=${LSWLOGLIB} ${LIBRESWANLIB} -lgmp + LIBS+=${NSSLIBS} + + ifeq ($(USE_FIPSCHECK),true) +diff -Naur libreswan-3.12-orig/programs/rsasigkey/rsasigkey.8 libreswan-3.12/programs/rsasigkey/rsasigkey.8 +--- libreswan-3.12-orig/programs/rsasigkey/rsasigkey.8 2014-11-06 21:52:50.000000000 -0600 ++++ libreswan-3.12/programs/rsasigkey/rsasigkey.8 2015-02-26 21:25:39.302000000 -0600 +@@ -2,12 +2,12 @@ + .\" Title: IPSEC_RSASIGKEY + .\" Author: Paul Wouters + .\" Generator: DocBook XSL Stylesheets v1.78.1 +-.\" Date: 09/06/2013 ++.\" Date: 01/14/2015 + .\" Manual: Executable programs + .\" Source: libreswan + .\" Language: English + .\" +-.TH "IPSEC_RSASIGKEY" "8" "09/06/2013" "libreswan" "Executable programs" ++.TH "IPSEC_RSASIGKEY" "8" "01/14/2015" "libreswan" "Executable programs" + .\" ----------------------------------------------------------------- + .\" * Define some portability stuff + .\" ----------------------------------------------------------------- +@@ -31,9 +31,7 @@ + ipsec_rsasigkey \- generate RSA signature key + .SH "SYNOPSIS" + .HP \w'\fBipsec\fR\ 'u +-\fBipsec\fR \fIrsasigkey\fR [\-\-verbose] [\-\-random\ \fIfilename\fR] [\-\-configdir\ \fInssdbdir\fR] [\-\-password\ \fInsspassword\fR] [\-\-hostname\ \fIhostname\fR] [nbits] +-.HP \w'\fBipsec\fR\ 'u +-\fBipsec\fR \fIrsasigkey\fR [\-\-verbose] [\-\-configdir\ \fInssdbdir\fR] [\-\-password\ \fInsspassword\fR] [\-\-hostname\ \fIhostname\fR] ++\fBipsec\fR \fIrsasigkey\fR [\-\-verbose] [\-\-random\ \fIdevice\fR] [\-\-seed\ \fInumbits\fR] [\-\-configdir\ \fInssdbdir\fR] [\-\-password\ \fInsspassword\fR] [\-\-hostname\ \fIhostname\fR] [nbits] + .SH "DESCRIPTION" + .PP + \fIRsasigkey\fR +@@ -50,7 +48,8 @@ + .PP + The + \fB\-\-verbose\fR +-option makes\fIrsasigkey\fR ++option makes ++\fIrsasigkey\fR + give a running commentary on standard error\&. By default, it works in silence until it is ready to generate output\&. + .PP + The +@@ -58,9 +57,15 @@ + option specifies a source for random bits used to seed the crypto library\*(Aqs RNG\&. The default is + /dev/random + (see +-\fBrandom\fR(4))\&. FreeS/WAN and Openswan without NSS support used this option to specify the random source used to directly create keys\&. Libreswan only uses it to seed the crypto libraries RNG\&. Under Linux with hardware random support, special devices might show up as ++\fBrandom\fR(4))\&. FreeS/WAN and Openswan without NSS support use this option to specify the random source used to directly create keys\&. Libreswan only uses it to seed the NSS crypto libraries RNG\&. Under Linux with hardware random support, special devices might show up as + /dev/*rng* +-devices\&. However, these should never be access directly using this option, as hardware failures could lead to extremely non\-random values (streams of zeroes have been observed in the wild) ++devices\&. However, these should never be accessed directly using this option, as hardware failures could lead to extremely non\-random values (streams of zeroes have been observed in the wild) ++.PP ++The ++\fB\-\-seedbits\fR ++option specifies how many seed bits are pulled from the random device to seed the NSS PRNG\&. The default of 480bit comes from FIPS requirements\&. Seed bits are rounded up to a multiple of 8\&. ++.PP ++The use of a different random device or a reduction of seedbits from the default value is prevented when the system is running in FIPS mode\&. + .PP + The + \fB\-\-configdir\fR +@@ -69,7 +74,8 @@ + .PP + The + \fB\-\-password\fR +-option specifies the nss cryptographic module authentication password if the NSS module has been configured to require it\&. A password is required by hardware tokens and also by the internal softotken module when configured to run in FIPS mode\&. ++option specifies the nss cryptographic module authentication password if the NSS module has been configured to require it\&. A password is required by hardware tokens and also by the internal software token module when configured to run in FIPS mode\&. If the argument is ++\fIconfigdir\fR/nsspassword, the password comes from that file; otherwise argument is the password\&. + .PP + The + \fB\-\-hostname\fR +@@ -140,7 +146,7 @@ + \fBCoefficient\fR + line gives the Chinese Remainder Theorem coefficient, which is the inverse of + \fIq\fR, mod +-\fIp\fR\&. These additional numbers (which must all be kept as secret as the private exponent) are precomputed aids to rapid signature generation\&. When NSS is used, these values are not available outside the NSS security database (softtoken or hardware token) and are instead filled in with the CKA_ID\&. ++\fIp\fR\&. These additional numbers (which must all be kept as secret as the private exponent) are precomputed aids to rapid signature generation\&. When NSS is used, these values are not available outside the NSS security database (software token or hardware token) and are instead filled in with the CKA_ID\&. + .PP + No attempt is made to break long lines\&. + .PP +diff -Naur libreswan-3.12-orig/programs/rsasigkey/rsasigkey.8.xml libreswan-3.12/programs/rsasigkey/rsasigkey.8.xml +--- libreswan-3.12-orig/programs/rsasigkey/rsasigkey.8.xml 2014-11-06 21:52:50.000000000 -0600 ++++ libreswan-3.12/programs/rsasigkey/rsasigkey.8.xml 2015-02-26 21:25:39.302000000 -0600 +@@ -23,20 +23,13 @@ + ipsec + rsasigkey + --verbose +- --random filename ++ --random device ++ --seed numbits + --configdir nssdbdir + --password nsspassword + --hostname hostname + nbits + +- +- ipsec +- rsasigkey +- --verbose +- --configdir nssdbdir +- --password nsspassword +- --hostname hostname +- + + + +@@ -61,14 +54,22 @@ + source for random bits used to seed the crypto library's + RNG. The default is /dev/random (see + random4). +-FreeS/WAN and Openswan without NSS support used this option to specify ++FreeS/WAN and Openswan without NSS support use this option to specify + the random source used to directly create keys. Libreswan only uses +-it to seed the crypto libraries RNG. Under Linux with hardware random ++it to seed the NSS crypto libraries RNG. Under Linux with hardware random + support, special devices might show up as /dev/*rng* +-devices. However, these should never be access directly using this option, ++devices. However, these should never be accessed directly using this option, + as hardware failures could lead to extremely non-random values (streams + of zeroes have been observed in the wild) + ++The option specifies how many seed bits are pulled from ++the random device to seed the NSS PRNG. The default of 480bit comes from FIPS requirements. ++Seed bits are rounded up to a multiple of 8. ++ ++ ++The use of a different random device or a reduction of seedbits from the default value is ++prevented when the system is running in FIPS mode. ++ + The option specifies the nss configuration directory to use. + This is the directory where the NSS certificate, key and security modules databases reside. The + default value is /etc/ipsec.d. +diff -Naur libreswan-3.12-orig/programs/rsasigkey/rsasigkey.c libreswan-3.12/programs/rsasigkey/rsasigkey.c +--- libreswan-3.12-orig/programs/rsasigkey/rsasigkey.c 2014-11-06 21:52:50.000000000 -0600 ++++ libreswan-3.12/programs/rsasigkey/rsasigkey.c 2015-02-26 21:25:39.303000000 -0600 +@@ -4,7 +4,7 @@ + * Copyright (C) 2003-2008 Michael C Richardson + * Copyright (C) 2003-2009 Paul Wouters + * Copyright (C) 2009 Avesh Agarwal +- * Copyright (C) 2012-2013 Paul Wouters ++ * Copyright (C) 2012-2015 Paul Wouters + * + * 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 +@@ -64,26 +64,22 @@ + #define MIN_KEYBIT 2192 + + #ifndef DEVICE +-/* To the openwrt people: Do not change /dev/random to /dev/urandom. The +- * /dev/random device is ONLY used for generating long term keys, which +- * should NEVER be done with /dev/urandom. If people use X.509, PSK or +- * even raw RSA keys generated on other systems, changing this will have +- * 0 effect. It's better to fail or bail out of generating a key, then +- * generate a bad one. +- */ + # define DEVICE "/dev/random" + #endif + #ifndef MAXBITS + # define MAXBITS 20000 + #endif + ++#define DEFAULT_SEED_BITS 60 /* 480 bits of random seed */ ++ + #define E 3 /* standard public exponent */ + /* #define F4 65537 */ /* possible future public exponent, Fermat's 4th number */ + + #define NSSDIR "/etc/ipsec.d" + ++char *progname; + char usage[] = +- "rsasigkey [--verbose] [--random ] [--configdir ] [--password ] [--hostname host] []"; ++ "rsasigkey [--verbose] [--random ] [--configdir ] [--password ] [--hostname host] [--seedbits bits] []"; + struct option opts[] = { + { "rounds", 1, NULL, 'p', }, /* obsoleted */ + { "noopt", 0, NULL, 'n', }, /* obsoleted */ +@@ -96,6 +92,7 @@ + { "configdir", 1, NULL, 'c' }, + { "configdir2", 1, NULL, 'd' }, /* nss tools use -d */ + { "password", 1, NULL, 'P' }, ++ { "seedbits", 1, NULL, 's' }, + { 0, 0, NULL, 0, } + }; + int verbose = 0; /* narrate the action? */ +@@ -106,14 +103,13 @@ + char me[] = "ipsec rsasigkey"; /* for messages */ + + /* forwards */ +-void rsasigkey(int nbits, char *configdir, char *password); ++void rsasigkey(int nbits, int seedbits, char *configdir, char *password); + void getrandom(size_t nbytes, unsigned char *buf); + static const unsigned char *bundle(int e, mpz_t n, size_t *sizep); + static const char *conv(const unsigned char *bits, size_t nbytes, int format); + static const char *hexout(mpz_t var); + void report(char *msg); + +-#define RAND_BUF_SIZE 60 + + /* getModulus - returns modulus of the RSA public key */ + static SECItem *getModulus(SECKEYPublicKey *pk) +@@ -163,15 +159,17 @@ + } + + /* UpdateRNG - Updates NSS's PRNG with user generated entropy. */ +-static void UpdateNSS_RNG(void) ++static void UpdateNSS_RNG(int seedbits) + { + SECStatus rv; +- unsigned char buf[RAND_BUF_SIZE]; ++ int seedbytes = BYTES_FOR_BITS(seedbits); ++ unsigned char *buf = alloc_bytes(seedbytes,"TLA seedmix"); + +- getrandom(RAND_BUF_SIZE, buf); +- rv = PK11_RandomUpdate(buf, sizeof buf); ++ getrandom(seedbytes, buf); ++ rv = PK11_RandomUpdate(buf, seedbytes); + assert(rv == SECSuccess); + zero(&buf); ++ pfree(buf); + } + + /* Returns the password passed in in the text file. +@@ -303,6 +301,7 @@ + { + int opt; + int nbits = 0; ++ int seedbits = DEFAULT_SEED_BITS; + char *configdir = NULL; /* where the NSS databases reside */ + char *password = NULL; /* password for token authentication */ + +@@ -344,6 +343,16 @@ + case 'P': /* token authentication password */ + password = optarg; + break; ++ case 's': /* seed bits */ ++ seedbits = atoi(optarg); ++ if (PK11_IsFIPS()) { ++ if (seedbits < DEFAULT_SEED_BITS) { ++ fprintf(stderr, "%s: FIPS mode does not allow < %d seed bits\n", ++ me, DEFAULT_SEED_BITS); ++ exit(1); ++ } ++ } ++ break; + case '?': + default: + printf("Usage:\t%s\n", usage); +@@ -393,7 +402,7 @@ + exit(1); + } + +- rsasigkey(nbits, configdir, password); ++ rsasigkey(nbits, seedbits, configdir, password); + exit(0); + } + +@@ -405,7 +414,7 @@ + * real speed advantages. + * See also: https://www.imperialviolet.org/2012/03/16/rsae.html + */ +-void rsasigkey(int nbits, char *configdir, char *password) ++void rsasigkey(int nbits, int seedbits, char *configdir, char *password) + { + SECStatus rv; + PK11RSAGenParams rsaparams = { nbits, (long) E }; +@@ -483,7 +492,7 @@ + #endif /* 0 */ + + /* Do some random-number initialization. */ +- UpdateNSS_RNG(); ++ UpdateNSS_RNG(seedbits); + /* Log in to the token */ + if (password) { + rv = PK11_Authenticate(slot, PR_FALSE, &pwdata); +@@ -553,9 +562,7 @@ + /* + - getrandom - get some random bytes from /dev/random (or wherever) + */ +-void getrandom(nbytes, buf) +-size_t nbytes; +-unsigned char *buf; /* known to be big enough */ ++void getrandom(size_t nbytes, unsigned char *buf) + { + size_t ndone; + int dev; +@@ -570,8 +577,8 @@ + + ndone = 0; + if (verbose) { +- fprintf(stderr, "getting %d random bytes from %s...\n", +- (int) nbytes, ++ fprintf(stderr, "getting %d random seed bytes for NSS from %s...\n", ++ (int) nbytes * BITS_PER_BYTE, + device); + } + while (ndone < nbytes) { +@@ -683,3 +690,12 @@ + + fprintf(stderr, "%s\n", msg); + } ++/* exit_tool() is needed if the library was compiled with DEBUG, even if we are not. ++ * The odd-looking parens are to prevent macro expansion: ++ * lswlog.h without DEBUG define a macro exit_tool(). ++ */ ++void (exit_tool)(int x) ++{ ++ exit(x); ++} ++ diff --git a/SOURCES/libreswan-3.12-1203794-fipstest.patch b/SOURCES/libreswan-3.12-1203794-fipstest.patch new file mode 100644 index 0000000..dc6a248 --- /dev/null +++ b/SOURCES/libreswan-3.12-1203794-fipstest.patch @@ -0,0 +1,57 @@ +diff -Naur libreswan-3.12-orig/programs/pluto/ike_alg_aes.c libreswan-3.12/programs/pluto/ike_alg_aes.c +--- libreswan-3.12-orig/programs/pluto/ike_alg_aes.c 2015-04-12 16:52:11.748913102 -0400 ++++ libreswan-3.12/programs/pluto/ike_alg_aes.c 2015-04-12 20:19:08.330821771 -0400 +@@ -410,20 +410,24 @@ + + void ike_alg_aes_init(void) + { +- if (!test_aes_cbc(&algo_aes_cbc)) { ++ bool fips = libreswan_fipsmode(); ++ if (!fips && !test_aes_cbc(&algo_aes_cbc)) { + loglog(RC_LOG_SERIOUS, "CKM_AES_CBC: test failure"); ++ exit_pluto(6); + } + if (ike_alg_register_enc(&algo_aes_cbc) != 1) + loglog(RC_LOG_SERIOUS, "Warning: failed to register algo_aes_cbc for IKE"); + +- if (!test_aes_ctr(&algo_aes_ctr)) { ++ if (!fips && !test_aes_ctr(&algo_aes_ctr)) { + loglog(RC_LOG_SERIOUS, "CKM_AES_CTR: test failure"); ++ exit_pluto(6); + } + if (ike_alg_register_enc(&algo_aes_ctr) != 1) + loglog(RC_LOG_SERIOUS, "Warning: failed to register algo_aes_ctr for IKE"); + +- if (!test_aes_gcm()) { ++ if (!fips && !test_aes_gcm()) { + loglog(RC_LOG_SERIOUS, "CKM_AES_GCM: test failure"); ++ exit_pluto(6); + } + if (ike_alg_register_enc(&algo_aes_gcm_8) != 1) + loglog(RC_LOG_SERIOUS, "Warning: failed to register algo_aes_gcm_8 for IKE"); +diff -Naur libreswan-3.12-orig/programs/pluto/ike_alg_camellia.c libreswan-3.12/programs/pluto/ike_alg_camellia.c +--- libreswan-3.12-orig/programs/pluto/ike_alg_camellia.c 2015-04-12 16:52:11.705911919 -0400 ++++ libreswan-3.12/programs/pluto/ike_alg_camellia.c 2015-04-12 17:41:22.863365586 -0400 +@@ -94,11 +94,20 @@ + + void ike_alg_camellia_init(void) + { +- test_camellia_cbc(&algo_camellia_cbc); ++#ifdef FIPS_CHECK ++ bool fips = libreswan_fipsmode(); ++#else ++ bool fips = FALSE; ++#endif ++ ++ if (!fips && !test_camellia_cbc(&algo_camellia_cbc)) { ++ loglog(RC_LOG_SERIOUS, "CKM_CAMELLIA_CBC: test failure"); ++ exit_pluto(6); ++ } ++ + if (ike_alg_register_enc(&algo_camellia_cbc) != 1) + loglog(RC_LOG_SERIOUS, "Warning: failed to register algo_camellia_cbc for IKE"); + +- // test_camellia_ctr(&algo_camellia_ctr); + if (ike_alg_register_enc(&algo_camellia_ctr) != 1) + loglog(RC_LOG_SERIOUS, "Warning: failed to register algo_camellia_ctr for IKE"); + } diff --git a/SOURCES/libreswan-3.12-1207689-blacklist.patch b/SOURCES/libreswan-3.12-1207689-blacklist.patch new file mode 100644 index 0000000..2ed01e5 --- /dev/null +++ b/SOURCES/libreswan-3.12-1207689-blacklist.patch @@ -0,0 +1,160 @@ +diff -Naur libreswan-3.12-orig/Makefile.inc libreswan-3.12/Makefile.inc +--- libreswan-3.12-orig/Makefile.inc 2014-11-06 22:52:50.000000000 -0500 ++++ libreswan-3.12/Makefile.inc 2015-04-28 23:18:45.781649956 -0400 +@@ -176,7 +176,10 @@ + OSMOD_DESTDIR?=net/ipsec + + # What command to use to load the modules. openwrt does not have modprobe +-MODPROBE?=modprobe -q ++# Using -b enables blacklisting - this is needed for some known bad ++# versions of crypto acceleration modules. ++MODPROBEBIN?=modprobe ++MODPROBEARGS?=-q -b + + ### misc installation stuff + +@@ -521,7 +524,8 @@ + -e "s:@IPSEC_EXECDIR@:$(FINALLIBEXECDIR):g" \ + -e "s:@IPSEC_VARDIR@:$(FINALVARDIR):g" \ + -e "s:@IPSEC_SBINDIR@:$(FINALSBINDIR):g" \ +- -e "s:@MODPROBE@:$(MODPROBE):g" \ ++ -e "s:@MODPROBEBIN@:$(MODPROBEBIN):g" \ ++ -e "s:@MODPROBEARGS@:$(MODPROBEARGS):g" \ + -e "s:@USE_DEFAULT_CONNS@:$(USE_DEFAULT_CONNS):g" \ + + # For KVM testing setup +diff -Naur libreswan-3.12-orig/programs/_stackmanager/_stackmanager.in libreswan-3.12/programs/_stackmanager/_stackmanager.in +--- libreswan-3.12-orig/programs/_stackmanager/_stackmanager.in 2014-11-06 22:52:50.000000000 -0500 ++++ libreswan-3.12/programs/_stackmanager/_stackmanager.in 2015-04-28 23:16:25.709947026 -0400 +@@ -2,7 +2,7 @@ + # STACK startup script + # Copyright (C) 2007 Ken Bantoft + # Copyright (C) 2007-2008 Paul Wouters +-# Copyright (C) 2008-2014 Tuomo Soini ++# Copyright (C) 2008-2015 Tuomo Soini + # Copyright (C) 2012-2014 Paul Wouters + # + # This program is free software; you can redistribute it and/or modify it +@@ -24,6 +24,7 @@ + export PATH + + test ${IPSEC_INIT_SCRIPT_DEBUG} && set -v -x ++MODPROBE="@MODPROBEBIN@ @MODPROBEARGS@" + + kamepfkey=/proc/net/pfkey + ipsecpfkey=/proc/net/ipsec/version +@@ -119,11 +120,11 @@ + xfrm4_mode_beet esp4 esp6 ah4 ah6 af_key ip_vti + do + # echo -n "${mod} " >&2 +- @MODPROBE@ ${mod} 2>/dev/null ++ ${MODPROBE} ${mod} 2>/dev/null + done + + # xfrm_user is the old name for xfrm4_tunnel - backwards compatibility +- @MODPROBE@ xfrm_user 2>/dev/null ++ ${MODPROBE} xfrm_user 2>/dev/null + + fi + # Required for Labeled IPsec +@@ -184,19 +185,19 @@ + cryptomodules() { + # load hardware random and crypto related modules. + # some changed names over time +- @MODPROBE@ hw_random 2>/dev/null +- @MODPROBE@ hwrng 2>/dev/null +- @MODPROBE@ virtio-rng 2>/dev/null +- @MODPROBE@ amd-rng 2>/dev/null +- @MODPROBE@ intel-rng 2>/dev/null +- @MODPROBE@ geode-rng 2>/dev/null +- @MODPROBE@ timeriomem-rng 2>/dev/null +- @MODPROBE@ tpm-rng 2>/dev/null ++ ${MODPROBE} hw_random 2>/dev/null ++ ${MODPROBE} hwrng 2>/dev/null ++ ${MODPROBE} virtio-rng 2>/dev/null ++ ${MODPROBE} amd-rng 2>/dev/null ++ ${MODPROBE} intel-rng 2>/dev/null ++ ${MODPROBE} geode-rng 2>/dev/null ++ ${MODPROBE} timeriomem-rng 2>/dev/null ++ ${MODPROBE} tpm-rng 2>/dev/null + + # load any OCF and CryptoAPI modules we might need for acceleration + # (OCF works for NETKEY and KLIPS/MAST) + # OCF cryptosoft is for kernel acceleration (ESP/AH) +- @MODPROBE@ cryptosoft 2>/dev/null ++ ${MODPROBE} cryptosoft 2>/dev/null + # We skip cryptodev.ko because we no longer support /dev/crypto offloading + # (the overhead of cryptodev is not worth it even on embedded platforms) + +@@ -219,9 +220,9 @@ + # padlock must load before aes module - though does not exist on newer + # kernels + # padlock-aes must load before padlock-sha for some reason +- @MODPROBE@ padlock 2>/dev/null +- @MODPROBE@ padlock-aes 2>/dev/null +- @MODPROBE@ padlock-sha 2>/dev/null ++ ${MODPROBE} padlock 2>/dev/null ++ ${MODPROBE} padlock-aes 2>/dev/null ++ ${MODPROBE} padlock-sha 2>/dev/null + # load the most common ciphers/algo's + # aes-x86_64 has higher priority in via crypto api + # kernel directory does not match uname -m on x86_64 :( +@@ -234,7 +235,7 @@ + do + module=$(basename ${module} | sed "s/\.ko$//") + # echo -n "${module} " >&2 +- @MODPROBE@ ${module} 2>/dev/null ++ ${MODPROBE} ${module} 2>/dev/null + done + } + +@@ -264,10 +265,10 @@ + ;; + esac + # modprobe does not like specifying .o or .ko, but insmod needs it +- if [ "$(basename @MODPROBE@)" = "modprobe" ]; then +- @MODPROBE@ ipsec ++ if [ "$(basename "@MODPROBEBIN@")" = "modprobe" ]; then ++ ${MODPROBE} ipsec + else +- @MODPROBE@ ${modulename} ++ ${MODPROBE} ${modulename} + fi + + if [ ! -f ${ipsecpfkey} ]; then +@@ -418,7 +419,12 @@ + exit 4 + fi + +-stack="$(ipsec addconn --config ${IPSEC_CONF} --liststack)" ++if [ "$2" = "--netkey" ]; then ++ # manual override for use in docker ++ stack=netkey ++else ++ stack="$(ipsec addconn --config ${IPSEC_CONF} --liststack)" ++fi + + case ${stack} in + netkey|klips|mast|none) +@@ -435,15 +441,18 @@ + + case ${action} in + stop) +- # We don't unload NETKEY/XFRM on stop - only when we detect a stack change. ++ # We don't unload NETKEY/XFRM on stop - only when we detect a stack ++ # change. + if [ -f ${ipsecpfkey} ]; then + ipsec eroute --clear +- # this clears all IP addresses on ipsecX interfaces by unloading the module ++ # this clears all IP addresses on ipsecX interfaces by ++ # unloading the module + stopklips + elif [ -f ${kamepfkey} ]; then + ip xfrm state flush + ip xfrm policy flush +- # module unloading skipped on purpose - can hang for a long time or fail ++ # module unloading skipped on purpose - can hang for a long ++ # time or fail + fi + ;; + start) diff --git a/SOURCES/libreswan-3.12-1212121-cavs.patch b/SOURCES/libreswan-3.12-1212121-cavs.patch new file mode 100644 index 0000000..f1f7743 --- /dev/null +++ b/SOURCES/libreswan-3.12-1212121-cavs.patch @@ -0,0 +1,5368 @@ +diff -Naur libreswan-3.12-orig/programs/pluto/cavp.c libreswan-3.12/programs/pluto/cavp.c +--- libreswan-3.12-orig/programs/pluto/cavp.c 1969-12-31 19:00:00.000000000 -0500 ++++ libreswan-3.12/programs/pluto/cavp.c 2015-05-06 11:45:32.912301324 -0400 +@@ -0,0 +1,305 @@ ++/* ++ * Parse CAVP test vectors, for libreswan ++ * ++ * Copyright (C) 2015 Andrew Cagney ++ * ++ * 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. See . ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ */ ++ ++#include ++/* #include */ ++#include ++#include ++ ++#include "constants.h" ++#include "lswalloc.h" ++#include "ike_alg.h" ++#include "crypto.h" ++#include "crypt_symkey.h" ++#include "test_buffer.h" ++ ++#include "cavp.h" ++#include "cavp_print.h" ++#include "cavp_ikev1.h" ++#include "cavp_ikev2.h" ++ ++struct cavp *cavps[] = { ++ &cavp_ikev1_sig, ++ &cavp_ikev1_psk, ++ &cavp_ikev2, ++ NULL ++}; ++ ++#define BUF_SIZE 4096 ++ ++static struct cavp_entry *lookup_entry(struct cavp_entry *entries, const char *key) ++{ ++ struct cavp_entry *entry; ++ for (entry = entries; entry->op != NULL; entry++) { ++ if (strcmp(entry->key, key) == 0) { ++ return entry; ++ } ++ } ++ return NULL; ++} ++ ++enum what { INITIAL, BLANK, CONFIG, DATA, RUN, FINAL } state = INITIAL; ++ ++static void error_state(enum what state, enum what what) ++{ ++ fprintf(stderr, "bad state %d what %d\n", state, what); ++ exit(1); ++} ++ ++static struct cavp *cavp; ++ ++static void next_state(enum what what) ++{ ++ switch (state) { ++ case INITIAL: ++ switch (what) { ++ case CONFIG: ++ state = CONFIG; ++ break; ++ case BLANK: ++ break; ++ default: ++ error_state(state, what); ++ } ++ break; ++ case CONFIG: ++ switch (what) { ++ case CONFIG: ++ break; ++ case BLANK: ++ cavp->print_config(); ++ state = DATA; ++ break; ++ default: ++ error_state(state, what); ++ } ++ break; ++ case DATA: ++ switch (what) { ++ case DATA: ++ break; ++ case BLANK: ++ cavp->run(); ++ state = RUN; ++ break; ++ default: ++ error_state(state, what); ++ } ++ break; ++ case RUN: ++ switch (what) { ++ case CONFIG: ++ state = CONFIG; ++ break; ++ case DATA: ++ state = DATA; ++ break; ++ case BLANK: ++ break; ++ default: ++ error_state(state, what); ++ } ++ break; ++ default: ++ error_state(state, what); ++ break; ++ } ++} ++ ++struct hash_desc *hasher; ++char hasher_name[BUF_SIZE]; ++ ++void hash(struct cavp_entry *entry, ++ const char *value UNUSED) ++{ ++ strcpy(hasher_name, entry->key); ++ hasher = ike_alg_get_hasher(entry->value); ++ if (hasher == NULL) { ++ fprintf(stderr, "hasher %s not found\n", entry->key); ++ } ++} ++ ++void chunk(struct cavp_entry *entry, ++ const char *value) ++{ ++ freeanychunk(*(entry->chunk)); ++ *(entry->chunk) = decode_hex_to_chunk(entry->key, value); ++} ++ ++void symkey(struct cavp_entry *entry, ++ const char *value) ++{ ++ free_any_symkey(__func__, entry->symkey); ++ chunk_t chunk = decode_hex_to_chunk(entry->key, value); ++ *(entry->symkey) = chunk_to_key(CKM_DH_PKCS_DERIVE, chunk); ++ freeanychunk(chunk); ++} ++ ++void number(struct cavp_entry *entry, ++ const char *value) ++{ ++ *(entry->number) = atoi(value); ++} ++ ++void ignore(struct cavp_entry *entry UNUSED, ++ const char *value UNUSED) ++{ ++} ++ ++static void cavp_parser() ++{ ++ char line[BUF_SIZE]; ++ while (TRUE) { ++ if (fgets(line, sizeof(line), stdin) == NULL) { ++ int error = ferror(stdin); ++ if (error) { ++ fprintf(stderr, "Unexpected error: %s\n", ++ strerror(error)); ++ exit(1); ++ } ++ break; ++ } ++ /* trim trailing cr/nl. */ ++ int last = strlen(line) - 1; ++ while (last >= 0 && strchr("\r\n", line[last]) != NULL) { ++ last--; ++ } ++ line[last + 1] = '\0'; ++ /* break the line up */ ++ char *lparen = strchr(line, '['); ++ char *eq = strchr(line, '='); ++ char *rparen = strchr(line, ']'); ++ if (line[0] == '\0') { ++ next_state(BLANK); ++ /* blank */ ++ print_line(line); ++ } else if (line[0] == '#') { ++ /* # .... comment */ ++ if (cavp == NULL) { ++ struct cavp **cavpp; ++ for (cavpp = cavps; *cavpp != NULL; cavpp++) { ++ if (strstr(line, (*cavpp)->description) != NULL) { ++ cavp = *cavpp; ++ fprintf(stderr, "\ntest: %s (guess)\n\n", cavp->description); ++ break; ++ } ++ } ++ } ++ print_line(line); ++ } else if (lparen != NULL && rparen != NULL) { ++ next_state(CONFIG); ++ /* "[" [ " = " ] "]" */ ++ *rparen = '\0'; ++ char *key = lparen + 1; ++ char *value; ++ if (eq == NULL) { ++ value = NULL; ++ } else { ++ value = eq + 2; ++ *(eq - 1) = '\0'; ++ } ++ struct cavp_entry *entry = lookup_entry(cavp->config, key); ++ if (entry == NULL) { ++ fprintf(stderr, "unknown config entry: ['%s' = '%s']\n", key, value); ++ exit(1); ++ } ++ entry->op(entry, value); ++ } else if (eq != NULL) { ++ next_state(DATA); ++ *(eq - 1) = '\0'; ++ char *key = line; ++ char *value = eq + 2; ++ struct cavp_entry *entry = lookup_entry(cavp->data, key); ++ if (entry == NULL) { ++ fprintf(stderr, "unknown data entry: '%s' = '%s'\n", key, value); ++ exit(1); ++ } ++ entry->op(entry, value); ++ } else { ++ fprintf(stderr, "bad line: '%s'\n", line); ++ } ++ } ++} ++ ++static void usage() ++{ ++ fprintf(stderr, "Usage: cavp [ -OPTION ] |-\n"); ++ struct cavp **cavpp; ++ for (cavpp = cavps; *cavpp != NULL; cavpp++) { ++ fprintf(stderr, "\t-%s\t%s\n", (*cavpp)->alias, (*cavpp)->description); ++ } ++} ++ ++int main(int argc, char *argv[]) ++{ ++ if (argc <= 1) { ++ usage(); ++ exit(1); ++ } ++ char **argp = argv + 1; ++ ++ /* a -XXX option? */ ++ if ((*argp)[0] == '-' && (*argp)[1] != '\0') { ++ struct cavp **cavpp; ++ for (cavpp = cavps; *cavpp != NULL; cavpp++) { ++ if (strcmp(argv[1]+1, (*cavpp)->alias) == 0) { ++ cavp = *cavpp; ++ fprintf(stderr, "test: %s\n", cavp->description); ++ break; ++ } ++ } ++ if (cavp == NULL) { ++ fprintf(stderr, "Unknown test %s\n", argv[1]); ++ usage(); ++ exit(1); ++ } ++ argp++; ++ } else { ++ fprintf(stderr, "Guessing test type ...\n"); ++ } ++ ++ if (*argp == NULL) { ++ fprintf(stderr, "missing test file\n"); ++ usage(); ++ exit(1); ++ } ++ if (strcmp(*argp, "-") == 0) { ++ fprintf(stderr, "Reading from stdin\n"); ++ } else { ++ fprintf(stderr, "reading from %s\n", *argp); ++ if (freopen(*argp, "r", stdin) == NULL) { ++ perror("freopen"); ++ exit(1); ++ } ++ } ++ argp++; ++ ++ if (*argp != NULL) { ++ fprintf(stderr, "unexpected %s", *argp); ++ usage(); ++ exit(1); ++ } ++ ++ setbuf(stdout, NULL); ++ ++ NSS_NoDB_Init("."); ++ init_crypto(); ++ ++ cavp_parser(); ++ ++ NSS_Shutdown(); ++ return 0; ++} +diff -Naur libreswan-3.12-orig/programs/pluto/cavp.h libreswan-3.12/programs/pluto/cavp.h +--- libreswan-3.12-orig/programs/pluto/cavp.h 1969-12-31 19:00:00.000000000 -0500 ++++ libreswan-3.12/programs/pluto/cavp.h 2015-05-06 11:45:32.912301324 -0400 +@@ -0,0 +1,45 @@ ++/* ++ * Parse CAVP test vectors, for libreswan ++ * ++ * Copyright (C) 2015 Andrew Cagney ++ * ++ * 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. See . ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ */ ++ ++struct hash_desc; ++ ++struct cavp_entry { ++ const char *key; ++ void (*op)(struct cavp_entry *key, const char *value); ++ chunk_t *chunk; ++ PK11SymKey **symkey; ++ int *number; ++ struct hash_desc **hasher; ++ int value; ++}; ++ ++struct cavp { ++ const char *alias; ++ const char *description; ++ void (*print_config)(void); ++ void (*run)(void); ++ struct cavp_entry *config; ++ struct cavp_entry *data; ++}; ++ ++extern struct hash_desc *hasher; ++extern char hasher_name[]; ++void hash(struct cavp_entry *entry, const char *value); ++ ++void ignore(struct cavp_entry *entry, const char *value); ++void chunk(struct cavp_entry *entry, const char *value); ++void symkey(struct cavp_entry *entry, const char *value); ++void number(struct cavp_entry *entry, const char *value); +diff -Naur libreswan-3.12-orig/programs/pluto/cavp_ikev1.c libreswan-3.12/programs/pluto/cavp_ikev1.c +--- libreswan-3.12-orig/programs/pluto/cavp_ikev1.c 1969-12-31 19:00:00.000000000 -0500 ++++ libreswan-3.12/programs/pluto/cavp_ikev1.c 2015-05-06 11:45:32.913301336 -0400 +@@ -0,0 +1,174 @@ ++/* ++ * Parse IKEv1 CAVP test functions, for libreswan ++ * ++ * Copyright (C) 2015 Andrew Cagney ++ * ++ * 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. See . ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ */ ++ ++#include ++ ++#include "lswalloc.h" ++#include "ike_alg.h" ++ ++#include "ikev1_prf.h" ++#include "crypt_symkey.h" ++ ++#include "cavp.h" ++#include "cavp_print.h" ++#include "cavp_ikev1.h" ++ ++static int ni_length; ++static int nr_length; ++static int psk_length; ++static int g_xy_length; ++ ++static struct cavp_entry config_entries[] = { ++ { .key = "SHA-1", .op = hash, .value = OAKLEY_SHA1, }, ++ { .key = "SHA-224", .op = hash, .value = 0, }, ++ { .key = "SHA-256", .op = hash, .value = OAKLEY_SHA2_256, }, ++ { .key = "SHA-384", .op = hash, .value = OAKLEY_SHA2_384, }, ++ { .key = "SHA-512", .op = hash, .value = OAKLEY_SHA2_512, }, ++ { .key = "Ni length", .op = number, .number = &ni_length }, ++ { .key = "Nr length", .op = number, .number = &nr_length }, ++ { .key = "pre-shared-key length", .op = number, .number = &psk_length }, ++ { .key = "g^xy length", .op = number, .number = &g_xy_length }, ++ { .key = NULL } ++}; ++ ++static int count; ++static chunk_t psk; ++static chunk_t ni; ++static chunk_t nr; ++static chunk_t cky_i; ++static chunk_t cky_r; ++static PK11SymKey *g_xy; ++ ++static struct cavp_entry data_entries[] = { ++ { .key = "COUNT", .op = number, .number = &count }, ++ { .key = "g^xy", .op = symkey, .symkey = &g_xy }, ++ { .key = "Ni", .op = chunk, .chunk = &ni }, ++ { .key = "Nr", .op = chunk, .chunk = &nr }, ++ { .key = "CKY_I", .op = chunk, .chunk = &cky_i }, ++ { .key = "CKY_R", .op = chunk, .chunk = &cky_r }, ++ { .key = "pre-shared-key", .op = chunk, .chunk = &psk }, ++ { .key = "SKEYID", .op = ignore }, ++ { .key = "SKEYID_d", .op = ignore }, ++ { .key = "SKEYID_a", .op = ignore }, ++ { .key = "SKEYID_e", .op = ignore }, ++ { .key = "SKEYID_", .op = ignore }, ++ { .op = NULL } ++}; ++ ++static void ikev1_skeyid_alphabet(PK11SymKey *skeyid) ++{ ++ PK11SymKey *skeyid_d = ++ ikev1_skeyid_d(hasher, skeyid, ++ g_xy, cky_i, cky_r); ++ print_symkey("SKEYID_d", skeyid_d, 0); ++ ++ PK11SymKey *skeyid_a = ++ ikev1_skeyid_a(hasher, skeyid, skeyid_d, ++ g_xy, cky_i, cky_r); ++ print_symkey("SKEYID_a", skeyid_a, 0); ++ ++ PK11SymKey *skeyid_e = ++ ikev1_skeyid_e(hasher, skeyid, skeyid_a, ++ g_xy, cky_i, cky_r); ++ print_symkey("SKEYID_e", skeyid_e, 0); ++ ++ free_any_symkey("skeyid_d", &skeyid_d); ++ free_any_symkey("skeyid_e", &skeyid_e); ++ free_any_symkey("skeyid_a", &skeyid_a); ++} ++ ++static void print_sig_config() ++{ ++ config_number("g^xy length", g_xy_length); ++ config_key(hasher_name); ++ config_number("Ni length", ni_length); ++ config_number("Nr length", nr_length); ++} ++ ++static void run_sig(void) ++{ ++ print_number("COUNT", count); ++ print_chunk("CKY_I", cky_i, 0); ++ print_chunk("CKY_R", cky_r, 0); ++ print_chunk("Ni", ni, 0); ++ print_chunk("Nr", nr, 0); ++ print_symkey("g^xy", g_xy, 0); ++ ++ if (hasher == NULL) { ++ print_line(hasher_name); ++ return; ++ } ++ ++ PK11SymKey *skeyid = ++ ikev1_signature_skeyid(hasher, ++ ni, nr, ++ g_xy); ++ print_symkey("SKEYID", skeyid, 0); ++ ikev1_skeyid_alphabet(skeyid); ++ free_any_symkey("skeyid", &skeyid); ++} ++ ++struct cavp cavp_ikev1_sig = { ++ .alias = "v1sig", ++ .description = "IKE v1 Digital Signature Authentication", ++ .print_config = print_sig_config, ++ .run = run_sig, ++ .config = config_entries, ++ .data = data_entries, ++}; ++ ++static void print_psk_config(void) ++{ ++ config_number("g^xy length", g_xy_length); ++ config_key(hasher_name); ++ config_number("Ni length", ni_length); ++ config_number("Nr length", nr_length); ++ config_number("pre-shared-key length", psk_length); ++} ++ ++static void run_psk(void) ++{ ++ print_number("COUNT", count); ++ print_chunk("CKY_I", cky_i, 0); ++ print_chunk("CKY_R", cky_r, 0); ++ print_chunk("Ni", ni, 0); ++ print_chunk("Nr", nr, 0); ++ print_symkey("g^xy", g_xy, 0); ++ print_chunk("pre-shared-key", psk, 0); ++ ++ if (hasher == NULL) { ++ print_line(hasher_name); ++ return; ++ } ++ ++ PK11SymKey *skeyid = ++ ikev1_pre_shared_key_skeyid(hasher, ++ psk, ++ ni, nr, ++ g_xy); ++ print_symkey("SKEYID", skeyid, 0); ++ ikev1_skeyid_alphabet(skeyid); ++ free_any_symkey("skeyid", &skeyid); ++} ++ ++struct cavp cavp_ikev1_psk = { ++ .alias = "v1psk", ++ .description = "IKE v1 Pre-shared Key Authentication", ++ .print_config = print_psk_config, ++ .run = run_psk, ++ .config = config_entries, ++ .data = data_entries, ++}; +diff -Naur libreswan-3.12-orig/programs/pluto/cavp_ikev1.h libreswan-3.12/programs/pluto/cavp_ikev1.h +--- libreswan-3.12-orig/programs/pluto/cavp_ikev1.h 1969-12-31 19:00:00.000000000 -0500 ++++ libreswan-3.12/programs/pluto/cavp_ikev1.h 2015-05-06 11:45:32.913301336 -0400 +@@ -0,0 +1,18 @@ ++/* ++ * Parse IKEv1 CAVP test functions, for libreswan ++ * ++ * Copyright (C) 2015 Andrew Cagney ++ * ++ * 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. See . ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ */ ++ ++struct cavp cavp_ikev1_sig; ++struct cavp cavp_ikev1_psk; +diff -Naur libreswan-3.12-orig/programs/pluto/cavp_ikev2.c libreswan-3.12/programs/pluto/cavp_ikev2.c +--- libreswan-3.12-orig/programs/pluto/cavp_ikev2.c 1969-12-31 19:00:00.000000000 -0500 ++++ libreswan-3.12/programs/pluto/cavp_ikev2.c 2015-05-06 11:45:32.913301336 -0400 +@@ -0,0 +1,141 @@ ++/* ++ * Parse IKEv1 CAVP test functions, for libreswan ++ * ++ * Copyright (C) 2015 Andrew Cagney ++ * ++ * 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. See . ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ */ ++ ++#include ++ ++#include "lswalloc.h" ++#include "ike_alg.h" ++ ++#include "crypt_symkey.h" ++#include "ikev2_prf.h" ++ ++#include "cavp.h" ++#include "cavp_print.h" ++#include "cavp_ikev2.h" ++ ++static int g_ir_length; ++static int ni_length; ++static int nr_length; ++static int dkm_length; ++static int child_sa_dkm_length; ++ ++static struct cavp_entry config_entries[] = { ++ { .key = "g^ir length", .op = number, .number = &g_ir_length }, ++ { .key = "SHA-1", .op = hash, .value = OAKLEY_SHA1, }, ++ { .key = "SHA-224", .op = hash, .value = 0, }, ++ { .key = "SHA-256", .op = hash, .value = OAKLEY_SHA2_256, }, ++ { .key = "SHA-384", .op = hash, .value = OAKLEY_SHA2_384, }, ++ { .key = "SHA-512", .op = hash, .value = OAKLEY_SHA2_512, }, ++ { .key = "Ni length", .op = number, .number = &ni_length }, ++ { .key = "Nr length", .op = number, .number = &nr_length }, ++ { .key = "DKM length", .op = number, .number = &dkm_length }, ++ { .key = "Child SA DKM length", .op = number, .number = &child_sa_dkm_length }, ++ { .key = NULL } ++}; ++ ++static void ikev2_config() ++{ ++ config_number("g^ir length", g_ir_length); ++ config_key(hasher_name); ++ config_number("Ni length",ni_length); ++ config_number("Nr length",nr_length); ++ config_number("DKM length",dkm_length); ++ config_number("Child SA DKM length",child_sa_dkm_length); ++} ++ ++static int count; ++static chunk_t ni; ++static chunk_t nr; ++static PK11SymKey *g_ir; ++static PK11SymKey *g_ir_new; ++static chunk_t spi_i; ++static chunk_t spi_r; ++ ++static struct cavp_entry data_entries[] = { ++ { .key = "COUNT", .op = number, .number = &count }, ++ { .key = "g^ir", .op = symkey, .symkey = &g_ir }, ++ { .key = "g^ir (new)", .op = symkey, .symkey = &g_ir_new }, ++ { .key = "Ni", .op = chunk, .chunk = &ni }, ++ { .key = "Nr", .op = chunk, .chunk = &nr }, ++ { .key = "SPIi", .op = chunk, .chunk = &spi_i }, ++ { .key = "SPIr", .op = chunk, .chunk = &spi_r }, ++ { .key = "SKEYSEED", .op = ignore }, ++ { .key = "DKM", .op = ignore }, ++ { .key = "DKM(Child SA)", .op = ignore }, ++ { .key = "DKM(Child SA D-H)", .op = ignore }, ++ { .key = "SKEYSEED(Rekey)", .op = ignore }, ++ { .op = NULL } ++}; ++ ++static void run_ikev2(void) ++{ ++ print_number("COUNT", count); ++ print_chunk("Ni", ni, 0); ++ print_chunk("Nr", nr, 0); ++ print_symkey("g^ir", g_ir, 0); ++ print_symkey("g^ir (new)", g_ir_new, 0); ++ print_chunk("SPIi", spi_i, 0); ++ print_chunk("SPIr", spi_r, 0); ++ ++ if (hasher == NULL) { ++ print_line(hasher_name); ++ return; ++ } ++ ++ /* SKEYSEED = prf(Ni | Nr, g^ir) */ ++ PK11SymKey *skeyseed = ++ ikev2_ike_sa_skeyseed(hasher, ni, nr, g_ir); ++ print_symkey("SKEYSEED", skeyseed, 0); ++ ++ /* prf+(SKEYSEED, Ni | Nr | SPIi | SPIr) */ ++ PK11SymKey *dkm = ++ ikev2_ike_sa_keymat(hasher, skeyseed, ++ ni, nr, spi_i, spi_r, dkm_length / 8); ++ print_symkey("DKM", dkm, dkm_length / 8); ++ ++ /* prf+(SK_d, Ni | Nr) */ ++ PK11SymKey *SK_d = key_from_symkey_bytes(dkm, 0, hasher->hash_digest_len); ++ PK11SymKey *child_sa_dkm = ++ ikev2_child_sa_keymat(hasher, SK_d, NULL, ni, nr, child_sa_dkm_length / 8); ++ print_symkey("DKM(Child SA)", child_sa_dkm, child_sa_dkm_length / 8); ++ ++ /* prf+(SK_d, g^ir (new) | Ni | Nr) */ ++ PK11SymKey *child_sa_dkm_dh = ++ ikev2_child_sa_keymat(hasher, SK_d, g_ir_new, ni, nr, ++ child_sa_dkm_length / 8); ++ print_symkey("DKM(Child SA D-H)", child_sa_dkm_dh, child_sa_dkm_length / 8); ++ ++ /* prf(SK_d (old), g^ir (new) | Ni | Nr) */ ++ PK11SymKey *skeyseed_rekey = ++ ikev2_ike_sa_rekey_skeyseed(hasher, SK_d, g_ir_new, ni, nr); ++ print_symkey("SKEYSEED(Rekey)", skeyseed_rekey, 0); ++ ++ free_any_symkey("skeyseed", &skeyseed); ++ free_any_symkey("dkm", &dkm); ++ free_any_symkey("SK_d", &SK_d); ++ free_any_symkey("child_sa_dkm", &child_sa_dkm); ++ free_any_symkey("child_sa_dkm_dh", &child_sa_dkm_dh); ++ free_any_symkey("skeyseed_rekey", &skeyseed_rekey); ++} ++ ++struct cavp cavp_ikev2 = { ++ .alias = "v2", ++ .description = "IKE v2", ++ .print_config = ikev2_config, ++ .run = run_ikev2, ++ .config = config_entries, ++ .data = data_entries, ++}; +diff -Naur libreswan-3.12-orig/programs/pluto/cavp_ikev2.h libreswan-3.12/programs/pluto/cavp_ikev2.h +--- libreswan-3.12-orig/programs/pluto/cavp_ikev2.h 1969-12-31 19:00:00.000000000 -0500 ++++ libreswan-3.12/programs/pluto/cavp_ikev2.h 2015-05-06 11:45:32.914301347 -0400 +@@ -0,0 +1,17 @@ ++/* ++ * Parse IKEv1 CAVP test functions, for libreswan ++ * ++ * Copyright (C) 2015 Andrew Cagney ++ * ++ * 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. See . ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ */ ++ ++struct cavp cavp_ikev2; +diff -Naur libreswan-3.12-orig/programs/pluto/cavp_print.c libreswan-3.12/programs/pluto/cavp_print.c +--- libreswan-3.12-orig/programs/pluto/cavp_print.c 1969-12-31 19:00:00.000000000 -0500 ++++ libreswan-3.12/programs/pluto/cavp_print.c 2015-05-06 11:45:32.914301347 -0400 +@@ -0,0 +1,73 @@ ++/* ++ * Parse CAVP test vectors, for libreswan ++ * ++ * Copyright (C) 2015 Andrew Cagney ++ * ++ * 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. See . ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ */ ++ ++#include ++#include ++ ++#include "constants.h" ++#include "lswalloc.h" ++#include "crypt_symkey.h" ++#include "cavp_print.h" ++ ++/* ++ * The test vectors are CR-LF terminated, mimic this. ++ */ ++static const char crlf[] = "\r\n"; ++ ++void config_key(const char *key) ++{ ++ fputs("[", stdout); ++ fputs(key, stdout); ++ fputs("]", stdout); ++ fputs(crlf, stdout); ++} ++ ++void config_number(const char *key, int number) ++{ ++ printf("[%s = %d]%s", key, number, crlf); ++} ++ ++void print_chunk(const char *prefix, chunk_t chunk, size_t binlen) ++{ ++ printf("%s = ", prefix); ++ size_t len = binlen == 0 ? chunk.len ++ : binlen < chunk.len ? binlen ++ : chunk.len; ++ ++ size_t i = 0; ++ for (i = 0; i < len; i++) { ++ printf("%02x", chunk.ptr[i]); ++ } ++ printf("%s", crlf); ++} ++ ++void print_symkey(const char *prefix, PK11SymKey *key, size_t binlen) ++{ ++ chunk_t chunk = chunk_from_symkey(prefix, key); ++ print_chunk(prefix, chunk, binlen); ++ freeanychunk(chunk); ++} ++ ++void print_number(const char *prefix, int number) ++{ ++ printf("%s = %d%s", prefix, number, crlf); ++} ++ ++void print_line(const char *line) ++{ ++ fputs(line, stdout); ++ fputs(crlf, stdout); ++} +diff -Naur libreswan-3.12-orig/programs/pluto/cavp_print.h libreswan-3.12/programs/pluto/cavp_print.h +--- libreswan-3.12-orig/programs/pluto/cavp_print.h 1969-12-31 19:00:00.000000000 -0500 ++++ libreswan-3.12/programs/pluto/cavp_print.h 2015-05-06 11:45:32.914301347 -0400 +@@ -0,0 +1,23 @@ ++/* ++ * Parse CAVP test vectors, for libreswan ++ * ++ * Copyright (C) 2015 Andrew Cagney ++ * ++ * 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. See . ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ */ ++ ++void config_number(const char *prefix, int number); ++void config_key(const char *key); ++ ++void print_chunk(const char *prefix, chunk_t chunk, size_t binlen); ++void print_symkey(const char *prefix, PK11SymKey *key, size_t binlen); ++void print_number(const char *prefix, int number); ++void print_line(const char *line); +diff -Naur libreswan-3.12-orig/programs/pluto/cavp_stubs.c libreswan-3.12/programs/pluto/cavp_stubs.c +--- libreswan-3.12-orig/programs/pluto/cavp_stubs.c 1969-12-31 19:00:00.000000000 -0500 ++++ libreswan-3.12/programs/pluto/cavp_stubs.c 2015-05-06 11:45:32.915301359 -0400 +@@ -0,0 +1,21 @@ ++#include ++ ++#include "constants.h" ++#include "libreswan/passert.h" ++ ++/* ++ * Crud to get main to link. ++ */ ++libreswan_passert_fail_t libreswan_passert_fail; ++enum kernel_interface kern_interface; ++extern void exit_pluto(int status); ++void exit_pluto(int status UNUSED) { } ++extern void show_setup_plutomain(); ++void show_setup_plutomain() { } ++extern char *pluto_listen; ++char *pluto_listen = NULL; ++u_int16_t secctx_attr_type = 0; ++u_int16_t secctx_attr_value = 0; ++bool force_busy = FALSE; ++bool strict_crl_policy = FALSE; ++deltatime_t crl_check_interval = { 0 }; +diff -Naur libreswan-3.12-orig/programs/pluto/cbc_test_vectors.c libreswan-3.12/programs/pluto/cbc_test_vectors.c +--- libreswan-3.12-orig/programs/pluto/cbc_test_vectors.c 2015-05-06 11:44:21.562466284 -0400 ++++ libreswan-3.12/programs/pluto/cbc_test_vectors.c 2015-05-06 11:45:32.915301359 -0400 +@@ -13,6 +13,7 @@ + + #include "nss.h" + #include "pk11pub.h" ++#include "crypt_symkey.h" + + struct cbc_test_vector { + const char *description; +@@ -183,7 +184,7 @@ + } + + /* Clean up. */ +- PK11_FreeSymKey(sym_key); ++ free_any_symkey("sym_key", &sym_key); + + DBG(DBG_CRYPT, DBG_log("test_ctr_vector: %s %s", + test->description, ok ? "passed" : "failed")); +diff -Naur libreswan-3.12-orig/programs/pluto/crypt_dh.c libreswan-3.12/programs/pluto/crypt_dh.c +--- libreswan-3.12-orig/programs/pluto/crypt_dh.c 2015-05-06 11:44:21.583466531 -0400 ++++ libreswan-3.12/programs/pluto/crypt_dh.c 2015-05-06 11:45:32.917301382 -0400 +@@ -57,90 +57,20 @@ + #include "id.h" + #include "secrets.h" + #include "keys.h" +-#include "ikev2_prfplus.h" ++#include "crypt_dh.h" ++#include "crypt_symkey.h" + + #include + #include + #include + #include "lswconf.h" + +-/* #define PK11_Derive(base, mechanism, param, target, operation, keysize) \ +- * PK11_Derive_lsw(base, mechanism, param, target, operation, keysize) +- */ +- +-/* MUST BE THREAD-SAFE */ +-static PK11SymKey *pk11_extract_derive_wrapper_lsw(PK11SymKey *base, +- CK_EXTRACT_PARAMS bs, +- CK_MECHANISM_TYPE target, +- CK_ATTRIBUTE_TYPE operation, +- int keySize) +-{ +- SECItem param; +- +- param.data = (unsigned char*)&bs; +- param.len = sizeof(bs); +- +- return PK11_Derive_lsw(base, CKM_EXTRACT_KEY_FROM_KEY, ¶m, target, +- operation, keySize); +-} +- +-static CK_MECHANISM_TYPE nss_encryption_mech( +- const struct encrypt_desc *encrypter) +-{ +- /* the best wey have for "undefined" */ +- CK_MECHANISM_TYPE mechanism = CKM_VENDOR_DEFINED; +- +- switch (encrypter->common.algo_id) { +- case OAKLEY_3DES_CBC: +- mechanism = CKM_DES3_CBC; +- break; +-#ifdef NOT_YET +- case OAKLEY_CAST_CBC: +- mechanism = CKM_CAST5_CBC: +- break; +-#endif +- case OAKLEY_AES_CBC: +- mechanism = CKM_AES_CBC; +- break; +- case OAKLEY_CAMELLIA_CBC: +- mechanism = CKM_CAMELLIA_CBC; +- break; +- case OAKLEY_AES_CTR: +- mechanism = CKM_AES_CTR; +- break; +-#ifdef NOT_YET +- case OAKLEY_AES_CCM_8: +- case OAKLEY_AES_CCM_12: +- case OAKLEY_AES_CCM_16: +- mechanism = CKM_AES_CCM; +- break; +-#endif +- case OAKLEY_AES_GCM_8: +- case OAKLEY_AES_GCM_12: +- case OAKLEY_AES_GCM_16: +- mechanism = CKM_AES_GCM; +- break; +-#ifdef NOT_YET +- case OAKLEY_TWOFISH_CBC: +- mechanism = CKM_TWOFISH_CBC; +- break; +-#endif +- default: +- loglog(RC_LOG_SERIOUS, +- "NSS: Unsupported encryption mechanism for %s", +- strip_prefix(enum_name(&oakley_enc_names, +- encrypter->common.algo_id), "OAKLEY_")); +- break; +- } +- return mechanism; +-} +- + /** Compute DH shared secret from our local secret and the peer's public value. + * We make the leap that the length should be that of the group + * (see quoted passage at start of ACCEPT_KE). + */ + /* MUST BE THREAD-SAFE */ +-static PK11SymKey *calc_dh_shared(const chunk_t g, /* converted to SECItem */ ++PK11SymKey *calc_dh_shared(const chunk_t g, /* converted to SECItem */ + /*const*/ SECKEYPrivateKey *privk, /* NSS doesn't do const */ + const struct oakley_group_desc *group, + const SECKEYPublicKey *local_pubk) +@@ -214,7 +144,7 @@ + CKM_CONCATENATE_DATA_AND_BASE, + CKA_DERIVE, 0); + passert(newdhshared != NULL); +- PK11_FreeSymKey(dhshared); ++ free_any_symkey("dhshared", &dhshared); + dhshared = newdhshared; + freeanychunk(zeros); + } else { +@@ -240,862 +170,6 @@ + return dhshared; + } + +-/* SKEYID for preshared keys. +- * See draft-ietf-ipsec-ike-01.txt 4.1 +- */ +- +-static PK11SymKey *skeyid_preshared(const chunk_t pss, +- const chunk_t ni, +- const chunk_t nr, +- PK11SymKey *shared, +- const struct hash_desc *hasher) +-{ +- struct hmac_ctx ctx; +- +- passert(hasher != NULL); +- +- chunk_t nir; +- unsigned int k; +- CK_MECHANISM_TYPE mechanism; +- u_char buf1[HMAC_BUFSIZE * 2], buf2[HMAC_BUFSIZE * 2]; +- chunk_t buf1_chunk, buf2_chunk; +- PK11SymKey *skeyid; +- +- DBG(DBG_CRYPT, { +- DBG_log("NSS: skeyid inputs (pss+NI+NR+shared-secret) hasher: %s", +- hasher->common.name); +- DBG_log("shared-secret (pointer in chunk_t): %p", shared); +- DBG_dump_chunk("ni: ", ni); +- DBG_dump_chunk("nr: ", nr); +- }); +- +- /* We need to hmac_init with the concatenation of Ni_b and Nr_b, +- * so we have to build a temporary concatentation. +- */ +- +- nir.len = ni.len + nr.len; +- nir.ptr = alloc_bytes(nir.len, "Ni + Nr in skeyid_preshared"); +- memcpy(nir.ptr, ni.ptr, ni.len); +- memcpy(nir.ptr + ni.len, nr.ptr, nr.len); +- +- zero(&buf1); +- +- if (pss.len <= hasher->hash_block_size) { +- memcpy(buf1, pss.ptr, pss.len); +- } else { +- hasher->hash_init(&ctx.hash_ctx); +- hasher->hash_update(&ctx.hash_ctx, pss.ptr, pss.len); +- hasher->hash_final(buf1, &ctx.hash_ctx); +- } +- +- memcpy(buf2, buf1, hasher->hash_block_size); +- +- for (k = 0; k < hasher->hash_block_size; k++) { +- buf1[k] ^= HMAC_IPAD; +- buf2[k] ^= HMAC_OPAD; +- } +- +- /* pfree(nir.ptr); */ +- +- mechanism = nss_key_derivation_mech(hasher); +- buf1_chunk.ptr = buf1; +- buf1_chunk.len = hasher->hash_block_size; +- +- buf2_chunk.ptr = buf2; +- buf2_chunk.len = hasher->hash_block_size; +- +- PK11SymKey *tkey4 = pk11_derive_wrapper_lsw(shared, +- CKM_CONCATENATE_DATA_AND_BASE, buf1_chunk, CKM_EXTRACT_KEY_FROM_KEY, CKA_DERIVE, +- 0); +- /* nss_symkey_log(tkey4, "pss+ipad+shared"); */ +- +- CK_EXTRACT_PARAMS bs = 0; +- PK11SymKey *tkey5 = pk11_extract_derive_wrapper_lsw(tkey4, bs, +- CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, +- hasher->hash_block_size); +- /* nss_symkey_log(tkey5, "pss+ipad"); */ +- +- PK11SymKey *tkey6 = pk11_derive_wrapper_lsw(tkey5, +- CKM_CONCATENATE_BASE_AND_DATA, nir, mechanism, CKA_DERIVE, +- 0); +- pfree(nir.ptr); +- /* nss_symkey_log(tkey6, "pss+ipad+nir"); */ +- +- /* PK11SymKey *tkey1 = pk11_derive_wrapper_lsw(shared, CKM_CONCATENATE_DATA_AND_BASE, buf1_chunk, mechanism, CKA_DERIVE, 0); */ +- PK11SymKey *tkey2 = PK11_Derive_lsw(tkey6, mechanism, NULL, +- CKM_CONCATENATE_DATA_AND_BASE, +- CKA_DERIVE, 0); +- /* nss_symkey_log(tkey2, "pss : tkey2"); */ +- +- PK11SymKey *tkey3 = pk11_derive_wrapper_lsw(tkey2, +- CKM_CONCATENATE_DATA_AND_BASE, buf2_chunk, mechanism, CKA_DERIVE, +- 0); +- skeyid = PK11_Derive_lsw(tkey3, mechanism, NULL, +- CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, 0); +- /* nss_symkey_log(tkey2, "pss : tkey3"); */ +- +- PK11_FreeSymKey(tkey4); +- PK11_FreeSymKey(tkey5); +- PK11_FreeSymKey(tkey6); +- PK11_FreeSymKey(tkey2); +- PK11_FreeSymKey(tkey3); +- +- DBG(DBG_CRYPT, +- DBG_log("NSS: skeyid in skeyid_preshared() (pointer) %p: ", +- skeyid)); +- return skeyid; +-} +- +-/* MUST BE THREAD-SAFE */ +-static PK11SymKey *skeyid_digisig(const chunk_t ni, +- const chunk_t nr, +- /*const*/ PK11SymKey *shared, /* NSS doesn't do const */ +- const struct hash_desc *hasher) +-{ +- struct hmac_ctx ctx; +- chunk_t nir; +- unsigned int k; +- CK_MECHANISM_TYPE mechanism; +- u_char buf1[HMAC_BUFSIZE * 2], buf2[HMAC_BUFSIZE * 2]; +- chunk_t buf1_chunk, buf2_chunk; +- PK11SymKey *skeyid; +- +- DBG(DBG_CRYPT, { +- DBG_log("skeyid inputs (digi+NI+NR+shared) hasher: %s", +- hasher->common.name); +- DBG_dump_chunk("ni: ", ni); +- DBG_dump_chunk("nr: ", nr); +- }); +- +- /* We need to hmac_init with the concatenation of Ni_b and Nr_b, +- * so we have to build a temporary concatentation. +- */ +- nir.len = ni.len + nr.len; +- nir.ptr = alloc_bytes(nir.len, "Ni + Nr in skeyid_digisig"); +- memcpy(nir.ptr, ni.ptr, ni.len); +- memcpy(nir.ptr + ni.len, nr.ptr, nr.len); +- zero(&buf1); +- if (nir.len <= hasher->hash_block_size) { +- memcpy(buf1, nir.ptr, nir.len); +- } else { +- hasher->hash_init(&ctx.hash_ctx); +- hasher->hash_update(&ctx.hash_ctx, nir.ptr, nir.len); +- hasher->hash_final(buf1, &ctx.hash_ctx); +- } +- +- memcpy(buf2, buf1, hasher->hash_block_size); +- +- for (k = 0; k < hasher->hash_block_size; k++) { +- buf1[k] ^= HMAC_IPAD; +- buf2[k] ^= HMAC_OPAD; +- } +- +- pfree(nir.ptr); +- mechanism = nss_key_derivation_mech(hasher); +- buf1_chunk.ptr = buf1; +- buf1_chunk.len = hasher->hash_block_size; +- +- buf2_chunk.ptr = buf2; +- buf2_chunk.len = hasher->hash_block_size; +- +- PK11SymKey *tkey1 = pk11_derive_wrapper_lsw(shared, +- CKM_CONCATENATE_DATA_AND_BASE, buf1_chunk, mechanism, CKA_DERIVE, +- 0); +- PK11SymKey *tkey2 = PK11_Derive_lsw(tkey1, mechanism, NULL, +- CKM_CONCATENATE_DATA_AND_BASE, +- CKA_DERIVE, 0); +- PK11SymKey *tkey3 = pk11_derive_wrapper_lsw(tkey2, +- CKM_CONCATENATE_DATA_AND_BASE, buf2_chunk, mechanism, CKA_DERIVE, +- 0); +- skeyid = PK11_Derive_lsw(tkey3, mechanism, NULL, +- CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, 0); +- +- PK11_FreeSymKey(tkey1); +- PK11_FreeSymKey(tkey2); +- PK11_FreeSymKey(tkey3); +- +- DBG(DBG_CRYPT, +- DBG_log("NSS: digisig skeyid pointer: %p", skeyid)); +- +- return skeyid; +-} +- +-/* Generate the SKEYID_* and new IV +- * See draft-ietf-ipsec-ike-01.txt 4.1 +- */ +-/* MUST BE THREAD-SAFE */ +-static void calc_skeyids_iv(struct pcr_skeyid_q *skq, +- /*const*/ PK11SymKey *shared, /* NSS doesn't do const */ +- const size_t keysize, /* = st->st_oakley.enckeylen/BITS_PER_BYTE; */ +- PK11SymKey **skeyid_out, /* output */ +- PK11SymKey **skeyid_d_out, /* output */ +- PK11SymKey **skeyid_a_out, /* output */ +- PK11SymKey **skeyid_e_out, /* output */ +- chunk_t *new_iv, /* output */ +- PK11SymKey **enc_key_out /* output */ +- ) +-{ +- oakley_auth_t auth = skq->auth; +- oakley_hash_t hash = skq->prf_hash; +- const struct hash_desc *hasher = crypto_get_hasher(hash); +- chunk_t ni; +- chunk_t nr; +- chunk_t gi; +- chunk_t gr; +- chunk_t icookie; +- chunk_t rcookie; +- PK11SymKey +- *skeyid, +- *skeyid_d, +- *skeyid_a, +- *skeyid_e, +- *enc_key; +- const struct encrypt_desc *encrypter = skq->encrypter; +- +- /* this doesn't allocate any memory */ +- setchunk_from_wire(gi, skq, &skq->gi); +- setchunk_from_wire(gr, skq, &skq->gr); +- setchunk_from_wire(ni, skq, &skq->ni); +- setchunk_from_wire(nr, skq, &skq->nr); +- setchunk_from_wire(icookie, skq, &skq->icookie); +- setchunk_from_wire(rcookie, skq, &skq->rcookie); +- +- /* Generate the SKEYID */ +- switch (auth) { +- case OAKLEY_PRESHARED_KEY: +- { +- chunk_t pss; +- +- setchunk_from_wire(pss, skq, &skq->pss); +- skeyid = skeyid_preshared(pss, ni, nr, shared, hasher); +- } +- break; +- +- case OAKLEY_RSA_SIG: +- skeyid = skeyid_digisig(ni, nr, shared, hasher); +- break; +- +- /* Not implemented */ +- case OAKLEY_DSS_SIG: +- case OAKLEY_RSA_ENC: +- case OAKLEY_RSA_REVISED_MODE: +- case OAKLEY_ECDSA_P256: +- case OAKLEY_ECDSA_P384: +- case OAKLEY_ECDSA_P521: +- default: +- bad_case(auth); +- } +- +- /* generate SKEYID_* from SKEYID */ +- { +- +- chunk_t hmac_opad, hmac_ipad, hmac_pad, hmac_zerobyte, +- hmac_val1, hmac_val2; +- CK_OBJECT_HANDLE keyhandle; +- SECItem param, param1; +- +- hmac_opad = hmac_pads(HMAC_OPAD, hasher->hash_block_size); +- hmac_ipad = hmac_pads(HMAC_IPAD, hasher->hash_block_size); +- hmac_pad = hmac_pads(0x00, +- hasher->hash_block_size - +- hasher->hash_digest_len); +- hmac_zerobyte = hmac_pads(0x00, 1); +- hmac_val1 = hmac_pads(0x01, 1); +- hmac_val2 = hmac_pads(0x02, 1); +- +- DBG(DBG_CRYPT, DBG_log("NSS: Started key computation")); +- +- /*Deriving SKEYID_d = hmac_xxx(SKEYID, g^xy | CKY-I | CKY-R | 0) */ +- PK11SymKey *tkey1 = pk11_derive_wrapper_lsw(skeyid, +- CKM_CONCATENATE_BASE_AND_DATA, +- hmac_pad, +- CKM_XOR_BASE_AND_DATA, +- CKA_DERIVE, +- hasher->hash_block_size); +- +- passert(tkey1 != NULL); +- +- /*DBG(DBG_CRYPT, DBG_log("Started key computation: 1, length=%d", PK11_GetKeyLength(tkey1))); +- * nss_symkey_log(tkey1, "1"); +- */ +- +- PK11SymKey *tkey2 = pk11_derive_wrapper_lsw(tkey1, +- CKM_XOR_BASE_AND_DATA, +- hmac_ipad, +- CKM_CONCATENATE_BASE_AND_KEY, +- CKA_DERIVE, +- 0); +- +- passert(tkey2 != NULL); +- +- keyhandle = PK11_GetSymKeyHandle(shared); +- param.data = (unsigned char *) &keyhandle; +- param.len = sizeof(keyhandle); +- DBG(DBG_CRYPT, +- DBG_log("NSS: dh shared param len=%d", param.len)); +- +- PK11SymKey *tkey3 = PK11_Derive_lsw(tkey2, +- CKM_CONCATENATE_BASE_AND_KEY, +- ¶m, +- CKM_CONCATENATE_BASE_AND_DATA, +- CKA_DERIVE, +- 0); +- passert(tkey3 != NULL); +- +- PK11SymKey *tkey4 = pk11_derive_wrapper_lsw(tkey3, +- CKM_CONCATENATE_BASE_AND_DATA, +- icookie, +- CKM_CONCATENATE_BASE_AND_DATA, +- CKA_DERIVE, +- 0); +- passert(tkey4 != NULL); +- +- PK11SymKey *tkey5 = pk11_derive_wrapper_lsw(tkey4, +- CKM_CONCATENATE_BASE_AND_DATA, +- rcookie, +- CKM_CONCATENATE_BASE_AND_DATA, +- CKA_DERIVE, +- 0); +- +- passert(tkey5 != NULL); +- +- PK11SymKey *tkey6 = pk11_derive_wrapper_lsw(tkey5, +- CKM_CONCATENATE_BASE_AND_DATA, +- hmac_zerobyte, +- nss_key_derivation_mech(hasher), +- CKA_DERIVE, +- 0); +- +- passert(tkey6 != NULL); +- +- PK11SymKey *tkey7 = PK11_Derive_lsw(tkey6, +- nss_key_derivation_mech(hasher), +- NULL, +- CKM_CONCATENATE_BASE_AND_DATA, +- CKA_DERIVE, +- 0); +- passert(tkey7 != NULL); +- +- PK11SymKey *tkey8 = pk11_derive_wrapper_lsw(tkey1, +- CKM_XOR_BASE_AND_DATA, +- hmac_opad, +- CKM_CONCATENATE_BASE_AND_KEY, +- CKA_DERIVE, +- 0); +- passert(tkey8 != NULL); +- +- keyhandle = PK11_GetSymKeyHandle(tkey7); +- param.data = (unsigned char*)&keyhandle; +- param.len = sizeof(keyhandle); +- +- PK11SymKey *tkey9 = PK11_Derive_lsw(tkey8, +- CKM_CONCATENATE_BASE_AND_KEY, +- ¶m, +- nss_key_derivation_mech(hasher), +- CKA_DERIVE, +- 0); +- passert(tkey9 != NULL); +- +- skeyid_d = PK11_Derive_lsw(tkey9, +- nss_key_derivation_mech(hasher), +- NULL, +- CKM_CONCATENATE_BASE_AND_DATA, +- CKA_DERIVE, +- 0); +- passert(skeyid_d != NULL); +- /* nss_symkey_log(skeyid_d, "skeyid_d"); */ +- /*****End of SKEYID_d derivation***************************************/ +- +- /*Deriving SKEYID_a = hmac_xxx(SKEYID, SKEYID_d | g^xy | CKY-I | CKY-R | 1)*/ +- keyhandle = PK11_GetSymKeyHandle(skeyid_d); +- param.data = (unsigned char*)&keyhandle; +- param.len = sizeof(keyhandle); +- +- PK11SymKey *tkey10 = PK11_Derive_lsw(tkey2, +- CKM_CONCATENATE_BASE_AND_KEY, +- ¶m, +- CKM_CONCATENATE_BASE_AND_KEY, +- CKA_DERIVE, +- 0); +- passert(tkey10 != NULL); +- +- keyhandle = PK11_GetSymKeyHandle(shared); +- param.data = (unsigned char*)&keyhandle; +- param.len = sizeof(keyhandle); +- +- PK11SymKey *tkey11 = PK11_Derive_lsw(tkey10, +- CKM_CONCATENATE_BASE_AND_KEY, +- ¶m, +- CKM_CONCATENATE_BASE_AND_DATA, +- CKA_DERIVE, +- 0); +- passert(tkey11 != NULL); +- +- PK11SymKey *tkey12 = pk11_derive_wrapper_lsw(tkey11, +- CKM_CONCATENATE_BASE_AND_DATA, +- icookie, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, +- 0); +- passert(tkey12 != NULL); +- +- PK11SymKey *tkey13 = pk11_derive_wrapper_lsw(tkey12, +- CKM_CONCATENATE_BASE_AND_DATA, +- rcookie, +- CKM_CONCATENATE_BASE_AND_DATA, +- CKA_DERIVE, +- 0); +- passert(tkey13 != NULL); +- +- PK11SymKey *tkey14 = pk11_derive_wrapper_lsw(tkey13, +- CKM_CONCATENATE_BASE_AND_DATA, +- hmac_val1, +- nss_key_derivation_mech(hasher), +- CKA_DERIVE, +- 0); +- passert(tkey14 != NULL); +- +- PK11SymKey *tkey15 = PK11_Derive_lsw(tkey14, +- nss_key_derivation_mech(hasher), +- NULL, +- CKM_CONCATENATE_BASE_AND_DATA, +- CKA_DERIVE, +- 0); +- passert(tkey15 != NULL); +- +- keyhandle = PK11_GetSymKeyHandle(tkey15); +- param.data = (unsigned char*)&keyhandle; +- param.len = sizeof(keyhandle); +- +- PK11SymKey *tkey16 = PK11_Derive_lsw(tkey8, +- CKM_CONCATENATE_BASE_AND_KEY, ¶m, +- nss_key_derivation_mech(hasher), +- CKA_DERIVE, +- 0); +- passert(tkey16 != NULL); +- +- skeyid_a = PK11_Derive_lsw(tkey16, +- nss_key_derivation_mech(hasher), +- NULL, +- CKM_CONCATENATE_BASE_AND_DATA, +- CKA_DERIVE, +- 0); +- passert(skeyid_a != NULL); +- /* nss_symkey_log(skeyid_a, "skeyid_a"); */ +- /*****End of SKEYID_a derivation***************************************/ +- +- /*Deriving SKEYID_e = prf(SKEYID, SKEYID_a | g^xy | CKY-I | CKY-R | 2)*/ +- keyhandle = PK11_GetSymKeyHandle(skeyid_a); +- param.data = (unsigned char*)&keyhandle; +- param.len = sizeof(keyhandle); +- +- PK11SymKey *tkey17 = PK11_Derive_lsw(tkey2, +- CKM_CONCATENATE_BASE_AND_KEY, ¶m, CKM_CONCATENATE_BASE_AND_KEY, CKA_DERIVE, +- 0); +- passert(tkey17 != NULL); +- +- keyhandle = PK11_GetSymKeyHandle(shared); +- param.data = (unsigned char*)&keyhandle; +- param.len = sizeof(keyhandle); +- +- PK11SymKey *tkey18 = PK11_Derive_lsw(tkey17, +- CKM_CONCATENATE_BASE_AND_KEY, ¶m, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, +- 0); +- passert(tkey18 != NULL); +- +- PK11SymKey *tkey19 = pk11_derive_wrapper_lsw(tkey18, +- CKM_CONCATENATE_BASE_AND_DATA, +- icookie, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, +- 0); +- passert(tkey19 != NULL); +- +- PK11SymKey *tkey20 = pk11_derive_wrapper_lsw(tkey19, +- CKM_CONCATENATE_BASE_AND_DATA, +- rcookie, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, +- 0); +- passert(tkey20 != NULL); +- +- PK11SymKey *tkey21 = pk11_derive_wrapper_lsw(tkey20, +- CKM_CONCATENATE_BASE_AND_DATA, +- hmac_val2, +- nss_key_derivation_mech( +- hasher), CKA_DERIVE, +- 0); +- passert(tkey21 != NULL); +- +- PK11SymKey *tkey22 = PK11_Derive_lsw(tkey21, nss_key_derivation_mech( +- hasher), NULL, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, +- 0); +- passert(tkey22 != NULL); +- +- keyhandle = PK11_GetSymKeyHandle(tkey22); +- param.data = (unsigned char*)&keyhandle; +- param.len = sizeof(keyhandle); +- +- PK11SymKey *tkey23 = PK11_Derive_lsw(tkey8, +- CKM_CONCATENATE_BASE_AND_KEY, ¶m, +- nss_key_derivation_mech( +- hasher), CKA_DERIVE, +- 0); +- passert(tkey23 != NULL); +- +- DBG(DBG_CRYPT, DBG_log("NSS: enc keysize=%d", (int)keysize)); +- /* Deriving encryption key from SKEYID_e */ +- /* Oakley Keying Material +- * Derived from Skeyid_e: if it is not big enough, generate more +- * using the PRF. +- * See RFC 2409 "IKE" Appendix B +- */ +- +- CK_EXTRACT_PARAMS bitstart = 0; +- param1.data = (unsigned char*)&bitstart; +- param1.len = sizeof(bitstart); +- +- if (keysize <= hasher->hash_digest_len) { +- skeyid_e = PK11_Derive_lsw(tkey23, +- nss_key_derivation_mech(hasher), +- NULL, +- CKM_EXTRACT_KEY_FROM_KEY, /* note */ +- CKA_DERIVE, 0); +- passert(skeyid_e != NULL); +- /* nss_symkey_log(skeyid_e, "skeyid_e"); */ +- +- enc_key = PK11_DeriveWithFlags(skeyid_e, +- CKM_EXTRACT_KEY_FROM_KEY, ¶m1, +- nss_encryption_mech(encrypter), +- CKA_FLAGS_ONLY, keysize, +- CKF_ENCRYPT | CKF_DECRYPT); +- passert(enc_key != NULL); +- +- /* nss_symkey_log(enc_key, "enc_key"); */ +- } else { +- size_t i = 0; +- PK11SymKey *keymat; +- +- skeyid_e = PK11_Derive_lsw(tkey23, +- nss_key_derivation_mech(hasher), +- NULL, +- CKM_CONCATENATE_BASE_AND_DATA, /* note */ +- CKA_DERIVE, 0); +- passert(skeyid_e != NULL); +- /* nss_symkey_log(skeyid_e, "skeyid_e"); */ +- +- PK11SymKey *tkey25 = pk11_derive_wrapper_lsw(skeyid_e, +- CKM_CONCATENATE_BASE_AND_DATA, +- hmac_pad, CKM_XOR_BASE_AND_DATA, CKA_DERIVE, +- hasher->hash_block_size); +- passert(tkey25 != NULL); +- +- PK11SymKey *tkey26 = pk11_derive_wrapper_lsw(tkey25, +- CKM_XOR_BASE_AND_DATA, +- hmac_ipad, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, +- 0); +- passert(tkey26 != NULL); +- +- PK11SymKey *tkey27 = pk11_derive_wrapper_lsw(tkey26, +- CKM_CONCATENATE_BASE_AND_DATA, +- hmac_zerobyte, +- nss_key_derivation_mech( +- hasher), CKA_DERIVE, +- 0); +- passert(tkey27 != NULL); +- +- PK11SymKey *tkey28 = PK11_Derive_lsw(tkey27, nss_key_derivation_mech( +- hasher), NULL, +- CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, +- 0); +- passert(tkey28 != NULL); +- +- PK11SymKey *tkey29 = pk11_derive_wrapper_lsw(tkey25, +- CKM_XOR_BASE_AND_DATA, +- hmac_opad, CKM_CONCATENATE_BASE_AND_KEY, CKA_DERIVE, +- 0); +- passert(tkey29 != NULL); +- +- keyhandle = PK11_GetSymKeyHandle(tkey28); +- param.data = (unsigned char*)&keyhandle; +- param.len = sizeof(keyhandle); +- +- PK11SymKey *tkey30 = PK11_Derive_lsw(tkey29, +- CKM_CONCATENATE_BASE_AND_KEY, ¶m, +- nss_key_derivation_mech( +- hasher), CKA_DERIVE, +- 0); +- passert(tkey30 != NULL); +- +- PK11SymKey *tkey31 = PK11_Derive_lsw(tkey30, nss_key_derivation_mech( +- hasher), NULL, CKM_CONCATENATE_BASE_AND_KEY, CKA_DERIVE, +- 0); +- passert(tkey31 != NULL); +- +- keymat = tkey31; +- +- i += hasher->hash_digest_len; +- +- PK11SymKey *tkey32 = pk11_derive_wrapper_lsw(skeyid_e, +- CKM_CONCATENATE_BASE_AND_DATA, +- hmac_pad, CKM_XOR_BASE_AND_DATA, CKA_DERIVE, +- hasher->hash_block_size); +- passert(tkey32 != NULL); +- +- PK11SymKey *tkey33 = pk11_derive_wrapper_lsw(tkey32, +- CKM_XOR_BASE_AND_DATA, +- hmac_ipad, CKM_CONCATENATE_BASE_AND_KEY, CKA_DERIVE, +- 0); +- passert(tkey33 != NULL); +- +- PK11SymKey *tkey36 = pk11_derive_wrapper_lsw(tkey32, +- CKM_XOR_BASE_AND_DATA, +- hmac_opad, CKM_CONCATENATE_BASE_AND_KEY, CKA_DERIVE, +- 0); +- passert(tkey36 != NULL); +- +- for (;; ) { +- +- keyhandle = PK11_GetSymKeyHandle(tkey31); +- param.data = (unsigned char*)&keyhandle; +- param.len = sizeof(keyhandle); +- +- PK11SymKey *tkey34 = PK11_Derive_lsw(tkey33, +- CKM_CONCATENATE_BASE_AND_KEY, ¶m, +- nss_key_derivation_mech( +- hasher), CKA_DERIVE, +- 0); +- passert(tkey34 != NULL); +- +- PK11SymKey *tkey35 = PK11_Derive_lsw(tkey34, nss_key_derivation_mech( +- hasher), NULL, +- CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, +- 0); +- passert(tkey35 != NULL); +- +- keyhandle = PK11_GetSymKeyHandle(tkey35); +- param.data = (unsigned char*)&keyhandle; +- param.len = sizeof(keyhandle); +- +- PK11SymKey *tkey37 = PK11_Derive_lsw(tkey36, +- CKM_CONCATENATE_BASE_AND_KEY, ¶m, +- nss_key_derivation_mech( +- hasher), CKA_DERIVE, +- 0); +- passert(tkey37 != NULL); +- +- PK11SymKey *tkey38 = PK11_Derive_lsw(tkey37, nss_key_derivation_mech( +- hasher), NULL, CKM_CONCATENATE_BASE_AND_KEY, CKA_DERIVE, +- 0); +- passert(tkey38 != NULL); +- +- i += hasher->hash_digest_len; +- +- if (i >= keysize ) { +- +- /*concatenating K1 and K2 */ +- keyhandle = +- PK11_GetSymKeyHandle(tkey38); +- param.data = +- (unsigned char*)&keyhandle; +- param.len = sizeof(keyhandle); +- +- PK11SymKey *tkey39 = PK11_Derive_lsw( +- keymat, +- CKM_CONCATENATE_BASE_AND_KEY, +- ¶m, +- CKM_EXTRACT_KEY_FROM_KEY, +- CKA_DERIVE, 0); +- passert(tkey39 != NULL); +- +- enc_key = PK11_DeriveWithFlags(tkey39, +- CKM_EXTRACT_KEY_FROM_KEY, ¶m1, +- nss_encryption_mech(encrypter), +- CKA_FLAGS_ONLY, /*0*/ keysize, +- CKF_ENCRYPT | CKF_DECRYPT); +- +- /* nss_symkey_log(enc_key, "enc_key"); */ +- passert(enc_key != NULL); +- +- PK11_FreeSymKey(tkey25); +- PK11_FreeSymKey(tkey26); +- PK11_FreeSymKey(tkey27); +- PK11_FreeSymKey(tkey28); +- PK11_FreeSymKey(tkey29); +- PK11_FreeSymKey(tkey30); +- PK11_FreeSymKey(tkey31); +- PK11_FreeSymKey(tkey32); +- PK11_FreeSymKey(tkey33); +- PK11_FreeSymKey(tkey34); +- PK11_FreeSymKey(tkey35); +- PK11_FreeSymKey(tkey36); +- PK11_FreeSymKey(tkey37); +- PK11_FreeSymKey(tkey38); +- PK11_FreeSymKey(tkey39); +- PK11_FreeSymKey(keymat); +- +- DBG(DBG_CRYPT, +- DBG_log( +- "NSS: Freed 25-39 symkeys")); +- break; +- } else { +- +- keyhandle = +- PK11_GetSymKeyHandle(tkey38); +- param.data = +- (unsigned char*)&keyhandle; +- param.len = sizeof(keyhandle); +- +- PK11SymKey *tkey39 = PK11_Derive_lsw( +- keymat, +- CKM_CONCATENATE_BASE_AND_KEY, +- ¶m, +- CKM_CONCATENATE_BASE_AND_KEY, +- CKA_DERIVE, 0); +- passert(tkey39 != NULL); +- +- keymat = tkey39; +- PK11_FreeSymKey(tkey31); +- tkey31 = tkey38; +- PK11_FreeSymKey(tkey34); +- PK11_FreeSymKey(tkey35); +- PK11_FreeSymKey(tkey37); +- +- DBG(DBG_CRYPT, +- DBG_log( +- "NSS: Freed symkeys 31 34 35 37")); +- } +- } /*end for*/ +- } /*end else skeyid_e */ +- +- /*****End of SKEYID_e and encryption key derivation***************************************/ +- +- /********Saving pointers of all derived keys**********************************************/ +- *skeyid_out = skeyid; +- *skeyid_d_out = skeyid_d; +- *skeyid_a_out = skeyid_a; +- *skeyid_e_out = skeyid_e; +- *enc_key_out = enc_key; +- +- DBG(DBG_CRYPT, DBG_log("NSS: pointers skeyid_d %p, skeyid_a %p, skeyid_e %p, enc_key %p", +- skeyid_d, skeyid_a, skeyid_e, enc_key)); +- +- +- /*****Freeing tmp keys***************************************/ +- PK11_FreeSymKey(tkey1); +- PK11_FreeSymKey(tkey2); +- PK11_FreeSymKey(tkey3); +- PK11_FreeSymKey(tkey4); +- PK11_FreeSymKey(tkey5); +- PK11_FreeSymKey(tkey6); +- PK11_FreeSymKey(tkey7); +- PK11_FreeSymKey(tkey8); +- PK11_FreeSymKey(tkey9); +- PK11_FreeSymKey(tkey10); +- PK11_FreeSymKey(tkey11); +- PK11_FreeSymKey(tkey12); +- PK11_FreeSymKey(tkey13); +- PK11_FreeSymKey(tkey14); +- PK11_FreeSymKey(tkey15); +- PK11_FreeSymKey(tkey16); +- PK11_FreeSymKey(tkey17); +- PK11_FreeSymKey(tkey18); +- PK11_FreeSymKey(tkey19); +- PK11_FreeSymKey(tkey20); +- PK11_FreeSymKey(tkey21); +- PK11_FreeSymKey(tkey22); +- PK11_FreeSymKey(tkey23); +- +- DBG(DBG_CRYPT, DBG_log("NSS: Freed symkeys 1-23")); +- +- freeanychunk(hmac_opad); +- freeanychunk(hmac_ipad); +- freeanychunk(hmac_pad); +- freeanychunk(hmac_zerobyte); +- freeanychunk(hmac_val1); +- freeanychunk(hmac_val2); +- DBG(DBG_CRYPT, DBG_log("NSS: Freed padding chunks")); +- } +- +- /* generate IV */ +- { +- union hash_ctx hash_ctx; +- +- new_iv->len = hasher->hash_digest_len; +- new_iv->ptr = alloc_bytes(new_iv->len, "calculated new iv"); +- +- DBG(DBG_CRYPT, { +- DBG_dump_chunk("DH_i:", gi); +- DBG_dump_chunk("DH_r:", gr); +- }); +- hasher->hash_init(&hash_ctx); +- hasher->hash_update(&hash_ctx, gi.ptr, gi.len); +- hasher->hash_update(&hash_ctx, gr.ptr, gr.len); +- hasher->hash_final(new_iv->ptr, &hash_ctx); +- DBG(DBG_CRYPT, DBG_log("end of IV generation")); +- } +-} +- +-/* MUST BE THREAD-SAFE */ +-void calc_dh_iv(struct pluto_crypto_req *r) +-{ +- struct pcr_skeyid_r *skr = &r->pcr_d.dhr; +- struct pcr_skeyid_q dhq; +- const struct oakley_group_desc *group; +- PK11SymKey *shared; +- chunk_t g; +- SECKEYPrivateKey *ltsecret; +- PK11SymKey +- *skeyid, +- *skeyid_d, +- *skeyid_a, +- *skeyid_e, +- *enc_key; +- chunk_t new_iv; +- SECKEYPublicKey *pubk; +- +- /* copy the request, since the reply will re-use the memory of the r->pcr_d.dhq */ +- memcpy(&dhq, &r->pcr_d.dhq, sizeof(r->pcr_d.dhq)); +- +- /* clear out the reply */ +- zero(skr); +- INIT_WIRE_ARENA(*skr); +- +- group = lookup_group(dhq.oakley_group); +- passert(group != NULL); +- +- ltsecret = dhq.secret; +- pubk = dhq.pubk; +- +- /* now calculate the (g^x)(g^y) --- +- * need gi on responder, gr on initiator +- */ +- +- setchunk_from_wire(g, &dhq, dhq.role == O_RESPONDER ? &dhq.gi : &dhq.gr); +- +- DBG(DBG_CRYPT, +- DBG_dump_chunk("peer's g: ", g)); +- +- shared = calc_dh_shared(g, ltsecret, group, pubk); +- +- zero(&new_iv); +- +- /* okay, so now calculate IV */ +- calc_skeyids_iv(&dhq, +- shared, +- dhq.key_size, +- &skeyid, +- &skeyid_d, +- &skeyid_a, +- &skeyid_e, +- &new_iv, +- &enc_key); +- +- skr->shared = shared; +- skr->skeyid = skeyid; +- skr->skeyid_d = skeyid_d; +- skr->skeyid_a = skeyid_a; +- skr->skeyid_e = skeyid_e; +- skr->enc_key = enc_key; +- +- +- WIRE_CLONE_CHUNK(*skr, new_iv, new_iv); +- freeanychunk(new_iv); +-} + + /* MUST BE THREAD-SAFE */ + void calc_dh(struct pluto_crypto_req *r) +@@ -1128,496 +202,3 @@ + + skr->shared = calc_dh_shared(g, ltsecret, group, pubk); + } +- +-static chunk_t chunk_from_symkey(const char *name, PK11SymKey *source_key, +- size_t next_bit, size_t byte_size) +-{ +- if (byte_size == 0) { +- DBG(DBG_CRYPT, DBG_log("chunk_from_symkey: %s: zero size", name)); +- return empty_chunk; +- } +- CK_EXTRACT_PARAMS bs = next_bit; +- SECItem param = { .data = (unsigned char*)&bs, .len = sizeof(bs) }; +- PK11SymKey *sym_key = PK11_DeriveWithFlags(source_key, +- CKM_EXTRACT_KEY_FROM_KEY, +- ¶m, +- CKM_VENDOR_DEFINED, +- CKA_FLAGS_ONLY, byte_size, 0); +- if (sym_key == NULL) { +- loglog(RC_LOG_SERIOUS, "NSS: PK11_DeriveWithFlags failed while generating %s", name); +- return empty_chunk; +- } +- SECStatus s = PK11_ExtractKeyValue(sym_key); +- if (s != SECSuccess) { +- loglog(RC_LOG_SERIOUS, "NSS: PK11_ExtractKeyValue failed while generating %s", name); +- return empty_chunk; +- } +- /* Internal structure address, do not free. */ +- SECItem *data = PK11_GetKeyData(sym_key); +- if (data == NULL) { +- loglog(RC_LOG_SERIOUS, "NSS: PK11_GetKeyData failed while generating %s", name); +- return empty_chunk; +- } +- DBG(DBG_CRYPT, +- DBG_log("chunk_from_symkey: %s: extracted len %d bytes at %p", +- name, data->len, data->data)); +- if (data->len != byte_size) { +- loglog(RC_LOG_SERIOUS, "NSS: PK11_GetKeyData returned wrong number of bytes while generating %s", name); +- return empty_chunk; +- } +- chunk_t chunk; +- clonetochunk(chunk, data->data, data->len, name); +- DBG(DBG_CRYPT, DBG_dump_chunk(name, chunk)); +- PK11_FreeSymKey(sym_key); +- return chunk; +-} +- +-/* +- * IKEv2 - RFC4306 2.14 SKEYSEED - calculation. +- */ +- +-/* MUST BE THREAD-SAFE */ +-static void calc_skeyseed_v2(struct pcr_skeyid_q *skq, +- PK11SymKey *shared, +- const size_t key_size, +- const size_t salt_size, +- PK11SymKey **skeyseed_out, +- PK11SymKey **SK_d_out, +- PK11SymKey **SK_ai_out, +- PK11SymKey **SK_ar_out, +- PK11SymKey **SK_ei_out, +- PK11SymKey **SK_er_out, +- PK11SymKey **SK_pi_out, +- PK11SymKey **SK_pr_out, +- chunk_t *initiator_salt_out, +- chunk_t *responder_salt_out +- ) +-{ +- struct v2prf_stuff vpss; +- +- chunk_t hmac_opad, hmac_ipad, hmac_pad_prf; +- /* chunk_t hmac_pad_integ, hmac_zerobyte, hmac_val1, hmac_val2; */ +- +- CK_OBJECT_HANDLE keyhandle; +- SECItem param, param1; +- DBG(DBG_CRYPT, DBG_log("NSS: Started key computation")); +- +- PK11SymKey +- *skeyseed_k, +- *SK_d_k, +- *SK_ai_k, +- *SK_ar_k, +- *SK_ei_k, +- *SK_er_k, +- *SK_pi_k, +- *SK_pr_k; +- chunk_t initiator_salt; +- chunk_t responder_salt; +- +- zero(&vpss); +- +- /* this doesn't take any memory, it's just moving pointers around */ +- setchunk_from_wire(vpss.ni, skq, &skq->ni); +- setchunk_from_wire(vpss.nr, skq, &skq->nr); +- setchunk_from_wire(vpss.spii, skq, &skq->icookie); +- setchunk_from_wire(vpss.spir, skq, &skq->rcookie); +- +- DBG(DBG_CONTROLMORE, +- DBG_log("calculating skeyseed using prf=%s integ=%s cipherkey-size=%zu salt-size=%zu", +- enum_name(&ikev2_trans_type_prf_names, skq->prf_hash), +- enum_name(&ikev2_trans_type_integ_names, skq->integ_hash), +- key_size, salt_size)); +- +- const struct hash_desc *prf_hasher = (struct hash_desc *) +- ikev2_alg_find(IKE_ALG_HASH, skq->prf_hash); +- passert(prf_hasher != NULL); +- +- const struct encrypt_desc *encrypter = skq->encrypter; +- passert(encrypter != NULL); +- +- hmac_opad = hmac_pads(HMAC_OPAD, prf_hasher->hash_block_size); +- hmac_ipad = hmac_pads(HMAC_IPAD, prf_hasher->hash_block_size); +- hmac_pad_prf = hmac_pads(0x00, +- prf_hasher->hash_block_size - +- prf_hasher->hash_digest_len); +- +- /* generate SKEYSEED from key=(Ni|Nr), hash of shared */ +- skeyseed_k = skeyid_digisig(vpss.ni, vpss.nr, shared, prf_hasher); +- passert(skeyseed_k != NULL); +- +- /* now we have to generate the keys for everything */ +- { +- /* need to know how many bits to generate */ +- /* SK_d needs PRF hasher key bytes */ +- /* SK_p needs PRF hasher*2 key bytes */ +- /* SK_e needs key_size*2 key bytes */ +- /* ..._salt needs salt_size*2 bytes */ +- /* SK_a needs integ's key size*2 bytes */ +- +- int skd_bytes = prf_hasher->hash_key_size; +- int skp_bytes = prf_hasher->hash_key_size; +- const struct hash_desc *integ_hasher = +- (struct hash_desc *)ikev2_alg_find(IKE_ALG_INTEG, skq->integ_hash); +- int integ_size = integ_hasher != NULL ? integ_hasher->hash_key_size : 0; +- size_t total_keysize = skd_bytes + 2*skp_bytes + 2*key_size + 2*salt_size + 2*integ_size; +- DBG(DBG_CRYPT, +- DBG_log("calc_skeyseed_v2: %zd = %d(d) + 2*%d(p) + 2*%zd(key) + 2*%zd(salt) + 2*%d(integ) bytes", +- total_keysize, skd_bytes, skp_bytes, key_size, salt_size, integ_size)); +- vpss.counter[0] = 0x01; +- vpss.t.len = 0; +- +- DBG(DBG_CRYPT, { +- DBG_log("PRF+ input"); +- DBG_dump_chunk("Ni", vpss.ni); +- DBG_dump_chunk("Nr", vpss.nr); +- DBG_dump_chunk("SPIi", vpss.spii); +- DBG_dump_chunk("SPIr", vpss.spir); +- DBG_log("Total keysize needed %zd", +- total_keysize); +- }); +- +- PK11SymKey *finalkey = NULL; +- PK11SymKey *tkey11 = NULL; +- PK11SymKey *tkey1 = pk11_derive_wrapper_lsw(skeyseed_k, +- CKM_CONCATENATE_BASE_AND_DATA, +- hmac_pad_prf, CKM_XOR_BASE_AND_DATA, CKA_DERIVE, +- prf_hasher->hash_block_size); +- passert(tkey1 != NULL); +- +- for (;; ) { +- PK11SymKey *tkey3 = NULL; +- +- if (vpss.counter[0] == 0x01) { +- PK11SymKey *tkey2 = pk11_derive_wrapper_lsw( +- tkey1, CKM_XOR_BASE_AND_DATA, +- hmac_ipad, +- CKM_CONCATENATE_BASE_AND_DATA, +- CKA_DERIVE, +- 0); +- passert(tkey2 != NULL); +- +- tkey3 = pk11_derive_wrapper_lsw(tkey2, +- CKM_CONCATENATE_BASE_AND_DATA, +- vpss.ni, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, +- 0); +- PK11_FreeSymKey(tkey2); +- } else { +- PK11SymKey *tkey2 = pk11_derive_wrapper_lsw( +- tkey1, CKM_XOR_BASE_AND_DATA, +- hmac_ipad, +- CKM_CONCATENATE_BASE_AND_KEY, +- CKA_DERIVE, +- 0); +- passert(tkey2 != NULL); +- +- keyhandle = PK11_GetSymKeyHandle(tkey11); +- param.data = (unsigned char*)&keyhandle; +- param.len = sizeof(keyhandle); +- +- PK11SymKey *tkey12 = PK11_Derive_lsw(tkey2, +- CKM_CONCATENATE_BASE_AND_KEY, +- ¶m, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, +- 0); +- passert(tkey12 != NULL); +- +- tkey3 = pk11_derive_wrapper_lsw(tkey12, +- CKM_CONCATENATE_BASE_AND_DATA, +- vpss.ni, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, +- 0); +- PK11_FreeSymKey(tkey2); +- PK11_FreeSymKey(tkey11); +- PK11_FreeSymKey(tkey12); +- } +- +- passert(tkey3 != NULL); +- +- PK11SymKey *tkey4 = pk11_derive_wrapper_lsw(tkey3, +- CKM_CONCATENATE_BASE_AND_DATA, +- vpss.nr, +- CKM_CONCATENATE_BASE_AND_DATA, +- CKA_DERIVE, +- 0); +- passert(tkey4 != NULL); +- +- PK11SymKey *tkey5 = pk11_derive_wrapper_lsw(tkey4, +- CKM_CONCATENATE_BASE_AND_DATA, +- vpss.spii, +- CKM_CONCATENATE_BASE_AND_DATA, +- CKA_DERIVE, +- 0); +- passert(tkey5 != NULL); +- +- PK11SymKey *tkey6 = pk11_derive_wrapper_lsw(tkey5, +- CKM_CONCATENATE_BASE_AND_DATA, +- vpss.spir, +- CKM_CONCATENATE_BASE_AND_DATA, +- CKA_DERIVE, +- 0); +- passert(tkey6 != NULL); +- +- chunk_t counter; +- +- setchunk(counter, &vpss.counter[0], sizeof(vpss.counter[0])); +- PK11SymKey *tkey7 = pk11_derive_wrapper_lsw(tkey6, +- CKM_CONCATENATE_BASE_AND_DATA, +- counter, +- nss_key_derivation_mech(prf_hasher), +- CKA_DERIVE, +- 0); +- passert(tkey7 != NULL); +- +- PK11SymKey *tkey8 = PK11_Derive_lsw(tkey7, +- nss_key_derivation_mech(prf_hasher), +- NULL, +- CKM_CONCATENATE_BASE_AND_DATA, +- CKA_DERIVE, +- 0); +- passert(tkey8 != NULL); +- +- PK11SymKey *tkey9 = pk11_derive_wrapper_lsw(tkey1, +- CKM_XOR_BASE_AND_DATA, +- hmac_opad, +- CKM_CONCATENATE_BASE_AND_KEY, +- CKA_DERIVE, +- 0); +- passert(tkey9 != NULL); +- +- keyhandle = PK11_GetSymKeyHandle(tkey8); +- param.data = (unsigned char*)&keyhandle; +- param.len = sizeof(keyhandle); +- +- PK11SymKey *tkey10 = PK11_Derive_lsw(tkey9, +- CKM_CONCATENATE_BASE_AND_KEY, +- ¶m, +- nss_key_derivation_mech(prf_hasher), +- CKA_DERIVE, +- 0); +- passert(tkey10 != NULL); +- +- if (vpss.counter[0] == 0x01) { +- finalkey = PK11_Derive_lsw(tkey10, +- nss_key_derivation_mech(prf_hasher), +- NULL, +- CKM_CONCATENATE_BASE_AND_KEY, +- CKA_DERIVE, +- 0); +- passert(finalkey != NULL); +- +- tkey11 = PK11_Derive_lsw(tkey10, +- nss_key_derivation_mech(prf_hasher), +- NULL, +- CKM_CONCATENATE_BASE_AND_KEY, +- CKA_DERIVE, +- 0); +- passert(tkey11 != NULL); +- } else { +- tkey11 = PK11_Derive_lsw(tkey10, +- nss_key_derivation_mech(prf_hasher), +- NULL, +- CKM_EXTRACT_KEY_FROM_KEY, +- CKA_DERIVE, +- 0); +- passert(tkey11 != NULL); +- +- keyhandle = PK11_GetSymKeyHandle(tkey11); +- param.data = (unsigned char*)&keyhandle; +- param.len = sizeof(keyhandle); +- +- if ( total_keysize <= +- (PK11_GetKeyLength(finalkey) + +- PK11_GetKeyLength(tkey11)) ) { +- finalkey = PK11_Derive_lsw(finalkey, +- CKM_CONCATENATE_BASE_AND_KEY, +- ¶m, +- CKM_EXTRACT_KEY_FROM_KEY, +- CKA_DERIVE, +- 0); +- passert(finalkey != NULL); +- } else { +- finalkey = PK11_Derive_lsw(finalkey, +- CKM_CONCATENATE_BASE_AND_KEY, +- ¶m, +- CKM_CONCATENATE_BASE_AND_KEY, +- CKA_DERIVE, +- 0); +- passert(finalkey != NULL); +- } +- } +- +- PK11_FreeSymKey(tkey3); +- PK11_FreeSymKey(tkey4); +- PK11_FreeSymKey(tkey5); +- PK11_FreeSymKey(tkey6); +- PK11_FreeSymKey(tkey7); +- PK11_FreeSymKey(tkey8); +- PK11_FreeSymKey(tkey9); +- PK11_FreeSymKey(tkey10); +- +- if (total_keysize <= PK11_GetKeyLength(finalkey)) { +- PK11_FreeSymKey(tkey1); +- PK11_FreeSymKey(tkey11); +- break; +- } +- +- vpss.counter[0]++; +- } +- +- DBG(DBG_CRYPT, +- DBG_log("NSS ikev2: finished computing key material for IKEv2 SA")); +- +- CK_EXTRACT_PARAMS bs = 0; +- size_t next_bit = 0; +- +- SK_d_k = pk11_extract_derive_wrapper_lsw(finalkey, next_bit, +- CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, +- skd_bytes); +- next_bit += skd_bytes * BITS_PER_BYTE; +- +- SK_ai_k = pk11_extract_derive_wrapper_lsw(finalkey, next_bit, +- CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, +- integ_size); +- next_bit += integ_size * BITS_PER_BYTE; +- +- SK_ar_k = pk11_extract_derive_wrapper_lsw(finalkey, next_bit, +- CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, +- integ_size); +- next_bit += integ_size * BITS_PER_BYTE; +- +- bs = next_bit; +- param1.data = (unsigned char*)&bs; +- param1.len = sizeof(bs); +- SK_ei_k = PK11_DeriveWithFlags(finalkey, +- CKM_EXTRACT_KEY_FROM_KEY, +- ¶m1, +- nss_encryption_mech(encrypter), +- CKA_FLAGS_ONLY, key_size, +- CKF_ENCRYPT | CKF_DECRYPT); +- next_bit += key_size * BITS_PER_BYTE; +- +- initiator_salt = chunk_from_symkey("initiator salt", finalkey, +- next_bit, salt_size); +- next_bit += salt_size * BITS_PER_BYTE; +- +- bs = next_bit; +- param1.data = (unsigned char*)&bs; +- param1.len = sizeof(bs); +- SK_er_k = PK11_DeriveWithFlags(finalkey, +- CKM_EXTRACT_KEY_FROM_KEY, +- ¶m1, +- nss_encryption_mech(encrypter), +- CKA_FLAGS_ONLY, key_size, +- CKF_ENCRYPT | CKF_DECRYPT); +- next_bit += key_size * BITS_PER_BYTE; +- +- responder_salt = chunk_from_symkey("responder salt", finalkey, +- next_bit, salt_size); +- next_bit += salt_size * BITS_PER_BYTE; +- +- SK_pi_k = pk11_extract_derive_wrapper_lsw(finalkey, next_bit, +- CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, +- skp_bytes); +- next_bit += skp_bytes * BITS_PER_BYTE; +- +- SK_pr_k = pk11_extract_derive_wrapper_lsw(finalkey, next_bit, +- CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, +- skp_bytes); +- next_bit += skp_bytes * BITS_PER_BYTE; +- +- DBG(DBG_CRYPT, +- DBG_log("NSS ikev2: finished computing individual keys for IKEv2 SA")); +- PK11_FreeSymKey(finalkey); +- +- *skeyseed_out = skeyseed_k; +- *SK_d_out = SK_d_k; +- *SK_ai_out = SK_ai_k; +- *SK_ar_out = SK_ar_k; +- *SK_ei_out = SK_ei_k; +- *SK_er_out = SK_er_k; +- *SK_pi_out = SK_pi_k; +- *SK_pr_out = SK_pr_k; +- *initiator_salt_out = initiator_salt; +- *responder_salt_out = responder_salt; +- +- freeanychunk(hmac_opad); +- freeanychunk(hmac_ipad); +- freeanychunk(hmac_pad_prf); +- } +- DBG(DBG_CRYPT, +- DBG_log("calc_skeyseed_v2 pointers: shared %p, skeyseed %p, SK_d %p, SK_ai %p, SK_ar %p, SK_ei %p, SK_er %p, SK_pi %p, SK_pr %p", +- shared, skeyseed_k, SK_d_k, SK_ai_k, SK_ar_k, SK_ei_k, SK_er_k, SK_pi_k, SK_pr_k); +- DBG_dump_chunk("calc_skeyseed_v2 initiator salt", initiator_salt); +- DBG_dump_chunk("calc_skeyseed_v2 responder salt", responder_salt)); +-} +- +-/* MUST BE THREAD-SAFE */ +-void calc_dh_v2(struct pluto_crypto_req *r) +-{ +- struct pcr_skeycalc_v2_r *skr = &r->pcr_d.dhv2; +- struct pcr_skeyid_q dhq; +- const struct oakley_group_desc *group; +- PK11SymKey *shared; +- chunk_t g; +- SECKEYPrivateKey *ltsecret; +- PK11SymKey *skeyseed; +- PK11SymKey +- *SK_d, +- *SK_ai, +- *SK_ar, +- *SK_ei, +- *SK_er, +- *SK_pi, +- *SK_pr; +- chunk_t initiator_salt; +- chunk_t responder_salt; +- SECKEYPublicKey *pubk; +- +- /* copy the request, since the reply will re-use the memory of the r->pcr_d.dhq */ +- memcpy(&dhq, &r->pcr_d.dhq, sizeof(r->pcr_d.dhq)); +- +- /* clear out the reply */ +- zero(skr); +- INIT_WIRE_ARENA(*skr); +- +- group = lookup_group(dhq.oakley_group); +- passert(group != NULL); +- +- ltsecret = dhq.secret; +- pubk = dhq.pubk; +- +- /* now calculate the (g^x)(g^y) --- need gi on responder, gr on initiator */ +- +- setchunk_from_wire(g, &dhq, dhq.role == O_RESPONDER ? &dhq.gi : &dhq.gr); +- +- DBG(DBG_CRYPT, DBG_dump_chunk("peer's g: ", g)); +- +- shared = calc_dh_shared(g, ltsecret, group, pubk); +- +- /* okay, so now all the shared key material */ +- calc_skeyseed_v2(&dhq, /* input */ +- shared, /* input */ +- dhq.key_size, /* input */ +- dhq.salt_size, /* input */ +- +- &skeyseed, /* output */ +- &SK_d, /* output */ +- &SK_ai, /* output */ +- &SK_ar, /* output */ +- &SK_ei, /* output */ +- &SK_er, /* output */ +- &SK_pi, /* output */ +- &SK_pr, /* output */ +- &initiator_salt, /* output */ +- &responder_salt); /* output */ +- +- skr->shared = shared; +- skr->skeyseed = skeyseed; +- skr->skeyid_d = SK_d; +- skr->skeyid_ai = SK_ai; +- skr->skeyid_ar = SK_ar; +- skr->skeyid_ei = SK_ei; +- skr->skeyid_er = SK_er; +- skr->skeyid_pi = SK_pi; +- skr->skeyid_pr = SK_pr; +- skr->skey_initiator_salt = initiator_salt; +- skr->skey_responder_salt = responder_salt; +-} +diff -Naur libreswan-3.12-orig/programs/pluto/crypt_dh.h libreswan-3.12/programs/pluto/crypt_dh.h +--- libreswan-3.12-orig/programs/pluto/crypt_dh.h 1969-12-31 19:00:00.000000000 -0500 ++++ libreswan-3.12/programs/pluto/crypt_dh.h 2015-05-06 11:45:32.918301394 -0400 +@@ -0,0 +1,46 @@ ++/* ++ * DH crypto functions, for libreswan ++ * ++ * Copyright (C) 2007-2008 Michael C. Richardson ++ * Copyright (C) 2008 Antony Antony ++ * Copyright (C) 2009 David McCullough ++ * Copyright (C) 2009-2012 Avesh Agarwal ++ * Copyright (C) 2009-2010 Paul Wouters ++ * Copyright (C) 2010 Tuomo Soini ++ * Copyright (C) 2012-2013 Paul Wouters ++ * Copyright (C) 2012 Wes Hardaker ++ * Copyright (C) 2013 Antony Antony ++ * Copyright (C) 2013 D. Hugh Redelmeier ++ * Copyright (C) 2015 Paul Wouters ++ * Copyright (C) 2015 Andrew Cagney ++ * ++ * 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. See . ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ */ ++ ++#ifndef crypt_dh_h ++#define crypt_dh_h ++ ++#include ++#include "lswalloc.h" ++ ++struct oakley_group_desc; ++ ++PK11SymKey *calc_dh_shared(chunk_t g, /* converted to SECItem */ ++ /*const*/ SECKEYPrivateKey *privk, /* NSS doesn't do const */ ++ const struct oakley_group_desc *group, ++ const SECKEYPublicKey *local_pubk); ++ ++ ++struct pluto_crypto_req; ++ ++void calc_dh(struct pluto_crypto_req *r); ++ ++#endif +diff -Naur libreswan-3.12-orig/programs/pluto/crypto.h libreswan-3.12/programs/pluto/crypto.h +--- libreswan-3.12-orig/programs/pluto/crypto.h 2014-11-06 22:52:50.000000000 -0500 ++++ libreswan-3.12/programs/pluto/crypto.h 2015-05-06 11:45:32.918301394 -0400 +@@ -127,24 +127,14 @@ + aes_xcbc_context ctx_aes_xcbc; + }; + +-/* HMAC package +- * Note that hmac_ctx can be (and is) copied since there are +- * no persistent pointers into it. ++/* ++ * HMAC package (new code should use crypt_prf). + */ + ++struct crypt_prf; + struct hmac_ctx { +- const struct hash_desc *h; /* underlying hash function */ +- size_t hmac_digest_len; /* copy of h->hash_digest_len */ +- union hash_ctx hash_ctx; /* ctx for hash function */ +- u_char buf1[HMAC_BUFSIZE], buf2[HMAC_BUFSIZE]; +-#ifdef USE_SHA2 +- sha256_context ctx_sha256; +- sha512_context ctx_sha512; +-#endif +- aes_xcbc_context ctx_aes_xcbc; +- +- PK11SymKey *ikey, *okey; +- PK11Context *ctx_nss; ++ struct crypt_prf *prf; ++ size_t hmac_digest_len; + }; + + extern void hmac_init(struct hmac_ctx *ctx, +@@ -167,18 +157,7 @@ + } + + extern CK_MECHANISM_TYPE nss_key_derivation_mech(const struct hash_desc *hasher); +-extern void nss_symkey_log(PK11SymKey *key, const char *msg); + extern chunk_t hmac_pads(u_char val, unsigned int len); +-extern PK11SymKey *pk11_derive_wrapper_lsw(PK11SymKey *base, +- CK_MECHANISM_TYPE mechanism, +- chunk_t data, +- CK_MECHANISM_TYPE target, +- CK_ATTRIBUTE_TYPE operation, +- int keySize); +-extern PK11SymKey *PK11_Derive_lsw(PK11SymKey *base, +- CK_MECHANISM_TYPE mechanism, +- SECItem *param, CK_MECHANISM_TYPE target, +- CK_ATTRIBUTE_TYPE operation, int keySize); + + enum crk_proto { + CRK_ESPorAH, +diff -Naur libreswan-3.12-orig/programs/pluto/crypt_prf.c libreswan-3.12/programs/pluto/crypt_prf.c +--- libreswan-3.12-orig/programs/pluto/crypt_prf.c 1969-12-31 19:00:00.000000000 -0500 ++++ libreswan-3.12/programs/pluto/crypt_prf.c 2015-05-06 11:45:32.919301405 -0400 +@@ -0,0 +1,203 @@ ++/* ++ * PRF helper functions, for libreswan ++ * ++ * Copyright (C) 2007-2008 Michael C. Richardson ++ * Copyright (C) 2008 Antony Antony ++ * Copyright (C) 2009 David McCullough ++ * Copyright (C) 2009-2012 Avesh Agarwal ++ * Copyright (C) 2009-2010 Paul Wouters ++ * Copyright (C) 2010 Tuomo Soini ++ * Copyright (C) 2012-2013 Paul Wouters ++ * Copyright (C) 2012 Wes Hardaker ++ * Copyright (C) 2013 Antony Antony ++ * Copyright (C) 2013 D. Hugh Redelmeier ++ * Copyright (C) 2015 Paul Wouters ++ * Copyright (C) 2015 Andrew Cagney ++ * ++ * 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. See . ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ */ ++ ++#include ++ ++//#include "libreswan.h" ++#include "lswalloc.h" ++#include "lswlog.h" ++#include "ike_alg.h" ++#include "crypt_prf.h" ++#include "crypt_symkey.h" ++#include "crypto.h" ++ ++struct crypt_prf { ++ const char *name; ++ const struct hash_desc *hasher; ++ /* for converting chunks to symkeys */ ++ PK11SymKey *scratch; ++ /* Did we allocate KEY? */ ++ bool we_own_key; ++ /* intermediate values */ ++ PK11SymKey *key; ++ PK11SymKey *inner; ++}; ++ ++/* ++ * During the init phase, accumulate the key material in KEY. ++ */ ++struct crypt_prf *crypt_prf_init(const char *name, const struct hash_desc *hasher, ++ PK11SymKey *scratch) ++{ ++ struct crypt_prf *prf = alloc_bytes(sizeof(struct crypt_prf), name); ++ DBG(DBG_CRYPT, DBG_log("%s prf: init %p", name, prf)); ++ prf->name = name; ++ prf->hasher = hasher; ++ prf->scratch = scratch; ++ prf->we_own_key = FALSE; ++ prf->key = NULL; ++ prf->inner = NULL; ++ return prf; ++} ++ ++/* ++ * Update KEY marking it as ours. Only call with a KEY we created. ++ */ ++static void update_key(struct crypt_prf *prf, PK11SymKey *key) ++{ ++ if (prf->we_own_key) { ++ free_any_symkey(__func__, &prf->key); ++ } ++ prf->we_own_key = TRUE; ++ prf->key = key; ++} ++ ++void crypt_prf_init_symkey(const char *name, struct crypt_prf *prf, PK11SymKey *key) ++{ ++ DBG(DBG_CRYPT, DBG_log("%s prf: init symkey %s %p (length %d)", ++ prf->name, name, key, PK11_GetKeyLength(key))); ++ if (prf->key == NULL) { ++ prf->we_own_key = FALSE; ++ prf->key = key; ++ } else { ++ update_key(prf, concat_symkey_symkey(prf->hasher, prf->key, key)); ++ } ++} ++ ++void crypt_prf_init_chunk(const char *name, struct crypt_prf *prf, chunk_t key) ++{ ++ DBG(DBG_CRYPT, DBG_log("%s prf: init chunk %s %p (length %zd)", ++ prf->name, name, key.ptr, key.len)); ++ if (prf->key == NULL) { ++ prf->key = symkey_from_chunk(prf->scratch, key); ++ prf->we_own_key = TRUE; ++ } else { ++ update_key(prf, concat_symkey_chunk(prf->hasher, prf->key, key)); ++ } ++} ++ ++/* ++ * Prepare for update phase (accumulate seed material). ++ */ ++void crypt_prf_update(struct crypt_prf *prf) ++{ ++ DBG(DBG_CRYPT, DBG_log("%s prf: update", prf->name)); ++ /* create the prf key from KEY. */ ++ passert(prf->key != NULL); ++ /* If the key is too big, re-hash it down to size. */ ++ if (PK11_GetKeyLength(prf->key) > prf->hasher->hash_block_size) { ++ update_key(prf, hash_symkey(prf->hasher, prf->key)); ++ } ++ /* If the key is too small, pad it. */ ++ if (PK11_GetKeyLength(prf->key) < prf->hasher->hash_block_size) { ++ /* pad it to block_size. */ ++ chunk_t hmac_pad_prf = hmac_pads(0x00, ++ (prf->hasher->hash_block_size - ++ PK11_GetKeyLength(prf->key))); ++ update_key(prf, concat_symkey_chunk(prf->hasher, prf->key, ++ hmac_pad_prf)); ++ freeanychunk(hmac_pad_prf); ++ } ++ passert(prf->key != NULL); ++ ++ /* Start forming the inner hash input: (key^IPAD)|... */ ++ passert(prf->inner == NULL); ++ chunk_t hmac_ipad = hmac_pads(HMAC_IPAD, prf->hasher->hash_block_size); ++ prf->inner = xor_symkey_chunk(prf->key, hmac_ipad); ++ freeanychunk(hmac_ipad); ++} ++ ++void crypt_prf_update_chunk(const char *name, struct crypt_prf *prf, ++ chunk_t update) ++{ ++ DBG(DBG_CRYPT, DBG_log("%s prf: update chunk %s %p (length %zd)", ++ prf->name, name, update.ptr, update.len)); ++ append_symkey_chunk(prf->hasher, &(prf->inner), update); ++} ++ ++void crypt_prf_update_symkey(const char *name, struct crypt_prf *prf, ++ PK11SymKey *update) ++{ ++ DBG(DBG_CRYPT, DBG_log("%s prf: update symkey %s %p (length %d)", ++ prf->name, name, update, ++ PK11_GetKeyLength(update))); ++ append_symkey_symkey(prf->hasher, &(prf->inner), update); ++} ++ ++void crypt_prf_update_byte(const char *name, struct crypt_prf *prf, ++ uint8_t update) ++{ ++ DBG(DBG_CRYPT, DBG_log("%s prf: update byte %s", prf->name, name)); ++ append_symkey_byte(prf->hasher, &(prf->inner), update); ++} ++ ++void crypt_prf_update_bytes(const char *name, struct crypt_prf *prf, ++ const void *update, size_t sizeof_update) ++{ ++ DBG(DBG_CRYPT, DBG_log("%s prf: update bytes %s %p (length %zd)", ++ prf->name, name, update, sizeof_update)); ++ append_symkey_bytes(prf->hasher, &(prf->inner), update, sizeof_update); ++} ++ ++PK11SymKey *crypt_prf_final(struct crypt_prf *prf) ++{ ++ DBG(DBG_CRYPT, DBG_log("%s prf: final", prf->name)); ++ passert(prf->inner != NULL); ++ /* run that through hasher */ ++ PK11SymKey *hashed_inner = hash_symkey(prf->hasher, prf->inner); ++ free_any_symkey("prf inner", &prf->inner); ++ ++ /* Input to outer hash: (key^OPAD)|hashed_inner. */ ++ chunk_t hmac_opad = hmac_pads(HMAC_OPAD, prf->hasher->hash_block_size); ++ PK11SymKey *outer = xor_symkey_chunk(prf->key, hmac_opad); ++ freeanychunk(hmac_opad); ++ append_symkey_symkey(prf->hasher, &outer, hashed_inner); ++ free_any_symkey("prf hashed inner", &hashed_inner); ++ ++ /* Finally hash that */ ++ PK11SymKey *hashed_outer = hash_symkey(prf->hasher, outer); ++ free_any_symkey("prf outer", &outer); ++ ++ if (prf->we_own_key) { ++ free_any_symkey("prf key", &prf->key); ++ } ++ prf->key = NULL; /* help debug */ ++ pfree(prf); ++ ++ DBG(DBG_CRYPT, DBG_dump_symkey("prf result", hashed_outer)); ++ return hashed_outer; ++} ++ ++void crypt_prf_final_bytes(struct crypt_prf *prf, ++ void *bytes, size_t sizeof_bytes) ++{ ++ const char *name = prf->name; ++ PK11SymKey *result = crypt_prf_final(prf); ++ prf = NULL; /* no longer valid */ ++ bytes_from_symkey_bytes(name, result, 0, bytes, sizeof_bytes); ++ free_any_symkey(__func__, &result); ++} +diff -Naur libreswan-3.12-orig/programs/pluto/crypt_prf.h libreswan-3.12/programs/pluto/crypt_prf.h +--- libreswan-3.12-orig/programs/pluto/crypt_prf.h 1969-12-31 19:00:00.000000000 -0500 ++++ libreswan-3.12/programs/pluto/crypt_prf.h 2015-05-06 11:45:32.919301405 -0400 +@@ -0,0 +1,86 @@ ++/* ++ * prf and keying material helper functions, for libreswan ++ * ++ * Copyright (C) 2007 Michael C. Richardson ++ * Copyright (C) 2010 Paul Wouters ++ * Copyright (C) 2013 D. Hugh Redelmeier ++ * Copyright (C) 2015 Andrew Cagney ++ * ++ * 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. See . ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ */ ++ ++#ifndef crypt_prf_h ++#define crypt_prf_h ++ ++#include ++ ++struct hash_desc; ++struct crypt_prf; ++ ++/* ++ * Primitives implementing PRF described in rfc2104. ++ * ++ * This implementation tries to keep all the input and output material ++ * secure inside SymKeys. To that end, it should be good for ++ * generating keying material. ++ * ++ * The slightly clunky, interface is described in-line below. ++ */ ++ ++/* ++ * Call this first; always. ++ * ++ * SCRATCH is used as a secure starting point when the key is formed ++ * from raw bytes (or memory). ++ */ ++struct crypt_prf *crypt_prf_init(const char *name, ++ const struct hash_desc *hasher, ++ PK11SymKey *scratch); ++ ++/* ++ * Next load up the raw-key by calling one or more of the following. ++ * Multiple calls concatenate the key. ++ * ++ * Even when SCRATCH above was passed the KEY, the below must be ++ * called. ++ */ ++void crypt_prf_init_symkey(const char *name, struct crypt_prf *prf, PK11SymKey *key); ++void crypt_prf_init_chunk(const char *name, struct crypt_prf *prf, ++ chunk_t key); ++void crypt_prf_init_bytes(const char *name, struct crypt_prf *prf, ++ const void *key, size_t sizeof_key); ++ ++/* ++ * Then call this to flip to seed/data/text mode; always. ++ */ ++void crypt_prf_update(struct crypt_prf *prf); ++ ++/* ++ * Call these to accumulate the seed/data/text. ++ */ ++void crypt_prf_update_chunk(const char *name, struct crypt_prf *prf, ++ chunk_t update); ++void crypt_prf_update_symkey(const char *name, struct crypt_prf *prf, ++ PK11SymKey *update); ++void crypt_prf_update_byte(const char *name, struct crypt_prf *prf, uint8_t byte); ++void crypt_prf_update_bytes(const char *name, struct crypt_prf *prf, ++ const void *bytes, size_t count); ++ ++/* ++ * Finally ... ++ * ++ * This will free PRF. ++ */ ++PK11SymKey *crypt_prf_final(struct crypt_prf *prf); ++void crypt_prf_final_bytes(struct crypt_prf *prf, ++ void *bytes, size_t sizeof_bytes); ++ ++#endif +diff -Naur libreswan-3.12-orig/programs/pluto/crypt_symkey.c libreswan-3.12/programs/pluto/crypt_symkey.c +--- libreswan-3.12-orig/programs/pluto/crypt_symkey.c 1969-12-31 19:00:00.000000000 -0500 ++++ libreswan-3.12/programs/pluto/crypt_symkey.c 2015-05-06 11:45:32.920301417 -0400 +@@ -0,0 +1,468 @@ ++/* ++ * SYMKEY manipulation functions, for libreswan ++ * ++ * Copyright (C) 2015 Andrew Cagney ++ * ++ * 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. See . ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ */ ++ ++#include "libreswan.h" ++#include "lswalloc.h" ++#include "lswlog.h" ++#include "ike_alg.h" ++#include "crypt_symkey.h" ++#include "crypto.h" ++ ++/* ++ * XXX: Is there an NSS version of this? ++ */ ++ ++static const char *ckm_to_string(CK_MECHANISM_TYPE mechanism) ++{ ++ const char *t; ++#define CASE(T) case T: t = #T; eat(t, "CKM_"); return t ++ switch (mechanism) { ++ ++ CASE(CKM_CONCATENATE_BASE_AND_DATA); ++ CASE(CKM_CONCATENATE_BASE_AND_KEY); ++ CASE(CKM_CONCATENATE_DATA_AND_BASE); ++ ++ CASE(CKM_XOR_BASE_AND_DATA); ++ ++ CASE(CKM_EXTRACT_KEY_FROM_KEY); ++ ++ CASE(CKM_VENDOR_DEFINED); ++ ++ CASE(CKM_AES_CBC); ++ CASE(CKM_DES3_CBC); ++ CASE(CKM_CAMELLIA_CBC); ++ CASE(CKM_AES_CTR); ++ CASE(CKM_AES_GCM); ++ ++ CASE(CKM_MD5_KEY_DERIVATION); ++ CASE(CKM_SHA1_KEY_DERIVATION); ++ CASE(CKM_SHA256_KEY_DERIVATION); ++ CASE(CKM_SHA384_KEY_DERIVATION); ++ CASE(CKM_SHA512_KEY_DERIVATION); ++ ++ default: ++ DBG(DBG_CRYPT, DBG_log("unknown mechanism 0x%08x", (int) mechanism)); ++ return "unknown-mechanism"; ++ } ++#undef CASE ++} ++ ++void free_any_symkey(const char *prefix, PK11SymKey **key) ++{ ++ if (*key != NULL) { ++ DBG(DBG_CRYPT, DBG_log("%s: free key %p", prefix, *key)); ++ PK11_FreeSymKey(*key); ++ } else { ++ DBG(DBG_CRYPT, DBG_log("%s: free key NULL", prefix)); ++ } ++ *key = NULL; ++} ++ ++void DBG_dump_symkey(const char *prefix, PK11SymKey *key) ++{ ++ if (key == NULL) { ++ /* ++ * For instance, when a zero-length key gets extracted ++ * from an existing key. ++ */ ++ DBG_log("%s key is NULL", prefix); ++ } else { ++ DBG_log("%s key %p %d mechanism(type) %s", ++ prefix, key, PK11_GetKeyLength(key), ++ ckm_to_string(PK11_GetMechanism(key))); ++ if (DBGP(DBG_PRIVATE)) { ++ chunk_t chunk = chunk_from_symkey(prefix, key); ++ DBG_dump_chunk(prefix, chunk); ++ freeanychunk(chunk); ++ } else { ++ DBG_log("%s contents are private", prefix); ++ } ++ } ++} ++ ++/* ++ * XXX: Is there any documentation on this generic operation? ++ */ ++static PK11SymKey *merge_symkey_bytes(PK11SymKey *base_key, ++ const void *bytes, size_t sizeof_bytes, ++ CK_MECHANISM_TYPE derive, ++ CK_MECHANISM_TYPE target) ++{ ++ passert(sizeof_bytes > 0); ++ CK_KEY_DERIVATION_STRING_DATA string = { ++ .pData = (void *)bytes, ++ .ulLen = sizeof_bytes, ++ }; ++ SECItem param = { ++ .data = (unsigned char*)&string, ++ .len = sizeof(string), ++ }; ++ CK_ATTRIBUTE_TYPE operation = CKA_DERIVE; ++ int key_size = 0; ++ ++ DBG(DBG_CRYPT, ++ DBG_log("derive %s using %s", ckm_to_string(derive), ++ ckm_to_string(target)); ++ DBG_dump_symkey("base", base_key); ++ DBG_dump("data", bytes, sizeof_bytes)); ++ PK11SymKey *result = PK11_Derive(base_key, derive, ¶m, target, ++ operation, key_size); ++ DBG(DBG_CRYPT, DBG_dump_symkey("result", result)); ++ ++ return result; ++} ++ ++/* ++ * SYMKEY I/O operations. ++ * ++ * SYMKEY_FROM_CHUNK uses the SCRATCH key as a secure starting point ++ * for creating the key. ++ */ ++ ++PK11SymKey *symkey_from_bytes(PK11SymKey *scratch, const void *bytes, ++ size_t sizeof_bytes) ++{ ++ PK11SymKey *tmp = merge_symkey_bytes(scratch, bytes, sizeof_bytes, ++ CKM_CONCATENATE_DATA_AND_BASE, ++ CKM_EXTRACT_KEY_FROM_KEY); ++ passert(tmp != NULL); ++ PK11SymKey *key = key_from_symkey_bytes(tmp, 0, sizeof_bytes); ++ passert(key != NULL); ++ free_any_symkey(__func__, &tmp); ++ return key; ++} ++ ++PK11SymKey *symkey_from_chunk(PK11SymKey *scratch, chunk_t chunk) ++{ ++ return symkey_from_bytes(scratch, chunk.ptr, chunk.len); ++} ++ ++/* ++ * Concatenate two pieces of keying material creating a ++ * new SYMKEY object. ++ */ ++ ++PK11SymKey *concat_symkey_symkey(const struct hash_desc *hasher, ++ PK11SymKey *lhs, PK11SymKey *rhs) ++{ ++ CK_OBJECT_HANDLE keyhandle = PK11_GetSymKeyHandle(rhs); ++ /* give the parameters explicit names - there are too many */ ++ PK11SymKey *base_key = lhs; ++ CK_MECHANISM_TYPE derive = CKM_CONCATENATE_BASE_AND_KEY; ++ SECItem param = { ++ .data = (unsigned char*)&keyhandle, ++ .len = sizeof(keyhandle) ++ }; ++ CK_MECHANISM_TYPE target = nss_key_derivation_mech(hasher); ++ CK_ATTRIBUTE_TYPE operation = CKA_DERIVE; ++ int key_size = 0; ++ ++ DBG(DBG_CRYPT, ++ DBG_log("concate symkey(base) symkey(key) target %s", ++ ckm_to_string(target)); ++ DBG_dump_symkey("base", lhs); ++ DBG_dump_symkey("key", rhs)); ++ PK11SymKey *result = PK11_Derive(base_key, derive, ¶m, target, ++ operation, key_size); ++ DBG(DBG_CRYPT, DBG_dump_symkey("result", result)); ++ ++ return result; ++} ++ ++PK11SymKey *concat_symkey_bytes(const struct hash_desc *hasher, ++ PK11SymKey *lhs, const void *rhs, ++ size_t sizeof_rhs) ++{ ++ CK_MECHANISM_TYPE mechanism = nss_key_derivation_mech(hasher); ++ return merge_symkey_bytes(lhs, rhs, sizeof_rhs, ++ CKM_CONCATENATE_BASE_AND_DATA, ++ mechanism); ++} ++ ++PK11SymKey *concat_symkey_chunk(const struct hash_desc *hasher, ++ PK11SymKey *lhs, chunk_t rhs) ++{ ++ return concat_symkey_bytes(hasher, lhs, rhs.ptr, rhs.len); ++} ++ ++PK11SymKey *concat_symkey_byte(const struct hash_desc *hasher, ++ PK11SymKey *lhs, uint8_t rhs) ++{ ++ return concat_symkey_bytes(hasher, lhs, &rhs, sizeof(rhs)); ++} ++ ++/* ++ * Append new keying material to an existing key; replace the existing ++ * key with the result. ++ * ++ * Use this to chain a series of concat operations. ++ */ ++ ++void append_symkey_symkey(const struct hash_desc *hasher, ++ PK11SymKey **lhs, PK11SymKey *rhs) ++{ ++ PK11SymKey *newkey = concat_symkey_symkey(hasher, *lhs, rhs); ++ free_any_symkey(__func__, lhs); ++ *lhs = newkey; ++} ++ ++void append_symkey_bytes(const struct hash_desc *hasher, ++ PK11SymKey **lhs, const void *rhs, ++ size_t sizeof_rhs) ++{ ++ PK11SymKey *newkey = concat_symkey_bytes(hasher, *lhs, ++ rhs, sizeof_rhs); ++ free_any_symkey(__func__, lhs); ++ *lhs = newkey; ++} ++ ++void append_symkey_chunk(const struct hash_desc *hasher, ++ PK11SymKey **lhs, chunk_t rhs) ++{ ++ append_symkey_bytes(hasher, lhs, rhs.ptr, rhs.len); ++} ++ ++void append_symkey_byte(const struct hash_desc *hasher, ++ PK11SymKey **lhs, uint8_t rhs) ++{ ++ append_symkey_bytes(hasher, lhs, &rhs, sizeof(rhs)); ++} ++ ++/* ++ * Extract raw-bytes from a SYMKEY. ++ * ++ * Offset into the SYMKEY is in either BITS or BYTES. ++ */ ++ ++static PK11SymKey *key_from_key_bits(PK11SymKey *base_key, ++ CK_MECHANISM_TYPE target, ++ CK_FLAGS flags, ++ size_t next_bit, size_t key_size) ++{ ++ /* spell out all the parameters */ ++ CK_EXTRACT_PARAMS bs = next_bit; ++ SECItem param = { ++ .data = (unsigned char*)&bs, ++ .len = sizeof(bs), ++ }; ++ CK_MECHANISM_TYPE derive = CKM_EXTRACT_KEY_FROM_KEY; ++ CK_ATTRIBUTE_TYPE operation = CKA_FLAGS_ONLY; ++ ++ DBG(DBG_CRYPT, ++ DBG_log("%s key from base key bits %zd length %zd flags 0x%lx", ++ ckm_to_string(target), next_bit, key_size, flags); ++ DBG_dump_symkey("base key", base_key)); ++ PK11SymKey *result = PK11_DeriveWithFlags(base_key, derive, ¶m, ++ target, operation, ++ key_size, flags); ++ DBG(DBG_CRYPT, DBG_dump_symkey("result", result)); ++ ++ return result; ++} ++ ++void *bytes_from_symkey_bits(const char *name, ++ PK11SymKey *source_key, size_t next_bit, ++ void *bytes, size_t sizeof_bytes) ++{ ++ DBG(DBG_CRYPT, ++ DBG_log("%s: extracting %zd bytes starting at bit %zd from symkey %p into %p", ++ name, sizeof_bytes, next_bit, source_key, bytes)); ++ if (sizeof_bytes == 0) { ++ return NULL; ++ } ++ PK11SymKey *sym_key = key_from_key_bits(source_key, ++ CKM_VENDOR_DEFINED, 0, ++ next_bit, sizeof_bytes); ++ if (sym_key == NULL) { ++ loglog(RC_LOG_SERIOUS, "NSS key-from-key failed while generating %s", name); ++ return NULL; ++ } ++ SECStatus s = PK11_ExtractKeyValue(sym_key); ++ if (s != SECSuccess) { ++ loglog(RC_LOG_SERIOUS, "NSS: PK11_ExtractKeyValue failed while generating %s", name); ++ return NULL; ++ } ++ /* Internal structure address, do not free. */ ++ SECItem *data = PK11_GetKeyData(sym_key); ++ if (data == NULL) { ++ loglog(RC_LOG_SERIOUS, "NSS: PK11_GetKeyData failed while generating %s", name); ++ return NULL; ++ } ++ DBG(DBG_CRYPT, ++ DBG_log("chunk_from_symkey: %s: extracted len %d bytes at %p", ++ name, data->len, data->data)); ++ if (data->len != sizeof_bytes) { ++ loglog(RC_LOG_SERIOUS, "NSS: PK11_GetKeyData returned wrong number of bytes while generating %s", name); ++ return NULL; ++ } ++ /* Only alloc, when all looks good. */ ++ if (bytes == NULL) { ++ bytes = alloc_bytes(sizeof_bytes, name); ++ DBG(DBG_CRYPT, ++ DBG_log("%s: allocated %zd bytes at %p", ++ name, sizeof_bytes, bytes)); ++ } ++ memcpy(bytes, data->data, sizeof_bytes); ++ DBG(DBG_PRIVATE, DBG_dump(name, bytes, sizeof_bytes)); ++ free_any_symkey(__func__, &sym_key); ++ ++ return bytes; ++} ++ ++void *bytes_from_symkey_bytes(const char *name, PK11SymKey *source_key, ++ size_t next_byte, void *bytes, ++ size_t sizeof_bytes) ++{ ++ return bytes_from_symkey_bits(name, source_key, ++ next_byte * BITS_PER_BYTE, ++ bytes, sizeof_bytes); ++} ++ ++chunk_t chunk_from_symkey_bits(const char *name, PK11SymKey *source_key, ++ size_t next_bit, size_t sizeof_chunk) ++{ ++ void *bytes = bytes_from_symkey_bits(name, source_key, next_bit, ++ NULL, sizeof_chunk); ++ if (bytes == NULL) { ++ return empty_chunk; ++ } ++ chunk_t chunk; ++ setchunk(chunk, bytes, sizeof_chunk); ++ return chunk; ++} ++ ++chunk_t chunk_from_symkey_bytes(const char *name, PK11SymKey *source_key, ++ size_t next_byte, size_t sizeof_chunk) ++{ ++ return chunk_from_symkey_bits(name, source_key, ++ next_byte * BITS_PER_BYTE, sizeof_chunk); ++} ++ ++chunk_t chunk_from_symkey(const char *name, PK11SymKey *source_key) ++{ ++ return chunk_from_symkey_bits(name, source_key, 0, ++ PK11_GetKeyLength(source_key)); ++} ++ ++/* ++ * Extract SIZEOF_SYMKEY bytes of keying material as an ENCRYPTER key ++ * (i.e., can be used to encrypt/decrypt data using ENCRYPTER). ++ * ++ * Offset into the SYMKEY is in either BITS or BYTES. ++ */ ++ ++PK11SymKey *encrypt_key_from_symkey_bits(PK11SymKey *source_key, ++ const struct encrypt_desc *encrypter, ++ size_t next_bit, size_t sizeof_symkey) ++{ ++ return key_from_key_bits(source_key, ++ nss_encryption_mech(encrypter), ++ CKF_ENCRYPT | CKF_DECRYPT, ++ next_bit, sizeof_symkey); ++} ++ ++PK11SymKey *encrypt_key_from_symkey_bytes(PK11SymKey *source_key, ++ const struct encrypt_desc *encrypter, ++ size_t next_byte, size_t sizeof_symkey) ++{ ++ return encrypt_key_from_symkey_bits(source_key, encrypter, ++ next_byte * BITS_PER_BYTE, ++ sizeof_symkey); ++} ++ ++/* ++ * Extract SIZEOF_KEY bytes of keying material as a KEY. It inherits ++ * the BASE_KEYs type. Good for hash keys. ++ * ++ * Offset into the SYMKEY is in either BITS or BYTES. ++ */ ++ ++PK11SymKey *key_from_symkey_bits(PK11SymKey *base_key, ++ size_t next_bit, size_t key_size) ++{ ++ CK_EXTRACT_PARAMS bs = next_bit; ++ SECItem param = { ++ .data = (unsigned char*)&bs, ++ .len = sizeof(bs), ++ }; ++ CK_MECHANISM_TYPE derive = CKM_EXTRACT_KEY_FROM_KEY; ++ CK_MECHANISM_TYPE target = CKM_CONCATENATE_BASE_AND_DATA; ++ CK_ATTRIBUTE_TYPE operation = CKA_DERIVE; ++ /* XXX: can this use key_from_key_bits? */ ++ ++ DBG(DBG_CRYPT, ++ DBG_log("%s key from symkey(base key) bits %zd length %zd", ++ ckm_to_string(target), ++ next_bit, key_size); ++ DBG_dump_symkey("base key", base_key)); ++ PK11SymKey *result = PK11_Derive(base_key, derive, ¶m, target, ++ operation, key_size); ++ DBG(DBG_CRYPT, DBG_dump_symkey("result", result)); ++ ++ return result; ++} ++ ++PK11SymKey *key_from_symkey_bytes(PK11SymKey *source_key, ++ size_t next_byte, size_t sizeof_key) ++{ ++ return key_from_symkey_bits(source_key, ++ next_byte * BITS_PER_BYTE, ++ sizeof_key); ++} ++ ++/* ++ * Run HASHER on the key. ++ * ++ * This assumes that NSS works. Based on old code, 3.14 may have had ++ * problems with SHA-2. ++ */ ++PK11SymKey *hash_symkey(const struct hash_desc *hasher, ++ PK11SymKey *base_key) ++{ ++ CK_MECHANISM_TYPE derive = nss_key_derivation_mech(hasher); ++ SECItem *param = NULL; ++ CK_MECHANISM_TYPE target = CKM_CONCATENATE_BASE_AND_KEY; ++ CK_ATTRIBUTE_TYPE operation = CKA_DERIVE; ++ int key_size = 0; ++ ++ DBG(DBG_CRYPT, ++ DBG_log("%s hash symkey(base key)", ckm_to_string(derive)); ++ DBG_dump_symkey("base key", base_key)); ++ PK11SymKey *result = PK11_Derive(base_key, derive, param, target, ++ operation, key_size); ++ DBG(DBG_CRYPT, DBG_dump_symkey("result", result)); ++ ++ return result; ++} ++ ++/* ++ * XOR a symkey with a chunk. ++ * ++ * XXX: hmac.c had very similar code, only, instead of ++ * target=CKM_CONCATENATE_BASE_AND_DATA it used ++ * target=hasher-to-ckm(hasher). ++ * ++ * hasher-to-ckm maped hasher->common.alg_id to CMK vis: OAKLEY_MD5 -> ++ * CKM_MD5; OAKLEY_SHA1 -> CKM_SHA_1; OAKLEY_SHA2_256 -> CKM_SHA256; ++ * OAKLEY_SHA2_384 -> CKM_SHA384; OAKLEY_SHA2_512 -> CKM_SHA512; only ++ * in the default case it would set target to 0x80000000???? ++ */ ++PK11SymKey *xor_symkey_chunk(PK11SymKey *lhs, chunk_t rhs) ++{ ++ return merge_symkey_bytes(lhs, rhs.ptr, rhs.len, ++ CKM_XOR_BASE_AND_DATA, ++ CKM_CONCATENATE_BASE_AND_DATA); ++} +diff -Naur libreswan-3.12-orig/programs/pluto/crypt_symkey.h libreswan-3.12/programs/pluto/crypt_symkey.h +--- libreswan-3.12-orig/programs/pluto/crypt_symkey.h 1969-12-31 19:00:00.000000000 -0500 ++++ libreswan-3.12/programs/pluto/crypt_symkey.h 2015-05-06 11:45:32.920301417 -0400 +@@ -0,0 +1,131 @@ ++/* ++ * SYMKEY manipulation functions, for libreswan ++ * ++ * Copyright (C) 2015 Andrew Cagney ++ * ++ * 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. See . ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ */ ++ ++#ifndef crypt_symkey_h ++#define crypt_symkey_h ++ ++#include ++#include ++#include "lswalloc.h" ++ ++struct hash_desc; ++struct encrypt_desc; ++ ++void DBG_dump_symkey(const char *prefix, PK11SymKey *key); ++ ++/* ++ * Free any symkey and then stomp on the pointer. ++ */ ++void free_any_symkey(const char *prefix, PK11SymKey **key); ++ ++/* ++ * Use SCRATCH key as a secure starting point for creating the key ++ * from the raw bytes, or chunk. ++ */ ++ ++PK11SymKey *symkey_from_bytes(PK11SymKey *scratch, const void *bytes, ++ size_t sizeof_bytes); ++ ++PK11SymKey *symkey_from_chunk(PK11SymKey *scratch, chunk_t chunk); ++ ++/* ++ * Concatenate two pieces of keying material creating a ++ * new SYMKEY object. ++ */ ++PK11SymKey *concat_symkey_symkey(const struct hash_desc *hasher, ++ PK11SymKey *lhs, PK11SymKey *rhs); ++PK11SymKey *concat_symkey_bytes(const struct hash_desc *hasher, ++ PK11SymKey *lhs, const void *rhs, ++ size_t sizeof_rhs); ++PK11SymKey *concat_symkey_chunk(const struct hash_desc *hasher, ++ PK11SymKey *lhs, chunk_t rhs); ++PK11SymKey *concat_symkey_byte(const struct hash_desc *hasher, ++ PK11SymKey *lhs, uint8_t rhs); ++ ++/* ++ * Append new keying material to an existing key; replace the existing ++ * key with the result. ++ * ++ * Use this to chain a series of concat operations. ++ */ ++void append_symkey_symkey(const struct hash_desc *hasher, ++ PK11SymKey **lhs, PK11SymKey *rhs); ++void append_symkey_bytes(const struct hash_desc *hasher, ++ PK11SymKey **lhs, const void *rhs, ++ size_t sizeof_rhs); ++void append_symkey_chunk(const struct hash_desc *hasher, ++ PK11SymKey **lhs, chunk_t rhs); ++void append_symkey_byte(const struct hash_desc *hasher, ++ PK11SymKey **lhs, uint8_t rhs); ++ ++/* ++ * Extract raw-bytes from a SYMKEY. ++ * ++ * Offset into the SYMKEY is in either BITS or BYTES. ++ * ++ * bytes_from_ has a querk where, if BYTES is NULL, the buffer is ++ * allocated. ++ */ ++void *bytes_from_symkey_bits(const char *name, PK11SymKey *source_key, ++ size_t next_bit, void *bytes, ++ size_t sizeof_bytes); ++void *bytes_from_symkey_bytes(const char *name, PK11SymKey *source_key, ++ size_t next_byte, void *bytes, ++ size_t sizeof_bytes); ++chunk_t chunk_from_symkey_bits(const char *name, PK11SymKey *source_key, ++ size_t next_bit, size_t sizeof_chunk); ++chunk_t chunk_from_symkey_bytes(const char *name, PK11SymKey *source_key, ++ size_t next_byte, size_t sizeof_chunk); ++chunk_t chunk_from_symkey(const char *name, PK11SymKey *source_key); ++ ++/* ++ * Extract SIZEOF_SYMKEY bytes of keying material as an ENCRYPTER key ++ * (i.e., can be used to encrypt/decrypt data using ENCRYPTER). ++ * ++ * Offset into the SYMKEY is in either BITS or BYTES. ++ */ ++PK11SymKey *encrypt_key_from_symkey_bytes(PK11SymKey *source_key, ++ const struct encrypt_desc *encrypter, ++ size_t next_byte, size_t sizeof_symkey); ++PK11SymKey *encrypt_key_from_symkey_bits(PK11SymKey *source_key, ++ const struct encrypt_desc *encrypter, ++ size_t next_bit, size_t sizeof_symkey); ++ ++/* ++ * Extract SIZEOF_KEY bytes of keying material as a KEY. It inherits ++ * the BASE_KEYs type. Good for hash keys. ++ * ++ * Offset into the SYMKEY is in either BITS or BYTES. ++ */ ++PK11SymKey *key_from_symkey_bits(PK11SymKey *base_key, ++ size_t next_bit, size_t key_size); ++PK11SymKey *key_from_symkey_bytes(PK11SymKey *source_key, ++ size_t next_byte, size_t sizeof_key); ++ ++/* ++ * Hash a symkey using HASHER. ++ * ++ * This gets used by the PRF when the BASE_KEY is too long. ++ */ ++PK11SymKey *hash_symkey(const struct hash_desc *hasher, ++ PK11SymKey *base_key); ++ ++/* ++ * XOR a symkey with a chunk. ++ */ ++PK11SymKey *xor_symkey_chunk(PK11SymKey *lhs, chunk_t rhs); ++ ++#endif +diff -Naur libreswan-3.12-orig/programs/pluto/ctr_test_vectors.c libreswan-3.12/programs/pluto/ctr_test_vectors.c +--- libreswan-3.12-orig/programs/pluto/ctr_test_vectors.c 2015-05-06 11:44:21.564466307 -0400 ++++ libreswan-3.12/programs/pluto/ctr_test_vectors.c 2015-05-06 11:45:32.921301428 -0400 +@@ -12,6 +12,7 @@ + + #include "nss.h" + #include "pk11pub.h" ++#include "crypt_symkey.h" + + struct ctr_test_vector { + // CK_MECHANISM_TYPE cipher_mechanism; +@@ -203,7 +204,8 @@ + ok = 0; + } + +- PK11_FreeSymKey(sym_key); ++ /* Clean up. */ ++ free_any_symkey("sym_key", &sym_key); + DBG(DBG_CRYPT, DBG_log("test_ctr_vector: %s %s", + test->description, ok ? "passed" : "failed")); + return ok; +diff -Naur libreswan-3.12-orig/programs/pluto/gcm_test_vectors.c libreswan-3.12/programs/pluto/gcm_test_vectors.c +--- libreswan-3.12-orig/programs/pluto/gcm_test_vectors.c 2015-05-06 11:44:21.584466542 -0400 ++++ libreswan-3.12/programs/pluto/gcm_test_vectors.c 2015-05-06 11:45:32.921301428 -0400 +@@ -24,6 +24,7 @@ + + #include "nss.h" + #include "pk11pub.h" ++#include "crypt_symkey.h" + + struct gcm_test_vector { + const char *key; +@@ -165,14 +166,16 @@ + } + + freeanychunk(salted_iv); +- freeanychunk(wire_iv); + freeanychunk(salt); +- freeanychunk(tag); ++ freeanychunk(wire_iv); ++ freeanychunk(aad); + freeanychunk(plaintext); + freeanychunk(ciphertext); ++ freeanychunk(tag); + freeanychunk(text_and_tag); + +- PK11_FreeSymKey(sym_key); ++ /* Clean up. */ ++ free_any_symkey("sym_key", &sym_key); + DBG(DBG_CRYPT, DBG_log("test_gcm_vector: %s", ok ? "passed" : "failed")); + return ok; + } +diff -Naur libreswan-3.12-orig/programs/pluto/hmac.c libreswan-3.12/programs/pluto/hmac.c +--- libreswan-3.12-orig/programs/pluto/hmac.c 2014-11-06 22:52:50.000000000 -0500 ++++ libreswan-3.12/programs/pluto/hmac.c 2015-05-06 11:45:32.921301428 -0400 +@@ -5,8 +5,9 @@ + * Copyright (C) 2009 Paul Wouters + * Copyright (C) 2010-2012 Avesh Agarwal + * Copyright (C) 2012 Paul Wouters +- * Copyright (C) 2012-2013 Paul Wouters ++ * Copyright (C) 2012-2015 Paul Wouters + * Copyright (C) 2013 D. Hugh Redelmeier ++ * Copyright (C) 2015, Andrew Cagney + * + * 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 +@@ -40,272 +41,42 @@ + #include + #include "lswconf.h" + #include "lswlog.h" ++#include "crypt_symkey.h" ++#include "crypt_prf.h" + + /* HMAC package + * rfc2104.txt specifies how HMAC works. + */ + +-static CK_MECHANISM_TYPE nss_hash_mech(const struct hash_desc *hasher); +-static SECOidTag nss_hash_oid(const struct hash_desc *hasher); +- + void hmac_init(struct hmac_ctx *ctx, + const struct hash_desc *h, + /*const*/ PK11SymKey *symkey) /* NSS doesn't like const! */ + { +- SECStatus status; +- PK11SymKey +- *tkey1, +- *tkey2; +- unsigned int klen = PK11_GetKeyLength(symkey); +- chunk_t hmac_opad, hmac_ipad, hmac_pad; +- +- ctx->h = h; ++ /* ++ * Note: The SYMKEY passed to crypt_prf_init is used to ++ * generate secure keying material from nothing. ++ * crypt_prf_init_symkey() establishes the actual key. ++ */ ++ ctx->prf = crypt_prf_init("hmac", h, symkey); + ctx->hmac_digest_len = h->hash_digest_len; +- +- /* DBG(DBG_CRYPT, DBG_log("NSS: hmac init")); */ +- +- hmac_opad = hmac_pads(HMAC_OPAD, h->hash_block_size); +- hmac_ipad = hmac_pads(HMAC_IPAD, h->hash_block_size); +- hmac_pad = hmac_pads(0x00, h->hash_block_size - klen); +- +- if (klen > h->hash_block_size) { +- tkey1 = PK11_Derive_lsw(symkey, nss_key_derivation_mech(h), +- NULL, +- CKM_CONCATENATE_BASE_AND_DATA, +- CKA_DERIVE, +- 0); +- } else { +- tkey1 = symkey; +- } +- +- tkey2 = pk11_derive_wrapper_lsw(tkey1, CKM_CONCATENATE_BASE_AND_DATA, +- hmac_pad, +- CKM_XOR_BASE_AND_DATA, CKA_DERIVE, +- h->hash_block_size); +- passert(tkey2 != NULL); +- +- ctx->ikey = pk11_derive_wrapper_lsw(tkey2, CKM_XOR_BASE_AND_DATA, +- hmac_ipad, nss_hash_mech(h), +- CKA_DIGEST, 0); +- passert(ctx->ikey != NULL); +- +- ctx->okey = pk11_derive_wrapper_lsw(tkey2, CKM_XOR_BASE_AND_DATA, +- hmac_opad, nss_hash_mech(h), +- CKA_DIGEST, 0); +- passert(ctx->okey != NULL); +- +- if (tkey1 != symkey) +- PK11_FreeSymKey(tkey1); +- PK11_FreeSymKey(tkey2); +- +- freeanychunk(hmac_opad); +- freeanychunk(hmac_ipad); +- freeanychunk(hmac_pad); +- ctx->ctx_nss = PK11_CreateDigestContext(nss_hash_oid(h)); +- passert(ctx->ctx_nss != NULL); +- +- status = PK11_DigestBegin(ctx->ctx_nss); +- passert(status == SECSuccess); +- +- status = PK11_DigestKey(ctx->ctx_nss, ctx->ikey); +- passert(status == SECSuccess); ++ crypt_prf_init_symkey("symkey", ctx->prf, symkey); ++ crypt_prf_update(ctx->prf); + } + + void hmac_update(struct hmac_ctx *ctx, + const u_char *data, size_t data_len) + { +- DBG(DBG_CRYPT, DBG_dump("hmac_update data value: ", data, data_len)); +- if (data_len > 0) { +- SECStatus status; +- +- DBG(DBG_CRYPT, DBG_log("hmac_update: inside if")); +- status = PK11_DigestOp(ctx->ctx_nss, data, data_len); +- DBG(DBG_CRYPT, DBG_log("hmac_update: after digest")); +- passert(status == SECSuccess); +- DBG(DBG_CRYPT, DBG_log("hmac_update: after assert")); +- } ++ crypt_prf_update_bytes("data", ctx->prf, data, data_len); + } + + void hmac_final(u_char *output, struct hmac_ctx *ctx) + { +- unsigned int outlen; +- SECStatus status; +- +- status = PK11_DigestFinal(ctx->ctx_nss, output, &outlen, +- ctx->hmac_digest_len); +- passert(status == SECSuccess); +- passert(outlen == ctx->hmac_digest_len); +- PK11_DestroyContext(ctx->ctx_nss, PR_TRUE); +- ctx->ctx_nss = NULL; +- +- ctx->ctx_nss = PK11_CreateDigestContext(nss_hash_oid(ctx->h)); +- passert(ctx->ctx_nss != NULL); +- +- status = PK11_DigestBegin(ctx->ctx_nss); +- passert(status == SECSuccess); +- +- status = PK11_DigestKey(ctx->ctx_nss, ctx->okey); +- passert(status == SECSuccess); +- +- status = PK11_DigestOp(ctx->ctx_nss, output, outlen); +- passert(status == SECSuccess); +- +- status = PK11_DigestFinal(ctx->ctx_nss, output, &outlen, +- ctx->hmac_digest_len); +- passert(status == SECSuccess); +- passert(outlen == ctx->hmac_digest_len); +- PK11_DestroyContext(ctx->ctx_nss, PR_TRUE); +- +- if (ctx->ikey != NULL) +- PK11_FreeSymKey(ctx->ikey); +- if (ctx->okey != NULL) +- PK11_FreeSymKey(ctx->okey); +- /* DBG(DBG_CRYPT, DBG_log("NSS: hmac final end")); */ +-} +- +-static SECOidTag nss_hash_oid(const struct hash_desc *hasher) +-{ +- SECOidTag mechanism; +- +- switch (hasher->common.algo_id) { +- case OAKLEY_MD5: +- mechanism = SEC_OID_MD5; +- break; +- case OAKLEY_SHA1: +- mechanism = SEC_OID_SHA1; +- break; +- case OAKLEY_SHA2_256: +- mechanism = SEC_OID_SHA256; +- break; +- case OAKLEY_SHA2_384: +- mechanism = SEC_OID_SHA384; +- break; +- case OAKLEY_SHA2_512: +- mechanism = SEC_OID_SHA512; +- break; +- default: +- libreswan_log("NSS: key derivation mechanism (hasher->common.algo_id=%d not supported", +- hasher->common.algo_id); +- mechanism = 0; /* ??? what should we do to recover? */ +- break; +- } +- return mechanism; +-} +- +-static CK_MECHANISM_TYPE nss_hash_mech(const struct hash_desc *hasher) +-{ +- CK_MECHANISM_TYPE mechanism; +- +- switch (hasher->common.algo_id) { +- case OAKLEY_MD5: +- mechanism = CKM_MD5; +- break; +- case OAKLEY_SHA1: +- mechanism = CKM_SHA_1; +- break; +- case OAKLEY_SHA2_256: +- mechanism = CKM_SHA256; +- break; +- case OAKLEY_SHA2_384: +- mechanism = CKM_SHA384; +- break; +- case OAKLEY_SHA2_512: +- mechanism = CKM_SHA512; +- break; +- default: +- /* ??? surely this requires more than a DBG entry! */ +- DBG(DBG_CRYPT, +- DBG_log("NSS: key derivation mechanism not supported")); +- mechanism = 0x80000000; /* ??? what should we do to recover? */ +- break; +- } +- return mechanism; +-} +- +-PK11SymKey *pk11_derive_wrapper_lsw(PK11SymKey *base, +- CK_MECHANISM_TYPE mechanism, +- chunk_t data, CK_MECHANISM_TYPE target, +- CK_ATTRIBUTE_TYPE operation, int keySize) +-{ +- CK_KEY_DERIVATION_STRING_DATA string; +- SECItem param; +- +- string.pData = data.ptr; +- string.ulLen = data.len; +- param.data = (unsigned char*)&string; +- param.len = sizeof(string); +- +- return PK11_Derive(base, mechanism, ¶m, target, operation, +- keySize); ++ crypt_prf_final_bytes(ctx->prf, output, ctx->hmac_digest_len); + } + +-/* MUST BE THREAD-SAFE */ +-PK11SymKey *PK11_Derive_lsw(PK11SymKey *base, CK_MECHANISM_TYPE mechanism, +- SECItem *param, CK_MECHANISM_TYPE target, +- CK_ATTRIBUTE_TYPE operation, int keysize) +-{ +- if (param == NULL && keysize == 0) { +- SECOidTag oid; +- PK11Context *ctx; +- unsigned char dkey[HMAC_BUFSIZE * 2]; +- SECItem dkey_param; +- SECStatus status; +- unsigned int len; +- CK_EXTRACT_PARAMS bs; +- chunk_t dkey_chunk; +- +- switch (mechanism) { +- case CKM_SHA256_KEY_DERIVATION: +- oid = SEC_OID_SHA256; +- break; +- case CKM_SHA384_KEY_DERIVATION: +- oid = SEC_OID_SHA384; +- break; +- case CKM_SHA512_KEY_DERIVATION: +- oid = SEC_OID_SHA512; +- break; +- default: +- return PK11_Derive(base, mechanism, param, target, +- operation, keysize); +- } +- +- ctx = PK11_CreateDigestContext(oid); +- passert(ctx != NULL); +- status = PK11_DigestBegin(ctx); +- passert(status == SECSuccess); +- status = PK11_DigestKey(ctx, base); +- passert(status == SECSuccess); +- status = PK11_DigestFinal(ctx, dkey, &len, sizeof dkey); +- passert(status == SECSuccess); +- PK11_DestroyContext(ctx, PR_TRUE); +- +- dkey_chunk.ptr = dkey; +- dkey_chunk.len = len; +- +- PK11SymKey *tkey1 = pk11_derive_wrapper_lsw(base, +- CKM_CONCATENATE_DATA_AND_BASE, dkey_chunk, CKM_EXTRACT_KEY_FROM_KEY, CKA_DERIVE, +- 0); +- passert(tkey1 != NULL); +- +- bs = 0; +- dkey_param.data = (unsigned char*)&bs; +- dkey_param.len = sizeof(bs); +- PK11SymKey *tkey2 = PK11_Derive(tkey1, +- CKM_EXTRACT_KEY_FROM_KEY, +- &dkey_param, target, operation, +- len); +- passert(tkey2 != NULL); +- +- if (tkey1 != NULL) +- PK11_FreeSymKey(tkey1); +- +- return tkey2; +- +- } else { +- return PK11_Derive(base, mechanism, param, target, operation, +- keysize); +- } +-} ++/* ++ * XXX: This should be moved to crypt_symkey.c and made private. ++ */ + + CK_MECHANISM_TYPE nss_key_derivation_mech(const struct hash_desc *hasher) + { +@@ -335,6 +106,11 @@ + return mechanism; + } + ++/* ++ * XXX: This has nothing to do with HMAC; it should be made part of ++ * the chunk_t library code. ++ */ ++ + chunk_t hmac_pads(u_char val, unsigned int len) + { + chunk_t ret; +@@ -346,31 +122,3 @@ + + return ret; + } +- +-void nss_symkey_log(PK11SymKey *key, const char *msg) +-{ +- if (key == NULL) { +- /* ??? should we print this even if !DBG_CRYPT? */ +- DBG_log("NULL key %s", msg); +- } else { +- DBG(DBG_CRYPT, { +- DBG_log("computed key %s with length =%d", msg, +- PK11_GetKeyLength(key)); +- +- if (!PK11_IsFIPS()) { +- SECStatus status = PK11_ExtractKeyValue(key); +- +- if (status == SECSuccess) { +- SECItem *keydata = PK11_GetKeyData(key); +- +- DBG_dump("value: ", keydata->data, +- keydata->len); +- +- SECITEM_FreeItem(keydata, PR_TRUE); /* ??? this was commented out. Why? */ +- } else { +- DBG_log("unobtainable key %s", msg); +- } +- } +- }); +- } +-} +diff -Naur libreswan-3.12-orig/programs/pluto/hostpair.c libreswan-3.12/programs/pluto/hostpair.c +--- libreswan-3.12-orig/programs/pluto/hostpair.c 2014-11-06 22:52:50.000000000 -0500 ++++ libreswan-3.12/programs/pluto/hostpair.c 2015-05-06 11:45:32.922301440 -0400 +@@ -286,7 +286,7 @@ + */ + passert(p == *pp); + +- terminate_connection(p->name); ++ // terminate_connection(p->name); + p->interface = NULL; + + *pp = p->hp_next; /* advance *pp */ +diff -Naur libreswan-3.12-orig/programs/pluto/ike_alg_aes.c libreswan-3.12/programs/pluto/ike_alg_aes.c +--- libreswan-3.12-orig/programs/pluto/ike_alg_aes.c 2015-05-06 11:44:21.609466836 -0400 ++++ libreswan-3.12/programs/pluto/ike_alg_aes.c 2015-05-06 11:45:47.617471739 -0400 +@@ -410,7 +410,11 @@ + + void ike_alg_aes_init(void) + { +- bool fips = libreswan_fipsmode(); ++#ifdef FIPS_CHECK ++ bool fips = libreswan_fipsproduct() || libreswan_fipskernel(); ++#else ++ bool fips = FALSE; ++#endif + if (!fips && !test_aes_cbc(&algo_aes_cbc)) { + loglog(RC_LOG_SERIOUS, "CKM_AES_CBC: test failure"); + exit_pluto(6); +diff -Naur libreswan-3.12-orig/programs/pluto/ike_alg.c libreswan-3.12/programs/pluto/ike_alg.c +--- libreswan-3.12-orig/programs/pluto/ike_alg.c 2015-05-06 11:44:21.585466554 -0400 ++++ libreswan-3.12/programs/pluto/ike_alg.c 2015-05-06 11:45:32.922301440 -0400 +@@ -322,3 +322,53 @@ + ret = lookup_group(c->alg_info_esp->esp_pfsgroup); + return ret; + } ++ ++CK_MECHANISM_TYPE nss_encryption_mech(const struct encrypt_desc *encrypter) ++{ ++ /* the best wey have for "undefined" */ ++ CK_MECHANISM_TYPE mechanism = CKM_VENDOR_DEFINED; ++ ++ switch (encrypter->common.algo_id) { ++ case OAKLEY_3DES_CBC: ++ mechanism = CKM_DES3_CBC; ++ break; ++#ifdef NOT_YET ++ case OAKLEY_CAST_CBC: ++ mechanism = CKM_CAST5_CBC: ++ break; ++#endif ++ case OAKLEY_AES_CBC: ++ mechanism = CKM_AES_CBC; ++ break; ++ case OAKLEY_CAMELLIA_CBC: ++ mechanism = CKM_CAMELLIA_CBC; ++ break; ++ case OAKLEY_AES_CTR: ++ mechanism = CKM_AES_CTR; ++ break; ++#ifdef NOT_YET ++ case OAKLEY_AES_CCM_8: ++ case OAKLEY_AES_CCM_12: ++ case OAKLEY_AES_CCM_16: ++ mechanism = CKM_AES_CCM; ++ break; ++#endif ++ case OAKLEY_AES_GCM_8: ++ case OAKLEY_AES_GCM_12: ++ case OAKLEY_AES_GCM_16: ++ mechanism = CKM_AES_GCM; ++ break; ++#ifdef NOT_YET ++ case OAKLEY_TWOFISH_CBC: ++ mechanism = CKM_TWOFISH_CBC; ++ break; ++#endif ++ default: ++ loglog(RC_LOG_SERIOUS, ++ "NSS: Unsupported encryption mechanism for %s", ++ strip_prefix(enum_name(&oakley_enc_names, ++ encrypter->common.algo_id), "OAKLEY_")); ++ break; ++ } ++ return mechanism; ++} +diff -Naur libreswan-3.12-orig/programs/pluto/ike_alg_camellia.c libreswan-3.12/programs/pluto/ike_alg_camellia.c +--- libreswan-3.12-orig/programs/pluto/ike_alg_camellia.c 2015-05-06 11:44:21.610466848 -0400 ++++ libreswan-3.12/programs/pluto/ike_alg_camellia.c 2015-05-06 11:45:47.617471739 -0400 +@@ -95,7 +95,7 @@ + void ike_alg_camellia_init(void) + { + #ifdef FIPS_CHECK +- bool fips = libreswan_fipsmode(); ++ bool fips = libreswan_fipsproduct() || libreswan_fipskernel(); + #else + bool fips = FALSE; + #endif +diff -Naur libreswan-3.12-orig/programs/pluto/ike_alg.h libreswan-3.12/programs/pluto/ike_alg.h +--- libreswan-3.12-orig/programs/pluto/ike_alg.h 2015-05-06 11:44:21.585466554 -0400 ++++ libreswan-3.12/programs/pluto/ike_alg.h 2015-05-06 11:45:32.922301440 -0400 +@@ -186,5 +186,6 @@ + extern void ike_alg_sha2_init(void); + #endif + ++CK_MECHANISM_TYPE nss_encryption_mech(const struct encrypt_desc *encrypter); + + #endif /* _IKE_ALG_H */ +diff -Naur libreswan-3.12-orig/programs/pluto/ikev1_prf.c libreswan-3.12/programs/pluto/ikev1_prf.c +--- libreswan-3.12-orig/programs/pluto/ikev1_prf.c 1969-12-31 19:00:00.000000000 -0500 ++++ libreswan-3.12/programs/pluto/ikev1_prf.c 2015-05-06 11:45:32.923301452 -0400 +@@ -0,0 +1,348 @@ ++/* ++ * Calculate IKEv1 prf and keying material, for libreswan ++ * ++ * Copyright (C) 2007 Michael C. Richardson ++ * Copyright (C) 2010 Paul Wouters ++ * Copyright (C) 2013 D. Hugh Redelmeier ++ * Copyright (C) 2015 Andrew Cagney ++ * ++ * 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. See . ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ */ ++ ++#include ++#include ++ ++#include "libreswan.h" ++#include "lswlog.h" ++#include "constants.h" ++#include "defs.h" ++#include "sysqueue.h" ++#include "crypto.h" ++#include "crypt_dh.h" ++#include "crypt_prf.h" ++#include "ikev1_prf.h" ++#include "ike_alg.h" ++#include "packet.h" ++#include "pluto_crypt.h" ++#include "crypt_symkey.h" ++ ++/* ++ * Compute: SKEYID = prf(Ni_b | Nr_b, g^xy) ++ * ++ * MUST BE THREAD-SAFE ++ */ ++PK11SymKey *ikev1_signature_skeyid(const struct hash_desc *hasher, ++ const chunk_t Ni, ++ const chunk_t Nr, ++ /*const*/ PK11SymKey *dh_secret /* NSS doesn't do const */) ++{ ++ struct crypt_prf *prf = crypt_prf_init("SKEYID sig", hasher, dh_secret); ++ /* key = Ni|Nr */ ++ crypt_prf_init_chunk("Ni", prf, Ni); ++ crypt_prf_init_chunk("Nr", prf, Nr); ++ /* seed = g^xy */ ++ crypt_prf_update(prf); ++ crypt_prf_update_symkey("g^xy", prf, dh_secret); ++ /* generate */ ++ return crypt_prf_final(prf); ++} ++ ++/* ++ * Compute: SKEYID = prf(pre-shared-key, Ni_b | Nr_b) ++ */ ++PK11SymKey *ikev1_pre_shared_key_skeyid(const struct hash_desc *hasher, ++ chunk_t pre_shared_key, ++ chunk_t Ni, chunk_t Nr, ++ PK11SymKey *scratch) ++{ ++ struct crypt_prf *prf = crypt_prf_init("SKEYID psk", hasher, scratch); ++ /* key = pre-shared-key */ ++ crypt_prf_init_chunk("psk", prf, pre_shared_key); ++ /* seed = Ni_b | Nr_b */ ++ crypt_prf_update(prf); ++ crypt_prf_update_chunk("Ni", prf, Ni); ++ crypt_prf_update_chunk("Nr", prf, Nr); ++ /* generate */ ++ return crypt_prf_final(prf); ++} ++ ++/* ++ * SKEYID_d = prf(SKEYID, g^xy | CKY-I | CKY-R | 0) ++ */ ++PK11SymKey *ikev1_skeyid_d(const struct hash_desc *hasher, ++ PK11SymKey *skeyid, ++ PK11SymKey *dh_secret, ++ chunk_t cky_i, chunk_t cky_r) ++{ ++ struct crypt_prf *prf = crypt_prf_init("SKEYID_d", hasher, dh_secret); ++ /* key = SKEYID */ ++ crypt_prf_init_symkey("SKEYID", prf, skeyid); ++ /* seed = g^xy | CKY-I | CKY-R | 0 */ ++ crypt_prf_update(prf); ++ crypt_prf_update_symkey("g^xy", prf, dh_secret); ++ crypt_prf_update_chunk("CKI_i", prf, cky_i); ++ crypt_prf_update_chunk("CKI_r", prf, cky_r); ++ crypt_prf_update_byte("0", prf, 0); ++ /* generate */ ++ return crypt_prf_final(prf); ++} ++ ++/* ++ * SKEYID_a = prf(SKEYID, SKEYID_d | g^xy | CKY-I | CKY-R | 1) ++ */ ++PK11SymKey *ikev1_skeyid_a(const struct hash_desc *hasher, ++ PK11SymKey *skeyid, ++ PK11SymKey *skeyid_d, PK11SymKey *dh_secret, ++ chunk_t cky_i, chunk_t cky_r) ++{ ++ struct crypt_prf *prf = crypt_prf_init("SKEYID_a", hasher, dh_secret); ++ /* key = SKEYID */ ++ crypt_prf_init_symkey("SKEYID", prf, skeyid); ++ /* seed = SKEYID_d | g^xy | CKY-I | CKY-R | 1 */ ++ crypt_prf_update(prf); ++ crypt_prf_update_symkey("SKEYID_d", prf, skeyid_d); ++ crypt_prf_update_symkey("g^xy", prf, dh_secret); ++ crypt_prf_update_chunk("CKI_i", prf, cky_i); ++ crypt_prf_update_chunk("CKI_r", prf, cky_r); ++ crypt_prf_update_byte("1", prf, 1); ++ /* generate */ ++ return crypt_prf_final(prf); ++} ++ ++/* ++ * SKEYID_e = prf(SKEYID, SKEYID_a | g^xy | CKY-I | CKY-R | 2) ++ */ ++PK11SymKey *ikev1_skeyid_e(const struct hash_desc *hasher, ++ PK11SymKey *skeyid, ++ PK11SymKey *skeyid_a, PK11SymKey *dh_secret, ++ chunk_t cky_i, chunk_t cky_r) ++{ ++ struct crypt_prf *prf = crypt_prf_init("SKEYID_e", hasher, dh_secret); ++ /* key = SKEYID */ ++ crypt_prf_init_symkey("SKEYID", prf, skeyid); ++ /* seed = SKEYID_a | g^xy | CKY-I | CKY-R | 2 */ ++ crypt_prf_update(prf); ++ crypt_prf_update_symkey("SKEYID_a", prf, skeyid_a); ++ crypt_prf_update_symkey("g^xy", prf, dh_secret); ++ crypt_prf_update_chunk("CKI_i", prf, cky_i); ++ crypt_prf_update_chunk("CKI_r", prf, cky_r); ++ crypt_prf_update_byte("2", prf, 2); ++ /* generate */ ++ return crypt_prf_final(prf); ++} ++ ++static PK11SymKey *appendix_b_keymat_e(const struct hash_desc *hasher, ++ const struct encrypt_desc *encrypter, ++ PK11SymKey *skeyid_e, ++ unsigned required_keymat) ++{ ++ if (PK11_GetKeyLength(skeyid_e) >= required_keymat) { ++ return encrypt_key_from_symkey_bytes(skeyid_e, encrypter, 0, ++ required_keymat); ++ } ++ /* K1 = prf(skeyid_e, 0) */ ++ PK11SymKey *keymat; ++ { ++ struct crypt_prf *prf = crypt_prf_init("appendix_b", ++ hasher, skeyid_e); ++ crypt_prf_init_symkey("SKEYID_e", prf, skeyid_e); ++ crypt_prf_update(prf); ++ crypt_prf_update_byte("0", prf, 0); ++ keymat = crypt_prf_final(prf); ++ } ++ ++ /* make a copy to keep things easy */ ++ PK11SymKey *old_k = key_from_symkey_bytes(keymat, 0, PK11_GetKeyLength(keymat)); ++ while (PK11_GetKeyLength(keymat) < required_keymat) { ++ /* Kn = prf(skeyid_e, Kn-1) */ ++ struct crypt_prf *prf = crypt_prf_init("SKEYID_e", hasher, skeyid_e); ++ crypt_prf_init_symkey("SKEYID_e", prf, skeyid_e); ++ crypt_prf_update(prf); ++ crypt_prf_update_symkey("old_k", prf, old_k); ++ PK11SymKey *new_k = crypt_prf_final(prf); ++ append_symkey_symkey(hasher, &keymat, new_k); ++ free_any_symkey("old_k#N", &old_k); ++ old_k = new_k; ++ } ++ free_any_symkey("old_k#final", &old_k); ++ PK11SymKey *cryptkey = encrypt_key_from_symkey_bytes(keymat, encrypter, 0, ++ required_keymat); ++ free_any_symkey("keymat", &keymat); ++ return cryptkey; ++} ++ ++/* Generate the SKEYID_* and new IV ++ * See draft-ietf-ipsec-ike-01.txt 4.1 ++ */ ++/* MUST BE THREAD-SAFE */ ++static void calc_skeyids_iv(struct pcr_skeyid_q *skq, ++ /*const*/ PK11SymKey *shared, /* NSS doesn't do const */ ++ const size_t keysize, /* = st->st_oakley.enckeylen/BITS_PER_BYTE; */ ++ PK11SymKey **skeyid_out, /* output */ ++ PK11SymKey **skeyid_d_out, /* output */ ++ PK11SymKey **skeyid_a_out, /* output */ ++ PK11SymKey **skeyid_e_out, /* output */ ++ chunk_t *new_iv, /* output */ ++ PK11SymKey **enc_key_out /* output */ ++ ) ++{ ++ oakley_auth_t auth = skq->auth; ++ oakley_hash_t hash = skq->prf_hash; ++ const struct hash_desc *hasher = crypto_get_hasher(hash); ++ chunk_t ni; ++ chunk_t nr; ++ chunk_t gi; ++ chunk_t gr; ++ chunk_t icookie; ++ chunk_t rcookie; ++ const struct encrypt_desc *encrypter = skq->encrypter; ++ ++ /* this doesn't allocate any memory */ ++ setchunk_from_wire(gi, skq, &skq->gi); ++ setchunk_from_wire(gr, skq, &skq->gr); ++ setchunk_from_wire(ni, skq, &skq->ni); ++ setchunk_from_wire(nr, skq, &skq->nr); ++ setchunk_from_wire(icookie, skq, &skq->icookie); ++ setchunk_from_wire(rcookie, skq, &skq->rcookie); ++ ++ /* Generate the SKEYID */ ++ PK11SymKey *skeyid; ++ switch (auth) { ++ case OAKLEY_PRESHARED_KEY: ++ { ++ chunk_t pss; ++ ++ setchunk_from_wire(pss, skq, &skq->pss); ++ skeyid = ikev1_pre_shared_key_skeyid(hasher, pss, ++ ni, nr, shared); ++ } ++ break; ++ ++ case OAKLEY_RSA_SIG: ++ skeyid = ikev1_signature_skeyid(hasher, ni, nr, shared); ++ break; ++ ++ /* Not implemented */ ++ case OAKLEY_DSS_SIG: ++ case OAKLEY_RSA_ENC: ++ case OAKLEY_RSA_REVISED_MODE: ++ case OAKLEY_ECDSA_P256: ++ case OAKLEY_ECDSA_P384: ++ case OAKLEY_ECDSA_P521: ++ default: ++ bad_case(auth); ++ } ++ ++ /* generate SKEYID_* from SKEYID */ ++ PK11SymKey *skeyid_d = ikev1_skeyid_d(hasher, skeyid, shared, ++ icookie, rcookie); ++ PK11SymKey *skeyid_a = ikev1_skeyid_a(hasher, skeyid, skeyid_d, ++ shared, icookie, rcookie); ++ PK11SymKey *skeyid_e = ikev1_skeyid_e(hasher, skeyid, skeyid_a, ++ shared, icookie, rcookie); ++ ++ PK11SymKey *enc_key = appendix_b_keymat_e(hasher, encrypter, ++ skeyid_e, keysize); ++ ++ *skeyid_out = skeyid; ++ *skeyid_d_out = skeyid_d; ++ *skeyid_a_out = skeyid_a; ++ *skeyid_e_out = skeyid_e; ++ *enc_key_out = enc_key; ++ ++ DBG(DBG_CRYPT, DBG_log("NSS: pointers skeyid_d %p, skeyid_a %p, skeyid_e %p, enc_key %p", ++ skeyid_d, skeyid_a, skeyid_e, enc_key)); ++ ++ /* generate IV */ ++ { ++ union hash_ctx hash_ctx; ++ ++ new_iv->len = hasher->hash_digest_len; ++ new_iv->ptr = alloc_bytes(new_iv->len, "calculated new iv"); ++ ++ DBG(DBG_CRYPT, { ++ DBG_dump_chunk("DH_i:", gi); ++ DBG_dump_chunk("DH_r:", gr); ++ }); ++ hasher->hash_init(&hash_ctx); ++ hasher->hash_update(&hash_ctx, gi.ptr, gi.len); ++ hasher->hash_update(&hash_ctx, gr.ptr, gr.len); ++ hasher->hash_final(new_iv->ptr, &hash_ctx); ++ DBG(DBG_CRYPT, DBG_log("end of IV generation")); ++ } ++} ++ ++/* MUST BE THREAD-SAFE */ ++void calc_dh_iv(struct pluto_crypto_req *r) ++{ ++ struct pcr_skeyid_r *skr = &r->pcr_d.dhr; ++ struct pcr_skeyid_q dhq; ++ const struct oakley_group_desc *group; ++ PK11SymKey *shared; ++ chunk_t g; ++ SECKEYPrivateKey *ltsecret; ++ PK11SymKey ++ *skeyid, ++ *skeyid_d, ++ *skeyid_a, ++ *skeyid_e, ++ *enc_key; ++ chunk_t new_iv; ++ SECKEYPublicKey *pubk; ++ ++ /* copy the request, since the reply will re-use the memory of the r->pcr_d.dhq */ ++ memcpy(&dhq, &r->pcr_d.dhq, sizeof(r->pcr_d.dhq)); ++ ++ /* clear out the reply */ ++ zero(skr); ++ INIT_WIRE_ARENA(*skr); ++ ++ group = lookup_group(dhq.oakley_group); ++ passert(group != NULL); ++ ++ ltsecret = dhq.secret; ++ pubk = dhq.pubk; ++ ++ /* now calculate the (g^x)(g^y) --- ++ * need gi on responder, gr on initiator ++ */ ++ ++ setchunk_from_wire(g, &dhq, dhq.role == O_RESPONDER ? &dhq.gi : &dhq.gr); ++ ++ DBG(DBG_CRYPT, ++ DBG_dump_chunk("peer's g: ", g)); ++ ++ shared = calc_dh_shared(g, ltsecret, group, pubk); ++ ++ zero(&new_iv); ++ ++ /* okay, so now calculate IV */ ++ calc_skeyids_iv(&dhq, ++ shared, ++ dhq.key_size, ++ &skeyid, ++ &skeyid_d, ++ &skeyid_a, ++ &skeyid_e, ++ &new_iv, ++ &enc_key); ++ ++ skr->shared = shared; ++ skr->skeyid = skeyid; ++ skr->skeyid_d = skeyid_d; ++ skr->skeyid_a = skeyid_a; ++ skr->skeyid_e = skeyid_e; ++ skr->enc_key = enc_key; ++ ++ ++ WIRE_CLONE_CHUNK(*skr, new_iv, new_iv); ++ freeanychunk(new_iv); ++} +diff -Naur libreswan-3.12-orig/programs/pluto/ikev1_prf.h libreswan-3.12/programs/pluto/ikev1_prf.h +--- libreswan-3.12-orig/programs/pluto/ikev1_prf.h 1969-12-31 19:00:00.000000000 -0500 ++++ libreswan-3.12/programs/pluto/ikev1_prf.h 2015-05-06 11:45:32.923301452 -0400 +@@ -0,0 +1,66 @@ ++/* ++ * Calculate IKEv1 prf and keying material, for libreswan ++ * ++ * Copyright (C) 2007 Michael C. Richardson ++ * Copyright (C) 2010 Paul Wouters ++ * Copyright (C) 2013 D. Hugh Redelmeier ++ * Copyright (C) 2015 Andrew Cagney ++ * ++ * 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. See . ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ */ ++ ++#ifndef ikev1_prf_h ++#define ikev1_prf_h ++ ++/* ++ * IKE SA SKEYID for authentication ++ * ++ * Be warned, this is not DSS (even though NIST call it Digital ++ * Signature Algorithm). It is used by RSA-SIG. ++ */ ++PK11SymKey *ikev1_signature_skeyid(const struct hash_desc *hasher, ++ const chunk_t Ni_b, const chunk_t Nr_b, ++ PK11SymKey *dh_secret); ++ ++PK11SymKey *ikev1_pre_shared_key_skeyid(const struct hash_desc *hasher, ++ chunk_t pre_shared_key, ++ chunk_t Ni_b, chunk_t Nr_b, ++ PK11SymKey *scratch); ++ ++/* ++ * Authenticated keying material. ++ * ++ * Perhaps this should just return a struct? ++ */ ++ ++PK11SymKey *ikev1_skeyid_d(const struct hash_desc *hasher, ++ PK11SymKey *skeyid, ++ PK11SymKey *dh_secret, ++ chunk_t cky_i, chunk_t cky_r); ++ ++PK11SymKey *ikev1_skeyid_a(const struct hash_desc *hasher, ++ PK11SymKey *skeyid, ++ PK11SymKey *skeyid_d, PK11SymKey *dh_secret, ++ chunk_t cky_i, chunk_t cky_r); ++ ++PK11SymKey *ikev1_skeyid_e(const struct hash_desc *hasher, ++ PK11SymKey *skeyid, ++ PK11SymKey *skeyid_a, PK11SymKey *dh_secret, ++ chunk_t cky_i, chunk_t cky_r); ++ ++/* ++ * Old way. ++ */ ++struct pluto_crypto_req; ++ ++void calc_dh_iv(struct pluto_crypto_req *r); ++ ++#endif +diff -Naur libreswan-3.12-orig/programs/pluto/ikev1_quick.c libreswan-3.12/programs/pluto/ikev1_quick.c +--- libreswan-3.12-orig/programs/pluto/ikev1_quick.c 2014-11-06 22:52:50.000000000 -0500 ++++ libreswan-3.12/programs/pluto/ikev1_quick.c 2015-05-06 11:45:32.923301452 -0400 +@@ -70,6 +70,7 @@ + #include "plutoalg.h" + + #include "pluto_crypt.h" ++#include "crypt_prf.h" + #include "ikev1.h" + #include "ikev1_quick.h" + #include "ikev1_continuations.h" +@@ -470,13 +471,8 @@ + + for (i = 0;; ) { + if (st->st_shared_nss != NULL) { +- /* PFS: include the g^xy */ +- SECStatus s; +- +- s = PK11_DigestKey(ctx_me.ctx_nss, st->st_shared_nss); +- passert(s == SECSuccess); +- s = PK11_DigestKey(ctx_peer.ctx_nss, st->st_shared_nss); +- passert(s == SECSuccess); ++ crypt_prf_update_symkey("g^xy", ctx_me.prf, st->st_shared_nss); ++ crypt_prf_update_symkey("g^xy", ctx_peer.prf, st->st_shared_nss); + } + hmac_update(&ctx_me, &protoid, sizeof(protoid)); + hmac_update(&ctx_peer, &protoid, sizeof(protoid)); +diff -Naur libreswan-3.12-orig/programs/pluto/ikev2_crypto.c libreswan-3.12/programs/pluto/ikev2_crypto.c +--- libreswan-3.12-orig/programs/pluto/ikev2_crypto.c 2014-11-06 22:52:50.000000000 -0500 ++++ libreswan-3.12/programs/pluto/ikev2_crypto.c 2015-05-06 11:45:32.924301463 -0400 +@@ -49,15 +49,16 @@ + #include "crypto.h" /* requires sha1.h and md5.h */ + #include "demux.h" + #include "ikev2.h" +-#include "ikev2_prfplus.h" ++#include "ikev2_prf.h" + #include "ike_alg.h" + #include "alg_info.h" + #include "kernel_alg.h" ++#include "crypt_symkey.h" ++#include "ikev2_prf.h" ++ + + void ikev2_derive_child_keys(struct state *st, enum phase1_role role) + { +- struct v2prf_stuff childsacalc; +- + chunk_t ikeymat, rkeymat; + /* ??? note assumption that AH and ESP cannot be combined */ + struct ipsec_proto_info *ipi = +@@ -81,17 +82,6 @@ + passert(ei != NULL); + ipi->attrs.transattrs.ei = ei; + +- zero(&childsacalc); +- childsacalc.prf_hasher = st->st_oakley.prf_hasher; +- +- setchunk(childsacalc.ni, st->st_ni.ptr, st->st_ni.len); +- setchunk(childsacalc.nr, st->st_nr.ptr, st->st_nr.len); +- childsacalc.spii.len = 0; +- childsacalc.spir.len = 0; +- +- childsacalc.counter[0] = 1; +- childsacalc.skeyseed = st->st_skey_d_nss; +- + /* ??? no account is taken of AH */ + /* transid is same as esp_ealg_id */ + switch (ei->transid) { +@@ -150,11 +140,20 @@ + * salt (AES_GCM_SALT_BYTES) + */ + +- v2genbytes(&ikeymat, ipi->keymat_len, +- "initiator keys", &childsacalc); +- +- v2genbytes(&rkeymat, ipi->keymat_len, +- "responder keys", &childsacalc); ++ chunk_t ni; ++ chunk_t nr; ++ setchunk(ni, st->st_ni.ptr, st->st_ni.len); ++ setchunk(nr, st->st_nr.ptr, st->st_nr.len); ++ ++ PK11SymKey *keymat = ikev2_child_sa_keymat(st->st_oakley.prf_hasher, ++ st->st_skey_d_nss, ++ NULL/*dh*/, ni, nr, ++ ipi->keymat_len * 2); ++ ikeymat = chunk_from_symkey_bytes("initiator keys", keymat, ++ 0, ipi->keymat_len); ++ rkeymat = chunk_from_symkey_bytes("initiator keys", keymat, ++ ipi->keymat_len, ipi->keymat_len); ++ free_any_symkey("keymat", &keymat); + + if (role != O_INITIATOR) { + DBG(DBG_CRYPT, { +diff -Naur libreswan-3.12-orig/programs/pluto/ikev2_prf.c libreswan-3.12/programs/pluto/ikev2_prf.c +--- libreswan-3.12-orig/programs/pluto/ikev2_prf.c 1969-12-31 19:00:00.000000000 -0500 ++++ libreswan-3.12/programs/pluto/ikev2_prf.c 2015-05-06 11:45:32.924301463 -0400 +@@ -0,0 +1,405 @@ ++/* ++ * Calculate IKEv2 prf and keying material, for libreswan ++ * ++ * Copyright (C) 2007 Michael C. Richardson ++ * Copyright (C) 2010 Paul Wouters ++ * Copyright (C) 2013 D. Hugh Redelmeier ++ * Copyright (C) 2015 Andrew Cagney ++ * ++ * 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. See . ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * This code was developed with the support of Redhat corporation. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "sysdep.h" ++#include "constants.h" ++#include "defs.h" ++#include "packet.h" ++#include "demux.h" ++#include "crypto.h" ++#include "rnd.h" ++#include "state.h" ++#include "pluto_crypt.h" ++#include "lswlog.h" ++#include "log.h" ++#include "timer.h" ++#include "ike_alg.h" ++#include "id.h" ++#include "secrets.h" ++#include "keys.h" ++#include "ikev2_prf.h" ++#include "crypt_prf.h" ++#include "crypt_dh.h" ++#include "crypt_symkey.h" ++ ++/* ++ * IKEv2 - RFC4306 2.14 SKEYSEED - calculation. ++ */ ++ ++/* MUST BE THREAD-SAFE */ ++static void calc_skeyseed_v2(struct pcr_skeyid_q *skq, ++ PK11SymKey *shared, ++ const size_t key_size, ++ const size_t salt_size, ++ PK11SymKey **skeyseed_out, ++ PK11SymKey **SK_d_out, ++ PK11SymKey **SK_ai_out, ++ PK11SymKey **SK_ar_out, ++ PK11SymKey **SK_ei_out, ++ PK11SymKey **SK_er_out, ++ PK11SymKey **SK_pi_out, ++ PK11SymKey **SK_pr_out, ++ chunk_t *initiator_salt_out, ++ chunk_t *responder_salt_out ++ ) ++ ++{ ++ DBG(DBG_CRYPT, DBG_log("NSS: Started key computation")); ++ ++ PK11SymKey ++ *skeyseed_k, ++ *SK_d_k, ++ *SK_ai_k, ++ *SK_ar_k, ++ *SK_ei_k, ++ *SK_er_k, ++ *SK_pi_k, ++ *SK_pr_k; ++ chunk_t initiator_salt; ++ chunk_t responder_salt; ++ ++ ++ ++ /* this doesn't take any memory, it's just moving pointers around */ ++ chunk_t ni; ++ chunk_t nr; ++ chunk_t spii; ++ chunk_t spir; ++ setchunk_from_wire(ni, skq, &skq->ni); ++ setchunk_from_wire(nr, skq, &skq->nr); ++ setchunk_from_wire(spii, skq, &skq->icookie); ++ setchunk_from_wire(spir, skq, &skq->rcookie); ++ ++ DBG(DBG_CONTROLMORE, ++ DBG_log("calculating skeyseed using prf=%s integ=%s cipherkey-size=%zu salt-size=%zu", ++ enum_name(&ikev2_trans_type_prf_names, skq->prf_hash), ++ enum_name(&ikev2_trans_type_integ_names, skq->integ_hash), ++ key_size, salt_size)); ++ ++ const struct hash_desc *prf_hasher = (struct hash_desc *) ++ ikev2_alg_find(IKE_ALG_HASH, skq->prf_hash); ++ passert(prf_hasher != NULL); ++ ++ const struct encrypt_desc *encrypter = skq->encrypter; ++ passert(encrypter != NULL); ++ ++ /* generate SKEYSEED from key=(Ni|Nr), hash of shared */ ++ skeyseed_k = ikev2_ike_sa_skeyseed(prf_hasher, ni, nr, shared); ++ passert(skeyseed_k != NULL); ++ ++ /* now we have to generate the keys for everything */ ++ ++ /* need to know how many bits to generate */ ++ /* SK_d needs PRF hasher key bytes */ ++ /* SK_p needs PRF hasher*2 key bytes */ ++ /* SK_e needs key_size*2 key bytes */ ++ /* ..._salt needs salt_size*2 bytes */ ++ /* SK_a needs integ's key size*2 bytes */ ++ ++ int skd_bytes = prf_hasher->hash_key_size; ++ int skp_bytes = prf_hasher->hash_key_size; ++ const struct hash_desc *integ_hasher = ++ (struct hash_desc *)ikev2_alg_find(IKE_ALG_INTEG, skq->integ_hash); ++ int integ_size = integ_hasher != NULL ? integ_hasher->hash_key_size : 0; ++ size_t total_keysize = skd_bytes + 2*skp_bytes + 2*key_size + 2*salt_size + 2*integ_size; ++ PK11SymKey *finalkey = ikev2_ike_sa_keymat(prf_hasher, skeyseed_k, ++ ni, nr, spii, spir, ++ total_keysize); ++ ++ size_t next_byte = 0; ++ ++ SK_d_k = key_from_symkey_bytes(finalkey, next_byte, skd_bytes); ++ next_byte += skd_bytes; ++ ++ SK_ai_k = key_from_symkey_bytes(finalkey, next_byte, integ_size); ++ next_byte += integ_size; ++ ++ SK_ar_k = key_from_symkey_bytes(finalkey, next_byte, integ_size); ++ next_byte += integ_size; ++ ++ /* The encryption key and salt are extracted together. */ ++ SK_ei_k = encrypt_key_from_symkey_bytes(finalkey, encrypter, ++ next_byte, key_size); ++ next_byte += key_size; ++ initiator_salt = chunk_from_symkey_bytes("initiator salt", finalkey, ++ next_byte, salt_size); ++ next_byte += salt_size; ++ ++ /* The encryption key and salt are extracted together. */ ++ SK_er_k = encrypt_key_from_symkey_bytes(finalkey, encrypter, ++ next_byte, key_size); ++ next_byte += key_size; ++ responder_salt = chunk_from_symkey_bytes("responder salt", finalkey, ++ next_byte, salt_size); ++ next_byte += salt_size; ++ ++ SK_pi_k = key_from_symkey_bytes(finalkey, next_byte, skp_bytes); ++ ++ ++ ++ next_byte += skp_bytes; ++ ++ SK_pr_k = key_from_symkey_bytes(finalkey, next_byte, skp_bytes); ++ ++ ++ ++ next_byte += skp_bytes; ++ ++ DBG(DBG_CRYPT, ++ DBG_log("NSS ikev2: finished computing individual keys for IKEv2 SA")); ++ free_any_symkey("finalkey", &finalkey); ++ ++ *skeyseed_out = skeyseed_k; ++ *SK_d_out = SK_d_k; ++ *SK_ai_out = SK_ai_k; ++ *SK_ar_out = SK_ar_k; ++ *SK_ei_out = SK_ei_k; ++ *SK_er_out = SK_er_k; ++ *SK_pi_out = SK_pi_k; ++ *SK_pr_out = SK_pr_k; ++ *initiator_salt_out = initiator_salt; ++ *responder_salt_out = responder_salt; ++ ++ ++ ++ DBG(DBG_PRIVATE, ++ DBG_log("calc_skeyseed_v2 pointers: shared %p, skeyseed %p, SK_d %p, SK_ai %p, SK_ar %p, SK_ei %p, SK_er %p, SK_pi %p, SK_pr %p", ++ shared, skeyseed_k, SK_d_k, SK_ai_k, SK_ar_k, SK_ei_k, SK_er_k, SK_pi_k, SK_pr_k); ++ DBG_dump_chunk("calc_skeyseed_v2 initiator salt", initiator_salt); ++ DBG_dump_chunk("calc_skeyseed_v2 responder salt", responder_salt); ++ ); ++ ++} ++ ++/* MUST BE THREAD-SAFE */ ++void calc_dh_v2(struct pluto_crypto_req *r) ++{ ++ struct pcr_skeycalc_v2_r *skr = &r->pcr_d.dhv2; ++ struct pcr_skeyid_q dhq; ++ const struct oakley_group_desc *group; ++ PK11SymKey *shared; ++ chunk_t g; ++ SECKEYPrivateKey *ltsecret; ++ PK11SymKey *skeyseed; ++ PK11SymKey ++ *SK_d, ++ *SK_ai, ++ *SK_ar, ++ *SK_ei, ++ *SK_er, ++ *SK_pi, ++ *SK_pr; ++ chunk_t initiator_salt; ++ chunk_t responder_salt; ++ ++ ++ SECKEYPublicKey *pubk; ++ ++ /* copy the request, since the reply will re-use the memory of the r->pcr_d.dhq */ ++ memcpy(&dhq, &r->pcr_d.dhq, sizeof(r->pcr_d.dhq)); ++ ++ /* clear out the reply */ ++ zero(skr); ++ INIT_WIRE_ARENA(*skr); ++ ++ group = lookup_group(dhq.oakley_group); ++ passert(group != NULL); ++ ++ ltsecret = dhq.secret; ++ pubk = dhq.pubk; ++ ++ /* now calculate the (g^x)(g^y) --- need gi on responder, gr on initiator */ ++ ++ setchunk_from_wire(g, &dhq, dhq.role == O_RESPONDER ? &dhq.gi : &dhq.gr); ++ ++ DBG(DBG_CRYPT, DBG_dump_chunk("peer's g: ", g)); ++ ++ shared = calc_dh_shared(g, ltsecret, group, pubk); ++ ++ /* okay, so now all the shared key material */ ++ calc_skeyseed_v2(&dhq, /* input */ ++ shared, /* input */ ++ dhq.key_size, /* input */ ++ dhq.salt_size, /* input */ ++ ++ &skeyseed, /* output */ ++ &SK_d, /* output */ ++ &SK_ai, /* output */ ++ &SK_ar, /* output */ ++ &SK_ei, /* output */ ++ &SK_er, /* output */ ++ &SK_pi, /* output */ ++ &SK_pr, /* output */ ++ &initiator_salt, /* output */ ++ &responder_salt /* output */ ++ ); ++ ++ ++ skr->shared = shared; ++ skr->skeyseed = skeyseed; ++ skr->skeyid_d = SK_d; ++ skr->skeyid_ai = SK_ai; ++ skr->skeyid_ar = SK_ar; ++ skr->skeyid_ei = SK_ei; ++ skr->skeyid_er = SK_er; ++ skr->skeyid_pi = SK_pi; ++ skr->skeyid_pr = SK_pr; ++ skr->skey_initiator_salt = initiator_salt; ++ skr->skey_responder_salt = responder_salt; ++ ++ ++} ++ ++static PK11SymKey *ikev2_prfplus(const struct hash_desc *hasher, ++ PK11SymKey *key, PK11SymKey *seed, ++ size_t required_keymat) ++{ ++ uint8_t count = 1; ++ ++ /* T1(prfplus) = prf(KEY, SEED|1) */ ++ PK11SymKey *prfplus; ++ { ++ struct crypt_prf *prf = crypt_prf_init("prf+0", ++ hasher, key); ++ crypt_prf_init_symkey("key", prf, key); ++ crypt_prf_update(prf); ++ crypt_prf_update_symkey("seed", prf, seed); ++ crypt_prf_update_byte("1++", prf, count++); ++ prfplus = crypt_prf_final(prf); ++ } ++ ++ /* make a copy to keep things easy */ ++ PK11SymKey *old_t = key_from_symkey_bytes(prfplus, 0, PK11_GetKeyLength(prfplus)); ++ while (PK11_GetKeyLength(prfplus) < required_keymat) { ++ /* Tn = prf(KEY, Tn-1|SEED|n) */ ++ struct crypt_prf *prf = crypt_prf_init("prf+N", ++ hasher, key); ++ crypt_prf_init_symkey("key", prf, key); ++ crypt_prf_update(prf); ++ crypt_prf_update_symkey("old_t", prf, old_t); ++ crypt_prf_update_symkey("seed", prf, seed); ++ crypt_prf_update_byte("N++", prf, count++); ++ PK11SymKey *new_t = crypt_prf_final(prf); ++ append_symkey_symkey(hasher, &prfplus, new_t); ++ free_any_symkey("old_t[N]", &old_t); ++ old_t = new_t; ++ } ++ free_any_symkey("old_t[final]", &old_t); ++ return prfplus; ++} ++ ++/* ++ * SKEYSEED = prf(Ni | Nr, g^ir) ++ */ ++PK11SymKey *ikev2_ike_sa_skeyseed(const struct hash_desc *hasher, ++ const chunk_t Ni, const chunk_t Nr, ++ PK11SymKey *dh_secret) ++{ ++ struct crypt_prf *prf = crypt_prf_init("ike sa SKEYSEED", ++ hasher, dh_secret); ++ /* key = Ni|Nr */ ++ crypt_prf_init_chunk("Ni", prf, Ni); ++ crypt_prf_init_chunk("Nr", prf, Nr); ++ /* seed = g^ir */ ++ crypt_prf_update(prf); ++ /* generate */ ++ crypt_prf_update_symkey("g^ir", prf, dh_secret); ++ return crypt_prf_final(prf); ++} ++ ++/* ++ * SKEYSEED = prf(SK_d (old), g^ir (new) | Ni | Nr) ++ */ ++PK11SymKey *ikev2_ike_sa_rekey_skeyseed(const struct hash_desc *hasher, ++ PK11SymKey *SK_d_old, ++ PK11SymKey *new_dh_secret, ++ const chunk_t Ni, const chunk_t Nr) ++{ ++ struct crypt_prf *prf = crypt_prf_init("ike sa rekey skeyseed", ++ hasher, new_dh_secret); ++ /* key = SK_d (old) */ ++ crypt_prf_init_symkey("SK_d (old)", prf, SK_d_old); ++ /* seed: g^ir (new) | Ni | Nr) */ ++ crypt_prf_update(prf); ++ crypt_prf_update_symkey("g^ir (new)", prf, new_dh_secret); ++ crypt_prf_update_chunk("Ni", prf, Ni); ++ crypt_prf_update_chunk("Nr", prf, Nr); ++ /* generate */ ++ return crypt_prf_final(prf); ++} ++ ++/* ++ * Compute: prf+ (SKEYSEED, Ni | Nr | SPIi | SPIr) ++ */ ++PK11SymKey *ikev2_ike_sa_keymat(const struct hash_desc *hasher, ++ PK11SymKey *skeyseed, ++ const chunk_t Ni, const chunk_t Nr, ++ const chunk_t SPIi, const chunk_t SPIr, ++ size_t required_bytes) ++{ ++ PK11SymKey *data = symkey_from_chunk(skeyseed, Ni); ++ append_symkey_chunk(hasher, &data, Nr); ++ append_symkey_chunk(hasher, &data, SPIi); ++ append_symkey_chunk(hasher, &data, SPIr); ++ PK11SymKey *prfplus = ikev2_prfplus(hasher, skeyseed, data, ++ required_bytes); ++ free_any_symkey(__func__, &data); ++ return prfplus; ++} ++ ++/* ++ * Compute: prf+(SK_d, [ g^ir (new) | ] Ni | Nr) ++ */ ++PK11SymKey *ikev2_child_sa_keymat(const struct hash_desc *hasher, ++ PK11SymKey *SK_d, ++ PK11SymKey *new_dh_secret, ++ const chunk_t Ni, const chunk_t Nr, ++ size_t required_bytes) ++{ ++ PK11SymKey *data; ++ if (new_dh_secret == NULL) { ++ data = symkey_from_chunk(SK_d, Ni); ++ append_symkey_chunk(hasher, &data, Nr); ++ } else { ++ data = concat_symkey_chunk(hasher, new_dh_secret, Ni); ++ append_symkey_chunk(hasher, &data, Nr); ++ } ++ PK11SymKey *prfplus = ikev2_prfplus(hasher, SK_d, data, ++ required_bytes); ++ free_any_symkey(__func__, &data); ++ return prfplus; ++} +diff -Naur libreswan-3.12-orig/programs/pluto/ikev2_prf.h libreswan-3.12/programs/pluto/ikev2_prf.h +--- libreswan-3.12-orig/programs/pluto/ikev2_prf.h 1969-12-31 19:00:00.000000000 -0500 ++++ libreswan-3.12/programs/pluto/ikev2_prf.h 2015-05-06 11:45:32.924301463 -0400 +@@ -0,0 +1,58 @@ ++/* ++ * Calculate IKEv2 prf and keying material, for libreswan ++ * ++ * Copyright (C) 2007 Michael C. Richardson ++ * Copyright (C) 2010 Paul Wouters ++ * Copyright (C) 2013 D. Hugh Redelmeier ++ * Copyright (C) 2015 Andrew Cagney ++ * ++ * 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. See . ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ */ ++ ++#ifndef _IKEV2_PRF_H ++#define _IKEV2_PRF_H ++ ++/* ++ * IKE SA ++ */ ++PK11SymKey *ikev2_ike_sa_skeyseed(const struct hash_desc *prf_hasher, ++ const chunk_t Ni, const chunk_t Nr, ++ PK11SymKey *dh_secret); ++ ++PK11SymKey *ikev2_ike_sa_rekey_skeyseed(const struct hash_desc *prf_hasher, ++ PK11SymKey *old_SK_d, ++ PK11SymKey *new_dh_secret, ++ const chunk_t Ni, const chunk_t Nr); ++ ++PK11SymKey *ikev2_ike_sa_keymat(const struct hash_desc *prf_hasher, ++ PK11SymKey *skeyseed, ++ const chunk_t Ni, const chunk_t Nr, ++ const chunk_t SPIi, const chunk_t SPIr, ++ size_t required_bytes); ++ ++/* ++ * Child SA ++ */ ++PK11SymKey *ikev2_child_sa_keymat(const struct hash_desc *prf_hasher, ++ PK11SymKey *SK_d, ++ PK11SymKey *new_dh_secret, ++ const chunk_t Ni, const chunk_t Nr, ++ size_t required_bytes); ++ ++/* ++ * Old way ... ++ */ ++ ++struct pluto_crypto_req; ++ ++void calc_dh_v2(struct pluto_crypto_req *r); ++ ++#endif +diff -Naur libreswan-3.12-orig/programs/pluto/ikev2_prfplus.c libreswan-3.12/programs/pluto/ikev2_prfplus.c +--- libreswan-3.12-orig/programs/pluto/ikev2_prfplus.c 2014-11-06 22:52:50.000000000 -0500 ++++ libreswan-3.12/programs/pluto/ikev2_prfplus.c 1969-12-31 19:00:00.000000000 -0500 +@@ -1,106 +0,0 @@ +-/* +- * Cryptographic helper function - calculate prf+() for ikev2 +- * +- * Copyright (C) 2007 Michael C. Richardson +- * Copyright (C) 2010 Paul Wouters +- * Copyright (C) 2013 D. Hugh Redelmeier +- * +- * 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. See . +- * +- * This program is distributed in the hope that it will be useful, but +- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +- * for more details. +- * +- * This code was developed with the support of Redhat corporation. +- * +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include +- +-#include "sysdep.h" +-#include "constants.h" +-#include "defs.h" +-#include "packet.h" +-#include "demux.h" +-#include "crypto.h" +-#include "rnd.h" +-#include "state.h" +-#include "pluto_crypt.h" +-#include "lswlog.h" +-#include "log.h" +-#include "timer.h" +-#include "ike_alg.h" +-#include "id.h" +-#include "secrets.h" +-#include "keys.h" +-#include "ikev2_prfplus.h" +- +-static void v2prfplus(struct v2prf_stuff *vps) +-{ +- struct hmac_ctx ctx; +- +- hmac_init(&ctx, vps->prf_hasher, vps->skeyseed); +- hmac_update_chunk(&ctx, vps->t); +- hmac_update_chunk(&ctx, vps->ni); +- hmac_update_chunk(&ctx, vps->nr); +- hmac_update_chunk(&ctx, vps->spii); +- hmac_update_chunk(&ctx, vps->spir); +- hmac_update(&ctx, vps->counter, 1); +- hmac_final_chunk(vps->t, "skeyseed_t1", &ctx); +- DBG(DBG_CRYPT, { +- char b[20]; +- snprintf(b, sizeof(b), "prf+[%u]:", vps->counter[0]); +- DBG_dump_chunk(b, vps->t); +- }); +- +- vps->counter[0]++; +- vps->availbytes = vps->t.len; +- vps->nextbytes = 0; +-} +- +-void v2genbytes(chunk_t *need, +- unsigned int needed, const char *name, +- struct v2prf_stuff *vps) +-{ +- u_char *target; +- +- need->ptr = alloc_bytes(needed, name); +- need->len = needed; +- target = need->ptr; +- +- while (needed > vps->availbytes) { +- if (vps->availbytes) { +- /* use any bytes which are presently in the buffer */ +- memcpy(target, &vps->t.ptr[vps->nextbytes], +- vps->availbytes); +- target += vps->availbytes; +- needed -= vps->availbytes; +- vps->availbytes = 0; +- } +- /* generate more bits into t1 */ +- v2prfplus(vps); +- } +- passert(needed <= vps->availbytes); +- +- memcpy(target, &vps->t.ptr[vps->nextbytes], needed); +- vps->availbytes -= needed; +- vps->nextbytes += needed; +-} +- +diff -Naur libreswan-3.12-orig/programs/pluto/ikev2_prfplus.h libreswan-3.12/programs/pluto/ikev2_prfplus.h +--- libreswan-3.12-orig/programs/pluto/ikev2_prfplus.h 2014-11-06 22:52:50.000000000 -0500 ++++ libreswan-3.12/programs/pluto/ikev2_prfplus.h 1969-12-31 19:00:00.000000000 -0500 +@@ -1,20 +0,0 @@ +-#ifndef _IKEV2_PRF_H +-#define _IKEV2_PRF_H +-struct v2prf_stuff { +- chunk_t t; +- const struct hash_desc *prf_hasher; +- PK11SymKey *skeyseed; +- chunk_t ni; +- chunk_t nr; +- chunk_t spii; +- chunk_t spir; +- u_char counter[1]; /* why is this an array of 1? */ +- unsigned int availbytes; +- unsigned int nextbytes; +-}; +- +-extern void v2genbytes(chunk_t *need, +- unsigned int needed, const char *name, +- struct v2prf_stuff *vps); +- +-#endif +diff -Naur libreswan-3.12-orig/programs/pluto/ikev2_psk.c libreswan-3.12/programs/pluto/ikev2_psk.c +--- libreswan-3.12-orig/programs/pluto/ikev2_psk.c 2014-11-06 22:52:50.000000000 -0500 ++++ libreswan-3.12/programs/pluto/ikev2_psk.c 2015-05-06 11:45:32.925301475 -0400 +@@ -54,12 +54,14 @@ + #include "server.h" + #include "vendor.h" + #include "keys.h" ++#include "crypt_prf.h" ++#include "crypt_symkey.h" + + #include + #include + +-static u_char psk_key_pad_str[] = "Key Pad for IKEv2"; /* 4306 2:15 */ +-static int psk_key_pad_str_len = 17; /* sizeof( psk_key_pad_str); -1 */ ++static const char psk_key_pad_str[] = "Key Pad for IKEv2"; /* 4306 2:15 */ ++static const size_t psk_key_pad_str_len = 17; /* sizeof( psk_key_pad_str); -1 */ + + static bool ikev2_calculate_psk_sighash(struct state *st, + enum phase1_role role, +@@ -71,8 +73,7 @@ + const char *nonce_name; + const struct connection *c = st->st_connection; + const chunk_t *pss = get_preshared_secret(c); +- unsigned int hash_len = st->st_oakley.prf_hasher->hash_digest_len; +- unsigned char prf_psk[hash_len]; ++ const size_t hash_len = st->st_oakley.prf_hasher->hash_digest_len; + + if (pss == NULL) { + libreswan_log("No matching PSK found for connection:%s", +@@ -80,52 +81,25 @@ + return FALSE; /* failure: no PSK to use */ + } + +- CK_EXTRACT_PARAMS bs; +- SECItem param; +- + /* RFC 4306 2.15: + * AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), ) + */ + + /* calculate inner prf */ ++ PK11SymKey *prf_psk; + { +- struct hmac_ctx id_ctx; +- +- PK11SymKey *tkey1 = pk11_derive_wrapper_lsw(st->st_shared_nss, +- CKM_CONCATENATE_DATA_AND_BASE, *pss, CKM_EXTRACT_KEY_FROM_KEY, CKA_DERIVE, +- 0); +- passert(tkey1 != NULL); +- +- bs = 0; +- param.data = (unsigned char*)&bs; +- param.len = sizeof(bs); +- PK11SymKey *tkey2 = PK11_Derive(tkey1, +- CKM_EXTRACT_KEY_FROM_KEY, +- ¶m, +- CKM_CONCATENATE_BASE_AND_DATA, +- CKA_DERIVE, pss->len); +- passert(tkey2 != NULL); +- +- hmac_init(&id_ctx, st->st_oakley.prf_hasher, tkey2); +- +- PK11_FreeSymKey(tkey1); +- PK11_FreeSymKey(tkey2); +- hmac_update(&id_ctx, psk_key_pad_str, psk_key_pad_str_len); +- hmac_final(prf_psk, &id_ctx); ++ struct crypt_prf *prf = ++ crypt_prf_init(("" ++ " = prf(,\"Key Pad for IKEv2\")"), ++ st->st_oakley.prf_hasher, ++ st->st_shared_nss/*scratch*/); ++ crypt_prf_init_chunk("shared secret", prf, *pss); ++ crypt_prf_update(prf); ++ crypt_prf_update_bytes(psk_key_pad_str/*name*/, prf, ++ psk_key_pad_str, psk_key_pad_str_len); ++ prf_psk = crypt_prf_final(prf); + } + +- DBG(DBG_CRYPT, +- DBG_log("negotiated prf: %s hash length: %lu", +- st->st_oakley.prf_hasher->common.name, +- (long unsigned) hash_len)); +- DBG(DBG_PRIVATE, +- DBG_log("PSK , secret, used %s, length %lu", +- pss->ptr, (long unsigned) pss->len); +- DBG_log("keypad used \"%s\", length %d", psk_key_pad_str, +- psk_key_pad_str_len)); +- DBG(DBG_CRYPT, +- DBG_dump("inner prf output", prf_psk, hash_len)); +- + /* decide nonce based on the role */ + if (role == O_INITIATOR) { + /* on initiator, we need to hash responders nonce */ +@@ -138,52 +112,32 @@ + + /* calculate outer prf */ + { +- struct hmac_ctx id_ctx; +- chunk_t pp_chunk; +- +- pp_chunk.ptr = prf_psk; +- pp_chunk.len = hash_len; +- +- PK11SymKey *tkey1 = pk11_derive_wrapper_lsw(st->st_shared_nss, +- CKM_CONCATENATE_DATA_AND_BASE, +- pp_chunk, +- CKM_EXTRACT_KEY_FROM_KEY, +- CKA_DERIVE, +- 0); +- passert(tkey1 != NULL); +- +- bs = 0; +- param.data = (unsigned char*)&bs; +- param.len = sizeof(bs); +- PK11SymKey *tkey2 = PK11_Derive(tkey1, +- CKM_EXTRACT_KEY_FROM_KEY, +- ¶m, +- CKM_CONCATENATE_BASE_AND_DATA, +- CKA_DERIVE, hash_len); +- passert(tkey2 != NULL); +- +- hmac_init(&id_ctx, st->st_oakley.prf_hasher, tkey2); +- +- PK11_FreeSymKey(tkey1); +- PK11_FreeSymKey(tkey2); +- +-/* +- * For the responder, the octets to +- * be signed start with the first octet of the first SPI in the header +- * of the second message and end with the last octet of the last payload +- * in the second message. Appended to this (for purposes of computing +- * the signature) are the initiator's nonce Ni (just the value, not the +- * payload containing it), and the value prf(SK_pr,IDr') where IDr' is +- * the responder's ID payload excluding the fixed header. Note that +- * neither the nonce Ni nor the value prf(SK_pr,IDr') are transmitted. +- */ +- +- hmac_update(&id_ctx, firstpacket.ptr, firstpacket.len); +- hmac_update(&id_ctx, nonce->ptr, nonce->len); +- hmac_update(&id_ctx, idhash, hash_len); +- hmac_final(signed_octets, &id_ctx); +- ++ struct crypt_prf *prf = ++ crypt_prf_init(("" ++ " = prf(, )"), ++ st->st_oakley.prf_hasher, ++ st->st_shared_nss /*scratch*/); ++ crypt_prf_init_symkey("", prf, prf_psk); ++ /* ++ * For the responder, the octets to be signed start ++ * with the first octet of the first SPI in the header ++ * of the second message and end with the last octet ++ * of the last payload in the second message. ++ * Appended to this (for purposes of computing the ++ * signature) are the initiator's nonce Ni (just the ++ * value, not the payload containing it), and the ++ * value prf(SK_pr,IDr') where IDr' is the responder's ++ * ID payload excluding the fixed header. Note that ++ * neither the nonce Ni nor the value prf(SK_pr,IDr') ++ * are transmitted. ++ */ ++ crypt_prf_update(prf); ++ crypt_prf_update_chunk("first-packet", prf, firstpacket); ++ crypt_prf_update_chunk("nonce", prf, *nonce); ++ crypt_prf_update_bytes("hash", prf, idhash, hash_len); ++ crypt_prf_final_bytes(prf, signed_octets, hash_len); + } ++ free_any_symkey("", &prf_psk); + + DBG(DBG_CRYPT, + DBG_dump_chunk("inputs to hash1 (first packet)", firstpacket); +diff -Naur libreswan-3.12-orig/programs/pluto/initiate.c libreswan-3.12/programs/pluto/initiate.c +--- libreswan-3.12-orig/programs/pluto/initiate.c 2014-11-06 22:52:50.000000000 -0500 ++++ libreswan-3.12/programs/pluto/initiate.c 2015-05-06 11:45:32.925301475 -0400 +@@ -132,7 +132,7 @@ + c->name, c->interface->ip_dev->id_rname, + p->ip_dev->id_rname); + } +- terminate_connection(c->name); ++ // terminate_connection(c->name); + c->interface = NULL; /* withdraw orientation */ + return FALSE; + } +diff -Naur libreswan-3.12-orig/programs/pluto/log.c libreswan-3.12/programs/pluto/log.c +--- libreswan-3.12-orig/programs/pluto/log.c 2015-05-06 11:44:21.548466119 -0400 ++++ libreswan-3.12/programs/pluto/log.c 2015-05-06 11:45:32.926301486 -0400 +@@ -1208,7 +1208,7 @@ + if (!st->st_ikev2) { + /* ikev1 takes integ from prf, ecept of cause gcm */ + /* but we dont support gcm in ikev1 for now */ +- snprintf(integname, sizeof(integname), prfname); ++ jam_str(integname, sizeof(integname), prfname); + } else { + snprintf(integname, sizeof(integname), "none"); + } +diff -Naur libreswan-3.12-orig/programs/pluto/Makefile libreswan-3.12/programs/pluto/Makefile +--- libreswan-3.12-orig/programs/pluto/Makefile 2015-05-06 11:44:21.590466613 -0400 ++++ libreswan-3.12/programs/pluto/Makefile 2015-05-06 11:45:32.926301486 -0400 +@@ -129,7 +129,8 @@ + ikev1_dpd.c ikev1_dpd.h ikev1_spdb_struct.c \ + ikev1_msgid.c \ + ikev2.c ikev2_parent.c ikev2_child.c ikev2_crypto.c \ +- ikev2_prfplus.c ikev2_spdb_struct.c \ ++ crypt_symkey.c crypt_prf.c ikev1_prf.c ikev2_prf.c \ ++ ikev2_spdb_struct.c \ + ikev2_rsa.c ikev2_psk.c ikev2_x509.c \ + kernel.c kernel.h \ + ${NETKEY_SRCS} \ +@@ -176,7 +177,8 @@ + OBJSPLUTO += myid.o ipsec_doi.o + OBJSPLUTO += ikev1.o ikev1_main.o ikev1_quick.o ikev1_dpd.o ikev1_spdb_struct.o ikev1_msgid.o + OBJSPLUTO += ikev2.o ikev2_parent.o ikev2_child.o ikev2_spdb_struct.o +-OBJSPLUTO += ikev2_rsa.o ikev2_psk.o ikev2_x509.o ikev2_crypto.o ikev2_prfplus.o ++OBJSPLUTO += ikev2_rsa.o ikev2_psk.o ikev2_x509.o ikev2_crypto.o ++OBJSPLUTO += crypt_symkey.o crypt_prf.o ikev1_prf.o ikev2_prf.o + OBJSPLUTO += kernel.o + OBJSPLUTO += $(NETKEY_OBJS) $(BSDKAME_OBJS) ${KLIPS_OBJS} ${MAST_OBJS} ${WIN2K_OBJS} ${PFKEYv2_OBJS} + OBJSPLUTO += kernel_noklips.o rcv_whack.o +@@ -203,14 +205,16 @@ + OBJSWHACK = whack.o + OBJSWHACKINIT = whackinit.o + ++CAVP += cavp ++ + # we can't do tests with two conditions, but we can concatenate the strings + SHOULDWERESTART=${USE_OBJDIR}$(wildcard plutomain.c) + ifeq ($(SHOULDWERESTART),trueplutomain.c) + all programs clean install: + cd ${LIBRESWANSRCDIR} && cd ${OBJDIRTOP}/programs/pluto && $(MAKE) $@ + else +-all: $(BINNAMEPLUTO) $(BINNAMEADNSIFNEEDED) $(BINNAMEWHACK) #$(BINNAMEWHACKINIT) +-programs: $(BINNAMEPLUTO) $(BINNAMEADNSIFNEEDED) $(BINNAMEWHACK) $(MANPAGES) #$(BINNAMEWHACKINIT) ++all: $(BINNAMEPLUTO) $(BINNAMEADNSIFNEEDED) $(BINNAMEWHACK) $(CAVP) #$(BINNAMEWHACKINIT) ++programs: $(BINNAMEPLUTO) $(BINNAMEADNSIFNEEDED) $(BINNAMEWHACK) $(MANPAGES) $(CAVP) #$(BINNAMEWHACKINIT) + clean: cleanall + install: doinstall + endif +@@ -290,6 +294,20 @@ + + checkprograms: + ++# Cryptographic Algorithm Validation Program (CAVP) ++# see: http://csrc.nist.gov/groups/STM/cavp/index.html ++CAVPSRC += cavp.c ++CAVPSRC += cavp_print.c ++CAVPSRC += cavp_stubs.c ++CAVPSRC += cavp_ikev1.c ++CAVPSRC += cavp_ikev2.c ++DISTSRC += $(CAVPSRC) ++OBJSCAVP = $(CAVPSRC:.c=.o) $(filter-out plutomain.o, $(OBJSPLUTO)) ++cavp: $(OBJSCAVP) ++ $(CC) -o $@ $(OBJSCAVP) \ ++ $(LDFLAGS) $(USERLINK) $(LIBSPLUTO) ${PLUTOMINUSL} ++ ++ + .c.o: + $(CC) $(USERCOMPILE) ${PORTINCLUDE} $(COPTS) $(ALLFLAGS) -c $< + +diff -Naur libreswan-3.12-orig/programs/pluto/pluto_constants.c libreswan-3.12/programs/pluto/pluto_constants.c +--- libreswan-3.12-orig/programs/pluto/pluto_constants.c 2015-05-06 11:44:21.549466131 -0400 ++++ libreswan-3.12/programs/pluto/pluto_constants.c 2015-05-06 11:45:32.926301486 -0400 +@@ -161,6 +161,9 @@ + /* story for state */ + + const char *const state_story[] = { ++ "not defined and probably dead (internal)", /* STATE_UNDEFINED */ ++ "got an ACQUIRE message for this pair (internal)", /* OPPO_QCQUIRE */ ++ "got TXT specifying gateway (internal)", /* OPPO_GW_DISCOVERED */ + "expecting MI1", /* STATE_MAIN_R0 */ + "sent MI1, expecting MR1", /* STATE_MAIN_I1 */ + "sent MR1, expecting MI2", /* STATE_MAIN_R1 */ +@@ -206,7 +209,7 @@ + }; + + enum_names state_stories = +- { STATE_MAIN_R0, STATE_IKEv2_ROOF - 1, state_story, NULL }; ++ { STATE_UNDEFINED, STATE_IKEv2_ROOF - 1, state_story, NULL }; + + static const char *const natt_method_result_name[] = { + }; +diff -Naur libreswan-3.12-orig/programs/pluto/pluto_crypt.c libreswan-3.12/programs/pluto/pluto_crypt.c +--- libreswan-3.12-orig/programs/pluto/pluto_crypt.c 2014-11-06 22:52:50.000000000 -0500 ++++ libreswan-3.12/programs/pluto/pluto_crypt.c 2015-05-06 11:45:32.927301498 -0400 +@@ -63,6 +63,10 @@ + #include "lswconf.h" + + #include "lsw_select.h" ++#include "ikev2_prf.h" ++#include "crypt_dh.h" ++#include "ikev1_prf.h" ++ + + TAILQ_HEAD(req_queue, pluto_crypto_req_cont); + +diff -Naur libreswan-3.12-orig/programs/pluto/pluto_crypt.h libreswan-3.12/programs/pluto/pluto_crypt.h +--- libreswan-3.12-orig/programs/pluto/pluto_crypt.h 2015-05-06 11:44:21.570466378 -0400 ++++ libreswan-3.12/programs/pluto/pluto_crypt.h 2015-05-06 11:45:32.927301498 -0400 +@@ -382,10 +382,6 @@ + extern void finish_dh_v2(struct state *st, + const struct pluto_crypto_req *r); + +-extern void calc_dh_iv(struct pluto_crypto_req *r); +-extern void calc_dh(struct pluto_crypto_req *r); +-extern void calc_dh_v2(struct pluto_crypto_req *r); +- + extern void unpack_KE_from_helper( + struct state *st, + const struct pluto_crypto_req *r, +diff -Naur libreswan-3.12-orig/programs/pluto/state.c libreswan-3.12/programs/pluto/state.c +--- libreswan-3.12-orig/programs/pluto/state.c 2015-05-06 11:44:21.571466389 -0400 ++++ libreswan-3.12/programs/pluto/state.c 2015-05-06 11:45:32.928301510 -0400 +@@ -65,6 +65,7 @@ + #include "md5.h" + #include "cookie.h" + #include "crypto.h" /* requires sha1.h and md5.h */ ++#include "crypt_symkey.h" + #include "spdb.h" + + #include +@@ -525,12 +526,7 @@ + freeanychunk(st->st_nr); + + +-# define free_any_nss_symkey(p) { \ +- if ((p) != NULL) { \ +- PK11_FreeSymKey(p); \ +- (p) = NULL; \ +- } \ +- } ++# define free_any_nss_symkey(p) free_any_symkey(#p, &(p)) + /* ??? free_any_nss_symkey(st->st_shared_nss); */ + free_any_nss_symkey(st->st_skeyseed_nss); /* same as st_skeyid_nss */ + free_any_nss_symkey(st->st_skey_d_nss); /* same as st_skeyid_d_nss */ +@@ -1440,7 +1436,7 @@ + c->name, inst, + st->st_remoteport, + enum_name(&state_names, st->st_state), +- state_story[st->st_state - STATE_MAIN_R0], ++ enum_name(&state_stories, st->st_state), + st->st_event ? enum_name(&timer_event_names, + st->st_event->ev_type) : "none", + delta, +diff -Naur libreswan-3.12-orig/programs/pluto/test_buffer.c libreswan-3.12/programs/pluto/test_buffer.c +--- libreswan-3.12-orig/programs/pluto/test_buffer.c 2015-05-06 11:44:21.591466625 -0400 ++++ libreswan-3.12/programs/pluto/test_buffer.c 2015-05-06 11:45:32.928301510 -0400 +@@ -40,7 +40,7 @@ + * If this function fails, crash and burn. Its been fed static data + * so should never ever have a problem. + */ +-static chunk_t decode_hex_to_chunk(const char *original, const char *string) ++chunk_t decode_hex_to_chunk(const char *original, const char *string) + { + /* The decoded buffer can't be bigger than the encoded string. */ + chunk_t chunk = zalloc_chunk(strlen(string), original); +@@ -154,8 +154,15 @@ + PK11SymKey *decode_to_key(CK_MECHANISM_TYPE cipher_mechanism, + const char *encoded_key) + { +- PK11SlotInfo *slot = PK11_GetBestSlot(cipher_mechanism, NULL); + chunk_t raw_key = decode_to_chunk("key", encoded_key); ++ PK11SymKey *sym_key = chunk_to_key(cipher_mechanism, raw_key); ++ freeanychunk(raw_key); ++ return sym_key; ++} ++ ++PK11SymKey *chunk_to_key(CK_MECHANISM_TYPE cipher_mechanism, chunk_t raw_key) ++{ ++ PK11SlotInfo *slot = PK11_GetBestSlot(cipher_mechanism, NULL); + SECItem key_item; + key_item.type = siBuffer; + key_item.data = raw_key.ptr; /* ptr to an array of key bytes */ +@@ -163,7 +170,6 @@ + PK11SymKey *sym_key = PK11_ImportSymKey(slot, cipher_mechanism, + PK11_OriginUnwrap, + CKA_ENCRYPT, &key_item, NULL); +- freeanychunk(raw_key); + PK11_FreeSlot(slot); + return sym_key; + } +diff -Naur libreswan-3.12-orig/programs/pluto/test_buffer.h libreswan-3.12/programs/pluto/test_buffer.h +--- libreswan-3.12-orig/programs/pluto/test_buffer.h 2015-05-06 11:44:21.592466636 -0400 ++++ libreswan-3.12/programs/pluto/test_buffer.h 2015-05-06 11:45:32.928301510 -0400 +@@ -13,6 +13,7 @@ + * for more details. + */ + ++chunk_t decode_hex_to_chunk(const char *original, const char *string); + chunk_t decode_to_chunk(const char *prefix, const char *string); + int compare_chunks(const char *prefix, + chunk_t expected, +@@ -24,3 +25,5 @@ + size_t offset, size_t length); + + PK11SymKey *decode_to_key(CK_MECHANISM_TYPE cipher_mechanism, const char *string); ++ ++PK11SymKey *chunk_to_key(CK_MECHANISM_TYPE cipher_mechanism, chunk_t raw_key); diff --git a/SOURCES/libreswan-3.12-CVE-2015-3204.patch b/SOURCES/libreswan-3.12-CVE-2015-3204.patch new file mode 100644 index 0000000..8dfd1f5 --- /dev/null +++ b/SOURCES/libreswan-3.12-CVE-2015-3204.patch @@ -0,0 +1,169 @@ +diff --git a/lib/libswan/constants.c b/lib/libswan/constants.c +index a003e99..8f3a107 100644 +--- a/lib/libswan/constants.c ++++ b/lib/libswan/constants.c +@@ -43,12 +43,11 @@ + * The buffer bound (size) must be greater than 0. + * That allows a guarantee that the result is NUL-terminated. + * +- * The result is a pointer: +- * if the string fits, to the NUL at the end of the string in dest; +- * if the string was truncated, to the roof of dest. ++ * The result is a pointer to the NUL at the end of the string in dest. + * +- * Warning: Is it really wise to silently truncate? Only the caller knows. +- * The caller SHOULD check by seeing if the result equals dest's roof. ++ * Warning: no indication of truncation is returned. ++ * An earlier version did indicate truncation, but that feature was never used. ++ * This version is more robust and has a simpler contract. + */ + char *jam_str(char *dest, size_t size, const char *src) + { +@@ -56,12 +55,11 @@ char *jam_str(char *dest, size_t size, const char *src) + + { + size_t full_len = strlen(src); +- bool oflow = size - 1 < full_len; +- size_t copy_len = oflow ? size - 1 : full_len; ++ size_t copy_len = size - 1 < full_len ? size - 1 : full_len; + + memcpy(dest, src, copy_len); + dest[copy_len] = '\0'; +- return dest + copy_len + (oflow ? 1 : 0); ++ return dest + copy_len; + } + } + +diff --git a/include/packet.h b/include/packet.h +index c9b0df9..55f8b11 100644 +--- a/include/packet.h ++++ b/include/packet.h +@@ -657,6 +657,8 @@ struct isakmp_nat_oa { + extern struct_desc isakmp_nat_d; + extern struct_desc isakmp_nat_oa; + ++extern struct_desc isakmp_ignore_desc; /* generic payload (when ignoring) */ ++ + /* ISAKMP IKE Fragmentation Payload + * Cisco proprietary, undocumented + * Microsoft documentation link: http://msdn.microsoft.com/en-us/library/cc233452.aspx +diff --git a/programs/pluto/ikev1.c b/programs/pluto/ikev1.c +index e8157bb..155a27c 100644 +--- a/programs/pluto/ikev1.c ++++ b/programs/pluto/ikev1.c +@@ -1810,8 +1810,7 @@ void process_packet_tail(struct msg_digest **mdp) + switch (np) { + case ISAKMP_NEXT_NATD_RFC: + case ISAKMP_NEXT_NATOA_RFC: +- if (st == NULL || +- (st->hidden_variables.st_nat_traversal & NAT_T_WITH_RFC_VALUES) == LEMPTY) { ++ if ((st->hidden_variables.st_nat_traversal & NAT_T_WITH_RFC_VALUES) == LEMPTY) { + /* + * don't accept NAT-D/NAT-OA reloc directly in message, + * unless we're using NAT-T RFC +@@ -1832,6 +1831,7 @@ void process_packet_tail(struct msg_digest **mdp) + /* payload type is out of range or requires special handling */ + switch (np) { + case ISAKMP_NEXT_ID: ++ /* ??? two kinds of ID payloads */ + sd = (IS_PHASE1(from_state) || + IS_PHASE15(from_state)) ? + &isakmp_identification_desc : +@@ -1839,20 +1839,48 @@ void process_packet_tail(struct msg_digest **mdp) + break; + + case ISAKMP_NEXT_NATD_DRAFTS: +- np = ISAKMP_NEXT_NATD_RFC; /* NAT-D was a private use type before RFC-3947 */ ++ /* NAT-D was a private use type before RFC-3947 -- same format */ ++ np = ISAKMP_NEXT_NATD_RFC; + sd = payload_desc(np); + break; + + case ISAKMP_NEXT_NATOA_DRAFTS: +- np = ISAKMP_NEXT_NATOA_RFC; /* NAT-OA was a private use type before RFC-3947 */ ++ /* NAT-OA was a private use type before RFC-3947 -- same format */ ++ np = ISAKMP_NEXT_NATOA_RFC; + sd = payload_desc(np); + break; + +- case ISAKMP_NEXT_SAK: /* AKA ISAKMP_NEXT_NATD_BADDRAFTS */ ++ case ISAKMP_NEXT_SAK: /* or ISAKMP_NEXT_NATD_BADDRAFTS */ ++ /* ++ * Official standards say that this is ISAKMP_NEXT_SAK, ++ * a part of Group DOI, something we don't implement. ++ * Old non-updated Cisco gear abused this number in ancient NAT drafts. ++ * We ignore (rather than reject) this in support of people ++ * with crufty Cisco machines. ++ */ + loglog(RC_LOG_SERIOUS, +- "%smessage with unsupported payload ISAKMP_NEXT_SAK (as ISAKMP_NEXT_NATD_BADDRAFTS) ignored", ++ "%smessage with unsupported payload ISAKMP_NEXT_SAK (or ISAKMP_NEXT_NATD_BADDRAFTS) ignored", + excuse); +- break; ++ /* ++ * Hack to discard payload, whatever it was. ++ * Since we are skipping the rest of the loop ++ * body we must do some things ourself: ++ * - demarshall the payload ++ * - grab the next payload number (np) ++ * - don't keep payload (don't increment pd) ++ * - skip rest of loop body ++ */ ++ if (!in_struct(&pd->payload, &isakmp_ignore_desc, &md->message_pbs, ++ &pd->pbs)) { ++ loglog(RC_LOG_SERIOUS, ++ "%smalformed payload in packet", ++ excuse); ++ SEND_NOTIFICATION(PAYLOAD_MALFORMED); ++ return; ++ } ++ np = pd->payload.generic.isag_np; ++ /* NOTE: we do not increment pd! */ ++ continue; /* skip rest of the loop */ + + default: + loglog(RC_LOG_SERIOUS, +@@ -1865,6 +1893,8 @@ void process_packet_tail(struct msg_digest **mdp) + passert(sd != NULL); + } + ++ passert(np < LELEM_ROOF); ++ + { + lset_t s = LELEM(np); + +diff --git a/programs/pluto/packet.c b/programs/pluto/packet.c +index 2b104db..e759b5e 100644 +--- a/programs/pluto/packet.c ++++ b/programs/pluto/packet.c +@@ -81,9 +81,6 @@ static field_desc isag_fields[] = { + { ft_end, 0, NULL, NULL } + }; + +-static struct_desc isakmp_generic_desc = +- { "ISAKMP Generic Payload", isag_fields, sizeof(struct isakmp_generic) }; +- + /* ISAKMP Data Attribute (generic representation within payloads) + * layout from RFC 2408 "ISAKMP" section 3.3 + * This is not a payload type. +@@ -647,6 +644,11 @@ struct_desc isakmp_nat_oa = + { "ISAKMP NAT-OA Payload", isanat_oa_fields, + sizeof(struct isakmp_nat_oa) }; + ++/* Generic payload (when ignoring) */ ++ ++struct_desc isakmp_ignore_desc = ++ { "ignored ISAKMP Generic Payload", isag_fields, sizeof(struct isakmp_generic) }; ++ + /* ISAKMP IKE Fragmentation Payload + * Cisco proprietary, undocumented + * +@@ -1892,7 +1894,7 @@ bool out_generic(u_int8_t np, struct_desc *sd, + { + struct isakmp_generic gen; + +- passert(sd->fields == isakmp_generic_desc.fields); ++ passert(sd->fields == isag_fields); + gen.isag_np = np; + return out_struct(&gen, sd, outs, obj_pbs); + } diff --git a/SOURCES/v6neighbor-hole.conf b/SOURCES/v6neighbor-hole.conf new file mode 100644 index 0000000..8ac7616 --- /dev/null +++ b/SOURCES/v6neighbor-hole.conf @@ -0,0 +1,58 @@ +# Passthrough For proper IPv6 Neighbor Discovery (RFC 4861) +# +# The unicast Neighbor Advertisement reply message must be sent +# in plaintext) even if we have an IPsec SA for the destination, +# because the other end might have crashed or rebooted and lost +# its IPsec SA with our end. It will use IPv6 Neighbor Discovery +# to find our end again. Without this policy hole, the neighbor +# discovery answer packet is caught by the kernel and encrypted. +# As a result, the rebooted end won't be able to find us and won't +# be able to send us an IKE packet to re-establish the IPsec SA. +# +# While the Neighbor Solicitation is multicast and would not +# not be caught by the IPsec stack, we use it in the configuration +# to limit the range of ipv6-icmp covered. In a way, this would +# only need to be an outbound SA, but SA's come in bundles, so we +# need an unbound SA as well. Leaving protoport empty or set to +# any ipv6-icmp would cause us to send out more unencrypted traffic, +# which would be dropped once the IPsec SA has re-established. +# So we set the inbound protoport to ipv6-icmp Neighbor Advertisement. +# (solution by Jaroslav Aster) +# +# Configuration +# +# ipv6-icmp Neighbor Solicitation is Type 135, Code 0. +# ipv6-icmp Neighbor Advertisement is Type 136, Code 0. +# As per RFC 4301/5996, icmp type is put in the most significant 8 bits +# and the icmp code is in the least significant 8 bits of port field. +# proto is 58 (ipv6-icmp) +# type = 135 (0x87) or 136 (0x88) +# code = 0 (0x00) +# so "port" in protoport is 0x8700 (34560) for Neighbor Solicitation. +# so "port" in protoport is 0x8800 (34816) for Neighbor Advertisement. + +conn v6neighbor-hole-in + left=::1 + leftsubnet=::0/0 + leftprotoport=58/34560 + rightprotoport=58/34816 + rightsubnet=::0/0 + right=::0 + connaddrfamily=ipv6 + authby=never + type=passthrough + auto=route + priority=10 + +conn v6neighbor-hole-out + left=::1 + leftsubnet=::0/0 + leftprotoport=58/34816 + rightprotoport=58/34560 + rightsubnet=::0/0 + right=::0 + connaddrfamily=ipv6 + authby=never + type=passthrough + auto=route + priority=10 diff --git a/SPECS/libreswan.spec b/SPECS/libreswan.spec index 5b4280e..ef05c54 100644 --- a/SPECS/libreswan.spec +++ b/SPECS/libreswan.spec @@ -16,10 +16,14 @@ Name: libreswan Summary: IPsec implementation with IKEv1 and IKEv2 keying protocols Version: 3.12 -Release: %{?prever:0.}5%{?prever:.%{prever}}%{?dist} +Release: %{?prever:0.}10.1%{?prever:.%{prever}}%{?dist} License: GPLv2 Url: https://www.libreswan.org/ Source: https://download.libreswan.org/%{name}-%{version}%{?prever}.tar.gz +Source1: v6neighbor-hole.conf +Source2: ikev1_dsa.fax.bz2 +Source3: ikev1_psk.fax.bz2 +Source4: ikev2.fax.bz2 Group: System Environment/Daemons BuildRequires: gmp-devel bison flex redhat-rpm-config pkgconfig BuildRequires: systemd @@ -36,6 +40,17 @@ Patch5: libreswan-3.12-1131503-invalid-ke.patch Patch6: libreswan-3.12-1134297-aes_ctr.patch Patch7: libreswan-3.12-1162770-gcm-man.patch Patch8: libreswan-3.12-826264-ike-aes-gcm.patch +#rhbz 1198650 +Patch9: libreswan-3.12-1170018-netlink-label.patch +#rhbz 1198649 +Patch10: libreswan-3.12-1182224-bsi-random.patch +#rhbz 1211146 +Patch11: libreswan-3.12-1203794-fipstest.patch +# rhbz 1213652 +Patch12: libreswan-3.12-1212121-cavs.patch +# rhbz 1208022 +Patch13: libreswan-3.12-1207689-blacklist.patch +Patch14: libreswan-3.12-CVE-2015-3204.patch Conflicts: openswan < %{version}-%{release} Obsoletes: openswan < %{version}-%{release} @@ -97,6 +112,13 @@ Libreswan is based on Openswan-2.6.38 which in turn is based on FreeS/WAN-2.04 %patch6 -p1 %patch7 -p1 %patch8 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch13 -p1 +%patch14 -p1 + # remove man page for ipsec.conf so it is forced to regenerate rm ./programs/configs/ipsec.conf.5 @@ -176,6 +198,24 @@ install -m644 packaging/fedora/libreswan-prelink.conf %{buildroot}%{_sysconfdir} echo "include /etc/ipsec.d/*.secrets" > %{buildroot}%{_sysconfdir}/ipsec.secrets rm -fr %{buildroot}/etc/rc.d/rc* +install -m644 %{SOURCE1} %{buildroot}%{_sysconfdir}/ipsec.d/v6neighbor-hole.conf +sed -i "s/#include \/etc\/ipsec.d\/\*.conf/include \/etc\/ipsec.d\/\*.conf/" %{buildroot}%{_sysconfdir}/ipsec.conf +# cavs testing +cp -a OBJ.*/programs/pluto/cavp %{buildroot}%{_libexecdir}/ipsec + +%check +# There is an elaborate upstream testing infrastructure which we do not run here +# We only run the CAVS tests here +cp %{SOURCE2} %{SOURCE3} %{SOURCE4} . +bunzip2 *.fax.bz2 +echo "starting CAVS test for IKEv2" +OBJ.linux.*/programs/pluto/cavp -v2 ikev2.fax | diff -u ikev2.fax - > /dev/null +echo "starting CAVS test for IKEv1 RSASIG" +OBJ.linux.*/programs/pluto/cavp -v1sig ikev1_dsa.fax | diff -u ikev1_dsa.fax - > /dev/null +echo "starting CAVS test for IKEv1 PSK" +OBJ.linux.*/programs/pluto/cavp -v1psk ikev1_psk.fax | diff -u ikev1_psk.fax - > /dev/null +echo "CAVS tests passed" + %files %doc CHANGES COPYING CREDITS README* LICENSE %doc docs/*.* docs/examples @@ -184,6 +224,7 @@ rm -fr %{buildroot}/etc/rc.d/rc* %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/sysconfig/pluto %attr(0600,root,root) %config(noreplace) %{_sysconfdir}/ipsec.secrets %attr(0700,root,root) %dir %{_sysconfdir}/ipsec.d +%attr(0644,root,root) %{_sysconfdir}/ipsec.d/v6neighbor-hole.conf %attr(0700,root,root) %dir %{_sysconfdir}/ipsec.d/cacerts %attr(0700,root,root) %dir %{_sysconfdir}/ipsec.d/crls %attr(0700,root,root) %dir %{_sysconfdir}/ipsec.d/policies @@ -217,6 +258,29 @@ if [ ! -f %{_sysconfdir}/ipsec.d/cert8.db ] ; then fi %changelog +* Fri May 29 2015 Paul Wouters - 3.12-10.1 +- Resolves: rhbz#1226407 CVE-2015-3204 libreswan: crafted IKE packet causes daemon restart + +* Tue May 05 2015 Paul Wouters - 3.12-10 +- Resolves: rhbz#1213652 Support CAVS [updated another prf() free symkey, bogus fips mode fix] + +* Tue Apr 28 2015 Paul Wouters - 3.12-9 +- Resolves: rhbz#1213652 Support CAVS [updated to kill another copy of prf()] +- Resolves: rhbz#1208023 Libreswan with IPv6 [updated patch by Jaroslav Aster] +- Resolves: rhbz#1208022 libreswan ignores module blacklist [updated modprobe handling] + +* Mon Apr 20 2015 Paul Wouters - 3.12-8 +- Resolves: rhbz#1213652 Support CAVS testing of the PRF/PRF+ functions + +* Mon Apr 13 2015 Paul Wouters - 3.12-7 +- Resolves: rhbz#1208022 libreswan ignores module blacklist rules +- Resolves: rhbz#1208023 Libreswan with IPv6 in RHEL7 fails after reboot +- Resolves: rhbz#1211146 pluto crashes in fips mode + +* Tue Mar 17 2015 Paul Wouters - 3.12-6 +- Resolves: rhbz#1198650 SELinux context string size limit +- Resolves: rhbz#1198649 Add new option for BSI random requirement + * Tue Jan 20 2015 Paul Wouters - 3.12-5 - Resolves: rhbz#826264 aes-gcm implementation support (for IKEv2) - Resolves: rhbz#1074018 Audit key agreement (integ gcm fixup)