/* * The IKE Scanner (ike-scan) is Copyright (C) 2003-2007 Roy Hills, * NTA Monitor Ltd. * * 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. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library, and distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. * * If this license is unacceptable to you, I may be willing to negotiate * alternative licenses (contact ike-scan@nta-monitor.com). * * You are encouraged to send comments, improvements or suggestions to * me at ike-scan@nta-monitor.com. * * $Id: isakmp.c 9884 2007-01-14 19:05:39Z rsh $ * * Author: Roy Hills * Date: 7 November 2003 * * Functions to construct ISAKMP headers and payloads. * */ #include "ike-scan.h" static char rcsid[] = "$Id: isakmp.c 9884 2007-01-14 19:05:39Z rsh $"; /* RCS ID for ident(1) */ const id_name_map notification_map[] = { /* From RFC 2408 3.14.1 */ {0, "UNSPECIFIED"}, {1, "INVALID-PAYLOAD-TYPE"}, {2, "DOI-NOT-SUPPORTED"}, {3, "SITUATION-NOT-SUPPORTED"}, {4, "INVALID-COOKIE"}, {5, "INVALID-MAJOR-VERSION"}, {6, "INVALID-MINOR-VERSION"}, {7, "INVALID-EXCHANGE-TYPE"}, {8, "INVALID-FLAGS"}, {9, "INVALID-MESSAGE-ID"}, {10, "INVALID-PROTOCOL-ID"}, {11, "INVALID-SPI"}, {12, "INVALID-TRANSFORM-ID"}, {13, "ATTRIBUTES-NOT-SUPPORTED"}, {14, "NO-PROPOSAL-CHOSEN"}, {15, "BAD-PROPOSAL-SYNTAX"}, {16, "PAYLOAD-MALFORMED"}, {17, "INVALID-KEY-INFORMATION"}, {18, "INVALID-ID-INFORMATION"}, {19, "INVALID-CERT-ENCODING"}, {20, "INVALID-CERTIFICATE"}, {21, "CERT-TYPE-UNSUPPORTED"}, {22, "INVALID-CERT-AUTHORITY"}, {23, "INVALID-HASH-INFORMATION"}, {24, "AUTHENTICATION-FAILED"}, {25, "INVALID-SIGNATURE"}, {26, "ADDRESS-NOTIFICATION"}, {27, "NOTIFY-SA-LIFETIME"}, {28, "CERTIFICATE-UNAVAILABLE"}, {29, "UNSUPPORTED-EXCHANGE-TYPE"}, {30, "UNEQUAL-PAYLOAD-LENGTHS"}, {9101, "Checkpoint-Firewall-1"}, {9110, "Checkpoint-Firewall-1"}, {24576, "RESPONDER-LIFETIME"}, /* Next 3 are from RFC 2407 4.6.3 */ {24577, "REPLAY-STATUS"}, {24578, "INITIAL-CONTACT"}, {-1, NULL} }; const id_name_map notification_map2[] = { /* From RFC 4306 3.10.1 */ {0, "RESERVED"}, {1, "UNSUPPORTED_CRITICAL_PAYLOAD"}, {4, "INVALID_IKE_SPI"}, {5, "INVALID_MAJOR_VERSION"}, {7, "INVALID_SYNTAX"}, {9, "INVALID_MESSAGE_ID"}, {11, "INVALID_SPI"}, {14, "NO_PROPOSAL_CHOSEN"}, {17, "INVALID_KE_PAYLOAD"}, {24, "AUTHENTICATION_FAILED"}, {34, "SINGLE_PAIR_REQUIRED"}, {35, "NO_ADDITIONAL_SAS"}, {36, "INTERNAL_ADDRESS_FAILURE"}, {37, "FAILED_CP_REQUIRED"}, {38, "TS_UNACCEPTABLE"}, {39, "INVALID_SELECTORS"}, {9101, "Checkpoint-Firewall-1"}, {9110, "Checkpoint-Firewall-1"}, {16384, "INITIAL_CONTACT"}, {16385, "SET_WINDOW_SIZE"}, {16386, "ADDITIONAL_TS_POSSIBLE"}, {16387, "IPCOMP_SUPPORTED"}, {16388, "NAT_DETECTION_SOURCE_IP"}, {16389, "NAT_DETECTION_DESTINATION_IP"}, {16390, "COOKIE"}, {16391, "USE_TRANSPORT_MODE"}, {16392, "HTTP_CERT_LOOKUP_SUPPORTED"}, {16393, "REKEY_SA"}, {16394, "ESP_TFC_PADDING_NOT_SUPPORTED"}, {16395, "NON_FIRST_FRAGMENTS_ALSO"}, {-1, NULL} }; const id_name_map attr_map[] = { /* From RFC 2409 App. A and */ {1, "Enc"}, /* draft-ietf-ipsec-isakmp-gss-auth */ {2, "Hash"}, {3, "Auth"}, {4, "Group"}, {5, "GroupType"}, {6, "GroupPrime/IrreduciblePolynomial"}, {7, "GroupGeneratorOne"}, {8, "GroupGeneratorTwo"}, {9, "GroupCurve A"}, {10, "GroupCurve B"}, {11, "LifeType"}, {12, "LifeDuration"}, {13, "PRF"}, {14, "KeyLength"}, {15, "FieldSize"}, {16, "GroupOrder"}, {16384, "GSSIdentityName"}, {-1, NULL} }; const id_name_map trans_type_map[] = { /* From RFC 4306 3.3.2 */ {1, "Encr"}, {2, "Prf"}, {3, "Integ"}, {4, "DH_Group"}, {5, "ESN"}, {-1, NULL} }; const id_name_map enc_map[] = { /* From RFC 2409 App. A */ {1, "DES"}, {2, "IDEA"}, {3, "Blowfish"}, {4, "RC5"}, {5, "3DES"}, {6, "CAST"}, {7, "AES"}, /* RFC 3602 */ {8, "Camellia"}, /* draft-kato-ipsec-ciph-camellia-01.txt */ {65001, "Mars"}, /* Defined in strongSwan constants.h */ {65002, "RC6"}, /* Defined in strongSwan constants.h */ {65003, "ID_65003"}, /* Defined in strongSwan constants.h */ {65004, "Serpent"}, /* Defined in strongSwan constants.h */ {65005, "Twofish"}, /* Defined in strongSwan constants.h */ {-1, NULL} }; const id_name_map encr_map[] = { /* From RFC 4306 3.3.2 */ {1, "DES_IV64"}, {2, "DES"}, {3, "3DES"}, {4, "RC5"}, {5, "IDEA"}, {6, "CAST"}, {7, "Blowfish"}, {8, "3IDEA"}, {9, "DES_IV32"}, {11, "NULL"}, {12, "AES_CBC"}, {13, "AES_CTR"}, {-1, NULL} }; const id_name_map hash_map[] = { /* From RFC 2409 App. A */ {1, "MD5"}, {2, "SHA1"}, {3, "Tiger"}, {4, "SHA2-256"}, {5, "SHA2-384"}, {6, "SHA2-512"}, {-1, NULL} }; const id_name_map prf_map[] = { /* From RFC 4306 3.3.2 */ {1, "HMAC_MD5"}, {2, "HMAC_SHA1"}, {3, "HMAC_TIGER"}, {4, "AES128_XCBC"}, {-1, NULL} }; const id_name_map auth_map[] = { /* From RFC 2409 App. A */ {1, "PSK"}, {2, "DSS"}, {3, "RSA_Sig"}, {4, "RSA_Enc"}, {5, "RSA_RevEnc"}, {6, "ElGamel_Enc"}, {7, "ElGamel_RevEnc"}, {8, "ECDSA_Sig"}, {128, "CRACK"}, /* From draft-harkins-ipsra-crack-00 */ {64221, "Hybrid"}, {65001, "XAUTH"}, {-1, NULL} }; const id_name_map integ_map[] = { /* From RFC 4306 3.3.2 */ {1, "HMAC_MD5_96"}, {2, "HMAC_SHA1_96"}, {3, "DES_MAC"}, {4, "KPDK_MD5"}, {5, "AES_XCBC_96"}, {-1, NULL} }; const id_name_map dh_map[] = { /* From RFC 2409 App. A */ {1, "1:modp768"}, /* and RFC 3526 */ {2, "2:modp1024"}, {3, "3:ec2n155"}, {4, "4:ec2n185"}, {5, "5:modp1536"}, {6, "6:ec2n163"}, {7, "7:ec2n163"}, {8, "8:ec2n283"}, {9, "9:ec2n283"}, {10, "10:ec2n409"}, {11, "11:ec2n409"}, {12, "12:ec2n571"}, {13, "13:ec2n571"}, {14, "14:modp2048"}, {15, "15:modp3072"}, {16, "16:modp4096"}, {17, "17:modp6144"}, {18, "18:modp8192"}, {-1, NULL} }; const id_name_map life_map[] = { /* From RFC 2409 App. A */ {1, "Seconds"}, {2, "Kilobytes"}, {-1, NULL} }; const id_name_map payload_map[] = { /* Payload types from RFC 2408 3.1 */ {1, "SecurityAssociation"}, /* and RFC 4306 3.2 */ {2, "Proposal"}, {3, "Transform"}, {4, "KeyExchange"}, {5, "Identification"}, {6, "Certificate"}, {7, "CertificateRequest"}, {8, "Hash"}, {9, "Signature"}, {10, "Nonce"}, {11, "Notification"}, {12, "Delete"}, {13, "VendorID"}, {20, "NAT-D"}, /* RFC 3947 NAT Discovery */ {33, "SecurityAssociation"}, {34, "KeyExchange"}, {35, "IDI"}, {36, "IDR"}, {37, "Certificate"}, {38, "CertificateRequest"}, {39, "AUTH"}, {40, "Nonce"}, {41, "Notification"}, {42, "Delete"}, {43, "VendorID"}, {44, "TSI"}, {45, "TSR"}, {46, "Encrypted"}, {47, "Configuration"}, {48, "EAP"}, {-1, NULL} }; const id_name_map doi_map[] = { {0, "ISAKMP"}, {1, "IPsec"}, {-1, NULL} }; const id_name_map protocol_map[] = { {1, "PROTO_ISAKMP"}, {2, "PROTO_IPSEC_AH"}, {3, "PROTO_IPSEC_ESP"}, {4, "PROTO_IPSEC_COMP"}, {-1, NULL} }; const id_name_map id_map[] = { /* From RFC 2407 4.6.2.1 */ {1, "ID_IPV4_ADDR"}, {2, "ID_FQDN"}, {3, "ID_USER_FQDN"}, {4, "ID_IPV4_ADDR_SUBNET"}, {5, "ID_IPV6_ADDR"}, {6, "ID_IPV6_ADDR_SUBNET"}, {7, "ID_IPV4_ADDR_RANGE"}, {8, "ID_IPV6_ADDR_RANGE"}, {9, "ID_DER_ASN1_DN"}, {10, "ID_DER_ASN1_GN"}, {11, "ID_KEY_ID"}, }; const id_name_map cert_map[] = { /* From RFC 2408 Sec. 3.9 */ {1, "PKCS #7 wrapped X.509 certificate"}, {2, "PGP Certificate"}, {3, "DNS Signed Key"}, {4, "X.509 Certificate - Signature"}, {5, "X.509 Certificate - Key Exchange"}, {6, "Kerberos Tokens"}, {7, "Certificate Revocation List (CRL)"}, {8, "Authority Revocation List (ARL)"}, {9, "SPKI Certificate"}, {10, "X.509 Certificate - Attribute"}, {-1, NULL} }; extern psk_crack psk_values; extern int mbz_value; /* * make_isakmp_hdr -- Construct an ISAKMP Header * * Inputs: * * xchg Exchange Type (e.g. ISAKMP_XCHG_IDPROT for main mode) * next Next Payload Type * length ISAKMP Message total length * header_version Version number to put in the header * hdr_flags Flags to put in the header * hdr_msgid Message ID to put in the header * rcookie_data Responder cookie data, or NULL for default * rcookie_data_len Length of responder cookie data (<=8) * * Returns: * * Pointer to created ISAKMP Header. * * This constructs an ISAKMP header. It fills in the static values. * The initiator cookie should be changed to a unique per-host value * before the packet is sent. */ unsigned char* make_isakmp_hdr(unsigned xchg, unsigned next, unsigned length, int header_version, int hdr_flags, unsigned hdr_msgid, unsigned char *rcookie_data, size_t rcookie_data_len) { unsigned char *payload; struct isakmp_hdr* hdr; payload = Malloc(sizeof(struct isakmp_hdr)); hdr = (struct isakmp_hdr*) payload; /* Overlay header struct on payload */ memset(hdr, mbz_value, sizeof(struct isakmp_hdr)); hdr->isa_icookie[0] = 0xdeadbeef; /* Initiator cookie */ hdr->isa_icookie[1] = 0xdeadbeef; hdr->isa_rcookie[0] = 0; /* Set responder cookie to 0 */ hdr->isa_rcookie[1] = 0; if (rcookie_data) { memcpy(hdr->isa_rcookie, rcookie_data, rcookie_data_len); } hdr->isa_np = next; /* Next Payload Type */ hdr->isa_version = header_version; /* v1.0 by default */ hdr->isa_xchg = xchg; /* Exchange type */ hdr->isa_flags = hdr_flags; /* Flags */ hdr->isa_msgid = htonl(hdr_msgid); /* Message ID */ hdr->isa_length = htonl(length); /* Total ISAKMP message length */ return payload; } /* * make_sa -- Construct an SA payload * * Inputs: * * outlen (output) length of SA payload * next Next Payload Type * doi Domain of interpretation * situation Situation * proposals Pointer to list of proposals * proposal_len length of proposal list * * Returns: * * Pointer to the SA payload. * * This constructs an SA payload. */ unsigned char* make_sa(size_t *outlen, unsigned next, unsigned doi, unsigned situation, unsigned char *proposals, size_t proposal_len) { unsigned char *payload; struct isakmp_sa* hdr; unsigned char *cp; size_t len; hdr = Malloc(sizeof(struct isakmp_sa)); memset(hdr, mbz_value, sizeof(struct isakmp_sa)); hdr->isasa_np = next; /* Next Payload Type */ hdr->isasa_doi = htonl(doi); /* Default is IPsec DOI */ hdr->isasa_situation = htonl(situation); /* Default SIT_IDENTITY_ONLY */ len = sizeof(struct isakmp_sa) + proposal_len; hdr->isasa_length = htons(len); /* SA Payload length */ payload = Malloc(len); cp = payload; memcpy(cp, hdr, sizeof(struct isakmp_sa)); cp += sizeof(struct isakmp_sa); memcpy(cp, proposals, proposal_len); *outlen = len; return payload; } /* * make_sa2 -- Construct an IKEv2 SA payload * * Inputs: * * outlen (output) length of SA payload * next Next Payload Type * proposals Pointer to list of proposals * proposal_len length of proposal list * * Returns: * * Pointer to the SA payload. * * This constructs an IKEv2 SA payload. */ unsigned char* make_sa2(size_t *outlen, unsigned next, unsigned char *proposals, size_t proposal_len) { unsigned char *payload; struct isakmp_sa2* hdr; unsigned char *cp; size_t len; hdr = Malloc(sizeof(struct isakmp_sa2)); memset(hdr, mbz_value, sizeof(struct isakmp_sa2)); hdr->isasa2_np = next; /* Next Payload Type */ len = sizeof(struct isakmp_sa2) + proposal_len; hdr->isasa2_length = htons(len); /* SA Payload length */ payload = Malloc(len); cp = payload; memcpy(cp, hdr, sizeof(struct isakmp_sa2)); cp += sizeof(struct isakmp_sa2); memcpy(cp, proposals, proposal_len); *outlen = len; return payload; } /* * add_prop -- Add a proposal payload to the list of proposals * * Inputs: * * outlen (output) Proposal payload length * notrans Number of transforms in this proposal * protocol Protocol * spi_size SPI Size * transforms Pointer to transform list * transform_len Length of transform list * * Returns: * * Pointer to proposal payload. * * This function can either be called with finished = 0, in which case * notrans, protocol, spi_size, transforms and transform_len must be * specified, and the function will return NULL, OR it can be called with * finished = 1 in which case notrans, protocol, spi_size, transforms and * transform_len are ignored and the function will return a pointer to the * finished payload and will set *length to the length of this payload. * * ISAKMP SAs are only allowed to contain one proposal, RFC 2409 section 5 * states: * * "To put it another way, for phase 1 exchanges there MUST NOT be * multiple Proposal Payloads for a single SA payload and there MUST NOT * be multiple SA payloads." * * However, this function does not enforce this restriction. */ unsigned char* add_prop(int finished, size_t *outlen, unsigned notrans, unsigned protocol, unsigned spi_size, unsigned char *transforms, size_t transform_len) { static int first_proposal = 1; static unsigned char *prop_start=NULL; /* Start of set of proposals */ static size_t cur_offset; /* Start of current proposal */ static size_t end_offset; /* End of proposals */ static unsigned prop_no=1; unsigned char *prop; /* Proposal payload */ size_t len; /* Proposal length */ /* * Construct a proposal if we are not finalising. * Set next to ISAKMP_NEXT_P (more proposals), and increment prop_no for next * time round. */ if (!finished) { prop = make_prop(&len, ISAKMP_NEXT_P, prop_no, notrans, protocol, spi_size, transforms, transform_len); prop_no++; if (first_proposal) { cur_offset = 0; end_offset = len; prop_start = Malloc(end_offset); memcpy(prop_start, prop, len); first_proposal = 0; } else { cur_offset = end_offset; end_offset += len; prop_start = Realloc(prop_start, end_offset); memcpy(prop_start+cur_offset, prop, len); } free(prop); return NULL; } else { struct isakmp_proposal* hdr = (struct isakmp_proposal*) (prop_start+cur_offset); /* Overlay */ first_proposal = 1; hdr->isap_np = ISAKMP_NEXT_NONE; /* No more proposals */ *outlen = end_offset; return prop_start; } } /* * make_prop -- Construct a proposal payload * * Inputs: * * outlen (output) Proposal payload length * next next payload (2=more props, 0=no more props) * number proposal number * notrans Number of transforms in this proposal * protocol Protocol * spi_size SPI Size * transforms Pointer to transform list * transform_len Length of transform list * * Returns: * * Pointer to proposal payload. * * This constructs a single proposal payload. */ unsigned char* make_prop(size_t *outlen, unsigned next, unsigned number, unsigned notrans, unsigned protocol, unsigned spi_size, unsigned char *transforms, size_t transform_len) { unsigned char *payload; struct isakmp_proposal* hdr; unsigned char *cp; size_t len; /* Allocate and initialise the proposal header */ hdr = Malloc(sizeof(struct isakmp_proposal)); memset(hdr, mbz_value, sizeof(struct isakmp_proposal)); hdr->isap_np = next; hdr->isap_proposal = number; hdr->isap_protoid = protocol; hdr->isap_spisize = spi_size; /* SPI Size */ hdr->isap_notrans = notrans; /* Number of transforms */ /* Determine total SA length and allocate payload memory */ len = sizeof(struct isakmp_proposal) + spi_size + transform_len; hdr->isap_length = htons(len); /* Proposal payload length */ payload = Malloc(len); cp = payload; /* Copy the proposal header to the payload */ memcpy(cp, hdr, sizeof(struct isakmp_proposal)); cp += sizeof(struct isakmp_proposal); free(hdr); /* If the SPI size is non-zero, add a random SPI of the specified length */ if (spi_size > 0) { int i; for (i=0; iisat_np = 0; /* No more transforms */ *length = end_offset; return trans_start; } } /* * make_transform -- Construct a single transform payload * * Inputs: * * length (output) length of entire transform payload. * next Next Payload Type (3 = More transforms; 0=No more transforms) * number Transform number * trans_id Transform ID (generally KEY_IKE) * attr Pointer to list of attributes * attr_len Attribute length in bytes * * Returns: * * Pointer to transform payload. * * This constructs a single transform payload. * Most of the values are defined in RFC 2409 Appendix A. */ unsigned char* make_transform(size_t *length, unsigned next, unsigned number, unsigned trans_id, unsigned char *attr, size_t attr_len) { struct isakmp_transform* hdr; /* Transform header */ unsigned char *payload; unsigned char *cp; size_t len; /* Payload Length */ /* Allocate and initialise the transform header */ hdr = Malloc(sizeof(struct isakmp_transform)); memset(hdr, mbz_value, sizeof(struct isakmp_transform)); hdr->isat_np = next; /* Next payload type */ hdr->isat_transnum = number; /* Transform Number */ hdr->isat_transid = trans_id; len = attr_len + sizeof(struct isakmp_transform); hdr->isat_length = htons(len); /* Transform length */ *length = len; /* Allocate memory for payload and copy structures to payload */ payload = Malloc(len); cp = payload; memcpy(cp, hdr, sizeof(struct isakmp_transform)); free(hdr); cp += sizeof(struct isakmp_transform); memcpy(cp, attr, attr_len); return payload; } /* * add_transform -- Add a transform payload to set of transforms. * * Inputs: * * finished 0 if adding a new transform; 1 if finalising. * length (output) length of entire transform payload. * trans_id Transform ID * attr Pointer to list of attributes * attr_len Length of attribute list * * Returns: * * Pointer to new set of transform payloads. * * This function can either be called with finished = 0, in which case * attr and attr_len must be specified, and the function will return NULL, * OR it can be called with finished = 1 in which case attr and attr_len * are ignored and the function will return a pointer to the finished * payload and will set *length to the length of this payload. */ unsigned char* add_transform(int finished, size_t *length, unsigned trans_id, unsigned char *attr, size_t attr_len) { static int first_transform = 1; static unsigned char *trans_start=NULL; /* Start of set of transforms */ static size_t cur_offset; /* Start of current transform */ static size_t end_offset; /* End of transforms */ static unsigned trans_no=1; unsigned char *trans; /* Transform payload */ size_t len; /* Transform length */ /* * Construct a transform if we are not finalising. * Set next to ISAKMP_NEXT_T (more transforms), and increment trans_no for * next time round. */ if (!finished) { trans = make_transform(&len, ISAKMP_NEXT_T, trans_no, trans_id, attr, attr_len); trans_no++; if (first_transform) { cur_offset = 0; end_offset = len; trans_start = Malloc(end_offset); memcpy(trans_start, trans, len); first_transform = 0; } else { cur_offset = end_offset; end_offset += len; trans_start = Realloc(trans_start, end_offset); memcpy(trans_start+cur_offset, trans, len); } free(trans); return NULL; } else { struct isakmp_transform* hdr = (struct isakmp_transform*) (trans_start+cur_offset); /* Overlay */ first_transform = 1; hdr->isat_np = ISAKMP_NEXT_NONE; /* No more transforms */ *length = end_offset; return trans_start; } } /* * make_transform2 -- Construct a single IKEv2 transform payload * * Inputs: * * length (output) length of entire transform payload. * next Next Payload Type (3 = More transforms; 0=No more transforms) * trans_type Transform type * trans_id Transform ID * attr Pointer to list of attributes, or NULL for no attributes * attr_len Attribute length in bytes. Zero if no attributes. * * Returns: * * Pointer to transform payload. * * This constructs a single IKEv2 transform payload. * Most of the values are defined in RFC 4306 Section 3.3. */ unsigned char* make_transform2(size_t *length, unsigned next, unsigned trans_type, unsigned trans_id, unsigned char *attr, size_t attr_len) { struct isakmp_transform2* hdr; /* Transform header */ unsigned char *payload; unsigned char *cp; size_t len; /* Payload Length */ /* Allocate and initialise the transform header */ hdr = Malloc(sizeof(struct isakmp_transform2)); memset(hdr, mbz_value, sizeof(struct isakmp_transform2)); hdr->isat2_np = next; /* Next payload type */ hdr->isat2_transtype = trans_type; /* Transform Type */ hdr->isat2_transid = htons(trans_id); /* Transform ID */ len = attr_len + sizeof(struct isakmp_transform2); hdr->isat2_length = htons(len); /* Transform length */ *length = len; /* Allocate memory for payload and copy structures to payload */ payload = Malloc(len); cp = payload; memcpy(cp, hdr, sizeof(struct isakmp_transform2)); free(hdr); cp += sizeof(struct isakmp_transform2); memcpy(cp, attr, attr_len); return payload; } /* * add_transform2 -- Add a transform payload to set of transforms. * * Inputs: * * finished 0 if adding a new transform; 1 if finalising. * length (output) length of entire transform payload. * trans_type Transform type * trans_id Transform ID * attr Pointer to list of attributes * attr_len Length of attribute list * * Returns: * * Pointer to new set of transform payloads. * * This function can either be called with finished = 0, in which case * attr and attr_len must be specified, and the function will return NULL, * OR it can be called with finished = 1 in which case attr and attr_len * are ignored and the function will return a pointer to the finished * payload and will set *length to the length of this payload. */ unsigned char* add_transform2(int finished, size_t *length, unsigned trans_type, unsigned trans_id, unsigned char *attr, size_t attr_len) { static int first_transform = 1; static unsigned char *trans_start=NULL; /* Start of set of transforms */ static size_t cur_offset; /* Start of current transform */ static size_t end_offset; /* End of transforms */ unsigned char *trans; /* Transform payload */ size_t len; /* Transform length */ /* * Construct a transform if we are not finalising. * Set next to ISAKMP_NEXT_T (more transforms) */ if (!finished) { trans = make_transform2(&len, ISAKMP_NEXT_T, trans_type, trans_id, attr, attr_len); if (first_transform) { cur_offset = 0; end_offset = len; trans_start = Malloc(end_offset); memcpy(trans_start, trans, len); first_transform = 0; } else { cur_offset = end_offset; end_offset += len; trans_start = Realloc(trans_start, end_offset); memcpy(trans_start+cur_offset, trans, len); } free(trans); return NULL; } else { struct isakmp_transform2* hdr = (struct isakmp_transform2*) (trans_start+cur_offset); /* Overlay */ first_transform = 1; hdr->isat2_np = ISAKMP_NEXT_NONE; /* No more transforms */ *length = end_offset; return trans_start; } } /* * make_attr -- Construct a transform attribute * * Inputs: * * outlen (output) Total length of transform attribute. * type Attribute Type. 'B' = basic, 'V' = variable. * class Attribute Class * length Attribute data length for variable type (ignored for basic). * b_value Basic Attribute Value * v_value Pointer to Variable Attribute Value * * Returns: * * Pointer to transform attribute. * * For variable attribute types, the data must be in network byte * order, and its length should be a multiple of 4 bytes to avoid * alignment issues. * * If type is "B", then length and v_value are ignored. If type is "V", * then b_value is ignored. */ unsigned char * make_attr(size_t *outlen, int type, unsigned class, size_t length, unsigned b_value, void *v_value) { struct isakmp_attribute *hdr; unsigned char *cp; size_t total_len; total_len = sizeof(struct isakmp_attribute); if (type == 'V') total_len += length; cp = Malloc(total_len); hdr = (struct isakmp_attribute *) cp; memset(hdr, mbz_value, sizeof(struct isakmp_attribute)); if (type == 'B') { /* Basic Attribute */ hdr->isaat_af_type = htons(class | 0x8000); hdr->isaat_lv = htons(b_value); } else { /* Variable Attribute */ hdr->isaat_af_type = htons(class); hdr->isaat_lv = htons(length); memcpy(cp+sizeof(struct isakmp_attribute), v_value, length); } *outlen = total_len; return cp; } /* * add_attr -- Add a new attribute onto the list of attributes * * Inputs: * * finished 0 if adding a new attribute; 1 if finalising. * outlen (output) Total length of attribute list. * type Attribute Type. 'B' = basic, 'V' = variable. * class Attribute Class * length Attribute data length for variable type (ignored for basic). * b_value Basic Attribute Value * v_value Pointer to Variable Attribute Value * * Returns: * * Pointer to attribute list * * This function can either be called with finished = 0, in which case * type, class, length and either b_value or v_value must be specified, * and the function will return NULL; or it can be called with * finished = 1 in which case type, class, length, b_value and v_value * are ignored and the function will return a pointer to the finished * attribute list and will set *outlen to the length of the attribute * list. */ unsigned char * add_attr(int finished, size_t *outlen, int type, unsigned class, size_t length, unsigned b_value, void *v_value) { static int first_attr=1; unsigned char *attr; static unsigned char *attr_start=NULL; /* Start of attr list */ static size_t cur_offset; /* Start of current attr */ static size_t end_offset; /* End of attr list */ size_t len; /* Attr length */ /* * Construct a new attribute if we are not finalising. */ if (!finished) { attr = make_attr(&len, type, class, length, b_value, v_value); if (first_attr) { cur_offset = 0; end_offset = len; attr_start = Malloc(end_offset); memcpy(attr_start, attr, len); first_attr = 0; } else { cur_offset = end_offset; end_offset += len; attr_start = Realloc(attr_start, end_offset); memcpy(attr_start+cur_offset, attr, len); } return NULL; } else { first_attr = 1; *outlen = end_offset; return attr_start; } } /* * make_vid -- Construct a vendor id payload * * Inputs: * * length (output) length of Vendor ID payload. * next Next Payload Type * vid_data Vendor ID data * vid_data_len Vendor ID data length * * Returns: * * Pointer to vendor id payload. * * This constructs a vendor id payload. It fills in the static values. * The next pointer value must be filled in later. */ unsigned char* make_vid(size_t *length, unsigned next, unsigned char *vid_data, size_t vid_data_len) { unsigned char *payload; struct isakmp_vid* hdr; payload = Malloc(sizeof(struct isakmp_vid)+vid_data_len); hdr = (struct isakmp_vid*) payload; /* Overlay vid struct on payload */ memset(hdr, mbz_value, sizeof(struct isakmp_vid)); hdr->isavid_np = next; /* Next payload type */ hdr->isavid_length = htons(sizeof(struct isakmp_vid)+vid_data_len); memcpy(payload+sizeof(struct isakmp_vid), vid_data, vid_data_len); *length = sizeof(struct isakmp_vid) + vid_data_len; return payload; } /* * add_vid -- Add a vendor ID payload to the set of VIDs. * * Inputs: * * finished 0 if adding a new VIDs; 1 if finalising. * length (output) length of entire VID payload set. * vid_data Vendor ID data * vid_data_len Vendor ID data length * next Next payload type (only when finished == 1) * * Returns: * * Pointer to the VID payload. * * This function can either be called with finished = 0, in which case * vid_data and vid_data_len must be specified, and * the function will return NULL, OR it can be called with finished = 1 * in which case vid_data and vid_data_len are * ignored and the function will return a pointer to the finished * payload and will set *length to the length of this payload. */ unsigned char* add_vid(int finished, size_t *length, unsigned char *vid_data, size_t vid_data_len, unsigned next) { static int first_vid = 1; static unsigned char *vid_start=NULL; /* Start of set of VIDs */ static size_t cur_offset; /* Start of current VID */ static size_t end_offset; /* End of VIDs */ unsigned char *vid; /* VID payload */ size_t len; /* VID length */ /* * Construct a VID if we are not finalising. */ if (!finished) { vid = make_vid(&len, ISAKMP_NEXT_VID, vid_data, vid_data_len); if (first_vid) { cur_offset = 0; end_offset = len; vid_start = Malloc(end_offset); memcpy(vid_start, vid, len); first_vid = 0; } else { cur_offset = end_offset; end_offset += len; vid_start = Realloc(vid_start, end_offset); memcpy(vid_start+cur_offset, vid, len); } return NULL; } else { struct isakmp_vid* hdr = (struct isakmp_vid*) (vid_start+cur_offset); /* Overlay */ hdr->isavid_np = next; *length = end_offset; return vid_start; } } /* * make_ke -- Make a Key Exchange payload * * Inputs: * * length (output) length of key exchange payload. * next Next Payload Type * kx_data_len Key exchange data length * * Returns: * * Pointer to key exchange payload. * * A real implementation would fill in the key exchange payload with the * Diffie Hellman public value. However, we just use random data. */ unsigned char* make_ke(size_t *length, unsigned next, size_t kx_data_len) { unsigned char *payload; struct isakmp_kx* hdr; unsigned char *kx_data; unsigned i; if (kx_data_len % 4) err_msg("Key exchange data length %d is not a multiple of 4", kx_data_len); payload = Malloc(sizeof(struct isakmp_kx)+kx_data_len); hdr = (struct isakmp_kx*) payload; /* Overlay kx struct on payload */ memset(hdr, mbz_value, sizeof(struct isakmp_kx)); kx_data = payload + sizeof(struct isakmp_kx); for (i=0; iisakx_np = next; /* Next payload type */ hdr->isakx_length = htons(sizeof(struct isakmp_kx)+kx_data_len); *length = sizeof(struct isakmp_kx) + kx_data_len; return payload; } /* * make_ke2 -- Make an IKEv2 Key Exchange payload * * Inputs: * * length (output) length of key exchange payload. * next Next Payload Type * dh_group Diffie Hellman group number * kx_data_len Key exchange data length * * Returns: * * Pointer to key exchange payload. * * A real implementation would fill in the key exchange payload with the * Diffie Hellman public value. However, we just use random data. */ unsigned char* make_ke2(size_t *length, unsigned next, unsigned dh_group, size_t kx_data_len) { unsigned char *payload; struct isakmp_kx2* hdr; unsigned char *kx_data; unsigned i; if (kx_data_len % 4) err_msg("Key exchange data length %d is not a multiple of 4", kx_data_len); payload = Malloc(sizeof(struct isakmp_kx2)+kx_data_len); hdr = (struct isakmp_kx2*) payload; /* Overlay kx struct on payload */ memset(hdr, mbz_value, sizeof(struct isakmp_kx2)); kx_data = payload + sizeof(struct isakmp_kx2); for (i=0; iisakx2_np = next; /* Next payload type */ hdr->isakx2_length = htons(sizeof(struct isakmp_kx2)+kx_data_len); hdr->isakx2_dhgroup = htons(dh_group); *length = sizeof(struct isakmp_kx2) + kx_data_len; return payload; } /* * make_nonce -- Make a Nonce payload * * Inputs: * * length (output) length of nonce payload. * next Next Payload Type * nonce_len Length of nonce data. * * Returns: * * Pointer to nonce payload. * * RFC 2409 states that: "The length of nonce payload MUST be between 8 * and 256 bytes inclusive". However, this function doesn't enforce the * restriction. */ unsigned char* make_nonce(size_t *length, unsigned next, size_t nonce_len) { unsigned char *payload; struct isakmp_nonce* hdr; unsigned char *cp; unsigned i; payload = Malloc(sizeof(struct isakmp_nonce)+nonce_len); hdr = (struct isakmp_nonce*) payload; /* Overlay nonce struct on payload */ memset(hdr, mbz_value, sizeof(struct isakmp_nonce)); hdr->isanonce_np = next; /* Next payload type */ hdr->isanonce_length = htons(sizeof(struct isakmp_nonce)+nonce_len); cp = payload+sizeof(struct isakmp_vid); for (i=0; iisaid_np = next; /* Next payload type */ hdr->isaid_length = htons(sizeof(struct isakmp_id)+id_data_len); hdr->isaid_idtype = idtype; /* * RFC 2407 4.6.2: "During Phase I negotiations, the ID port and protocol * fields MUST be set to zero or to UDP port 500" */ hdr->isaid_doi_specific_a = 17; /* Protocol: UDP */ hdr->isaid_doi_specific_b = htons(500); /* Port: 500 */ memcpy(payload+sizeof(struct isakmp_id), id_data, id_data_len); *length = sizeof(struct isakmp_id) + id_data_len; return payload; } /* * make_udphdr -- Construct a UDP header for encapsulated IKE * * Inputs: * * length (output) length of UDP header * sport UDP source port * dport UDP destination port * udplen UDP length * * Returns: * * Pointer to constructed UDP header * * This constructs a UDP header which is used for IKE * encapsulated within TCP. */ unsigned char* make_udphdr(size_t *length, unsigned sport, unsigned dport, unsigned udplen) { unsigned char *payload; ike_udphdr *hdr; payload = Malloc(sizeof(ike_udphdr)); hdr = (ike_udphdr*) payload; /* Overlay UDP hdr on payload */ hdr->source = htons(sport); hdr->dest = htons(dport); hdr->len = htons(udplen); hdr->check = 0; /* should use in_cksum() */ *length = sizeof(ike_udphdr); return payload; } /* * make_cr -- Construct a certificate request payload * * Inputs: * * length (output) length of certificate request payload. * next Next Payload Type * cr_data Certificate request data * cr_data_len Certificate request data length * * Returns: * * Pointer to certificate request payload. * * This constructs a certificate request payload. */ unsigned char* make_cr(size_t *length, unsigned next, unsigned char *cr_data, size_t cr_data_len) { unsigned char *payload; struct isakmp_generic* hdr; payload = Malloc(sizeof(struct isakmp_generic)+cr_data_len); hdr = (struct isakmp_generic*) payload; memset(hdr, mbz_value, sizeof(struct isakmp_generic)); hdr->isag_np = next; /* Next payload type */ hdr->isag_length = htons(sizeof(struct isakmp_generic)+cr_data_len); memcpy(payload+sizeof(struct isakmp_generic), cr_data, cr_data_len); *length = sizeof(struct isakmp_generic) + cr_data_len; return payload; } /* * skip_payload -- Skip an ISAMKP payload * * Inputs: * * cp Pointer to start of payload to skip * len Packet length remaining * next Next payload type. * * Returns: * * Pointer to start of next payload, or NULL if no next payload. */ unsigned char * skip_payload(unsigned char *cp, size_t *len, unsigned *next) { struct isakmp_generic hdr; /* * Signal no more payloads by setting length to zero, next * payload to none and returning NULL if the packet length is * less that the ISAKMP generic header size. */ if (*len < sizeof(struct isakmp_generic)) { *len=0; *next=ISAKMP_NEXT_NONE; return NULL; } /* * Fill in the generic header from the packet. We must do this * by copying rather than overlaying because we cannot be sure * that "cp" is suitably aligned. */ memcpy(&hdr, cp, sizeof(hdr)); /* * Signal no more payloads if: * * The payload length is greater than the packet length; or * The payload length is less than the size of the generic header; or * There is no next payload. * * Also set *next to none and return null. */ if (ntohs(hdr.isag_length) >= *len || ntohs(hdr.isag_length) < sizeof(struct isakmp_generic) || hdr.isag_np == ISAKMP_NEXT_NONE) { *len=0; *next=ISAKMP_NEXT_NONE; return NULL; } /* * There is another payload after this one, so adjust length and * return pointer to next payload. */ *len = *len - ntohs(hdr.isag_length); *next = hdr.isag_np; return cp + ntohs(hdr.isag_length); } /* * process_isakmp_hdr -- Process ISAKMP header * * Inputs: * * cp Pointer to start of ISAKMP header * len Packet length remaining * next Next payload type. * type Exchange type * hdr_descr ISAKMP Header description string * * Returns: * * Pointer to start of next payload, or NULL if no next payload. */ unsigned char * process_isakmp_hdr(unsigned char *cp, size_t *len, unsigned *next, unsigned *type, char **hdr_descr) { struct isakmp_hdr *hdr = (struct isakmp_hdr *) cp; char *msg; char *msg2; /* * Signal no more payloads by setting length to zero if: * * The packet length is less than the ISAKMP header size; or * The payload length is less than the size of the header; or * There is no next payload. * * Also set *next to none and return null. */ if (*len < sizeof(struct isakmp_hdr) || ntohl(hdr->isa_length) < sizeof(struct isakmp_hdr) || hdr->isa_np == ISAKMP_NEXT_NONE) { *hdr_descr = NULL; *len=0; *next=ISAKMP_NEXT_NONE; *type=ISAKMP_XCHG_NONE; return NULL; } /* * Create ISAKMP header description string. */ msg2 = hexstring((unsigned char *)hdr->isa_rcookie, 8); msg = make_message("HDR=(CKY-R=%s", msg2); free(msg2); if (hdr->isa_version != 0x10) { /* Version not 1.0 */ msg2 = msg; if (hdr->isa_version == 0x20) { msg = make_message("%s, IKEv2", msg2); } else { msg = make_message("%s, version=0x%.2x", msg2, hdr->isa_version); } free(msg2); } if ((hdr->isa_version==0x10 && hdr->isa_flags != 0) || (hdr->isa_version==0x20 && hdr->isa_flags != 0x20)) { msg2 = msg; msg = make_message("%s, flags=0x%.2x", msg2, hdr->isa_flags); free(msg2); } if (hdr->isa_msgid != 0) { /* Non-Zero msgid - shouldn't happen */ msg2 = msg; msg = make_message("%s, msgid=%.8x", msg2, ntohl(hdr->isa_msgid)); free(msg2); } msg2 = msg; msg = make_message("%s)", msg2); free(msg2); /* * There is another payload after this one, so adjust length and * return pointer to next payload. */ *hdr_descr = msg; *len = *len - sizeof(struct isakmp_hdr); *next = hdr->isa_np; *type = hdr->isa_xchg; return cp + sizeof(struct isakmp_hdr); } /* * process_sa -- Process SA Payload * * Inputs: * * cp Pointer to start of SA payload * len Packet length remaining * type Exchange type. * quiet Only print the basic info if nonzero * multiline Split decodes across lines if nonzero * hdr_descr ISAKMP Header description string * * Returns: * * Pointer to SA description string. * * The description string pointer returned points to malloc'ed storage * which should be free'ed by the caller when it's no longer needed. */ char * process_sa(unsigned char *cp, size_t len, unsigned type, int quiet, int multiline, char *hdr_descr) { struct isakmp_sa *sa_hdr = (struct isakmp_sa *) cp; struct isakmp_proposal *prop_hdr = (struct isakmp_proposal *) (cp + sizeof(struct isakmp_sa)); char *msg; char *msg2; char *msg3; unsigned char *attr_ptr; size_t safelen; /* Shorter of actual and claimed length */ safelen = (ntohs(sa_hdr->isasa_length)isasa_length):len; /* * Return with a "too short to decode" message if either the remaining * packet length or the claimed payload length is less than the combined * size of the SA, Proposal, and transform headers. */ if (safelen < sizeof(struct isakmp_sa) + sizeof(struct isakmp_proposal) + sizeof(struct isakmp_transform)) return make_message("IKE Handshake returned (packet too short to decode)"); /* * Build the first part of the message based on the exchange type. */ if (type == ISAKMP_XCHG_IDPROT) { /* Main Mode */ msg = make_message("Main Mode Handshake returned"); } else if (type == ISAKMP_XCHG_AGGR) { /* Aggressive Mode */ msg = make_message("Aggressive Mode Handshake returned"); } else { msg = make_message("UNKNOWN Mode Handshake returned (%u)", type); } /* * If quiet is not in effect, add the ISAKMP header details to the message. */ if (!quiet) { msg2 = msg; msg = make_message("%s%s%s", msg2, multiline?"\n\t":" ", hdr_descr); free(msg2); } /* * We should have exactly one transform in the server's response. * If there is not exactly one transform, then add this fact to the * message. This normally means that we've received our own output. */ if (prop_hdr->isap_notrans != 1) { msg2 = msg; msg = make_message("%s (%d transforms)", msg2, prop_hdr->isap_notrans); free(msg2); } /* * If quiet is not in effect, and we have exactly one transform, add the * transform details to the message. */ if (!quiet && prop_hdr->isap_notrans==1) { int firstloop=1; msg2 = msg; msg = make_message("%s%sSA=(", msg2, multiline?"\n\t":" "); free(msg2); if (prop_hdr->isap_spisize != 0) { /* Non-Zero SPI */ msg2 = msg; msg3 = hexstring(cp + sizeof(struct isakmp_sa) + sizeof(struct isakmp_proposal), prop_hdr->isap_spisize); msg = make_message("%sSPI=%s ", msg2, msg3); free(msg2); free(msg3); } attr_ptr = (cp + sizeof(struct isakmp_sa) + sizeof(struct isakmp_proposal) + prop_hdr->isap_spisize + sizeof(struct isakmp_transform)); safelen -= sizeof(struct isakmp_sa) + sizeof(struct isakmp_proposal) + prop_hdr->isap_spisize + sizeof(struct isakmp_transform); while (safelen) { msg2 = msg; msg3 = process_attr(&attr_ptr, &safelen); if (firstloop) { /* Don't need leading space for 1st attr */ msg = make_message("%s%s", msg2, msg3); firstloop=0; } else { msg = make_message("%s %s", msg2, msg3); } free(msg2); free(msg3); } msg2 = msg; msg = make_message("%s)", msg2); free(msg2); } return msg; } /* * process_sa2 -- Process an IKEv2 SA Payload * * Inputs: * * cp Pointer to start of SA payload * len Packet length remaining * type Exchange type. * quiet Only print the basic info if nonzero * multiline Split decodes across lines if nonzero * hdr_descr ISAKMP Header description string * * Returns: * * Pointer to SA description string. * * The description string pointer returned points to malloc'ed storage * which should be free'ed by the caller when it's no longer needed. */ char * process_sa2(unsigned char *cp, size_t len, unsigned type, int quiet, int multiline, char *hdr_descr) { struct isakmp_sa2 *sa_hdr = (struct isakmp_sa2 *) cp; struct isakmp_proposal *prop_hdr = (struct isakmp_proposal *) (cp + sizeof(struct isakmp_sa2)); char *msg; char *msg2; char *msg3; unsigned char *trans_ptr; size_t safelen; /* Shorter of actual and claimed length */ safelen = (ntohs(sa_hdr->isasa2_length)isasa2_length):len; /* * Return with a "too short to decode" message if either the remaining * packet length or the claimed payload length is less than the combined * size of the SA, Proposal, and transform headers. */ if (safelen < sizeof(struct isakmp_sa2) + sizeof(struct isakmp_proposal) + sizeof(struct isakmp_transform2)) return make_message("IKEv2 Handshake returned (packet too short to decode)"); /* * Build the first part of the message based on the exchange type. */ if (type == ISAKMP_XCHG_IKE_SA_INIT) { msg = make_message("IKEv2 SA_INIT Handshake returned"); } else { msg = make_message("UNKNOWN Mode Handshake returned (%u)", type); } /* * If quiet is not in effect, add the ISAKMP header details to the message. */ if (!quiet) { msg2 = msg; msg = make_message("%s%s%s", msg2, multiline?"\n\t":" ", hdr_descr); free(msg2); } /* * We should have exactly one proposal in the server's response. * If there is not exactly one proposal, then add this fact to the * message. This normally means that we've received our own output. */ if (prop_hdr->isap_np != ISAKMP_NEXT_NONE) { msg2 = msg; msg = make_message("%s (multiple proposals)", msg2); free(msg2); } /* * If quiet is not in effect, and we have exactly one proposal, add the * proposal details to the message. */ if (!quiet && prop_hdr->isap_np == ISAKMP_NEXT_NONE) { int firstloop=1; msg2 = msg; msg = make_message("%s%sSA=(", msg2, multiline?"\n\t":" "); free(msg2); if (prop_hdr->isap_spisize != 0) { /* Non-Zero SPI */ msg2 = msg; msg3 = hexstring(cp + sizeof(struct isakmp_sa2) + sizeof(struct isakmp_proposal), prop_hdr->isap_spisize); msg = make_message("%sSPI=%s ", msg2, msg3); free(msg2); free(msg3); } trans_ptr = cp + sizeof(struct isakmp_sa2) + sizeof(struct isakmp_proposal) + prop_hdr->isap_spisize; safelen -= sizeof(struct isakmp_sa2) + sizeof(struct isakmp_proposal) + prop_hdr->isap_spisize; while (safelen) { msg2 = msg; msg3 = process_transform2(&trans_ptr, &safelen); if (firstloop) { /* Don't need leading space for 1st attr */ msg = make_message("%s%s", msg2, msg3); firstloop=0; } else { msg = make_message("%s %s", msg2, msg3); } free(msg2); free(msg3); } msg2 = msg; msg = make_message("%s)", msg2); free(msg2); } return msg; } /* * process_attr -- Process transform attribute * * Inputs: * * cp Pointer to start of attribute * len Packet length remaining * * Returns: * * Pointer to attribute description string. * * The description string pointer returned points to malloc'ed storage * which should be free'ed by the caller when it's no longer needed. */ char * process_attr(unsigned char **cp, size_t *len) { char *msg; struct isakmp_attribute *attr_hdr = (struct isakmp_attribute *) *cp; char attr_type; /* B=Basic, V=Variable */ unsigned attr_class; unsigned attr_value=0; char *attr_class_str; char *attr_value_str; size_t value_len; size_t size; if (ntohs(attr_hdr->isaat_af_type) & 0x8000) { /* Basic attribute */ attr_type = 'B'; attr_class = ntohs (attr_hdr->isaat_af_type) & 0x7fff; attr_value = ntohs (attr_hdr->isaat_lv); value_len = 0; /* Value is in length field */ } else { /* Variable attribute */ attr_type = 'V'; attr_class = ntohs (attr_hdr->isaat_af_type); value_len = ntohs (attr_hdr->isaat_lv); } attr_class_str = make_message("%s", id_to_name(attr_class, attr_map)); if (attr_type == 'B') { switch (attr_class) { case 1: /* Encryption Algorithm */ attr_value_str = make_message("%s", id_to_name(attr_value, enc_map)); break; case 2: /* Hash Algorithm */ attr_value_str = make_message("%s", id_to_name(attr_value, hash_map)); break; case 3: /* Authentication Method */ attr_value_str = make_message("%s", id_to_name(attr_value, auth_map)); break; case 4: /* Group Description */ attr_value_str = make_message("%s", id_to_name(attr_value, dh_map)); break; case 11: /* Life Type */ attr_value_str = make_message("%s", id_to_name(attr_value, life_map)); break; default: attr_value_str = make_message("%u", attr_value); break; } } else { attr_value_str = hexstring((*cp) + sizeof (struct isakmp_attribute), value_len); } if (attr_type == 'B') msg = make_message("%s=%s", attr_class_str, attr_value_str); else msg = make_message("%s(%u)=0x%s", attr_class_str, value_len, attr_value_str); free(attr_class_str); free(attr_value_str); size=sizeof (struct isakmp_attribute) + value_len; if (size >= *len) { *len=0; } else { *len -= size; (*cp) += size; } return msg; } /* * process_transform2 -- Process IKEv2 transforms * * Inputs: * * cp Pointer to start of transform * len Packet length remaining * * Returns: * * Pointer to transform description string. * * The description string pointer returned points to malloc'ed storage * which should be free'ed by the caller when it's no longer needed. */ char * process_transform2(unsigned char **cp, size_t *len) { char *msg; struct isakmp_transform2 *trans_hdr = (struct isakmp_transform2 *) *cp; unsigned trans_type; unsigned trans_id; char *trans_type_str; char *trans_id_str; size_t size; trans_type = trans_hdr->isat2_transtype; trans_id = ntohs(trans_hdr->isat2_transid); trans_type_str = make_message("%s", id_to_name(trans_type, trans_type_map)); switch (trans_type) { case 1: /* Encryption Algorithm */ trans_id_str = make_message("%s", id_to_name(trans_id, encr_map)); break; case 2: /* Pseudo-random Function */ trans_id_str = make_message("%s", id_to_name(trans_id, prf_map)); break; case 3: /* Integrity Algorithm */ trans_id_str = make_message("%s", id_to_name(trans_id, integ_map)); break; case 4: /* Diffie-Hellman Group */ trans_id_str = make_message("%s", id_to_name(trans_id, dh_map)); break; default: trans_id_str = make_message("%u", trans_id); break; } size=ntohs(trans_hdr->isat2_length); if (size > sizeof(struct isakmp_transform2)) { /* Attributes present */ unsigned char *attr_ptr = (*cp) + sizeof(struct isakmp_transform2); struct isakmp_attribute *attr_hdr = (struct isakmp_attribute *) attr_ptr; unsigned attr_class=0; unsigned attr_value=0; if (ntohs(attr_hdr->isaat_af_type) & 0x8000) { /* Basic attribute */ attr_class = ntohs (attr_hdr->isaat_af_type) & 0x7fff; attr_value = ntohs (attr_hdr->isaat_lv); } else { /* Variable attribute */ warn_msg("WARNING: Ignoring IKEv2 variable length transform attribute"); } msg = make_message("%s=%s,%s=%u", trans_type_str, trans_id_str, id_to_name(attr_class, attr_map), attr_value); } else { /* No attributes */ msg = make_message("%s=%s", trans_type_str, trans_id_str); } free(trans_type_str); free(trans_id_str); if (size >= *len) { *len=0; } else { *len -= size; (*cp) += size; } return msg; } /* * process_vid -- Process Vendor ID Payload * * Inputs: * * cp Pointer to start of Vendor ID payload * len Packet length remaining * vidlist List of Vendor ID patterns. * * Returns: * * Pointer to Vendor ID description string. * * The description string pointer returned points to malloc'ed storage * which should be free'ed by the caller when it's no longer needed. */ char * process_vid(unsigned char *cp, size_t len, vid_pattern_list *vidlist) { struct isakmp_vid *hdr = (struct isakmp_vid *) cp; char *msg; char *hexvid; char *p; unsigned char *vid_data; size_t data_len; vid_pattern_list *ve; if (len < sizeof(struct isakmp_vid) || ntohs(hdr->isavid_length) < sizeof(struct isakmp_vid)) return make_message("VID (packet too short to decode)"); vid_data = cp + sizeof(struct isakmp_vid); /* Points to start of VID data */ data_len = ntohs(hdr->isavid_length) < len ? ntohs(hdr->isavid_length) : len; data_len -= sizeof(struct isakmp_vid); hexvid = hexstring(vid_data, data_len); msg=make_message("VID=%s", hexvid); /* * Try to find a match in the Vendor ID pattern list. */ ve = vidlist; while(ve != NULL) { if (!(regexec(ve->regex, hexvid, 0, NULL, 0))) { p=msg; msg=make_message("%s (%s)", p, ve->name); free(p); break; /* Stop looking after first match */ } ve=ve->next; } free(hexvid); return msg; } /* * process_notify -- Process notify Payload * * Inputs: * * cp Pointer to start of notify payload * len Packet length remaining * quiet Only print the basic info if nonzero * multiline Split decodes across lines if nonzero * hdr_descr ISAKMP Header description string * * Returns: * * Pointer to notify description string. * * This function is only used for notification messages that are part * of an informational exchange. Notification messages that are part * of another exchange type are handled with process_notification() * instead. This is an ugly hack. * * The description string pointer returned points to malloc'ed storage * which should be free'ed by the caller when it's no longer needed. */ char * process_notify(unsigned char *cp, size_t len, int quiet, int multiline, char *hdr_descr) { struct isakmp_notification *hdr = (struct isakmp_notification *) cp; char *msg; char *msg2; unsigned msg_type; size_t msg_len; unsigned char *msg_data; char *notify_msg; if (len < sizeof(struct isakmp_notification) || ntohs(hdr->isan_length) < sizeof(struct isakmp_notification)) return make_message("Notify message (packet too short to decode)"); msg_type = ntohs(hdr->isan_type); msg_len = ntohs(hdr->isan_length) - sizeof(struct isakmp_notification); msg_data = cp + sizeof(struct isakmp_notification); if (msg_type == 9101 || msg_type == 9110) { /* Firewall-1 message types */ notify_msg = printable(msg_data, msg_len); msg=make_message("Notify message %u (Firewall-1) Message=\"%s\"", msg_type, notify_msg); free(notify_msg); } else { /* All other Message Types */ msg=make_message("Notify message %u (%s)", msg_type, id_to_name(msg_type, notification_map)); } /* * If quiet is not in effect, add the ISAKMP header details to the message. */ if (!quiet) { msg2 = msg; msg = make_message("%s%s%s", msg2, multiline?"\n\t":" ", hdr_descr); free(msg2); } return msg; } /* * process_notify2 -- Process IKEv2 notify Payload * * Inputs: * * cp Pointer to start of notify payload * len Packet length remaining * quiet Only print the basic info if nonzero * multiline Split decodes across lines if nonzero * hdr_descr ISAKMP Header description string * * Returns: * * Pointer to notify description string. * * This function is only used for notification messages that are part * of an informational exchange. Notification messages that are part * of another exchange type are handled with process_notification() * instead. This is an ugly hack. * * The description string pointer returned points to malloc'ed storage * which should be free'ed by the caller when it's no longer needed. */ char * process_notify2(unsigned char *cp, size_t len, int quiet, int multiline, char *hdr_descr) { struct isakmp_notification2 *hdr = (struct isakmp_notification2 *) cp; char *msg; char *msg2; unsigned msg_type; size_t msg_len; unsigned char *msg_data; char *notify_msg; if (len < sizeof(struct isakmp_notification2) || ntohs(hdr->isan2_length) < sizeof(struct isakmp_notification2)) return make_message("Notify message (packet too short to decode)"); msg_type = ntohs(hdr->isan2_type); msg_len = ntohs(hdr->isan2_length) - sizeof(struct isakmp_notification2); msg_data = cp + sizeof(struct isakmp_notification2); if (msg_type == 9101 || msg_type == 9110) { /* Firewall-1 message types */ notify_msg = printable(msg_data, msg_len); msg=make_message("Notify message %u (Firewall-1) Message=\"%s\"", msg_type, notify_msg); free(notify_msg); } else { /* All other Message Types */ msg=make_message("Notify message %u (%s)", msg_type, id_to_name(msg_type, notification_map2)); } /* * If quiet is not in effect, add the ISAKMP header details to the message. */ if (!quiet) { msg2 = msg; msg = make_message("%s%s%s", msg2, multiline?"\n\t":" ", hdr_descr); free(msg2); } return msg; } /* * process_notification -- Process notification Payload * * Inputs: * * cp Pointer to start of notify payload * len Packet length remaining * * Returns: * * Pointer to notify description string. * * The description string pointer returned points to malloc'ed storage * which should be free'ed by the caller when it's no longer needed. */ char * process_notification(unsigned char *cp, size_t len) { struct isakmp_notification *hdr = (struct isakmp_notification *) cp; char *msg; char *msg2; unsigned msg_type; size_t msg_len; unsigned char *msg_data; char *hex_spi; unsigned char *notification_spi; char *hex_data; size_t spi_len; uint32_t doi; unsigned proto_id; if (len < sizeof(struct isakmp_notification) || ntohs(hdr->isan_length) < sizeof(struct isakmp_notification)) return make_message("Notification (packet too short to decode)"); doi = ntohl(hdr->isan_doi); proto_id = hdr->isan_protoid; msg_type = ntohs(hdr->isan_type); notification_spi = cp + sizeof(struct isakmp_notification); spi_len = hdr->isan_spisize; hex_spi = hexstring(notification_spi, spi_len); msg_len = ntohs(hdr->isan_length) - sizeof(struct isakmp_notification) - spi_len; msg_data = cp + sizeof(struct isakmp_notification) + spi_len; hex_data = hexstring(msg_data, msg_len); msg=make_message("Notification=("); if (doi != 1) { /* DOI not IPsec */ msg2 = msg; msg = make_message("%sDOI=%s, ", msg2, id_to_name(doi, doi_map)); free(msg2); } if (proto_id != 1) { /* Protocol ID not ISAKMP */ msg2 = msg; msg = make_message("%sProto_ID=%s, ", msg2, id_to_name(proto_id, protocol_map)); free(msg2); } msg2 = msg; msg=make_message("%sType=%s, SPI=%s, Data=%s)", msg2, id_to_name(msg_type, notification_map), hex_spi, hex_data); free(msg2); free(hex_spi); free(hex_data); return msg; } /* * process_id -- Process identification Payload * * Inputs: * * cp Pointer to start of identification payload * len Packet length remaining * * Returns: * * Pointer to identification description string. * * The description string pointer returned points to malloc'ed storage * which should be free'ed by the caller when it's no longer needed. */ char * process_id(unsigned char *cp, size_t len) { struct isakmp_id *hdr = (struct isakmp_id *) cp; unsigned idtype; char *msg; char *msg2; unsigned char *id_data; size_t data_len; if (len < sizeof(struct isakmp_id) || ntohs(hdr->isaid_length) < sizeof(struct isakmp_id)) return make_message("ID (packet too short to decode)"); id_data = cp + sizeof(struct isakmp_id); /* Points to start of ID data */ data_len = ntohs(hdr->isaid_length) < len ? ntohs(hdr->isaid_length) : len; data_len -= sizeof(struct isakmp_id); idtype = hdr->isaid_idtype; switch(idtype) { char *id; /* Printable ID */ struct in_addr in; /* IPv4 Address */ struct in_addr in2; /* IPv4 Address */ unsigned char *mask; /* Netmask */ case ID_IPV4_ADDR: if (data_len >= sizeof(struct in_addr)) { memcpy(&in, id_data, sizeof(struct in_addr)); msg=make_message("Value=%s", inet_ntoa(in)); } else { msg=make_message("Value too short to decode"); } break; case ID_IPV4_ADDR_SUBNET: if (data_len >= sizeof(struct in_addr) + 4) { memcpy(&in, id_data, sizeof(struct in_addr)); mask = id_data + sizeof(struct in_addr); msg=make_message("Value=%s/%u.%u.%u.%u", inet_ntoa(in), mask[0], mask[1], mask[2], mask[3]); } else { msg=make_message("Value too short to decode"); } break; case ID_IPV4_ADDR_RANGE: if (data_len >= 2 * sizeof(struct in_addr)) { memcpy(&in, id_data, sizeof(struct in_addr)); memcpy(&in2, id_data+sizeof(struct in_addr), sizeof(struct in_addr)); msg=make_message("Value=%s-%s", inet_ntoa(in), inet_ntoa(in2)); } else { msg=make_message("Value too short to decode"); } break; case ID_FQDN: case ID_USER_FQDN: id = printable(id_data, data_len); msg=make_message("Value=%s", id); free(id); break; case ID_KEY_ID: id = hexstring(id_data, data_len); msg = make_message("Value=%s", id); free(id); break; case ID_IPV6_ADDR: case ID_IPV6_ADDR_SUBNET: case ID_IPV6_ADDR_RANGE: case ID_DER_ASN1_DN: case ID_DER_ASN1_GN: msg=make_message("Decode not supported for this type"); break; default: msg = make_message("Unknown ID Type"); break; } msg2=msg; msg=make_message("ID(Type=%s, %s)", id_to_name(idtype,id_map), msg2); free(msg2); return msg; } /* * process_cert -- Process Certificate Payload * * Inputs: * * cp Pointer to start of certificate payload * len Packet length remaining * next The previous next payload type * * Returns: * * Pointer to certificate description string. * * The description string pointer returned points to malloc'ed storage * which should be free'ed by the caller when it's no longer needed. */ char * process_cert(unsigned char *cp, size_t len, unsigned next) { struct isakmp_generic *hdr = (struct isakmp_generic *) cp; char *msg; unsigned char cert_type; unsigned char *cert_data; size_t data_len; if (len < sizeof(struct isakmp_generic) + 1 || ntohs(hdr->isag_length) < sizeof(struct isakmp_generic) + 1) return make_message("Certificate (packet too short to decode)"); cert_data = cp + sizeof(struct isakmp_generic); cert_type = *cert_data++; data_len = ntohs(hdr->isag_length) < len ? ntohs(hdr->isag_length) : len; data_len -= sizeof(struct isakmp_generic) + 1; msg=make_message("%s(Type=%s, Length=%u bytes)", id_to_name(next, payload_map), id_to_name(cert_type, cert_map), data_len); return msg; } /* * process_delete -- Process Delete Payload * * Inputs: * * cp Pointer to start of Delete payload * len Packet length remaining * * Returns: * * Pointer to Delete description string. * * The description string pointer returned points to malloc'ed storage * which should be free'ed by the caller when it's no longer needed. */ char * process_delete(unsigned char *cp, size_t len) { struct isakmp_delete *hdr = (struct isakmp_delete *) cp; char *msg; char *hex_spi; unsigned char *delete_spi; size_t spi_len; if (len < sizeof(struct isakmp_delete) || ntohs(hdr->isad_length) < sizeof(struct isakmp_delete)) return make_message("Delete (packet too short to decode)"); delete_spi = cp + sizeof(struct isakmp_delete); spi_len = ntohs(hdr->isad_length) < len ? ntohs(hdr->isad_length) : len; spi_len -= sizeof(struct isakmp_delete); hex_spi = hexstring(delete_spi, spi_len); msg=make_message("Delete=(SPI_Size=%u, SPI_Count=%u, SPI_Data=%s)", hdr->isad_spisize, ntohs(hdr->isad_nospi), hex_spi); free(hex_spi); return msg; } /* * process_generic -- Process Generic ISAKMP Payload * * Inputs: * * cp Pointer to start of Delete payload * len Packet length remaining * * Returns: * * Pointer to payload description string. * * The description string pointer returned points to malloc'ed storage * which should be free'ed by the caller when it's no longer needed. */ char * process_generic(unsigned char *cp, size_t len, unsigned next) { struct isakmp_generic *hdr = (struct isakmp_generic *) cp; char *msg; if (len < sizeof(struct isakmp_generic) || ntohs(hdr->isag_length) < sizeof(struct isakmp_generic)) { msg = make_message("%s (packet too short to decode)", id_to_name(next, payload_map)); return msg; } msg=make_message("%s(%u bytes)", id_to_name(next, payload_map), ntohs(hdr->isag_length) - sizeof(struct isakmp_generic)); return msg; } /* * add_isakmp_payload -- Add an ISAKMP payload to the current packet * * Inputs: * * payload Pointer to the payload to add * payload_len Length of the payload * new_payload Pointer to the new payload within the packet * * Returns: * * A pointer to the ISAKMP packet. * * This function assumes that "payload" is a pointer to malloc'ed * storage, and will free it after use. */ unsigned char * add_isakmp_payload(unsigned char *payload, size_t payload_len, unsigned char **new_payload) { static unsigned char *isakmp_packet = NULL; static size_t offset = 0; unsigned char *payload_ptr; /* * Allocate memory for the packet on the first call. */ if (isakmp_packet == NULL) { isakmp_packet = Malloc(MAXUDP); } /* * Calculate position within the packet to add the new payload. * Copy the new payload starting at this position, then free the * payload memory. */ payload_ptr = isakmp_packet+offset; memcpy(payload_ptr, payload, payload_len); free(payload); /* * Set the new_payload argument to the position of the newly added * payload within the packet, and return the address of the start * of the packet. */ *new_payload = payload_ptr; return isakmp_packet; } /* * print_payload -- Print an ISAKMP payload in hex * * Inputs: * * cp Pointer to start of ISAKMP payload * payload Numeric value of this payload type, 0 = ISAKMP header * dir Direction: 'I' for initiator or 'R' for responder * * Returns: * * None * * This function is used for debugging. It trusts the length in the * generic ISAKMP header, and so could misbehave with corrupted packets. */ void print_payload(unsigned char *cp, unsigned payload, int dir) { struct isakmp_generic *hdr = (struct isakmp_generic *) cp; struct isakmp_hdr *ihdr = (struct isakmp_hdr *) cp; char *hexdata; unsigned char *data; size_t data_len; if (payload) { /* Some other payload */ data = cp + sizeof(struct isakmp_generic); /* Points to start of data */ data_len = ntohs(hdr->isag_length); data_len -= sizeof(struct isakmp_generic); hexdata = hexstring(data, data_len); switch (payload) { case ISAKMP_NEXT_SA: printf("sa%c_b_hex=\"%s\"\n", (dir=='I')?'i':'r', hexdata); break; case ISAKMP_NEXT_KE: printf("g_x%c_hex=\"%s\"\n", (dir=='I')?'i':'r', hexdata); break; case ISAKMP_NEXT_ID: printf("idi%c_b_hex=\"%s\"\n", (dir=='I')?'i':'r', hexdata); break; case ISAKMP_NEXT_HASH: printf("expected_hash_%c_hex=\"%s\"\n", (dir=='I')?'i':'r', hexdata); break; case ISAKMP_NEXT_NONCE: printf("n%c_b_hex=\"%s\"\n", (dir=='I')?'i':'r', hexdata); break; default: printf("UNKNOWN PAYLOAD TYPE: %d\n", payload); break; } free(hexdata); } else { /* ISAKMP Header */ hexdata = hexstring((unsigned char *)ihdr->isa_icookie, 8); printf("cky_i_hex=\"%s\"\n", hexdata); free(hexdata); hexdata = hexstring((unsigned char *)ihdr->isa_rcookie, 8); printf("cky_r_hex=\"%s\"\n", hexdata); free(hexdata); } } /* * add_psk_crack_payload -- Add an ISAKMP payload to PSK crack structure * * Inputs: * * cp Pointer to start of ISAKMP payload * payload Numeric value of this payload type, 0 = ISAKMP header * dir Direction: 'I' for initiator or 'R' for responder * * Returns: * * None * * This function trusts the length in the generic ISAKMP header, so * could misbehave with corrupted packets. */ void add_psk_crack_payload(unsigned char *cp, unsigned payload, int dir) { struct isakmp_generic *hdr = (struct isakmp_generic *) cp; struct isakmp_hdr *ihdr = (struct isakmp_hdr *) cp; unsigned char *data; size_t data_len; if (payload) { /* Normal ISAKMP payload */ data_len = ntohs(hdr->isag_length) - sizeof(struct isakmp_generic); data = Malloc(data_len); memcpy(data, cp + sizeof(struct isakmp_generic), data_len); switch (payload) { case ISAKMP_NEXT_SA: if (dir == 'I') { psk_values.sai_b = data; psk_values.sai_b_len = data_len; } break; case ISAKMP_NEXT_KE: if (dir == 'I') { psk_values.g_xi = data; psk_values.g_xi_len = data_len; } else { psk_values.g_xr = data; psk_values.g_xr_len = data_len; } break; case ISAKMP_NEXT_ID: if (dir == 'R') { psk_values.idir_b = data; psk_values.idir_b_len = data_len; } break; case ISAKMP_NEXT_HASH: if (dir == 'R') { psk_values.hash_r = data; psk_values.hash_r_len = data_len; } break; case ISAKMP_NEXT_NONCE: if (dir == 'I') { psk_values.ni_b = data; psk_values.ni_b_len = data_len; } else { psk_values.nr_b = data; psk_values.nr_b_len = data_len; } break; default: warn_msg("add_psk_crack_payload: UNKNOWN PAYLOAD TYPE: %d\n", payload); break; } } else { /* ISAKMP Header */ data_len=8; /* ISAKMP cookies are 8 bytes long */ data=Malloc(data_len); memcpy(data, (unsigned char *)ihdr->isa_rcookie, 8); psk_values.cky_r = data; psk_values.cky_r_len = data_len; data=Malloc(data_len); memcpy(data, (unsigned char *)ihdr->isa_icookie, 8); psk_values.cky_i = data; psk_values.cky_i_len = data_len; } } /* * print_psk_crack_values -- Display the PSK crack values * * Inputs: * * psk_crack_file Name of PSK data output file, or NULL for stdout * * Returns: * * None * * This function prints the PSK crack values in the following format: * * g_xr:g_xi:cky_r:cky_i:sai_b:idir_b:ni_b:nr_b:hash_r */ void print_psk_crack_values(const char *psk_crack_file) { char *hexdata; FILE *fp; if (psk_crack_file[0]) { if ((fp = fopen(psk_crack_file, "w")) == NULL) { err_sys("ERROR: fopen"); } } else { fp = stdout; printf("IKE PSK parameters (g_xr:g_xi:cky_r:cky_i:sai_b:idir_b:ni_b:nr_b:hash_r):\n"); } hexdata=hexstring(psk_values.g_xr, psk_values.g_xr_len); fprintf(fp, "%s:", hexdata); free(hexdata); hexdata=hexstring(psk_values.g_xi, psk_values.g_xi_len); fprintf(fp, "%s:", hexdata); free(hexdata); hexdata=hexstring(psk_values.cky_r, psk_values.cky_r_len); fprintf(fp, "%s:", hexdata); free(hexdata); hexdata=hexstring(psk_values.cky_i, psk_values.cky_i_len); fprintf(fp, "%s:", hexdata); free(hexdata); hexdata=hexstring(psk_values.sai_b, psk_values.sai_b_len); fprintf(fp, "%s:", hexdata); free(hexdata); hexdata=hexstring(psk_values.idir_b, psk_values.idir_b_len); fprintf(fp, "%s:", hexdata); free(hexdata); hexdata=hexstring(psk_values.ni_b, psk_values.ni_b_len); fprintf(fp, "%s:", hexdata); free(hexdata); hexdata=hexstring(psk_values.nr_b, psk_values.nr_b_len); fprintf(fp, "%s:", hexdata); free(hexdata); hexdata=hexstring(psk_values.hash_r, psk_values.hash_r_len); fprintf(fp, "%s\n", hexdata); free(hexdata); } /* * clone_payload -- Clone the ISAKMP payload * * Inputs: * * pkt_ptr Pointer to the payload to clone * bytes_left Number of bytes remaining in the packet * * Returns: * * Pointer to the cloned payload or NULL if no payload. * * This function clones the ISAKMP payload starting at pkt_ptr, with * a maximum size of bytes_left. It copies the payload to a newly * allocated memory block to ensure that it is suitably aligned for * those CPUs that have alignment restrictions. * * The return value points to Malloc'ed memory, which should be * free'ed when it is no longer required. */ unsigned char * clone_payload(const unsigned char *pkt_ptr, size_t bytes_left) { struct isakmp_generic hdr; unsigned char *clone_ptr; size_t payload_len; /* * Ensure that there is sufficient data to fill the generic * header. */ if (bytes_left < sizeof(struct isakmp_generic)) { return NULL; } /* * Fill in the generic header from the packet. We must do this * by copying rather than overlaying because we cannot be sure * that "pkt_ptr" is suitably aligned. */ memcpy(&hdr, pkt_ptr, sizeof(hdr)); /* * Determine the length of the payload. */ payload_len = ntohs(hdr.isag_length); if (payload_len > bytes_left) payload_len = bytes_left; /* * Allocate memory and copy payload. */ clone_ptr = Malloc(payload_len); memcpy(clone_ptr, pkt_ptr, payload_len); return clone_ptr; } void isakmp_use_rcsid(void) { fprintf(stderr, "%s\n", rcsid); /* Use rcsid to stop compiler optimising away */ }