diff -Naur libreswan-3.29-orig/include/impair.h libreswan-3.29/include/impair.h --- libreswan-3.29-orig/include/impair.h 2019-06-10 10:22:04.000000000 -0400 +++ libreswan-3.29/include/impair.h 2019-06-11 19:22:39.786283961 -0400 @@ -1,6 +1,6 @@ -/* impair operation +/* impair operation, for libreswan * - * Copyright (C) 2019 Andrew Cagney + * Copyright (C) 2018-2019 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 @@ -22,9 +22,7 @@ #include "lswcdefs.h" /* - * How to impair something. This is just the start ... - * - * Extra enums go here. + * Meddle with the contents of a payload. */ enum send_impairment { @@ -35,6 +33,21 @@ SEND_ROOF, /* >= ROOF -> */ }; +/* + * Meddle with a specific exchange. + */ + +enum exchange_impairment { + NO_EXCHANGE = 0, + NOTIFICATION_EXCHANGE, + QUICK_EXCHANGE, + XAUTH_EXCHANGE, + DELETE_EXCHANGE, +}; + +/* + * add more here + */ #if 0 enum xxx_impair ...; #endif @@ -53,6 +66,10 @@ extern enum send_impairment impair_ike_key_length_attribute; extern enum send_impairment impair_child_key_length_attribute; +extern enum send_impairment impair_v1_hash_payload; +extern enum exchange_impairment impair_v1_hash_exchange; +extern bool impair_v1_hash_check; + /* * What whack sends across the wire for a impair. */ diff -Naur libreswan-3.29-orig/lib/libswan/impair.c libreswan-3.29/lib/libswan/impair.c --- libreswan-3.29-orig/lib/libswan/impair.c 2019-06-10 10:22:04.000000000 -0400 +++ libreswan-3.29/lib/libswan/impair.c 2019-06-11 19:22:54.290445191 -0400 @@ -1,5 +1,4 @@ -/* - * impair constants, for libreswan +/* impair constants, for libreswan * * Copyright (C) 2017-2019 Andrew Cagney * Copyright (C) 2019-2019 Paul Wouters @@ -125,6 +124,19 @@ static const struct keywords send_impairment_keywords = DIRECT_KEYWORDS("send impaired content", send_impairment_value); +static const struct keyword exchange_impairment_value[] = { +#define S(E, H) [E##_EXCHANGE] = { .name = "SEND_" #E, .sname = #E, .value = E##_EXCHANGE, .details = H, } + S(NO, "do not modify exchanges"), + S(QUICK, "modify IKEv1 QUICK exchanges"), + S(XAUTH, "modify IKEv1 XAUTH exchanges"), + S(NOTIFICATION, "modify notification (informational) exchanges"), + S(DELETE, "modify delete exchanges"), +#undef S +}; + +static const struct keywords exchange_impairment_keywords = + DIRECT_KEYWORDS("impaire exchange content", exchange_impairment_value); + struct impairment { const char *what; const char *help; @@ -182,6 +194,27 @@ .how_keynum = &send_impairment_keywords, V(impair_child_key_length_attribute), }, + + /* + * IKEv1: hash payloads + */ + { + .what = "v1-hash-check", + .help = "disable check of incoming IKEv1 hash payload", + V(impair_emitting), + }, + { + .what = "v1-hash-payload", + .help = "corrupt the outgoing HASH payload", + .how_keynum = &send_impairment_keywords, + V(impair_v1_hash_payload), + }, + { + .what = "v1-hash-exchange", + .help = "the outgoing exchange that should contain the corrupted HASH payload", + .how_keynum = &exchange_impairment_keywords, + V(impair_v1_hash_exchange), + }, }; static void help(const char *prefix, const struct impairment *cr) @@ -522,8 +555,9 @@ } /* - * declare these last so that all references are forced to use the - * declaration in the header. + * XXX: define these at the end of the file so that all references are + * forced to use the declaration in the header (help stop code + * refering to the wrong variable?). */ bool impair_revival; @@ -531,3 +565,6 @@ enum send_impairment impair_ke_payload; enum send_impairment impair_ike_key_length_attribute; enum send_impairment impair_child_key_length_attribute; +bool impair_v1_hash_check; +enum send_impairment impair_v1_hash_payload; +enum exchange_impairment impair_v1_hash_exchange; diff -Naur libreswan-3.29-orig/programs/pluto/ikev1.c libreswan-3.29/programs/pluto/ikev1.c --- libreswan-3.29-orig/programs/pluto/ikev1.c 2019-06-10 10:22:04.000000000 -0400 +++ libreswan-3.29/programs/pluto/ikev1.c 2019-06-11 19:27:44.516665524 -0400 @@ -157,6 +157,7 @@ #include "ikev1_dpd.h" #include "hostpair.h" #include "ip_address.h" +#include "ikev1_hash.h" #ifdef HAVE_NM #include "kernel.h" @@ -181,6 +182,8 @@ lset_t opt_payloads; /* optional payloads (any mumber) */ enum event_type timeout_event; ikev1_state_transition_fn *processor; + const char *message; + enum v1_hash_type hash_type; }; /* State Microcode Flags, in several groups */ @@ -255,6 +258,7 @@ static const struct state_v1_microcode v1_state_microcode_table[] = { #define P(n) LELEM(ISAKMP_NEXT_ ##n) +#define FM(F) .processor = F, .message = #F /***** Phase 1 Main Mode *****/ @@ -266,7 +270,9 @@ { STATE_MAIN_R0, STATE_MAIN_R1, SMF_ALL_AUTH | SMF_REPLY, P(SA), P(VID) | P(CR), - EVENT_SO_DISCARD, main_inI1_outR1 }, + EVENT_SO_DISCARD, + FM(main_inI1_outR1), + .hash_type = V1_HASH_NONE, }, /* STATE_MAIN_I1: R1 --> I2 * HDR, SA --> auth dependent @@ -281,7 +287,9 @@ { STATE_MAIN_I1, STATE_MAIN_I2, SMF_ALL_AUTH | SMF_INITIATOR | SMF_REPLY, P(SA), P(VID) | P(CR), - EVENT_RETRANSMIT, main_inR1_outI2 }, + EVENT_RETRANSMIT, + FM(main_inR1_outI2), + .hash_type = V1_HASH_NONE, }, /* STATE_MAIN_R1: I2 --> R2 * SMF_PSK_AUTH, SMF_DS_AUTH: HDR, KE, Ni --> HDR, KE, Nr @@ -294,17 +302,23 @@ { STATE_MAIN_R1, STATE_MAIN_R2, SMF_PSK_AUTH | SMF_DS_AUTH | SMF_REPLY | SMF_RETRANSMIT_ON_DUPLICATE, P(KE) | P(NONCE), P(VID) | P(CR) | P(NATD_RFC), - EVENT_RETRANSMIT, main_inI2_outR2 }, + EVENT_RETRANSMIT, + FM(main_inI2_outR2), + .hash_type = V1_HASH_NONE, }, { STATE_MAIN_R1, STATE_UNDEFINED, SMF_PKE_AUTH | SMF_REPLY | SMF_RETRANSMIT_ON_DUPLICATE, P(KE) | P(ID) | P(NONCE), P(VID) | P(CR) | P(HASH), - EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ }, + EVENT_RETRANSMIT, + FM(unexpected) /* ??? not yet implemented */, + .hash_type = V1_HASH_NONE, }, { STATE_MAIN_R1, STATE_UNDEFINED, SMF_RPKE_AUTH | SMF_REPLY | SMF_RETRANSMIT_ON_DUPLICATE, P(NONCE) | P(KE) | P(ID), P(VID) | P(CR) | P(HASH) | P(CERT), - EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ }, + EVENT_RETRANSMIT, + FM(unexpected) /* ??? not yet implemented */, + .hash_type = V1_HASH_NONE, }, /* for states from here on, output message must be encrypted */ @@ -319,17 +333,24 @@ { STATE_MAIN_I2, STATE_MAIN_I3, SMF_PSK_AUTH | SMF_DS_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY, P(KE) | P(NONCE), P(VID) | P(CR) | P(NATD_RFC), - EVENT_RETRANSMIT, main_inR2_outI3 }, + EVENT_RETRANSMIT, + FM(main_inR2_outI3), + /* calls main_mode_hash() after DH */ + .hash_type = V1_HASH_NONE, }, { STATE_MAIN_I2, STATE_UNDEFINED, SMF_PKE_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY, P(KE) | P(ID) | P(NONCE), P(VID) | P(CR), - EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ }, + EVENT_RETRANSMIT, + FM(unexpected) /* ??? not yet implemented */, + .hash_type = V1_HASH_NONE, }, { STATE_MAIN_I2, STATE_UNDEFINED, SMF_ALL_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY, P(NONCE) | P(KE) | P(ID), P(VID) | P(CR), - EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ }, + EVENT_RETRANSMIT, + FM(unexpected) /* ??? not yet implemented */, + .hash_type = V1_HASH_NONE, }, /* for states from here on, input message must be encrypted */ @@ -342,20 +363,34 @@ SMF_PSK_AUTH | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2, P(ID) | P(HASH), P(VID) | P(CR), - EVENT_SA_REPLACE, main_inI3_outR3 }, + EVENT_SA_REPLACE, + FM(main_inI3_outR3), + /* calls oakley_id_and_auth() which calls main_mode_hash() */ + /* RFC 2409: 5. Exchanges & 5.2 Phase 1 Authenticated With Public Key Encryption + HASH_I = prf(SKEYID, g^xi | g^xr | CKY-I | CKY-R | SAi_b | IDii_b ) */ + .hash_type = V1_HASH_NONE, }, { STATE_MAIN_R2, STATE_MAIN_R3, SMF_DS_AUTH | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2, P(ID) | P(SIG), P(VID) | P(CR) | P(CERT), - EVENT_SA_REPLACE, main_inI3_outR3 }, + EVENT_SA_REPLACE, + FM(main_inI3_outR3), + /* calls oakley_id_and_auth() which calls main_mode_hash() */ + /* RFC 2409: 5. Exchanges & 5.1 IKE Phase 1 Authenticated With Signatures + HASH_I = prf(SKEYID, g^xi | g^xr | CKY-I | CKY-R | SAi_b | IDii_b ) + SIG_I = SIGN(HASH_I) *", + SIG_I = SIGN(HASH_I) */ + .hash_type = V1_HASH_NONE, }, { STATE_MAIN_R2, STATE_UNDEFINED, SMF_PKE_AUTH | SMF_RPKE_AUTH | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2, P(HASH), P(VID) | P(CR), - EVENT_SA_REPLACE, unexpected /* ??? not yet implemented */ }, + EVENT_SA_REPLACE, + FM(unexpected) /* ??? not yet implemented */, + .hash_type = V1_HASH_NONE, }, /* STATE_MAIN_I3: R3 --> done * SMF_PSK_AUTH: HDR*, IDr1, HASH_R --> done @@ -367,31 +402,48 @@ SMF_PSK_AUTH | SMF_INITIATOR | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2, P(ID) | P(HASH), P(VID) | P(CR), - EVENT_SA_REPLACE, main_inR3 }, + EVENT_SA_REPLACE, + FM(main_inR3), + /* calls oakley_id_and_auth() which calls main_mode_hash() */ + /* RFC 2409: 5. Exchanges & 5.2 Phase 1 Authenticated With Public Key Encryption + HASH_R = prf(SKEYID, g^xr | g^xi | CKY-R | CKY-I | SAi_b | IDir_b ) */ + .hash_type = V1_HASH_NONE, }, { STATE_MAIN_I3, STATE_MAIN_I4, SMF_DS_AUTH | SMF_INITIATOR | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2, P(ID) | P(SIG), P(VID) | P(CR) | P(CERT), - EVENT_SA_REPLACE, main_inR3 }, + EVENT_SA_REPLACE, + FM(main_inR3), + /* calls oakley_id_and_auth() which calls main_mode_hash() */ + /* RFC 2409: 5. Exchanges & 5.1 IKE Phase 1 Authenticated With Signatures + HASH_R = prf(SKEYID, g^xr | g^xi | CKY-R | CKY-I | SAi_b | IDir_b ) + SIG_R = SIGN(HASH_R) */ + .hash_type = V1_HASH_NONE, }, { STATE_MAIN_I3, STATE_UNDEFINED, SMF_PKE_AUTH | SMF_RPKE_AUTH | SMF_INITIATOR | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2, P(HASH), P(VID) | P(CR), - EVENT_SA_REPLACE, unexpected /* ??? not yet implemented */ }, + EVENT_SA_REPLACE, + FM(unexpected) /* ??? not yet implemented */, + .hash_type = V1_HASH_NONE, }, /* STATE_MAIN_R3: can only get here due to packet loss */ { STATE_MAIN_R3, STATE_UNDEFINED, SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RETRANSMIT_ON_DUPLICATE, LEMPTY, LEMPTY, - EVENT_NULL, unexpected }, + EVENT_NULL, + FM(unexpected), + .hash_type = V1_HASH_NONE, }, /* STATE_MAIN_I4: can only get here due to packet loss */ { STATE_MAIN_I4, STATE_UNDEFINED, SMF_ALL_AUTH | SMF_INITIATOR | SMF_ENCRYPTED, LEMPTY, LEMPTY, - EVENT_NULL, unexpected }, + EVENT_NULL, + FM(unexpected), + .hash_type = V1_HASH_NONE, }, /***** Phase 1 Aggressive Mode *****/ @@ -413,7 +465,10 @@ { STATE_AGGR_R0, STATE_AGGR_R1, SMF_PSK_AUTH | SMF_DS_AUTH | SMF_REPLY, P(SA) | P(KE) | P(NONCE) | P(ID), P(VID) | P(NATD_RFC), - EVENT_SO_DISCARD, aggr_inI1_outR1 }, + EVENT_SO_DISCARD, + FM(aggr_inI1_outR1), + /* N/A */ + .hash_type = V1_HASH_NONE, }, /* STATE_AGGR_I1: * SMF_PSK_AUTH: HDR, SA, KE, Nr, IDir, HASH_R @@ -425,13 +480,24 @@ SMF_PSK_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2, P(SA) | P(KE) | P(NONCE) | P(ID) | P(HASH), P(VID) | P(NATD_RFC), - EVENT_SA_REPLACE, aggr_inR1_outI2 }, + EVENT_SA_REPLACE, + FM(aggr_inR1_outI2), + /* after DH calls oakley_id_and_auth() which calls main_mode_hash() */ + /* RFC 2409: 5. Exchanges & 5.2 Phase 1 Authenticated With Public Key Encryption + HASH_R = prf(SKEYID, g^xr | g^xi | CKY-R | CKY-I | SAi_b | IDir_b ) */ + .hash_type = V1_HASH_NONE, }, { STATE_AGGR_I1, STATE_AGGR_I2, SMF_DS_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2, P(SA) | P(KE) | P(NONCE) | P(ID) | P(SIG), P(VID) | P(NATD_RFC), - EVENT_SA_REPLACE, aggr_inR1_outI2 }, + EVENT_SA_REPLACE, + FM(aggr_inR1_outI2), + /* after DH calls oakley_id_and_auth() which calls main_mode_hash() */ + /* RFC 2409: 5. Exchanges & 5.1 IKE Phase 1 Authenticated With Signatures + HASH_R = prf(SKEYID, g^xr | g^xi | CKY-R | CKY-I | SAi_b | IDir_b ) + SIG_R = SIGN(HASH_R) */ + .hash_type = V1_HASH_NONE, }, /* STATE_AGGR_R1: * SMF_PSK_AUTH: HDR*, HASH_I --> done @@ -442,24 +508,39 @@ SMF_OUTPUT_ENCRYPTED | SMF_RELEASE_PENDING_P2 | SMF_RETRANSMIT_ON_DUPLICATE, P(HASH), P(VID) | P(NATD_RFC), - EVENT_SA_REPLACE, aggr_inI2 }, + EVENT_SA_REPLACE, + FM(aggr_inI2), + /* calls oakley_id_and_auth() which calls main_mode_hash() */ + /* RFC 2409: 5. Exchanges & 5.2 Phase 1 Authenticated With Public Key Encryption + HASH_I = prf(SKEYID, g^xi | g^xr | CKY-I | CKY-R | SAi_b | IDii_b ) */ + .hash_type = V1_HASH_NONE, }, { STATE_AGGR_R1, STATE_AGGR_R2, SMF_DS_AUTH | SMF_FIRST_ENCRYPTED_INPUT | SMF_OUTPUT_ENCRYPTED | SMF_RELEASE_PENDING_P2 | SMF_RETRANSMIT_ON_DUPLICATE, P(SIG), P(VID) | P(NATD_RFC), - EVENT_SA_REPLACE, aggr_inI2 }, + EVENT_SA_REPLACE, + FM(aggr_inI2), + /* calls oakley_id_and_auth() which calls main_mode_hash() */ + /* RFC 2409: 5. Exchanges & 5.1 IKE Phase 1 Authenticated With Signatures + HASH_I = prf(SKEYID, g^xi | g^xr | CKY-I | CKY-R | SAi_b | IDii_b ) + SIG_I = SIGN(HASH_I) */ + .hash_type = V1_HASH_NONE, }, /* STATE_AGGR_I2: can only get here due to packet loss */ { STATE_AGGR_I2, STATE_UNDEFINED, SMF_ALL_AUTH | SMF_INITIATOR | SMF_RETRANSMIT_ON_DUPLICATE, - LEMPTY, LEMPTY, EVENT_NULL, unexpected }, + LEMPTY, LEMPTY, EVENT_NULL, + FM(unexpected), + .hash_type = V1_HASH_NONE, }, /* STATE_AGGR_R2: can only get here due to packet loss */ { STATE_AGGR_R2, STATE_UNDEFINED, SMF_ALL_AUTH, - LEMPTY, LEMPTY, EVENT_NULL, unexpected }, + LEMPTY, LEMPTY, EVENT_NULL, + FM(unexpected), + .hash_type = V1_HASH_NONE, }, /***** Phase 2 Quick Mode *****/ @@ -478,7 +559,11 @@ { STATE_QUICK_R0, STATE_QUICK_R1, SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY, P(HASH) | P(SA) | P(NONCE), /* P(SA) | */ P(KE) | P(ID) | P(NATOA_RFC), - EVENT_RETRANSMIT, quick_inI1_outR1 }, + EVENT_RETRANSMIT, + FM(quick_inI1_outR1), + /* RFC 2409: 5.5 Phase 2 - Quick Mode: + HASH(1) = prf(SKEYID_a, M-ID | ) */ + .hash_type = V1_HASH_1, }, /* STATE_QUICK_I1: * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ] --> @@ -489,7 +574,11 @@ { STATE_QUICK_I1, STATE_QUICK_I2, SMF_ALL_AUTH | SMF_INITIATOR | SMF_ENCRYPTED | SMF_REPLY, P(HASH) | P(SA) | P(NONCE), /* P(SA) | */ P(KE) | P(ID) | P(NATOA_RFC), - EVENT_SA_REPLACE, quick_inR1_outI2 }, + EVENT_SA_REPLACE, + FM(quick_inR1_outI2), + /* RFC 2409: 5.5 Phase 2 - Quick Mode: + HASH(2) = prf(SKEYID_a, M-ID | Ni_b | ) */ + .hash_type = V1_HASH_2, }, /* STATE_QUICK_R1: HDR*, HASH(3) --> done * Installs outbound IPsec SAs, routing, etc. @@ -497,20 +586,28 @@ { STATE_QUICK_R1, STATE_QUICK_R2, SMF_ALL_AUTH | SMF_ENCRYPTED, P(HASH), LEMPTY, - EVENT_SA_REPLACE, quick_inI2 }, + EVENT_SA_REPLACE, + FM(quick_inI2), + /* RFC 2409: 5.5 Phase 2 - Quick Mode: + HASH(3) = prf(SKEYID_a, 0 | M-ID | Ni_b | Nr_b) */ + .hash_type = V1_HASH_3, }, /* STATE_QUICK_I2: can only happen due to lost packet */ { STATE_QUICK_I2, STATE_UNDEFINED, SMF_ALL_AUTH | SMF_INITIATOR | SMF_ENCRYPTED | SMF_RETRANSMIT_ON_DUPLICATE, LEMPTY, LEMPTY, - EVENT_NULL, unexpected }, + EVENT_NULL, + FM(unexpected), + .hash_type = V1_HASH_NONE, }, /* STATE_QUICK_R2: can only happen due to lost packet */ { STATE_QUICK_R2, STATE_UNDEFINED, SMF_ALL_AUTH | SMF_ENCRYPTED, LEMPTY, LEMPTY, - EVENT_NULL, unexpected }, + EVENT_NULL, + FM(unexpected), + .hash_type = V1_HASH_NONE, }, /***** informational messages *****/ @@ -522,7 +619,9 @@ { STATE_INFO, STATE_UNDEFINED, SMF_ALL_AUTH, LEMPTY, LEMPTY, - EVENT_NULL, informational }, + EVENT_NULL, + FM(informational), + .hash_type = V1_HASH_NONE, }, /* Informational Exchange (RFC 2408 4.8): * HDR* N/D @@ -531,29 +630,41 @@ { STATE_INFO_PROTECTED, STATE_UNDEFINED, SMF_ALL_AUTH | SMF_ENCRYPTED, P(HASH), LEMPTY, - EVENT_NULL, informational }, + EVENT_NULL, + FM(informational), + /* RFC 2409: 5.7 ISAKMP Informational Exchanges: + HASH(1) = prf(SKEYID_a, M-ID | N/D) */ + .hash_type = V1_HASH_1, }, { STATE_XAUTH_R0, STATE_XAUTH_R1, SMF_ALL_AUTH | SMF_ENCRYPTED, P(MCFG_ATTR) | P(HASH), P(VID), - EVENT_NULL, xauth_inR0 }, /* Re-transmit may be done by previous state */ + EVENT_NULL, + FM(xauth_inR0), + /* RFC ????: */ + .hash_type = V1_HASH_1, }, /* Re-transmit may be done by previous state */ { STATE_XAUTH_R1, STATE_MAIN_R3, SMF_ALL_AUTH | SMF_ENCRYPTED, P(MCFG_ATTR) | P(HASH), P(VID), - EVENT_SA_REPLACE, xauth_inR1 }, + EVENT_SA_REPLACE, + FM(xauth_inR1), + /* RFC ????: */ + .hash_type = V1_HASH_1, }, #if 0 /* for situation where there is XAUTH + ModeCFG */ { STATE_XAUTH_R2, STATE_XAUTH_R3, SMF_ALL_AUTH | SMF_ENCRYPTED, P(MCFG_ATTR) | P(HASH), P(VID), - EVENT_SA_REPLACE, xauth_inR2 }, + EVENT_SA_REPLACE, + FM(xauth_inR2), }, { STATE_XAUTH_R3, STATE_MAIN_R3, SMF_ALL_AUTH | SMF_ENCRYPTED, P(MCFG_ATTR) | P(HASH), P(VID), - EVENT_SA_REPLACE, xauth_inR3 }, + EVENT_SA_REPLACE, + FM(xauth_inR3), }, #endif /* MODE_CFG_x: @@ -568,37 +679,57 @@ { STATE_MODE_CFG_R0, STATE_MODE_CFG_R1, SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY, P(MCFG_ATTR) | P(HASH), P(VID), - EVENT_SA_REPLACE, modecfg_inR0 }, + EVENT_SA_REPLACE, + FM(modecfg_inR0), + /* RFC ????: */ + .hash_type = V1_HASH_1, }, { STATE_MODE_CFG_R1, STATE_MODE_CFG_R2, SMF_ALL_AUTH | SMF_ENCRYPTED, P(MCFG_ATTR) | P(HASH), P(VID), - EVENT_SA_REPLACE, modecfg_inR1 }, + EVENT_SA_REPLACE, + FM(modecfg_inR1), + /* RFC ????: */ + .hash_type = V1_HASH_1, }, { STATE_MODE_CFG_R2, STATE_UNDEFINED, SMF_ALL_AUTH | SMF_ENCRYPTED, LEMPTY, LEMPTY, - EVENT_NULL, unexpected }, + EVENT_NULL, + FM(unexpected), + .hash_type = V1_HASH_NONE, }, { STATE_MODE_CFG_I1, STATE_MAIN_I4, SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2, P(MCFG_ATTR) | P(HASH), P(VID), - EVENT_SA_REPLACE, modecfg_inR1 }, + EVENT_SA_REPLACE, + FM(modecfg_inR1), + /* RFC ????: */ + .hash_type = V1_HASH_1, }, { STATE_XAUTH_I0, STATE_XAUTH_I1, SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2, P(MCFG_ATTR) | P(HASH), P(VID), - EVENT_RETRANSMIT, xauth_inI0 }, + EVENT_RETRANSMIT, + FM(xauth_inI0), + /* RFC ????: */ + .hash_type = V1_HASH_1, }, { STATE_XAUTH_I1, STATE_MAIN_I4, SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2, P(MCFG_ATTR) | P(HASH), P(VID), - EVENT_RETRANSMIT, xauth_inI1 }, + EVENT_RETRANSMIT, + FM(xauth_inI1), + /* RFC ????: */ + .hash_type = V1_HASH_1, }, { STATE_IKEv1_ROOF, STATE_IKEv1_ROOF, LEMPTY, LEMPTY, LEMPTY, - EVENT_NULL, NULL }, + EVENT_NULL, NULL, + .hash_type = V1_HASH_NONE, }, + +#undef FM #undef P }; @@ -748,6 +879,11 @@ DBGF(DBG_TMI, "processing IKEv1 state transition %s -> %s", from->fs_short_name, to->fs_short_name); + if (t->message == NULL) { + PEXPECT_LOG("transition %s -> %s missing .message", + from->fs_short_name, to->fs_short_name); + } + /* * Point .fs_v1_transitions at to the first entry in * v1_state_microcode_table for that state. All other @@ -786,10 +922,32 @@ * always true of a state? */ if ((t->flags & from->fs_flags) != from->fs_flags) { - DBGF(DBG_BASE, "transition %s -> %s missing flags 0x%"PRIxLSET, - from->fs_short_name, to->fs_short_name, from->fs_flags); + DBGF(DBG_BASE, "transition %s -> %s (%s) missing flags 0x%"PRIxLSET, + from->fs_short_name, to->fs_short_name, + t->message, from->fs_flags); } from->fs_flags |= t->flags & SMF_RETRANSMIT_ON_DUPLICATE; + + if (!(t->flags & SMF_FIRST_ENCRYPTED_INPUT) && + (t->flags & SMF_INPUT_ENCRYPTED) && + t->processor != unexpected) { + /* + * The first encrypted message carries + * authentication information so isn't + * applicable. Other encrypted messages + * require integrity via the HASH payload. + */ + if (!(t->req_payloads & LELEM(ISAKMP_NEXT_HASH))) { + PEXPECT_LOG("transition %s -> %s (%s) missing HASH payload", + from->fs_short_name, to->fs_short_name, + t->message); + } + if (t->hash_type == V1_HASH_NONE) { + PEXPECT_LOG("transition %s -> %s (%s) missing HASH protection", + from->fs_short_name, to->fs_short_name, + t->message); + } + } } /* @@ -2252,30 +2410,9 @@ } } - if (md->hdr.isa_xchg == ISAKMP_XCHG_INFO && - md->hdr.isa_np == ISAKMP_NEXT_HASH) { - pb_stream *const hash_pbs = &(md)->chain[ISAKMP_NEXT_HASH]->pbs; - u_char hash_val[MAX_DIGEST_LEN]; - size_t hash_len = quick_mode_hash12(hash_val, hash_pbs->roof, - md->message_pbs.roof, - st, &md->hdr.isa_msgid, FALSE); - if (pbs_left(hash_pbs) != hash_len) { - loglog(RC_LOG_SERIOUS, - "received 'informational' message HASH(1) data is the wrong length (received %zu bytes but expected %zu)", - pbs_left(hash_pbs), hash_len); - return; - } - if (!memeq(hash_pbs->cur, hash_val, hash_len)) { - if (DBGP(DBG_CRYPT)) { - DBG_dump("received 'informational':", - hash_pbs->cur, pbs_left(hash_pbs)); - } - loglog(RC_LOG_SERIOUS, - "received 'informational' message HASH(1) data does not match computed value"); - return; - } else { - dbg("received 'informational' message HASH(1) data ok"); - } + if (!check_v1_HASH(smc->hash_type, smc->message, st, md)) { + /*SEND_NOTIFICATION(INVALID_HASH_INFORMATION);*/ + return; } /* more sanity checking: enforce most ordering constraints */ diff -Naur libreswan-3.29-orig/programs/pluto/ikev1_hash.c libreswan-3.29/programs/pluto/ikev1_hash.c --- libreswan-3.29-orig/programs/pluto/ikev1_hash.c 1969-12-31 19:00:00.000000000 -0500 +++ libreswan-3.29/programs/pluto/ikev1_hash.c 2019-06-11 19:24:00.543181473 -0400 @@ -0,0 +1,158 @@ +/* IKEv1 HASH payload wierdness, for Libreswan + * + * Copyright (C) 2019 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 "ikev1_hash.h" + +#include "state.h" +#include "crypt_prf.h" +#include "ike_alg.h" +#include "lswlog.h" +#include "demux.h" +#include "impair.h" + +bool emit_v1_HASH(enum v1_hash_type hash_type, const char *what, + enum exchange_impairment exchange, + struct state *st, struct v1_hash_fixup *fixup, + pb_stream *rbody) +{ + zero(fixup); + fixup->what = what; + fixup->hash_type = hash_type; + fixup->impair = (impair_v1_hash_exchange == exchange + ? impair_v1_hash_payload : SEND_NORMAL); + if (fixup->impair == SEND_OMIT) { + libreswan_log("IMPAIR: omitting HASH payload for %s", what); + return true; + } + pb_stream hash_pbs; + if (!ikev1_out_generic(0, &isakmp_hash_desc, rbody, &hash_pbs)) { + return false; + } + if (fixup->impair == SEND_EMPTY) { + libreswan_log("IMPAIR: sending HASH payload with no data for %s", what); + } else { + /* reserve space for HASH data */ + fixup->hash_data = chunk(hash_pbs.cur, st->st_oakley.ta_prf->prf_output_size); + if (!out_zero(fixup->hash_data.len, &hash_pbs, "HASH DATA")) + return false; + } + close_output_pbs(&hash_pbs); + /* save start of rest of message for later */ + fixup->body = rbody->cur; + return true; +} + +void fixup_v1_HASH(struct state *st, const struct v1_hash_fixup *fixup, + msgid_t msgid, const uint8_t *roof) +{ + if (fixup->impair >= SEND_ROOF) { + libreswan_log("IMPAIR: setting HASH payload bytes to %02x", + fixup->impair - SEND_ROOF); + /* chunk_fill()? */ + memset(fixup->hash_data.ptr, fixup->impair - SEND_ROOF, + fixup->hash_data.len); + return; + } else if (fixup->impair != SEND_NORMAL) { + /* already logged above? */ + return; + } + struct crypt_prf *hash = + crypt_prf_init_symkey("HASH(1)", st->st_oakley.ta_prf, + "SKEYID_a", st->st_skeyid_a_nss); + /* msgid */ + passert(sizeof(msgid_t) == sizeof(uint32_t)); + msgid_t raw_msgid = htonl(msgid); + switch (fixup->hash_type) { + case V1_HASH_1: + /* HASH(1) = prf(SKEYID_a, M-ID | payload ) */ + crypt_prf_update_bytes(hash, "M-ID", &raw_msgid, sizeof(raw_msgid)); + crypt_prf_update_bytes(hash, "payload", + fixup->body, roof - fixup->body); + break; + case V1_HASH_2: + /* HASH(2) = prf(SKEYID_a, M-ID | Ni_b | payload ) */ + crypt_prf_update_bytes(hash, "M-ID", &raw_msgid, sizeof(raw_msgid)); + crypt_prf_update_chunk(hash, "Ni_b", st->st_ni); + crypt_prf_update_bytes(hash, "payload", + fixup->body, roof - fixup->body); + break; + case V1_HASH_3: + /* HASH(3) = prf(SKEYID_a, 0 | M-ID | Ni_b | Nr_b) */ + crypt_prf_update_byte(hash, "0", 0); + crypt_prf_update_bytes(hash, "M-ID", &raw_msgid, sizeof(raw_msgid)); + crypt_prf_update_chunk(hash, "Ni_b", st->st_ni); + crypt_prf_update_chunk(hash, "Nr_b", st->st_nr); + break; + default: + bad_case(fixup->hash_type); + } + /* stuff result into hash_data */ + passert(fixup->hash_data.len == st->st_oakley.ta_prf->prf_output_size); + crypt_prf_final_bytes(&hash, fixup->hash_data.ptr, fixup->hash_data.len); + if (DBGP(DBG_BASE)) { + DBG_log("%s HASH(%u):", fixup->what, fixup->hash_type); + DBG_dump_chunk(NULL, fixup->hash_data); + } +} + +bool check_v1_HASH(enum v1_hash_type type, const char *what, + struct state *st, struct msg_digest *md) +{ + if (type == V1_HASH_NONE) { + dbg("message '%s' HASH payload not checked early", what); + return true; + } + if (impair_v1_hash_check) { + libreswan_log("IMPAIR: skipping check of '%s' HASH payload", what); + return true; + } + if (md->hdr.isa_np != ISAKMP_NEXT_HASH) { + loglog(RC_LOG_SERIOUS, "received '%s' message is missing a HASH(%u) payload", + what, type); + return false; + } + pb_stream *hash_pbs = &md->chain[ISAKMP_NEXT_HASH]->pbs; + chunk_t received_hash = same_in_pbs_left_as_chunk(hash_pbs); + if (received_hash.len != st->st_oakley.ta_prf->prf_output_size) { + loglog(RC_LOG_SERIOUS, + "received '%s' message HASH(%u) data is the wrong length (received %zd bytes but expected %zd)", + what, type, received_hash.len, st->st_oakley.ta_prf->prf_output_size); + return false; + } + /* compute the expected hash */ + uint8_t hash_val[MAX_DIGEST_LEN]; + passert(sizeof(hash_val) >= st->st_oakley.ta_prf->prf_output_size); + struct v1_hash_fixup expected = { + .hash_data = chunk(hash_val, st->st_oakley.ta_prf->prf_output_size), + .body = received_hash.ptr + received_hash.len, + .what = what, + .hash_type = type, + }; + fixup_v1_HASH(st, &expected, md->hdr.isa_msgid, md->message_pbs.roof); + /* does it match? */ + if (!chunk_eq(received_hash, expected.hash_data)) { + if (DBGP(DBG_BASE)) { + DBG_log("received %s HASH_DATA:", what); + DBG_dump_chunk(NULL, received_hash); + } + loglog(RC_LOG_SERIOUS, + "received '%s' message HASH(%u) data does not match computed value", + what, type); + return false; + } + dbg("received '%s' message HASH(%u) data ok", what, type); + return true; +} diff -Naur libreswan-3.29-orig/programs/pluto/ikev1_hash.h libreswan-3.29/programs/pluto/ikev1_hash.h --- libreswan-3.29-orig/programs/pluto/ikev1_hash.h 1969-12-31 19:00:00.000000000 -0500 +++ libreswan-3.29/programs/pluto/ikev1_hash.h 2019-06-11 19:24:00.543181473 -0400 @@ -0,0 +1,77 @@ +/* IKEv1 HASH payload wierdness, for Libreswan + * + * Copyright (C) 2019 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_HASH_H +#define IKEV1_HASH_H + +#include +#include + +#include "chunk.h" +#include "defs.h" /* for msgid_t */ +#include "packet.h" /* for pb_stream */ +#include "impair.h" + +struct state; +struct msg_digest; + +/* + * RFC 2409: 5.5 Phase 2 - Quick Mode + * + * HASH(1) = prf(SKEYID_a, M-ID | SA | Ni [ | KE ] [ | IDci | IDcr ) + * aka HASH(1) = prf(SKEYID_a, M-ID | payload ) + * + * HASH(2) = prf(SKEYID_a, M-ID | Ni_b | SA | Nr [ | KE ] [ | IDci | IDcr ) + * aka HASH(2) = prf(SKEYID_a, M-ID | Ni_b | payload ) + * + * HASH(3) = prf(SKEYID_a, 0 | M-ID | Ni_b | Nr_b) + */ + +enum v1_hash_type { + V1_HASH_NONE, + V1_HASH_1 = 1, + V1_HASH_2 = 2, + V1_HASH_3 = 3, +}; + +/* + * Emit (saving where it is) and fixup (a previously saved) v1 HASH + * payload. + */ + +struct v1_hash_fixup { + chunk_t hash_data; + const uint8_t *body; + msgid_t msgid; + const char *what; + enum send_impairment impair; + enum v1_hash_type hash_type; +}; + +bool emit_v1_HASH(enum v1_hash_type type, const char *what, + enum exchange_impairment exchange, struct state *st, + struct v1_hash_fixup *hash_fixup, pb_stream *out_pbs); + +void fixup_v1_HASH(struct state *st, const struct v1_hash_fixup *data, + msgid_t msgid, const uint8_t *roof); + +/* + * Check the IKEv1 HASH payload. + */ +bool check_v1_HASH(enum v1_hash_type type, const char *what, + struct state *st, struct msg_digest *md); + +#endif diff -Naur libreswan-3.29-orig/programs/pluto/ikev1_main.c libreswan-3.29/programs/pluto/ikev1_main.c --- libreswan-3.29-orig/programs/pluto/ikev1_main.c 2019-06-10 10:22:04.000000000 -0400 +++ libreswan-3.29/programs/pluto/ikev1_main.c 2019-06-11 19:23:55.362124010 -0400 @@ -65,6 +65,7 @@ #include "fetch.h" #include "asn1.h" #include "pending.h" +#include "ikev1_hash.h" #include "crypto.h" #include "secrets.h" @@ -1547,6 +1548,10 @@ "received Hash Payload does not match computed value"); /* XXX Could send notification back */ r = STF_FAIL + INVALID_HASH_INFORMATION; + } else { + dbg("received '%s' message HASH_%s data ok", + aggrmode ? "Aggr" : "Main", + initiator ? "R" : "I" /*reverse*/); } break; } @@ -1555,6 +1560,11 @@ { r = RSA_check_signature(st, hash_val, hash_len, &md->chain[ISAKMP_NEXT_SIG]->pbs, 0 /* for ikev2 only*/); + if (r != STF_OK) { + dbg("received '%s' message SIG_%s data did not match computed value", + aggrmode ? "Aggr" : "Main", + initiator ? "R" : "I" /*reverse*/); + } break; } /* These are the only IKEv1 AUTH methods we support */ @@ -1862,14 +1872,11 @@ } stf_status send_isakmp_notification(struct state *st, - uint16_t type, const void *data, - size_t len) + uint16_t type, const void *data, + size_t len) { msgid_t msgid; pb_stream rbody; - u_char - *r_hashval, /* where in reply to jam hash value */ - *r_hash_start; /* start of what is to be hashed */ msgid = generate_msgid(st); @@ -1879,7 +1886,6 @@ /* HDR* */ { struct isakmp_hdr hdr = { - .isa_np = ISAKMP_NEXT_HASH, .isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION, .isa_xchg = ISAKMP_XCHG_INFO, @@ -1891,8 +1897,13 @@ if (!out_struct(&hdr, &isakmp_hdr_desc, &reply_stream, &rbody)) return STF_INTERNAL_ERROR; } - /* HASH -- create and note space to be filled later */ - START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_N); + + struct v1_hash_fixup hash_fixup; + if (!emit_v1_HASH(V1_HASH_1, "notification", + NOTIFICATION_EXCHANGE, + st, &hash_fixup, &rbody)) { + return STF_INTERNAL_ERROR; + } /* NOTIFY */ { @@ -1919,23 +1930,8 @@ close_output_pbs(¬ify_pbs); } + fixup_v1_HASH(st, &hash_fixup, msgid, rbody.cur); - { - /* finish computing HASH */ - struct hmac_ctx ctx; - - hmac_init(&ctx, st->st_oakley.ta_prf, st->st_skeyid_a_nss); - passert(sizeof(msgid_t) == sizeof(uint32_t)); - msgid_t raw_msgid = htonl(msgid); - hmac_update(&ctx, (const void *)&raw_msgid, sizeof(raw_msgid)); - hmac_update(&ctx, r_hash_start, rbody.cur - r_hash_start); - hmac_final(r_hashval, &ctx); - - DBG(DBG_CRYPT, { - DBG_log("HASH computed:"); - DBG_dump("", r_hashval, ctx.hmac_digest_len); - }); - } /* * save old IV (this prevents from copying a whole new state object * for NOTIFICATION / DELETE messages we don't need to maintain a state @@ -1984,13 +1980,9 @@ pb_stream pbs; pb_stream r_hdr_pbs; - u_char *r_hashval, *r_hash_start; static monotime_t last_malformed = MONOTIME_EPOCH; monotime_t n = mononow(); - r_hashval = NULL; - r_hash_start = NULL; - switch (type) { case PAYLOAD_MALFORMED: /* only send one per second. */ @@ -2065,7 +2057,6 @@ struct isakmp_hdr hdr = { .isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION, - .isa_np = encst ? ISAKMP_NEXT_HASH : ISAKMP_NEXT_N, .isa_xchg = ISAKMP_XCHG_INFO, .isa_msgid = msgid, .isa_flags = encst ? ISAKMP_FLAGS_v1_ENCRYPTION : 0, @@ -2078,15 +2069,14 @@ } /* HASH -- value to be filled later */ - if (encst) { - pb_stream hash_pbs; - passert(ikev1_out_generic(ISAKMP_NEXT_N, &isakmp_hash_desc, &r_hdr_pbs, - &hash_pbs)); - r_hashval = hash_pbs.cur; /* remember where to plant value */ - passert(out_zero(encst->st_oakley.ta_prf->prf_output_size, - &hash_pbs, "HASH(1)")); - close_output_pbs(&hash_pbs); - r_hash_start = r_hdr_pbs.cur; /* hash from after HASH(1) */ + struct v1_hash_fixup hash_fixup; + if (encst != NULL) { + if (!emit_v1_HASH(V1_HASH_1, "send notification", + NOTIFICATION_EXCHANGE, + encst, &hash_fixup, &r_hdr_pbs)) { + /* return STF_INTERNAL_ERROR; */ + return; + } } /* Notification Payload */ @@ -2111,21 +2101,8 @@ } /* calculate hash value and patch into Hash Payload */ - if (encst) { - struct hmac_ctx ctx; - - hmac_init(&ctx, encst->st_oakley.ta_prf, - encst->st_skeyid_a_nss); - passert(sizeof(msgid_t) == sizeof(uint32_t)); - msgid_t raw_msgid = htonl(msgid); - hmac_update(&ctx, (const void *)&raw_msgid, sizeof(raw_msgid)); - hmac_update(&ctx, r_hash_start, r_hdr_pbs.cur - r_hash_start); - hmac_final(r_hashval, &ctx); - - DBG(DBG_CRYPT, { - DBG_log("HASH(1) computed:"); - DBG_dump("", r_hashval, ctx.hmac_digest_len); - }); + if (encst != NULL) { + fixup_v1_HASH(encst, &hash_fixup, msgid, r_hdr_pbs.cur); } if (encst != NULL) { @@ -2242,9 +2219,6 @@ struct state *p1st; ip_said said[EM_MAXRELSPIS]; ip_said *ns = said; - u_char - *r_hashval, /* where in reply to jam hash value */ - *r_hash_start; /* start of what is to be hashed */ bool isakmp_sa = FALSE; /* If there are IPsec SA's related to this state struct... */ @@ -2288,7 +2262,6 @@ struct isakmp_hdr hdr = { .isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION, - .isa_np = ISAKMP_NEXT_HASH, .isa_xchg = ISAKMP_XCHG_INFO, .isa_msgid = msgid, .isa_flags = ISAKMP_FLAGS_v1_ENCRYPTION, @@ -2300,16 +2273,10 @@ } /* HASH -- value to be filled later */ - { - pb_stream hash_pbs; - - passert(ikev1_out_generic(ISAKMP_NEXT_D, &isakmp_hash_desc, &r_hdr_pbs, - &hash_pbs)); - r_hashval = hash_pbs.cur; /* remember where to plant value */ - passert(out_zero(p1st->st_oakley.ta_prf->prf_output_size, - &hash_pbs, "HASH(1)")); - close_output_pbs(&hash_pbs); - r_hash_start = r_hdr_pbs.cur; /* hash from after HASH(1) */ + struct v1_hash_fixup hash_fixup; + if (!emit_v1_HASH(V1_HASH_1, "send delete", DELETE_EXCHANGE, + p1st, &hash_fixup, &r_hdr_pbs)) { + return /* STF_INTERNAL_ERROR */; } /* Delete Payloads */ @@ -2375,22 +2342,7 @@ } /* calculate hash value and patch into Hash Payload */ - { - struct hmac_ctx ctx; - - hmac_init(&ctx, p1st->st_oakley.ta_prf, - p1st->st_skeyid_a_nss); - passert(sizeof(msgid_t) == sizeof(uint32_t)); - msgid_t raw_msgid = htonl(msgid); - hmac_update(&ctx, (const void *)&raw_msgid, sizeof(raw_msgid)); - hmac_update(&ctx, r_hash_start, r_hdr_pbs.cur - r_hash_start); - hmac_final(r_hashval, &ctx); - - DBG(DBG_CRYPT, { - DBG_log("HASH(1) computed:"); - DBG_dump("", r_hashval, ctx.hmac_digest_len); - }); - } + fixup_v1_HASH(p1st, &hash_fixup, msgid, r_hdr_pbs.cur); /* * Do a dance to avoid needing a new state object. diff -Naur libreswan-3.29-orig/programs/pluto/ikev1_quick.c libreswan-3.29/programs/pluto/ikev1_quick.c --- libreswan-3.29-orig/programs/pluto/ikev1_quick.c 2019-06-10 10:22:04.000000000 -0400 +++ libreswan-3.29/programs/pluto/ikev1_quick.c 2019-06-11 19:28:00.687844878 -0400 @@ -81,6 +81,7 @@ #include "pluto_x509.h" #include "ip_address.h" #include "af_info.h" +#include "ikev1_hash.h" #include @@ -660,69 +661,6 @@ return !bad_proposal; } -/* Compute HASH(1), HASH(2) of Quick Mode. - * HASH(1) is part of Quick I1 message. - * HASH(2) is part of Quick R1 message. - * Used by: quick_outI1, quick_inI1_outR1 (twice), quick_inR1_outI2 - * (see RFC 2409 "IKE" 5.5, pg. 18 or draft-ietf-ipsec-ike-01.txt 6.2 pg 25) - */ -size_t quick_mode_hash12(u_char *dest, const u_char *start, - const u_char *roof, - const struct state *st, const msgid_t *msgid, - bool hash2) -{ - struct hmac_ctx ctx; - -#if 0 /* if desperate to debug hashing */ -# define hmac_update(ctx, ptr, len) { \ - DBG_dump("hash input", (ptr), (len)); \ - (hmac_update)((ctx), (ptr), (len)); \ -} - DBG_dump("hash key", st->st_skeyid_a.ptr, st->st_skeyid_a.len); -#endif - hmac_init(&ctx, st->st_oakley.ta_prf, st->st_skeyid_a_nss); - passert(sizeof(msgid_t) == sizeof(uint32_t)); - msgid_t raw_msgid = htonl(*msgid); - hmac_update(&ctx, (const void *)&raw_msgid, sizeof(raw_msgid)); - if (hash2) - hmac_update_chunk(&ctx, st->st_ni); /* include Ni_b in the hash */ - hmac_update(&ctx, start, roof - start); - hmac_final(dest, &ctx); - - DBG(DBG_CRYPT, { - DBG_log("HASH(%d) computed:", hash2 + 1); - DBG_dump("", dest, ctx.hmac_digest_len); - }); - return ctx.hmac_digest_len; - -# undef hmac_update -} - -/* Compute HASH(3) in Quick Mode (part of Quick I2 message). - * Used by: quick_inR1_outI2, quick_inI2 - * See RFC2409 "The Internet Key Exchange (IKE)" 5.5. - * NOTE: this hash (unlike HASH(1) and HASH(2)) ONLY covers the - * Message ID and Nonces. This is a mistake. - */ -static size_t quick_mode_hash3(u_char *dest, struct state *st) -{ - struct hmac_ctx ctx; - - hmac_init(&ctx, st->st_oakley.ta_prf, st->st_skeyid_a_nss); - hmac_update(&ctx, (const u_char *)"\0", 1); - passert(sizeof(msgid_t) == sizeof(uint32_t)); - msgid_t raw_msgid = htonl(st->st_msgid); - hmac_update(&ctx, (const void*)&raw_msgid, sizeof(raw_msgid)); - hmac_update_chunk(&ctx, st->st_ni); - hmac_update_chunk(&ctx, st->st_nr); - hmac_final(dest, &ctx); - if (DBGP(DBG_CRYPT)) { - DBG_dump("HASH(3) computed:", dest, - ctx.hmac_digest_len); - } - return ctx.hmac_digest_len; -} - /* Compute Phase 2 IV. * Uses Phase 1 IV from st_iv; puts result in st_new_iv. */ @@ -879,9 +817,6 @@ struct state *isakmp_sa = state_with_serialno(st->st_clonedfrom); struct connection *c = st->st_connection; pb_stream rbody; - u_char /* set by START_HASH_PAYLOAD: */ - *r_hashval, /* where in reply to jam hash value */ - *r_hash_start; /* start of what is to be hashed */ bool has_client = c->spd.this.has_client || c->spd.that.has_client || c->spd.this.protocol != 0 || c->spd.that.protocol != 0 || c->spd.this.port != 0 || c->spd.that.port != 0; @@ -915,7 +850,6 @@ struct isakmp_hdr hdr = { .isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION, - .isa_np = ISAKMP_NEXT_HASH, .isa_xchg = ISAKMP_XCHG_QUICK, .isa_msgid = st->st_msgid, .isa_flags = ISAKMP_FLAGS_v1_ENCRYPTION, @@ -930,7 +864,11 @@ } /* HASH(1) -- create and note space to be filled later */ - START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_SA); + struct v1_hash_fixup hash_fixup; + if (!emit_v1_HASH(V1_HASH_1, "outI1", QUICK_EXCHANGE, + st, &hash_fixup, &rbody)) { + return STF_INTERNAL_ERROR; + } /* SA out */ @@ -1010,8 +948,7 @@ } /* finish computing HASH(1), inserting it in output */ - (void) quick_mode_hash12(r_hashval, r_hash_start, rbody.cur, - st, &st->st_msgid, FALSE); + fixup_v1_HASH(st, &hash_fixup, st->st_msgid, rbody.cur); /* encrypt message, except for fixed part of header */ @@ -1098,13 +1035,6 @@ struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID]; struct verify_oppo_bundle b; - /* HASH(1) in */ - CHECK_QUICK_HASH(md, - quick_mode_hash12(hash_val, hash_pbs->roof, - md->message_pbs.roof, - p1st, &md->hdr.isa_msgid, FALSE), - "HASH(1)", "Quick I1"); - /* [ IDci, IDcr ] in * We do this now (probably out of physical order) because * we wish to select the correct connection before we consult @@ -1577,9 +1507,6 @@ struct state *st = md->st; struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID]; struct payload_digest *const sapd = md->chain[ISAKMP_NEXT_SA]; - u_char /* set by START_HASH_PAYLOAD: */ - *r_hashval, /* where in reply to jam hash value */ - *r_hash_start; /* from where to start hashing */ /* Start the output packet. * @@ -1594,12 +1521,15 @@ /* HDR* out */ pb_stream rbody; - ikev1_init_out_pbs_echo_hdr(md, TRUE, ISAKMP_NEXT_HASH, + ikev1_init_out_pbs_echo_hdr(md, TRUE, 0, &reply_stream, reply_buffer, sizeof(reply_buffer), &rbody); - /* HASH(2) out -- first pass */ - START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_SA); + struct v1_hash_fixup hash_fixup; + if (!emit_v1_HASH(V1_HASH_2, "quick inR1 outI2", + QUICK_EXCHANGE, st, &hash_fixup, &rbody)) { + return STF_INTERNAL_ERROR; + } passert(st->st_connection != NULL); @@ -1720,8 +1650,7 @@ } /* Compute reply HASH(2) and insert in output */ - (void)quick_mode_hash12(r_hashval, r_hash_start, rbody.cur, - st, &st->st_msgid, TRUE); + fixup_v1_HASH(st, &hash_fixup, st->st_msgid, rbody.cur); /* Derive new keying material */ compute_keymats(st); @@ -1758,13 +1687,6 @@ stf_status quick_inR1_outI2(struct state *st, struct msg_digest *md) { - /* HASH(2) in */ - CHECK_QUICK_HASH(md, - quick_mode_hash12(hash_val, hash_pbs->roof, - md->message_pbs.roof, - st, &st->st_msgid, TRUE), - "HASH(2)", "Quick R1"); - /* SA in */ { struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA]; @@ -1812,7 +1734,7 @@ struct connection *c = st->st_connection; pb_stream rbody; - ikev1_init_out_pbs_echo_hdr(md, TRUE, ISAKMP_NEXT_HASH, + ikev1_init_out_pbs_echo_hdr(md, TRUE, 0, &reply_stream, reply_buffer, sizeof(reply_buffer), &rbody); @@ -1907,7 +1829,7 @@ /* HASH(3) out -- sometimes, we add more content */ { - u_char *r_hashval; /* set by START_HASH_PAYLOAD */ + struct v1_hash_fixup hash_fixup; #ifdef IMPAIR_UNALIGNED_I2_MSG { @@ -1945,12 +1867,13 @@ } } #else - START_HASH_PAYLOAD_NO_R_HASH_START(rbody, - ISAKMP_NEXT_NONE); + if (!emit_v1_HASH(V1_HASH_3, "quick_inR1_outI2", + QUICK_EXCHANGE, st, &hash_fixup, &rbody)) { + return STF_INTERNAL_ERROR; + } #endif - - (void)quick_mode_hash3(r_hashval, st); + fixup_v1_HASH(st, &hash_fixup, st->st_msgid, NULL); } /* Derive new keying material */ @@ -1986,12 +1909,8 @@ * (see RFC 2409 "IKE" 5.5) * Installs outbound IPsec SAs, routing, etc. */ -stf_status quick_inI2(struct state *st, struct msg_digest *md) +stf_status quick_inI2(struct state *st, struct msg_digest *md UNUSED) { - /* HASH(3) in */ - CHECK_QUICK_HASH(md, quick_mode_hash3(hash_val, st), - "HASH(3)", "Quick I2"); - /* Tell the kernel to establish the outbound and routing part of the new SA * (the previous state established inbound) * (unless the commit bit is set -- which we don't support). diff -Naur libreswan-3.29-orig/programs/pluto/ikev1_xauth.c libreswan-3.29/programs/pluto/ikev1_xauth.c --- libreswan-3.29-orig/programs/pluto/ikev1_xauth.c 2019-06-10 10:22:04.000000000 -0400 +++ libreswan-3.29/programs/pluto/ikev1_xauth.c 2019-06-11 19:28:00.688844889 -0400 @@ -78,6 +78,8 @@ #include "send.h" /* for send without recording */ #include "ikev1_send.h" #include "af_info.h" +#include "ikev1_hash.h" +#include "impair.h" /* forward declarations */ static stf_status xauth_client_ackstatus(struct state *st, @@ -198,25 +200,19 @@ * @param st State structure * @return size_t Length of the HASH */ -static size_t xauth_mode_cfg_hash(u_char *dest, - const u_char *start, - const u_char *roof, - const struct state *st) -{ - struct hmac_ctx ctx; - - hmac_init(&ctx, st->st_oakley.ta_prf, st->st_skeyid_a_nss); - passert(sizeof(msgid_t) == sizeof(uint32_t)); - msgid_t raw_msgid = htonl(st->st_msgid_phase15); - hmac_update(&ctx, (const void *)&raw_msgid, sizeof(raw_msgid)); - hmac_update(&ctx, start, roof - start); - hmac_final(dest, &ctx); - - DBG(DBG_CRYPT|DBG_XAUTH, { - DBG_log("XAUTH: HASH computed:"); - DBG_dump("", dest, ctx.hmac_digest_len); - }); - return ctx.hmac_digest_len; + +static bool emit_xauth_hash(const char *what, struct state *st, + struct v1_hash_fixup *hash_fixup, pb_stream *out) +{ + return emit_v1_HASH(V1_HASH_1, what, XAUTH_EXCHANGE, + st, hash_fixup, out); +} + +static void fixup_xauth_hash(struct state *st, + struct v1_hash_fixup *hash_fixup, + const uint8_t *roof) +{ + fixup_v1_HASH(st, hash_fixup, st->st_msgid_phase15, roof); } /** @@ -383,23 +379,10 @@ bool use_modecfg_addr_as_client_addr, uint16_t ap_id) { - unsigned char *r_hash_start, *r_hashval; - - /* START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_MCFG_ATTR); */ - - { - pb_stream hash_pbs; - - if (!ikev1_out_generic(ISAKMP_NEXT_MCFG_ATTR, &isakmp_hash_desc, rbody, &hash_pbs)) - return STF_INTERNAL_ERROR; - - r_hashval = hash_pbs.cur; /* remember where to plant value */ - if (!out_zero(st->st_oakley.ta_prf->prf_output_size, - &hash_pbs, "HASH")) - return STF_INTERNAL_ERROR; - - close_output_pbs(&hash_pbs); - r_hash_start = rbody->cur; /* hash from after HASH payload */ + struct v1_hash_fixup hash_fixup; + if (!emit_xauth_hash("XAUTH: mode config response", + st, &hash_fixup, rbody)) { + return STF_INTERNAL_ERROR; } /* ATTR out */ @@ -497,7 +480,7 @@ return STF_INTERNAL_ERROR; } - xauth_mode_cfg_hash(r_hashval, r_hash_start, rbody->cur, st); + fixup_xauth_hash(st, &hash_fixup, rbody->cur); if (!ikev1_close_message(rbody, st) || !ikev1_encrypt_message(rbody, st)) @@ -523,7 +506,6 @@ /* HDR out */ { struct isakmp_hdr hdr = { - .isa_np = ISAKMP_NEXT_HASH, .isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION, .isa_xchg = ISAKMP_XCHG_MODE_CFG, @@ -604,7 +586,6 @@ pb_stream reply; pb_stream rbody; unsigned char buf[256]; - u_char *r_hash_start, *r_hashval; const enum state_kind p_state = st->st_state; /* set up reply */ @@ -620,7 +601,6 @@ /* HDR out */ { struct isakmp_hdr hdr = { - .isa_np = ISAKMP_NEXT_HASH, .isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION, .isa_xchg = ISAKMP_XCHG_MODE_CFG, @@ -638,7 +618,11 @@ return STF_INTERNAL_ERROR; } - START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_MCFG_ATTR); + struct v1_hash_fixup hash_fixup; + if (!emit_xauth_hash("XAUTH: send request", + st, &hash_fixup, &rbody)) { + return STF_INTERNAL_ERROR; + } /* ATTR out */ { @@ -668,7 +652,7 @@ return STF_INTERNAL_ERROR; } - xauth_mode_cfg_hash(r_hashval, r_hash_start, rbody.cur, st); + fixup_xauth_hash(st, &hash_fixup, rbody.cur); if (!ikev1_close_message(&rbody, st)) return STF_INTERNAL_ERROR; @@ -719,7 +703,6 @@ pb_stream reply; pb_stream rbody; unsigned char buf[256]; - u_char *r_hash_start, *r_hashval; /* set up reply */ init_out_pbs(&reply, buf, sizeof(buf), "xauth_buf"); @@ -733,7 +716,6 @@ /* HDR out */ { struct isakmp_hdr hdr = { - .isa_np = ISAKMP_NEXT_HASH, .isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION, .isa_xchg = ISAKMP_XCHG_MODE_CFG, @@ -752,7 +734,11 @@ return STF_INTERNAL_ERROR; } - START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_MCFG_ATTR); + struct v1_hash_fixup hash_fixup; + if (!emit_xauth_hash("XAUTH: mode config request", + st, &hash_fixup, &rbody)) { + return STF_INTERNAL_ERROR; + } /* ATTR out */ { @@ -785,7 +771,7 @@ return STF_INTERNAL_ERROR; } - xauth_mode_cfg_hash(r_hashval, r_hash_start, rbody.cur, st); + fixup_xauth_hash(st, &hash_fixup, rbody.cur); if (!ikev1_close_message(&rbody, st)) return STF_INTERNAL_ERROR; @@ -821,7 +807,6 @@ pb_stream reply; pb_stream rbody; unsigned char buf[256]; - u_char *r_hash_start, *r_hashval; /* set up reply */ init_out_pbs(&reply, buf, sizeof(buf), "xauth_buf"); @@ -832,7 +817,6 @@ /* HDR out */ { struct isakmp_hdr hdr = { - .isa_np = ISAKMP_NEXT_HASH, .isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION, .isa_xchg = ISAKMP_XCHG_MODE_CFG, @@ -850,7 +834,10 @@ return STF_INTERNAL_ERROR; } - START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_MCFG_ATTR); + struct v1_hash_fixup hash_fixup; + if (!emit_xauth_hash("XAUTH: status", st, &hash_fixup, &rbody)) { + return STF_INTERNAL_ERROR; + } /* ATTR out */ { @@ -873,7 +860,7 @@ return STF_INTERNAL_ERROR; } - xauth_mode_cfg_hash(r_hashval, r_hash_start, rbody.cur, st); + fixup_xauth_hash(st, &hash_fixup, rbody.cur); if (!ikev1_close_message(&rbody, st)) return STF_INTERNAL_ERROR; @@ -1280,12 +1267,6 @@ bool gotname = FALSE, gotpassword = FALSE; - CHECK_QUICK_HASH(md, - xauth_mode_cfg_hash(hash_val, hash_pbs->roof, - md->message_pbs.roof, - st), - "XAUTH-HASH", "XAUTH R0"); - setchunk(name, unknown, sizeof(unknown) - 1); /* to make diagnostics easier */ /* XXX This needs checking with the proper RFC's - ISAKMP_CFG_ACK got added for Cisco interop */ @@ -1469,11 +1450,6 @@ DBG(DBG_CONTROLMORE, DBG_log("arrived in modecfg_inR0")); st->st_msgid_phase15 = md->hdr.isa_msgid; - CHECK_QUICK_HASH(md, - xauth_mode_cfg_hash(hash_val, - hash_pbs->roof, - md->message_pbs.roof, st), - "MODECFG-HASH", "MODE R0"); switch (ma->isama_type) { default: @@ -1559,12 +1535,6 @@ DBG(DBG_CONTROL, DBG_log("modecfg_inI2")); st->st_msgid_phase15 = md->hdr.isa_msgid; - CHECK_QUICK_HASH(md, - xauth_mode_cfg_hash(hash_val, - hash_pbs->roof, - md->message_pbs.roof, - st), - "MODECFG-HASH", "MODE R1"); /* CHECK that SET has been received. */ @@ -1690,11 +1660,6 @@ DBG(DBG_CONTROL, DBG_log("modecfg_inR1: received mode cfg reply")); st->st_msgid_phase15 = md->hdr.isa_msgid; - CHECK_QUICK_HASH(md, - xauth_mode_cfg_hash(hash_val, hash_pbs->roof, - md->message_pbs.roof, - st), - "MODECFG-HASH", "MODE R1"); switch (ma->isama_type) { default: @@ -1978,26 +1943,12 @@ pb_stream *rbody, uint16_t ap_id) { - unsigned char *r_hash_start, *r_hashval; char xauth_username[MAX_XAUTH_USERNAME_LEN]; struct connection *c = st->st_connection; - /* START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_MCFG_ATTR); */ - - { - pb_stream hash_pbs; - int np = ISAKMP_NEXT_MCFG_ATTR; - - if (!ikev1_out_generic(np, &isakmp_hash_desc, rbody, &hash_pbs)) - return STF_INTERNAL_ERROR; - - r_hashval = hash_pbs.cur; /* remember where to plant value */ - if (!out_zero(st->st_oakley.ta_prf->prf_output_size, - &hash_pbs, "HASH")) - return STF_INTERNAL_ERROR; - - close_output_pbs(&hash_pbs); - r_hash_start = (rbody)->cur; /* hash from after HASH payload */ + struct v1_hash_fixup hash_fixup; + if (!emit_xauth_hash("XAUTH: client response", st, &hash_fixup, rbody)) { + return STF_INTERNAL_ERROR; } /* MCFG_ATTR out */ @@ -2201,7 +2152,7 @@ libreswan_log("XAUTH: Answering XAUTH challenge with user='%s'", st->st_xauth_username); - xauth_mode_cfg_hash(r_hashval, r_hash_start, rbody->cur, st); + fixup_xauth_hash(st, &hash_fixup, rbody->cur); if (!ikev1_close_message(rbody, st) || !ikev1_encrypt_message(rbody, st)) @@ -2252,10 +2203,6 @@ } st->st_msgid_phase15 = md->hdr.isa_msgid; - CHECK_QUICK_HASH(md, xauth_mode_cfg_hash(hash_val, - hash_pbs->roof, - md->message_pbs.roof, st), - "MODECFG-HASH", "XAUTH I0"); switch (ma->isama_type) { default: @@ -2446,24 +2393,9 @@ pb_stream *rbody, uint16_t ap_id) { - unsigned char *r_hash_start, *r_hashval; - - /* START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_MCFG_ATTR); */ - - { - pb_stream hash_pbs; - int np = ISAKMP_NEXT_MCFG_ATTR; - - if (!ikev1_out_generic(np, &isakmp_hash_desc, rbody, &hash_pbs)) - return STF_INTERNAL_ERROR; - - r_hashval = hash_pbs.cur; /* remember where to plant value */ - if (!out_zero(st->st_oakley.ta_prf->prf_output_size, - &hash_pbs, "HASH")) - return STF_INTERNAL_ERROR; - - close_output_pbs(&hash_pbs); - r_hash_start = (rbody)->cur; /* hash from after HASH payload */ + struct v1_hash_fixup hash_fixup; + if (!emit_xauth_hash("XAUTH: ack status", st, &hash_fixup, rbody)) { + return STF_INTERNAL_ERROR; } /* ATTR out */ @@ -2486,7 +2418,7 @@ return STF_INTERNAL_ERROR; } - xauth_mode_cfg_hash(r_hashval, r_hash_start, rbody->cur, st); + fixup_xauth_hash(st, &hash_fixup, rbody->cur); if (!ikev1_close_message(rbody, st) || !ikev1_encrypt_message(rbody, st)) @@ -2525,11 +2457,6 @@ DBG(DBG_CONTROLMORE, DBG_log("Continuing with xauth_inI1")); st->st_msgid_phase15 = md->hdr.isa_msgid; - CHECK_QUICK_HASH(md, - xauth_mode_cfg_hash(hash_val, - hash_pbs->roof, - md->message_pbs.roof, st), - "MODECFG-HASH", "XAUTH I1"); switch (ma->isama_type) { default: diff -Naur libreswan-3.29-orig/programs/pluto/ipsec_doi.h libreswan-3.29/programs/pluto/ipsec_doi.h --- libreswan-3.29-orig/programs/pluto/ipsec_doi.h 2019-06-10 10:22:04.000000000 -0400 +++ libreswan-3.29/programs/pluto/ipsec_doi.h 2019-06-11 19:28:00.688844889 -0400 @@ -65,67 +65,6 @@ const struct oakley_group_desc *gr, struct payload_digest *ke_pd); -/* START_HASH_PAYLOAD_NO_HASH_START - * - * Emit a to-be-filled-in hash payload, noting the field start (r_hashval) - * and the start of the part of the message to be hashed (r_hash_start). - * This macro is magic. - * - it can cause the caller to return - * - it references variables local to the caller (r_hashval, st) - */ -#define START_HASH_PAYLOAD_NO_R_HASH_START(rbody, np) { \ - pb_stream hash_pbs; \ - if (!ikev1_out_generic(np, &isakmp_hash_desc, &(rbody), &hash_pbs)) \ - return STF_INTERNAL_ERROR; \ - r_hashval = hash_pbs.cur; /* remember where to plant value */ \ - if (!out_zero(st->st_oakley.ta_prf->prf_output_size, \ - &hash_pbs, "HASH")) \ - return STF_INTERNAL_ERROR; \ - close_output_pbs(&hash_pbs); \ -} - -/* START_HASH_PAYLOAD - * - * Emit a to-be-filled-in hash payload, noting the field start (r_hashval) - * and the start of the part of the message to be hashed (r_hash_start). - * This macro is magic. - * - it can cause the caller to return - * - it references variables local to the caller (r_hashval, r_hash_start, st) - */ -#define START_HASH_PAYLOAD(rbody, np) { \ - START_HASH_PAYLOAD_NO_R_HASH_START(rbody, np); \ - r_hash_start = (rbody).cur; /* hash from after HASH payload */ \ -} - -/* CHECK_QUICK_HASH - * - * This macro is magic -- it cannot be expressed as a function. - * - it causes the caller to return! - * - it declares local variables and expects the "do_hash" argument - * expression to reference them (hash_val, hash_pbs) - */ -#define CHECK_QUICK_HASH(md, do_hash, hash_name, msg_name) { \ - pb_stream *const hash_pbs = &(md)->chain[ISAKMP_NEXT_HASH]->pbs; \ - u_char hash_val[MAX_DIGEST_LEN]; \ - size_t hash_len = (do_hash); \ - if (pbs_left(hash_pbs) != hash_len || \ - !memeq(hash_pbs->cur, hash_val, hash_len)) { \ - if (DBGP(DBG_CRYPT)) { \ - DBG_dump("received " hash_name ":", \ - hash_pbs->cur, pbs_left(hash_pbs)); \ - } \ - loglog(RC_LOG_SERIOUS, \ - "received " hash_name " does not match computed value in " msg_name); \ - /* XXX Could send notification back */ \ - return STF_FAIL + INVALID_HASH_INFORMATION; \ - } \ - } - -size_t quick_mode_hash12(u_char *dest, const u_char *start, - const u_char *roof, - const struct state *st, const msgid_t *msgid, - bool hash2); - extern stf_status send_isakmp_notification(struct state *st, uint16_t type, const void *data, size_t len); diff -Naur libreswan-3.29-orig/programs/pluto/Makefile libreswan-3.29/programs/pluto/Makefile --- libreswan-3.29-orig/programs/pluto/Makefile 2019-06-10 10:22:04.000000000 -0400 +++ libreswan-3.29/programs/pluto/Makefile 2019-06-11 19:23:19.841729230 -0400 @@ -215,6 +215,7 @@ OBJS += ikev2_ipseckey.o endif OBJS += ikev1.o ikev1_main.o ikev1_quick.o ikev1_dpd.o ikev1_spdb_struct.o ikev1_msgid.o +OBJS += ikev1_hash.o OBJS += ikev2.o ikev2_parent.o ikev2_child.o ikev2_spdb_struct.o OBJS += ikev2_ecdsa.o ikev2_rsa.o ikev2_psk.o ikev2_ppk.o ikev2_crypto.o OBJS += ikev2_redirect.o