2735 lines
81 KiB
C
2735 lines
81 KiB
C
/*
|
|
* 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; i<spi_size; i++)
|
|
*(cp++) = (unsigned char) random_byte();
|
|
}
|
|
|
|
/* Add the transforms */
|
|
|
|
memcpy(cp, transforms, transform_len);
|
|
|
|
*outlen = len;
|
|
return payload;
|
|
}
|
|
|
|
/*
|
|
* make_trans_simple -- Construct a single simple transform payload
|
|
*
|
|
* Inputs:
|
|
*
|
|
* length (output) length of entire transform payload.
|
|
* next Next Payload Type (3 = More transforms; 0=No more transforms)
|
|
* number Transform number
|
|
* cipher The encryption algorithm
|
|
* keylen Key length for variable length keys (0=fixed key length)
|
|
* hash Hash algorithm
|
|
* auth Authentication method
|
|
* group DH Group number
|
|
* lifetime Lifetime in seconds (0=no lifetime)
|
|
* lifesize Life in kilobytes (0=no life)
|
|
*
|
|
* Returns:
|
|
*
|
|
* Pointer to transform payload.
|
|
*
|
|
* This constructs a single simple transform payload.
|
|
* Most of the values are defined in RFC 2409 Appendix A.
|
|
*
|
|
* This function can only create a transform with a restricted set of
|
|
* attributes in a defined order. To create a transform with an arbitrary
|
|
* set of attributes in any order, use the make_transform function
|
|
* instead.
|
|
*/
|
|
unsigned char*
|
|
make_trans_simple(size_t *length, unsigned next, unsigned number,
|
|
unsigned cipher, unsigned keylen, unsigned hash, unsigned auth,
|
|
unsigned group, unsigned char *lifetime_data,
|
|
size_t lifetime_data_len, unsigned char *lifesize_data,
|
|
size_t lifesize_data_len, int gss_id_flag, unsigned char *gss_data,
|
|
size_t gss_data_len, unsigned trans_id) {
|
|
|
|
unsigned char *payload;
|
|
unsigned char *attr;
|
|
size_t attr_len; /* Attribute Length */
|
|
|
|
/* Allocate and initialise the mandatory attributes */
|
|
|
|
add_attr(0, NULL, 'B', OAKLEY_ENCRYPTION_ALGORITHM, 0, cipher, NULL);
|
|
add_attr(0, NULL, 'B', OAKLEY_HASH_ALGORITHM, 0, hash, NULL);
|
|
add_attr(0, NULL, 'B', OAKLEY_AUTHENTICATION_METHOD, 0, auth, NULL);
|
|
add_attr(0, NULL, 'B', OAKLEY_GROUP_DESCRIPTION, 0, group, NULL);
|
|
|
|
/* Allocate and initialise the optional attributes */
|
|
|
|
if (keylen)
|
|
add_attr(0, NULL, 'B', OAKLEY_KEY_LENGTH, 0, keylen, NULL);
|
|
|
|
if (lifetime_data_len) {
|
|
add_attr(0, NULL, 'B', OAKLEY_LIFE_TYPE, 0, SA_LIFE_TYPE_SECONDS, NULL);
|
|
add_attr(0, NULL, 'V', OAKLEY_LIFE_DURATION, lifetime_data_len, 0,
|
|
lifetime_data);
|
|
}
|
|
|
|
if (lifesize_data_len) {
|
|
add_attr(0, NULL, 'B', OAKLEY_LIFE_TYPE, 0, SA_LIFE_TYPE_KBYTES, NULL);
|
|
add_attr(0, NULL, 'V', OAKLEY_LIFE_DURATION, lifesize_data_len, 0,
|
|
lifesize_data);
|
|
}
|
|
|
|
if (gss_id_flag)
|
|
add_attr(0, NULL, 'V', OAKLEY_GSS_ID, gss_data_len, 0, gss_data);
|
|
|
|
/* Finalise attributes and fill in length value */
|
|
|
|
attr = add_attr(1, &attr_len, '\0', 0, 0, 0, NULL);
|
|
|
|
/* Create transform */
|
|
|
|
payload = make_transform(length, next, number, trans_id, attr, attr_len);
|
|
free(attr);
|
|
|
|
return payload;
|
|
}
|
|
|
|
/*
|
|
* add_trans_simple -- Add a simple transform payload to set of transforms.
|
|
*
|
|
* Inputs:
|
|
*
|
|
* finished 0 if adding a new transform; 1 if finalising.
|
|
* length (output) length of entire transform payload.
|
|
* cipher The encryption algorithm
|
|
* keylen Key length for variable length keys (0=fixed key length)
|
|
* hash Hash algorithm
|
|
* auth Authentication method
|
|
* group DH Group number
|
|
* lifetime Lifetime in seconds (0=no lifetime)
|
|
*
|
|
* Returns:
|
|
*
|
|
* Pointer to new set of transform payloads.
|
|
*
|
|
* This function can either be called with finished = 0, in which case
|
|
* cipher, keylen, hash, auth, group and lifetime must be specified, and
|
|
* the function will return NULL, OR it can be called with finished = 1
|
|
* in which case cipher, keylen, hash, auth, group and lifetime are
|
|
* ignored and the function will return a pointer to the finished
|
|
* payload and will set *length to the length of this payload.
|
|
*
|
|
* This function can only create transforms with a restricted set of
|
|
* attributes in a defined order. To create transforms with an arbitrary
|
|
* set of attributes in any order, use the add_transform function
|
|
* instead.
|
|
*/
|
|
unsigned char*
|
|
add_trans_simple(int finished, size_t *length, unsigned cipher,
|
|
unsigned keylen, unsigned hash, unsigned auth,
|
|
unsigned group, unsigned char *lifetime_data,
|
|
size_t lifetime_data_len, unsigned char *lifesize_data,
|
|
size_t lifesize_data_len, int gss_id_flag,
|
|
unsigned char *gss_data, size_t gss_data_len,
|
|
unsigned trans_id) {
|
|
|
|
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_trans_simple(&len, ISAKMP_NEXT_T, trans_no, cipher, keylen,
|
|
hash, auth, group, lifetime_data,
|
|
lifetime_data_len, lifesize_data,
|
|
lifesize_data_len, gss_id_flag, gss_data,
|
|
gss_data_len, trans_id);
|
|
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 = 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; i<kx_data_len; i++)
|
|
*(kx_data++) = (unsigned char) random_byte();
|
|
|
|
hdr->isakx_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; i<kx_data_len; i++)
|
|
*(kx_data++) = (unsigned char) random_byte();
|
|
|
|
hdr->isakx2_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; i<nonce_len; i++)
|
|
*(cp++) = (unsigned char) random_byte();
|
|
|
|
*length = sizeof(struct isakmp_nonce)+nonce_len;
|
|
return payload;
|
|
}
|
|
|
|
/*
|
|
* make_id -- Make an Identification payload
|
|
*
|
|
* Inputs:
|
|
*
|
|
* length (output) length of ID payload.
|
|
* next Next Payload Type
|
|
* idtype Identification Type
|
|
* id_data ID data
|
|
* id_data_len ID data length
|
|
*
|
|
*/
|
|
unsigned char*
|
|
make_id(size_t *length, unsigned next, unsigned idtype, unsigned char *id_data,
|
|
size_t id_data_len) {
|
|
unsigned char *payload;
|
|
struct isakmp_id* hdr;
|
|
|
|
payload = Malloc(sizeof(struct isakmp_id)+id_data_len);
|
|
hdr = (struct isakmp_id*) payload; /* Overlay ID struct on payload */
|
|
memset(hdr, mbz_value, sizeof(struct isakmp_id));
|
|
|
|
hdr->isaid_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)<len)?ntohs(sa_hdr->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)<len)?ntohs(sa_hdr->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 */
|
|
}
|