diff -Naur libreswan-3.23-orig/programs/pluto/connections.c libreswan-3.23/programs/pluto/connections.c --- libreswan-3.23-orig/programs/pluto/connections.c 2018-01-25 15:19:46.000000000 -0500 +++ libreswan-3.23/programs/pluto/connections.c 2018-02-05 14:38:49.372280712 -0500 @@ -3158,10 +3158,8 @@ matching_peer_id && matching_peer_ca && matching_requested_ca, matching_peer_id, matching_peer_ca, matching_requested_ca);}); - /* Ignore template from which we instantiated - this should never happen */ if (c->kind == CK_INSTANCE && d->kind == CK_TEMPLATE && streq(c->name, d->name)) { - libreswan_log("Warning: not switching back to template of current instance (FIXME)"); - continue; + DBG(DBG_CONTROLMORE, DBG_log("template conn fits better than instance of it - different client on same IP/port requires new instance")); } /* 'You Tarzan, me Jane' check based on received IDr */ diff -Naur libreswan-3.23-orig/programs/pluto/hostpair.c libreswan-3.23/programs/pluto/hostpair.c --- libreswan-3.23-orig/programs/pluto/hostpair.c 2018-01-25 15:19:46.000000000 -0500 +++ libreswan-3.23/programs/pluto/hostpair.c 2018-02-05 14:38:57.865635032 -0500 @@ -144,17 +144,6 @@ hisport = pluto_port; for (prev = NULL, p = host_pairs; p != NULL; prev = p, p = p->next) { - if (p->connections != NULL && (p->connections->kind == CK_INSTANCE) && - (p->connections->spd.that.id.kind == ID_NULL)) - { - DBG(DBG_CONTROLMORE, { - char ci[CONN_INST_BUF]; - DBG_log("find_host_pair: ignore CK_INSTANCE with ID_NULL hp:\"%s\"%s", - p->connections->name, - fmt_conn_instance(p->connections, ci)); - }); - continue; - } DBG(DBG_CONTROLMORE, { ipstr_buf b1; diff -Naur libreswan-3.23-orig/programs/pluto/ikev2.h libreswan-3.23/programs/pluto/ikev2.h --- libreswan-3.23-orig/programs/pluto/ikev2.h 2018-01-25 15:19:46.000000000 -0500 +++ libreswan-3.23/programs/pluto/ikev2.h 2018-02-05 14:39:11.171190105 -0500 @@ -162,7 +162,9 @@ extern bool ikev2_calculate_rsa_sha1(struct state *st, enum original_role role, unsigned char *idhash, - pb_stream *a_pbs); + pb_stream *a_pbs, + bool calc_no_ppk_auth, + chunk_t *no_ppk_auth); extern bool ikev2_create_psk_auth(enum keyword_authby authby, struct state *st, diff -Naur libreswan-3.23-orig/programs/pluto/ikev2_parent.c libreswan-3.23/programs/pluto/ikev2_parent.c --- libreswan-3.23-orig/programs/pluto/ikev2_parent.c 2018-01-25 15:19:46.000000000 -0500 +++ libreswan-3.23/programs/pluto/ikev2_parent.c 2018-02-05 14:39:11.173190188 -0500 @@ -2783,7 +2783,9 @@ switch (a.isaa_type) { case IKEv2_AUTH_RSA: - if (!ikev2_calculate_rsa_sha1(pst, role, idhash_out, &a_pbs)) { + if (!ikev2_calculate_rsa_sha1(pst, role, idhash_out, &a_pbs, + FALSE, /* store-only not set */ + NULL /* store-only chunk unused */)) { loglog(RC_LOG_SERIOUS, "Failed to find our RSA key"); return STF_FATAL; } @@ -2792,7 +2794,7 @@ case IKEv2_AUTH_PSK: case IKEv2_AUTH_NULL: if (!ikev2_create_psk_auth(authby, pst, idhash_out, &a_pbs, - FALSE /* store-only not set */, + FALSE, /* store-only not set */ NULL /* store-only chunk unused */)) { loglog(RC_LOG_SERIOUS, "Failed to find our PreShared Key"); return STF_FATAL; @@ -2812,7 +2814,9 @@ return STF_INTERNAL_ERROR; } - if (!ikev2_calculate_rsa_sha1(pst, role, idhash_out, &a_pbs)) { + if (!ikev2_calculate_rsa_sha1(pst, role, idhash_out, &a_pbs, + FALSE, /* store-only not set */ + NULL /* store-only chunk unused */)) { loglog(RC_LOG_SERIOUS, "DigSig: failed to find our RSA key"); return STF_FATAL; } @@ -3224,7 +3228,7 @@ hmac_update(&id_ctx, id_start, id_len); hmac_final(idhash, &id_ctx); - if (pst->st_sk_pi_no_ppk != NULL) { + if (pst->st_seen_ppk && !LIN(POLICY_PPK_INSIST, pc->policy)) { struct hmac_ctx id_ctx_npa; hmac_init(&id_ctx_npa, pst->st_oakley.ta_prf, pst->st_sk_pi_no_ppk); @@ -3371,7 +3375,7 @@ notifies++; if (pst->st_seen_ppk) - notifies++; /* used for two payloads */ + notifies++; /* used for one or two payloads */ /* code does not support AH + ESP, not recommend rfc8221 section-4 */ struct ipsec_proto_info *proto_info @@ -3437,21 +3441,24 @@ } if (pst->st_seen_ppk) { chunk_t notify_data = create_unified_ppk_id(&ppk_id_p); + int np = LIN(POLICY_PPK_INSIST, cc->policy) ? ISAKMP_NEXT_v2NONE : ISAKMP_NEXT_v2N; - notifies--; /* used for 2 payloads */ - if (!ship_v2N(ISAKMP_NEXT_v2N, ISAKMP_PAYLOAD_NONCRITICAL, - PROTO_v2_RESERVED, &empty_chunk, - v2N_PPK_IDENTITY, ¬ify_data, - &e_pbs_cipher)) - return STF_INTERNAL_ERROR; + notifies--; /* used for one or two payloads */ + if (!ship_v2N(np, ISAKMP_PAYLOAD_NONCRITICAL, + PROTO_v2_RESERVED, &empty_chunk, + v2N_PPK_IDENTITY, ¬ify_data, + &e_pbs_cipher)) + return STF_INTERNAL_ERROR; freeanychunk(notify_data); - ikev2_calc_no_ppk_auth(cc, pst, idhash_npa, &pst->st_no_ppk_auth); - if (!ship_v2N(ISAKMP_NEXT_v2NONE, ISAKMP_PAYLOAD_NONCRITICAL, - PROTO_v2_RESERVED, &empty_chunk, - v2N_NO_PPK_AUTH, &pst->st_no_ppk_auth, - &e_pbs_cipher)) - return STF_INTERNAL_ERROR; + if (!LIN(POLICY_PPK_INSIST, cc->policy)) { + ikev2_calc_no_ppk_auth(cc, pst, idhash_npa, &pst->st_no_ppk_auth); + if (!ship_v2N(ISAKMP_NEXT_v2NONE, ISAKMP_PAYLOAD_NONCRITICAL, + PROTO_v2_RESERVED, &empty_chunk, + v2N_NO_PPK_AUTH, &pst->st_no_ppk_auth, + &e_pbs_cipher)) + return STF_INTERNAL_ERROR; + } } passert(notifies == 0); diff -Naur libreswan-3.23-orig/programs/pluto/ikev2_ppk.c libreswan-3.23/programs/pluto/ikev2_ppk.c --- libreswan-3.23-orig/programs/pluto/ikev2_ppk.c 2018-01-25 15:19:46.000000000 -0500 +++ libreswan-3.23/programs/pluto/ikev2_ppk.c 2018-02-05 14:39:11.173190188 -0500 @@ -113,7 +113,24 @@ enum keyword_authby authby = c->spd.this.authby; switch (authby) { case AUTH_RSASIG: - /* TODO */ + if (ikev2_calculate_rsa_sha1(st, st->st_original_role, id_hash, NULL, TRUE, no_ppk_auth)) { + if (st->st_hash_negotiated & NEGOTIATE_AUTH_HASH_SHA1) { + /* make blobs separately, and somehow combine them and no_ppk_auth + * to get an actual no_ppk_auth */ + int len = ASN1_LEN_ALGO_IDENTIFIER + ASN1_SHA1_RSA_OID_SIZE + no_ppk_auth->len; + u_char *blobs = alloc_bytes(len, "bytes for blobs for AUTH_DIGSIG NO_PPK_AUTH"); + u_char *ret = blobs; + memcpy(blobs, len_sha1_rsa_oid_blob, ASN1_LEN_ALGO_IDENTIFIER); + blobs += ASN1_LEN_ALGO_IDENTIFIER; + memcpy(blobs, sha1_rsa_oid_blob, ASN1_SHA1_RSA_OID_SIZE); + blobs += ASN1_SHA1_RSA_OID_SIZE; + memcpy(blobs, no_ppk_auth->ptr, no_ppk_auth->len); + chunk_t release = *no_ppk_auth; + setchunk(*no_ppk_auth, ret, len); + freeanychunk(release); + } + } + return STF_OK; break; case AUTH_PSK: if (ikev2_create_psk_auth(AUTH_PSK, st, id_hash, NULL, TRUE, no_ppk_auth)) diff -Naur libreswan-3.23-orig/programs/pluto/ikev2_rsa.c libreswan-3.23/programs/pluto/ikev2_rsa.c --- libreswan-3.23-orig/programs/pluto/ikev2_rsa.c 2018-01-25 15:19:46.000000000 -0500 +++ libreswan-3.23/programs/pluto/ikev2_rsa.c 2018-02-05 14:39:11.173190188 -0500 @@ -101,7 +101,9 @@ bool ikev2_calculate_rsa_sha1(struct state *st, enum original_role role, unsigned char *idhash, - pb_stream *a_pbs) + pb_stream *a_pbs, + bool calc_no_ppk_auth, + chunk_t *no_ppk_auth) { unsigned char signed_octets[SHA1_DIGEST_SIZE + 16]; size_t signed_len; @@ -136,8 +138,13 @@ if (shr == 0) return FALSE; passert(shr == (int)sz); - if (!out_raw(sig_val, sz, a_pbs, "rsa signature")) - return FALSE; + if (calc_no_ppk_auth == FALSE) { + if (!out_raw(sig_val, sz, a_pbs, "rsa signature")) + return FALSE; + } else { + clonetochunk(*no_ppk_auth, sig_val, sz, "NO_PPK_AUTH chunk"); + DBG(DBG_PRIVATE, DBG_dump_chunk("NO_PPK_AUTH payload", *no_ppk_auth)); + } } return TRUE; diff -Naur libreswan-3.23-orig/programs/pluto/nss_cert_verify.c libreswan-3.23/programs/pluto/nss_cert_verify.c --- libreswan-3.23-orig/programs/pluto/nss_cert_verify.c 2018-01-25 15:19:46.000000000 -0500 +++ libreswan-3.23/programs/pluto/nss_cert_verify.c 2018-02-05 14:38:52.685418927 -0500 @@ -498,60 +498,83 @@ bool cert_VerifySubjectAltName(const CERTCertificate *cert, const char *name) { - SECStatus rv; SECItem subAltName; - PLArenaPool *arena = NULL; - CERTGeneralName *nameList = NULL; - CERTGeneralName *current = NULL; - bool san_ip = FALSE; - unsigned int len = strlen(name); - ip_address myip; - - rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, + SECStatus rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, &subAltName); if (rv != SECSuccess) { DBG(DBG_X509, DBG_log("certificate contains no subjectAltName extension")); return FALSE; } - if (tnatoaddr(name, 0, AF_UNSPEC, &myip) == NULL) - san_ip = TRUE; + ip_address myip; + bool san_ip = (tnatoaddr(name, 0, AF_UNSPEC, &myip) == NULL); - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); passert(arena != NULL); - nameList = current = CERT_DecodeAltNameExtension(arena, &subAltName); - passert(current != NULL); + CERTGeneralName *nameList = CERT_DecodeAltNameExtension(arena, &subAltName); - do - { + if (nameList == NULL) { + loglog(RC_LOG_SERIOUS, "certificate subjectAltName extension failed to decode"); + PORT_FreeArena(arena, PR_FALSE); + return FALSE; + } + + /* + * nameList is a pointer into a non-empty circular linked list. + * This loop visits each entry. + * We have visited each when we come back to the start. + * We test only at the end, after we advance, because we want to visit + * the first entry the first time we see it but stop when we get to it + * the second time. + */ + CERTGeneralName *current = nameList; + do { switch (current->type) { case certDNSName: case certRFC822Name: - if (san_ip) - break; - if (current->name.other.len == len) { - if (memcmp(current->name.other.data, name, len) == 0) { - DBG(DBG_X509, DBG_log("subjectAltname %s found in certificate", name)); - PORT_FreeArena(arena, PR_FALSE); - return TRUE; - } - } + { + /* + * Match the parameter name with the name in the certificate. + * The name in the cert may start with "*."; that will match + * any initial component in name (up to the first '.'). + */ + /* we need to cast because name.other.data is unsigned char * */ + const char *c_ptr = (const void *) current->name.other.data; + size_t c_len = current->name.other.len; + + const char *n_ptr = name; + static const char wild[] = "*."; + const size_t wild_len = sizeof(wild) - 1; + + if (c_len > wild_len && startswith(c_ptr, wild)) { + /* wildcard in cert: ignore first component of name */ + c_ptr += wild_len; + c_len -= wild_len; + n_ptr = strchr(n_ptr, '.'); + if (n_ptr == NULL) + break; /* cannot match */ - if (current->name.other.len != 0 && current->name.other.len < IDTOA_BUF) { - char osan[IDTOA_BUF]; + n_ptr++; /* skip . */ + } - memcpy(osan,current->name.other.data, current->name.other.len); - osan[current->name.other.len] = '\0'; - DBG(DBG_X509, DBG_log("subjectAltname (len=%d) %s not match %s", current->name.other.len, osan, name)); - } else { - DBG(DBG_X509, DBG_log("subjectAltname does not match %s", name)); + if (c_len == strlen(n_ptr) && strncaseeq(n_ptr, c_ptr, c_len)) { + /* + * ??? if current->name.other.data contains bad characters, + * what prevents them being logged? + */ + DBG(DBG_X509, DBG_log("subjectAltname %s matched %*s in certificate", + name, current->name.other.len, current->name.other.data)); + PORT_FreeArena(arena, PR_FALSE); + return TRUE; } break; + } case certIPAddress: if (!san_ip) break; + if ((current->name.other.len == 4) && (addrtypeof(&myip) == AF_INET)) { if (memcmp(current->name.other.data, &myip.u.v4.sin_addr.s_addr, 4) == 0) { DBG(DBG_X509, DBG_log("subjectAltname IPv4 matches %s", name)); @@ -572,7 +595,7 @@ break; } } - DBG(DBG_X509, DBG_log("subjectAltnamea IP address family mismatch for %s", name)); + DBG(DBG_X509, DBG_log("subjectAltname IP address family mismatch for %s", name)); break; default: diff -Naur libreswan-3.23-orig/programs/_unbound-hook/_unbound-hook.in libreswan-3.23/programs/_unbound-hook/_unbound-hook.in --- libreswan-3.23-orig/programs/_unbound-hook/_unbound-hook.in 2018-01-25 15:19:46.000000000 -0500 +++ libreswan-3.23/programs/_unbound-hook/_unbound-hook.in 2018-02-05 14:38:49.373280754 -0500 @@ -1,31 +1,52 @@ #!/usr/bin/python +# +# Copyright (C) 2018 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 +# 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. import sys -import base64 -import commands +import subprocess -log = "" - -status, myip = commands.getstatusoutput("ip -o route get 1.0.0.1") +# Get my %defaultroute IP address +myip = subprocess.check_output("ip -o route get 8.8.8.8", shell=True) myip = myip.split("src")[1].strip().split()[0] argv = sys.argv -argc = len(sys.argv) +ourself = argv.pop(0) -#log += "Number or arguments is %d\n"%argc -#if argc >= 4: -# log += "QNAME:%s\n"%argv[1] -# log += "TTL:%s\n"%argv[2] -# log += "IP:%s\n"%argv[3] -# log += "IPSECKEY:%s\n"%argv[4] -# rr = argv[4] -# pref, gwtype, algo, gw, pubkey = rr.split(" ") -#log += "-----------------------------\n" - -cmdname = "@IPSEC_EXECDIR@/whack --keyid @%s --addkey --pubkeyrsa 0s%s"%(argv[1], pubkey) -cmdip = "@IPSEC_EXECDIR@/whack --keyid %s --addkey --pubkeyrsa 0s%s"%(argv[3], pubkey) -cmdoe = "@IPSEC_EXECDIR@/whack --oppohere %s --oppothere %s"%(myip, argv[3]) -ret, output = commands.getstatusoutput(cmdname) -ret, output = commands.getstatusoutput(cmdip) -ret, output = commands.getstatusoutput(cmdoe) -ret, output = commands.getstatusoutput("@IPSEC_EXECDIR@ whack --trafficstatus") +try: + qname = argv.pop(0) + ttl = argv.pop(0) + ip = argv.pop(0) +except: + sys.exit("Bad arguments to ipsec _unbound") + +while (argv != []): + try: + gwprec = argv.pop(0) + gwtype = argv.pop(0) + gwalg = argv.pop(0) + gwid = argv.pop(0) + pubkey = argv.pop(0) + addkeyip = "ipsec whack --keyid @%s --addkey --pubkeyrsa 0s%s"%(ip, pubkey) + addkeyhostname = "ipsec whack --keyid @%s --addkey --pubkeyrsa 0s%s"%(qname, pubkey) + print("processing an IPSECKEY record for Opportunistic IPsec to %s(%s)"%(qname,ip)) + print(subprocess.call(addkeyip, shell=True)) + print(subprocess.call(addkeyhostname, shell=True)) + except: + sys.exit("failed to process an IPSECKEY record for Opportunistic IPsec to %s(%s)"%(qname,ip)) + +# done injecting all IPSECKEY records into pluto - try actual OE now +cmdoeip = "ipsec whack --oppohere %s --oppothere %s"%(myip, ip) +print(subprocess.check_output(cmdoeip, shell=True)) +#cmdoeqname = "ipsec whack --oppohere %s --oppothere %s"%(myip, qname) +#ret, output = commands.getstatusoutput(cmdoeqname) +print(subprocess.check_output("ipsec whack --trafficstatus", shell=True)) diff --git a/include/ietf_constants.h b/include/ietf_constants.h index 8a1ba5d..38fa4de 100644 --- a/include/ietf_constants.h +++ b/include/ietf_constants.h @@ -1215,7 +1215,7 @@ enum ikev2_cp_attribute_type { IKEv2_EXTERNAL_SOURCE_IP4_NAT_INFO = 23, IKEv2_TIMEOUT_PERIOD_FOR_LIVENESS_CHECK = 24, IKEv2_INTERNAL_DNS_DOMAIN = 25, - /* IKEv2_INTERNAL_DNSSEC_TA = 26 expected */ + IKEv2_INTERNAL_DNSSEC_TA = 26 }; diff --git a/lib/libswan/constants.c b/lib/libswan/constants.c index 9ea9872..ab6db3e 100644 --- a/lib/libswan/constants.c +++ b/lib/libswan/constants.c @@ -1365,13 +1365,12 @@ static const char *const ikev2_cp_attribute_type_name[] = { "IKEv2_EXTERNAL_SOURCE_IP4_NAT_INFO", /* 3gpp */ "IKEv2_TIMEOUT_PERIOD_FOR_LIVENESS_CHECK", /* 3gpp */ "IKEv2_INTERNAL_DNS_DOMAIN", /* draft-ietf-ipsecme-split-dns */ - /* "IKEv2_INTERNAL_DNSSEC_TA", draft-ietf-ipsecme-split-dns, no Code Point yet */ + "IKEv2_INTERNAL_DNSSEC_TA", /* draft-ietf-ipsecme-split-dns */ }; enum_names ikev2_cp_attribute_type_names = { IKEv2_CP_ATTR_RESERVED, - IKEv2_INTERNAL_DNS_DOMAIN, - /* IKEv2_INTERNAL_DNSSEC_TA, */ + IKEv2_INTERNAL_DNSSEC_TA, ARRAY_REF(ikev2_cp_attribute_type_name), NULL, /* prefix */ NULL diff --git a/programs/addconn/addconn.c b/programs/addconn/addconn.c index ae56972..e818e0e 100644 --- a/programs/addconn/addconn.c +++ b/programs/addconn/addconn.c @@ -416,12 +416,11 @@ int main(int argc, char *argv[]) if (verbose) printf(" Pass #1: Loading auto=add, auto=route and auto=start connections\n"); - for (conn = cfg->conns.tqh_first; - conn != NULL; - conn = conn->link.tqe_next) { + for (conn = cfg->conns.tqh_first; conn != NULL; conn = conn->link.tqe_next) { if (conn->desired_state == STARTUP_ADD || conn->desired_state == STARTUP_ONDEMAND || - conn->desired_state == STARTUP_START) { + conn->desired_state == STARTUP_START) + { if (verbose) printf(" %s", conn->name); resolve_defaultroute(conn); @@ -436,30 +435,22 @@ int main(int argc, char *argv[]) starter_whack_listen(cfg); if (verbose) - printf(" Pass #2: Routing auto=route and auto=start connections\n"); + printf(" Pass #2: Routing auto=route connections\n"); - for (conn = cfg->conns.tqh_first; - conn != NULL; - conn = conn->link.tqe_next) { - if (conn->desired_state == STARTUP_ADD || - conn->desired_state == STARTUP_ONDEMAND || - conn->desired_state == STARTUP_START) { + for (conn = cfg->conns.tqh_first; conn != NULL; conn = conn->link.tqe_next) { + if (conn->desired_state == STARTUP_ONDEMAND) + { if (verbose) printf(" %s", conn->name); - resolve_defaultroute(conn); - if (conn->desired_state == STARTUP_ONDEMAND || - conn->desired_state == STARTUP_START) { + if (conn->desired_state == STARTUP_ONDEMAND) starter_whack_route_conn(cfg, conn); - } } } if (verbose) printf(" Pass #3: Initiating auto=start connections\n"); - for (conn = cfg->conns.tqh_first; - conn != NULL; - conn = conn->link.tqe_next) { + for (conn = cfg->conns.tqh_first; conn != NULL; conn = conn->link.tqe_next) { if (conn->desired_state == STARTUP_START) { if (verbose) printf(" %s", conn->name); diff --git a/programs/_updown.netkey/_updown.netkey.in b/programs/_updown.netkey/_updown.netkey.in index 64b2808..b343445 100644 --- a/programs/_updown.netkey/_updown.netkey.in +++ b/programs/_updown.netkey/_updown.netkey.in @@ -745,6 +745,7 @@ case "${PLUTO_VERB}" in up-client) # connection to my client subnet coming up # If you are doing a custom version, firewall commands go here. + addvtiiface updateresolvconf addcat addsource