summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sbin/isakmpd/BUGS50
-rw-r--r--sbin/isakmpd/DESIGN-NOTES345
-rw-r--r--sbin/isakmpd/Makefile74
-rw-r--r--sbin/isakmpd/QUESTIONS33
-rw-r--r--sbin/isakmpd/README59
-rw-r--r--sbin/isakmpd/TO-DO78
-rw-r--r--sbin/isakmpd/app.c65
-rw-r--r--sbin/isakmpd/app.h45
-rw-r--r--sbin/isakmpd/asn.c1155
-rw-r--r--sbin/isakmpd/asn.h155
-rw-r--r--sbin/isakmpd/asn_useful.c128
-rw-r--r--sbin/isakmpd/asn_useful.h96
-rw-r--r--sbin/isakmpd/attribute.c112
-rw-r--r--sbin/isakmpd/attribute.h52
-rw-r--r--sbin/isakmpd/cert.c94
-rw-r--r--sbin/isakmpd/cert.h68
-rw-r--r--sbin/isakmpd/conf.c426
-rw-r--r--sbin/isakmpd/conf.h64
-rw-r--r--sbin/isakmpd/constants.c92
-rw-r--r--sbin/isakmpd/constants.h49
-rw-r--r--sbin/isakmpd/cookie.c127
-rw-r--r--sbin/isakmpd/cookie.h50
-rw-r--r--sbin/isakmpd/crypto.c355
-rw-r--r--sbin/isakmpd/crypto.h145
-rw-r--r--sbin/isakmpd/dh.c79
-rw-r--r--sbin/isakmpd/dh.h47
-rw-r--r--sbin/isakmpd/doi.c64
-rw-r--r--sbin/isakmpd/doi.h92
-rw-r--r--sbin/isakmpd/exchange.c936
-rw-r--r--sbin/isakmpd/exchange.h165
-rw-r--r--sbin/isakmpd/exchange_num.cst46
-rw-r--r--sbin/isakmpd/field.c258
-rw-r--r--sbin/isakmpd/field.h56
-rw-r--r--sbin/isakmpd/genconstants.sh115
-rw-r--r--sbin/isakmpd/genfields.sh187
-rw-r--r--sbin/isakmpd/gmp_util.c76
-rw-r--r--sbin/isakmpd/gmp_util.h43
-rw-r--r--sbin/isakmpd/hash.c135
-rw-r--r--sbin/isakmpd/hash.h74
-rw-r--r--sbin/isakmpd/if.c121
-rw-r--r--sbin/isakmpd/if.h47
-rw-r--r--sbin/isakmpd/ike_auth.c539
-rw-r--r--sbin/isakmpd/ike_auth.h52
-rw-r--r--sbin/isakmpd/ike_main_mode.c883
-rw-r--r--sbin/isakmpd/ike_main_mode.h44
-rw-r--r--sbin/isakmpd/ike_quick_mode.c1069
-rw-r--r--sbin/isakmpd/ike_quick_mode.h44
-rw-r--r--sbin/isakmpd/init.c69
-rw-r--r--sbin/isakmpd/init.h41
-rw-r--r--sbin/isakmpd/ipsec.c1067
-rw-r--r--sbin/isakmpd/ipsec.h123
-rw-r--r--sbin/isakmpd/ipsec_doi.h45
-rw-r--r--sbin/isakmpd/ipsec_fld.fld64
-rw-r--r--sbin/isakmpd/ipsec_num.cst225
-rw-r--r--sbin/isakmpd/isakmp.h60
-rw-r--r--sbin/isakmpd/isakmp_doi.c218
-rw-r--r--sbin/isakmpd/isakmp_doi.h41
-rw-r--r--sbin/isakmpd/isakmp_fld.fld148
-rw-r--r--sbin/isakmpd/isakmp_num.cst156
-rw-r--r--sbin/isakmpd/isakmpd.8116
-rw-r--r--sbin/isakmpd/isakmpd.c220
-rw-r--r--sbin/isakmpd/isakmpd.conf.5175
-rw-r--r--sbin/isakmpd/isakmpd.conf.sample111
-rw-r--r--sbin/isakmpd/isakmpd_cert.samplebin0 -> 518 bytes
-rw-r--r--sbin/isakmpd/isakmpd_key.pub.samplebin0 -> 140 bytes
-rw-r--r--sbin/isakmpd/isakmpd_key.samplebin0 -> 608 bytes
-rw-r--r--sbin/isakmpd/log.c240
-rw-r--r--sbin/isakmpd/log.h55
-rw-r--r--sbin/isakmpd/math_2n.c1045
-rw-r--r--sbin/isakmpd/math_2n.h133
-rw-r--r--sbin/isakmpd/math_ec2n.c314
-rw-r--r--sbin/isakmpd/math_ec2n.h89
-rw-r--r--sbin/isakmpd/math_group.c533
-rw-r--r--sbin/isakmpd/math_group.h96
-rw-r--r--sbin/isakmpd/message.c1765
-rw-r--r--sbin/isakmpd/message.h178
-rw-r--r--sbin/isakmpd/pf_encap.c654
-rw-r--r--sbin/isakmpd/pf_encap.h65
-rw-r--r--sbin/isakmpd/pkcs.h79
-rw-r--r--sbin/isakmpd/prf.c165
-rw-r--r--sbin/isakmpd/prf.h61
-rw-r--r--sbin/isakmpd/regress/Makefile38
-rw-r--r--sbin/isakmpd/regress/asn/Makefile14
-rw-r--r--sbin/isakmpd/regress/asn/asntest.c147
-rw-r--r--sbin/isakmpd/regress/asn/ssh-test-ca.pem12
-rw-r--r--sbin/isakmpd/regress/b2n/Makefile12
-rw-r--r--sbin/isakmpd/regress/b2n/b2ntest.c367
-rw-r--r--sbin/isakmpd/regress/check.sh92
-rw-r--r--sbin/isakmpd/regress/crypto/Makefile12
-rw-r--r--sbin/isakmpd/regress/crypto/cryptotest.c167
-rw-r--r--sbin/isakmpd/regress/dh/Makefile14
-rw-r--r--sbin/isakmpd/regress/dh/dhtest.c106
-rw-r--r--sbin/isakmpd/regress/ec2n/Makefile12
-rw-r--r--sbin/isakmpd/regress/ec2n/ec2ntest.c146
-rw-r--r--sbin/isakmpd/regress/exchange/Makefile58
-rw-r--r--sbin/isakmpd/regress/exchange/def-i.1bin0 -> 72 bytes
-rw-r--r--sbin/isakmpd/regress/exchange/def-r.1bin0 -> 72 bytes
-rw-r--r--sbin/isakmpd/regress/exchange/run.sh141
-rw-r--r--sbin/isakmpd/regress/group/Makefile14
-rw-r--r--sbin/isakmpd/regress/group/grouptest.c125
-rw-r--r--sbin/isakmpd/regress/hmac/Makefile10
-rw-r--r--sbin/isakmpd/regress/hmac/hmactest.c97
-rw-r--r--sbin/isakmpd/regress/pkcs/Makefile13
-rw-r--r--sbin/isakmpd/regress/pkcs/pkcstest.c124
-rw-r--r--sbin/isakmpd/regress/prf/Makefile10
-rw-r--r--sbin/isakmpd/regress/prf/prftest.c115
-rw-r--r--sbin/isakmpd/regress/rsakeygen/Makefile12
-rw-r--r--sbin/isakmpd/regress/rsakeygen/rsakeygen.c121
-rw-r--r--sbin/isakmpd/regress/x509/Makefile14
-rw-r--r--sbin/isakmpd/regress/x509/certificate.txt8
-rw-r--r--sbin/isakmpd/regress/x509/x509test.c165
-rw-r--r--sbin/isakmpd/sa.c456
-rw-r--r--sbin/isakmpd/sa.h162
-rw-r--r--sbin/isakmpd/sysdep-openbsd.c167
-rw-r--r--sbin/isakmpd/sysdep.h56
-rw-r--r--sbin/isakmpd/timer.c126
-rw-r--r--sbin/isakmpd/timer.h58
-rw-r--r--sbin/isakmpd/transport.c245
-rw-r--r--sbin/isakmpd/transport.h118
-rw-r--r--sbin/isakmpd/udp.c411
-rw-r--r--sbin/isakmpd/udp.h44
-rw-r--r--sbin/isakmpd/ui.c307
-rw-r--r--sbin/isakmpd/ui.h47
-rw-r--r--sbin/isakmpd/util.c152
-rw-r--r--sbin/isakmpd/util.h53
-rw-r--r--sbin/isakmpd/x509.c844
-rw-r--r--sbin/isakmpd/x509.h98
127 files changed, 22950 insertions, 0 deletions
diff --git a/sbin/isakmpd/BUGS b/sbin/isakmpd/BUGS
new file mode 100644
index 00000000000..2eabfe3c778
--- /dev/null
+++ b/sbin/isakmpd/BUGS
@@ -0,0 +1,50 @@
+$Id: BUGS,v 1.1 1998/11/15 00:03:47 niklas Exp $
+
+Until we have a bug-tracking system setup, we might just add bugs to this
+file:
+------------------------------------------------------------------------------
+* message_drop frees the message, this is sometimes wrong and can cause
+ duplicate frees, for example when a proposal does not get chosen. [fixed]
+
+* Notifications should be their own exchanges, otherwise the IV gets
+ disturbed. [fixed]
+
+* We need a death timeout on half-ready SAs just like exchanges. At the
+ moment we leak SAs.
+
+* When we establish a phase 2 exchange we seem to get the wrong IV set,
+ according to SSH's logs. [fixed]
+
+* If a phase 1 SA negotiation exists with a cause that is to be sent in
+ a NOTIFY to the peer, we get multiple free calls on the cleanup of the
+ informational exchange.
+
+* IKE mandates that a HASH should be added to informational exchanges in
+ phase 2.
+
+* Message_send requires an exchange to exist, and potentially it tries to
+ encrypt a message multiple times when retransmitting. [fixed]
+
+* Multiple protocol proposals seems to fail. [fixed]
+
+* The initiator fails to match the responders choice of protocol suite with
+ the correct one of its own when several are offered. [fixed]
+
+* Duplicate specified sections is not detected. [fixed]
+
+* Quick mode establishments via UI using -P bind-addr gets "Address already in
+ use".
+
+* Not chosen proposals should be deleted from the protos list in the sa
+ structure. [fixed]
+
+* Setting SPIs generates "Invalid argument" errors due to one tunnel endpoint
+ being INADDR_ANY. [fixed]
+
+* ipsec_proto structs are never allocated. [fixed]
+
+* Remove SPIs of unused proposals. [fixed]
+
+* If the first proposal is turned down, the initiator gets confused.
+
+* Renegotiation after a failed phase 1 fails.
diff --git a/sbin/isakmpd/DESIGN-NOTES b/sbin/isakmpd/DESIGN-NOTES
new file mode 100644
index 00000000000..da3abe9181e
--- /dev/null
+++ b/sbin/isakmpd/DESIGN-NOTES
@@ -0,0 +1,345 @@
+$Id: DESIGN-NOTES,v 1.1 1998/11/15 00:03:48 niklas Exp $
+
+General coding conventions
+--------------------------
+GNU indentation, Max 80 characters per line, KNF comments, mem* instead of b*,
+BSD copyright (GPL alternative?), one header per module specifying the API.
+Multiple inclusion protection like this:
+
+#ifndef _HEADERNAME_H_
+#define _HEADERNAME_H_
+
+... Here comes the bulk of the header ...
+
+#endif /* _HEADERNAME_H_ */
+
+Start all files with RCS ID tags, i.e.
+
+/* $Id: DESIGN-NOTES,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+GCC -Wall clean, ANSI prototypes. System dependent facilities should be
+named sysdep_* and be placed in sysdep.c. Primary target systems are OpenBSD
+and Linux, but porting to Microsoft Windows variants should not be made
+overly difficult.
+
+Note places which needs reconsiderations with comments starting with the
+string "XXX", e.g.
+
+/* XXX Not implemented yet. */
+
+TOC
+---
+app.c Application support.
+asn.c ASN.1 utilities.
+asn_useful.c ASN.1. useful structure defintions.
+cert.c Dispatching certificate related functions to the according
+ module based on the encoding.
+conf.c Interface to isakmpd configuration.
+constants.c Value to name map of constants..
+cookie.c Cookie generation.
+crypto.c Generic cryptography.
+dh.c Diffie-Hellman exchange logic.
+doi.c Generic handling of different DOIs.
+exchange.c Exchange state machinery.
+exchange_num.cst
+ Some constants used for exhange scripts.
+field.c Generic handling of fields.
+genconstants.sh
+ Generate constant files from .cst source.
+genfields.sh Generate field description files from .fld source.
+gmp_util.c Utilities to ease interfaceing to GMP.
+hash.c Generic hash handling.
+if.c Network interface details.
+ike_auth.c IKE authentication method abstraction.
+ike_main_mode.c IKE's main mode exchange logic.
+ike_quick_mode.c
+ IKE's quick mode logic.
+init.c Initialization of all modules (might be autogenned in the
+ future).
+ipsec.c The IPSec DOI.
+ipsec_fld.fld Description of IPSec DOI-specific packet layouts.
+ipsec_num.cst Constants defined by the IPSec DOI.
+isakmp_doi.c The ISAKMP pseudo-DOI.
+isakmp_fld.fld Generic packet layout.
+isakmp_num.cst ISAKMP constants.
+isakmpd.c Main loop.
+log.c Logging of exceptional or informational messages.
+math_2n.c Polynomial math.
+math_ec2n.c Elliptic curve math.
+math_group.c Group math.
+message.c Generic message handling.
+pf_encap.c Interface with PF_ENCAP sockets (for use with IPSEC).
+pkcs.c PKCS#1: RSA Encryption Standard.
+prf.c Pseudo random functions.
+sa.c Handling of Security Associations (SAs).
+sysdep-*.c System dependent definitions.
+timer.c Timed events.
+transport.c Generic transport handling.
+udp.c The UDP transport.
+ui.c The "User Interface", i.e. the FIFO command handler.
+util.c Miscellaneous utility functions.
+x509.c Encoding/Decoding X509 Certificates and related structures.
+
+Central datatypes
+-----------------
+
+struct constant_map A map from constants to their ASCII names.
+struct crypto_xf A crypto class
+struct doi The DOI function switch
+struct event An event that is to happen at some point in time.
+struct exchange A description of an exchange while it is performed.
+struct field A description of an ISAKMP field.
+struct group A class abstracting out Oakley group operations
+struct hash A hashing class
+struct ipsec_exch IPSec-specific exchange fields.
+struct ipsec_proto IPSec-specific protocol attributes.
+struct ipsec_sa IPSec-specific SA stuff.
+struct message A generic ISAKMP message.
+struct payload A "fat" payload reference pointing into message buffers
+struct prf A pseudo random function class
+struct proto Per-protocol attributes.
+struct post_send Post-send function chain node.
+struct sa A security association.
+struct transport An ISAKMP transport, i.e. a channel where ISAKMP
+ messages are passed (not necessarily connection-
+ oriented). This is an abstract class, serving as
+ a superclass to the different specific transports.
+
+SAs & exchanges
+---------------
+
+struct exchange Have all fields belonging to a simple exchange
+ + a list of all the SAs being negotiated.
+ Short-lived.
+struct sa Only hold SA-specific stuff. Lives longer.
+
+In order to recognize exchanges and SAs it is good to know what constitutes
+their identities:
+
+Phase 1 exchange Cookie pair (apart from the first message of course,
+ where the responder cookie is zero.
+
+ISAKMP SA Cookie pair. I.e. there exists a one-to-one
+ mapping to the negotiation in this case.
+
+Phase 2 exchange Cookie pair + message ID.
+
+Generic SA Cookie pair + message ID + SPI.
+
+However it would be really nice to have a name of any SA that is natural
+to use for human beings, for things like deleteing SAs manually. The simplest
+ID would be the struct sa address. Another idea would be some kind of sequence
+number, either global or per-destination.
+
+The basic idea of control flow
+------------------------------
+
+The main loop just waits for events of any kind. Supposedly a message
+comes in, then the daemon looks to see if the cookies describes an
+existing ISAKMP SA, if they don't and the rcookie is zero, it triggers a
+setup of a new ISAKMP SA. An exhaustive validation phase of the message
+is gone through at this stage. If anything goes wrong, we drop the packet
+and probably send some notification back. After the SA is found we try to
+locate the exchange object and advance its state, else we try to create a
+new exchange.
+
+Need exchanges be an abstraction visible in the code? If so an exchange is
+roughly a very simple FSM (only timeouts and retransmissions are events that
+does not just advance the state through a sequential single path). The
+informational exchange is such a special case, I am not sure it's interesting
+to treat as an exchange in the logic of the implementation. The only reason
+to do so would be to keep the implementation tightly coupled to the
+specification for ease of understanding.
+
+When the exchange has been found the exchange engine "runs" a script which
+steps forward for each incoming message.
+
+Payload parsing details
+-----------------------
+
+After the generic header has been validated, we do a generic payload
+parsing pass over the message and sort out the payloads into buckets indexed
+by the payload type. Note that proposals and transforms are part of the SA
+payloads. We then pass over them once more validating each payload
+in numeric payload type order. This makes SA payloads come naturally first.
+
+Messages
+--------
+
+I am not sure there is any use in sharing the message structure for both
+incoming and outgoing messages but I do it anyhow. Specifically there are
+certain fields which only makes sense in one direction. Incoming messages
+only use one segment in the iovec vector, while outgoing has one segment per
+payload as well as one for the ISAKMP header. The iovec vector is
+reallocated for each payload added, maybe we should do it in chunks of a
+number of payloads instead, like 10 or so.
+
+Design "errors"
+---------------
+
+Currently there are two "errors" in our design. The first one is that the
+coupling between the IPSEC DOI and IKE is tight. It should be separated by
+a clean interface letting other key exchange models fit in instead of IKE.
+The second problem is that we need a protocol-specific opaque SA part
+in the DOI specific one. Now both IPSEC ESP attributes takes place even
+in ISAKMP SA structures.
+
+User control
+------------
+
+In order to control the daemon you send commands through a FIFO called
+isakmpd.fifo. The commands are one-letter codes followed by arguments.
+For now, only three commands are planned:
+
+c connect Establish an ISAKMP SA with a peer
+d debug Toggle some debug flag
+r report Report status information of the daemon
+
+For example you can do:
+
+c udp 127.0.0.1:555 2 1
+
+to get an ISAKMP SA established with the ISAKMP implementation listening
+on UDP port 555 at the local host. The SA will be established with an
+identity protection (exchange type 2) exchange and use the IPSEC DOI (DOI 1).
+
+In order to delete an SA you use the 'd' command. However this is not yet
+supported.
+
+To alter the level of debugging in the "LOG_MISC" logging class to 99 you do:
+
+D 0 99
+
+The report command is just an "r", and results in a list of active exchanges
+and security associations.
+
+The constant descriptions
+-------------------------
+
+We have invented a simple constant description language, for the sake
+of easily getting textual representations of manifest constants.
+The syntax is best described by an example:
+
+GROUP
+ CONSTANT_A 1
+ CONSTANT_B 2
+.
+
+This defines a constant map "group" with the following two defines:
+
+#define GROUP_CONSTANT_A 1
+#define GROUP_CONSTANT_B 2
+
+We can now get the textual representation by:
+
+ cp = constant_name (group, foo);
+
+Here foo is an integer with either of the two constants as a value.
+
+The field descriptions
+----------------------
+
+There is language for describing header and payload layouts too,
+similar to the constant descriptions. Here too I just show an example:
+
+RECORD_A
+ FIELD_A raw 4
+ FIELD_B num 2
+ FIELD_C mask 1 group_c_cst
+ FIELD_D ign 1
+ FIELD_E cst 2 group_e1_cst,group_e2_cst
+.
+
+RECORD_B : RECORD_A
+ FIELD_F raw
+.
+
+This creates some utility constants like RECORD_A_SZ, RECORD_A_FIELD_A_LEN,
+RECORD_A_FIELD_A_OFF, RECORD_A_FIELD_B_LEN etc. The *_OFF contains the
+octet offset into the record and the *_LEN constants are the lenghts.
+The type fields can be: raw, num, mask, ign & cst. Raw are used for
+octet buffers, num for (unsigned) numbers of 1, 2 or 4 octet's length
+in network byteorder, mask is a bitmask where the bit values have symbols
+coupled to them via the constant maps given after the length in octets
+(also 1, 2 or 4). Ign is just a filler type, ot padding and lastly cst
+denotes constants whose values can be found in the given constant map(s).
+The last field in a record can be a raw, without a length, then just an
+_OFF symbol will be generated. You can offset the first symbol to the
+size of another record, like is done above for RECORD_B, i.e. in that
+case RECORD_A_SZ == RECORD_B_FIELD_F_OFF. All this data are collected
+in struct field arrays which makes it possible to symbolically print out
+entire payloads in readable form via field_dump_payload.
+
+Identification
+--------------
+
+ISAKMP supports a lot of identity types, and we should too of course.
+
+* Main mode
+
+Today when we connect we do it based on the peer's IP address. That does not
+automatically mean we should do policy decision based on IPs, rather we should
+look at the ID the peer provide and get policy info keyed on that.
+
+Perhaps we get an ID saying the peer is FQDN niklas.hallqvist.se, then our
+policy rules might look like:
+
+[IQ_FQDN]
+# If commented, internal verification is used
+#Verificator= verify_fqdn
+Accept= no
+
+[ID_FQDN niklas.hallqvist.se]
+Policy= MY_POLICY_001
+
+[MY_POLICY_001]
+# Whatever policy rules we might have.
+Accept= yes
+
+Which means niklas.hallqvist.se is allowed to negotiate SAs with us, but
+noone else.
+
+* Quick mode
+
+In quick mode the identities are implicitly the IP addresses of the peers,
+which must mean the IP addresses actually used for the ISAKMP tunnel.
+
+License to use
+--------------
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+Maybe we should skip clause 3? Or redo it to mention the development was not
+"by" but rather "funded by"? I think the comment about funding after the
+license might also mention the actual author(s). Possibly the GPL should
+be added as a 2ary distribution license to use if wanted?
diff --git a/sbin/isakmpd/Makefile b/sbin/isakmpd/Makefile
new file mode 100644
index 00000000000..9ab6b18e279
--- /dev/null
+++ b/sbin/isakmpd/Makefile
@@ -0,0 +1,74 @@
+# $Id: Makefile,v 1.1 1998/11/15 00:03:48 niklas Exp $
+
+#
+# Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Ericsson Radio Systems.
+# 4. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# This code was written under funding by Ericsson Radio Systems.
+#
+
+PROG= isakmpd
+SRCS= app.c asn.c asn_useful.c attribute.c cert.c constants.c \
+ conf.c cookie.c crypto.c dh.c doi.c exchange.c exchange_num.c \
+ field.c gmp_util.c hash.c if.c ike_auth.c ike_main_mode.c \
+ ike_quick_mode.c init.c ipsec.c ipsec_fld.c ipsec_num.c \
+ isakmpd.c isakmp_doi.c isakmp_fld.c isakmp_num.c log.c \
+ message.c math_2n.c math_ec2n.c math_group.c pf_encap.c \
+ pkcs.c prf.c sa.c sysdep.c timer.c transport.c udp.c ui.c \
+ util.c x509.c
+CLEANFILES= exchange_num.c exchange_num.h ipsec_num.c ipsec_num.h \
+ isakmp_num.c isakmp_num.h ipsec_fld.c ipsec_fld.h \
+ isakmp_fld.c isakmp_fld.h
+MAN= isakmpd.8 isakmpd.conf.5
+LDADD= -lgmp -ldes
+DPADD= ${LIBGMP} ${LIBDES}
+CFLAGS+= -Wall -I. -I${.CURDIR} -DNEED_SYSDEP_APP
+DEBUG= -g
+
+SUBDIR= regress
+
+exchange_num.c exchange_num.h: genconstants.sh exchange_num.cst
+ /bin/sh ${.CURDIR}/genconstants.sh ${.CURDIR}/exchange_num
+
+ipsec_fld.c ipsec_fld.h: genfields.sh ipsec_fld.fld
+ /bin/sh ${.CURDIR}/genfields.sh ${.CURDIR}/ipsec_fld
+
+ipsec_num.c ipsec_num.h: genconstants.sh ipsec_num.cst
+ /bin/sh ${.CURDIR}/genconstants.sh ${.CURDIR}/ipsec_num
+
+isakmp_fld.c isakmp_fld.h: genfields.sh isakmp_fld.fld
+ /bin/sh ${.CURDIR}/genfields.sh ${.CURDIR}/isakmp_fld
+
+isakmp_num.c isakmp_num.h: genconstants.sh isakmp_num.cst
+ /bin/sh ${.CURDIR}/genconstants.sh ${.CURDIR}/isakmp_num
+
+beforedepend: ipsec_fld.h ipsec_num.h isakmp_fld.h isakmp_num.h
+
+.include <bsd.prog.mk>
+.include <bsd.subdir.mk>
diff --git a/sbin/isakmpd/QUESTIONS b/sbin/isakmpd/QUESTIONS
new file mode 100644
index 00000000000..2ac283565d2
--- /dev/null
+++ b/sbin/isakmpd/QUESTIONS
@@ -0,0 +1,33 @@
+$Id: QUESTIONS,v 1.1 1998/11/15 00:03:48 niklas Exp $
+
+Does the spec limit the count of SA payloads in a message? Where if so?
+[ Only the specific IKE main mode does. In the IKE spec.]
+
+The message ID field of the header, can it be considered a SA identifier
+if used together with the cookiepair? [Yes, it is meant to be that]
+
+DOI 0, what protocols are defined for it? Where?
+
+Isn't this a potential DOS attack:
+Hostile user listens for ISAKMP traffic, and then extracts cookiepairs
+and message IDs which he uses to flood any of the peers with spoofed
+packets pretending to be the other one. Most probably these packets will
+result in error notifications which potentially result in SA tear-down?
+Maybe should notifications never be issued for erroneous packets which
+cannot be authenticated? Or should we not tear down SAs as results of
+notifications?
+
+Certicom claims to hold licenses for Elliptic Curve Cryptography? Does this
+concern us? See: http://grouper.ieee.org/groups/p1363/patents.html
+
+Main mode when using public key encryption authentication does not look
+like an identity protection exchange to me. Must I really get rid of
+the generic ISAKMP payload presense tests?
+
+IV generation is not described precisely in Appendix B of -oakley-08.txt:
+'Subsequent messages MUST use the last CBC encryption block from the previous
+message as their IV'. This probably means that we take the new IV from the
+last encrypted block of the last message we sent. The SSH testing site uses
+the last block from the last message they received. This is probably not
+what was meant and should be clarified on ipsec@tis.com.
+[ From what we have gathered this is what is meant. ]
diff --git a/sbin/isakmpd/README b/sbin/isakmpd/README
new file mode 100644
index 00000000000..94ecc7602c9
--- /dev/null
+++ b/sbin/isakmpd/README
@@ -0,0 +1,59 @@
+$Id: README,v 1.1 1998/11/15 00:03:48 niklas Exp $
+
+This is isakmpd, a BSD-licensed ISAKMP/Oakley (a.k.a. IKE)
+implementation. It's written by Niklas Hallqvist and Niels Provos,
+funded by Ericsson Radio Systems AB. Currently it is just work in
+progress, it cannot be used for anything real. For example it does not
+renegotiate SAs when an application says they have expired. It is not
+released, thus I won't bother calling it any version numbers. When you
+got the source, hopefully the archive was named with a date which
+reflects when it was created. These archives are also known as snapshots
+and will be created at irregular intervals and put up on ftp.gsnig.net
+and ftp.appli.se in /pub/isakmpd.
+
+Isakmpd is being developed under OpenBSD, with OpenBSD as its primary
+target, soon enough however, a Linux effort will be started. Until
+then the makefile support assumes a BSD environment.
+
+Assuming you have an OpenBSD /usr/share/mk and use the OpenBSD (or
+similar) make(1), you build isakmpd this way:
+
+ln -s sysdep-openbsd.c sysdep.c
+make obj && make depend && make
+
+Then obj/isakmpd will be the daemon. I suggest you try it by running
+under gdb with args similar to:
+ -d -n -p5000 -D0=99 -D1=99 -D2=99 -D3=99 -D4=99 -D5=99 \
+ -f/tmp/isakmpd.fifo -cisakmpd.conf.sample
+
+That will run isakmpd in the foreground, not connected to any application
+(like an IPSEC implementation) logging to stderr with full debugging ouput,
+listening on UDP port 5000, accepting control commands via the named pipe
+called /tmp/isakmpd.fifo and reading its configuration from the
+isakmpd.conf.sample file (found in the isakmpd directory).
+
+If you are root you can try to run without -n -p5000 thus getting it to
+talk to your IPSec stack and use the standard port 500 instead.
+
+Read log.[ch] and ui.c to see how to alter the debugging levels.
+Now you have setup your daemon and can watch incoming negotiations.
+But how do you get such? Either use http://isakmp-test.ssh.fi/,
+there's an excellent service, just waiting for you. Or you can try to
+start another isakmpd on another port (say -p5001 or so, instead)
+and another fifo (let's say /tmp/other.fifo), then issue this command:
+
+$ echo "c udp 127.0.0.1:5000 2 1" >/tmp/other.fifo
+
+and watch. You can turn on debugging on that isakmpd too of course, for
+greater fun. When the ISAKMP SA is setup you can try quick mode too:
+
+$ echo "c udp 127.0.0.1:5000 32 1" >/tmp/other.fifo
+
+You will by now have noticed that this implementation is incomplete, but
+who cares? You are here because you want to read code, start porting work
+or help us out fixing what need's to be fixed.
+
+Happy IKEing!
+
+Niklas Hallqvist <niklas@openbsd.org>
+Niels Provos <provos@openbsd.org>
diff --git a/sbin/isakmpd/TO-DO b/sbin/isakmpd/TO-DO
new file mode 100644
index 00000000000..35b9354072b
--- /dev/null
+++ b/sbin/isakmpd/TO-DO
@@ -0,0 +1,78 @@
+$Id: TO-DO,v 1.1 1998/11/15 00:03:48 niklas Exp $
+
+This file is pretty lame as it should really contain a lot more given that
+the program is far from ready in any area.
+
+* Add debugging messages, maybe possible to control asynchronously. [done]
+
+* Implement the local policy governing logging and notification of exceptional
+ conditions.
+
+* A field description mechanism used for things like making packet dumps
+ readable etc. Both Photurisd and Pluto does this. [done]
+
+* Fix the cookies. <Niels> [done]
+
+* Garbage collect transports (ref-counting?).
+
+* Retransmission/dup packet handling. [done]
+
+* Generic payload checks. [mostly done]
+
+* For math, speed up multiplication and division functions.
+
+* Cleanup of SAs when dropping messages. [done]
+
+* Look over message resource tracking.
+
+* Retransmission timing & count adaptivity and configurability.
+ [configurability done]
+
+* Quick mode exchanges [done]
+
+* Aggressive mode exchange. <Niels>
+
+* Finish main mode exchange [done]
+
+* Separation of key exchange from the IPSEC DOI, i.e. factor out IKE details.
+
+* Setup the IPSEC situation field in the main mode. [done]
+
+* Kernel interface for IPSEC parameter passing.
+
+* Notify of unsupported situations.
+
+* Set/get field macros generated from the field descriptions. [done]
+
+* SIGHUP handler with reparsing of config file. [done]
+
+* RSA signature authentication <Niels> [done]
+
+* DSS signature authentication
+
+* RSA encryption authentication
+
+* New group mode
+
+* DELETE payload handling, and generation from ui.
+
+* Deal well with incoming informational exchanges.
+
+* Generate all possible SA attributes in quick mode. [done]
+
+* Validate incoming attribute according to policy, main mode.
+
+* Validate incoming attribute according to policy, quick mode.
+
+* Cleanup reserved SPIs on cleanup of associated SAs. [done]
+
+* Validate attribute types (i.e. that what the specs tells should be
+ basic).
+
+* Cleanup reserved SPIs in proposals never chosen. [done]
+
+* Add time measuring and reporting to the exchange code for catching of
+ bottlenecks.
+
+* Rescan interfaces on SIGHUP and on reception of messages on the INADDR_ANY
+ listener socket.
diff --git a/sbin/isakmpd/app.c b/sbin/isakmpd/app.c
new file mode 100644
index 00000000000..c3eddb9b4eb
--- /dev/null
+++ b/sbin/isakmpd/app.c
@@ -0,0 +1,65 @@
+/* $Id: app.c,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+/*
+ * XXX This is just a wrapper module for now. Later we might handle many
+ * applications simultaneously but right now, we assume one system-dependent
+ * one only.
+ */
+
+#include "app.h"
+#include "log.h"
+#include "sysdep.h"
+
+int app_socket;
+
+/* Set this to not get any applications setup. */
+int app_none = 0;
+
+void
+app_init ()
+{
+ if (app_none)
+ return;
+ app_socket = sysdep_app_open ();
+ if (app_socket == -1)
+ log_fatal ("app_init: cannot open connection to application");
+}
+
+void
+app_handler ()
+{
+ sysdep_app_handler (app_socket);
+}
diff --git a/sbin/isakmpd/app.h b/sbin/isakmpd/app.h
new file mode 100644
index 00000000000..c9d724c0366
--- /dev/null
+++ b/sbin/isakmpd/app.h
@@ -0,0 +1,45 @@
+/* $Id: app.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _APP_H_
+#define _APP_H_
+
+extern int app_socket;
+extern int app_none;
+
+extern void app_handler (void);
+extern void app_init (void);
+
+#endif /* _APP_H_ */
diff --git a/sbin/isakmpd/asn.c b/sbin/isakmpd/asn.c
new file mode 100644
index 00000000000..11e45882680
--- /dev/null
+++ b/sbin/isakmpd/asn.c
@@ -0,0 +1,1155 @@
+/* $Id: asn.c,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gmp.h>
+#include <unistd.h>
+
+#include "log.h"
+#include "asn.h"
+#include "gmp_util.h"
+
+struct asn_handler table[] = {
+ {TAG_INTEGER, asn_free_integer,
+ asn_get_encoded_len_integer, asn_decode_integer, asn_encode_integer},
+ {TAG_OBJECTID, asn_free_objectid,
+ asn_get_encoded_len_objectid, asn_decode_objectid, asn_encode_objectid},
+ {TAG_SEQUENCE, asn_free_sequence,
+ asn_get_encoded_len_sequence, asn_decode_sequence, asn_encode_sequence},
+ {TAG_SET, asn_free_sequence,
+ asn_get_encoded_len_sequence, asn_decode_sequence, asn_encode_sequence},
+ {TAG_UTCTIME, asn_free_string,
+ asn_get_encoded_len_string, asn_decode_string, asn_encode_string},
+ {TAG_BITSTRING, asn_free_string,
+ asn_get_encoded_len_string, asn_decode_string, asn_encode_string},
+ {TAG_OCTETSTRING, asn_free_string,
+ asn_get_encoded_len_string, asn_decode_string, asn_encode_string},
+ {TAG_BOOL, asn_free_string,
+ asn_get_encoded_len_string, asn_decode_string, asn_encode_string},
+ {TAG_PRINTSTRING, asn_free_string,
+ asn_get_encoded_len_string, asn_decode_string, asn_encode_string},
+ {TAG_RAW, asn_free_raw,
+ asn_get_encoded_len_raw, asn_decode_raw, asn_encode_raw},
+ {TAG_NULL, asn_free_null,
+ asn_get_encoded_len_null, asn_decode_null, asn_encode_null},
+ {TAG_ANY, asn_free_null,
+ NULL, asn_decode_any, NULL},
+ {TAG_STOP, NULL, NULL, NULL, NULL}
+};
+
+int
+asn_get_from_file (char *name, u_int8_t **asn, u_int32_t *asnlen)
+{
+ int fd, res = 0;
+ struct stat st;
+
+ if (stat (name, &st) == -1)
+ {
+ log_error ("asn_get_from_file: failed to state %s", name);
+ return 0;
+ }
+
+ *asnlen = st.st_size;
+
+ if ((fd = open (name, O_RDONLY)) == -1)
+ {
+ log_error ("asn_get_from_file: failed to open %s", name);
+ return 0;
+ }
+
+ if ((*asn = malloc (st.st_size)) == NULL)
+ {
+ log_print ("asn_get_from_file: out of memory");
+ res = 0;
+ goto done;
+ }
+
+ if (read (fd, *asn, st.st_size) != st.st_size ||
+ asn_get_len (*asn) != *asnlen)
+ {
+ log_print ("x509_asn_obtain: asn file ended early");
+ free (*asn);
+ res = 0;
+ goto done;
+ }
+
+ res = 1;
+
+ done:
+ close (fd);
+
+ return res;
+}
+
+struct norm_type *
+asn_template_clone (struct norm_type *obj, int constructed)
+{
+ struct norm_type *p;
+ u_int32_t i;
+
+ if (!constructed)
+ {
+ p = malloc (sizeof (struct norm_type));
+ if (p == NULL)
+ return NULL;
+
+ memcpy (p, obj, sizeof (struct norm_type));
+
+ obj = p;
+ }
+
+ if (obj->type != TAG_SEQUENCE && obj->type != TAG_SET)
+ {
+ obj->len = 0;
+ obj->data = NULL;
+ }
+ else if (obj->type == TAG_SEQUENCE || obj->type == TAG_SET)
+ {
+ p = obj;
+ obj = obj->data;
+ i = 0;
+ while (obj[i++].type != TAG_STOP);
+
+ p->data = malloc (i * sizeof (struct norm_type));
+ if (p->data == NULL)
+ return NULL;
+
+ memcpy (p->data, obj, i * sizeof (struct norm_type));
+ obj = p->data;
+
+ i = 0;
+ while (obj[i].type != TAG_STOP)
+ {
+ obj[i].len = 0;
+ if (asn_template_clone (&obj[i], 1) == NULL)
+ return NULL;
+
+ i++;
+ }
+ }
+
+ return obj;
+}
+
+/* Associates a human readable name to an OBJECT IDENTIFIER */
+
+char *
+asn_parse_objectid (struct asn_objectid *table, char *id)
+{
+ u_int32_t len = 0;
+ char *p = NULL;
+ static char buf[LINE_MAX];
+
+ if (id == NULL)
+ return NULL;
+
+ while (table->name != NULL)
+ {
+ if (!strcmp (table->objectid, id))
+ return table->name;
+ if (!strncmp (table->objectid, id, strlen (table->objectid)) &&
+ strlen (table->objectid) > len)
+ {
+ len = strlen (table->objectid);
+ p = table->name;
+ }
+
+ table++;
+ }
+
+ if (len == 0)
+ return NULL;
+
+ strncpy (buf, p, sizeof (buf) - 1);
+ buf[sizeof (buf) - 1] = 0;
+ strncat (buf + strlen (buf), id + len, sizeof (buf) -1 - strlen (buf));
+ buf[sizeof (buf) - 1] = 0;
+
+ return buf;
+}
+
+/* Retrieves the pointer to a data type referenced by the path name */
+
+struct norm_type *
+asn_decompose (char *path, struct norm_type *obj)
+{
+ char *p, *p2, *tmp;
+ int counter;
+
+ if (!strcasecmp (path, obj->name))
+ return obj->data;
+
+ p = path = strdup (path);
+ p2 = strsep (&p, ".");
+
+ if (strcasecmp (p2, obj->name) || p == NULL)
+ goto fail;
+
+ while (p != NULL)
+ {
+ obj = obj->data;
+ if (obj == NULL)
+ break;
+
+ p2 = strsep (&p, ".");
+
+ /*
+ * For SEQUENCE OF or SET OF, we want to be able to say
+ * AttributeValueAssertion[1] for the 2nd value.
+ */
+ tmp = strchr (p2, '[');
+ if (tmp != NULL)
+ {
+ counter = atoi (tmp+1);
+ *tmp = 0;
+ }
+ else
+ counter = 0;
+
+ /* Find the Tag */
+ while (obj->type != TAG_STOP)
+ {
+ if (!strcasecmp (p2, obj->name) && counter-- == 0)
+ break;
+ obj++;
+ }
+
+ if (obj->type == TAG_STOP)
+ goto fail;
+
+ if (p == NULL)
+ goto done;
+
+ if (obj->type != TAG_SEQUENCE && obj->type != TAG_SET)
+ goto fail;
+ }
+
+ done:
+ free (path);
+ return obj;
+
+ fail:
+ free (path);
+ return NULL;
+}
+
+/* Gets an entry from the ASN.1 tag switch table */
+
+struct asn_handler *
+asn_get (enum asn_tags type)
+{
+ struct asn_handler *h = table;
+
+ while (h->type != TAG_STOP)
+ if (h->type == type)
+ return h;
+ else
+ h++;
+
+ return NULL;
+}
+
+/*
+ * For the long form of BER encoding we need to know in how many
+ * octets the length can be encoded.
+ */
+
+u_int32_t
+asn_sizeinoctets (u_int32_t len)
+{
+ u_int32_t log = 0;
+
+ while (len)
+ {
+ log++;
+ len >>= 8;
+ }
+
+ return log;
+}
+
+u_int8_t *
+asn_format_header (struct norm_type *obj, u_int8_t *asn, u_int8_t **data)
+{
+ u_int8_t *buf = NULL, type;
+ u_int16_t len_off, len;
+ struct asn_handler *h;
+
+ h = asn_get (obj->type);
+ if (h == NULL)
+ return NULL;
+
+ if (asn != NULL)
+ buf = asn;
+
+ /* We only do low tag at the moment */
+ len_off = 1;
+
+ len = h->get_encoded_len (obj, &type);
+
+ if (buf == NULL && (buf = malloc (len)) == NULL)
+ return NULL;
+
+ if (type != ASN_LONG_FORM)
+ {
+ len -= len_off + 1;
+ buf[len_off] = len;
+
+ *data = buf + len_off + 1;
+ }
+ else
+ {
+ u_int16_t tmp;
+ int octets = asn_sizeinoctets (len);
+
+ len -= len_off + 1 + octets;
+ *data = buf + len_off + 1 + octets;
+
+ buf[len_off] = octets | ASN_LONG_FORM;
+
+ tmp = len;
+ while (--octets >= 0)
+ {
+ buf[len_off + 1 + octets] = tmp;
+ tmp >>= 8;
+ }
+ }
+
+ if (ISEXPLICIT(obj))
+ {
+ u_int8_t *erg;
+ /* Explicit tagging add an outer layer */
+ struct norm_type tmp = {obj->type, obj->class&0x3, NULL, 0, obj->data};
+
+ /* XXX - force the class to be CONTEXT */
+ buf[0] = GET_EXP(obj) | (((enum asn_classes)CONTEXT & 0x3) << 6) |
+ ASN_CONSTRUCTED;
+ erg = asn_format_header (&tmp, *data, data);
+
+ if (erg && (obj->type == TAG_SEQUENCE || obj->type == TAG_SET))
+ erg[0] |= ASN_CONSTRUCTED;
+ }
+ else
+ /* XXX low tag only */
+ buf[0] = obj->type | (obj->class << 6);
+
+ return buf;
+}
+
+u_int32_t
+asn_get_encoded_len (struct norm_type *obj, u_int32_t len, u_int8_t *type)
+{
+ u_int32_t len_off = 1;
+
+ if (len <= 127)
+ {
+ /* Short form */
+ len = len + 1 + len_off;
+ if (type != NULL)
+ *type = 0;
+ }
+ else
+ {
+ /* Long Form */
+ len = len + asn_sizeinoctets (len) + 1 + len_off;
+ if (type != NULL)
+ *type = ASN_LONG_FORM;
+ }
+
+ if (obj != NULL && ISEXPLICIT(obj))
+ len = asn_get_encoded_len (NULL, len, NULL);
+
+ return len;
+}
+
+/* Tries to decode an ANY tag, if we cant handle it we just raw encode it */
+
+u_int8_t *
+asn_decode_any (u_int8_t *asn, u_int32_t asnlen, struct norm_type *obj)
+{
+ struct asn_handler *h;
+ enum asn_tags type;
+
+ type = TAG_TYPE (asn);
+ if (type == TAG_SEQUENCE || type == TAG_SET)
+ type = TAG_RAW;
+
+ h = asn_get (type);
+ if (h == NULL)
+ {
+ type = TAG_RAW;
+ h = asn_get (type);
+ }
+
+ obj->type = type;
+ return h->decode (asn, asnlen, obj);
+}
+
+u_int32_t
+asn_get_encoded_len_integer (struct norm_type *obj, u_int8_t *type)
+{
+ u_int16_t len_off;
+ u_int32_t len = obj->len;
+ u_int32_t tmp;
+ mpz_t a;
+
+ /* XXX - We only do low tag at the moment */
+ len_off = 1;
+
+ obj->len = len = mpz_sizeinoctets ((mpz_ptr) obj->data);
+ mpz_init_set (a, (mpz_ptr) obj->data);
+
+ if (len > 1)
+ mpz_fdiv_q_2exp (a, a, (len - 1) << 3);
+
+ tmp = mpz_fdiv_r_ui (a, a, 256);
+ mpz_clear (a);
+
+ /*
+ * We only need to encode positive integers, ASN.1 defines
+ * negative integers to have the msb set, so if data[0] has
+ * msb set we need to introduce a zero octet.
+ */
+ if (tmp & 0x80)
+ len++;
+
+ return asn_get_encoded_len (obj, len, type);
+}
+
+/*
+ * Encode an integer value.
+ * Input = obj, output = asn or return value.
+ */
+
+u_int8_t *
+asn_encode_integer (struct norm_type *obj, u_int8_t *asn)
+{
+ u_int8_t *buf, *data;
+ u_int32_t len;
+
+ buf = asn_format_header (obj, asn, &data);
+
+ if (buf == NULL)
+ return NULL;
+
+ len = mpz_sizeinoctets ((mpz_ptr) obj->data);
+ mpz_getraw (data, (mpz_ptr) obj->data, len);
+
+ /* XXX - We only deal with unsigned integers at the moment */
+ if (data[0] & 0x80)
+ {
+ memmove (data + 1, data, len);
+ data[0] = 0;
+ }
+
+ return buf;
+}
+
+u_int8_t *
+asn_decode_integer (u_int8_t *asn, u_int32_t asnlen, struct norm_type *obj)
+{
+ u_int8_t *data;
+ u_int32_t len;
+
+ if (asnlen < asn_get_len (asn))
+ {
+ log_print ("asn_decode_integer: ASN.1 content is bigger than buffer");
+ return NULL;
+ }
+
+ len = asn_get_data_len (obj, &asn, &data);
+
+ if (TAG_TYPE(asn) != TAG_INTEGER)
+ {
+ log_print ("asn_decode_integer: expected tag type INTEGER, got %d",
+ TAG_TYPE(asn));
+ return NULL;
+ }
+
+ obj->data = malloc (sizeof (mpz_ptr));
+ if (obj->data == NULL)
+ {
+ log_print ("asn_decode_integer: out of memory.");
+ return NULL;
+ }
+
+ mpz_init ((mpz_ptr) obj->data);
+ mpz_setraw ((mpz_ptr) obj->data, data, len);
+
+ obj->len = len;
+
+ return data + len;
+}
+
+void
+asn_free_integer (struct norm_type *obj)
+{
+ if (obj->data != NULL)
+ {
+ mpz_clear ((mpz_ptr) obj->data);
+ free (obj->data);
+ }
+}
+
+
+u_int32_t
+asn_get_encoded_len_string (struct norm_type *obj, u_int8_t *type)
+{
+ return asn_get_encoded_len (obj, obj->len, type);
+}
+
+/*
+ * Encode a String
+ * Input = obj, output = asn or return value.
+ */
+
+u_int8_t *
+asn_encode_string (struct norm_type *obj, u_int8_t *asn)
+{
+ u_int8_t *buf, *data;
+
+ buf = asn_format_header (obj, asn, &data);
+
+ if (buf == NULL)
+ return NULL;
+
+ memcpy (data, obj->data, obj->len);
+
+ return buf;
+}
+
+u_int8_t *
+asn_decode_string (u_int8_t *asn, u_int32_t asnlen, struct norm_type *obj)
+{
+ u_int8_t *data;
+ u_int32_t len;
+
+ obj->len = len = asn_get_data_len (obj, &asn, &data);
+
+ if (TAG_TYPE(asn) != obj->type)
+ {
+ log_print ("asn_decode_string: expected tag type STRING(%d), got %d",
+ obj->type, TAG_TYPE(asn));
+ return NULL;
+ }
+
+ if (asnlen < asn_get_len (asn))
+ {
+ log_print ("asn_decode_string: ASN.1 content is bigger than buffer");
+ return NULL;
+ }
+
+ obj->data = malloc (obj->len + 1);
+ if (obj->data == NULL)
+ return NULL;
+ memcpy ((char *)obj->data, data, obj->len);
+ /*
+ * Encode a terminating '0', this is irrelevant for OCTET strings
+ * but nice for printable strings which do not include the terminating
+ * zero.
+ */
+ ((char *)obj->data)[obj->len] = 0;
+
+ return data + len;
+}
+
+void
+asn_free_string (struct norm_type *obj)
+{
+ if (obj->data != NULL)
+ free (obj->data);
+}
+
+
+u_int32_t
+asn_get_encoded_len_objectid (struct norm_type *obj, u_int8_t *type)
+{
+ u_int16_t len_off;
+ u_int32_t len;
+ u_int32_t tmp;
+ char *buf, *buf2;
+
+ /* XXX - We only do low tag at the moment */
+ len_off = 1;
+
+ /* The first two numbers are encoded together */
+ buf = obj->data;
+ tmp = strtol (buf, &buf2, 10);
+ buf = buf2;
+ tmp = strtol (buf, &buf2, 10);
+ buf = buf2;
+
+ len = 1;
+ while (*buf)
+ {
+ tmp = strtol (buf, &buf2, 10);
+ if (buf == buf2)
+ break;
+
+ buf = buf2;
+ do {
+ tmp >>= 7;
+ len++;
+ } while (tmp);
+ }
+
+ /* The first two ids are encoded as one octet */
+ obj->len = len - 1;
+
+ return asn_get_encoded_len (obj, len, type);
+}
+
+/*
+ * Encode an Object Identifier
+ * Input = obj, output = asn or return value.
+ */
+
+u_int8_t *
+asn_encode_objectid (struct norm_type *obj, u_int8_t *asn)
+{
+ u_int8_t *buf, *data;
+ char *enc, *enc2;
+ u_int32_t tmp, tmp2;
+ int flag = 0;
+
+ buf = asn_format_header (obj, asn, &data);
+
+ if (buf == NULL)
+ return NULL;
+
+ enc = obj->data;
+ while (*enc)
+ {
+ /* First two ids are encoded as one octet */
+ if (flag == 0)
+ {
+ tmp = strtol (enc, &enc2, 10);
+ if (enc == enc2)
+ return NULL;
+ enc = enc2;
+ tmp2 = strtol (enc, &enc2, 10) + 40 * tmp;
+ flag = 1;
+ }
+ else
+ tmp2 = strtol (enc, &enc2, 10);
+
+ if (enc == enc2)
+ break;
+
+ /* Reverse the digits to base-128 */
+ tmp = 0;
+ do {
+ tmp <<= 7;
+ tmp += tmp2 & 0x7f;
+ tmp2 >>= 7;
+ } while (tmp2);
+
+ enc = enc2;
+ do {
+ /* If the next octet still belongs to the data set msb */
+ *data++ = (tmp & 0x7f) | ( tmp > 127 ? 0x80 : 0);
+ tmp >>= 7;
+ } while (tmp);
+ }
+
+ return buf;
+}
+
+u_int8_t *
+asn_decode_objectid (u_int8_t *asn, u_int32_t asnlen, struct norm_type *obj)
+{
+ u_int8_t *data;
+ u_int32_t len, c, tmp;
+ int flag = 0;
+ void *new_buf;
+
+ len = asn_get_data_len (obj, &asn, &data);
+
+ if (TAG_TYPE(asn) != TAG_OBJECTID)
+ {
+ log_print ("asn_decode_objectid: expected tag type OBJECTID, got %d",
+ TAG_TYPE(asn));
+ return NULL;
+ }
+
+ if (asnlen < asn_get_len (asn))
+ {
+ log_print ("asn_decode_objectid: ASN.1 content is bigger than buffer");
+ return NULL;
+ }
+
+ obj->data = NULL;
+ obj->len = 0;
+ while (len > 0)
+ {
+ tmp = 0;
+ do {
+ tmp <<= 7;
+ tmp += *data & 0x7f;
+ } while (len-- > 0 && (*data++ & 0x80));
+
+ if (flag == 0)
+ c = snprintf (NULL, 0, "%d %d ", tmp/40, tmp % 40) + 1;
+ else
+ c = snprintf (NULL, 0, "%d ", tmp) + 1;
+
+ new_buf = realloc (obj->data, obj->len + c);
+ if (new_buf == NULL)
+ {
+ free (obj->data);
+ obj->data = NULL;
+ log_print ("asn_decode_objectid: out of memory.");
+ return NULL;
+ }
+ obj->data = new_buf;
+
+ if (flag == 0)
+ {
+ sprintf (obj->data + obj->len, "%d %d ", tmp/40, tmp % 40);
+ flag = 1;
+ }
+ else
+ sprintf (obj->data + obj->len, "%d ", tmp);
+
+ obj->len = strlen (obj->data);
+ }
+
+ if (obj->data != NULL)
+ ((char *)obj->data)[obj->len - 1] = 0;
+
+ return data;
+}
+
+void
+asn_free_objectid (struct norm_type *obj)
+{
+ if (obj->data != NULL)
+ free (obj->data);
+}
+
+
+u_int32_t
+asn_get_encoded_len_raw (struct norm_type *obj, u_int8_t *type)
+{
+ if (type != NULL)
+ {
+ if (obj->len > 127)
+ *type = ASN_LONG_FORM;
+ else
+ *type = 0;
+ }
+
+ return obj->len;
+}
+
+u_int8_t *
+asn_encode_raw (struct norm_type *obj, u_int8_t *asn)
+{
+ u_int8_t *buf = NULL;
+
+ if (obj->len == 0)
+ return asn;
+
+ if (asn != NULL)
+ buf = asn;
+
+ if (buf == NULL && (buf = malloc (obj->len)) == NULL)
+ return NULL;
+
+ memcpy (buf, obj->data, obj->len);
+
+ return buf;
+}
+
+u_int8_t *
+asn_decode_raw (u_int8_t *asn, u_int32_t asnlen, struct norm_type *obj)
+{
+ obj->len = asn_get_len (asn);
+ if (asnlen < obj->len)
+ {
+ log_print ("asn_decode_raw: ASN.1 content is bigger than buffer");
+ return NULL;
+ }
+
+ obj->data = malloc (obj->len);
+ if (obj->data == NULL)
+ {
+ log_print ("asn_decode_raw: out of memory");
+ return NULL;
+ }
+
+ memcpy (obj->data, asn, obj->len);
+
+ return asn + obj->len;
+}
+
+void
+asn_free_raw (struct norm_type *obj)
+{
+ if (obj->data != NULL)
+ free (obj->data);
+}
+
+u_int32_t
+asn_get_encoded_len_null (struct norm_type *obj, u_int8_t *type)
+{
+ return asn_get_encoded_len (obj, 0, type);
+}
+
+u_int8_t *
+asn_encode_null (struct norm_type *obj, u_int8_t *asn)
+{
+ u_int8_t *buf = NULL;
+
+ if (asn != NULL)
+ buf = asn;
+
+ if (buf == NULL && (buf = malloc (2)) == NULL)
+ return NULL;
+
+ buf[0] = obj->type;
+ buf[1] = 0;
+
+ return buf;
+}
+
+u_int8_t *
+asn_decode_null (u_int8_t *asn, u_int32_t asnlen, struct norm_type *obj)
+{
+ obj->data = NULL;
+ obj->len = 0;
+
+ return asn + asn_get_len (asn);
+}
+
+void
+asn_free_null (struct norm_type *obj)
+{
+ obj->data = NULL;
+}
+
+void
+asn_free (struct norm_type *obj)
+{
+ struct asn_handler *h = asn_get (obj->type);
+
+ if (h == NULL)
+ log_print ("asn_free: unkown ASN.1 type %d", obj->type);
+ else
+ h->free (obj);
+}
+
+/*
+ * Returns the whole length of the BER encoded ASN.1 object.
+ */
+
+u_int32_t
+asn_get_len (u_int8_t *asn)
+{
+ u_int32_t len;
+ u_int8_t *data;
+ struct norm_type tmp = {TAG_RAW, UNIVERSAL, NULL, 0, NULL};
+
+ len = asn_get_data_len (&tmp, &asn, &data);
+
+ if (asn == NULL)
+ return 0;
+
+ return (data - asn) + len;
+}
+
+/*
+ * Returns the length of the ASN content, and a pointer to the content
+ * data itself.
+ * For TAG_NULL the data length is zero, so we have to return an error
+ * in asn, asn will be NULL in case of error.
+ */
+
+u_int32_t
+asn_get_data_len (struct norm_type *obj, u_int8_t **asn, u_int8_t **data)
+{
+ u_int32_t len;
+ u_int16_t len_off = 1;
+
+ if (obj != NULL && ISEXPLICIT(obj))
+ {
+ struct norm_type tmp = {TAG_RAW, UNIVERSAL, NULL, 0, NULL};
+
+ if (TAG_TYPE(*asn) != GET_EXP(obj))
+ {
+ log_print ("asn_get_data_len: explict tagging was needed");
+ *asn = NULL;
+ return 0;
+ }
+
+ asn_get_data_len (&tmp, asn, data);
+ *asn = *data;
+ }
+
+ if ((*asn)[len_off] & ASN_LONG_FORM)
+ {
+ int i, octets = (*asn)[len_off] & 0x7f;
+
+ /* XXX - we only decode really small length */
+ if (octets > sizeof (len))
+ {
+ log_print ("asn_get_data_len: long form length %d exceeds "
+ "allowed maximum", octets);
+ *asn = NULL;
+ return 0;
+ }
+
+ for (len = 0, i = 0; i < octets; i++)
+ {
+ len = (len << 8) | (*asn)[len_off + 1 + i];
+ }
+
+ if (data != NULL)
+ *data = *asn + len_off + 1 + octets;
+ }
+ else
+ {
+ /* Short form */
+ len = (*asn)[len_off];
+
+ if (data != NULL)
+ *data = *asn + len_off + 1;
+ }
+
+ return len;
+}
+
+void
+asn_free_sequence (struct norm_type *obj)
+{
+ struct norm_type *in = obj->data;
+ struct asn_handler *h;
+
+ if (in == NULL)
+ return;
+
+ while (in->type != TAG_STOP)
+ {
+ h = asn_get (in->type);
+ if (h == NULL)
+ break;
+
+ h->free (in++);
+ }
+
+ free (obj->data);
+}
+
+u_int32_t
+asn_get_encoded_len_sequence (struct norm_type *seq, u_int8_t *type)
+{
+ u_int32_t len, i;
+ struct asn_handler *h;
+ struct norm_type *obj = (struct norm_type *) seq->data;
+
+ /* Get whole data length */
+ for (len = 0, i = 0; obj[i].type != TAG_STOP; i++)
+ {
+ h = asn_get (obj[i].type);
+ if (h == NULL)
+ {
+ log_print ("asn_encode_sequence: unkown type %d", obj[i].type);
+ break;
+ }
+ len += h->get_encoded_len (&obj[i], NULL);
+ }
+
+ return asn_get_encoded_len (seq, len, type);
+}
+
+u_int8_t *
+asn_encode_sequence (struct norm_type *seq, u_int8_t *asn)
+{
+ u_int32_t len;
+ u_int8_t *erg, *data;
+ struct norm_type *obj;
+ struct asn_handler *h;
+ int i;
+
+ if ((h = asn_get (seq->type)) == NULL)
+ return NULL;
+
+ obj = (struct norm_type *) seq->data;
+
+ erg = asn_format_header (seq, asn, &data);
+ if (erg == NULL)
+ return NULL;
+
+ for (i = 0, len = 0; obj[i].type != TAG_STOP; i++)
+ {
+ h = asn_get (obj[i].type);
+ if (h == NULL)
+ {
+ log_print ("asn_encode_sequence: unknown ASN.1 tag %d", obj[i].type);
+ return NULL;
+ }
+
+ /* A structure can be optional, indicated by data == NULL */
+ if (h->encode (&obj[i], data + len) == NULL && obj->data != NULL)
+ {
+ log_print ("asn_encode_sequence: encoding of %s failed",
+ obj[i].name);
+ return NULL;
+ }
+ len += h->get_encoded_len (&obj[i], NULL);
+ }
+
+ erg[0] |= ASN_CONSTRUCTED;
+
+ return erg;
+}
+
+u_int8_t *
+asn_decode_sequence (u_int8_t *asn, u_int32_t asnlen, struct norm_type *obj)
+{
+ u_int8_t *p, *data;
+ u_int32_t len, flags, objects;
+ struct asn_handler *h;
+ void *new_buf;
+
+ if (asnlen < asn_get_len (asn))
+ {
+ log_print ("asn_decode_sequence: ASN.1 content is bigger than buffer");
+ return NULL;
+ }
+
+ len = asn_get_data_len (obj, &asn, &data);
+
+ /* XXX - an empty sequence is that okay */
+ if (len == 0)
+ return data;
+
+ if (TAG_TYPE(asn) != obj->type)
+ {
+ log_print ("asn_decode_sequence: expected tag type SEQUENCE/SET, got %d",
+ TAG_TYPE(asn));
+ return NULL;
+ }
+
+ /* Handle dynamic sized sets and sequences */
+ flags = obj->flags;
+
+ if (flags & ASN_FLAG_ZEROORMORE)
+ {
+ struct norm_type stop_tag = {TAG_STOP};
+ struct norm_type *tmp;
+
+ /* Zero occurences */
+ if (len == 0)
+ {
+ asn_free (obj);
+ obj->data = NULL;
+ return data;
+ }
+
+ /* Count number of objects */
+ p = data;
+ objects = 0;
+ while (p < data + len)
+ {
+ objects++;
+ p += asn_get_len (p);
+ }
+ if (p != data + len)
+ {
+ log_print ("asn_decode_sequence: SEQ/SET OF too many elements");
+ return NULL;
+ }
+
+ /*
+ * Create new templates for dynamically added objects,
+ * the ASN.1 tags SEQUENCE OF and SET OF, specify an unknown
+ * number of elements.
+ */
+
+ new_buf = realloc (obj->data,
+ (objects+1) * sizeof (struct norm_type));
+ if (new_buf == NULL)
+ {
+ asn_free (obj);
+ obj->data = NULL;
+ log_print ("asn_decode_sequence: out of memory");
+ return NULL;
+ }
+ obj->data = new_buf;
+
+ tmp = obj->data;
+
+ /* Copy TAG_STOP */
+ memcpy (tmp + objects, &stop_tag, sizeof (struct norm_type));
+ while (objects-- > 1)
+ {
+ memcpy (tmp + objects, tmp, sizeof (struct norm_type));
+ if (asn_template_clone (tmp + objects, 1) == NULL)
+ return NULL;
+ }
+ }
+
+ obj = (struct norm_type *) obj->data;
+
+ p = data;
+ while (p < data + len)
+ {
+ if (obj->type == TAG_STOP)
+ break;
+ h = asn_get (obj->type);
+ if (h == NULL)
+ {
+ log_print ("asn_decode_sequence: unknown ASN.1 tag %d", obj->type);
+ return NULL;
+ }
+
+ if ((p = h->decode (p, (data - p) + len, obj++)) == NULL)
+ break;
+ }
+
+ if (p < data + len)
+ log_print ("asn_decode_sequence: ASN tag was not decoded completely");
+
+ if (p == NULL)
+ return NULL;
+
+ return data + len;
+}
diff --git a/sbin/isakmpd/asn.h b/sbin/isakmpd/asn.h
new file mode 100644
index 00000000000..9a0e55f8936
--- /dev/null
+++ b/sbin/isakmpd/asn.h
@@ -0,0 +1,155 @@
+/* $Id: asn.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _ASN_H_
+#define _ASN_H_
+
+/* Very very simple module for compiling ASN.1 BER encoding */
+
+enum asn_classes {
+ UNIVERSAL = 0,
+ APPLICATION = 1,
+ CONTEXT = 2,
+ PRIVATE = 3
+};
+
+#define TAG_EXPLICIT 4
+#define TAG_EXPSHIFTS 5
+
+#define ISEXPLICIT(x) ((x)->class & TAG_EXPLICIT)
+#define ADD_EXP(x,y) ((x << TAG_EXPSHIFTS) | TAG_EXPLICIT | (y))
+#define GET_EXP(x) ((x)->class >> TAG_EXPSHIFTS)
+
+enum asn_tags {
+ TAG_BOOL = 1,
+ TAG_INTEGER = 2,
+ TAG_BITSTRING = 3,
+ TAG_OCTETSTRING = 4,
+ TAG_NULL = 5,
+ TAG_OBJECTID = 6, /* Internal Representation as ASCII String */
+ TAG_SEQUENCE = 16,
+ TAG_SET = 17,
+ TAG_PRINTSTRING = 19,
+ TAG_UTCTIME = 23, /* Represenation as ASCII String */
+ TAG_STOP = -1, /* None official ASN tag, indicates end */
+ TAG_RAW = -2, /* Placeholder for something we cant handle */
+ TAG_ANY = -3, /* Either we can handle it or it is RAW */
+};
+
+struct norm_type {
+ enum asn_tags type;
+ enum asn_classes class;
+ const char *name;
+ u_int32_t len;
+ void *data;
+ u_int32_t flags;
+};
+
+struct asn_objectid {
+ char *name;
+ char *objectid;
+};
+
+struct asn_handler {
+ enum asn_tags type;
+ void (*free) (struct norm_type *);
+ u_int32_t (*get_encoded_len) (struct norm_type *, u_int8_t *type);
+ u_int8_t *(*decode) (u_int8_t *, u_int32_t, struct norm_type *);
+ u_int8_t *(*encode) (struct norm_type *, u_int8_t *);
+};
+
+#define ASN_FLAG_ZEROORMORE 0x0001
+
+/* Construct a Sequence */
+#define SEQ(x,y) {TAG_SEQUENCE, UNIVERSAL, x, 0, y}
+#define SEQOF(x,y) {TAG_SEQUENCE, UNIVERSAL, x, 0, y, ASN_FLAG_ZEROORMORE}
+#define SET(x,y) {TAG_SET, UNIVERSAL, x, 0, y}
+#define SETOF(x,y) {TAG_SET, UNIVERSAL, x, 0, y, ASN_FLAG_ZEROORMORE}
+
+#define TAG_TYPE(x) ((enum asn_tags)((x)[0] & 0x1f))
+
+/* Tag modifiers */
+#define ASN_CONSTRUCTED 0x20 /* Constructed object type */
+
+/* Length modifiers */
+#define ASN_LONG_FORM 0x80 /* Number of length octets */
+
+/* Function prototypes */
+
+u_int8_t *asn_encode_integer (struct norm_type *, u_int8_t *);
+u_int8_t *asn_decode_integer (u_int8_t *, u_int32_t, struct norm_type *);
+u_int32_t asn_get_encoded_len_integer (struct norm_type *, u_int8_t *);
+void asn_free_integer (struct norm_type *);
+
+u_int8_t *asn_encode_string (struct norm_type *, u_int8_t *);
+u_int8_t *asn_decode_string (u_int8_t *, u_int32_t, struct norm_type *);
+u_int32_t asn_get_encoded_len_string (struct norm_type *, u_int8_t *);
+void asn_free_string (struct norm_type *);
+
+u_int8_t *asn_encode_objectid (struct norm_type *, u_int8_t *);
+u_int8_t *asn_decode_objectid (u_int8_t *, u_int32_t, struct norm_type *);
+u_int32_t asn_get_encoded_len_objectid (struct norm_type *, u_int8_t *);
+void asn_free_objectid (struct norm_type *);
+
+u_int8_t *asn_encode_raw (struct norm_type *, u_int8_t *);
+u_int8_t *asn_decode_raw (u_int8_t *, u_int32_t, struct norm_type *);
+u_int32_t asn_get_encoded_len_raw (struct norm_type *, u_int8_t *);
+void asn_free_raw (struct norm_type *);
+
+u_int8_t *asn_encode_null (struct norm_type *, u_int8_t *);
+u_int8_t *asn_decode_null (u_int8_t *, u_int32_t, struct norm_type *);
+u_int32_t asn_get_encoded_len_null (struct norm_type *, u_int8_t *);
+void asn_free_null (struct norm_type *);
+
+u_int8_t *asn_encode_sequence (struct norm_type *, u_int8_t *);
+u_int8_t *asn_decode_sequence (u_int8_t *, u_int32_t, struct norm_type *);
+u_int32_t asn_get_encoded_len_sequence (struct norm_type *, u_int8_t *);
+void asn_free_sequence (struct norm_type *);
+
+u_int8_t *asn_decode_any (u_int8_t *, u_int32_t, struct norm_type *);
+
+void asn_free (struct norm_type *);
+
+int asn_get_from_file (char *, u_int8_t **, u_int32_t *);
+struct norm_type *asn_template_clone (struct norm_type *, int);
+
+u_int32_t asn_sizeinoctets (u_int32_t);
+u_int32_t asn_get_len (u_int8_t *);
+u_int32_t asn_get_data_len (struct norm_type *, u_int8_t **, u_int8_t **);
+u_int32_t asn_get_encoded_len (struct norm_type *, u_int32_t, u_int8_t *);
+
+char *asn_parse_objectid (struct asn_objectid *, char *);
+struct norm_type *asn_decompose (char *, struct norm_type *);
+#endif /* _ASN_H_ */
diff --git a/sbin/isakmpd/asn_useful.c b/sbin/isakmpd/asn_useful.c
new file mode 100644
index 00000000000..512009f81cb
--- /dev/null
+++ b/sbin/isakmpd/asn_useful.c
@@ -0,0 +1,128 @@
+/* $Id: asn_useful.c,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+
+#include "asn.h"
+#include "asn_useful.h"
+
+struct norm_type AlgorithmIdentifier[] = {
+ {TAG_OBJECTID, UNIVERSAL, "algorithm", 0, NULL},
+ {TAG_ANY, UNIVERSAL, "parameters", 0, NULL},
+ {TAG_STOP, UNIVERSAL, NULL, 0, NULL}};
+
+struct norm_type Signed[] = {
+ {TAG_RAW, UNIVERSAL, "data", 0, NULL},
+ SEQ("algorithm", AlgorithmIdentifier),
+ {TAG_BITSTRING, UNIVERSAL, "encrypted", 0, NULL},
+ {TAG_STOP, UNIVERSAL, NULL, 0, NULL}};
+
+struct norm_type Validity[] = {
+ {TAG_UTCTIME, UNIVERSAL, "notBefore", 0, NULL},
+ {TAG_UTCTIME, UNIVERSAL, "notAfter", 0, NULL},
+ {TAG_STOP, UNIVERSAL, NULL, 0, NULL}};
+
+struct norm_type AttributeValueAssertion[] = {
+ {TAG_OBJECTID, UNIVERSAL, "AttributeType", 0, NULL},
+ {TAG_ANY, UNIVERSAL, "AttributeValue", 0, NULL},
+ {TAG_STOP, UNIVERSAL, NULL, 0, NULL}};
+
+struct norm_type RelativeDistinguishedName[] = {
+ SEQ ("AttributeValueAssertion", AttributeValueAssertion),
+ {TAG_STOP}};
+
+/*
+ * For decoding this structure is dynamically resized, we add two Names
+ * only for encoding purposes.
+ */
+struct norm_type RDNSequence[] = {
+ SETOF ("RelativeDistinguishedName", RelativeDistinguishedName),
+ SETOF ("RelativeDistinguishedName", RelativeDistinguishedName),
+ {TAG_STOP}};
+
+struct norm_type SubjectPublicKeyInfo[] = {
+ SEQ ("algorithm", AlgorithmIdentifier),
+ {TAG_BITSTRING, UNIVERSAL, "subjectPublicKey", 0, NULL},
+ {TAG_STOP}};
+
+struct norm_type Extension[] = {
+ {TAG_OBJECTID, UNIVERSAL, "extnId", 0, NULL},
+ {TAG_BOOL, UNIVERSAL, "critical", 0, NULL},
+ {TAG_OCTETSTRING, UNIVERSAL, "extnValue", 0, NULL},
+ {TAG_STOP}};
+
+struct norm_type Extensions[] = {
+ SEQ ("extension", Extension),
+ {TAG_STOP}};
+
+struct norm_type Certificate[] = {
+ /* We need to add an explicit tag, HACK XXX */
+ {TAG_INTEGER, ADD_EXP(0, UNIVERSAL), "version", 0, NULL},
+ {TAG_INTEGER, UNIVERSAL, "serialNumber", 0, NULL},
+ SEQ ("signature", AlgorithmIdentifier),
+ SEQOF ("issuer", RDNSequence),
+ SEQ ("validity", Validity),
+ SEQOF ("subject", RDNSequence),
+ SEQ ("subjectPublicKeyInfo", SubjectPublicKeyInfo),
+ {TAG_RAW, UNIVERSAL, "extension", 0, NULL},
+ {TAG_STOP}};
+
+struct norm_type DigestInfo[] = {
+ SEQ ("digestAlgorithm", AlgorithmIdentifier),
+ {TAG_OCTETSTRING, UNIVERSAL, "digest", 0, NULL},
+ {TAG_STOP}};
+
+struct asn_objectid asn_ids[] = {
+ {"AttributeType", ASN_ID_ATTRIBUTE_TYPE},
+ {"CountryName", ASN_ID_COUNTRY_NAME},
+ {"LocalityName", ASN_ID_LOCALITY_NAME},
+ {"StateOrProvinceName", ASN_ID_STATE_NAME},
+ {"OrganizationName", ASN_ID_ORGANIZATION_NAME},
+ {"OrganizationUnitName", ASN_ID_ORGUNIT_NAME},
+ {"CommonUnitName", ASN_ID_COMMONUNIT_NAME},
+ {"pkcs-1", ASN_ID_PKCS},
+ {"rsaEncryption", ASN_ID_RSAENCRYPTION},
+ {"md2WithRSAEncryption", ASN_ID_MD2WITHRSAENC},
+ {"md4WithRSAEncryption", ASN_ID_MD4WITHRSAENC},
+ {"md5WithRSAEncryption", ASN_ID_MD5WITHRSAENC},
+ {"md2", ASN_ID_MD2},
+ {"md4", ASN_ID_MD4},
+ {"md5", ASN_ID_MD5},
+ {"emailAddress", ASN_ID_EMAILADDRESS},
+ {"id-ce", ASN_ID_CE},
+ {"subjectAltName", ASN_ID_SUBJECT_ALT_NAME},
+ {"issuerAltName", ASN_ID_ISSUER_ALT_NAME},
+ {"basicConstraints", ASN_ID_BASIC_CONSTRAINTS},
+ {NULL, NULL} };
diff --git a/sbin/isakmpd/asn_useful.h b/sbin/isakmpd/asn_useful.h
new file mode 100644
index 00000000000..be32c825794
--- /dev/null
+++ b/sbin/isakmpd/asn_useful.h
@@ -0,0 +1,96 @@
+/* $Id: asn_useful.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _ASN_USEFUL_H_
+#define _ASN_USEFUL_H_
+
+extern struct norm_type AlgorithmIdentifier[];
+extern struct norm_type Signed[];
+extern struct norm_type Validity[];
+extern struct norm_type RDNSequence[];
+extern struct norm_type Extensions[];
+extern struct norm_type Certificate[];
+extern struct norm_type DigestInfo[];
+
+extern struct asn_objectid asn_ids[];
+
+/* Accessing a SIGNED type */
+#define ASN_SIGNED(x) ((struct norm_type *)((x)->data))
+#define ASN_SIGNED_DATA(x) (ASN_SIGNED(x)->data)
+#define ASN_SIGNED_ALGID(x) ((struct norm_type *)(ASN_SIGNED(x)+1)->data)
+#define ASN_SIGNED_ENCRYPTED(x) (ASN_SIGNED(x)+2)->data
+
+#define ASN_SIGNED_ALGORITHM(x) (ASN_SIGNED_ALGID(x)->data)
+
+/* Accessing a Certificate */
+#define ASN_NT struct norm_type *
+#define ASN_CERT(x) ((ASN_NT)((x)->data))
+#define ASN_CERT_VERSION(x) ASN_CERT(x)->data
+#define ASN_CERT_SN(x) (ASN_CERT(x)+1)->data
+#define ASN_CERT_ALGID(x) ((ASN_NT)((ASN_CERT(X)+2)->data))
+#define ASN_CERT_ALGORITHM(x) (ASN_CERT_ALGID(x)->data)
+#define ASN_CERT_ISSUER(x) (ASN_CERT(x)+3)
+#define ASN_CERT_VALIDITY(x) (ASN_CERT(x)+4)
+#define ASN_CERT_SUBJECT(x) (ASN_CERT(x)+5)
+#define ASN_CERT_PUBLICKEY(x) (ASN_CERT(x)+6)
+
+/* Accesing type Validity */
+#define ASN_VAL_BEGIN(x) (char *)(((ASN_NT)((x)->data))->data)
+#define ASN_VAL_END(x) (char *)(((ASN_NT)((x)->data)+1)->data)
+
+#define ASN_ID_ATTRIBUTE_TYPE "2 5 4"
+#define ASN_ID_COUNTRY_NAME ASN_ID_ATTRIBUTE_TYPE" 6"
+#define ASN_ID_LOCALITY_NAME ASN_ID_ATTRIBUTE_TYPE" 7"
+#define ASN_ID_STATE_NAME ASN_ID_ATTRIBUTE_TYPE" 8"
+#define ASN_ID_ORGANIZATION_NAME ASN_ID_ATTRIBUTE_TYPE" 10"
+#define ASN_ID_ORGUNIT_NAME ASN_ID_ATTRIBUTE_TYPE" 11"
+#define ASN_ID_COMMONUNIT_NAME ASN_ID_ATTRIBUTE_TYPE" 3"
+
+#define ASN_ID_PKCS "1 2 840 113549 1 1"
+#define ASN_ID_MD2 "1 2 840 113549 2 2"
+#define ASN_ID_MD4 "1 2 840 113549 2 4"
+#define ASN_ID_MD5 "1 2 840 113549 2 5"
+#define ASN_ID_RSAENCRYPTION ASN_ID_PKCS" 1"
+#define ASN_ID_MD2WITHRSAENC ASN_ID_PKCS" 2"
+#define ASN_ID_MD4WITHRSAENC ASN_ID_PKCS" 3"
+#define ASN_ID_MD5WITHRSAENC ASN_ID_PKCS" 4"
+
+#define ASN_ID_EMAILADDRESS "1 2 840 113549 1 9 1"
+
+#define ASN_ID_CE "2 5 29"
+#define ASN_ID_SUBJECT_ALT_NAME ASN_ID_CE" 17"
+#define ASN_ID_ISSUER_ALT_NAME ASN_ID_CE" 18"
+#define ASN_ID_BASIC_CONSTRAINTS ASN_ID_CE" 19"
+#endif /* _ASN_USEFUL_H_ */
diff --git a/sbin/isakmpd/attribute.c b/sbin/isakmpd/attribute.c
new file mode 100644
index 00000000000..5acf8a37e32
--- /dev/null
+++ b/sbin/isakmpd/attribute.c
@@ -0,0 +1,112 @@
+/* $Id: attribute.c,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+
+#include "attribute.h"
+#include "conf.h"
+#include "log.h"
+#include "isakmp.h"
+#include "util.h"
+
+u_int8_t *
+attribute_set_basic (u_int8_t *buf, u_int16_t type, u_int16_t value)
+{
+ SET_ISAKMP_ATTR_TYPE (buf, ISAKMP_ATTR_MAKE (1, type));
+ SET_ISAKMP_ATTR_LENGTH_VALUE (buf, value);
+ return buf + ISAKMP_ATTR_VALUE_OFF;
+}
+
+u_int8_t *
+attribute_set_var (u_int8_t *buf, u_int16_t type, u_int8_t *value,
+ u_int16_t len)
+{
+ SET_ISAKMP_ATTR_TYPE (buf, ISAKMP_ATTR_MAKE (0, type));
+ SET_ISAKMP_ATTR_LENGTH_VALUE (buf, len);
+ memcpy (buf + ISAKMP_ATTR_VALUE_OFF, value, len);
+ return buf + ISAKMP_ATTR_VALUE_OFF + len;
+}
+
+/* Validate an area of ISAKMP attributes. */
+int
+attribute_map (u_int8_t *buf, size_t sz,
+ int (*func) (u_int16_t, u_int8_t *, u_int16_t, void *),
+ void *arg)
+{
+ u_int8_t *attr;
+ int fmt;
+ u_int16_t type;
+ u_int8_t *value;
+ u_int16_t len;
+
+ for (attr = buf; attr < buf + sz; attr = value + len)
+ {
+ if (attr + ISAKMP_ATTR_VALUE_OFF > buf + sz)
+ return -1;
+ type = GET_ISAKMP_ATTR_TYPE (attr);
+ fmt = ISAKMP_ATTR_FORMAT (type);
+ type = ISAKMP_ATTR_TYPE (type);
+ value
+ = attr + (fmt ? ISAKMP_ATTR_LENGTH_VALUE_OFF : ISAKMP_ATTR_VALUE_OFF);
+ len = (fmt ? ISAKMP_ATTR_LENGTH_VALUE_LEN
+ : GET_ISAKMP_ATTR_LENGTH_VALUE (attr));
+ if (value + len > buf + sz)
+ return -1;
+ if (func (type, value, len, arg))
+ return -1;
+ }
+ return 0;
+}
+
+int
+attribute_set_constant (char *section, char *tag, struct constant_map *map,
+ int attr_class, u_int8_t **attr)
+{
+ char *name;
+ int value;
+
+ name = conf_get_str (section, tag);
+ if (!name)
+ {
+ /* XXX Should we really log hard like this? */
+ log_print ("attribute_set_constant: no %s in the %s section", tag,
+ section);
+ return -1;
+ }
+ value = constant_value (map, name);
+ *attr = attribute_set_basic (*attr, attr_class, value);
+ return 0;
+}
diff --git a/sbin/isakmpd/attribute.h b/sbin/isakmpd/attribute.h
new file mode 100644
index 00000000000..99b51b00029
--- /dev/null
+++ b/sbin/isakmpd/attribute.h
@@ -0,0 +1,52 @@
+/* $Id: attribute.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _ATTRIBUTE_H_
+#define _ATTRIBUTE_H_
+
+#include <sys/types.h>
+
+struct constant_map;
+
+extern int attribute_map (u_int8_t *, size_t,
+ int (*) (u_int16_t, u_int8_t *, u_int16_t, void *),
+ void *);
+extern u_int8_t *attribute_set_basic (u_int8_t *, u_int16_t, u_int16_t);
+extern int attribute_set_constant (char *, char *, struct constant_map *,
+ int, u_int8_t **);
+extern u_int8_t *attribute_set_var (u_int8_t *, u_int16_t, u_int8_t *,
+ u_int16_t);
+
+#endif /* _ATTRIBUTE_H_ */
diff --git a/sbin/isakmpd/cert.c b/sbin/isakmpd/cert.c
new file mode 100644
index 00000000000..297b9c32681
--- /dev/null
+++ b/sbin/isakmpd/cert.c
@@ -0,0 +1,94 @@
+/* $Id: cert.c,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cert.h"
+#include "isakmp_num.h"
+#include "x509.h"
+
+struct cert_handler cert_handler[] = {
+ {ISAKMP_CERTENC_X509_SIG,
+ x509_certreq_validate, x509_certreq_decode, x509_free_aca,
+ x509_cert_obtain, x509_cert_get_key, x509_cert_get_subject}
+};
+
+struct cert_handler *
+cert_get (u_int16_t id)
+{
+ int i;
+
+ for (i = 0; i < sizeof cert_handler / sizeof cert_handler[0]; i++)
+ if (id == cert_handler[i].id)
+ return &cert_handler[i];
+ return NULL;
+}
+
+
+/* Decode a CERTREQ and return a parsed structure */
+
+struct certreq_aca *
+certreq_decode (u_int16_t type, u_int8_t *data, u_int32_t datalen)
+{
+ struct cert_handler *handler;
+ struct certreq_aca aca, *ret;
+
+ if ((handler = cert_get (type)) == NULL)
+ return NULL;
+
+ aca.id = type;
+ aca.handler = handler;
+
+ if (datalen > 0)
+ {
+ aca.data = handler->certreq_decode (data, datalen);
+ if (aca.data == NULL)
+ return NULL;
+ }
+ else
+ aca.data = NULL;
+
+ if ((ret = malloc (sizeof (aca))) == NULL)
+ {
+ handler->free_aca (aca.data);
+ return NULL;
+ }
+
+ memcpy (ret, &aca, sizeof (aca));
+
+ return ret;
+}
diff --git a/sbin/isakmpd/cert.h b/sbin/isakmpd/cert.h
new file mode 100644
index 00000000000..b4ff8701474
--- /dev/null
+++ b/sbin/isakmpd/cert.h
@@ -0,0 +1,68 @@
+/* $Id: cert.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _CERT_H_
+#define _CERT_H_
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+struct exchange;
+
+struct cert_handler {
+ u_int16_t id; /* ISAKMP Cert Encoding ID */
+ int (*certreq_validate) (u_int8_t *, u_int32_t);
+ void *(*certreq_decode) (u_int8_t *, u_int32_t);
+ void (*free_aca) (void *);
+ int (*cert_obtain) (struct exchange *, void *, u_int8_t **, u_int32_t *);
+ int (*cert_get_key) (u_int8_t *, u_int32_t, void *);
+ int (*cert_get_subject) (u_int8_t *, u_int32_t, u_int8_t **, u_int32_t *);
+};
+
+/* the acceptable authority of cert request */
+
+struct certreq_aca {
+ TAILQ_ENTRY (certreq_aca) link;
+
+ u_int16_t id;
+ struct cert_handler *handler;
+ void *data; /* if NULL everything is acceptable */
+};
+
+struct cert_handler *cert_get (u_int16_t);
+struct certreq_aca *certreq_decode (u_int16_t, u_int8_t *, u_int32_t);
+
+#endif /* _CERT_H_ */
diff --git a/sbin/isakmpd/conf.c b/sbin/isakmpd/conf.c
new file mode 100644
index 00000000000..a05a9f9ec3b
--- /dev/null
+++ b/sbin/isakmpd/conf.c
@@ -0,0 +1,426 @@
+/* $Id: conf.c,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/queue.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "conf.h"
+#include "log.h"
+
+/*
+ * Radix-64 Encoding.
+ */
+
+const u_int8_t bin2asc[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+const u_int8_t asc2bin[] =
+{
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 62, 255, 255, 255, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 255, 255, 255, 255, 255, 255,
+ 255, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 255, 255, 255, 255, 255,
+ 255, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 255, 255, 255, 255, 255
+};
+
+struct conf_binding {
+ LIST_ENTRY (conf_binding) link;
+ char *section;
+ char *tag;
+ char *value;
+};
+
+char *conf_path = CONFIG_FILE;
+LIST_HEAD (conf_bindings, conf_binding) conf_bindings;
+
+static off_t conf_sz;
+static char *conf_addr;
+
+/*
+ * Insert a tag-value combination from LINE (the equal sign is at POS)
+ * into SECTION of our configuration database.
+ * XXX Should really be a hash table implementation.
+ */
+static void
+conf_set (char *section, char *line, int pos)
+{
+ struct conf_binding *node;
+ int i;
+
+ node = malloc (sizeof *node);
+ if (!node)
+ log_fatal ("conf_set: out of memory");
+ node->section = section;
+ node->tag = line;
+ for (i = 0; line[i] && i < pos; i++)
+ ;
+ line[i] = '\0';
+ if (conf_get_str (section, line))
+ {
+ log_print ("conf_set: duplicate tag [%s]:%s, ignoring...\n", section,
+ line);
+ return;
+ }
+ node->value = line + pos + 1 + strspn (line + pos + 1, " \t");
+ LIST_INSERT_HEAD (&conf_bindings, node, link);
+ log_debug (LOG_MISC, 70, "(%s,%s)->%s", node->section, node->tag,
+ node->value);
+}
+
+/*
+ * Parse the line LINE of SZ bytes. Skip Comments, recognize section
+ * headers and feed tag-value pairs into our configuration database.
+ */
+static void
+conf_parse_line (char *line, size_t sz)
+{
+ char *cp = line;
+ int i;
+ static char *section = 0;
+ static int ln = 0;
+
+ ln++;
+ for (i = 0; line[i]; i++)
+ if (!isprint (*cp))
+ {
+ log_print ("conf_parse_line: %d:"
+ "ignoring line %d with non-printable characters", ln);
+ return;
+ }
+
+ /* Lines starting with '#' or ';' are comments. */
+ if (*line == '#' || *line == ';')
+ return;
+
+ /* '[section]' parsing... */
+ if (*line == '[')
+ {
+ for (i = 1; i < sz; i++)
+ if (line[i] == ']')
+ break;
+ if (i == sz)
+ {
+ log_print ("conf_parse_line: %d:"
+ "non-matched ']', ignoring until next section", ln);
+ section = 0;
+ return;
+ }
+ section = malloc (i);
+ strncpy (section, line + 1, i - 1);
+ section[i - 1] = '\0';
+ return;
+ }
+
+ /* Deal with assignments. */
+ for (i = 0; i < sz; i++)
+ if (cp[i] == '=')
+ {
+ /* If no section, we are ignoring the lines. */
+ if (!section)
+ {
+ log_print ("conf_parse_line: %d: ignoring line due to no section",
+ ln);
+ return;
+ }
+ conf_set (section, line, i);
+ return;
+ }
+
+ /* Other non-empty lines are wierd. */
+ i = strspn (line, " \t");
+ if (line[i])
+ log_print ("conf_parse_line: %d: syntax error", ln);
+
+ return;
+}
+
+/* Parse the mapped configuration file. */
+static void
+conf_parse (void)
+{
+ char *cp = conf_addr;
+ char *conf_end = conf_addr + conf_sz;
+ char *line;
+
+ line = cp;
+ while (cp < conf_end)
+ {
+ if (*cp == '\n')
+ {
+ /* Check for escaped newlines. */
+ if (cp > conf_addr && *(cp - 1) == '\\')
+ *(cp - 1) = *cp = ' ';
+ else
+ {
+ *cp = '\0';
+ conf_parse_line (line, cp - line);
+ line = cp + 1;
+ }
+ }
+ cp++;
+ }
+ if (cp != line)
+ log_print ("conf_parse: last line non-terminated, ignored.");
+}
+
+/* Open the config file and map it into our address space, then parse it. */
+void
+conf_init (void)
+{
+ int fd;
+ struct stat st;
+
+ /*
+ * Start by freeing potential existing configuration.
+ *
+ * XXX One could envision doing this late, surviving failures with just
+ * a warning log message that the new configuration did not get read
+ * and that the former one persists.
+ */
+ if (conf_addr)
+ {
+ while (LIST_FIRST (&conf_bindings))
+ LIST_REMOVE (LIST_FIRST (&conf_bindings), link);
+ free (conf_addr);
+ }
+
+ fd = open (conf_path, O_RDONLY);
+ if (fd == -1)
+ log_fatal ("open (\"%s\", O_RDONLY)", conf_path);
+ if (fstat (fd, &st) == -1)
+ log_fatal ("fstat (%d, &st)", fd);
+ conf_sz = st.st_size;
+ conf_addr = malloc (conf_sz);
+ if (!conf_addr)
+ log_fatal ("malloc (%d)", conf_sz);
+ /* XXX I assume short reads won't happen here. */
+ if (read (fd, conf_addr, conf_sz) != conf_sz)
+ log_fatal ("read (%d, %p, %d)", fd, conf_addr, conf_sz);
+ close (fd);
+
+ LIST_INIT (&conf_bindings);
+ conf_parse ();
+}
+
+/* Return the numeric value denoted by TAG in section SECTION. */
+int
+conf_get_num (char *section, char *tag)
+{
+ char *value = conf_get_str (section, tag);
+
+ if (value)
+ return atoi (value);
+ return 0;
+}
+
+/* Return the string value denoted by TAG in section SECTION. */
+char *
+conf_get_str (char *section, char *tag)
+{
+ struct conf_binding *cb;
+
+ for (cb = LIST_FIRST (&conf_bindings); cb; cb = LIST_NEXT (cb, link))
+ if (strcasecmp (section, cb->section) == 0
+ && strcasecmp (tag, cb->tag) == 0)
+ {
+ log_debug (LOG_MISC, 60, "conf_get_str: (%s, %s) -> %s", section,
+ tag, cb->value);
+ return cb->value;
+ }
+ log_debug (LOG_MISC, 60,
+ "conf_get_str: configuration value not found (%s, %s)", section,
+ tag);
+ return 0;
+}
+
+struct conf_list *
+conf_get_list (char *section, char *tag)
+{
+ char *liststr = 0, *p, *field;
+ struct conf_list *list = 0;
+ struct conf_list_node *node;
+
+ list = malloc (sizeof *list);
+ if (!list)
+ goto cleanup;
+ TAILQ_INIT (&list->fields);
+ list->cnt = 0;
+ liststr = conf_get_str (section, tag);
+ if (!liststr)
+ goto cleanup;
+ liststr = strdup (liststr);
+ if (!liststr)
+ goto cleanup;
+ p = liststr;
+ while ((field = strsep (&p, ", \t")) != NULL)
+ {
+ if (*field == '\0')
+ {
+ log_print ("conf_get_list: empty field, ignoring...");
+ continue;
+ }
+ list->cnt++;
+ node = malloc (sizeof *node);
+ if (!node)
+ goto cleanup;
+ node->field = field;
+ TAILQ_INSERT_TAIL (&list->fields, node, link);
+ }
+ return list;
+
+ cleanup:
+ if (list)
+ conf_free_list (list);
+ if (liststr)
+ free (liststr);
+ return 0;
+}
+
+/* Decode a PEM encoded buffer. */
+int
+conf_decode_base64(u_int8_t *out, u_int32_t *len, u_char *buf)
+{
+ u_int32_t c = 0;
+ u_int8_t c1, c2, c3, c4;
+
+ while (*buf)
+ {
+ if (*buf > 127 || (c1 = asc2bin[*buf]) == 255)
+ return 0;
+ buf++;
+
+ if (*buf > 127 || (c2 = asc2bin[*buf]) == 255)
+ return 0;
+ buf++;
+
+ if (*buf == '=')
+ {
+ c3 = c4 = 0;
+ c++;
+
+ /* Check last four bit */
+ if (c2 & 0xF)
+ return 0;
+
+ if (!strcmp (buf, "=="))
+ buf++;
+ else
+ return 0;
+ }
+ else if (*buf > 127 || (c3 = asc2bin[*buf]) == 255)
+ return 0;
+ else
+ {
+ if (*++buf == '=')
+ {
+ c4 = 0;
+ c += 2;
+
+ /* Check last two bit */
+ if (c3 & 3)
+ return 0;
+
+ if (strcmp(buf, "="))
+ return 0;
+
+ }
+ else if (*buf > 127 || (c4 = asc2bin[*buf]) == 255)
+ return 0;
+ else
+ c += 3;
+ }
+
+ buf++;
+ *out++ = (c1 << 2) | (c2 >> 4);
+ *out++ = (c2 << 4) | (c3 >> 2);
+ *out++ = (c3 << 6) | c4;
+ }
+
+ *len = c;
+ return 1;
+
+}
+
+/* Read a line from a stream to the buffer. */
+int
+conf_get_line (FILE *stream, char *buf, u_int32_t len)
+{
+ char c;
+
+ while (len-- > 1)
+ {
+ c = fgetc (stream);
+ if (c == '\n')
+ {
+ *buf = 0;
+ return 1;
+ }
+ else if (c == EOF)
+ break;
+
+ *buf++ = c;
+ }
+
+ *buf = 0;
+ return 0;
+}
+
+void
+conf_free_list (struct conf_list *list)
+{
+ while (TAILQ_FIRST (&list->fields))
+ TAILQ_REMOVE (&list->fields, TAILQ_FIRST (&list->fields), link);
+ free (list);
+}
diff --git a/sbin/isakmpd/conf.h b/sbin/isakmpd/conf.h
new file mode 100644
index 00000000000..de8c2e821e3
--- /dev/null
+++ b/sbin/isakmpd/conf.h
@@ -0,0 +1,64 @@
+/* $Id: conf.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _CONF_H_
+#define _CONF_H_
+
+#include <sys/queue.h>
+#include <stdio.h>
+
+#define CONFIG_FILE "/etc/isakmpd.conf"
+
+struct conf_list_node {
+ TAILQ_ENTRY (conf_list_node) link;
+ char *field;
+};
+
+struct conf_list {
+ int cnt;
+ TAILQ_HEAD (conf_list_fields_head, conf_list_node) fields;
+};
+
+extern char *conf_path;
+
+extern void conf_init (void);
+extern void conf_free_list (struct conf_list *);
+extern struct conf_list *conf_get_list (char *, char *);
+extern int conf_get_num (char *, char *);
+extern char *conf_get_str (char *, char *);
+extern int conf_get_line (FILE *, char *, u_int32_t);
+extern int conf_decode_base64 (u_int8_t *out, u_int32_t *len, u_char *buf);
+
+#endif /* _CONF_H_ */
diff --git a/sbin/isakmpd/constants.c b/sbin/isakmpd/constants.c
new file mode 100644
index 00000000000..964cda17254
--- /dev/null
+++ b/sbin/isakmpd/constants.c
@@ -0,0 +1,92 @@
+/* $Id: constants.c,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "constants.h"
+
+int
+constant_value (struct constant_map *map, char *name)
+{
+ struct constant_map *entry = map;
+
+ for (entry = map; entry->name; entry++)
+ if (strcasecmp (entry->name, name) == 0)
+ return entry->value;
+ return 0;
+}
+
+char *
+constant_lookup (struct constant_map *map, int value)
+{
+ struct constant_map *entry = map;
+
+ for (entry = map; entry->name; entry++)
+ if (entry->value == value)
+ return entry->name;
+ return 0;
+}
+
+char *
+constant_name (struct constant_map *map, int value)
+{
+ static char tmp[32]; /* XXX Ugly, I know. */
+ char *retval = constant_lookup (map, value);
+
+ if (!retval)
+ {
+ snprintf (tmp, 32, "<Unknown %d>", value);
+ return tmp;
+ }
+ return retval;
+}
+
+char *
+constant_name_maps (struct constant_map **maps, int value)
+{
+ static char tmp[32]; /* XXX Ugly, I know. */
+ char *retval;
+ struct constant_map **map;
+
+ for (map = maps; *map; map++)
+ {
+ retval = constant_lookup (*map, value);
+ if (retval)
+ return retval;
+ }
+ snprintf (tmp, 32, "<Unknown %d>", value);
+ return tmp;
+}
diff --git a/sbin/isakmpd/constants.h b/sbin/isakmpd/constants.h
new file mode 100644
index 00000000000..68efe7c41f3
--- /dev/null
+++ b/sbin/isakmpd/constants.h
@@ -0,0 +1,49 @@
+/* $Id: constants.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _CONSTANTS_H_
+#define _CONSTANTS_H_
+
+struct constant_map {
+ int value;
+ char *name;
+};
+
+extern char *constant_lookup (struct constant_map *, int);
+extern char *constant_name (struct constant_map *, int);
+extern char *constant_name_maps (struct constant_map **, int);
+extern int constant_value (struct constant_map *, char *);
+
+#endif /* _CONSTANTS_H_ */
diff --git a/sbin/isakmpd/cookie.c b/sbin/isakmpd/cookie.c
new file mode 100644
index 00000000000..b31473957d6
--- /dev/null
+++ b/sbin/isakmpd/cookie.c
@@ -0,0 +1,127 @@
+/* $Id: cookie.c,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sha1.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cookie.h"
+#include "exchange.h"
+#include "hash.h"
+#include "log.h"
+#include "timer.h"
+#include "transport.h"
+#include "util.h"
+
+#define COOKIE_EVENT_FREQ 360
+#define COOKIE_SECRET_SIZE 16
+
+void cookie_secret_reset (void);
+
+u_int8_t cookie_secret[COOKIE_SECRET_SIZE];
+
+/*
+ * Generate an anti-clogging token (a protection against an attacker forcing
+ * us to keep state for a flood of connection requests) a.k.a. a cookie
+ * at BUF, LEN bytes long. The cookie will be generated by hashing of
+ * information found, among otherplaces, in transport T and exchange
+ * EXCHANGE.
+ */
+void
+cookie_gen (struct transport *t, struct exchange *exchange, u_int8_t *buf,
+ size_t len)
+{
+ struct hash* hash = hash_get (HASH_SHA1);
+ struct sockaddr *name;
+ int name_len;
+
+ hash->Init (hash->ctx);
+ (*t->vtbl->get_dst) (t, &name, &name_len);
+ hash->Update (hash->ctx, (u_int8_t *)name, name_len);
+ (*t->vtbl->get_src) (t, &name, &name_len);
+ hash->Update (hash->ctx, (u_int8_t *)name, name_len);
+ if (exchange->initiator)
+ {
+ u_int8_t tmpsecret[COOKIE_SECRET_SIZE];
+
+ getrandom (tmpsecret, COOKIE_SECRET_SIZE);
+ hash->Update (hash->ctx, tmpsecret, COOKIE_SECRET_SIZE);
+ }
+ else
+ {
+ hash->Update (hash->ctx, exchange->cookies + ISAKMP_HDR_ICOOKIE_OFF,
+ ISAKMP_HDR_ICOOKIE_LEN);
+ hash->Update (hash->ctx, cookie_secret, COOKIE_SECRET_SIZE);
+ }
+
+ hash->Final (hash->digest, hash->ctx);
+ memcpy (buf, hash->digest, len);
+}
+
+/*
+ * Reset the secret which is used for the responder cookie.
+ * As responder we do not want to keep state in the cookie
+ * exchange, which means when the cookie secret is reset,
+ * our cookie response has timed out.
+ */
+void
+cookie_secret_reset (void)
+{
+ getrandom (cookie_secret, COOKIE_SECRET_SIZE);
+}
+
+/*
+ * Handle the cookie reset event, and reschedule with timer.
+ */
+void
+cookie_reset_event (void *arg)
+{
+ struct timeval now;
+
+ cookie_secret_reset ();
+
+ gettimeofday (&now, 0);
+ now.tv_sec += COOKIE_EVENT_FREQ;
+ timer_add_event ("cookie_reset_event", cookie_reset_event, arg, &now);
+}
+
+void
+cookie_init (void)
+{
+ /* Start responder cookie resets. */
+ cookie_reset_event (NULL);
+}
diff --git a/sbin/isakmpd/cookie.h b/sbin/isakmpd/cookie.h
new file mode 100644
index 00000000000..b1ed008a5bf
--- /dev/null
+++ b/sbin/isakmpd/cookie.h
@@ -0,0 +1,50 @@
+/* $Id: cookie.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _COOKIE_H_
+#define _COOKIE_H_
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+struct exchange;
+struct transport;
+
+extern void cookie_gen (struct transport *, struct exchange *, u_int8_t *,
+ size_t);
+extern void cookie_init (void);
+extern void cookie_reset_event (void *);
+
+#endif /* _COOKIE_H_ */
diff --git a/sbin/isakmpd/crypto.c b/sbin/isakmpd/crypto.c
new file mode 100644
index 00000000000..aba4002f06b
--- /dev/null
+++ b/sbin/isakmpd/crypto.c
@@ -0,0 +1,355 @@
+/* $Id: crypto.c,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "crypto.h"
+#include "log.h"
+
+enum cryptoerr des1_init (struct keystate *, u_int8_t *, u_int16_t);
+enum cryptoerr des3_init (struct keystate *, u_int8_t *, u_int16_t);
+enum cryptoerr blf_init (struct keystate *, u_int8_t *, u_int16_t);
+enum cryptoerr cast_init (struct keystate *, u_int8_t *, u_int16_t);
+void des1_encrypt (struct keystate *, u_int8_t *, u_int16_t);
+void des1_decrypt (struct keystate *, u_int8_t *, u_int16_t);
+void des3_encrypt (struct keystate *, u_int8_t *, u_int16_t);
+void des3_decrypt (struct keystate *, u_int8_t *, u_int16_t);
+void blf_encrypt (struct keystate *, u_int8_t *, u_int16_t);
+void blf_decrypt (struct keystate *, u_int8_t *, u_int16_t);
+void cast1_encrypt (struct keystate *, u_int8_t *, u_int16_t);
+void cast1_decrypt (struct keystate *, u_int8_t *, u_int16_t);
+
+struct crypto_xf transforms[] = {
+ {
+ DES_CBC, "Data Encryption Standard (CBC-Mode)", 8, 8, BLOCKSIZE, NULL,
+ des1_init,
+ des1_encrypt, des1_decrypt
+ },
+ {
+ TRIPLEDES_CBC, "Triple-DES (CBC-Mode)", 24, 24, BLOCKSIZE, NULL,
+ des3_init,
+ des3_encrypt, des3_decrypt
+ },
+ {
+ BLOWFISH_CBC, "Blowfish (CBC-Mode)", 12, 56, BLOCKSIZE, NULL,
+ blf_init,
+ blf_encrypt, blf_decrypt
+ },
+ {
+ CAST_CBC, "CAST (CBC-Mode)", 12, 16, BLOCKSIZE, NULL,
+ cast_init,
+ cast1_encrypt, cast1_decrypt
+ },
+};
+
+/* Hmm, the function prototypes for des are really dumb */
+#define DC (des_cblock *)
+
+enum cryptoerr
+des1_init (struct keystate *ks, u_int8_t *key, u_int16_t len)
+{
+ /* des_set_key returns -1 for parity problems, and -2 for weak keys */
+ des_set_odd_parity (DC key);
+ switch (des_set_key (DC key, ks->ks_des[0]))
+ {
+ case -2:
+ return EWEAKKEY;
+ default:
+ return EOKAY;
+ }
+}
+
+void
+des1_encrypt (struct keystate *ks, u_int8_t *d, u_int16_t len)
+{
+ des_cbc_encrypt (DC d, DC d, len, ks->ks_des[0], DC ks->riv, DES_ENCRYPT);
+}
+
+void
+des1_decrypt (struct keystate *ks, u_int8_t *d, u_int16_t len)
+{
+ des_cbc_encrypt (DC d, DC d, len, ks->ks_des[0], DC ks->riv, DES_DECRYPT);
+}
+
+enum cryptoerr
+des3_init (struct keystate *ks, u_int8_t *key, u_int16_t len)
+{
+ des_set_odd_parity (DC key);
+ des_set_odd_parity (DC key + 1);
+ des_set_odd_parity (DC key + 2);
+
+ /* As of the draft Tripe-DES does not check for weak keys */
+ des_set_key (DC key, ks->ks_des[0]);
+ des_set_key (DC key + 1, ks->ks_des[1]);
+ des_set_key (DC key + 2, ks->ks_des[2]);
+
+ return EOKAY;
+}
+
+void
+des3_encrypt (struct keystate *ks, u_int8_t *data, u_int16_t len)
+{
+ u_int8_t iv[MAXBLK];
+
+ memcpy (iv, ks->riv, ks->xf->blocksize);
+ des_ede3_cbc_encrypt (DC data, DC data, len, ks->ks_des[0], ks->ks_des[1],
+ ks->ks_des[2], DC iv, DES_ENCRYPT);
+}
+
+void
+des3_decrypt (struct keystate *ks, u_int8_t *data, u_int16_t len)
+{
+ u_int8_t iv[MAXBLK];
+
+ memcpy (iv, ks->riv, ks->xf->blocksize);
+ des_ede3_cbc_encrypt (DC data, DC data, len, ks->ks_des[0], ks->ks_des[1],
+ ks->ks_des[2], DC iv, DES_DECRYPT);
+}
+#undef DC
+
+enum cryptoerr
+blf_init (struct keystate *ks, u_int8_t *key, u_int16_t len)
+{
+ blf_key (&ks->ks_blf, key, len);
+
+ return EOKAY;
+}
+
+void
+blf_encrypt (struct keystate *ks, u_int8_t *data, u_int16_t len)
+{
+ u_int16_t i, blocksize = ks->xf->blocksize;
+ u_int8_t *iv = ks->liv;
+ u_int32_t xl, xr;
+
+ memcpy (iv, ks->riv, blocksize);
+
+ for (i = 0; i < len; data += blocksize, i += blocksize)
+ {
+ XOR64 (data, iv);
+ xl = GET_32BIT_BIG (data);
+ xr = GET_32BIT_BIG (data + 4);
+ Blowfish_encipher (&ks->ks_blf, &xl, &xr);
+ SET_32BIT_BIG (data, xl);
+ SET_32BIT_BIG (data + 4, xr);
+ SET64 (iv, data);
+ }
+}
+
+void
+blf_decrypt (struct keystate *ks, u_int8_t *data, u_int16_t len)
+{
+ u_int16_t i, blocksize = ks->xf->blocksize;
+ u_int32_t xl, xr;
+
+ data += len - blocksize;
+ for (i = len - blocksize; i >= blocksize; data -= blocksize, i -= blocksize)
+ {
+ xl = GET_32BIT_BIG (data);
+ xr = GET_32BIT_BIG (data + 4);
+ Blowfish_decipher (&ks->ks_blf, &xl, &xr);
+ SET_32BIT_BIG (data, xl);
+ SET_32BIT_BIG (data + 4, xr);
+ XOR64 (data, data - blocksize);
+
+ }
+ xl = GET_32BIT_BIG (data);
+ xr = GET_32BIT_BIG (data + 4);
+ Blowfish_decipher (&ks->ks_blf, &xl, &xr);
+ SET_32BIT_BIG (data, xl);
+ SET_32BIT_BIG (data + 4, xr);
+ XOR64 (data, ks->riv);
+}
+
+enum cryptoerr
+cast_init (struct keystate *ks, u_int8_t *key, u_int16_t len)
+{
+ cast_setkey (&ks->ks_cast, key, len);
+ return EOKAY;
+}
+
+void
+cast1_encrypt (struct keystate *ks, u_int8_t *data, u_int16_t len)
+{
+ u_int16_t i, blocksize = ks->xf->blocksize;
+ u_int8_t *iv = ks->liv;
+
+ memcpy (iv, ks->riv, blocksize);
+
+ for (i = 0; i < len; data += blocksize, i += blocksize)
+ {
+ XOR64 (data, iv);
+ cast_encrypt (&ks->ks_cast, data, data);
+ SET64 (iv, data);
+ }
+}
+
+void
+cast1_decrypt (struct keystate *ks, u_int8_t *data, u_int16_t len)
+{
+ u_int16_t i, blocksize = ks->xf->blocksize;
+
+ data += len - blocksize;
+ for (i = len - blocksize; i >= blocksize; data -= blocksize, i -= blocksize)
+ {
+ cast_decrypt (&ks->ks_cast, data, data);
+ XOR64 (data, data - blocksize);
+ }
+ cast_decrypt (&ks->ks_cast, data, data);
+ XOR64 (data, ks->riv);
+}
+
+struct crypto_xf *
+crypto_get (enum transform id)
+{
+ int i;
+
+ for (i = 0; i < sizeof transforms / sizeof transforms[0]; i++)
+ if (id == transforms[i].id)
+ return &transforms[i];
+
+ return 0;
+}
+
+struct keystate *
+crypto_init (struct crypto_xf *xf, u_int8_t *key, u_int16_t len,
+ enum cryptoerr *err)
+{
+ struct keystate *ks = NULL;
+
+ if (len < xf->keymin || len > xf->keymax)
+ {
+ log_debug (LOG_CRYPTO, 10, "crypto_init: invalid key length %d", len);
+ *err = EKEYLEN;
+ return NULL;
+ }
+
+ if ((ks = calloc (1, sizeof (struct keystate))) == NULL)
+ {
+ *err = ENOCRYPTO;
+ return NULL;
+ }
+
+ ks->xf = xf;
+
+ /* Set up the iv */
+ ks->riv = ks->iv;
+ ks->liv = ks->iv2;
+
+ log_debug_buf (LOG_CRYPTO, 40, "crypto_init: key", key, len);
+
+ *err = xf->init (ks, key, len);
+ if (*err != EOKAY)
+ {
+ log_debug (LOG_CRYPTO, 30, "crypto_init: weak key found for %s",
+ xf->name);
+ free (ks);
+ return NULL;
+ }
+
+ return ks;
+}
+
+void
+crypto_update_iv (struct keystate *ks)
+{
+ u_int8_t *tmp;
+
+ tmp = ks->riv;
+ ks->riv = ks->liv;
+ ks->liv = tmp;
+
+ log_debug_buf (LOG_CRYPTO, 50, "crypto_update_iv: updated IV", ks->riv,
+ ks->xf->blocksize);
+}
+
+void
+crypto_init_iv (struct keystate *ks, u_int8_t *buf, size_t len)
+{
+ memcpy (ks->riv, buf, len);
+
+ log_debug_buf (LOG_CRYPTO, 50, "crypto_update_iv: initialized IV", ks->riv,
+ len);
+}
+
+void
+crypto_encrypt (struct keystate *ks, u_int8_t *buf, u_int16_t len)
+{
+ log_debug_buf (LOG_CRYPTO, 10, "crypto_encrypt: before encryption", buf,
+ len);
+ ks->xf->encrypt (ks, buf, len);
+ memcpy (ks->liv, buf + len - ks->xf->blocksize, ks->xf->blocksize);
+ log_debug_buf (LOG_CRYPTO, 30, "crypto_encrypt: after encryption", buf,
+ len);
+}
+
+void
+crypto_decrypt (struct keystate *ks, u_int8_t *buf, u_int16_t len)
+{
+ log_debug_buf (LOG_CRYPTO, 10, "crypto_decrypt: before decryption", buf,
+ len);
+ /*
+ * XXX There is controversy about the correctness of updating the IV
+ * like this.
+ */
+ memcpy (ks->liv, buf + len - ks->xf->blocksize, ks->xf->blocksize);
+ ks->xf->decrypt (ks, buf, len);;
+ log_debug_buf (LOG_CRYPTO, 30, "crypto_decrypt: after decryption", buf,
+ len);
+}
+
+struct keystate *
+crypto_clone_keystate (struct keystate *oks)
+{
+ struct keystate *ks;
+
+ ks = malloc (sizeof *ks);
+ if (!ks)
+ return 0;
+ memcpy (ks, oks, sizeof *ks);
+ if (oks->riv == oks->iv)
+ {
+ ks->riv = ks->iv;
+ ks->liv = ks->iv2;
+ }
+ else
+ {
+ ks->riv = ks->iv2;
+ ks->liv = ks->iv;
+ }
+ return ks;
+}
diff --git a/sbin/isakmpd/crypto.h b/sbin/isakmpd/crypto.h
new file mode 100644
index 00000000000..961ef232d14
--- /dev/null
+++ b/sbin/isakmpd/crypto.h
@@ -0,0 +1,145 @@
+/* $Id: crypto.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _CRYPTO_H_
+#define _CRYPTO_H_
+
+#include <des.h>
+#include <blf.h>
+#include <cast.h>
+
+#define USE_32BIT
+#if defined (USE_64BIT)
+
+#define XOR64(x,y) *(u_int64_t *)(x) ^= *(u_int64_t *)(y);
+#define SET64(x,y) *(u_int64_t *)(x) = *(u_int64_t *)(y);
+
+#elif defined (USE_32BIT)
+
+#define XOR64(x,y) *(u_int32_t *)(x) ^= *(u_int32_t *)(y); \
+ *(u_int32_t *)((u_int8_t *)(x) + 4) ^= *(u_int32_t *)((u_int8_t *)(y) + 4);
+#define SET64(x,y) *(u_int32_t *)(x) = *(u_int32_t *)(y); \
+ *(u_int32_t *)((u_int8_t *)(x) + 4) = *(u_int32_t *)((u_int8_t *)(y) + 4);
+
+#else
+
+#define XOR8(x,y,i) (x)[i] ^= (y)[i];
+#define XOR64(x,y) XOR8(x,y,0); XOR8(x,y,1); XOR8(x,y,2); XOR8(x,y,3); \
+ XOR8(x,y,4); XOR8(x,y,5); XOR8(x,y,6); XOR8(x,y,7);
+#define SET8(x,y,i) (x)[i] = (y)[i];
+#define SET64(x,y) SET8(x,y,0); SET8(x,y,1); SET8(x,y,2); SET8(x,y,3); \
+ SET8(x,y,4); SET8(x,y,5); SET8(x,y,6); SET8(x,y,7);
+
+#endif /* USE_64BIT */
+
+#define SET_32BIT_BIG(x,y) (x)[3]= (y); (x)[2]= (y) >> 8; \
+ (x)[1] = (y) >> 16; (x)[0]= (y) >> 24;
+#define GET_32BIT_BIG(x) (u_int32_t)(x)[3] | ((u_int32_t)(x)[2] << 8) | \
+ ((u_int32_t)(x)[1] << 16)| ((u_int32_t)(x)[0] << 24);
+
+/*
+ * This is standard for all block ciphers we use at the moment.
+ * Theoretically this could increase in future, e.g. for TwoFish.
+ * Keep MAXBLK uptodate
+ */
+#define BLOCKSIZE 8
+
+#define MAXBLK BLOCKSIZE
+
+struct keystate {
+ struct crypto_xf *xf; /* Back pointer */
+ u_int16_t ebytes; /* Number of encrypted bytes */
+ u_int16_t dbytes; /* Number of decrypted bytes */
+ time_t life; /* Creation time */
+ u_int8_t iv[MAXBLK]; /* Next IV to use */
+ u_int8_t iv2[MAXBLK];
+ u_int8_t *riv, *liv;
+ union {
+ des_key_schedule desks[3];
+ blf_ctx blfks;
+ cast_key castks;
+ } keydata;
+};
+
+#define ks_des keydata.desks
+#define ks_blf keydata.blfks
+#define ks_cast keydata.castks
+
+/*
+ * Information about the cryptotransform.
+ *
+ * XXX - In regards to the IV (Initialization Vector) the drafts are
+ * completly fucked up and specify a MUST as how it is derived, so
+ * we also have to provide for that. I just don't know where.
+ * Furthermore is this enum needed at all? It seems to be Oakley IDs
+ * only anyhow, and we already have defines for that in ipsec_doi.h.
+ */
+enum transform {
+ DES_CBC=1, /* This is a MUST */
+ IDEA_CBC=2, /* Licensed, DONT use */
+ BLOWFISH_CBC=3,
+ RC5_R16_B64_CBC=4, /* Licensed, DONT use */
+ TRIPLEDES_CBC=5, /* This is a SHOULD */
+ CAST_CBC=6
+};
+
+enum cryptoerr {
+ EOKAY, /* No error */
+ ENOCRYPTO, /* A none crypto related error, see errno */
+ EWEAKKEY, /* A weak key was found in key setup */
+ EKEYLEN, /* The key length was invalid for the cipher */
+};
+
+struct crypto_xf {
+ enum transform id; /* Oakley ID */
+ char *name; /* Transform Name */
+ u_int16_t keymin, keymax; /* Possible Keying Bytes */
+ u_int16_t blocksize; /* Need to keep IV in the state */
+ struct keystate *state; /* Key information, can also be passed sep. */
+ enum cryptoerr (*init) (struct keystate *, u_int8_t *, u_int16_t);
+ void (*encrypt) (struct keystate *, u_int8_t *, u_int16_t);
+ void (*decrypt) (struct keystate *, u_int8_t *, u_int16_t);
+};
+
+extern struct keystate *crypto_clone_keystate (struct keystate *);
+extern void crypto_decrypt (struct keystate *, u_int8_t *, u_int16_t);
+extern void crypto_encrypt (struct keystate *, u_int8_t *, u_int16_t);
+extern struct crypto_xf *crypto_get (enum transform);
+extern struct keystate *crypto_init (struct crypto_xf *, u_int8_t *,
+ u_int16_t, enum cryptoerr *);
+extern void crypto_init_iv (struct keystate *, u_int8_t *, size_t);
+extern void crypto_update_iv (struct keystate *);
+
+#endif /* _CRYPTO_H_ */
diff --git a/sbin/isakmpd/dh.c b/sbin/isakmpd/dh.c
new file mode 100644
index 00000000000..5062ad44b05
--- /dev/null
+++ b/sbin/isakmpd/dh.c
@@ -0,0 +1,79 @@
+/* $Id: dh.c,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+
+#include "math_group.h"
+#include "dh.h"
+#include "log.h"
+
+/*
+ * Returns the length of our exchange value.
+ */
+
+int
+dh_getlen (struct group *group)
+{
+ return group->getlen (group);
+}
+
+/*
+ * Creates the exchange value we are offering to the other party.
+ * Each time this function is called a new value is created, that
+ * means the application has to save the exchange value itself,
+ * dh_create_exchange should only be called once.
+ */
+
+void
+dh_create_exchange (struct group *group, u_int8_t *buf)
+{
+ group->setrandom (group, group->c);
+ group->operation (group, group->a, group->gen, group->c);
+ group->getraw (group, group->a, buf);
+}
+
+/*
+ * Creates the Diffie-Hellman shared secret in 'secret', where 'exchange'
+ * is the exchange value offered by the other party. No length verification
+ * is done for the value, the application has to do that.
+ */
+
+void
+dh_create_shared (struct group *group, u_int8_t *secret, u_int8_t *exchange)
+{
+ group->setraw (group, group->b, exchange, group->getlen(group));
+ group->operation (group, group->a, group->b, group->c);
+ group->getraw (group, group->a, secret);
+}
diff --git a/sbin/isakmpd/dh.h b/sbin/isakmpd/dh.h
new file mode 100644
index 00000000000..cf8c8a9ce69
--- /dev/null
+++ b/sbin/isakmpd/dh.h
@@ -0,0 +1,47 @@
+/* $Id: dh.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _DH_H_
+#define _DH_H_
+
+#include <sys/types.h>
+
+struct group;
+
+int dh_getlen (struct group *);
+void dh_create_exchange (struct group *, u_int8_t *);
+void dh_create_shared (struct group *, u_int8_t *, u_int8_t *);
+
+#endif /* _DH_H_ */
diff --git a/sbin/isakmpd/doi.c b/sbin/isakmpd/doi.c
new file mode 100644
index 00000000000..2724ddf5001
--- /dev/null
+++ b/sbin/isakmpd/doi.c
@@ -0,0 +1,64 @@
+/* $Id: doi.c,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+
+#include "doi.h"
+
+static LIST_HEAD (doi_list, doi) doi_tab;
+
+void
+doi_init ()
+{
+ LIST_INIT (&doi_tab);
+}
+
+struct doi *
+doi_lookup (u_int8_t doi_id)
+{
+ struct doi *doi;
+
+ for (doi = LIST_FIRST (&doi_tab); doi && doi->id != doi_id;
+ doi = LIST_NEXT (doi, link))
+ ;
+ return doi;
+}
+
+void
+doi_register (struct doi *doi)
+{
+ LIST_INSERT_HEAD (&doi_tab, doi, link);
+}
+
diff --git a/sbin/isakmpd/doi.h b/sbin/isakmpd/doi.h
new file mode 100644
index 00000000000..bc3a06f98f4
--- /dev/null
+++ b/sbin/isakmpd/doi.h
@@ -0,0 +1,92 @@
+/* $Id: doi.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _DOI_H_
+#define _DOI_H_
+
+#include <sys/types.h>
+#include <sys/queue.h>
+
+struct exchange;
+struct keystate;
+struct message;
+struct proto;
+struct sa;
+
+/* XXX This structure needs per-field commenting. */
+struct doi {
+ LIST_ENTRY (doi) link;
+ u_int8_t id;
+
+ /* Size of DOI-specific exchange data. */
+ size_t exchange_size;
+
+ /* Size of DOI-specific security association data. */
+ size_t sa_size;
+
+ /* Size of DOI-specific protocol data. */
+ size_t proto_size;
+
+ int (*debug_attribute) (u_int16_t, u_int8_t *, u_int16_t, void *);
+ void (*delete_spi) (struct sa *, struct proto *, int);
+ u_int16_t *(*exchange_script) (u_int8_t);
+ void (*finalize_exchange) (struct message *);
+ void (*free_exchange_data) (void *);
+ void (*free_proto_data) (void *);
+ void (*free_sa_data) (void *);
+ struct keystate *(*get_keystate) (struct message *);
+ u_int8_t *(*get_spi) (size_t *, u_int8_t, struct message *);
+ int (*is_attribute_incompatible) (u_int16_t, u_int8_t *, u_int16_t, void *);
+ void (*setup_situation) (u_int8_t *);
+ size_t (*situation_size) (void);
+ u_int8_t (*spi_size) (u_int8_t);
+ int (*validate_attribute) (u_int16_t, u_int8_t *, u_int16_t, void *);
+ int (*validate_exchange) (u_int8_t);
+ int (*validate_id_information) (u_int8_t, u_int8_t *, u_int8_t *, size_t,
+ struct exchange *);
+ int (*validate_key_information) (u_int8_t *, size_t);
+ int (*validate_notification) (u_int16_t);
+ int (*validate_proto) (u_int8_t);
+ int (*validate_situation) (u_int8_t *, size_t *);
+ int (*validate_transform_id) (u_int8_t, u_int8_t);
+ int (*initiator) (struct message *msg);
+ int (*responder) (struct message *msg);
+};
+
+extern void doi_init (void);
+extern struct doi *doi_lookup (u_int8_t);
+extern void doi_register (struct doi *);
+
+#endif /* _DOI_H_ */
diff --git a/sbin/isakmpd/exchange.c b/sbin/isakmpd/exchange.c
new file mode 100644
index 00000000000..b8d99386f71
--- /dev/null
+++ b/sbin/isakmpd/exchange.c
@@ -0,0 +1,936 @@
+/* $Id: exchange.c,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cert.h"
+#include "constants.h"
+#include "cookie.h"
+#include "crypto.h"
+#include "doi.h"
+#include "exchange.h"
+#include "isakmp.h"
+#include "log.h"
+#include "message.h"
+#include "timer.h"
+#include "sa.h"
+#include "util.h"
+
+/* Initial number of bits from the cookies used as hash. */
+#define INITIAL_BUCKET_BITS 6
+
+/*
+ * Don't try to use more bits than this as a hash.
+ * We only XOR 16 bits so going above that means changing the code below
+ * too.
+ */
+#define MAX_BUCKET_BITS 16
+
+static void exchange_dump (char *, struct exchange *);
+static void exchange_free_aux (struct exchange *);
+
+static LIST_HEAD (exchange_list, exchange) *exchange_tab;
+
+/* Works both as a maximum index and a mask. */
+static int bucket_mask;
+
+/*
+ * Validation scripts used to test messages for correct content of
+ * payloads depending on the exchange type.
+ */
+int16_t script_base[] = {
+ ISAKMP_PAYLOAD_SA, /* Initiator -> responder. */
+ ISAKMP_PAYLOAD_NONCE,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_SA, /* Responder -> initiator. */
+ ISAKMP_PAYLOAD_NONCE,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_KEY_EXCH, /* Initiator -> responder. */
+ ISAKMP_PAYLOAD_ID,
+ EXCHANGE_SCRIPT_AUTH,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_KEY_EXCH, /* Responder -> initiator. */
+ ISAKMP_PAYLOAD_ID,
+ EXCHANGE_SCRIPT_AUTH,
+ EXCHANGE_SCRIPT_END
+};
+
+int16_t script_identity_protection[] = {
+ ISAKMP_PAYLOAD_SA, /* Initiator -> responder. */
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_SA, /* Responder -> initiator. */
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_KEY_EXCH, /* Initiator -> responder. */
+ ISAKMP_PAYLOAD_NONCE,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_KEY_EXCH, /* Responder -> initiator. */
+ ISAKMP_PAYLOAD_NONCE,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_ID, /* Initiator -> responder. */
+ EXCHANGE_SCRIPT_AUTH,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_ID, /* Responder -> initiator. */
+ EXCHANGE_SCRIPT_AUTH,
+ EXCHANGE_SCRIPT_END
+};
+
+int16_t script_authentication_only[] = {
+ ISAKMP_PAYLOAD_SA, /* Initiator -> responder. */
+ ISAKMP_PAYLOAD_NONCE,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_SA, /* Responder -> initiator. */
+ ISAKMP_PAYLOAD_NONCE,
+ ISAKMP_PAYLOAD_ID,
+ EXCHANGE_SCRIPT_AUTH,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_ID, /* Initiator -> responder. */
+ EXCHANGE_SCRIPT_AUTH,
+ EXCHANGE_SCRIPT_END
+};
+
+int16_t script_aggressive[] = {
+ ISAKMP_PAYLOAD_SA, /* Initiator -> responder. */
+ ISAKMP_PAYLOAD_KEY_EXCH,
+ ISAKMP_PAYLOAD_NONCE,
+ ISAKMP_PAYLOAD_ID,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_SA, /* Responder -> initiator. */
+ ISAKMP_PAYLOAD_KEY_EXCH,
+ ISAKMP_PAYLOAD_NONCE,
+ ISAKMP_PAYLOAD_ID,
+ EXCHANGE_SCRIPT_AUTH,
+ EXCHANGE_SCRIPT_SWITCH,
+ EXCHANGE_SCRIPT_AUTH, /* Initiator -> responder. */
+ EXCHANGE_SCRIPT_END
+};
+
+int16_t script_informational[] = {
+ EXCHANGE_SCRIPT_INFO, /* Initiator -> responder. */
+ EXCHANGE_SCRIPT_END
+};
+
+/*
+ * Check what exchange SA is negotiated with and return a suitable validation
+ * script.
+ */
+u_int16_t *
+exchange_script (struct exchange *exchange)
+{
+ switch (exchange->type)
+ {
+ case ISAKMP_EXCH_BASE:
+ return script_base;
+ case ISAKMP_EXCH_ID_PROT:
+ return script_identity_protection;
+ case ISAKMP_EXCH_AUTH_ONLY:
+ return script_authentication_only;
+ case ISAKMP_EXCH_AGGRESSIVE:
+ return script_aggressive;
+ case ISAKMP_EXCH_INFO:
+ return script_informational;
+ default:
+ if (exchange->type >= ISAKMP_EXCH_DOI_MIN
+ && exchange->type <= ISAKMP_EXCH_DOI_MAX)
+ return exchange->doi->exchange_script (exchange->type);
+ }
+ return 0;
+}
+
+/*
+ * Validate the message MSG's contents wrt what payloads the exchange type
+ * requires at this point in the dialogoue. Return -1 if the validation fails,
+ * 0 if it succeeds and the script is not finished and 1 if it's ready.
+ */
+static int
+exchange_validate (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ int16_t *pc = exchange->exch_pc;
+
+ while (*pc != EXCHANGE_SCRIPT_END && *pc != EXCHANGE_SCRIPT_SWITCH)
+ {
+ log_debug (LOG_MISC, 90, "exchange_validate: checking for required %s",
+ *pc >= ISAKMP_PAYLOAD_NONE
+ ? constant_name (isakmp_payload_cst, *pc)
+ : constant_name (exchange_script_cst, *pc));
+
+ /* Check for existence of the required payloads. */
+ if ((*pc > 0 && !TAILQ_FIRST (&msg->payload[*pc]))
+ || (*pc == EXCHANGE_SCRIPT_AUTH
+ && !TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_HASH])
+ && !TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_SIG]))
+ || (*pc == EXCHANGE_SCRIPT_INFO
+ && !TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_NOTIFY])
+ && !TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_DELETE])))
+ {
+ /* Missing payload. */
+ log_debug (LOG_MESSAGE, 70,
+ "exchange_validate: msg %p requires missing %s", msg,
+ *pc >= ISAKMP_PAYLOAD_NONE
+ ? constant_name (isakmp_payload_cst, *pc)
+ : constant_name (exchange_script_cst, *pc));
+ return -1;
+ }
+ pc++;
+ }
+ if (*pc == EXCHANGE_SCRIPT_END)
+ /* Cleanup. */
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Run the exchange script from a point given by the "program counter"
+ * upto either the script's end or a transmittal of a message. If we are
+ * at the point of a reception of a message, that message should be handed
+ * in here in the MSG argument. Otherwise we are the initiator and should
+ * expect MSG to be a half-cooked message without payloads.
+ */
+void
+exchange_run (struct message *msg)
+{
+ int i, done = 0;
+ struct exchange *exchange = msg->exchange;
+ int (*handler) (struct message *) = (exchange->initiator
+ ? exchange->doi->initiator
+ : exchange->doi->responder);
+ struct payload *payload;
+
+ while (!done)
+ {
+ /*
+ * It's our turn if we're either the initiator on an even step,
+ * or the responder on an odd step of the dialogue.
+ */
+ if (exchange->initiator ^ (exchange->step % 2))
+ {
+ done = 1;
+ if (exchange->step)
+ msg = message_alloc_reply (msg);
+ message_setup_header (msg, exchange->type, 0, exchange->message_id);
+ if (handler (msg))
+ {
+ /*
+ * This can happen when transient starvation of memory occurs.
+ * XXX The peer's retransmit ought to kick-start this exchange
+ * again. If he's stopped retransmitting he's likely dropped
+ * the SA at his side so we need to do that too, i.e.
+ * implement automatic SA teardown after a certain amount
+ * of inactivity.
+ */
+ log_print ("exchange_run: exchange->doi->%s (%p) failed",
+ exchange->initiator ? "initiator" : "responder", msg);
+ message_free (msg);
+ return;
+ }
+
+ switch (exchange_validate (msg))
+ {
+ case 1:
+ /*
+ * The last message of an exchange should not be retransmitted.
+ * We should save this message in the ISAKMP SA if this is the
+ * final message of a phase 1 exchange. Then we can retransmit
+ * "on-demand" if we see retransmits of the last message of the
+ * peer later.
+ * XXX Think about this some more wrt the last message in
+ * phase 2 messages, does this not apply there too?
+ * MSG_NO_RETRANS and MSG_KEEP seems to go hand in hand btw..
+ * Unify?
+ */
+ msg->flags |= MSG_NO_RETRANS | MSG_KEEP;
+ if (msg->isakmp_sa)
+ {
+ if (msg->isakmp_sa->last_sent_in_setup)
+ message_free (msg->isakmp_sa->last_sent_in_setup);
+ msg->isakmp_sa->last_sent_in_setup = msg;
+ }
+
+ /*
+ * After we physically have sent our last message we need to
+ * do SA-specific finalization, like telling our application
+ * the SA is ready to be used, or issuing a CONNECTED notify
+ * if we set the COMMIT bit.
+ */
+ message_register_post_send (msg, exchange_finalize);
+
+ /* Fallthrough. */
+
+ case 0:
+ /* XXX error handling. */
+ message_send (msg);
+ break;
+
+ default:
+ log_print ("exchange_run: exchange_validate failed, DOI error");
+ exchange_free (exchange);
+ message_free (msg);
+ return;
+ }
+ }
+ else
+ {
+ done = exchange_validate (msg);
+ switch (done)
+ {
+ case 0:
+ case 1:
+ /* Feed the message to the DOI. */
+ if (handler (msg))
+ {
+ /*
+ * Trust the peer to retransmit.
+ * XXX We have to implement SA aging with automatic teardown.
+ */
+ message_free (msg);
+ return;
+ }
+
+ /*
+ * Go over the yet unhandled payloads and feed them to DOI
+ * for handling.
+ */
+ for (i = ISAKMP_PAYLOAD_SA; i < ISAKMP_PAYLOAD_RESERVED_MIN; i++)
+ if (i != ISAKMP_PAYLOAD_PROPOSAL
+ && i != ISAKMP_PAYLOAD_TRANSFORM)
+ for (payload = TAILQ_FIRST (&msg->payload[i]); payload;
+ payload = TAILQ_NEXT (payload, link))
+ if ((payload->flags & PL_MARK) == 0)
+ log_print ("exchange_run: unexpected payload %s",
+ constant_name (isakmp_payload_cst, i));
+
+ /*
+ * We have advanced the state. If we have been processing an
+ * incoming message, record that message as the one to do
+ * duplication tests against.
+ */
+ if (exchange->last_received)
+ message_free (exchange->last_received);
+ exchange->last_received = msg;
+ if (exchange->flags & EXCHANGE_FLAG_ENCRYPT)
+ crypto_update_iv (exchange->keystate);
+
+ if (done)
+ {
+ exchange_finalize (msg);
+ return;
+ }
+ break;
+
+ case -1:
+ log_print ("exchange_run: exchange_validate failed");
+ /* XXX Is this the best error notification type? */
+ message_drop (msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 0, 1);
+ return;
+ }
+ }
+
+ log_debug (LOG_MISC, 40, "exchange_run: finished step %d, advancing...",
+ exchange->step);
+ exchange->step++;
+ while (*exchange->exch_pc != EXCHANGE_SCRIPT_SWITCH
+ && *exchange->exch_pc != EXCHANGE_SCRIPT_END)
+ exchange->exch_pc++;
+ exchange->exch_pc++;
+ }
+}
+
+void
+exchange_init ()
+{
+ int i;
+
+ bucket_mask = (1 << INITIAL_BUCKET_BITS) - 1;
+ exchange_tab = malloc ((bucket_mask + 1) * sizeof (struct exchange_list));
+ if (!exchange_tab)
+ log_fatal ("exchange_init: out of memory");
+ for (i = 0; i <= bucket_mask; i++)
+ {
+ LIST_INIT (&exchange_tab[i]);
+ }
+
+}
+
+void
+exchange_resize ()
+{
+ int new_mask = (bucket_mask + 1) * 2 - 1;
+ int i;
+ struct exchange_list *new_tab;
+
+ new_tab
+ = realloc (exchange_tab, (new_mask + 1) * sizeof (struct exchange_list));
+ if (!new_tab)
+ return;
+ for (i = bucket_mask + 1; i <= new_mask; i++)
+ {
+ LIST_INIT (&new_tab[i]);
+ }
+ bucket_mask = new_mask;
+ /* XXX Rehash existing entries. */
+}
+
+/* Lookup a phase 1 exchange out of just the initiator cookie. */
+struct exchange *
+exchange_lookup_from_icookie (u_int8_t *cookie)
+{
+ int i;
+ struct exchange *exchange;
+
+ for (i = 0; i < bucket_mask; i++)
+ for (exchange = LIST_FIRST (&exchange_tab[i]); exchange;
+ exchange = LIST_NEXT (exchange, link))
+ if (memcmp (exchange->cookies, cookie, ISAKMP_HDR_ICOOKIE_LEN) == 0
+ && exchange->phase == 1)
+ return exchange;
+ return 0;
+}
+
+int
+exchange_enter (struct exchange *exchange)
+{
+ u_int16_t bucket = 0;
+ int i;
+ u_int8_t *cp;
+
+ /* XXX We might resize if we are crossing a certain threshold */
+
+ for (i = 0; i < ISAKMP_HDR_COOKIES_LEN; i += 2)
+ {
+ cp = exchange->cookies + i;
+ /* Doing it this way avoids alignment problems. */
+ bucket ^= cp[0] | cp[1] << 8;
+ }
+ for (i = 0; i < ISAKMP_HDR_MESSAGE_ID_LEN; i += 2)
+ {
+ cp = exchange->message_id + i;
+ /* Doing it this way avoids alignment problems. */
+ bucket ^= cp[0] | cp[1] << 8;
+ }
+ bucket &= bucket_mask;
+ LIST_INSERT_HEAD (&exchange_tab[bucket], exchange, link);
+ return 1;
+}
+
+/*
+ * Lookup the exchange given by the header fields MSG. PHASE2 is false when
+ * looking for phase 1 exchanges and true otherwise.
+ */
+struct exchange *
+exchange_lookup (u_int8_t *msg, int phase2)
+{
+ u_int16_t bucket = 0;
+ int i;
+ struct exchange *exchange;
+ u_int8_t *cp;
+
+ /*
+ * We use the cookies to get bits to use as an index into exchange_tab, as at
+ * least one (our cookie) is a good hash, xoring all the bits, 16 at a
+ * time, and then masking, should do. Doing it this way means we can
+ * validate cookies very fast thus delimiting the effects of "Denial of
+ * service"-attacks using packet flooding.
+ */
+ for (i = 0; i < ISAKMP_HDR_COOKIES_LEN; i += 2)
+ {
+ cp = msg + ISAKMP_HDR_COOKIES_OFF + i;
+ /* Doing it this way avoids alignment problems. */
+ bucket ^= cp[0] | cp[1] << 8;
+ }
+ if (phase2)
+ for (i = 0; i < ISAKMP_HDR_MESSAGE_ID_LEN; i += 2)
+ {
+ cp = msg + ISAKMP_HDR_MESSAGE_ID_OFF + i;
+ /* Doing it this way avoids alignment problems. */
+ bucket ^= cp[0] | cp[1] << 8;
+ }
+ bucket &= bucket_mask;
+ for (exchange = LIST_FIRST (&exchange_tab[bucket]);
+ exchange && (memcmp (msg + ISAKMP_HDR_COOKIES_OFF, exchange->cookies,
+ ISAKMP_HDR_COOKIES_LEN) != 0
+ || (phase2 && memcmp (msg + ISAKMP_HDR_MESSAGE_ID_OFF,
+ exchange->message_id,
+ ISAKMP_HDR_MESSAGE_ID_LEN) != 0));
+ exchange = LIST_NEXT (exchange, link))
+ ;
+
+ return exchange;
+}
+
+/*
+ * Create a phase PHASE exchange where INITIATOR denotes our role. DOI
+ * is the domain of interpretation identifier and TYPE tells what exchange
+ * type to use per either the DOI document or the ISAKMP spec proper.
+ * NSA tells how many SAs we should pre-allocate, and should be zero
+ * when we have the responder role.
+ */
+static struct exchange *
+exchange_create (int phase, int initiator, int doi, int type)
+{
+ struct exchange *exchange;
+ struct timeval expiration;
+
+ /*
+ * We want the exchange zeroed for exchange_free to be able to find out
+ * what fields have been filled-in.
+ */
+ exchange = calloc (1, sizeof *exchange);
+ if (!exchange)
+ return 0;
+ exchange->phase = phase;
+ exchange->step = 0;
+ exchange->initiator = initiator;
+ memset (exchange->cookies, 0, ISAKMP_HDR_COOKIES_LEN);
+ memset (exchange->message_id, 0, ISAKMP_HDR_MESSAGE_ID_LEN);
+ exchange->doi = doi_lookup (doi);
+ exchange->type = type;
+ exchange->exch_pc = exchange_script (exchange);
+ exchange->last_sent = exchange->last_received = 0;
+ TAILQ_INIT (&exchange->sa_list);
+ TAILQ_INIT (&exchange->aca_list);
+
+ /* Allocate the DOI-specific structure and initialize it to zeroes. */
+ exchange->data = calloc (1, exchange->doi->exchange_size);
+ if (!exchange->data)
+ {
+ exchange_free (exchange);
+ return 0;
+ }
+
+ gettimeofday(&expiration, 0);
+ expiration.tv_sec += EXCHANGE_MAX_TIME;
+ exchange->death = timer_add_event ("exchange_free_aux",
+ (void (*) (void *))exchange_free_aux,
+ exchange, &expiration);
+ if (!exchange->death)
+ {
+ /* If we don't give up we might start leaking... */
+ exchange_free (exchange);
+ return 0;
+ }
+
+ return exchange;
+}
+
+/* Establish a phase 1 exchange. */
+void
+exchange_establish_p1 (struct transport *t, u_int8_t type, u_int32_t doi,
+ void *args)
+{
+ struct exchange *exchange;
+ struct message *msg;
+
+ exchange = exchange_create (1, 1, doi, type);
+ if (!exchange)
+ {
+ /* XXX Do something here? */
+ return;
+ }
+ cookie_gen (t, exchange, exchange->cookies, ISAKMP_HDR_ICOOKIE_LEN);
+ exchange_enter (exchange);
+ exchange_dump ("exchange_establish_p1", exchange);
+
+ msg = message_alloc (t, 0, ISAKMP_HDR_SZ);
+ msg->exchange = exchange;
+
+ /*
+ * Don't install a transport into this SA as it will be an INADDR_ANY
+ * address in the local end, which is not good at all. Let the reply
+ * packet install the transport instead.
+ */
+ sa_create (exchange, 0);
+ msg->isakmp_sa = TAILQ_FIRST (&exchange->sa_list);
+ if (!msg->isakmp_sa)
+ {
+ /* XXX Do something more here? */
+ exchange_free (exchange);
+ return;
+ }
+
+ msg->extra = args;
+
+ exchange_run (msg);
+}
+
+/* Establish a phase 2 exchange. XXX With just one SA for now. */
+void
+exchange_establish_p2 (struct sa *isakmp_sa, u_int8_t type, void *args)
+{
+ struct exchange *exchange;
+ struct message *msg;
+ int i;
+
+ exchange = exchange_create (2, 1, isakmp_sa->doi->id, type);
+ if (!exchange)
+ {
+ /* XXX Do something here? */
+ return;
+ }
+ memcpy (exchange->cookies, isakmp_sa->cookies, ISAKMP_HDR_COOKIES_LEN);
+ getrandom (exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN);
+ exchange->flags |= EXCHANGE_FLAG_ENCRYPT;
+ exchange_enter (exchange);
+ exchange_dump ("exchange_establish_p2", exchange);
+
+ /* XXX Number of SAs should come from the args structure. */
+ for (i = 0; i < 1; i++)
+ if (sa_create (exchange, isakmp_sa->transport))
+ {
+ while (TAILQ_FIRST (&exchange->sa_list))
+ TAILQ_REMOVE (&exchange->sa_list, TAILQ_FIRST (&exchange->sa_list),
+ next);
+ exchange_free (exchange);
+ return;
+ }
+
+ msg = message_alloc (isakmp_sa->transport, 0, ISAKMP_HDR_SZ);
+ msg->isakmp_sa = isakmp_sa;
+ msg->extra = args;
+
+ /* This needs to be done late or else get_keystate won't work right. */
+ msg->exchange = exchange;
+
+ exchange_run (msg);
+}
+
+/* Out of an incoming phase 1 message, setup an exchange. */
+struct exchange *
+exchange_setup_p1 (struct message *msg, u_int32_t doi)
+{
+ struct exchange *exchange;
+
+ exchange = exchange_create (1, 0, doi,
+ GET_ISAKMP_HDR_EXCH_TYPE (msg->iov[0].iov_base));
+ if (!exchange)
+ return 0;
+ cookie_gen (msg->transport, exchange,
+ exchange->cookies + ISAKMP_HDR_ICOOKIE_LEN,
+ ISAKMP_HDR_RCOOKIE_LEN);
+ GET_ISAKMP_HDR_ICOOKIE (msg->iov[0].iov_base, exchange->cookies);
+ exchange_enter (exchange);
+ exchange_dump ("exchange_setup_p1", exchange);
+ return exchange;
+}
+
+/* Out of an incoming phase 2 message, setup an exchange. */
+struct exchange *
+exchange_setup_p2 (struct message *msg, u_int8_t doi)
+{
+ struct exchange *exchange;
+ u_int8_t *buf = msg->iov[0].iov_base;
+
+ exchange = exchange_create (2, 0, doi, GET_ISAKMP_HDR_EXCH_TYPE (buf));
+ if (!exchange)
+ return 0;
+ GET_ISAKMP_HDR_ICOOKIE (buf, exchange->cookies);
+ GET_ISAKMP_HDR_RCOOKIE (buf, exchange->cookies + ISAKMP_HDR_ICOOKIE_LEN);
+ GET_ISAKMP_HDR_MESSAGE_ID (buf, exchange->message_id);
+ exchange_enter (exchange);
+ exchange_dump ("exchange_setup_p2", exchange);
+ return exchange;
+}
+
+static void
+exchange_dump (char *header, struct exchange *exchange)
+{
+ log_debug (LOG_MISC, 10,
+ "%s: %s phase %d doi %d exchange %d step %d msgid %08x",
+ header, exchange->initiator ? "initiator" : "responder",
+ exchange->phase, exchange->doi->id, exchange->type,
+ exchange->step, decode_32 (exchange->message_id));
+ log_debug (LOG_MISC, 10,
+ "%s: icookie %08x%08x rcookie %08x%08x", header,
+ decode_32 (exchange->cookies), decode_32 (exchange->cookies + 4),
+ decode_32 (exchange->cookies + 8),
+ decode_32 (exchange->cookies + 12));
+}
+
+void
+exchange_report (void)
+{
+ int i;
+ struct exchange *exchange;
+
+ for (i = 0; i < bucket_mask; i++)
+ for (exchange = LIST_FIRST (&exchange_tab[i]); exchange;
+ exchange = LIST_NEXT (exchange, link))
+ exchange_dump ("exchange_report", exchange);
+}
+
+/*
+ * Release all resources this exchange is using *except* for the "death"
+ * event. When removing an exchange from the expiration handler that event
+ * will be dealt with therein instead.
+ */
+static void
+exchange_free_aux (struct exchange *exchange)
+{
+ if (exchange->last_received)
+ message_free (exchange->last_received);
+ if (exchange->last_sent)
+ message_free (exchange->last_sent);
+ if (exchange->nonce_i)
+ free (exchange->nonce_i);
+ if (exchange->nonce_r)
+ free (exchange->nonce_r);
+ if (exchange->id_i)
+ free (exchange->id_i);
+ if (exchange->id_r)
+ free (exchange->id_r);
+ if (exchange->keystate)
+ free (exchange->keystate);
+ if (exchange->doi && exchange->doi->free_exchange_data)
+ exchange->doi->free_exchange_data (exchange->data);
+ if (exchange->data)
+ free (exchange->data);
+ exchange_free_aca_list (exchange);
+ LIST_REMOVE (exchange, link);
+ free (exchange);
+}
+
+/* Release all resources this exchange is using. */
+void
+exchange_free (struct exchange *exchange)
+{
+ if (exchange->death)
+ timer_remove_event (exchange->death);
+ exchange_free_aux (exchange);
+}
+
+/*
+ * Upgrade the phase 1 exchange and its ISAKMP SA with the rcookie of our
+ * peer (found in his recently sent message MSG).
+ */
+void
+exchange_upgrade_p1 (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+
+ LIST_REMOVE (exchange, link);
+ GET_ISAKMP_HDR_RCOOKIE (msg->iov[0].iov_base,
+ exchange->cookies + ISAKMP_HDR_ICOOKIE_LEN);
+ exchange_enter (exchange);
+ sa_isakmp_upgrade (msg);
+}
+
+void
+exchange_finalize (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct sa *sa;
+ struct proto *proto;
+ int i;
+
+ exchange_dump ("exchange_finalize", exchange);
+
+ /*
+ * Walk over all the SAs and noting them as ready. If we set the COMMIT
+ * bit, tell the peer each SA is connected.
+ * XXX The decision should really be based on if a SA was installed
+ * successfully.
+ */
+ for (sa = TAILQ_FIRST (&exchange->sa_list); sa; sa = TAILQ_NEXT (sa, next))
+ {
+ if (exchange->flags & EXCHANGE_FLAG_I_COMMITTED)
+ {
+ for (proto = TAILQ_FIRST (&sa->protos); proto;
+ proto = TAILQ_NEXT (proto, link))
+ for (i = 0; i < 2; i++)
+ message_send_notification (exchange->last_received,
+ msg->isakmp_sa,
+ ISAKMP_NOTIFY_STATUS_CONNECTED, proto,
+ i);
+ }
+ sa->flags |= SA_FLAG_READY;
+ sa->exch_type = exchange->type;
+ }
+
+ /*
+ * If this was an phase 1 SA negotiation, save the keystate in the ISAKMP SA
+ * structure for future initialization of phase 2 exchanges' keystates.
+ */
+ if (exchange->phase == 1 && msg->isakmp_sa)
+ {
+ msg->isakmp_sa->keystate = exchange->keystate;
+ exchange->keystate = 0;
+ }
+ exchange->doi->finalize_exchange (msg);
+
+ /* No need for this anymore. */
+ exchange_free (exchange);
+}
+
+/* Stash a nonce into the exchange data. */
+static int
+exchange_nonce (struct exchange *exchange, int peer, size_t nonce_sz,
+ u_int8_t *buf)
+{
+ int initiator = exchange->initiator ^ peer;
+ u_int8_t **nonce;
+ size_t *nonce_len;
+ char header[32];
+
+ nonce = initiator ? &exchange->nonce_i : &exchange->nonce_r;
+ nonce_len = initiator ? &exchange->nonce_i_len : &exchange->nonce_r_len;
+ *nonce_len = nonce_sz;
+ *nonce = malloc (nonce_sz);
+ if (!*nonce)
+ return -1;
+ memcpy (*nonce, buf, nonce_sz);
+ snprintf (header, 32, "exchange_nonce: NONCE_%c", initiator ? 'i' : 'r');
+ log_debug_buf (LOG_MISC, 80, header, *nonce, nonce_sz);
+ return 0;
+}
+
+/* Generate our NONCE. */
+int
+exchange_gen_nonce (struct message *msg, size_t nonce_sz)
+{
+ struct exchange *exchange = msg->exchange;
+ u_int8_t *buf;
+
+ buf = malloc (ISAKMP_NONCE_SZ + nonce_sz);
+ if (!buf)
+ return -1;
+ getrandom (buf + ISAKMP_NONCE_DATA_OFF, nonce_sz);
+ if (message_add_payload (msg, ISAKMP_PAYLOAD_NONCE, buf,
+ ISAKMP_NONCE_SZ + nonce_sz, 1))
+ {
+ free (buf);
+ return -1;
+ }
+ return exchange_nonce (exchange, 0, nonce_sz, buf + ISAKMP_NONCE_DATA_OFF);
+}
+
+/* Save the peer's NONCE. */
+int
+exchange_save_nonce (struct message *msg)
+{
+ struct payload *noncep;
+ struct exchange *exchange = msg->exchange;
+
+ noncep = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_NONCE]);
+ noncep->flags |= PL_MARK;
+ return exchange_nonce (exchange, 1,
+ GET_ISAKMP_GEN_LENGTH (noncep->p)
+ - ISAKMP_NONCE_DATA_OFF,
+ noncep->p + ISAKMP_NONCE_DATA_OFF);
+}
+
+/* Save the peer's CERT REQuests. */
+int
+exchange_save_certreq (struct message *msg)
+{
+ struct payload *cp = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_CERT_REQ]);
+ struct exchange *exchange = msg->exchange;
+ struct certreq_aca *tmp;
+
+ for ( ; cp; cp = TAILQ_NEXT (cp, link))
+ {
+ cp->flags |= PL_MARK;
+ tmp = certreq_decode (GET_ISAKMP_CERTREQ_TYPE (cp->p),
+ cp->p + ISAKMP_CERTREQ_AUTHORITY_OFF,
+ GET_ISAKMP_GEN_LENGTH (cp->p) -
+ ISAKMP_CERTREQ_AUTHORITY_OFF);
+ if (tmp == NULL)
+ continue;
+ TAILQ_INSERT_TAIL (&exchange->aca_list, tmp, link);
+ }
+
+ return 0;
+}
+
+/* Free the list of pending CERTREQ */
+
+void
+exchange_free_aca_list (struct exchange *exchange)
+{
+ struct certreq_aca *aca;
+
+ for (aca = TAILQ_FIRST (&exchange->aca_list); aca;
+ aca = TAILQ_FIRST (&exchange->aca_list))
+ {
+ if (aca->data != NULL)
+ {
+ if (aca->handler != NULL)
+ aca->handler->free_aca (aca->data);
+ free (aca->data);
+ }
+ TAILQ_REMOVE (&exchange->aca_list, aca, link);
+ free (aca);
+ }
+}
+
+/* Obtain Certificates from Acceptable Certification Authority */
+
+int
+exchange_add_certs (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct certreq_aca *aca;
+ u_int8_t *cert;
+ u_int32_t certlen;
+
+ for (aca = TAILQ_FIRST (&exchange->aca_list); aca;
+ aca = TAILQ_NEXT (aca, link))
+ {
+ /* XXX? If we can not satisfy a CERTREQ we drop the message */
+ if (!aca->handler->cert_obtain (exchange, aca->data, &cert, &certlen))
+ {
+ log_print ("exchange_add_certs: could not obtain cert for a type %d "
+ "cert request", aca->id);
+ return -1;
+ }
+ cert = realloc (cert, ISAKMP_CERT_SZ + certlen);
+ if (cert == NULL)
+ return -1;
+ memmove (cert + ISAKMP_CERT_DATA_OFF, cert, certlen);
+ SET_ISAKMP_CERT_ENCODING (cert, aca->id);
+ if (message_add_payload (msg, ISAKMP_PAYLOAD_CERT, cert,
+ ISAKMP_CERT_SZ + certlen, 1))
+ {
+ free (cert);
+ return -1;
+ }
+ }
+
+ /* We dont need the CERT REQs any more, they are anwsered */
+ exchange_free_aca_list (exchange);
+
+ return 0;
+}
diff --git a/sbin/isakmpd/exchange.h b/sbin/isakmpd/exchange.h
new file mode 100644
index 00000000000..f84b0260944
--- /dev/null
+++ b/sbin/isakmpd/exchange.h
@@ -0,0 +1,165 @@
+/* $Id: exchange.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _EXCHANGE_H_
+#define _EXCHANGE_H_
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include "exchange_num.h"
+#include "isakmp.h"
+
+/* Remove an exchange if it has not been fully negotiated in this time. */
+#define EXCHANGE_MAX_TIME 120
+
+struct crypto_xf;
+struct certreq_aca;
+struct doi;
+struct event;
+struct keystate;
+struct message;
+struct payload;
+struct transport;
+struct sa;
+
+struct exchange {
+ /* Link to exchanges with the same hash value. */
+ LIST_ENTRY (exchange) link;
+
+ /* When several SA's are being negotiated we keep them here. */
+ TAILQ_HEAD (sa_head, sa) sa_list;
+
+ /*
+ * The event that will occur when it has taken too long time to try to
+ * run the exchange and which will trigger auto-destruction.
+ */
+ struct event *death;
+
+ /*
+ * Both initiator and responder cookies.
+ * XXX For code clarity we might split this into two fields.
+ */
+ u_int8_t cookies[ISAKMP_HDR_COOKIES_LEN];
+
+ /* The message ID signifying phase 2 exchanges. */
+ u_int8_t message_id[ISAKMP_HDR_MESSAGE_ID_LEN];
+
+ /* The exchange type we are using. */
+ u_int8_t type;
+
+ /* Phase is 1 for ISAKMP SA exchanges, and 2 for application ones. */
+ u_int8_t phase;
+
+ /* The "step counter" of the exchange, starting from zero. */
+ u_int8_t step;
+
+ /* 1 if we are the initiator, 0 if we are the responder. */
+ u_int8_t initiator;
+
+ /* Various flags, look below for descriptions. */
+ u_int32_t flags;
+
+ /* The DOI that is to handle DOI-specific issues for this exchange. */
+ struct doi *doi;
+
+ /*
+ * A "program counter" into the script that validate message contents for
+ * this exchange.
+ */
+ int16_t *exch_pc;
+
+ /* The last message received, used for checking for duplicates. */
+ struct message *last_received;
+
+ /* The last message sent, to be acked when something new is received. */
+ struct message *last_sent;
+
+ /*
+ * Initiator's & responder's nonces respectively, with lengths.
+ * XXX Should this be in the DOI-specific parts instead?
+ */
+ u_int8_t *nonce_i;
+ size_t nonce_i_len;
+ u_int8_t *nonce_r;
+ size_t nonce_r_len;
+
+ /* XXX Do we want to save these in the exchange at all? */
+ u_int8_t *id_i;
+ size_t id_i_len;
+ u_int8_t *id_r;
+ size_t id_r_len;
+
+ /* Crypto info needed to encrypt/decrypt packets in this exchange. */
+ struct crypto_xf *crypto;
+ int key_length;
+ struct keystate *keystate;
+
+ /* Acceptable authorities for cert requests */
+ TAILQ_HEAD (aca_head, certreq_aca) aca_list;
+
+ /* DOI-specific opaque data. */
+ void *data;
+};
+
+/* The flag bits. */
+#define EXCHANGE_FLAG_I_COMMITTED 1
+#define EXCHANGE_FLAG_HE_COMMITTED 2
+#define EXCHANGE_FLAG_COMMITTED (EXCHANGE_FLAG_I_COMMITTED \
+ | EXCHANGE_FLAG_HE_COMMITTED)
+#define EXCHANGE_FLAG_ENCRYPT 4
+
+extern void exchange_finalize (struct message *);
+extern void exchange_free (struct exchange *);
+extern void exchange_establish_p1 (struct transport *, u_int8_t, u_int32_t,
+ void *);
+extern void exchange_establish_p2 (struct sa *, u_int8_t, void *);
+extern int exchange_gen_nonce (struct message *, size_t);
+extern void exchange_init (void);
+extern struct exchange *exchange_lookup (u_int8_t *, int);
+extern struct exchange *exchange_lookup_from_icookie (u_int8_t *);
+extern void exchange_report (void);
+extern void exchange_run (struct message *);
+extern int exchange_save_nonce (struct message *);
+extern int exchange_save_certreq (struct message *);
+extern void exchange_free_aca_list (struct exchange *);
+extern int exchange_add_certs (struct message *);
+extern u_int16_t *exchange_script (struct exchange *);
+extern struct exchange *exchange_setup_p1 (struct message *, u_int32_t);
+extern struct exchange *exchange_setup_p2 (struct message *, u_int8_t);
+extern void exchange_upgrade_p1 (struct message *);
+
+#endif /* _EXCHANGE_H_ */
diff --git a/sbin/isakmpd/exchange_num.cst b/sbin/isakmpd/exchange_num.cst
new file mode 100644
index 00000000000..821020e2cd9
--- /dev/null
+++ b/sbin/isakmpd/exchange_num.cst
@@ -0,0 +1,46 @@
+# $Id: exchange_num.cst,v 1.1 1998/11/15 00:03:48 niklas Exp $
+
+#
+# Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Ericsson Radio Systems.
+# 4. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# This code was written under funding by Ericsson Radio Systems.
+#
+
+# Special exchange script symbols.
+EXCHANGE_SCRIPT
+# Special type signifying PAYLOAD_HASH or PALOAD_SIG must be present.
+ AUTH -1
+# Special type signifying PAYLOAD_NOTIFY or PALOAD_DELETE must be present.
+ INFO -2
+# Switch roles at this point in the exchange.
+ SWITCH -3
+# End of script
+ END -4
+.
diff --git a/sbin/isakmpd/field.c b/sbin/isakmpd/field.c
new file mode 100644
index 00000000000..d040886018b
--- /dev/null
+++ b/sbin/isakmpd/field.c
@@ -0,0 +1,258 @@
+/* $Id: field.c,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "constants.h"
+#include "field.h"
+#include "log.h"
+#include "util.h"
+
+static char *field_debug_raw (u_int8_t *, size_t, struct constant_map **);
+static char *field_debug_num (u_int8_t *, size_t, struct constant_map **);
+static char *field_debug_mask (u_int8_t *, size_t, struct constant_map **);
+static char *field_debug_ign (u_int8_t *, size_t, struct constant_map **);
+static char *field_debug_cst (u_int8_t *, size_t, struct constant_map **);
+
+/* Contents must match the enum in struct field. */
+static char *(*decode_field[]) (u_int8_t *, size_t, struct constant_map **) = {
+ field_debug_raw,
+ field_debug_num,
+ field_debug_mask,
+ field_debug_ign,
+ field_debug_cst
+};
+
+/*
+ * Return a string showing the hexadecimal contents of the LEN-sized buffer
+ * BUF. MAPS should be zero and is only here because the API requires it.
+ */
+static char *
+field_debug_raw (u_int8_t *buf, size_t len, struct constant_map **maps)
+{
+ char *retval, *p;
+
+ if (len == 0)
+ return 0;
+ retval = malloc (3 + len * 2);
+ if (!retval)
+ return 0;
+ strcpy (retval, "0x");
+ p = retval + 2;
+ while (len--)
+ {
+ sprintf (p, "%02x", *buf++);
+ p += 2;
+ }
+ return retval;
+}
+
+/*
+ * Convert the unsigned LEN-sized number at BUF of network byteorder to a
+ * 32-bit unsigned integer of host byteorder pointed to by VAL.
+ */
+static int
+extract_val (u_int8_t *buf, size_t len, u_int32_t *val)
+{
+ switch (len)
+ {
+ case 1:
+ *val = *buf;
+ break;
+ case 2:
+ *val = decode_16 (buf);
+ break;
+ case 4:
+ *val = decode_32 (buf);
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Return a textual representation of the unsigned number pointed to by BUF
+ * which is LEN octets long. MAPS should be zero and is only here because
+ * the API requires it.
+ */
+static char *
+field_debug_num (u_int8_t *buf, size_t len, struct constant_map **maps)
+{
+ char *retval;
+ u_int32_t val;
+
+ if (extract_val (buf, len, &val))
+ return 0;
+ asprintf (&retval, "%u", val);
+ return retval;
+}
+
+/*
+ * Return the symbolic names of the flags pointed to by BUF which is LEN
+ * octets long, using the constant maps MAPS.
+ */
+static char *
+field_debug_mask (u_int8_t *buf, size_t len, struct constant_map **maps)
+{
+ u_int32_t val;
+ u_int32_t bit;
+ char *retval, *new_buf, *name;
+ size_t buf_sz;
+
+ if (extract_val (buf, len, &val))
+ return 0;
+
+ /* Size for brackets, two spaces and a NUL terminator. */
+ buf_sz = 5;
+ retval = malloc (buf_sz);
+ if (!retval)
+ return 0;
+
+ strcpy (retval, "[ ");
+ for (bit = 1; bit; bit <<= 1)
+ {
+ if (val & bit)
+ {
+ name = constant_name_maps (maps, bit);
+ buf_sz += strlen (name);
+ new_buf = realloc (retval, buf_sz);
+ if (!new_buf)
+ {
+ free (retval);
+ return 0;
+ }
+ retval = new_buf;
+ strcat (retval, name);
+ strcat (retval, " ");
+ }
+ }
+ strcat (retval, "]");
+ return retval;
+}
+
+/*
+ * Just a dummy needed to skip the unused LEN sized space at BUF. MAPS
+ * should be zero and is only here because the API requires it.
+ */
+static char *
+field_debug_ign (u_int8_t *buf, size_t len, struct constant_map **maps)
+{
+ return 0;
+}
+
+/*
+ * Return the symbolic name of a constant pointed to by BUF which is LEN
+ * octets long, using the constant maps MAPS.
+ */
+static char *
+field_debug_cst (u_int8_t *buf, size_t len, struct constant_map **maps)
+{
+ u_int32_t val;
+
+ if (extract_val (buf, len, &val))
+ return 0;
+
+ return strdup (constant_name_maps (maps, val));
+}
+
+/* Pretty-print a field from BUF as described by F. */
+void
+field_dump_field (struct field *f, u_int8_t *buf)
+{
+ char *value;
+
+ value = decode_field[(int)f->type] (buf + f->offset, f->len, f->maps);
+ if (value)
+ {
+ log_debug (LOG_MESSAGE, 70, "%s: %s", f->name, value);
+ free (value);
+ }
+}
+
+/* Pretty-print all the fields of BUF as described in FIELDS. */
+void
+field_dump_payload (struct field *fields, u_int8_t *buf)
+{
+ struct field *field;
+
+ for (field = fields; field->name; field++)
+ field_dump_field (field, buf);
+}
+
+/* Return the numeric value of the field F of BUF. */
+u_int32_t
+field_get_num (struct field *f, u_int8_t *buf)
+{
+ u_int32_t val;
+
+ if (extract_val(buf + f->offset, f->len, &val))
+ return 0;
+ return val;
+}
+
+/* Stash the number VAL into BUF's field F. */
+void
+field_set_num (struct field *f, u_int8_t *buf, u_int32_t val)
+{
+ switch (f->len)
+ {
+ case 1:
+ buf[f->offset] = val;
+ break;
+ case 2:
+ encode_16 (buf + f->offset, val);
+ break;
+ case 4:
+ encode_32 (buf + f->offset, val);
+ break;
+ }
+}
+
+/* Stash BUF's raw field F into VAL. */
+void
+field_get_raw (struct field *f, u_int8_t *buf, u_int8_t *val)
+{
+ memcpy (val, buf + f->offset, f->len);
+}
+
+/* Stash the buffer VAL into BUF's field F. */
+void
+field_set_raw (struct field *f, u_int8_t *buf, u_int8_t *val)
+{
+ memcpy (buf + f->offset, val, f->len);
+}
diff --git a/sbin/isakmpd/field.h b/sbin/isakmpd/field.h
new file mode 100644
index 00000000000..48943e3d07b
--- /dev/null
+++ b/sbin/isakmpd/field.h
@@ -0,0 +1,56 @@
+/* $Id: field.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _FIELD_H_
+#define _FIELD_H_
+
+#include <sys/types.h>
+
+struct field {
+ char *name;
+ int offset;
+ size_t len;
+ enum { raw, num, mask, ign, cst } type;
+ struct constant_map **maps;
+};
+
+extern void field_dump_field (struct field *, u_int8_t *);
+extern void field_dump_payload (struct field *, u_int8_t *);
+extern u_int32_t field_get_num (struct field *, u_int8_t *);
+extern void field_get_raw (struct field *, u_int8_t *, u_int8_t *);
+extern void field_set_num (struct field *, u_int8_t *, u_int32_t);
+extern void field_set_raw (struct field *, u_int8_t *, u_int8_t *);
+
+#endif /* _FIELD_H_ */
diff --git a/sbin/isakmpd/genconstants.sh b/sbin/isakmpd/genconstants.sh
new file mode 100644
index 00000000000..757b3274fe3
--- /dev/null
+++ b/sbin/isakmpd/genconstants.sh
@@ -0,0 +1,115 @@
+# $Id: genconstants.sh,v 1.1 1998/11/15 00:03:48 niklas Exp $
+
+#
+# Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Ericsson Radio Systems.
+# 4. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# This code was written under funding by Ericsson Radio Systems.
+#
+
+base=`basename $1`
+upcased_name=`echo $base |tr a-z A-Z`
+
+awk=${AWK:-awk}
+
+locase_function='function locase (str) {
+ cmd = "echo " str " |tr A-Z a-z"
+ cmd | getline retval;
+ close (cmd);
+ return retval;
+}'
+
+$awk "
+$locase_function
+"'
+BEGIN {
+ print "/* DO NOT EDIT-- this file is automatically generated. */\n"
+ print "#ifndef _'$upcased_name'_H_"
+ print "#define _'$upcased_name'_H_\n"
+ print "#include \"constants.h\"\n"
+}
+
+/^[#.]/ {
+ next
+}
+
+/^[^ ]/ {
+ prefix = $1
+ printf ("extern struct constant_map %s_cst[];\n\n", locase(prefix));
+ next
+}
+
+/^[ ]/ && $1 {
+ printf ("#define %s_%s %s\n", prefix, $1, $2)
+ next
+}
+
+{
+ print
+}
+
+END {
+ printf ("\n")
+ print "#endif /* _'$upcased_name'_H_ */"
+}
+' <$1.cst >$base.h
+
+$awk "
+$locase_function
+"'
+BEGIN {
+ print "/* DO NOT EDIT-- this file is automatically generated. */\n"
+ print "#include \"constants.h\"\n"
+ print "#include \"'$base'.h\"\n"
+}
+
+/^#/ {
+ next
+}
+
+/^\./ {
+ print " { 0, 0 }\n};\n"
+ next
+}
+
+/^[^ ]/ {
+ prefix = $1
+ printf ("struct constant_map %s_cst[] = {\n", locase(prefix))
+ next
+}
+
+/^[ ]/ && $1 {
+ printf (" { %s_%s, \"%s\" }, \n", prefix, $1, $1)
+ next
+}
+
+{
+ print
+}
+' <$1.cst >$base.c
diff --git a/sbin/isakmpd/genfields.sh b/sbin/isakmpd/genfields.sh
new file mode 100644
index 00000000000..0cb6db41cd7
--- /dev/null
+++ b/sbin/isakmpd/genfields.sh
@@ -0,0 +1,187 @@
+# $Id: genfields.sh,v 1.1 1998/11/15 00:03:48 niklas Exp $
+
+#
+# Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Ericsson Radio Systems.
+# 4. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# This code was written under funding by Ericsson Radio Systems.
+#
+
+base=`basename $1`
+upcased_name=`echo $base |tr a-z A-Z`
+
+awk=${AWK:-awk}
+
+locase_function='function locase (str) {
+ cmd = "echo " str " |tr A-Z a-z"
+ cmd | getline retval;
+ close (cmd);
+ return retval;
+}'
+
+$awk "
+$locase_function
+"'
+BEGIN {
+ print "/* DO NOT EDIT-- this file is automatically generated. */\n"
+ print "#ifndef _'$upcased_name'_H_"
+ print "#define _'$upcased_name'_H_\n"
+
+ print "#include \"field.h\"\n"
+
+ print "struct constant_map;\n"
+}
+
+/^#/ {
+ next
+}
+
+/^\./ {
+ printf ("#define %s_SZ %d\n", prefix, off)
+ size[prefix] = off
+ next
+}
+
+/^[^ ]/ {
+ prefix = $1
+ printf ("extern struct field %s_fld[];\n\n", locase(prefix));
+ if ($3)
+ {
+ off = size[$3]
+ }
+ else
+ {
+ off = 0
+ }
+ i = 0
+ next
+}
+
+/^[ ]/ && $1 {
+ printf ("#define %s_%s_OFF %d\n", prefix, $1, off)
+ if ($3)
+ {
+ printf ("#define %s_%s_LEN %d\n", prefix, $1, $3)
+ }
+ if ($4)
+ {
+ printf ("extern struct constant_map *%s_%s_maps[];\n", locase(prefix),
+ locase($1))
+ }
+ if ($2 == "raw")
+ {
+ printf ("#define GET_%s_%s(buf, val) ", prefix, $1)
+ printf ("field_get_raw (%s_fld + %d, buf, val)\n", locase(prefix), i)
+ printf ("#define SET_%s_%s(buf, val) ", prefix, $1)
+ printf ("field_set_raw (%s_fld + %d, buf, val)\n", locase(prefix), i)
+ }
+ else
+ {
+ printf ("#define GET_%s_%s(buf) field_get_num (%s_fld + %d, buf)\n",
+ prefix, $1, locase(prefix), i)
+ printf ("#define SET_%s_%s(buf, val) ", prefix, $1)
+ printf ("field_set_num (%s_fld + %d, buf, val)\n", locase(prefix), i)
+ }
+ off += $3
+ i++
+ next
+}
+
+{
+ print
+}
+
+END {
+ printf ("\n")
+ print "#endif /* _'$upcased_name'_H_ */"
+}
+' <$1.fld >$base.h
+
+$awk "
+$locase_function
+"'
+BEGIN {
+ print "/* DO NOT EDIT-- this file is automatically generated. */\n"
+ print "#include \"constants.h\""
+ print "#include \"field.h\""
+ print "#include \"'$base'.h\""
+ print "#include \"isakmp_num.h\""
+ print "#include \"ipsec_num.h\""
+}
+
+/^#/ {
+ next
+}
+
+/^\./ {
+ print " { 0, 0, 0, 0, 0 }\n};\n"
+ size[prefix] = off
+ for (map in maps)
+ {
+ printf ("struct constant_map *%s_%s_maps[] = { ", locase(prefix),
+ locase(map))
+ printf ("%s,0 };\n", maps[map])
+ }
+ next
+}
+
+/^[^ ]/ {
+ prefix = $1
+ printf ("struct field %s_fld[] = {\n", locase(prefix))
+ if ($3)
+ {
+ off = size[$3]
+ }
+ else
+ {
+ off = 0
+ }
+ delete maps
+ next
+}
+
+/^[ ]/ && $1 {
+ if ($4)
+ {
+ maps_name = locase(prefix)"_"locase($1)"_maps"
+ maps[$1] = $4
+ }
+ else
+ {
+ maps_name = "0"
+ }
+ printf (" { \"%s\", %d, %d, %s, %s }, \n", $1, off, $3, $2, maps_name)
+ off += $3
+ next
+}
+
+{
+ print
+}
+' <$1.fld >$base.c
diff --git a/sbin/isakmpd/gmp_util.c b/sbin/isakmpd/gmp_util.c
new file mode 100644
index 00000000000..c3f0fc32601
--- /dev/null
+++ b/sbin/isakmpd/gmp_util.c
@@ -0,0 +1,76 @@
+/* $Id: gmp_util.c,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <gmp.h>
+
+#include "gmp_util.h"
+
+/* Various utility functions for gmp, used in more than one module */
+
+u_int32_t
+mpz_sizeinoctets (mpz_ptr a)
+{
+ return (7 + mpz_sizeinbase (a, 2)) >> 3;
+}
+
+void
+mpz_getraw (u_int8_t *raw, mpz_ptr v, u_int32_t len)
+{
+ mpz_t a, tmp;
+
+ mpz_init_set (a, v);
+ mpz_init (tmp);
+
+ while (len-- > 0)
+ raw[len] = mpz_fdiv_qr_ui (a, tmp, a, 256);
+
+ mpz_clear (a);
+ mpz_clear (tmp);
+}
+
+void
+mpz_setraw (mpz_ptr d, u_int8_t *s, u_int32_t l)
+{
+ u_int32_t i;
+
+ mpz_set_ui (d, 0);
+ for (i = 0; i < l; i++)
+ {
+ mpz_mul_ui (d, d, 256);
+ mpz_add_ui (d, d, s[i]);
+ }
+}
+
diff --git a/sbin/isakmpd/gmp_util.h b/sbin/isakmpd/gmp_util.h
new file mode 100644
index 00000000000..a600c448ffc
--- /dev/null
+++ b/sbin/isakmpd/gmp_util.h
@@ -0,0 +1,43 @@
+/* $Id: gmp_util.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _GMP_UTIL_H_
+#define _GMP_UTIL_H_
+
+u_int32_t mpz_sizeinoctets (mpz_ptr);
+void mpz_getraw (u_int8_t *, mpz_ptr, u_int32_t);
+void mpz_setraw (mpz_ptr, u_int8_t *, u_int32_t);
+
+#endif /* _GMP_UTIL_H_ */
diff --git a/sbin/isakmpd/hash.c b/sbin/isakmpd/hash.c
new file mode 100644
index 00000000000..d78e941427b
--- /dev/null
+++ b/sbin/isakmpd/hash.c
@@ -0,0 +1,135 @@
+/* $Id: hash.c,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <string.h>
+#include <md5.h>
+#include <sha1.h>
+
+#include "hash.h"
+
+void hmac_init (struct hash *, unsigned char *, int);
+void hmac_final (unsigned char *, struct hash *);
+
+/* Temporary hash contexts. */
+static union {
+ MD5_CTX md5ctx;
+ SHA1_CTX sha1ctx;
+} Ctx, Ctx2;
+
+/* Temporary hash digest. */
+static unsigned char digest[HASH_MAX];
+
+/* Encapsulation of hash functions. */
+
+static struct hash hashes[] = {
+ { HASH_MD5, 5, MD5_SIZE, (void *)&Ctx.md5ctx, digest,
+ sizeof (MD5_CTX), (void *)&Ctx2.md5ctx,
+ (void (*) (void *))MD5Init,
+ (void (*) (void *, unsigned char *, unsigned int))MD5Update,
+ (void (*) (unsigned char *, void *))MD5Final,
+ hmac_init, hmac_final },
+ { HASH_SHA1, 6, SHA1_SIZE, (void *)&Ctx.sha1ctx, digest,
+ sizeof (SHA1_CTX), (void *)&Ctx2.sha1ctx,
+ (void (*) (void *))SHA1Init,
+ (void (*) (void *, unsigned char *, unsigned int))SHA1Update,
+ (void (*) (unsigned char *, void *))SHA1Final,
+ hmac_init, hmac_final },
+};
+
+struct hash *
+hash_get (enum hashes hashtype)
+{
+ int i;
+
+ for (i = 0; i < sizeof hashes / sizeof hashes[0]; i++)
+ if (hashtype == hashes[i].type)
+ return &hashes[i];
+
+ return NULL;
+}
+
+/*
+ * Initial a hash for HMAC usage this requires a special init function.
+ * ctx, ctx2 hold the contexts, if you want to use the hash object for
+ * something else in the meantime, be sure to store the contexts somewhere.
+ */
+
+void
+hmac_init (struct hash *hash, unsigned char *okey, int len)
+{
+ int i, blocklen = HMAC_BLOCKLEN;
+ unsigned char key[HMAC_BLOCKLEN];
+
+ if (len > blocklen)
+ {
+ /* Truncate key down to blocklen */
+ hash->Init (hash->ctx);
+ hash->Update (hash->ctx, okey, len);
+ hash->Final (key, hash->ctx);
+ }
+ else
+ {
+ memset (key, 0, blocklen);
+ memcpy (key, okey, len);
+ }
+
+ /* HMAC I and O pad computation */
+ for (i=0; i < blocklen; i++)
+ key[i] ^= HMAC_IPAD_VAL;
+
+ hash->Init (hash->ctx);
+ hash->Update (hash->ctx, key, blocklen);
+
+ for (i=0; i < blocklen; i++)
+ key[i] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL);
+
+ hash->Init (hash->ctx2);
+ hash->Update (hash->ctx2, key, blocklen);
+
+ memset (key, 0, blocklen);
+}
+
+/*
+ * HMAC Final function
+ */
+
+void
+hmac_final (unsigned char *digest, struct hash *hash)
+{
+ hash->Final (digest, hash->ctx);
+ hash->Update (hash->ctx2, digest, hash->hashsize);
+ hash->Final (digest, hash->ctx2);
+}
diff --git a/sbin/isakmpd/hash.h b/sbin/isakmpd/hash.h
new file mode 100644
index 00000000000..2bd8c4ee046
--- /dev/null
+++ b/sbin/isakmpd/hash.h
@@ -0,0 +1,74 @@
+/* $Id: hash.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _HASH_H_
+#define _HASH_H_
+
+/* Normal mode hash encapsulation */
+
+#define MD5_SIZE 16
+#define SHA1_SIZE 20
+#define HASH_MAX SHA1_SIZE
+
+enum hashes {
+ HASH_MD5 = 0,
+ HASH_SHA1
+};
+
+struct hash {
+ enum hashes type;
+ int id; /* ISAKMP/Oakley ID */
+ u_int8_t hashsize; /* Size of the hash */
+ void *ctx; /* Pointer to a context, for HMAC ictx */
+ char *digest; /* Pointer to a digest */
+ int ctxsize;
+ void *ctx2; /* Pointer to a 2nd context, for HMAC octx */
+ void (*Init) (void *);
+ void (*Update) (void *, unsigned char *, unsigned int);
+ void (*Final) (unsigned char *, void *);
+ void (*HMACInit) (struct hash *, unsigned char *, int);
+ void (*HMACFinal) (unsigned char *, struct hash *);
+};
+
+/* HMAC Hash Encapsulation */
+
+#define HMAC_IPAD_VAL 0x36
+#define HMAC_OPAD_VAL 0x5C
+#define HMAC_BLOCKLEN 64
+
+extern struct hash *hash_get (enum hashes);
+extern void hmac_init (struct hash *, unsigned char *, int);
+
+#endif /* _HASH_H_ */
diff --git a/sbin/isakmpd/if.c b/sbin/isakmpd/if.c
new file mode 100644
index 00000000000..2be69a14928
--- /dev/null
+++ b/sbin/isakmpd/if.c
@@ -0,0 +1,121 @@
+/* $Id: if.c,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "if.h"
+
+/* XXX Unsafe if either x or y has side-effects. */
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+
+/* Most boxes has less than 16 interfaces, so this might be a good guess. */
+#define INITIAL_IFREQ_COUNT 16
+
+/*
+ * Get all network interface configurations.
+ * Return 0 if successful, -1 otherwise.
+ */
+int
+siocgifconf (struct ifconf *ifcp)
+{
+ int s;
+ int len;
+ caddr_t buf, new_buf;
+
+ /* Get a socket to ask for the network interface configurations. */
+ s = socket (AF_INET, SOCK_DGRAM, 0);
+ if (s == -1)
+ return -1;
+
+ len = sizeof (struct ifreq) * INITIAL_IFREQ_COUNT;
+ buf = 0;
+ while (1)
+ {
+ /*
+ * Allocate a larger buffer each time around the loop and get the
+ * network interfaces configurations into it.
+ */
+ ifcp->ifc_len = len;
+ new_buf = realloc (buf, len);
+ if (!new_buf)
+ goto err;
+ ifcp->ifc_buf = buf = new_buf;
+ if (ioctl (s, SIOCGIFCONF, ifcp) == -1)
+ goto err;
+
+ /*
+ * If there is place for another ifreq we can be sure that the buffer
+ * was big enough, otherwise double the size and try again.
+ */
+ if (len - ifcp->ifc_len >= sizeof (struct ifreq))
+ break;
+ len *= 2;
+ }
+ close (s);
+ return 0;
+
+err:
+ if (buf)
+ free (buf);
+ close (s);
+ return -1;
+}
+
+int
+if_map (void (*func) (struct ifreq *, void *), void *arg)
+{
+ struct ifconf ifc;
+ struct ifreq *ifrp;
+ caddr_t limit, p;
+ size_t len;
+
+ if (siocgifconf (&ifc))
+ return -1;
+
+ limit = ifc.ifc_buf + ifc.ifc_len;
+ for (p = ifc.ifc_buf; p < limit; p += len)
+ {
+ ifrp = (struct ifreq *)p;
+ (*func) (ifrp, arg);
+ len = sizeof ifrp->ifr_name
+ + MAX (ifrp->ifr_addr.sa_len, sizeof ifrp->ifr_addr);
+ }
+ return 0;
+}
diff --git a/sbin/isakmpd/if.h b/sbin/isakmpd/if.h
new file mode 100644
index 00000000000..21d52600c31
--- /dev/null
+++ b/sbin/isakmpd/if.h
@@ -0,0 +1,47 @@
+/* $Id: if.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _IF_H_
+#define _IF_H_
+
+#include <sys/types.h>
+
+struct ifreq;
+struct ifconf;
+
+extern int if_map (void (*) (struct ifreq *, void *), void *);
+extern int siocgifconf (struct ifconf *);
+
+#endif /* _IF_H_ */
diff --git a/sbin/isakmpd/ike_auth.c b/sbin/isakmpd/ike_auth.c
new file mode 100644
index 00000000000..a109e92a199
--- /dev/null
+++ b/sbin/isakmpd/ike_auth.c
@@ -0,0 +1,539 @@
+/* $Id: ike_auth.c,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "asn.h"
+#include "cert.h"
+#include "conf.h"
+#include "exchange.h"
+#include "gmp.h"
+#include "gmp_util.h"
+#include "hash.h"
+#include "ike_auth.h"
+#include "ipsec.h"
+#include "ipsec_doi.h"
+#include "log.h"
+#include "message.h"
+#include "pkcs.h"
+#include "prf.h"
+
+static u_int8_t *enc_gen_skeyid (struct exchange *, size_t *);
+static u_int8_t *pre_shared_gen_skeyid (struct exchange *, size_t *);
+static u_int8_t *sig_gen_skeyid (struct exchange *, size_t *);
+
+static int pre_shared_decode_hash (struct message *);
+static int rsa_sig_decode_hash (struct message *);
+static int pre_shared_encode_hash (struct message *);
+static int rsa_sig_encode_hash (struct message *);
+
+static int ike_auth_hash (struct exchange *, u_int8_t *);
+
+static struct ike_auth ike_auth[] = {
+ { IKE_AUTH_PRE_SHARED, pre_shared_gen_skeyid, pre_shared_decode_hash,
+ pre_shared_encode_hash},
+ { IKE_AUTH_DSS, sig_gen_skeyid, pre_shared_decode_hash,
+ pre_shared_encode_hash},
+ { IKE_AUTH_RSA_SIG, sig_gen_skeyid, rsa_sig_decode_hash,
+ rsa_sig_encode_hash},
+ { IKE_AUTH_RSA_ENC, enc_gen_skeyid, pre_shared_decode_hash,
+ pre_shared_encode_hash},
+ { IKE_AUTH_RSA_ENC_REV, enc_gen_skeyid, pre_shared_decode_hash,
+ pre_shared_encode_hash},
+};
+
+struct ike_auth *
+ike_auth_get (u_int16_t id)
+{
+ int i;
+
+ for (i = 0; i < sizeof ike_auth / sizeof ike_auth[0]; i++)
+ if (id == ike_auth[i].id)
+ return &ike_auth[i];
+ return 0;
+}
+
+static u_int8_t *
+pre_shared_gen_skeyid (struct exchange *exchange, size_t *sz)
+{
+ struct prf *prf;
+ struct ipsec_exch *ie = exchange->data;
+ u_int8_t *skeyid;
+ u_int8_t *key;
+
+ /*
+ * Get the default pre-shared key.
+ * XXX This will be per-IP configurable too later, and representable in
+ * hex too.
+ */
+ key = conf_get_str ("pre_shared", "key");
+ prf = prf_alloc (ie->prf_type, ie->hash->type, key, strlen (key));
+ if (!prf)
+ return 0;
+
+ *sz = prf->blocksize;
+ skeyid = malloc (*sz);
+ if (!skeyid)
+ {
+ prf_free (prf);
+ return 0;
+ }
+
+ prf->Init (prf->prfctx);
+ prf->Update (prf->prfctx, exchange->nonce_i, exchange->nonce_i_len);
+ prf->Update (prf->prfctx, exchange->nonce_r, exchange->nonce_r_len);
+ prf->Final (skeyid, prf->prfctx);
+ prf_free (prf);
+
+ return skeyid;
+}
+
+/* Both DSS & RSA signature authentication uses this algorithm. */
+static u_int8_t *
+sig_gen_skeyid (struct exchange *exchange, size_t *sz)
+{
+ struct prf *prf;
+ struct ipsec_exch *ie = exchange->data;
+ u_int8_t *skeyid, *key;
+
+ key = malloc (exchange->nonce_i_len + exchange->nonce_r_len);
+ if (!key)
+ return 0;
+ memcpy (key, exchange->nonce_i, exchange->nonce_i_len);
+ memcpy (key + exchange->nonce_i_len, exchange->nonce_r,
+ exchange->nonce_r_len);
+ prf = prf_alloc (ie->prf_type, ie->hash->type, key,
+ exchange->nonce_i_len + exchange->nonce_r_len);
+ free (key);
+ if (!prf)
+ return 0;
+
+ *sz = prf->blocksize;
+ skeyid = malloc (*sz);
+ if (!skeyid)
+ {
+ prf_free (prf);
+ return 0;
+ }
+
+ prf->Init (prf->prfctx);
+ prf->Update (prf->prfctx, ie->g_xy, ie->g_x_len);
+ prf->Final (skeyid, prf->prfctx);
+ prf_free (prf);
+
+ return skeyid;
+}
+
+/*
+ * Both standard and revised RSA encryption authentication uses this SKEYID
+ * computation.
+ */
+static u_int8_t *
+enc_gen_skeyid (struct exchange *exchange, size_t *sz)
+{
+ struct prf *prf;
+ struct ipsec_exch *ie = exchange->data;
+ struct hash *hash = ie->hash;
+ u_int8_t *skeyid;
+
+ hash->Init (hash->ctx);
+ hash->Update (hash->ctx, exchange->nonce_i, exchange->nonce_i_len);
+ hash->Update (hash->ctx, exchange->nonce_r, exchange->nonce_r_len);
+ hash->Final (hash->digest, hash->ctx);
+ prf = prf_alloc (ie->prf_type, hash->type, hash->digest, *sz);
+ if (!prf)
+ return 0;
+
+ *sz = prf->blocksize;
+ skeyid = malloc (*sz);
+ if (!skeyid)
+ {
+ prf_free (prf);
+ return 0;
+ }
+
+ prf->Init (prf->prfctx);
+ prf->Update (prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN);
+ prf->Final (skeyid, prf->prfctx);
+ prf_free (prf);
+
+ return skeyid;
+}
+
+static int
+pre_shared_decode_hash (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ struct payload *payload;
+ size_t hashsize = ie->hash->hashsize;
+ char header[80];
+ int initiator = exchange->initiator;
+ u_int8_t **hash_p;
+
+ /* Choose the right fields to fill-in. */
+ hash_p = initiator ? &ie->hash_r : &ie->hash_i;
+
+ payload = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_HASH]);
+ if (!payload)
+ return -1;
+
+ /* Check that the hash is of the correct size. */
+ if (GET_ISAKMP_GEN_LENGTH (payload->p) - ISAKMP_GEN_SZ != hashsize)
+ return -1;
+
+ /* XXX Need this hash be in the SA? */
+ *hash_p = malloc (hashsize);
+ if (!*hash_p)
+ return -1;
+
+ memcpy (*hash_p, payload->p + ISAKMP_HASH_DATA_OFF, hashsize);
+ snprintf (header, 80, "pre_shared_decode_hash: HASH_%c",
+ initiator ? 'R' : 'I');
+ log_debug_buf (LOG_MISC, 80, header, *hash_p, hashsize);
+
+ payload->flags |= PL_MARK;
+
+ return 0;
+}
+
+/*
+ * Decrypt the HASH in SIG, we already need a parsed ID payload
+ */
+
+static int
+rsa_sig_decode_hash (struct message *msg)
+{
+ struct cert_handler *handler;
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ struct payload *p;
+ struct rsa_public_key key;
+ size_t hashsize = ie->hash->hashsize;
+ char header[80];
+ int initiator = exchange->initiator;
+ u_int8_t **hash_p, *id_cert, *id;
+ u_int16_t len;
+ u_int32_t id_cert_len;
+ size_t id_len;
+
+ /* Choose the right fields to fill-in. */
+ hash_p = initiator ? &ie->hash_r : &ie->hash_i;
+ id = initiator ? exchange->id_r : exchange->id_i;
+ id_len = initiator ? exchange->id_r_len : exchange->id_i_len;
+
+ if (id == NULL || id_len == 0)
+ {
+ log_print ("rsa_sig_decode_hash: no ID in sa");
+ return -1;
+ }
+
+ /* Just bother with the ID data field. */
+ id += ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ;
+ id_len -= ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ;
+
+ p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_CERT]);
+ if (!p)
+ return -1;
+
+ if ((handler = cert_get (GET_ISAKMP_CERT_ENCODING(p->p))) == NULL)
+ {
+ log_print ("rsa_sig_decode_hash: no handler for CERT encoding");
+ return -1;
+ }
+
+ /* XXX - this assumes IPv4 here */
+ if (!handler->cert_get_subject (p->p + ISAKMP_CERT_DATA_OFF,
+ GET_ISAKMP_GEN_LENGTH(p->p) -
+ ISAKMP_CERT_DATA_OFF,
+ &id_cert, &id_cert_len))
+ {
+ log_print ("rsa_sig_decode_hash: can not get subject from CERT");
+ return -1;
+ }
+
+ if (id_cert_len != id_len || memcmp (id, id_cert, id_len))
+ {
+ log_print ("rsa_sig_decode_hash: CERT subject does not match ID");
+ free (id_cert);
+ return -1;
+ }
+ free (id_cert);
+
+ if (!handler->cert_get_key (p->p + ISAKMP_CERT_DATA_OFF,
+ GET_ISAKMP_GEN_LENGTH(p->p) -
+ ISAKMP_CERT_DATA_OFF,
+ &key))
+ {
+ log_print ("rsa_sig_decode_hash: decoding payload CERT failed");
+ return -1;
+ }
+
+ p->flags |= PL_MARK;
+
+ p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_SIG]);
+ if (!p)
+ {
+ pkcs_free_public_key (&key);
+ return -1;
+ }
+
+ /* Check that the sig is of the correct size. */
+ if (GET_ISAKMP_GEN_LENGTH (p->p) - ISAKMP_SIG_SZ != mpz_sizeinoctets (key.n))
+ {
+ pkcs_free_public_key (&key);
+ log_print ("rsa_sig_decode_hash: SIG payload length does not match "
+ "public key");
+ return -1;
+ }
+
+ if (!pkcs_rsa_decrypt (PKCS_PRIVATE, key.n, key.e,
+ p->p + ISAKMP_SIG_DATA_OFF, hash_p, &len))
+ {
+ pkcs_free_public_key (&key);
+ return -1;
+ }
+
+ pkcs_free_public_key (&key);
+
+ if (len != hashsize)
+ {
+ free (*hash_p);
+ *hash_p = NULL;
+ return -1;
+ }
+
+ snprintf (header, 80, "rsa_sig_decode_hash: HASH_%c", initiator ? 'R' : 'I');
+ log_debug_buf (LOG_MISC, 80, header, *hash_p, hashsize);
+
+ p->flags |= PL_MARK;
+
+ return 0;
+}
+
+static int
+pre_shared_encode_hash (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ size_t hashsize = ie->hash->hashsize;
+ char header[80];
+ int initiator = exchange->initiator;
+ u_int8_t *buf;
+
+ /* XXX - hashsize is not necessarily prf->blocksize */
+ buf = malloc (ISAKMP_HASH_SZ + hashsize);
+ if (!buf)
+ {
+ /* XXX Log? */
+ return -1;
+ }
+
+ if (ike_auth_hash (exchange, buf + ISAKMP_HASH_DATA_OFF) == -1)
+ {
+ /* XXX Log? */
+ free (buf);
+ return -1;
+ }
+
+ snprintf (header, 80, "pre_shared_encode_hash: HASH_%c",
+ initiator ? 'I' : 'R');
+ log_debug_buf (LOG_MISC, 80, header, buf + ISAKMP_HASH_DATA_OFF, hashsize);
+ if (message_add_payload (msg, ISAKMP_PAYLOAD_HASH, buf,
+ ISAKMP_HASH_SZ + hashsize, 1))
+ {
+ /* XXX Log? */
+ free (buf);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* Encrypt the HASH into a SIG type */
+
+static int
+rsa_sig_encode_hash (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ size_t hashsize = ie->hash->hashsize;
+ struct cert_handler *handler;
+ struct rsa_private_key key;
+ char header[80];
+ int initiator = exchange->initiator;
+ u_int8_t *buf, *asn, *data;
+ u_int32_t asnlen, datalen;
+ char *keyfile;
+
+ /* XXX - this needs to be configureable */
+ handler = cert_get (ISAKMP_CERTENC_X509_SIG);
+ if (handler == NULL)
+ {
+ /* XXX - Log? */
+ return -1;
+ }
+ /* XXX - implicitly uses exchange->id_{i,r} */
+ if (!handler->cert_obtain (exchange, NULL, &data, &datalen))
+ {
+ /* XXX - Log? */
+ return -1;
+ }
+
+ buf = realloc (data, ISAKMP_CERT_SZ + datalen);
+ if (buf == NULL)
+ {
+ /* XXX Log? */
+ free (data);
+ return -1;
+ }
+ memmove (buf + ISAKMP_CERT_SZ, buf, datalen);
+ SET_ISAKMP_CERT_ENCODING (buf, ISAKMP_CERTENC_X509_SIG);
+ if (message_add_payload (msg, ISAKMP_PAYLOAD_CERT, buf,
+ ISAKMP_CERT_SZ + datalen, 1))
+ {
+ /* XXX Log? */
+ free (buf);
+ return -1;
+ }
+
+ /* XXX - do we want to store our files in ASN.1 ? */
+ keyfile = conf_get_str ("rsa_sig", "privkey");
+ if (!asn_get_from_file (keyfile, &asn, &asnlen))
+ {
+ /* XXX Log? */
+ return -1;
+ }
+
+ if (!pkcs_private_key_from_asn (&key, asn, asnlen))
+ {
+ /* XXX Log? */
+ free (asn);
+ return -1;
+ }
+ free (asn);
+
+ /* XXX - hashsize is not necessarily prf->blocksize */
+ buf = malloc (hashsize);
+ if (!buf)
+ {
+ /* XXX Log? */
+ pkcs_free_private_key (&key);
+ return -1;
+ }
+
+ if (ike_auth_hash (exchange, buf) == -1)
+ {
+ /* XXX Log? */
+ free (buf);
+ pkcs_free_private_key (&key);
+ return -1;
+ }
+
+ snprintf (header, 80, "rsa_sig_encode_hash: HASH_%c", initiator ? 'I' : 'R');
+ log_debug_buf (LOG_MISC, 80, header, buf, hashsize);
+
+ if (!pkcs_rsa_encrypt (PKCS_PRIVATE, key.n, key.e, buf, hashsize,
+ &data, &datalen))
+ {
+ free (buf);
+ pkcs_free_private_key (&key);
+ return -1;
+ }
+ pkcs_free_private_key (&key);
+ free (buf);
+
+ buf = realloc (data, ISAKMP_SIG_SZ + datalen);
+ if (!buf)
+ {
+ /* XXX Log? */
+ free (data);
+ return -1;
+ }
+ memmove (buf + ISAKMP_SIG_SZ, buf, datalen);
+
+ snprintf (header, 80, "rsa_sig_encode_hash: SIG_%c", initiator ? 'I' : 'R');
+ log_debug_buf (LOG_MISC, 80, header, buf + ISAKMP_SIG_DATA_OFF, datalen);
+ if (message_add_payload (msg, ISAKMP_PAYLOAD_SIG, buf,
+ ISAKMP_SIG_SZ + datalen, 1))
+ {
+ /* XXX Log? */
+ free (buf);
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+ike_auth_hash (struct exchange *exchange, u_int8_t *buf)
+{
+ struct ipsec_exch *ie = exchange->data;
+ struct prf *prf;
+ struct hash *hash = ie->hash;
+ int initiator = exchange->initiator;
+ u_int8_t *id;
+ size_t id_len;
+
+ /* Choose the right fields to fill-in. */
+ id = initiator ? exchange->id_i : exchange->id_r;
+ id_len = initiator ? exchange->id_i_len : exchange->id_r_len;
+
+ /* Allocate the prf and start calculating our HASH. */
+ prf = prf_alloc (ie->prf_type, hash->type, ie->skeyid, ie->skeyid_len);
+ if (!prf)
+ return -1;
+
+ prf->Init (prf->prfctx);
+ prf->Update (prf->prfctx, initiator ? ie->g_xi : ie->g_xr, ie->g_x_len);
+ prf->Update (prf->prfctx, initiator ? ie->g_xr : ie->g_xi, ie->g_x_len);
+ prf->Update (prf->prfctx,
+ exchange->cookies
+ + (initiator ? ISAKMP_HDR_ICOOKIE_OFF : ISAKMP_HDR_RCOOKIE_OFF),
+ ISAKMP_HDR_ICOOKIE_LEN);
+ prf->Update (prf->prfctx,
+ exchange->cookies
+ + (initiator ? ISAKMP_HDR_RCOOKIE_OFF : ISAKMP_HDR_ICOOKIE_OFF),
+ ISAKMP_HDR_ICOOKIE_LEN);
+ prf->Update (prf->prfctx, ie->sa_i_b, ie->sa_i_b_len);
+ prf->Update (prf->prfctx, id, id_len);
+ prf->Final (buf, prf->prfctx);
+ prf_free (prf);
+
+ return 0;
+}
diff --git a/sbin/isakmpd/ike_auth.h b/sbin/isakmpd/ike_auth.h
new file mode 100644
index 00000000000..79224ff5b09
--- /dev/null
+++ b/sbin/isakmpd/ike_auth.h
@@ -0,0 +1,52 @@
+/* $Id: ike_auth.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _IKE_AUTH_H_
+#define _IKE_AUTH_H_
+
+#include <sys/types.h>
+
+struct exchange;
+
+struct ike_auth {
+ u_int16_t id;
+ u_int8_t *(*gen_skeyid) (struct exchange *, size_t *);
+ int (*decode_hash) (struct message *);
+ int (*encode_hash) (struct message *);
+};
+
+extern struct ike_auth *ike_auth_get (u_int16_t);
+
+#endif /* _IKE_AUTH_H_ */
diff --git a/sbin/isakmpd/ike_main_mode.c b/sbin/isakmpd/ike_main_mode.c
new file mode 100644
index 00000000000..94e8eddac7b
--- /dev/null
+++ b/sbin/isakmpd/ike_main_mode.c
@@ -0,0 +1,883 @@
+/* $Id: ike_main_mode.c,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "attribute.h"
+#include "conf.h"
+#include "constants.h"
+#include "crypto.h"
+#include "dh.h"
+#include "doi.h"
+#include "exchange.h"
+#include "hash.h"
+#include "ike_auth.h"
+#include "ike_main_mode.h"
+#include "ipsec.h"
+#include "ipsec_doi.h"
+#include "isakmp.h"
+#include "log.h"
+#include "math_group.h"
+#include "message.h"
+#include "prf.h"
+#include "sa.h"
+#include "transport.h"
+#include "util.h"
+
+static int initiator_send_SA (struct message *);
+static int initiator_recv_SA (struct message *);
+static int initiator_send_KE_NONCE (struct message *);
+static int initiator_recv_KE_NONCE (struct message *);
+static int initiator_send_ID_AUTH (struct message *);
+static int initiator_recv_ID_AUTH (struct message *);
+static int responder_recv_SA (struct message *);
+static int responder_send_SA (struct message *);
+static int responder_recv_KE_NONCE (struct message *);
+static int responder_send_KE_NONCE (struct message *);
+static int responder_recv_ID_AUTH (struct message *);
+static int responder_send_ID_AUTH (struct message *);
+static int recv_KE_NONCE (struct message *);
+static int recv_ID_AUTH (struct message *);
+static int send_KE_NONCE (struct message *, size_t);
+static int send_ID_AUTH (struct message *);
+static int post_exchange_KE_NONCE (struct message *);
+
+int (*ike_main_mode_initiator[]) (struct message *) = {
+ initiator_send_SA,
+ initiator_recv_SA,
+ initiator_send_KE_NONCE,
+ initiator_recv_KE_NONCE,
+ initiator_send_ID_AUTH,
+ initiator_recv_ID_AUTH
+};
+
+int (*ike_main_mode_responder[]) (struct message *) = {
+ responder_recv_SA,
+ responder_send_SA,
+ responder_recv_KE_NONCE,
+ responder_send_KE_NONCE,
+ responder_recv_ID_AUTH,
+ responder_send_ID_AUTH
+};
+
+/* Offer a set of transforms to the responder. */
+static int
+initiator_send_SA (struct message *msg)
+{
+ struct ipsec_exch *ie = msg->exchange->data;
+ u_int8_t *proposal = 0, *sa_buf = 0, *attr;
+ u_int8_t **transform = 0;
+ size_t transforms_len = 0, proposal_len, sa_len;
+ size_t *transform_len = 0;
+ struct conf_list *conf, *life_conf;
+ struct conf_list_node *xf, *life;
+ int i, value, update_nextp;
+ struct payload *p;
+ struct proto *proto;
+
+ /* Get the list of transforms. */
+ conf = conf_get_list ("Main mode initiator", "Offered-transforms");
+ if (!conf)
+ return -1;
+
+ transform = calloc (conf->cnt, sizeof *transform);
+ if (!transform)
+ goto bail_out;
+ transform_len = calloc (conf->cnt, sizeof *transform_len);
+ if (!transform_len)
+ goto bail_out;
+
+ for (xf = TAILQ_FIRST (&conf->fields), i = 0; i < conf->cnt;
+ i++, xf = TAILQ_NEXT (xf, link))
+ {
+ /* XXX The sizing needs to be dynamic. */
+ transform[i]
+ = malloc (ISAKMP_TRANSFORM_SA_ATTRS_OFF + 16 * ISAKMP_ATTR_VALUE_OFF);
+ if (!transform[i])
+ goto bail_out;
+ SET_ISAKMP_TRANSFORM_NO (transform[i], i);
+ SET_ISAKMP_TRANSFORM_ID (transform[i], IPSEC_TRANSFORM_KEY_IKE);
+ SET_ISAKMP_TRANSFORM_RESERVED (transform[i], 0);
+
+ attr = transform[i] + ISAKMP_TRANSFORM_SA_ATTRS_OFF;
+
+ if (attribute_set_constant (xf->field, "ENCRYPTION_ALGORITHM",
+ ike_encrypt_cst,
+ IKE_ATTR_ENCRYPTION_ALGORITHM, &attr))
+ goto bail_out;
+
+ if (attribute_set_constant (xf->field, "HASH_ALGORITHM", ike_hash_cst,
+ IKE_ATTR_HASH_ALGORITHM, &attr))
+ goto bail_out;
+
+ if (attribute_set_constant (xf->field, "AUTHENTICATION_METHOD",
+ ike_auth_cst, IKE_ATTR_AUTHENTICATION_METHOD,
+ &attr))
+ goto bail_out;
+
+ if (attribute_set_constant (xf->field, "GROUP_DESCRIPTION",
+ ike_group_desc_cst,
+ IKE_ATTR_GROUP_DESCRIPTION, &attr))
+ {
+ /*
+ * If no group description exists, try looking for a user-defined
+ * one.
+ */
+ if (attribute_set_constant (xf->field, "GROUP_TYPE", ike_group_cst,
+ IKE_ATTR_GROUP_TYPE, &attr))
+ goto bail_out;
+
+#if 0
+ if (attribute_set_bignum (xf->field, "GROUP_PRIME",
+ IKE_ATTR_GROUP_PRIME, &attr))
+ goto bail_out;
+
+ if (attribute_set_bignum (xf->field, "GROUP_GENERATOR_2",
+ IKE_ATTR_GROUP_GENERATOR_2, &attr))
+ goto bail_out;
+
+ if (attribute_set_bignum (xf->field, "GROUP_GENERATOR_2",
+ IKE_ATTR_GROUP_GENERATOR_2, &attr))
+ goto bail_out;
+
+ if (attribute_set_bignum (xf->field, "GROUP_CURVE_A",
+ IKE_ATTR_GROUP_CURVE_A, &attr))
+ goto bail_out;
+
+ if (attribute_set_bignum (xf->field, "GROUP_CURVE_B",
+ IKE_ATTR_GROUP_CURVE_B, &attr))
+ goto bail_out;
+#endif
+ }
+
+ /*
+ * Life durations are special, we should be able to specify
+ * several, one per type.
+ */
+ life_conf = conf_get_list (xf->field, "Life");
+ if (life_conf)
+ {
+ for (life = TAILQ_FIRST (&life_conf->fields); life;
+ life = TAILQ_NEXT (life, link))
+ {
+ attribute_set_constant (life->field, "LIFE_TYPE",
+ ike_duration_cst, IKE_ATTR_LIFE_TYPE,
+ &attr);
+
+ /* XXX Does only handle 16-bit entities! */
+ value = conf_get_num (life->field, "LIFE_DURATION");
+ if (value)
+ attr
+ = attribute_set_basic (attr, IKE_ATTR_LIFE_DURATION, value);
+ }
+ }
+
+ attribute_set_constant (xf->field, "PRF", ike_prf_cst, IKE_ATTR_PRF,
+ &attr);
+
+ value = conf_get_num (xf->field, "KEY_LENGTH");
+ if (value)
+ attr = attribute_set_basic (attr, IKE_ATTR_KEY_LENGTH, value);
+
+ value = conf_get_num (xf->field, "FIELD_SIZE");
+ if (value)
+ attr = attribute_set_basic (attr, IKE_ATTR_FIELD_SIZE, value);
+
+ value = conf_get_num (xf->field, "GROUP_ORDER");
+ if (value)
+ attr = attribute_set_basic (attr, IKE_ATTR_GROUP_ORDER, value);
+
+ /* Record the real transform size. */
+ transforms_len += transform_len[i] = attr - transform[i];
+ }
+
+ proposal_len = ISAKMP_PROP_SPI_OFF;
+ proposal = malloc (proposal_len);
+ if (!proposal)
+ goto bail_out;
+ SET_ISAKMP_PROP_NO (proposal, 1);
+ SET_ISAKMP_PROP_PROTO (proposal, ISAKMP_PROTO_ISAKMP);
+ SET_ISAKMP_PROP_SPI_SZ (proposal, 0);
+ SET_ISAKMP_PROP_NTRANSFORMS (proposal, conf->cnt);
+
+ /* XXX I would like to see this factored out. */
+ proto = calloc (1, sizeof *proto);
+ if (!proto)
+ goto bail_out;
+ proto->no = 1;
+ proto->proto = ISAKMP_PROTO_ISAKMP;
+ proto->sa = TAILQ_FIRST (&msg->exchange->sa_list);
+ TAILQ_INSERT_TAIL (&TAILQ_FIRST (&msg->exchange->sa_list)->protos, proto,
+ link);
+
+ sa_len = ISAKMP_SA_SIT_OFF + IPSEC_SIT_SIT_LEN;
+ sa_buf = malloc (sa_len);
+ if (!sa_buf)
+ goto bail_out;
+ SET_ISAKMP_SA_DOI (sa_buf, IPSEC_DOI_IPSEC);
+ SET_IPSEC_SIT_SIT (sa_buf + ISAKMP_SA_SIT_OFF, IPSEC_SIT_IDENTITY_ONLY);
+
+ /*
+ * Add the payloads. As this is a SA, we need to recompute the
+ * lengths of the payloads containing others.
+ */
+ if (message_add_payload (msg, ISAKMP_PAYLOAD_SA, sa_buf, sa_len, 1))
+ goto bail_out;
+ SET_ISAKMP_GEN_LENGTH (sa_buf,
+ sa_len + proposal_len + transforms_len);
+ sa_buf = 0;
+
+ if (message_add_payload (msg, ISAKMP_PAYLOAD_PROPOSAL, proposal,
+ proposal_len, 0))
+ goto bail_out;
+ SET_ISAKMP_GEN_LENGTH (proposal, proposal_len + transforms_len);
+ proposal = 0;
+
+ update_nextp = 0;
+ for (i = 0; i < conf->cnt; i++)
+ {
+ if (message_add_payload (msg, ISAKMP_PAYLOAD_TRANSFORM, transform[i],
+ transform_len[i], update_nextp))
+ goto bail_out;
+ update_nextp = 1;
+ transform[i] = 0;
+ }
+
+ /* Save SA payload body in ie->sa_i_b, length ie->sa_i_b_len. */
+ ie->sa_i_b_len = sa_len + proposal_len + transforms_len - ISAKMP_GEN_SZ;
+ ie->sa_i_b = malloc (ie->sa_i_b_len);
+ if (!ie->sa_i_b)
+ goto bail_out;
+ memcpy (ie->sa_i_b,
+ TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_SA])->p + ISAKMP_GEN_SZ,
+ sa_len - ISAKMP_GEN_SZ);
+ memcpy (ie->sa_i_b + sa_len - ISAKMP_GEN_SZ,
+ TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_PROPOSAL])->p,
+ proposal_len);
+ transforms_len = 0;
+ for (i = 0, p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_TRANSFORM]);
+ i < conf->cnt; i++, p = TAILQ_NEXT (p, link))
+ {
+ memcpy (ie->sa_i_b + sa_len + proposal_len + transforms_len
+ - ISAKMP_GEN_SZ,
+ p->p, transform_len[i]);
+ transforms_len += transform_len[i];
+ }
+
+ return 0;
+
+ bail_out:
+ if (sa_buf)
+ free (sa_buf);
+ if (proposal)
+ free (proposal);
+ if (transform)
+ {
+ for (i = 0; i < conf->cnt; i++)
+ if (transform[i])
+ free (transform[i]);
+ free (transform);
+ }
+ if (transform_len)
+ free (transform_len);
+ if (conf)
+ conf_free_list (conf);
+ return -1;
+}
+
+/* Figure out what transform the responder chose. */
+static int
+initiator_recv_SA (struct message *msg)
+{
+ struct sa *sa;
+ struct proto *proto;
+ struct payload *sa_p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_SA]);
+ struct payload *prop = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_PROPOSAL]);
+ struct payload *xf = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_TRANSFORM]);
+
+ /*
+ * IKE requires that only one SA with only one proposal exists and since
+ * we are getting an answer on our transform offer, only one transform.
+ */
+ if (TAILQ_NEXT (sa_p, link) || TAILQ_NEXT (prop, link)
+ || TAILQ_NEXT (xf, link))
+ {
+ log_print ("initiator_recv_SA: "
+ "multiple SA, proposal or transform payloads in main mode");
+ /* XXX Is there a better notification type? */
+ message_drop (msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 0, 0);
+ return -1;
+ }
+
+ sa = TAILQ_FIRST (&msg->exchange->sa_list);
+
+ /* Build the protection suite in our SA. */
+ if (sa_add_transform (sa, xf, msg->exchange->initiator, &proto))
+ {
+ /* XXX Log? */
+ return -1;
+ }
+
+ /* XXX Check that the chosen transform matches an offer. */
+ ipsec_decode_transform (msg, sa, TAILQ_FIRST (&sa->protos), xf->p);
+
+ /* Mark the SA as handled. */
+ sa_p->flags |= PL_MARK;
+ return 0;
+}
+
+/* Send our public DH value and a nonce to the responder. */
+static int
+initiator_send_KE_NONCE (struct message *msg)
+{
+ struct ipsec_exch *ie = msg->exchange->data;
+
+ ie->g_x_len = dh_getlen (ie->group);
+
+ /* XXX I want a better way to specify the nonce's size. */
+ return send_KE_NONCE (msg, 16);
+}
+
+/* Accept receptor's public DH value and nonce. */
+static int
+initiator_recv_KE_NONCE (struct message *msg)
+{
+ if (recv_KE_NONCE (msg))
+ return -1;
+
+ return post_exchange_KE_NONCE (msg);
+}
+
+static int
+initiator_send_ID_AUTH (struct message *msg)
+{
+ msg->exchange->flags |= EXCHANGE_FLAG_ENCRYPT;
+ return send_ID_AUTH (msg);
+}
+
+static int
+initiator_recv_ID_AUTH (struct message *msg)
+{
+ return recv_ID_AUTH (msg);
+}
+
+/*
+ * Accept a set of transforms offered by the initiator and chose one we can
+ * handle.
+ */
+static int
+responder_recv_SA (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct sa *sa = TAILQ_FIRST (&exchange->sa_list);
+ struct payload *sa_p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_SA]);
+ struct payload *prop = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_PROPOSAL]);
+ struct ipsec_exch *ie = exchange->data;
+
+ /* Mark the SA as handled. */
+ sa_p->flags |= PL_MARK;
+
+ /* IKE requires that only one SA with only one proposal exists. */
+ if (TAILQ_NEXT (sa_p, link) || TAILQ_NEXT (prop, link))
+ {
+ log_print ("responder_recv_SA: "
+ "multiple SA or proposal payloads in main mode");
+ /* XXX Is there a better notification type? */
+ message_drop (msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 0, 0);
+ return -1;
+ }
+
+ /* Chose a transform from the SA. */
+ if (message_negotiate_sa (msg) || !TAILQ_FIRST (&sa->protos))
+ return -1;
+
+ /* XXX Move into message_negotiate_sa? */
+ ipsec_decode_transform (msg, sa, TAILQ_FIRST (&sa->protos),
+ TAILQ_FIRST (&sa->protos)->chosen->p);
+
+ /*
+ * Check that the mandatory attributes: encryption, hash, authentication
+ * method and Diffie-Hellman group description, has been supplied.
+ */
+ if (!exchange->crypto || !ie->hash || !ie->ike_auth || !ie->group)
+ {
+ message_drop (msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 0, 0);
+ return -1;
+ }
+
+ /* Save the body for later hash computation. */
+ ie->sa_i_b_len = GET_ISAKMP_GEN_LENGTH (sa_p->p) - ISAKMP_GEN_SZ;
+ ie->sa_i_b = malloc (ie->sa_i_b_len);
+ if (!ie->sa_i_b)
+ {
+ /* XXX How to log and notify peer? */
+ return -1;
+ }
+ memcpy (ie->sa_i_b, sa_p->p + ISAKMP_GEN_SZ, ie->sa_i_b_len);
+
+ return 0;
+}
+
+/* Reply with the transform we chose. */
+static int
+responder_send_SA (struct message *msg)
+{
+ /* Add the SA payload with the transform that was chosen. */
+ return message_add_sa_payload (msg);
+}
+
+/* Accept initiator's public DH value and nonce. */
+static int
+responder_recv_KE_NONCE (struct message *msg)
+{
+ return recv_KE_NONCE (msg);
+}
+
+/* Send our public DH value and a nonce to the initiator. */
+static int
+responder_send_KE_NONCE (struct message *msg)
+{
+ /* XXX Should we really just use the initiator's nonce size? */
+ if (send_KE_NONCE (msg, msg->exchange->nonce_i_len))
+ return -1;
+
+ /*
+ * Calculate DH values & key material in parallel with the message going
+ * on a roundtrip over the wire.
+ */
+ message_register_post_send (msg,
+ (void (*) (struct message *))
+ post_exchange_KE_NONCE);
+
+ return 0;
+}
+
+/* Receive ID and HASH and check that the exchange has been consistent. */
+static int
+responder_recv_ID_AUTH (struct message *msg)
+{
+ return recv_ID_AUTH (msg);
+}
+
+static int
+responder_send_ID_AUTH (struct message *msg)
+{
+ return send_ID_AUTH (msg);
+}
+
+/* Send our public DH value and a nonce to the peer. */
+static int
+send_KE_NONCE (struct message *msg, size_t nonce_sz)
+{
+ /* Public DH key. */
+ if (ipsec_gen_g_x (msg))
+ {
+ /* XXX How to log and notify peer? */
+ return -1;
+ }
+
+ /* Generate a nonce, and add it to the message. */
+ if (exchange_gen_nonce (msg, nonce_sz))
+ {
+ /* XXX Log? */
+ return -1;
+ }
+
+ /* Try to add certificates which are acceptable for the CERTREQs */
+ if (exchange_add_certs (msg))
+ {
+ /* XXX Log? */
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Receive our peer's public DH value and nonce. */
+static int
+recv_KE_NONCE (struct message *msg)
+{
+ /* Copy out the initiator's DH public value. */
+ if (ipsec_save_g_x (msg))
+ {
+ /* XXX How to log and notify peer? */
+ return -1;
+ }
+
+ /* Copy out the initiator's nonce. */
+ if (exchange_save_nonce (msg))
+ {
+ /* XXX How to log and notify peer? */
+ return -1;
+ }
+
+ /* Copy out the initiator's cert requests. */
+ if (exchange_save_certreq (msg))
+ {
+ /* XXX How to log and notify peer? */
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Compute DH values and key material. This is done in a post-send function
+ * as that means we can do parallel work in both the initiator and responder
+ * thus speeding up exchanges.
+ */
+static int
+post_exchange_KE_NONCE (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ struct prf *prf;
+ struct hash *hash = ie->hash;
+ enum cryptoerr err;
+
+ /* Compute Diffie-Hellman shared value. */
+ ie->g_xy = malloc (ie->g_x_len);
+ if (!ie->g_xy)
+ {
+ /* XXX How to log and notify peer? */
+ return -1;
+ }
+ dh_create_shared (ie->group, ie->g_xy,
+ exchange->initiator ? ie->g_xr : ie->g_xi);
+ log_debug_buf (LOG_MISC, 80, "post_exchange_KE_NONCE: g^xy", ie->g_xy,
+ ie->g_x_len);
+
+ /* Compute the SKEYID depending on the authentication method. */
+ ie->skeyid = ie->ike_auth->gen_skeyid (exchange, &ie->skeyid_len);
+ if (!ie->skeyid)
+ {
+ /* XXX Log and teardown? */
+ return -1;
+ }
+ log_debug_buf (LOG_MISC, 80, "post_exchange_KE_NONCE: SKEYID",
+ ie->skeyid, ie->skeyid_len);
+
+ /* SKEYID_d. */
+ ie->skeyid_d = malloc (ie->skeyid_len);
+ if (!ie->skeyid_d)
+ {
+ /* XXX Log and teardown? */
+ return -1;
+ }
+ prf = prf_alloc (ie->prf_type, hash->type, ie->skeyid,
+ ie->skeyid_len);
+ if (!prf)
+ {
+ /* XXX Log and teardown? */
+ return -1;
+ }
+ prf->Init (prf->prfctx);
+ prf->Update (prf->prfctx, ie->g_xy, ie->g_x_len);
+ prf->Update (prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN);
+ prf->Update (prf->prfctx, "\0", 1);
+ prf->Final (ie->skeyid_d, prf->prfctx);
+ log_debug_buf (LOG_MISC, 80, "post_exchange_KE_NONCE: SKEYID_d",
+ ie->skeyid_d, ie->skeyid_len);
+
+ /* SKEYID_a. */
+ ie->skeyid_a = malloc (ie->skeyid_len);
+ if (!ie->skeyid_a)
+ {
+ /* XXX Log & teardown? */
+ prf_free (prf);
+ return -1;
+ }
+ prf->Init (prf->prfctx);
+ prf->Update (prf->prfctx, ie->skeyid_d, ie->skeyid_len);
+ prf->Update (prf->prfctx, ie->g_xy, ie->g_x_len);
+ prf->Update (prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN);
+ prf->Update (prf->prfctx, "\1", 1);
+ prf->Final (ie->skeyid_a, prf->prfctx);
+ log_debug_buf (LOG_MISC, 80, "post_exchange_KE_NONCE: SKEYID_a",
+ ie->skeyid_a, ie->skeyid_len);
+
+ /* SKEYID_e. */
+ ie->skeyid_e = malloc (ie->skeyid_len);
+ if (!ie->skeyid_e)
+ {
+ /* XXX Log and teardown? */
+ prf_free (prf);
+ return -1;
+ }
+ prf->Init (prf->prfctx);
+ prf->Update (prf->prfctx, ie->skeyid_a, ie->skeyid_len);
+ prf->Update (prf->prfctx, ie->g_xy, ie->g_x_len);
+ prf->Update (prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN);
+ prf->Update (prf->prfctx, "\2", 1);
+ prf->Final (ie->skeyid_e, prf->prfctx);
+ prf_free (prf);
+ log_debug_buf (LOG_MISC, 80, "post_exchange_KE_NONCE: SKEYID_e",
+ ie->skeyid_e, ie->skeyid_len);
+
+ /* Key length determination. */
+ if (!exchange->key_length)
+ exchange->key_length = exchange->crypto->keymax;
+
+ /* Derive a longer key from skeyid_e */
+ if (ie->skeyid_len < exchange->key_length)
+ {
+ u_int16_t len, keylen;
+ u_int8_t *key, *p;
+
+ prf = prf_alloc (ie->prf_type, hash->type, ie->skeyid_e, ie->skeyid_len);
+ if (!prf)
+ {
+ /* XXX - notify peer */
+ return -1;
+ }
+
+ /* Make keylen a multiple of prf->blocksize */
+ keylen = exchange->key_length;
+ if (keylen % prf->blocksize)
+ keylen += prf->blocksize - (keylen % prf->blocksize);
+
+ if ((key = malloc (keylen)) == NULL)
+ {
+ /* XXX - notify peer */
+ return -1;
+ }
+
+ prf->Init (prf->prfctx);
+ prf->Update (prf->prfctx, "\0", 1);
+ prf->Final (key, prf->prfctx);
+
+ for (len = prf->blocksize, p = key; len < exchange->key_length;
+ len += prf->blocksize, p += prf->blocksize)
+ {
+ prf->Init (prf->prfctx);
+ prf->Update (prf->prfctx, p, prf->blocksize);
+ prf->Final (p + prf->blocksize, prf->prfctx);
+ }
+ prf_free (prf);
+
+ /* Set up our keystate using the derived encryption key */
+ exchange->keystate
+ = crypto_init (exchange->crypto, key, exchange->key_length, &err);
+
+ free (key);
+ }
+ else
+ /* Set up our keystate using the raw skeyid_e */
+ exchange->keystate = crypto_init (exchange->crypto, ie->skeyid_e,
+ exchange->key_length, &err);
+ /* Special handling for DES weak keys */
+ if (!exchange->keystate && err == EWEAKKEY
+ && (exchange->key_length << 1) <= ie->skeyid_len)
+ {
+ log_print ("post_exchange_KE_NONCE: weak key, trying subseq. skeyid_e");
+ exchange->keystate = crypto_init (exchange->crypto,
+ ie->skeyid_e + exchange->key_length,
+ exchange->key_length, &err);
+ }
+
+ if (!exchange->keystate)
+ {
+ log_print ("post_exchange_KE_NONCE: "
+ "exchange->crypto->init () failed: %d", err);
+
+ /*
+ * XXX We really need to know if problems are of transient nature
+ * or fatal (like failed assertions etc.)
+ */
+ return -1;
+ }
+
+ /* Setup IV. XXX Only for CBC transforms, no? */
+ hash->Init (hash->ctx);
+ hash->Update (hash->ctx, ie->g_xi, ie->g_x_len);
+ hash->Update (hash->ctx, ie->g_xr, ie->g_x_len);
+ hash->Final (hash->digest, hash->ctx);
+ crypto_init_iv (exchange->keystate, hash->digest,
+ exchange->crypto->blocksize);
+
+ return 0;
+}
+
+static int
+send_ID_AUTH (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ u_int8_t *buf;
+ char header[80];
+ size_t sz;
+ struct sockaddr *src;
+ int src_len;
+ int initiator = exchange->initiator;
+ u_int8_t **id;
+ size_t *id_len;
+
+ /* Choose the right fields to fill-in. */
+ id = initiator ? &exchange->id_i : &exchange->id_r;
+ id_len = initiator ? &exchange->id_i_len : &exchange->id_r_len;
+
+ /* XXX This begs to be more dynamic. */
+ sz = ISAKMP_ID_DATA_OFF + 4;
+ buf = malloc (sz);
+ if (!buf)
+ {
+ /* XXX Log? */
+ return -1;
+ }
+ msg->transport->vtbl->get_src (msg->transport, &src, &src_len);
+ /* XXX Assumes IPv4. */
+ SET_ISAKMP_ID_TYPE (buf, IPSEC_ID_IPV4_ADDR);
+ SET_IPSEC_ID_PROTO (buf + ISAKMP_ID_DOI_DATA_OFF, 0);
+ SET_IPSEC_ID_PORT (buf + ISAKMP_ID_DOI_DATA_OFF, 0);
+ /* Already in network byteorder. */
+ memcpy (buf + ISAKMP_ID_DATA_OFF,
+ &((struct sockaddr_in *)src)->sin_addr.s_addr, sizeof (in_addr_t));
+ if (message_add_payload (msg, ISAKMP_PAYLOAD_ID, buf, sz, 1))
+ {
+ /* XXX Log? */
+ free (buf);
+ return -1;
+ }
+ *id_len = sz - ISAKMP_GEN_SZ;
+ *id = malloc (*id_len);
+ if (!*id)
+ {
+ /* XXX Log? */
+ return -1;
+ }
+ memcpy (*id, buf + ISAKMP_GEN_SZ, *id_len);
+ snprintf (header, 80, "send_ID_AUTH: %s",
+ constant_name (ipsec_id_cst, GET_ISAKMP_ID_TYPE (buf)));
+ log_debug_buf (LOG_MISC, 40, header, buf + ISAKMP_ID_DATA_OFF,
+ sz - ISAKMP_ID_DATA_OFF);
+
+ if (ie->ike_auth->encode_hash (msg) == -1)
+ {
+ /* XXX Log? */
+ return -1;
+ }
+
+ /*
+ * XXX Many people say the COMMIT flag is just junk, especially in Phase 1.
+ */
+#ifdef notyet
+ if ((exchange->flags & EXCHANGE_FLAG_COMMITTED) == 0)
+ exchange->flags |= EXCHANGE_FLAG_I_COMMITTED;
+#endif
+
+ return 0;
+}
+
+/* Receive ID and HASH and check that the exchange has been consistent. */
+static int
+recv_ID_AUTH (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ struct payload *payload;
+ struct prf *prf;
+ struct hash *hash = ie->hash;
+ char header[80];
+ size_t hashsize = hash->hashsize;
+ int initiator = exchange->initiator;
+ u_int8_t **hash_p, **id;
+ size_t *id_len;
+
+ /* Choose the right fields to fill in */
+ hash_p = initiator ? &ie->hash_r : &ie->hash_i;
+ id = initiator ? &exchange->id_r : &exchange->id_i;
+ id_len = initiator ? &exchange->id_r_len : &exchange->id_i_len;
+
+ /* XXX Do I really have to save the ID in the SA? */
+ payload = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_ID]);
+ *id_len = GET_ISAKMP_GEN_LENGTH (payload->p) - ISAKMP_GEN_SZ;
+ *id = malloc (*id_len);
+ if (!*id)
+ {
+ /* XXX Log? */
+ return -1;
+ }
+ memcpy (*id, payload->p + ISAKMP_GEN_SZ, *id_len);
+ snprintf (header, 80, "recv_ID_AUTH: %s",
+ constant_name (ipsec_id_cst, GET_ISAKMP_ID_TYPE (payload->p)));
+ log_debug_buf (LOG_MISC, 40, header, payload->p + ISAKMP_ID_DATA_OFF,
+ *id_len + ISAKMP_GEN_SZ - ISAKMP_ID_DATA_OFF);
+ payload->flags |= PL_MARK;
+
+ /* The decoded hash will be in ie->hash_r or ie->hash_i */
+ if (ie->ike_auth->decode_hash (msg) == -1)
+ {
+ message_drop (msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 0, 0);
+ return -1;
+ }
+
+ /* Allocate the prf and start calculating his HASH. */
+ prf = prf_alloc (ie->prf_type, hash->type, ie->skeyid, ie->skeyid_len);
+ if (!prf)
+ {
+ /* XXX Log? */
+ return -1;
+ }
+ prf->Init (prf->prfctx);
+ prf->Update (prf->prfctx, initiator ? ie->g_xr : ie->g_xi, ie->g_x_len);
+ prf->Update (prf->prfctx, initiator ? ie->g_xi : ie->g_xr, ie->g_x_len);
+ prf->Update (prf->prfctx,
+ exchange->cookies
+ + (initiator ? ISAKMP_HDR_RCOOKIE_OFF : ISAKMP_HDR_ICOOKIE_OFF),
+ ISAKMP_HDR_ICOOKIE_LEN);
+ prf->Update (prf->prfctx,
+ exchange->cookies
+ + (initiator ? ISAKMP_HDR_ICOOKIE_OFF : ISAKMP_HDR_RCOOKIE_OFF),
+ ISAKMP_HDR_ICOOKIE_LEN);
+ prf->Update (prf->prfctx, ie->sa_i_b, ie->sa_i_b_len);
+ prf->Update (prf->prfctx, *id, *id_len);
+ prf->Final (hash->digest, prf->prfctx);
+ prf_free (prf);
+ snprintf (header, 80, "recv_ID_AUTH: computed HASH_%c",
+ initiator ? 'R' : 'I');
+ log_debug_buf (LOG_MISC, 80, header, hash->digest, hashsize);
+
+ /* Check that the hash we got matches the one we computed. */
+ if (memcmp (*hash_p, hash->digest, hashsize) != 0)
+ {
+ /* XXX Log? */
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/sbin/isakmpd/ike_main_mode.h b/sbin/isakmpd/ike_main_mode.h
new file mode 100644
index 00000000000..68d38b26074
--- /dev/null
+++ b/sbin/isakmpd/ike_main_mode.h
@@ -0,0 +1,44 @@
+/* $Id: ike_main_mode.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _IKE_MAIN_MODE_H_
+#define _IKE_MAIN_MODE_H_
+
+struct message;
+
+extern int (*ike_main_mode_initiator[]) (struct message *msg);
+extern int (*ike_main_mode_responder[]) (struct message *msg);
+
+#endif /* _IKE_MAIN_MODE_H_ */
diff --git a/sbin/isakmpd/ike_quick_mode.c b/sbin/isakmpd/ike_quick_mode.c
new file mode 100644
index 00000000000..0f566c6bbe0
--- /dev/null
+++ b/sbin/isakmpd/ike_quick_mode.c
@@ -0,0 +1,1069 @@
+/* $Id: ike_quick_mode.c,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "attribute.h"
+#include "conf.h"
+#include "dh.h"
+#include "doi.h"
+#include "exchange.h"
+#include "hash.h"
+#include "ike_quick_mode.h"
+#include "ipsec.h"
+#include "log.h"
+#include "math_group.h"
+#include "message.h"
+#include "prf.h"
+#include "sa.h"
+#include "transport.h"
+
+static void gen_g_xy (struct message *);
+static int initiator_send_HASH_SA_NONCE (struct message *);
+static int initiator_recv_HASH_SA_NONCE (struct message *);
+static int initiator_send_HASH (struct message *);
+static void post_quick_mode (struct message *);
+static int responder_recv_HASH_SA_NONCE (struct message *);
+static int responder_send_HASH_SA_NONCE (struct message *);
+static int responder_recv_HASH (struct message *);
+
+int (*ike_quick_mode_initiator[]) (struct message *) = {
+ initiator_send_HASH_SA_NONCE,
+ initiator_recv_HASH_SA_NONCE,
+ initiator_send_HASH
+};
+
+int (*ike_quick_mode_responder[]) (struct message *) = {
+ responder_recv_HASH_SA_NONCE,
+ responder_send_HASH_SA_NONCE,
+ responder_recv_HASH
+};
+
+/*
+ * Offer several sets of transforms to the responder.
+ * XXX Split this huge function up and look for common code with main mode.
+ */
+static int
+initiator_send_HASH_SA_NONCE (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct doi *doi = exchange->doi;
+ struct ipsec_exch *ie = exchange->data;
+ struct sa *isakmp_sa = msg->isakmp_sa;
+ struct ipsec_sa *isa = isakmp_sa->data;
+ u_int8_t ***transform = 0, ***new_transform;
+ u_int8_t **proposal = 0, **new_proposal;
+ u_int8_t *sa_buf = 0, *attr, *saved_nextp_sa, *saved_nextp_prop;
+ u_int8_t *buf;
+ u_int8_t *spi;
+ size_t spi_sz;
+ struct prf *prf;
+ struct hash *hash = hash_get (isa->hash);
+ size_t hashsize = hash->hashsize;
+ size_t proposal_len = 0, proposals_len = 0, sa_len;
+ size_t **transform_len = 0, **new_transform_len;
+ size_t *transforms_len = 0, *new_transforms_len;
+ int *transform_cnt = 0, *new_transform_cnt;
+ char header[80];
+ int i, suite_no, prop_no, prot_no, xf_no, value, update_nextp, protocol_num;
+ int prop_cnt = 0;
+ struct proto *proto;
+ struct conf_list *suite_conf = 0, *prot_conf = 0, *xf_conf = 0, *life_conf;
+ struct conf_list_node *suite, *prot, *xf, *life;
+ struct constant_map *id_map;
+ char *protocol_id, *transform_id;
+
+ /* We want a HASH payload to start with. XXX Share with ike_main_mode.c? */
+ buf = malloc (ISAKMP_HASH_SZ + hashsize);
+ if (!buf)
+ {
+ /* XXX Log? */
+ return -1;
+ }
+ if (message_add_payload (msg, ISAKMP_PAYLOAD_HASH, buf,
+ ISAKMP_HASH_SZ + hashsize, 1))
+ {
+ /* XXX Log? */
+ free (buf);
+ return -1;
+ }
+
+ /* Get the list of protocol suites. */
+ suite_conf = conf_get_list ("Quick mode initiator", "Offered-suites");
+ if (!suite_conf)
+ return -1;
+
+ for (suite = TAILQ_FIRST (&suite_conf->fields), suite_no = prop_no = 0;
+ suite_no < suite_conf->cnt;
+ suite_no++, suite = TAILQ_NEXT (suite, link))
+ {
+ /* Now get each protocol in this specific protocol suite. */
+ prot_conf = conf_get_list (suite->field, "Protocols");
+ if (!prot_conf)
+ goto bail_out;
+
+ for (prot = TAILQ_FIRST (&prot_conf->fields), prot_no = 0;
+ prot_no < prot_conf->cnt;
+ prot_no++, prot = TAILQ_NEXT (prot, link))
+ {
+ /* Make sure we have a proposal/transform vectors. */
+ if (prop_no >= prop_cnt)
+ {
+ /* This resize algorithm is completely arbitrary. */
+ prop_cnt = 2 * prop_cnt + 10;
+ new_proposal = realloc (proposal, prop_cnt * sizeof *proposal);
+ if (!new_proposal)
+ goto bail_out;
+ proposal = new_proposal;
+
+ new_transforms_len = realloc (transforms_len,
+ prop_cnt * sizeof *transforms_len);
+ if (!new_transforms_len)
+ goto bail_out;
+ transforms_len = new_transforms_len;
+
+ new_transform = realloc (transform,
+ prop_cnt * sizeof *transform);
+ if (!new_transform)
+ goto bail_out;
+ transform = new_transform;
+
+ new_transform_cnt = realloc (transform_cnt,
+ prop_cnt * sizeof *transform_cnt);
+ if (!new_transform_cnt)
+ goto bail_out;
+ transform_cnt = new_transform_cnt;
+
+ new_transform_len = realloc (transform_len,
+ prop_cnt * sizeof *transform_len);
+ if (!new_transform_len)
+ goto bail_out;
+ transform_len = new_transform_len;
+ }
+
+ protocol_id = conf_get_str (prot->field, "PROTOCOL_ID");
+ if (!protocol_id)
+ goto bail_out;
+
+ /* XXX Not too beautiful, but do we have a choice? */
+ id_map = strcasecmp (protocol_id, "IPSEC_AH") == 0 ? ipsec_ah_cst
+ : strcasecmp (protocol_id, "IPSEC_ESP") == 0 ? ipsec_esp_cst
+ : strcasecmp (protocol_id, "IPCOMP") == 0 ? ipsec_ipcomp_cst : 0;
+ if (!id_map)
+ goto bail_out;
+
+ /* Now get each transform we offer for this protocol. */
+ xf_conf = conf_get_list (prot->field, "Transforms");
+ if (!xf_conf)
+ goto bail_out;
+ transform_cnt[prop_no] = xf_conf->cnt;
+
+ transform[prop_no] = calloc (transform_cnt[prop_no],
+ sizeof **transform);
+ if (!transform[prop_no])
+ goto bail_out;
+ transform_len[prop_no]
+ = calloc (transform_cnt[prop_no], sizeof **transform_len);
+ if (!transform_len[prop_no])
+ goto bail_out;
+
+ transforms_len[prop_no] = 0;
+ for (xf = TAILQ_FIRST (&xf_conf->fields), xf_no = 0;
+ xf_no < transform_cnt[prop_no];
+ xf_no++, xf = TAILQ_NEXT (xf, link))
+ {
+
+ /* XXX The sizing needs to be dynamic. */
+ transform[prop_no][xf_no] = calloc (ISAKMP_TRANSFORM_SA_ATTRS_OFF
+ + 9 * ISAKMP_ATTR_VALUE_OFF,
+ 1);
+ if (!transform[prop_no][xf_no])
+ goto bail_out;
+ SET_ISAKMP_TRANSFORM_NO (transform[prop_no][xf_no], xf_no + 1);
+
+ transform_id = conf_get_str (xf->field, "TRANSFORM_ID");
+ if (!transform_id)
+ goto bail_out;
+ SET_ISAKMP_TRANSFORM_ID (transform[prop_no][xf_no],
+ constant_value (id_map, transform_id));
+ SET_ISAKMP_TRANSFORM_RESERVED (transform[prop_no][xf_no], 0);
+
+ attr = transform[prop_no][xf_no] + ISAKMP_TRANSFORM_SA_ATTRS_OFF;
+
+ /*
+ * Life durations are special, we should be able to specify
+ * several, one per type.
+ */
+ life_conf = conf_get_list (xf->field, "Life");
+ if (life_conf)
+ {
+ for (life = TAILQ_FIRST (&life_conf->fields); life;
+ life = TAILQ_NEXT (life, link))
+ {
+ attribute_set_constant (life->field, "SA_LIFE_TYPE",
+ ipsec_duration_cst,
+ IPSEC_ATTR_SA_LIFE_TYPE, &attr);
+
+ /* XXX Does only handle 16-bit entities! */
+ value = conf_get_num (life->field, "SA_LIFE_DURATION");
+ if (value)
+ attr
+ = attribute_set_basic (attr,
+ IPSEC_ATTR_SA_LIFE_DURATION,
+ value);
+ }
+ }
+
+ attribute_set_constant (xf->field, "ENCAPSULATION_MODE",
+ ipsec_encap_cst,
+ IPSEC_ATTR_ENCAPSULATION_MODE, &attr);
+
+ attribute_set_constant (xf->field, "AUTHENTICATION_ALGORITHM",
+ ipsec_auth_cst,
+ IPSEC_ATTR_AUTHENTICATION_ALGORITHM,
+ &attr);
+
+ attribute_set_constant (xf->field, "GROUP_DESCRIPTION",
+ ike_group_desc_cst,
+ IKE_ATTR_GROUP_DESCRIPTION, &attr);
+
+ value = conf_get_num (xf->field, "KEY_LENGTH");
+ if (value)
+ attr = attribute_set_basic (attr, IPSEC_ATTR_KEY_LENGTH,
+ value);
+
+ value = conf_get_num (xf->field, "KEY_ROUNDS");
+ if (value)
+ attr = attribute_set_basic (attr, IPSEC_ATTR_KEY_ROUNDS,
+ value);
+
+ value = conf_get_num (xf->field, "COMPRESS_DICTIONARY_SIZE");
+ if (value)
+ attr
+ = attribute_set_basic (attr,
+ IPSEC_ATTR_COMPRESS_DICTIONARY_SIZE,
+ value);
+
+ value = conf_get_num (xf->field, "COMPRESS_PRIVATE_ALGORITHM");
+ if (value)
+ attr
+ = attribute_set_basic (attr,
+ IPSEC_ATTR_COMPRESS_PRIVATE_ALGORITHM,
+ value);
+
+ /* Record the real transform size. */
+ transforms_len[prop_no] += (transform_len[prop_no][xf_no]
+ = attr - transform[prop_no][xf_no]);
+ }
+
+ /*
+ * Get SPI from application.
+ * XXX Should we care about unknown constants?
+ */
+ protocol_num = constant_value (ipsec_proto_cst, protocol_id);
+ spi = doi->get_spi (&spi_sz, protocol_num, msg);
+ if (spi_sz && !spi)
+ goto bail_out;
+
+ proposal_len = ISAKMP_PROP_SPI_OFF + spi_sz;
+ proposals_len += proposal_len + transforms_len[prop_no];
+ proposal[prop_no] = malloc (proposal_len);
+ if (!proposal[prop_no])
+ goto bail_out;
+ SET_ISAKMP_PROP_NO (proposal[prop_no], suite_no + 1);
+ SET_ISAKMP_PROP_PROTO (proposal[prop_no], protocol_num);
+
+ /* XXX I would like to see this factored out. */
+ proto = calloc (1, sizeof *proto);
+ if (!proto)
+ goto bail_out;
+ if (doi->proto_size)
+ {
+ proto->data = calloc (1, doi->proto_size);
+ if (!proto->data)
+ goto bail_out;
+ }
+ proto->no = suite_no + 1;
+ proto->proto = protocol_num;
+ proto->sa = TAILQ_FIRST (&exchange->sa_list);
+ TAILQ_INSERT_TAIL (&TAILQ_FIRST (&exchange->sa_list)->protos, proto,
+ link);
+
+ SET_ISAKMP_PROP_SPI_SZ (proposal[prop_no], spi_sz);
+ memcpy (proposal[prop_no] + ISAKMP_PROP_SPI_OFF, spi, spi_sz);
+ proto->spi_sz[exchange->initiator] = spi_sz;
+ proto->spi[exchange->initiator] = spi;
+
+ SET_ISAKMP_PROP_NTRANSFORMS (proposal[prop_no],
+ transform_cnt[prop_no]);
+ prop_no++;
+ }
+ }
+
+ sa_len = ISAKMP_SA_SIT_OFF + IPSEC_SIT_SIT_LEN;
+ sa_buf = malloc (sa_len);
+ if (!sa_buf)
+ goto bail_out;
+ SET_ISAKMP_SA_DOI (sa_buf, IPSEC_DOI_IPSEC);
+ SET_IPSEC_SIT_SIT (sa_buf + ISAKMP_SA_SIT_OFF, IPSEC_SIT_IDENTITY_ONLY);
+
+ /*
+ * Add the payloads. As this is a SA, we need to recompute the
+ * lengths of the payloads containing others. We also need to
+ * reset these payload's "next payload type" field.
+ */
+ if (message_add_payload (msg, ISAKMP_PAYLOAD_SA, sa_buf, sa_len, 1))
+ goto bail_out;
+ SET_ISAKMP_GEN_LENGTH (sa_buf, sa_len + proposals_len);
+ sa_buf = 0;
+
+ update_nextp = 0;
+ saved_nextp_sa = msg->nextp;
+ for (i = 0; i < prop_no; i++)
+ {
+ if (message_add_payload (msg, ISAKMP_PAYLOAD_PROPOSAL, proposal[i],
+ proposal_len, update_nextp))
+ goto bail_out;
+ SET_ISAKMP_GEN_LENGTH (proposal[i], proposal_len + transforms_len[i]);
+ proposal[i] = 0;
+
+ update_nextp = 0;
+ saved_nextp_prop = msg->nextp;
+ for (xf_no = 0; xf_no < transform_cnt[i]; xf_no++)
+ {
+ if (message_add_payload (msg, ISAKMP_PAYLOAD_TRANSFORM,
+ transform[i][xf_no],
+ transform_len[i][xf_no], update_nextp))
+ goto bail_out;
+ update_nextp = 1;
+ transform[i][xf_no] = 0;
+ }
+ msg->nextp = saved_nextp_prop;
+ update_nextp = 1;
+ }
+ msg->nextp = saved_nextp_sa;
+
+ /*
+ * Save SA payload body in ie->sa_i_b, length ie->sa_i_b_len.
+ */
+ ie->sa_i_b = message_copy (msg, ISAKMP_GEN_SZ, &ie->sa_i_b_len);
+ if (!ie->sa_i_b)
+ goto bail_out;
+
+ /*
+ * Generate a nonce, and add it to the message.
+ * XXX I want a better way to specify the nonce's size.
+ */
+ if (exchange_gen_nonce (msg, 16))
+ {
+ /* XXX Log? */
+ return -1;
+ }
+
+ /* Generate optional KEY_EXCH payload. */
+ if (ie->group)
+ {
+ ie->g_x_len = dh_getlen (ie->group);
+
+ if (ipsec_gen_g_x (msg))
+ {
+ /* XXX Log? */
+ return -1;
+ }
+ }
+
+ /* XXX Generate optional client ID payloads. */
+
+ /* Allocate the prf and start calculating our HASH(1). XXX Share? */
+ log_debug_buf (LOG_MISC, 90, "initiator_send_HASH_SA_NONCE: SKEYID_a",
+ isa->skeyid_a, isa->skeyid_len);
+ prf = prf_alloc (isa->prf_type, hash->type, isa->skeyid_a, isa->skeyid_len);
+ if (!prf)
+ {
+ /* XXX Log? */
+ return -1;
+ }
+ prf->Init (prf->prfctx);
+ log_debug_buf (LOG_MISC, 90, "initiator_send_HASH_SA_NONCE: message_id",
+ exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN);
+ prf->Update (prf->prfctx, exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN);
+
+ /* Loop over all payloads after HASH(1). */
+ for (i = 2; i < msg->iovlen; i++)
+ {
+ /* XXX Misleading payload type printouts. */
+ snprintf (header, 80,
+ "initiator_send_HASH_SA_NONCE: payload %d after HASH(1)",
+ i - 1);
+ log_debug_buf (LOG_MISC, 90, header, msg->iov[i].iov_base,
+ msg->iov[i].iov_len);
+ prf->Update (prf->prfctx, msg->iov[i].iov_base, msg->iov[i].iov_len);
+ }
+ prf->Final (buf + ISAKMP_HASH_DATA_OFF, prf->prfctx);
+ prf_free (prf);
+ log_debug_buf (LOG_MISC, 80, "initiator_send_HASH_SA_NONCE: HASH(1)",
+ buf + ISAKMP_HASH_DATA_OFF, hashsize);
+
+ return 0;
+
+ bail_out:
+ if (sa_buf)
+ free (sa_buf);
+ if (proposal)
+ {
+ for (i = 0; i < prop_no; i++)
+ {
+ if (proposal[i])
+ free (proposal[i]);
+ if (transform[i])
+ {
+ for (xf_no = 0; xf_no < xf_conf->cnt; xf_no++)
+ if (transform[i][xf_no])
+ free (transform[i][xf_no]);
+ free (transform[i]);
+ }
+ if (transform_len[i])
+ free (transform_len[i]);
+ }
+ free (proposal);
+ free (transforms_len);
+ free (transform);
+ free (transform_len);
+ free (transform_cnt);
+ }
+ if (xf_conf)
+ conf_free_list (xf_conf);
+ if (prot_conf)
+ conf_free_list (prot_conf);
+ if (suite_conf)
+ conf_free_list (suite_conf);
+ return -1;
+}
+
+/* Figure out what transform the responder chose. */
+static int
+initiator_recv_HASH_SA_NONCE (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ struct sa *sa;
+ struct proto *proto;
+ struct payload *sa_p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_SA]);
+ struct payload *xf;
+ struct payload *hashp = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_HASH]);
+ struct payload *kep = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_KEY_EXCH]);
+ struct prf *prf;
+ struct sa *isakmp_sa = msg->isakmp_sa;
+ struct ipsec_sa *isa = isakmp_sa->data;
+ struct hash *hash = hash_get (isa->hash);
+ size_t hashsize = hash->hashsize;
+ u_int8_t *rest;
+ size_t rest_len;
+
+ /*
+ * As we are getting an answer on our transform offer, only one transform
+ * should be given.
+ *
+ * XXX Currently we only support negotiating one SA per quick mode run.
+ */
+ if (TAILQ_NEXT (sa_p, link))
+ {
+ log_print ("initiator_recv_HASH_SA_NONCE: "
+ "multiple SA payloads in quick mode");
+ /* XXX Is there a better notification type? */
+ message_drop (msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 0, 0);
+ return -1;
+ }
+
+ sa = TAILQ_FIRST (&msg->exchange->sa_list);
+
+ /* Build the protection suite in our SA. */
+ for (xf = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_TRANSFORM]); xf;
+ xf = TAILQ_NEXT (xf, link))
+ {
+ /*
+ * XXX We could check that the proposal each transform belongs to
+ * is unique.
+ */
+
+ if (sa_add_transform (sa, xf, exchange->initiator, &proto))
+ {
+ /* XXX Log? */
+ return -1;
+ }
+
+ /* XXX Check that the chosen transform matches an offer. */
+
+ ipsec_decode_transform (msg, sa, proto, xf->p);
+ }
+
+ /* Now remove offers that we don't need anymore. */
+ for (proto = TAILQ_FIRST (&sa->protos); proto;
+ proto = TAILQ_NEXT (proto, link))
+ if (!proto->chosen)
+ proto_free (proto);
+
+ /* Mark the SA as handled. */
+ sa_p->flags |= PL_MARK;
+
+ /* Allocate the prf and start calculating our HASH(1). XXX Share? */
+ log_debug_buf (LOG_MISC, 90, "initiator_recv_HASH_SA_NONCE: SKEYID_a",
+ isa->skeyid_a, isa->skeyid_len);
+ prf = prf_alloc (isa->prf_type, hash->type, isa->skeyid_a, isa->skeyid_len);
+ if (!prf)
+ {
+ /* XXX Log? */
+ return -1;
+ }
+ prf->Init (prf->prfctx);
+ log_debug_buf (LOG_MISC, 90, "initiator_recv_HASH_SA_NONCE: message_id",
+ exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN);
+ prf->Update (prf->prfctx, exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN);
+ log_debug_buf (LOG_MISC, 90, "initiator_recv_HASH_SA_NONCE: NONCE_I_b",
+ exchange->nonce_i, exchange->nonce_i_len);
+ prf->Update (prf->prfctx, exchange->nonce_i, exchange->nonce_i_len);
+ rest = hashp->p + GET_ISAKMP_GEN_LENGTH (hashp->p);
+ rest_len = (GET_ISAKMP_HDR_LENGTH (msg->iov[0].iov_base)
+ - (rest - (u_int8_t*)msg->iov[0].iov_base));
+ log_debug_buf (LOG_MISC, 90,
+ "initiator_recv_HASH_SA_NONCE: payloads after HASH(2)", rest,
+ rest_len);
+ prf->Update (prf->prfctx, rest, rest_len);
+ prf->Final (hash->digest, prf->prfctx);
+ prf_free (prf);
+ log_debug_buf (LOG_MISC, 80,
+ "initiator_recv_HASH_SA_NONCE: computed HASH(2)",
+ hash->digest, hashsize);
+ if (memcmp (hashp->p + ISAKMP_HASH_DATA_OFF, hash->digest, hashsize) != 0)
+ {
+ /* XXX Log & notify? */
+ return -1;
+ }
+ /* Mark the HASH as handled. */
+ hashp->flags |= PL_MARK;
+
+ /* XXX Errors possible? */
+ ie->group = group_get (isa->group_desc);
+
+ /* Copy out the initiator's nonce. */
+ if (exchange_save_nonce (msg))
+ {
+ /* XXX How to log and notify peer? */
+ return -1;
+ }
+
+ /* Handle the optional KEY_EXCH payload. */
+ if (kep && ipsec_save_g_x (msg))
+ {
+ /* XXX How to log and notify peer? */
+ return -1;
+ }
+
+ /* XXX Handle optional client ID payloads. */
+
+ return 0;
+}
+
+static int
+initiator_send_HASH (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ struct sa *isakmp_sa = msg->isakmp_sa;
+ struct ipsec_sa *isa = isakmp_sa->data;
+ struct prf *prf;
+ u_int8_t *buf;
+ struct hash *hash = hash_get (isa->hash);
+ size_t hashsize = hash->hashsize;
+
+ /* We want a HASH payload to start with. XXX Share with ike_main_mode.c? */
+ buf = malloc (ISAKMP_HASH_SZ + hashsize);
+ if (!buf)
+ {
+ /* XXX Log? */
+ return -1;
+ }
+ if (message_add_payload (msg, ISAKMP_PAYLOAD_HASH, buf,
+ ISAKMP_HASH_SZ + hashsize, 1))
+ {
+ /* XXX Log? */
+ free (buf);
+ return -1;
+ }
+
+ /* Allocate the prf and start calculating our HASH(3). XXX Share? */
+ log_debug_buf (LOG_MISC, 90, "initiator_send_HASH: SKEYID_a", isa->skeyid_a,
+ isa->skeyid_len);
+ prf = prf_alloc (isa->prf_type, isa->hash, isa->skeyid_a, isa->skeyid_len);
+ if (!prf)
+ {
+ /* XXX Log? */
+ return -1;
+ }
+ prf->Init (prf->prfctx);
+ prf->Update (prf->prfctx, "\0", 1);
+ log_debug_buf (LOG_MISC, 90, "initiator_send_HASH: message_id",
+ exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN);
+ prf->Update (prf->prfctx, exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN);
+ log_debug_buf (LOG_MISC, 90, "initiator_send_HASH: NONCE_I_b",
+ exchange->nonce_i, exchange->nonce_i_len);
+ prf->Update (prf->prfctx, exchange->nonce_i, exchange->nonce_i_len);
+ log_debug_buf (LOG_MISC, 90, "initiator_send_HASH: NONCE_R_b",
+ exchange->nonce_r, exchange->nonce_r_len);
+ prf->Update (prf->prfctx, exchange->nonce_r, exchange->nonce_r_len);
+ prf->Final (buf + ISAKMP_GEN_SZ, prf->prfctx);
+ prf_free (prf);
+ log_debug_buf (LOG_MISC, 90, "initiator_send_HASH: HASH(3)",
+ buf + ISAKMP_GEN_SZ, hashsize);
+
+ if (ie->group)
+ message_register_post_send (msg, gen_g_xy);
+ message_register_post_send (msg, post_quick_mode);
+
+ return 0;
+}
+
+static void
+post_quick_mode (struct message *msg)
+{
+ struct sa *isakmp_sa = msg->isakmp_sa;
+ struct ipsec_sa *isa = isakmp_sa->data;
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ struct prf *prf;
+ struct sa *sa;
+ struct proto *proto;
+ struct ipsec_proto *iproto = proto->data;
+ u_int8_t *keymat;
+ int i;
+
+ /*
+ * Loop over all SA negotiations and do both an in- and an outgoing SA
+ * per protocol.
+ */
+ for (sa = TAILQ_FIRST (&exchange->sa_list); sa; sa = TAILQ_NEXT (sa, next))
+ {
+ for (proto = TAILQ_FIRST (&sa->protos); proto;
+ proto = TAILQ_NEXT (proto, link))
+ {
+ iproto = proto->data;
+
+ /*
+ * There are two SAs for each SA negotiation, incoming and outcoing.
+ */
+ for (i = 0; i < 2; i++)
+ {
+ prf = prf_alloc (isa->prf_type, isa->hash, isa->skeyid_d,
+ isa->skeyid_len);
+ if (!prf)
+ {
+ /* XXX What to do? */
+ continue;
+ }
+
+ ie->keymat_len = ipsec_keymat_length (proto);
+
+ /*
+ * We need to roundup the length of the key material buffer
+ * to a multiple of the PRF´s blocksize as it is generated
+ * in chunks of that blocksize.
+ */
+ iproto->keymat[i]
+ = malloc (((ie->keymat_len + prf->blocksize - 1)
+ / prf->blocksize) * prf->blocksize);
+ if (!iproto->keymat[i])
+ {
+ /* XXX What to do? */
+ free (prf);
+ continue;
+ }
+
+ for (keymat = iproto->keymat[i];
+ keymat < iproto->keymat[i] + ie->keymat_len;
+ keymat += prf->blocksize)
+ {
+ prf->Init (prf->prfctx);
+
+ if (keymat != iproto->keymat[i])
+ {
+ /* Hash in last round's KEYMAT. */
+ log_debug_buf (LOG_MISC, 90,
+ "post_quick_mode: last KEYMAT",
+ keymat - prf->blocksize, prf->blocksize);
+ prf->Update (prf->prfctx, keymat - prf->blocksize,
+ prf->blocksize);
+ }
+
+ /* If PFS is used hash in g^xy. */
+ if (ie->g_xy)
+ {
+ log_debug_buf (LOG_MISC, 90, "post_quick_mode: g^xy",
+ ie->g_xy, ie->g_x_len);
+ prf->Update (prf->prfctx, ie->g_xy, ie->g_x_len);
+ }
+ log_debug (LOG_MISC, 90,
+ "post_quick_mode: suite %d proto %d", proto->no,
+ proto->proto);
+ prf->Update (prf->prfctx, &proto->proto, 1);
+ log_debug_buf (LOG_MISC, 90, "post_quick_mode: SPI",
+ proto->spi[i], proto->spi_sz[i]);
+ prf->Update (prf->prfctx, proto->spi[i], proto->spi_sz[i]);
+ log_debug_buf (LOG_MISC, 90, "post_quick_mode: Ni_b",
+ exchange->nonce_i, exchange->nonce_i_len);
+ prf->Update (prf->prfctx, exchange->nonce_i,
+ exchange->nonce_i_len);
+ log_debug_buf (LOG_MISC, 90, "post_quick_mode: Nr_b",
+ exchange->nonce_r, exchange->nonce_r_len);
+ prf->Update (prf->prfctx, exchange->nonce_r,
+ exchange->nonce_r_len);
+ prf->Final (keymat, prf->prfctx);
+ }
+ prf_free (prf);
+ log_debug_buf (LOG_MISC, 90, "post_quick_mode: KEYMAT",
+ iproto->keymat[i], ie->keymat_len);
+ }
+ }
+ }
+}
+
+/*
+ * Accept a set of transforms offered by the initiator and chose one we can
+ * handle.
+ * XXX Describe in more detail.
+ */
+static int
+responder_recv_HASH_SA_NONCE (struct message *msg)
+{
+ struct payload *hashp, *kep;
+ struct sa *sa;
+ struct sa *isakmp_sa = msg->isakmp_sa;
+ struct ipsec_sa *isa = isakmp_sa->data;
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ struct prf *prf;
+ u_int8_t *hash, *my_hash;
+ size_t hash_len;
+ u_int8_t *pkt = msg->iov[0].iov_base;
+ u_int8_t group_desc = 0;
+ int retval = -1;
+ struct proto *proto;
+
+ hashp = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_HASH]);
+ hash = hashp->p;
+ hashp->flags |= PL_MARK;
+
+ /* The HASH payload should be the first one. */
+ if (hash != pkt + ISAKMP_HDR_SZ)
+ {
+ /* XXX Is there a better notification type? */
+ message_drop (msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 0, 0);
+ return -1;
+ }
+ hash_len = GET_ISAKMP_GEN_LENGTH (hash);
+ my_hash = malloc (hash_len - ISAKMP_GEN_SZ);
+ if (!my_hash)
+ {
+ /* XXX Log? */
+ return -1;
+ }
+
+ /* Check the payload's integrity. */
+ log_debug_buf (LOG_MISC, 90, "responder_recv_HASH_SA_NONCE: SKEYID_a",
+ isa->skeyid_a, isa->skeyid_len);
+ prf = prf_alloc (isa->prf_type, isa->hash, isa->skeyid_a, isa->skeyid_len);
+ if (!prf)
+ {
+ /* XXX Log? */
+ return -1;
+ }
+ prf->Init (prf->prfctx);
+ log_debug_buf (LOG_MISC, 90, "responder_recv_HASH_SA_NONCE: message_id",
+ exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN);
+ prf->Update (prf->prfctx, exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN);
+ log_debug_buf (LOG_MISC, 90,
+ "responder_recv_HASH_SA_NONCE: message after HASH",
+ hash + hash_len,
+ msg->iov[0].iov_len - ISAKMP_HDR_SZ - hash_len);
+ prf->Update (prf->prfctx, hash + hash_len,
+ msg->iov[0].iov_len - ISAKMP_HDR_SZ - hash_len);
+ prf->Final (my_hash, prf->prfctx);
+ prf_free (prf);
+ log_debug_buf (LOG_MISC, 90,
+ "responder_recv_HASH_SA_NONCE: computed HASH(1)", my_hash,
+ hash_len - ISAKMP_GEN_SZ);
+ if (memcmp (hash + ISAKMP_GEN_SZ, my_hash, hash_len - ISAKMP_GEN_SZ) != 0)
+ {
+ /* XXX Is there a better notification type? */
+ message_drop (msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, 0, 0, 0);
+ return -1;
+ }
+
+ if (message_negotiate_sa (msg))
+ return -1;
+
+ kep = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_KEY_EXCH]);
+
+ for (sa = TAILQ_FIRST (&exchange->sa_list); sa;
+ sa = TAILQ_NEXT (sa, next))
+ {
+ for (proto = TAILQ_FIRST (&sa->protos); proto;
+ proto = TAILQ_NEXT (proto, link))
+ /* XXX we need to have some attributes per proto, not all per SA. */
+ ipsec_decode_transform (msg, sa, proto, proto->chosen->p);
+
+
+ isa = sa->data;
+
+ /* Check the SA for reasonableness. */
+
+ /* The group description is mandatory if we got a KEY_EXCH payload. */
+ if (kep)
+ {
+ if (!isa->group_desc)
+ {
+ message_drop (msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 0, 0);
+ continue;
+ }
+
+ /* Also, all SAs must have equal groups. */
+ if (!group_desc)
+ group_desc = isa->group_desc;
+ else if (group_desc != isa->group_desc)
+ {
+ message_drop (msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 0, 0);
+ continue;
+ }
+ }
+
+ /* At least one SA was accepted. */
+ retval = 0;
+ }
+
+ /* XXX Errors possible? */
+ ie->group = group_get (group_desc);
+
+ /* Copy out the initiator's nonce. */
+ if (exchange_save_nonce (msg))
+ {
+ /* XXX How to log and notify peer? */
+ return -1;
+ }
+
+ /* Handle the optional KEY_EXCH payload. */
+ if (kep && ipsec_save_g_x (msg))
+ {
+ /* XXX How to log and notify peer? */
+ return -1;
+ }
+
+ /* XXX Handle optional client ID payloads. */
+
+ return retval;
+}
+
+/* Reply with the transform we chose. */
+static int
+responder_send_HASH_SA_NONCE (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ struct sa *isakmp_sa = msg->isakmp_sa;
+ struct ipsec_sa *isa = isakmp_sa->data;
+ struct prf *prf;
+ struct hash *hash = hash_get (isa->hash);
+ size_t hashsize = hash->hashsize;
+ size_t nonce_sz = exchange->nonce_i_len;
+ u_int8_t *buf;
+ int initiator = exchange->initiator;
+ char header[80];
+ int i;
+
+ /* We want a HASH payload to start with. XXX Share with ike_main_mode.c? */
+ buf = malloc (ISAKMP_HASH_SZ + hashsize);
+ if (!buf)
+ {
+ /* XXX Log? */
+ return -1;
+ }
+ if (message_add_payload (msg, ISAKMP_PAYLOAD_HASH, buf,
+ ISAKMP_HASH_SZ + hashsize, 1))
+ {
+ /* XXX Log? */
+ free (buf);
+ return -1;
+ }
+
+ /* Add the SA payload(s) with the transform(s) that was/were chosen. */
+ if (message_add_sa_payload (msg))
+ {
+ /* XXX Log? */
+ return -1;
+ }
+
+ /* Generate a nonce, and add it to the message. */
+ if (exchange_gen_nonce (msg, nonce_sz))
+ {
+ /* XXX Log? */
+ return -1;
+ }
+
+ /* Generate optional KEY_EXCH payload. */
+ if (ie->group && ipsec_gen_g_x (msg))
+ {
+ /* XXX Log? */
+ return -1;
+ }
+
+ /* XXX Generate optional client ID payload. */
+
+ /* Allocate the prf and start calculating our HASH(2). XXX Share? */
+ log_debug_buf (LOG_MISC, 90, "responder_send_HASH_SA_NONCE: SKEYID_a",
+ isa->skeyid_a, isa->skeyid_len);
+ prf = prf_alloc (isa->prf_type, hash->type, isa->skeyid_a, isa->skeyid_len);
+ if (!prf)
+ {
+ /* XXX Log? */
+ return -1;
+ }
+ prf->Init (prf->prfctx);
+ log_debug_buf (LOG_MISC, 90, "responder_send_HASH_SA_NONCE: message_id",
+ exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN);
+ prf->Update (prf->prfctx, exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN);
+ log_debug_buf (LOG_MISC, 90, "responder_send_HASH_SA_NONCE: NONCE_I_b",
+ exchange->nonce_i, exchange->nonce_i_len);
+ prf->Update (prf->prfctx, exchange->nonce_i, exchange->nonce_i_len);
+
+ /* Loop over all payloads after HASH(2). */
+ for (i = 2; i < msg->iovlen; i++)
+ {
+ /* XXX Misleading payload type printouts. */
+ snprintf (header, 80,
+ "responder_send_HASH_SA_NONCE: payload %d after HASH(2)",
+ i - 1);
+ log_debug_buf (LOG_MISC, 90, header, msg->iov[i].iov_base,
+ msg->iov[i].iov_len);
+ prf->Update (prf->prfctx, msg->iov[i].iov_base, msg->iov[i].iov_len);
+ }
+ prf->Final (buf + ISAKMP_HASH_DATA_OFF, prf->prfctx);
+ prf_free (prf);
+ snprintf (header, 80, "responder_send_HASH_SA_NONCE: HASH_%c",
+ initiator ? 'I' : 'R');
+ log_debug_buf (LOG_MISC, 80, header, buf + ISAKMP_HASH_DATA_OFF, hashsize);
+
+ if (ie->group)
+ message_register_post_send (msg, gen_g_xy);
+
+ return 0;
+}
+
+static void
+gen_g_xy (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+
+ /* Compute Diffie-Hellman shared value. */
+ ie->g_xy = malloc (ie->g_x_len);
+ if (!ie->g_xy)
+ {
+ /* XXX How to log and notify peer? */
+ return;
+ }
+ dh_create_shared (ie->group, ie->g_xy,
+ exchange->initiator ? ie->g_xr : ie->g_xi);
+ log_debug_buf (LOG_MISC, 80, "gen_g_xy: g^xy", ie->g_xy, ie->g_x_len);
+}
+
+static int
+responder_recv_HASH (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct sa *isakmp_sa = msg->isakmp_sa;
+ struct ipsec_sa *isa = isakmp_sa->data;
+ struct prf *prf;
+ u_int8_t *hash, *my_hash;
+ size_t hash_len;
+ struct payload *hashp;
+
+ /* Find HASH(3) and create our own hash, just as big. */
+ hashp = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_HASH]);
+ hash = hashp->p;
+ hashp->flags |= PL_MARK;
+ hash_len = GET_ISAKMP_GEN_LENGTH (hash);
+ my_hash = malloc (hash_len - ISAKMP_GEN_SZ);
+ if (!my_hash)
+ {
+ /* XXX Log? */
+ return -1;
+ }
+
+ /* Allocate the prf and start calculating our HASH(3). XXX Share? */
+ log_debug_buf (LOG_MISC, 90, "responder_recv_HASH: SKEYID_a", isa->skeyid_a,
+ isa->skeyid_len);
+ prf = prf_alloc (isa->prf_type, isa->hash, isa->skeyid_a, isa->skeyid_len);
+ if (!prf)
+ {
+ /* XXX Log? */
+ free (my_hash);
+ return -1;
+ }
+ prf->Init (prf->prfctx);
+ prf->Update (prf->prfctx, "\0", 1);
+ log_debug_buf (LOG_MISC, 90, "responder_recv_HASH: message_id",
+ exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN);
+ prf->Update (prf->prfctx, exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN);
+ log_debug_buf (LOG_MISC, 90, "responder_recv_HASH: NONCE_I_b",
+ exchange->nonce_i, exchange->nonce_i_len);
+ prf->Update (prf->prfctx, exchange->nonce_i, exchange->nonce_i_len);
+ log_debug_buf (LOG_MISC, 90, "responder_recv_HASH: NONCE_R_b",
+ exchange->nonce_r, exchange->nonce_r_len);
+ prf->Update (prf->prfctx, exchange->nonce_r, exchange->nonce_r_len);
+ prf->Final (my_hash, prf->prfctx);
+ prf_free (prf);
+ log_debug_buf (LOG_MISC, 90,
+ "responder_recv_HASH: computed HASH(3)", my_hash,
+ hash_len - ISAKMP_GEN_SZ);
+ if (memcmp (hash + ISAKMP_GEN_SZ, my_hash, hash_len - ISAKMP_GEN_SZ) != 0)
+ {
+ /* XXX Is there a better notification type? */
+ message_drop (msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, 0, 0, 0);
+ return -1;
+ }
+
+ post_quick_mode (msg);
+
+ return 0;
+}
diff --git a/sbin/isakmpd/ike_quick_mode.h b/sbin/isakmpd/ike_quick_mode.h
new file mode 100644
index 00000000000..87a4fa699b0
--- /dev/null
+++ b/sbin/isakmpd/ike_quick_mode.h
@@ -0,0 +1,44 @@
+/* $Id: ike_quick_mode.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _IKE_QUICK_MODE_H_
+#define _IKE_QUICK_MODE_H_
+
+struct message;
+
+extern int (*ike_quick_mode_initiator[]) (struct message *msg);
+extern int (*ike_quick_mode_responder[]) (struct message *msg);
+
+#endif /* _IKE_QUICK_MODE_H_ */
diff --git a/sbin/isakmpd/init.c b/sbin/isakmpd/init.c
new file mode 100644
index 00000000000..8e1e3c1eeb7
--- /dev/null
+++ b/sbin/isakmpd/init.c
@@ -0,0 +1,69 @@
+/* $Id: init.c,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+/* XXX This file could easily be built dynamically instead. */
+
+#include "app.h"
+#include "conf.h"
+#include "cookie.h"
+#include "doi.h"
+#include "exchange.h"
+#include "init.h"
+#include "ipsec.h"
+#include "isakmp_doi.h"
+#include "math_group.h"
+#include "sa.h"
+#include "timer.h"
+#include "transport.h"
+#include "udp.h"
+#include "ui.h"
+
+void
+init ()
+{
+ app_init ();
+ conf_init ();
+ doi_init ();
+ exchange_init ();
+ group_init ();
+ ipsec_init ();
+ isakmp_doi_init ();
+ timer_init ();
+ cookie_init (); /* Depends on properly setup timer queue */
+ sa_init ();
+ transport_init ();
+ udp_init ();
+ ui_init ();
+}
diff --git a/sbin/isakmpd/init.h b/sbin/isakmpd/init.h
new file mode 100644
index 00000000000..1746607d93b
--- /dev/null
+++ b/sbin/isakmpd/init.h
@@ -0,0 +1,41 @@
+/* $Id: init.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _INIT_H_
+#define _INIT_H_
+
+extern void init (void);
+
+#endif /* _INIT_H_ */
diff --git a/sbin/isakmpd/ipsec.c b/sbin/isakmpd/ipsec.c
new file mode 100644
index 00000000000..f8fe5553b86
--- /dev/null
+++ b/sbin/isakmpd/ipsec.c
@@ -0,0 +1,1067 @@
+/* $Id: ipsec.c,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "attribute.h"
+#include "constants.h"
+#include "crypto.h"
+#include "dh.h"
+#include "doi.h"
+#include "exchange.h"
+#include "hash.h"
+#include "ike_auth.h"
+#include "ike_main_mode.h"
+#include "ike_quick_mode.h"
+#include "ipsec.h"
+#include "ipsec_doi.h"
+#include "isakmp.h"
+#include "log.h"
+#include "math_group.h"
+#include "message.h"
+#include "prf.h"
+#include "sa.h"
+#include "sysdep.h"
+#include "timer.h"
+#include "transport.h"
+#include "util.h"
+
+struct ipsec_decode_arg {
+ struct message *msg;
+ struct sa *sa;
+ struct proto *proto;
+};
+
+static int ipsec_debug_attribute (u_int16_t, u_int8_t *, u_int16_t, void *);
+static void ipsec_delete_spi (struct sa *, struct proto *, int);
+static u_int16_t *ipsec_exchange_script (u_int8_t);
+static void ipsec_finalize_exchange (struct message *);
+static void ipsec_free_exchange_data (void *);
+static void ipsec_free_proto_data (void *);
+static void ipsec_free_sa_data (void *);
+static struct keystate *ipsec_get_keystate (struct message *);
+static u_int8_t *ipsec_get_spi (size_t *, u_int8_t, struct message *);
+static int ipsec_initiator (struct message *);
+static int ipsec_responder (struct message *);
+static void ipsec_setup_situation (u_int8_t *);
+static size_t ipsec_situation_size (void);
+static u_int8_t ipsec_spi_size (u_int8_t);
+static int ipsec_validate_attribute (u_int16_t, u_int8_t *, u_int16_t, void *);
+static int ipsec_validate_exchange (u_int8_t);
+static int ipsec_validate_id_information (u_int8_t, u_int8_t *, u_int8_t *,
+ size_t, struct exchange *);
+static int ipsec_validate_key_information (u_int8_t *, size_t);
+static int ipsec_validate_notification (u_int16_t);
+static int ipsec_validate_proto (u_int8_t);
+static int ipsec_validate_situation (u_int8_t *, size_t *);
+static int ipsec_validate_transform_id (u_int8_t, u_int8_t);
+
+static struct doi ipsec_doi = {
+ { 0 }, IPSEC_DOI_IPSEC,
+ sizeof (struct ipsec_exch), sizeof (struct ipsec_sa),
+ sizeof (struct ipsec_proto),
+ ipsec_debug_attribute,
+ ipsec_delete_spi,
+ ipsec_exchange_script,
+ ipsec_finalize_exchange,
+ ipsec_free_exchange_data,
+ ipsec_free_proto_data,
+ ipsec_free_sa_data,
+ ipsec_get_keystate,
+ ipsec_get_spi,
+ ipsec_is_attribute_incompatible,
+ ipsec_setup_situation,
+ ipsec_situation_size,
+ ipsec_spi_size,
+ ipsec_validate_attribute,
+ ipsec_validate_exchange,
+ ipsec_validate_id_information,
+ ipsec_validate_key_information,
+ ipsec_validate_notification,
+ ipsec_validate_proto,
+ ipsec_validate_situation,
+ ipsec_validate_transform_id,
+ ipsec_initiator,
+ ipsec_responder
+};
+
+int16_t script_quick_mode[] = {
+ ISAKMP_PAYLOAD_HASH, /* Initiator -> responder. */
+ ISAKMP_PAYLOAD_SA,
+ ISAKMP_PAYLOAD_NONCE,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_HASH, /* Responder -> initiator. */
+ ISAKMP_PAYLOAD_SA,
+ ISAKMP_PAYLOAD_NONCE,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_HASH, /* Initiator -> responder. */
+ EXCHANGE_SCRIPT_END
+};
+
+int16_t script_new_group_mode[] = {
+ ISAKMP_PAYLOAD_HASH, /* Initiator -> responder. */
+ ISAKMP_PAYLOAD_SA,
+ EXCHANGE_SCRIPT_SWITCH,
+ ISAKMP_PAYLOAD_HASH, /* Responder -> initiator. */
+ ISAKMP_PAYLOAD_SA,
+ EXCHANGE_SCRIPT_END
+};
+
+static void
+ipsec_finalize_exchange (struct message *msg)
+{
+ struct sa *isakmp_sa = msg->isakmp_sa;
+ struct ipsec_sa *isa = isakmp_sa->data;
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ struct sa *sa;
+ struct proto *proto, *last_proto = 0;
+ int initiator = exchange->initiator;
+ struct timeval expiration;
+
+ switch (exchange->phase)
+ {
+ case 1:
+ switch (exchange->type)
+ {
+ case ISAKMP_EXCH_ID_PROT:
+ case ISAKMP_EXCH_AGGRESSIVE:
+ isa->hash = ie->hash->type;
+ isa->prf_type = ie->prf_type;
+ isa->skeyid_len = ie->skeyid_len;
+ isa->skeyid_d = ie->skeyid_d;
+ isa->skeyid_a = ie->skeyid_a;
+ /* Prevents early free of SKEYID_*. */
+ ie->skeyid_a = ie->skeyid_d = 0;
+ break;
+ }
+
+ /* If a lifetime was negotiated sutup the death timer. */
+ if (isakmp_sa->seconds)
+ {
+ gettimeofday(&expiration, 0);
+ expiration.tv_sec += isakmp_sa->seconds;
+ isakmp_sa->death = timer_add_event ("sa_rekey_p1",
+ (void (*) (void *))sa_rekey_p1,
+ isakmp_sa, &expiration);
+ if (!isakmp_sa->death)
+ {
+ /* If we don't give up we might start leaking... */
+ sa_delete (isakmp_sa, 1);
+ return;
+ }
+ }
+ break;
+
+ case 2:
+ switch (exchange->type)
+ {
+ case IKE_EXCH_QUICK_MODE:
+ /*
+ * Tell the application(s) about the SPIs and key material.
+ */
+ for (sa = TAILQ_FIRST (&exchange->sa_list); sa;
+ sa = TAILQ_NEXT (sa, next))
+ {
+ for (proto = TAILQ_FIRST (&sa->protos), last_proto = 0; proto;
+ proto = TAILQ_NEXT (proto, link))
+ {
+ if (sysdep_ipsec_set_spi (sa, proto, 0, initiator)
+ || (last_proto
+ && sysdep_ipsec_group_spis (sa, last_proto, proto,
+ 0))
+ || sysdep_ipsec_set_spi (sa, proto, 1, initiator)
+ || (last_proto
+ && sysdep_ipsec_group_spis (sa, last_proto, proto,
+ 1)))
+ /* XXX Tear down this exchange. */
+ return;
+ last_proto = proto;
+ }
+ if (sysdep_ipsec_enable_spi (sa, initiator))
+ /* XXX Tear down this exchange. */
+ return;
+ }
+ break;
+ }
+ }
+}
+
+static void
+ipsec_free_exchange_data (void *vie)
+{
+ struct ipsec_exch *ie = vie;
+
+ if (ie->sa_i_b)
+ free (ie->sa_i_b);
+ if (ie->g_xi)
+ free (ie->g_xi);
+ if (ie->g_xr)
+ free (ie->g_xr);
+ if (ie->g_xy)
+ free (ie->g_xy);
+ if (ie->skeyid)
+ free (ie->skeyid);
+ if (ie->skeyid_d)
+ free (ie->skeyid_d);
+ if (ie->skeyid_a)
+ free (ie->skeyid_a);
+ if (ie->skeyid_e)
+ free (ie->skeyid_e);
+ if (ie->hash_i)
+ free (ie->hash_i);
+ if (ie->hash_r)
+ free (ie->hash_r);
+}
+
+static void
+ipsec_free_sa_data (void *visa)
+{
+ struct ipsec_sa *isa = visa;
+
+ if (isa->skeyid_a)
+ free (isa->skeyid_a);
+ if (isa->skeyid_d)
+ free (isa->skeyid_d);
+}
+
+static void
+ipsec_free_proto_data (void *viproto)
+{
+ struct ipsec_proto *iproto = viproto;
+ int i;
+
+ for (i = 0; i < 2; i++)
+ if (iproto->keymat[i])
+ free (iproto->keymat[i]);
+}
+
+static u_int16_t *
+ipsec_exchange_script (u_int8_t type)
+{
+ switch (type)
+ {
+ case IKE_EXCH_QUICK_MODE:
+ return script_quick_mode;
+ case IKE_EXCH_NEW_GROUP_MODE:
+ return script_new_group_mode;
+ }
+ return 0;
+}
+
+/* Requires doi_init to already have been called. */
+void
+ipsec_init ()
+{
+ doi_register (&ipsec_doi);
+}
+
+/* Given a message MSG, return a suitable IV (or rather keystate). */
+static struct keystate *
+ipsec_get_keystate (struct message *msg)
+{
+ struct keystate *ks;
+ struct hash *hash;
+
+ /* If we have already have an IV, use it. */
+ if (msg->exchange && msg->exchange->keystate)
+ return msg->exchange->keystate;
+
+ /*
+ * For phase 2 when no SA yet is setup we need to hash the IV used by
+ * the ISAKMP SA concatenated with the message ID, and use that as an
+ * IV for further cryptographic operations.
+ */
+ ks = crypto_clone_keystate (msg->isakmp_sa->keystate);
+ if (!ks)
+ return 0;
+
+ hash = hash_get (((struct ipsec_sa *)msg->isakmp_sa->data)->hash);
+ hash->Init (hash->ctx);
+ log_debug_buf (LOG_CRYPTO, 80, "ipsec_get_keystate: final phase 1 IV",
+ ks->riv, ks->xf->blocksize);
+ hash->Update (hash->ctx, ks->riv, ks->xf->blocksize);
+ log_debug_buf (LOG_CRYPTO, 80, "ipsec_get_keystate: message ID",
+ ((u_int8_t *)msg->iov[0].iov_base)
+ + ISAKMP_HDR_MESSAGE_ID_OFF,
+ ISAKMP_HDR_MESSAGE_ID_LEN);
+ hash->Update (hash->ctx,
+ ((u_int8_t *)msg->iov[0].iov_base) + ISAKMP_HDR_MESSAGE_ID_OFF,
+ ISAKMP_HDR_MESSAGE_ID_LEN);
+ hash->Final (hash->digest, hash->ctx);
+ crypto_init_iv (ks, hash->digest, ks->xf->blocksize);
+ log_debug_buf (LOG_CRYPTO, 80, "ipsec_get_keystate: phase 2 IV",
+ hash->digest, ks->xf->blocksize);
+ return ks;
+}
+
+static void
+ipsec_setup_situation (u_int8_t *buf)
+{
+ SET_IPSEC_SIT_SIT (buf + ISAKMP_SA_SIT_OFF, IPSEC_SIT_IDENTITY_ONLY);
+}
+
+static size_t
+ipsec_situation_size (void)
+{
+ return IPSEC_SIT_SIT_LEN;
+}
+
+static u_int8_t
+ipsec_spi_size (u_int8_t proto)
+{
+ return IPSEC_SPI_SIZE;
+}
+
+static int
+ipsec_validate_attribute (u_int16_t type, u_int8_t *value, u_int16_t len,
+ void *vmsg)
+{
+ struct message *msg = vmsg;
+
+ if ((msg->exchange->phase == 1
+ && (type < IKE_ATTR_ENCRYPTION_ALGORITHM
+ || type > IKE_ATTR_GROUP_ORDER))
+ || (msg->exchange->phase == 2
+ && (type < IPSEC_ATTR_SA_LIFE_TYPE
+ || type > IPSEC_ATTR_COMPRESS_PRIVATE_ALGORITHM)))
+ return -1;
+ return 0;
+}
+
+static int
+ipsec_validate_exchange (u_int8_t exch)
+{
+ return exch != IKE_EXCH_QUICK_MODE && exch != IKE_EXCH_NEW_GROUP_MODE;
+}
+
+static int
+ipsec_validate_id_information (u_int8_t type, u_int8_t *extra, u_int8_t *buf,
+ size_t sz, struct exchange *exchange)
+{
+ u_int8_t proto = GET_IPSEC_ID_PROTO (extra);
+ u_int16_t port = GET_IPSEC_ID_PORT (extra);
+
+ log_debug (LOG_MESSAGE, 0,
+ "ipsec_validate_id_information: proto %d port %d type %d",
+ proto, port, type);
+ if (type < IPSEC_ID_IPV4_ADDR || type > IPSEC_ID_KEY_ID)
+ return -1;
+
+ if (exchange->phase == 1
+ && (proto != IPPROTO_UDP || port != UDP_DEFAULT_PORT)
+ && (proto != 0 || port != 0))
+ {
+/* XXX SSH's ISAKMP tester fails this test (proto 17 - port 0). */
+#ifdef notyet
+ return -1;
+#else
+ log_print ("ipsec_validate_id_information: "
+ "dubious ID information accepted");
+#endif
+ }
+
+ /* XXX More checks? */
+
+ return 0;
+}
+
+static int
+ipsec_validate_key_information (u_int8_t *buf, size_t sz)
+{
+ /* XXX Not implemented yet. */
+ return 0;
+}
+
+static int
+ipsec_validate_notification (u_int16_t type)
+{
+ return type < IPSEC_NOTIFY_RESPONDER_LIFETIME
+ || type > IPSEC_NOTIFY_INITIAL_CONTACT ? -1 : 0;
+}
+
+static int
+ipsec_validate_proto (u_int8_t proto)
+{
+ return proto < IPSEC_PROTO_IPSEC_AH || proto > IPSEC_PROTO_IPCOMP ? -1 : 0;
+}
+
+static int
+ipsec_validate_situation (u_int8_t *buf, size_t *sz)
+{
+ int sit = GET_IPSEC_SIT_SIT (buf);
+ int off;
+
+ if (sit & (IPSEC_SIT_SECRECY | IPSEC_SIT_INTEGRITY))
+ {
+ /*
+ * XXX All the roundups below, round up to 32 bit boundaries given
+ * that the situation field is aligned. This is not necessarily so,
+ * but I interpret the drafts as this is like this they want it.
+ */
+ off = ROUNDUP_32 (GET_IPSEC_SIT_SECRECY_LENGTH (buf));
+ off += ROUNDUP_32 (GET_IPSEC_SIT_SECRECY_CAT_LENGTH (buf + off));
+ off += ROUNDUP_32 (GET_IPSEC_SIT_INTEGRITY_LENGTH (buf + off));
+ off += ROUNDUP_32 (GET_IPSEC_SIT_INTEGRITY_CAT_LENGTH (buf + off));
+ *sz = off + IPSEC_SIT_SZ;
+ }
+ else
+ *sz = IPSEC_SIT_SIT_LEN;
+
+ /* Currently only "identity only" situations are supported. */
+#ifdef notdef
+ return
+ sit & ~(IPSEC_SIT_IDENTITY_ONLY | IPSEC_SIT_SECRECY | IPSEC_SIT_INTEGRITY);
+#else
+ return sit & ~IPSEC_SIT_IDENTITY_ONLY;
+#endif
+ return 1;
+ return 0;
+}
+
+static int
+ipsec_validate_transform_id (u_int8_t proto, u_int8_t transform_id)
+{
+ switch (proto)
+ {
+ /*
+ * As no unexpected protocols can occur, we just tie the default case
+ * to the first case, in orer to silence a GCC warning.
+ */
+ default:
+ case ISAKMP_PROTO_ISAKMP:
+ return transform_id != IPSEC_TRANSFORM_KEY_IKE;
+ case IPSEC_PROTO_IPSEC_AH:
+ return
+ transform_id < IPSEC_AH_MD5 || transform_id > IPSEC_AH_DES ? -1 : 0;
+ case IPSEC_PROTO_IPSEC_ESP:
+ return transform_id < IPSEC_ESP_DES_IV64
+ || transform_id > IPSEC_ESP_NULL ? -1 : 0;
+ case IPSEC_PROTO_IPCOMP:
+ return transform_id < IPSEC_IPCOMP_OUI
+ || transform_id > IPSEC_IPCOMP_V42BIS ? -1 : 0;
+ }
+}
+
+static int
+ipsec_initiator (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ int (**script) (struct message *msg) = 0;
+
+ /* XXX Mostly not implemented yet. */
+
+ /* Check that the SA is coherent with the IKE rules. */
+ if ((exchange->phase == 1 && exchange->type != ISAKMP_EXCH_ID_PROT
+ && exchange->type != ISAKMP_EXCH_INFO)
+ || (exchange->phase == 2 && exchange->type == ISAKMP_EXCH_ID_PROT))
+ {
+ log_print ("ipsec_initiator: unsupported exchange type %d in phase %d",
+ exchange->type, exchange->phase);
+ return -1;
+ }
+
+ switch (exchange->type)
+ {
+ case ISAKMP_EXCH_BASE:
+ break;
+ case ISAKMP_EXCH_ID_PROT:
+ script = ike_main_mode_initiator;
+ break;
+ case ISAKMP_EXCH_AUTH_ONLY:
+ log_print ("ipsec_initiator: unuspported exchange type %d",
+ exchange->type);
+ return -1;
+ case ISAKMP_EXCH_AGGRESSIVE:
+ break;
+ case ISAKMP_EXCH_INFO:
+ message_send_info (msg);
+ break;
+ case IKE_EXCH_QUICK_MODE:
+ script = ike_quick_mode_initiator;
+ break;
+ case IKE_EXCH_NEW_GROUP_MODE:
+ break;
+ }
+
+ /* Run the script code for this step. */
+ if (script)
+ return script[exchange->step] (msg);
+
+ return 0;
+}
+
+static int
+ipsec_responder (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ int (**script) (struct message *msg) = 0;
+
+ /* Check that a new exchange is coherent with the IKE rules. */
+ if (exchange->step == 0
+ && ((exchange->phase == 1 && exchange->type != ISAKMP_EXCH_ID_PROT
+ && exchange->type != ISAKMP_EXCH_INFO)
+ || (exchange->phase == 2 && exchange->type == ISAKMP_EXCH_ID_PROT)))
+ {
+ message_drop (msg, ISAKMP_NOTIFY_UNSUPPORTED_EXCHANGE_TYPE, 0, 0, 0);
+ return -1;
+ }
+
+ log_debug (LOG_MISC, 30,
+ "ipsec_responder: phase %d exchange %d step %d", exchange->phase,
+ exchange->type, exchange->step);
+ switch (exchange->type)
+ {
+ case ISAKMP_EXCH_BASE:
+ case ISAKMP_EXCH_AUTH_ONLY:
+ message_drop (msg, ISAKMP_NOTIFY_UNSUPPORTED_EXCHANGE_TYPE, 0, 0, 0);
+ return -1;
+
+ case ISAKMP_EXCH_ID_PROT:
+ script = ike_main_mode_responder;
+ break;
+
+ case ISAKMP_EXCH_AGGRESSIVE:
+ /* XXX Not implemented yet. */
+ break;
+
+ case ISAKMP_EXCH_INFO:
+ /* XXX Not implemented yet. */
+ break;
+
+ case IKE_EXCH_QUICK_MODE:
+ script = ike_quick_mode_responder;
+ break;
+
+ case IKE_EXCH_NEW_GROUP_MODE:
+ /* XXX Not implemented yet. */
+ break;
+ }
+
+ /* Run the script code for this step. */
+ if (script)
+ return script[exchange->step] (msg);
+
+ /*
+ * XXX So far we don't accept any proposals for exchanges we don't support.
+ */
+ if (TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_SA]))
+ {
+ message_drop (msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 0, 0);
+ return -1;
+ }
+ return 0;
+}
+
+static enum hashes from_ike_hash (u_int16_t hash)
+{
+ switch (hash)
+ {
+ case IKE_HASH_MD5:
+ return HASH_MD5;
+ case IKE_HASH_SHA:
+ return HASH_SHA1;
+ }
+ return -1;
+}
+
+static enum transform from_ike_crypto (u_int16_t crypto)
+{
+ /* Coincidentally this is the null operation :-) */
+ return crypto;
+}
+
+int
+ipsec_is_attribute_incompatible (u_int16_t type, u_int8_t *value,
+ u_int16_t len, void *vmsg)
+{
+ struct message *msg = vmsg;
+
+ if (msg->exchange->phase == 1)
+ {
+ switch (type)
+ {
+ case IKE_ATTR_ENCRYPTION_ALGORITHM:
+ return !crypto_get (from_ike_crypto (decode_16 (value)));
+ case IKE_ATTR_HASH_ALGORITHM:
+ return !hash_get (from_ike_hash (decode_16 (value)));
+ case IKE_ATTR_AUTHENTICATION_METHOD:
+ return !ike_auth_get (decode_16 (value));
+ case IKE_ATTR_GROUP_DESCRIPTION:
+ return decode_16 (value) < IKE_GROUP_DESC_MODP_768
+ || decode_16 (value) > IKE_GROUP_DESC_EC2N_185;
+ case IKE_ATTR_GROUP_TYPE:
+ return 1;
+ case IKE_ATTR_GROUP_PRIME:
+ return 1;
+ case IKE_ATTR_GROUP_GENERATOR_1:
+ return 1;
+ case IKE_ATTR_GROUP_GENERATOR_2:
+ return 1;
+ case IKE_ATTR_GROUP_CURVE_A:
+ return 1;
+ case IKE_ATTR_GROUP_CURVE_B:
+ return 1;
+ case IKE_ATTR_LIFE_TYPE:
+ return decode_16 (value) < IKE_DURATION_SECONDS
+ || decode_16 (value) > IKE_DURATION_KILOBYTES;
+ case IKE_ATTR_LIFE_DURATION:
+ return 0;
+ case IKE_ATTR_PRF:
+ return 1;
+ case IKE_ATTR_KEY_LENGTH:
+ /*
+ * Our crypto routines only allows key-lengths which are multiples
+ * of an octet.
+ */
+ return decode_16 (value) % 8 != 0;
+ case IKE_ATTR_FIELD_SIZE:
+ return 1;
+ case IKE_ATTR_GROUP_ORDER:
+ return 1;
+ }
+ }
+ else
+ {
+ switch (type)
+ {
+ case IPSEC_ATTR_SA_LIFE_TYPE:
+ return decode_16 (value) < IPSEC_DURATION_SECONDS
+ || decode_16 (value) > IPSEC_DURATION_KILOBYTES;
+ case IPSEC_ATTR_SA_LIFE_DURATION:
+ return 0;
+ case IPSEC_ATTR_GROUP_DESCRIPTION:
+ return decode_16 (value) < IKE_GROUP_DESC_MODP_768
+ || decode_16 (value) > IKE_GROUP_DESC_EC2N_185;
+ case IPSEC_ATTR_ENCAPSULATION_MODE:
+ return decode_16 (value) < IPSEC_ENCAP_TUNNEL
+ || decode_16 (value) > IPSEC_ENCAP_TRANSPORT;
+ case IPSEC_ATTR_AUTHENTICATION_ALGORITHM:
+ return decode_16 (value) < IPSEC_AUTH_HMAC_MD5
+ || decode_16 (value) > IPSEC_AUTH_KPDK;
+ case IPSEC_ATTR_KEY_LENGTH:
+ return 1;
+ case IPSEC_ATTR_KEY_ROUNDS:
+ return 1;
+ case IPSEC_ATTR_COMPRESS_DICTIONARY_SIZE:
+ return 1;
+ case IPSEC_ATTR_COMPRESS_PRIVATE_ALGORITHM:
+ return 1;
+ }
+ }
+ /* XXX Silence gcc. */
+ return 1;
+}
+
+int
+ipsec_debug_attribute (u_int16_t type, u_int8_t *value, u_int16_t len,
+ void *vmsg)
+{
+ struct message *msg = vmsg;
+ char val[20];
+
+ /* XXX Transient solution. */
+ if (len == 2)
+ sprintf (val, "%d", decode_16 (value));
+ else if (len == 4)
+ sprintf (val, "%d", decode_32 (value));
+ else
+ sprintf (val, "unrepresentable");
+
+ log_debug (LOG_MESSAGE, 50, "Attribute %s value %s",
+ constant_name (msg->exchange->phase == 1
+ ? ike_attr_cst : ipsec_attr_cst, type),
+ val);
+ return 0;
+}
+
+int
+ipsec_decode_attribute (u_int16_t type, u_int8_t *value, u_int16_t len,
+ void *vida)
+{
+ struct ipsec_decode_arg *ida = vida;
+ struct message *msg = ida->msg;
+ struct sa *sa = ida->sa;
+ struct ipsec_sa *isa = sa->data;
+ struct proto *proto = ida->proto;
+ struct ipsec_proto *iproto = proto->data;
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ static int lifetype = 0;
+
+ if (exchange->phase == 1)
+ {
+ switch (type)
+ {
+ case IKE_ATTR_ENCRYPTION_ALGORITHM:
+ /* XXX Errors possible? */
+ exchange->crypto = crypto_get (from_ike_crypto (decode_16 (value)));
+ break;
+ case IKE_ATTR_HASH_ALGORITHM:
+ /* XXX Errors possible? */
+ ie->hash = hash_get (from_ike_hash (decode_16 (value)));
+ break;
+ case IKE_ATTR_AUTHENTICATION_METHOD:
+ /* XXX Errors possible? */
+ ie->ike_auth = ike_auth_get (decode_16 (value));
+ break;
+ case IKE_ATTR_GROUP_DESCRIPTION:
+ /* XXX Errors possible? */
+ ie->group = group_get (decode_16 (value));
+ break;
+ case IKE_ATTR_GROUP_TYPE:
+ break;
+ case IKE_ATTR_GROUP_PRIME:
+ break;
+ case IKE_ATTR_GROUP_GENERATOR_1:
+ break;
+ case IKE_ATTR_GROUP_GENERATOR_2:
+ break;
+ case IKE_ATTR_GROUP_CURVE_A:
+ break;
+ case IKE_ATTR_GROUP_CURVE_B:
+ break;
+ case IKE_ATTR_LIFE_TYPE:
+ lifetype = decode_16 (value);
+ return 0;
+ case IKE_ATTR_LIFE_DURATION:
+ switch (lifetype)
+ {
+ case IKE_DURATION_SECONDS:
+ switch (len)
+ {
+ case 2:
+ sa->seconds = decode_16 (value);
+ break;
+ case 4:
+ sa->seconds = decode_32 (value);
+ break;
+ default:
+ /* XXX Log. */
+ }
+ break;
+ case IKE_DURATION_KILOBYTES:
+ switch (len)
+ {
+ case 2:
+ sa->kilobytes = decode_16 (value);
+ break;
+ case 4:
+ sa->kilobytes = decode_32 (value);
+ break;
+ default:
+ /* XXX Log. */
+ }
+ break;
+ default:
+ /* XXX Log! */
+ }
+ break;
+ case IKE_ATTR_PRF:
+ break;
+ case IKE_ATTR_KEY_LENGTH:
+ exchange->key_length = decode_16 (value) / 8;
+ break;
+ case IKE_ATTR_FIELD_SIZE:
+ break;
+ case IKE_ATTR_GROUP_ORDER:
+ break;
+ }
+ }
+ else
+ {
+ switch (type)
+ {
+ case IPSEC_ATTR_SA_LIFE_TYPE:
+ lifetype = decode_16 (value);
+ return 0;
+ case IPSEC_ATTR_SA_LIFE_DURATION:
+ switch (lifetype)
+ {
+ case IPSEC_DURATION_SECONDS:
+ switch (len)
+ {
+ case 2:
+ sa->seconds = decode_16 (value);
+ break;
+ case 4:
+ sa->seconds = decode_32 (value);
+ break;
+ default:
+ /* XXX Log. */
+ }
+ break;
+ case IPSEC_DURATION_KILOBYTES:
+ switch (len)
+ {
+ case 2:
+ sa->kilobytes = decode_16 (value);
+ break;
+ case 4:
+ sa->kilobytes = decode_32 (value);
+ break;
+ default:
+ /* XXX Log. */
+ }
+ break;
+ default:
+ /* XXX Log! */
+ }
+ break;
+ case IPSEC_ATTR_GROUP_DESCRIPTION:
+ isa->group_desc = decode_16 (value);
+ break;
+ case IPSEC_ATTR_ENCAPSULATION_MODE:
+ /* XXX Multiple protocols must have same encapsulation mode, no? */
+ iproto->encap_mode = decode_16 (value);
+ break;
+ case IPSEC_ATTR_AUTHENTICATION_ALGORITHM:
+ iproto->auth = decode_16 (value);
+ break;
+ case IPSEC_ATTR_KEY_LENGTH:
+ iproto->keylen = decode_16 (value);
+ break;
+ case IPSEC_ATTR_KEY_ROUNDS:
+ iproto->keyrounds = decode_16 (value);
+ break;
+ case IPSEC_ATTR_COMPRESS_DICTIONARY_SIZE:
+ break;
+ case IPSEC_ATTR_COMPRESS_PRIVATE_ALGORITHM:
+ break;
+ }
+ }
+ lifetype = 0;
+ return 0;
+}
+
+/*
+ * Walk over the attributes of the transform payload found in BUF, and
+ * fill out the fields of the SA attached to MSG. Also mark the SA as
+ * processed.
+ */
+void
+ipsec_decode_transform (struct message *msg, struct sa *sa,
+ struct proto *proto, u_int8_t *buf)
+{
+ struct ipsec_exch *ie = msg->exchange->data;
+ struct ipsec_decode_arg ida;
+
+ log_debug (LOG_MISC, 20, "ipsec_decode_transform: transform %d chosen",
+ GET_ISAKMP_TRANSFORM_NO (buf));
+
+ ida.msg = msg;
+ ida.sa = sa;
+ ida.proto = proto;
+
+ /* The default IKE lifetime is 8 hours. */
+ if (sa->phase == 1)
+ sa->seconds = 28800;
+
+ /* Extract the attributes and stuff them into the SA. */
+ attribute_map (buf + ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ GET_ISAKMP_GEN_LENGTH (buf) - ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ ipsec_decode_attribute, &ida);
+
+ /*
+ * If no pseudo-random function was negotiated, it's HMAC.
+ * XXX As PRF_HMAC currently is zero, this is a no-op.
+ */
+ if (!ie->prf_type)
+ ie->prf_type = PRF_HMAC;
+}
+
+static void
+ipsec_delete_spi (struct sa *sa, struct proto *proto, int initiator)
+{
+ if (sa->phase == 1)
+ return;
+ /* XXX Error handling? Is it interesting? */
+ sysdep_ipsec_delete_spi (sa, proto, initiator);
+}
+
+static int
+ipsec_g_x (struct message *msg, int peer, u_int8_t *buf)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ u_int8_t **g_x;
+ int initiator = exchange->initiator ^ peer;
+ char header[32];
+
+ g_x = initiator ? &ie->g_xi : &ie->g_xr;
+ *g_x = malloc (ie->g_x_len);
+ if (!*g_x)
+ return -1;
+ memcpy (*g_x, buf, ie->g_x_len);
+ snprintf (header, 32, "ipsec_g_x: g^x%c", initiator ? 'i' : 'r');
+ log_debug_buf (LOG_MISC, 80, header, *g_x, ie->g_x_len);
+ return 0;
+}
+
+/* Generate our DH value. */
+int
+ipsec_gen_g_x (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ u_int8_t *buf;
+
+ buf = malloc (ISAKMP_KE_SZ + ie->g_x_len);
+ if (!buf)
+ return -1;
+
+ if (message_add_payload (msg, ISAKMP_PAYLOAD_KEY_EXCH, buf,
+ ISAKMP_KE_SZ + ie->g_x_len, 1))
+ {
+ free (buf);
+ return -1;
+ }
+
+ dh_create_exchange (ie->group, buf + ISAKMP_KE_DATA_OFF);
+ return ipsec_g_x (msg, 0, buf + ISAKMP_KE_DATA_OFF);
+}
+
+/* Save the peer's DH value. */
+int
+ipsec_save_g_x (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ struct payload *kep;
+
+ kep = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_KEY_EXCH]);
+ kep->flags |= PL_MARK;
+ ie->g_x_len = GET_ISAKMP_GEN_LENGTH (kep->p) - ISAKMP_KE_DATA_OFF;
+
+ /* Check that the given length matches the group's expectancy. */
+ if (ie->g_x_len != dh_getlen (ie->group))
+ {
+ /* XXX Is this a good notify type? */
+ message_drop (msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 0, 0);
+ return -1;
+ }
+
+ return ipsec_g_x (msg, 1, kep->p + ISAKMP_KE_DATA_OFF);
+}
+
+/*
+ * Get a SPI for PROTO and the transport MSG passed over. Store the
+ * size where SZ points. NB! A zero return is OK if *SZ is zero.
+ */
+static u_int8_t *
+ipsec_get_spi (size_t *sz, u_int8_t proto, struct message *msg)
+{
+ struct sockaddr *dst;
+ int dstlen;
+ struct transport *transport = msg->transport;
+
+ if (msg->exchange->phase == 1)
+ {
+ *sz = 0;
+ return 0;
+ }
+ else
+ {
+ /* We are the destination in the SA we want a SPI for. */
+ transport->vtbl->get_src (transport, &dst, &dstlen);
+ return sysdep_ipsec_get_spi (sz, proto, dst, dstlen);
+ }
+}
+
+int
+ipsec_esp_enckeylength (struct proto *proto)
+{
+ struct ipsec_proto *iproto = proto->data;
+
+ /* Compute the keylength to use. */
+ switch (proto->id)
+ {
+ case IPSEC_ESP_DES:
+ case IPSEC_ESP_DES_IV32:
+ case IPSEC_ESP_DES_IV64:
+ return 8;
+ case IPSEC_ESP_3DES:
+ return 24;
+ default:
+ return iproto->keylen / 8;
+ }
+}
+
+int
+ipsec_esp_authkeylength (struct proto *proto)
+{
+ struct ipsec_proto *iproto = proto->data;
+
+ switch (iproto->auth)
+ {
+ case IPSEC_AUTH_HMAC_MD5:
+ return 16;
+ case IPSEC_AUTH_HMAC_SHA:
+ return 20;
+ default:
+ return 0;
+ }
+}
+
+int
+ipsec_ah_keylength (struct proto *proto)
+{
+ switch (proto->id)
+ {
+ case IPSEC_AH_MD5:
+ return 16;
+ case IPSEC_AH_SHA:
+ return 20;
+ default:
+ return -1;
+ }
+}
+
+int
+ipsec_keymat_length (struct proto *proto)
+{
+ switch (proto->proto)
+ {
+ case IPSEC_PROTO_IPSEC_ESP:
+ return ipsec_esp_enckeylength (proto) + ipsec_esp_authkeylength (proto);
+ case IPSEC_PROTO_IPSEC_AH:
+ return ipsec_ah_keylength (proto);
+ default:
+ return -1;
+ }
+}
diff --git a/sbin/isakmpd/ipsec.h b/sbin/isakmpd/ipsec.h
new file mode 100644
index 00000000000..f8f9bb254c6
--- /dev/null
+++ b/sbin/isakmpd/ipsec.h
@@ -0,0 +1,123 @@
+/* $Id: ipsec.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _IPSEC_H_
+#define _IPSEC_H_
+
+#include "ipsec_doi.h"
+
+struct group;
+struct hash;
+struct ike_auth;
+struct message;
+struct proto;
+struct sa;
+
+/*
+ * IPSEC-specific data to be linked into the exchange struct.
+ * XXX Should probably be two different structs, one for phase 1 and one
+ * for phase 2 parameters.
+ */
+struct ipsec_exch {
+ struct hash *hash;
+ struct ike_auth *ike_auth;
+ struct group *group;
+ u_int16_t prf_type;
+
+ /*
+ * A copy of the initiator SA payload body for later computation of hashes.
+ * Phase 1 only.
+ */
+ size_t sa_i_b_len;
+ u_int8_t *sa_i_b;
+
+ /* Diffie-Hellman values. */
+ size_t g_x_len;
+ u_int8_t *g_xi;
+ u_int8_t *g_xr;
+ u_int8_t* g_xy;
+
+ /* SKEYIDs. XXX Phase 1 only? */
+ size_t skeyid_len;
+ u_int8_t *skeyid;
+ u_int8_t *skeyid_d;
+ u_int8_t *skeyid_a;
+ u_int8_t *skeyid_e;
+
+ /* HASH_I & HASH_R. XXX Do these need to be saved here? */
+ u_int8_t *hash_i;
+ u_int8_t *hash_r;
+
+ /* KEYMAT */
+ size_t keymat_len;
+};
+
+struct ipsec_sa {
+ /* Phase 1. */
+ u_int8_t hash;
+ size_t skeyid_len;
+ u_int8_t *skeyid_d;
+ u_int8_t *skeyid_a;
+ u_int16_t prf_type;
+
+ /* Phase 2. */
+ u_int16_t group_desc;
+};
+
+struct ipsec_proto {
+ /* Phase 2. */
+ u_int16_t encap_mode;
+ u_int16_t auth;
+ u_int16_t keylen;
+ u_int16_t keyrounds;
+
+ /* KEYMAT */
+ u_int8_t *keymat[2];
+};
+
+extern int ipsec_ah_keylength (struct proto *);
+extern int ipsec_decode_attribute (u_int16_t, u_int8_t *, u_int16_t, void *);
+extern void ipsec_decode_transform (struct message *, struct sa *,
+ struct proto *, u_int8_t *);
+extern int ipsec_esp_authkeylength (struct proto *);
+extern int ipsec_esp_enckeylength (struct proto *);
+extern int ipsec_gen_g_x (struct message *);
+extern void ipsec_init (void);
+extern int ipsec_is_attribute_incompatible (u_int16_t, u_int8_t *, u_int16_t,
+ void *);
+extern int ipsec_keymat_length (struct proto *);
+extern int ipsec_save_g_x (struct message *);
+
+#endif /* _IPSEC_H_ */
diff --git a/sbin/isakmpd/ipsec_doi.h b/sbin/isakmpd/ipsec_doi.h
new file mode 100644
index 00000000000..dc62e72b4c5
--- /dev/null
+++ b/sbin/isakmpd/ipsec_doi.h
@@ -0,0 +1,45 @@
+/* $Id: ipsec_doi.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _IPSEC_DOI_H_
+#define _IPSEC_DOI_H_
+
+#include "ipsec_fld.h"
+#include "ipsec_num.h"
+
+/* The SPI size of all IPSEC protocols. XXX Correct? */
+#define IPSEC_SPI_SIZE 4
+
+#endif /* _IPSEC_DOI_H_ */
diff --git a/sbin/isakmpd/ipsec_fld.fld b/sbin/isakmpd/ipsec_fld.fld
new file mode 100644
index 00000000000..36dd47b6e94
--- /dev/null
+++ b/sbin/isakmpd/ipsec_fld.fld
@@ -0,0 +1,64 @@
+# $Id: ipsec_fld.fld,v 1.1 1998/11/15 00:03:48 niklas Exp $
+
+#
+# Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Ericsson Radio Systems.
+# 4. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# This code was written under funding by Ericsson Radio Systems.
+#
+
+# XXX There are num-declared fields below that really are csts.
+
+# IPSEC's situation field's subdivision.
+IPSEC_SIT
+ SIT mask 4 ipsec_sit_cst
+ LABELED_DOMAIN_ID num 4
+ SECRECY_LENGTH num 2
+ RESERVED_1 ign 2
+# The following fields' offsets need the secrecy length added + 32bit
+# alignment.
+ SECRECY_CAT_LENGTH num 2
+ RESERVED_2 ign 2
+# The following fields' offsets need the secrecy cat length added + 32bit
+# alignment on top of the aforementioned offset.
+ INTEGRITY_LENGTH num 2
+ RESERVED_3 ign 2
+# The following fields' offsets need the integrity length added + 32bit
+# alignment on top of the aforementioned offset.
+ INTEGRITY_CAT_LENGTH num 2
+ RESERVED_4 ign 2
+# The IPSEC_SIT record's length need the integrity cat length added + 32bit
+# alignment on top of the aforementioned offset.
+.
+
+# IPSEC's layout of the identification payload's DOI data field.
+IPSEC_ID
+ PROTO num 1
+ PORT num 2
+.
diff --git a/sbin/isakmpd/ipsec_num.cst b/sbin/isakmpd/ipsec_num.cst
new file mode 100644
index 00000000000..3a98db038bd
--- /dev/null
+++ b/sbin/isakmpd/ipsec_num.cst
@@ -0,0 +1,225 @@
+# $Id: ipsec_num.cst,v 1.1 1998/11/15 00:03:48 niklas Exp $
+
+#
+# Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Ericsson Radio Systems.
+# 4. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# This code was written under funding by Ericsson Radio Systems.
+#
+
+# XXX Please fill in references to the drafts, chapter & verse for each
+# constant group below.
+
+# IPSEC DOI Identifier.
+IPSEC_DOI
+ IPSEC 1
+.
+
+# IPSEC SA attributes
+IPSEC_ATTR
+ SA_LIFE_TYPE 1
+ SA_LIFE_DURATION 2
+ GROUP_DESCRIPTION 3
+ ENCAPSULATION_MODE 4
+ AUTHENTICATION_ALGORITHM 5
+ KEY_LENGTH 6
+ KEY_ROUNDS 7
+ COMPRESS_DICTIONARY_SIZE 8
+ COMPRESS_PRIVATE_ALGORITHM 9
+.
+
+# IPSEC SA duration.
+IPSEC_DURATION
+ SECONDS 1
+ KILOBYTES 2
+.
+
+# IPSEC encapsulation mode.
+IPSEC_ENCAP
+ TUNNEL 1
+ TRANSPORT 2
+.
+
+# IPSEC authentication algorithm.
+IPSEC_AUTH
+ HMAC_MD5 1
+ HMAC_SHA 2
+ DES_MAC 3
+ KPDK 4
+.
+
+# IPSEC ID types.
+IPSEC_ID
+ IPV4_ADDR 1
+ FQDN 2
+ USER_FQDN 3
+ IPV4_ADDR_SUBNET 4
+ IPV6_ADDR 5
+ IPV6_ADDR_SUBNET 6
+ IPV4_RANGE 7
+ IPV6_RANGE 8
+ DER_ASN1_DN 9
+ DER_ASN1_GN 10
+ KEY_ID 11
+.
+
+# IKE SA attributes
+IKE_ATTR
+ ENCRYPTION_ALGORITHM 1
+ HASH_ALGORITHM 2
+ AUTHENTICATION_METHOD 3
+ GROUP_DESCRIPTION 4
+ GROUP_TYPE 5
+ GROUP_PRIME 6
+ GROUP_GENERATOR_1 7
+ GROUP_GENERATOR_2 8
+ GROUP_CURVE_A 9
+ GROUP_CURVE_B 10
+ LIFE_TYPE 11
+ LIFE_DURATION 12
+ PRF 13
+ KEY_LENGTH 14
+ FIELD_SIZE 15
+ GROUP_ORDER 16
+.
+
+# XXX Fill in reserved ranges for the attributes below.
+
+# IKE encryption algorithm.
+IKE_ENCRYPT
+ DES_CBC 1
+ IDEA_CBC 2
+ BLOWFISH_CBC 3
+ RC5_R16_B64_CBC 4
+ 3DES_CBC 5
+ CAST_CBC 6
+.
+
+# IKE hash algorithm.
+IKE_HASH
+ MD5 1
+ SHA 2
+ TIGER 3
+.
+
+# IKE authentication method.
+IKE_AUTH
+ PRE_SHARED 1
+ DSS 2
+ RSA_SIG 3
+ RSA_ENC 4
+ RSA_ENC_REV 5
+.
+
+# IKE group description.
+IKE_GROUP_DESC
+ MODP_768 1
+ MODP_1024 2
+ EC2N_155 3
+ EC2N_185 4
+.
+
+# IKE Group type.
+IKE_GROUP
+ MODP 1
+ ECP 2
+ EC2N 3
+.
+
+# IKE SA duration.
+IKE_DURATION
+ SECONDS 1
+ KILOBYTES 2
+.
+
+# IKE Pseudo random function. No defined so far.
+IKE_PRF
+.
+
+# IPSEC Situation bits.
+IPSEC_SIT
+ IDENTITY_ONLY 1
+ SECRECY 2
+ INTEGRITY 4
+.
+
+# IPSEC security protocol IDs.
+IPSEC_PROTO
+ IPSEC_AH 2
+ IPSEC_ESP 3
+ IPCOMP 4
+.
+
+# IPSEC ISAKMP transform IDs.
+IPSEC_TRANSFORM
+ KEY_IKE 1
+.
+
+# IPSEC AH transform IDs.
+IPSEC_AH
+ MD5 2
+ SHA 3
+ DES 4
+.
+
+# IPSEC ESP transform IDs.
+IPSEC_ESP
+ DES_IV64 1
+ DES 2
+ 3DES 3
+ RC5 4
+ IDEA 5
+ CAST 6
+ BLOWFISH 7
+ 3IDEA 8
+ DES_IV32 9
+ RC4 10
+ NULL 11
+.
+
+# IPSEC IPCOMP transform IDs
+IPSEC_IPCOMP
+ OUI 1
+ DEFLATE 2
+ LZS 3
+ V42BIS 4
+.
+
+# IPSEC notify message types.
+IPSEC_NOTIFY
+ RESPONDER_LIFETIME 24576
+ REPLAY_STATUS 24577
+ INITIAL_CONTACT 24578
+.
+
+# IKE exchange types.
+IKE_EXCH
+ QUICK_MODE 32
+ NEW_GROUP_MODE 33
+.
diff --git a/sbin/isakmpd/isakmp.h b/sbin/isakmpd/isakmp.h
new file mode 100644
index 00000000000..01adf8dabca
--- /dev/null
+++ b/sbin/isakmpd/isakmp.h
@@ -0,0 +1,60 @@
+/* $Id: isakmp.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _ISAKMP_H_
+#define _ISAKMP_H_
+
+#include "isakmp_fld.h"
+#include "isakmp_num.h"
+
+/* IANA assigned port */
+#define UDP_DEFAULT_PORT 500
+
+/* ISAKMP header extras defines */
+#define ISAKMP_HDR_COOKIES_OFF ISAKMP_HDR_ICOOKIE_OFF
+#define ISAKMP_HDR_COOKIES_LEN (ISAKMP_HDR_ICOOKIE_LEN \
+ + ISAKMP_HDR_ICOOKIE_LEN)
+
+/* ISAKMP attribute utilitiy macros. */
+#define ISAKMP_ATTR_FORMAT(x) ((x) >> 15)
+#define ISAKMP_ATTR_TYPE(x) ((x) & 0x7fff)
+#define ISAKMP_ATTR_MAKE(fmt, type) (((fmt) << 15) | (type))
+
+/* Version number handling. */
+#define ISAKMP_VERSION_MAJOR(x) ((x) >> 4)
+#define ISAKMP_VERSION_MINOR(x) ((x) & 0xf)
+#define ISAKMP_VERSION_MAKE(maj, min) ((maj) << 4 | (min))
+
+#endif /* _ISAKMP_H_ */
diff --git a/sbin/isakmpd/isakmp_doi.c b/sbin/isakmpd/isakmp_doi.c
new file mode 100644
index 00000000000..6c87d8bcccd
--- /dev/null
+++ b/sbin/isakmpd/isakmp_doi.c
@@ -0,0 +1,218 @@
+/* $Id: isakmp_doi.c,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+/*
+ * XXX This DOI is very fuzzily defined, and should perhaps be short-circuited
+ * to the IPSEC DOI instead. At the moment I will have it as its own DOI,
+ * as the ISAKMP architecture seems to imply it should be done like this.
+ */
+
+#include <sys/types.h>
+
+#include "doi.h"
+#include "exchange.h"
+#include "isakmp.h"
+#include "log.h"
+#include "message.h"
+#include "sa.h"
+#include "util.h"
+
+static int isakmp_debug_attribute (u_int16_t, u_int8_t *, u_int16_t, void *);
+static void isakmp_finalize_exchange (struct message *);
+static struct keystate *isakmp_get_keystate (struct message *);
+static int isakmp_initiator (struct message *);
+static int isakmp_responder (struct message *);
+static void isakmp_setup_situation (u_int8_t *);
+static size_t isakmp_situation_size (void);
+static u_int8_t isakmp_spi_size (u_int8_t);
+static int isakmp_validate_attribute (u_int16_t, u_int8_t *, u_int16_t,
+ void *);
+static int isakmp_validate_exchange (u_int8_t);
+static int isakmp_validate_id_information (u_int8_t, u_int8_t *, u_int8_t *,
+ size_t, struct exchange *);
+static int isakmp_validate_key_information (u_int8_t *, size_t);
+static int isakmp_validate_notification (u_int16_t);
+static int isakmp_validate_proto (u_int8_t);
+static int isakmp_validate_situation (u_int8_t *, size_t *);
+static int isakmp_validate_transform_id (u_int8_t, u_int8_t);
+
+static struct doi isakmp_doi = {
+ { 0 }, ISAKMP_DOI_ISAKMP, 0, 0, 0,
+ isakmp_debug_attribute,
+ 0, /* delete_spi not needed. */
+ 0, /* exchange_script not needed. */
+ isakmp_finalize_exchange,
+ 0, /* free_exchange_data not needed. */
+ 0, /* free_proto_data not needed. */
+ 0, /* free_sa_data not needed. */
+ isakmp_get_keystate,
+ 0, /* get_spi not needed. */
+ 0, /* XXX need maybe be filled-in. */
+ isakmp_setup_situation,
+ isakmp_situation_size,
+ isakmp_spi_size,
+ isakmp_validate_attribute,
+ isakmp_validate_exchange,
+ isakmp_validate_id_information,
+ isakmp_validate_key_information,
+ isakmp_validate_notification,
+ isakmp_validate_proto,
+ isakmp_validate_situation,
+ isakmp_validate_transform_id,
+ isakmp_initiator,
+ isakmp_responder
+};
+
+/* Requires doi_init to already have been called. */
+void
+isakmp_doi_init ()
+{
+ doi_register (&isakmp_doi);
+}
+
+int
+isakmp_debug_attribute (u_int16_t type, u_int8_t *value, u_int16_t len,
+ void *vmsg)
+{
+ /* XXX Not implemented yet. */
+ return 0;
+}
+
+static void
+isakmp_finalize_exchange (struct message *msg)
+{
+}
+
+static struct keystate *
+isakmp_get_keystate (struct message *msg)
+{
+ return 0;
+}
+
+static void
+isakmp_setup_situation (u_int8_t *buf)
+{
+ /* Nothing to do. */
+}
+
+static size_t
+isakmp_situation_size (void)
+{
+ return 0;
+}
+
+static u_int8_t
+isakmp_spi_size (u_int8_t proto)
+{
+ /* One way to specify ISAKMP SPIs is to say they're zero-sized. */
+ return 0;
+}
+
+static int
+isakmp_validate_attribute (u_int16_t type, u_int8_t *value, u_int16_t len,
+ void *vmsg)
+{
+ /* XXX Not implemented yet. */
+ return -1;
+}
+
+static int
+isakmp_validate_exchange (u_int8_t exch)
+{
+ /* If we get here the exchange is invalid. */
+ return -1;
+}
+
+static int
+isakmp_validate_id_information (u_int8_t type, u_int8_t *extra, u_int8_t *buf,
+ size_t sz, struct exchange *exchange)
+{
+ return zero_test (extra, ISAKMP_ID_DOI_DATA_LEN);
+}
+
+static int
+isakmp_validate_key_information (u_int8_t *buf, size_t sz)
+{
+ /* Nothing to do. */
+ return 0;
+}
+
+static int
+isakmp_validate_notification (u_int16_t type)
+{
+ /* If we get here the message type is invalid. */
+ return -1;
+}
+
+static int
+isakmp_validate_proto (u_int8_t proto)
+{
+ /* If we get here the protocol is invalid. */
+ return -1;
+}
+
+static int
+isakmp_validate_situation (u_int8_t *buf, size_t *sz)
+{
+ /* There are no situations in the ISAKMP DOI. */
+ *sz = 0;
+ return 0;
+}
+
+static int
+isakmp_validate_transform_id (u_int8_t proto, u_int8_t transform_id)
+{
+ /* XXX Not yet implemented. */
+ return -1;
+}
+
+static int
+isakmp_initiator (struct message *msg)
+{
+ /* XXX Not implemented yet. */
+ return 0;
+}
+
+static int
+isakmp_responder (struct message *msg)
+{
+ /* XXX So far we don't accept any proposals. */
+ if (TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_SA]))
+ {
+ message_drop (msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 0, 0);
+ return -1;
+ }
+ return 0;
+}
diff --git a/sbin/isakmpd/isakmp_doi.h b/sbin/isakmpd/isakmp_doi.h
new file mode 100644
index 00000000000..a1cbf6de37a
--- /dev/null
+++ b/sbin/isakmpd/isakmp_doi.h
@@ -0,0 +1,41 @@
+/* $Id: isakmp_doi.h,v 1.1 1998/11/15 00:03:48 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _ISAKMP_DOI_H_
+#define _ISAKMP_DOI_H_
+
+extern void isakmp_doi_init (void);
+
+#endif /* _ISAKMP_DOI_H_ */
diff --git a/sbin/isakmpd/isakmp_fld.fld b/sbin/isakmpd/isakmp_fld.fld
new file mode 100644
index 00000000000..19e2e36425f
--- /dev/null
+++ b/sbin/isakmpd/isakmp_fld.fld
@@ -0,0 +1,148 @@
+# $Id: isakmp_fld.fld,v 1.1 1998/11/15 00:03:48 niklas Exp $
+
+#
+# Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Ericsson Radio Systems.
+# 4. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# This code was written under funding by Ericsson Radio Systems.
+#
+
+# XXX There are num-declared fields below that really are csts.
+
+# The ISAKMP message header.
+ISAKMP_HDR
+# XXX I want a way to specify COOKIES as an overlay of ICOOKIE + RCOOKIE
+ ICOOKIE raw 8
+ RCOOKIE raw 8
+ NEXT_PAYLOAD cst 1 isakmp_payload_cst
+ VERSION num 1
+ EXCH_TYPE cst 1 ike_exch_cst,isakmp_exch_cst
+ FLAGS mask 1 isakmp_flags_cst
+ MESSAGE_ID raw 4
+ LENGTH num 4
+.
+
+# Generic payload header.
+ISAKMP_GEN
+ NEXT_PAYLOAD cst 1 isakmp_payload_cst
+ RESERVED ign 1
+ LENGTH num 2
+.
+
+# ISAKMP data attributes
+ISAKMP_ATTR
+ TYPE num 2
+ LENGTH_VALUE num 2
+ VALUE raw
+.
+
+# Security association payload.
+ISAKMP_SA : ISAKMP_GEN
+ DOI num 4 isakmp_doi_cst,ipsec_doi_cst
+ SIT raw
+.
+
+# Proposal payload.
+ISAKMP_PROP : ISAKMP_GEN
+ NO num 1
+ PROTO cst 1 isakmp_proto_cst,ipsec_proto_cst
+ SPI_SZ num 1
+ NTRANSFORMS num 1
+ SPI raw
+.
+
+# Transform payload.
+ISAKMP_TRANSFORM : ISAKMP_GEN
+ NO num 1
+ ID num 1
+ RESERVED ign 2
+ SA_ATTRS raw
+.
+
+# Key exchange payload.
+ISAKMP_KE : ISAKMP_GEN
+ DATA raw
+.
+
+# Identification payload.
+ISAKMP_ID : ISAKMP_GEN
+ TYPE num 1
+ DOI_DATA raw 3
+ DATA raw
+.
+
+# Certificate payload.
+ISAKMP_CERT : ISAKMP_GEN
+ ENCODING cst 1 isakmp_certenc_cst
+ DATA raw
+.
+
+# Certificate request payload.
+ISAKMP_CERTREQ : ISAKMP_GEN
+ TYPE cst 1 isakmp_certenc_cst
+ AUTHORITY raw
+.
+
+# Hash payload.
+ISAKMP_HASH : ISAKMP_GEN
+ DATA raw
+.
+
+# Signature payload.
+ISAKMP_SIG : ISAKMP_GEN
+ DATA raw
+.
+
+# Nonce payload.
+ISAKMP_NONCE : ISAKMP_GEN
+ DATA raw
+.
+
+# Notify payload.
+ISAKMP_NOTIFY : ISAKMP_GEN
+ DOI cst 4 isakmp_doi_cst,ipsec_doi_cst
+ PROTO cst 1 isakmp_proto_cst
+ SPI_SZ num 1
+ MSG_TYPE cst 2 isakmp_notify_cst
+ SPI raw
+.
+
+# Delete payload.
+ISAKMP_DELETE : ISAKMP_GEN
+ DOI cst 4 isakmp_doi_cst,ipsec_doi_cst
+ PROTO cst 1 isakmp_proto_cst
+ SPI_SZ num 1
+ NSPIS num 2
+ SPI raw
+.
+
+# Vendor ID payload.
+ISAKMP_VENDOR : ISAKMP_GEN
+ ID raw
+.
diff --git a/sbin/isakmpd/isakmp_num.cst b/sbin/isakmpd/isakmp_num.cst
new file mode 100644
index 00000000000..af292c8d8b2
--- /dev/null
+++ b/sbin/isakmpd/isakmp_num.cst
@@ -0,0 +1,156 @@
+# $Id: isakmp_num.cst,v 1.1 1998/11/15 00:03:48 niklas Exp $
+
+#
+# Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Ericsson Radio Systems.
+# 4. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# This code was written under funding by Ericsson Radio Systems.
+#
+
+# XXX Please fill in references to the drafts, chapter & verse for each
+# constant group below.
+# Also think about ranges, can they be specified diferently? Can we use
+# these constants for vlidity checks?
+
+# ISAKMP payload type.
+ISAKMP_PAYLOAD
+ NONE 0
+ SA 1
+ PROPOSAL 2
+ TRANSFORM 3
+ KEY_EXCH 4
+ ID 5
+ CERT 6
+ CERT_REQ 7
+ HASH 8
+ SIG 9
+ NONCE 10
+ NOTIFY 11
+ DELETE 12
+ VENDOR 13
+ RESERVED_MIN 14
+ RESERVED_MAX 127
+ PRIVATE_MIN 128
+ PRIVATE_MAX 255
+.
+
+# ISAKMP exchange types.
+ISAKMP_EXCH
+ NONE 0
+ BASE 1
+ ID_PROT 2
+ AUTH_ONLY 3
+ AGGRESSIVE 4
+ INFO 5
+ FUTURE_MIN 6
+ FUTURE_MAX 31
+ DOI_MIN 32
+ DOI_MAX 255
+.
+
+# ISAKMP flags.
+ISAKMP_FLAGS
+ ENC 1
+ COMMIT 2
+ AUTH_ONLY 4
+.
+
+# ISAKMP certificate encoding.
+ISAKMP_CERTENC
+ NONE 0
+ PKCS 1
+ PGP 2
+ DNS 3
+ X509_SIG 4
+ X509_KE 5
+ KERBEROS 6
+ CRL 7
+ ARL 8
+ SPKI 9
+ X509_ATTR 10
+ RESERVED_MIN 11
+ RESERVED_MAX 255
+.
+
+# ISAKMP Notify message types.
+ISAKMP_NOTIFY
+ INVALID_PAYLOAD_TYPE 1
+ DOI_NOT_SUPPORTED 2
+ SITUATION_NOT_SUPPORTED 3
+ INVALID_COOKIE 4
+ INVALID_MAJOR_VERSION 5
+ INVALID_MINOR_VERSION 6
+ INVALID_EXCHANGE_TYPE 7
+ INVALID_FLAGS 8
+ INVALID_MESSAGE_ID 9
+ INVALID_PROTOCOL_ID 10
+ INVALID_SPI 11
+ INVALID_TRANSFORM_ID 12
+ ATTRIBUTES_NOT_SUPPORTED 13
+ NO_PROPOSAL_CHOSEN 14
+ BAD_PROPOSAL_SYNTAX 15
+ PAYLOAD_MALFORMED 16
+ INVALID_KEY_INFORMATION 17
+ INVALID_ID_INFORMATION 18
+ INVALID_CERT_ENCODING 19
+ INVALID_CERTIFICATE 20
+ CERT_TYPE_UNSUPPORTED 21
+ INVALID_CERT_AUTHORITY 22
+ INVALID_HASH_INFORMATION 23
+ AUTHENTICATION_FAILED 24
+ INVALID_SIGNATURE 25
+ ADDRESS_NOTIFICATION 26
+ NOTIFY_SA_LIFETIME 27
+ CERTIFICATE_UNAVAILABLE 28
+ UNSUPPORTED_EXCHANGE_TYPE 29
+ UNEQUAL_PAYLOAD_LENGTHS 30
+ RESERVED_MIN 31
+ RESERVED_MAX 8191
+ PRIVATE_MIN 8192
+ PRIVATE_MAX 16383
+ STATUS_CONNECTED 16384
+ STATUS_RESERVED1_MIN 16385
+ STATUS_RESERVED1_MAX 24575
+ STATUS_DOI_MIN 12576
+ STATUS_DOI_MAX 32767
+ STATUS_PRIVATE_MIN 32768
+ STATUS_PRIVATE_MAX 40959
+ STATUS_RESERVED2_MIN 40960
+ STATUS_RESERVED2_MAX 65535
+.
+
+# ISAKMP DOI Identifier.
+ISAKMP_DOI
+ ISAKMP 0
+.
+
+# ISAKMP Protocol ID.
+ISAKMP_PROTO
+ ISAKMP 1
+.
diff --git a/sbin/isakmpd/isakmpd.8 b/sbin/isakmpd/isakmpd.8
new file mode 100644
index 00000000000..41edaf860c8
--- /dev/null
+++ b/sbin/isakmpd/isakmpd.8
@@ -0,0 +1,116 @@
+.\" $Id: isakmpd.8,v 1.1 1998/11/15 00:03:48 niklas Exp $
+.\"
+.\" Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Ericsson Radio Systems.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" This code was written under funding by Ericsson Radio Systems.
+.\"
+.\" Manual page, using -mandoc macros
+.\"
+.Dd July 31, 1998
+.Dt ISAKMPD 8
+.Os
+.Sh NAME
+.Nm isakmpd
+.Nd ISAKMP/Oakley aka IKE key management daemon
+.Sh SYNOPSIS
+.Nm isakmpd
+.Op Fl c Ar config-file
+.Op Fl d
+.Op Fl D Ar debug-class=level
+.Op Fl f Ar fifo
+.Op Fl n
+.Op Fl p Ar listen-port
+.Op Fl P Ar local-port
+.Op Fl r Ar seed
+.Sh DESCRIPTION
+The
+.Nm ISAKMP
+daemon establishes security associations for encrypted
+and/or authenticated network traffic.
+.Pp
+The daemon listens to a named pipe
+.Pa isakmpd.fifo
+for user requests and on a
+.Nm PF_ENCAP
+socket for kernel requests.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl c
+If given, the
+.Fl c
+option specifies an alternate configuration file instead of
+.Pa /etc/isakmpd.conf .
+.It Fl d
+The
+.Fl d
+option is used to make the daemon run in the foreground, logging to stderr.
+.It Fl D
+This argument is possible to specify many times. It takes a parameter of
+the form: class=level where both class and level are numbers. Class denotes
+a debugging class, and level the level you want that debugging class to
+limit debug printouts at. I.e. all debug printouts above the level specified
+will not output anything.
+.It Fl f
+The
+.Fl f
+option specifies the fifo (aka named pipe) where the daemon listens for
+user requests. If the path given is a dash,
+.Nm isakmpd
+will listen to stdin instead.
+.It Fl n
+When the
+.Fl n
+option is given, the kernel will not take part in the negotiations.
+This is a non-destructive mode so to say, in that it won't alter any
+SAs in the IPSEC stack.
+.It Fl r
+If given a deterministic random number sequence will be used internally.
+This is useful for setting up regression tests.
+.It Fl p
+The
+.Fl p
+option specifies the listen port the daemon will bind to.
+.It Fl P
+On the other hand, the port spcified to capital
+.Fl P
+will be what the daemon binds its local end to when acting as initiator.
+.El
+.Pp
+.Sh SEE ALSO
+.Xr isakmpd.conf 5 ,
+.Xr photurisd 8 ,
+.Xr ipsec 4 .
+.Sh HISTORY
+The ISAKMP/Oakley keymanagement protocol is described in the internet drafts
+.Nm draft-ietf-ipsec-isakmp ,
+.Nm draft-ietf-ipsec-ipsec-doi &
+.Nm draft-ietf-ipsec-isakmp-oakley .
+This implementation was done 1998 by Niklas Hallqvist and Niels Provos,
+sponsored by Ericsson Radio Systems.
+
diff --git a/sbin/isakmpd/isakmpd.c b/sbin/isakmpd/isakmpd.c
new file mode 100644
index 00000000000..0b334d4405f
--- /dev/null
+++ b/sbin/isakmpd/isakmpd.c
@@ -0,0 +1,220 @@
+/* $Id: isakmpd.c,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "app.h"
+#include "conf.h"
+#include "init.h"
+#include "log.h"
+#include "sysdep.h"
+#include "timer.h"
+#include "transport.h"
+#include "udp.h"
+#include "ui.h"
+
+extern char *optarg;
+extern int optind;
+
+/*
+ * Set if -d is given, currently just for running in the foreground and log
+ * to stderr instead of syslog.
+ */
+int debug = 0;
+
+/*
+ * Use -r seed to initalize random numbers to a deterministic sequence.
+ */
+extern int regrand;
+
+/*
+ * If we receive a SIGHUP signal, this flag gets set to show we need to
+ * reconfigure ASAP.
+ */
+static int sighupped = 0;
+
+static void
+usage ()
+{
+ fprintf (stderr,
+ "usage: %s [-d] [-c config-file] [-D class=level] [-f fifo] [-n]\n"
+ " [-p listen-port] [-P local-port] [-r seed]\n",
+ sysdep_progname ());
+ exit (1);
+}
+
+static void
+parse_args (int argc, char *argv[])
+{
+ int ch, cls, level;
+
+ while ((ch = getopt (argc, argv, "c:dD:f:np:P:r:")) != -1) {
+ switch (ch) {
+ case 'c':
+ conf_path = optarg;
+ break;
+ case 'd':
+ debug++;
+ break;
+ case 'D':
+ if (sscanf (optarg, "%d=%d", &cls, &level) != 2)
+ log_print ("parse_args: -D argument unparseable: %s", optarg);
+ else
+ log_debug_cmd (cls, level);
+ break;
+ case 'f':
+ ui_fifo = optarg;
+ break;
+ case 'n':
+ app_none++;
+ break;
+ case 'p':
+ udp_default_port = atoi (optarg);
+ break;
+ case 'P':
+ udp_bind_port = atoi (optarg);
+ break;
+ case 'r':
+ srandom (strtoul (optarg, NULL, 0));
+ regrand = 1;
+ break;
+ case '?':
+ default:
+ usage ();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+}
+
+/* Reinitialize after a SIGHUP reception. */
+static void
+reinit (void)
+{
+ /* Reread config file. */
+ conf_init ();
+
+ /* XXX Rescan interfaces. */
+
+ sighupped = 0;
+}
+
+static void
+sighup (int sig)
+{
+ sighupped = 1;
+}
+
+int
+main (int argc, char *argv[])
+{
+ fd_set rfds, wfds;
+ int n, m;
+ struct timeval tv, *timeout = &tv;
+
+ parse_args (argc, argv);
+ init ();
+ if (!debug)
+ {
+ if (daemon (0, 0))
+ log_fatal ("daemon");
+ /* Switch to syslog. */
+ log_to (0);
+ }
+
+ /* Reinitialize on HUP reception. */
+ signal (SIGHUP, sighup);
+
+ while (1)
+ {
+ /* If someone has sent SIGHUP to us, reconfigure. */
+ if (sighupped)
+ reinit ();
+
+ /* Setup the descriptors to look for incoming messages at. */
+ FD_ZERO (&rfds);
+ n = transport_fd_set (&rfds);
+ FD_SET (ui_socket, &rfds);
+ if (ui_socket + 1 > n)
+ n = ui_socket + 1;
+
+ /*
+ * XXX Some day we might want to deal with an abstract application
+ * class instead, with many instantiations possible.
+ */
+ if (!app_none)
+ {
+ FD_SET (app_socket, &rfds);
+ if (app_socket + 1 > n)
+ n = app_socket + 1;
+ }
+
+ /* Setup the descriptors that have pending messages to send. */
+ FD_ZERO (&wfds);
+ m = transport_pending_wfd_set (&wfds);
+ if (m > n)
+ n = m;
+
+ /* Find out when the next timed event is. */
+ timer_next_event (&timeout);
+
+ n = select (n, &rfds, &wfds, 0, timeout);
+ if (n == -1)
+ {
+ log_error ("select");
+ /*
+ * In order to give the unexpected error condition time to resolve
+ * without letting this process eat up all available CPU we sleep
+ * for a short while.
+ */
+ sleep (1);
+ }
+ else if (n)
+ {
+ transport_handle_messages (&rfds);
+ transport_send_messages (&wfds);
+ if (FD_ISSET (ui_socket, &rfds))
+ ui_handler ();
+ if (!app_none && FD_ISSET (app_socket, &rfds))
+ app_handler ();
+ }
+ timer_handle_expirations ();
+ }
+}
diff --git a/sbin/isakmpd/isakmpd.conf.5 b/sbin/isakmpd/isakmpd.conf.5
new file mode 100644
index 00000000000..1f767dafb70
--- /dev/null
+++ b/sbin/isakmpd/isakmpd.conf.5
@@ -0,0 +1,175 @@
+.\" $Id: isakmpd.conf.5,v 1.1 1998/11/15 00:03:49 niklas Exp $
+.\"
+.\" Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Ericsson Radio Systems.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" This code was written under funding by Ericsson Radio Systems.
+.\"
+.\" Manual page, using -mandoc macros
+.\"
+.Dd October 10, 1998
+.Dt ISAKMPD.CONF 8
+.Os
+.Sh NAME
+.Nm isakmpd.conf
+.Nd Configuration file for isakmpd
+.Sh DESCRIPTION
+The
+.Nm isakmpd.conf
+is the configuration file for
+.Nm isakmpd
+daemon managing security association and key management for the
+.Nm IPSEC
+layer of the kernel's networking stack.
+.Pp
+The file is of a well known type of format called .INI style, named after
+the suffix used by an overrated windowing environment for its configuration
+files. This format consists of sections, each beginning with a line looking
+like:
+.Bd -literal
+[Section name]
+.Ed
+Between the brackets is the name of the section following this section header.
+Inside a section many tag/value pairs can be stored, each one looking like:
+.Bd -literal
+Tag=Value
+.Ed
+If the value needs more space than fits on a single line it's possible to
+continue it on the next by ending the first with a backspace character
+immediately before the newline character. This method can extend a value for
+an arbitrary amount of lines.
+.Pp
+Comments can be put anywhere in the file by using a hash mark, "#". Then
+the comment goes on to the end of the line.
+.Pp
+.Sh EXAMPLE
+An example of a configuration file:
+.Pp
+.Bd -literal
+# A configuration sample for the isakmpd ISAKMP/Oakley (aka IKE) daemon.
+
+[General]
+Retransmits= 10
+
+[Main mode initiator]
+Offered-transforms= BLF-SHA-16,DES-MD5
+
+[Main mode responder]
+# XXX Not yet supported.
+#Accepted-transforms= BLF-SHA-M1024,BLF-SHA-EC185,BLF-SHA-EC155,DES-MD5
+
+[DES-MD5]
+ENCRYPTION_ALGORITHM= DES_CBC
+HASH_ALGORITHM= MD5
+AUTHENTICATION_METHOD= PRE_SHARED
+GROUP_DESCRIPTION= MODP_768
+
+[BLF-SHA-16]
+ENCRYPTION_ALGORITHM= BLOWFISH_CBC
+KEY_LENGTH= 128
+HASH_ALGORITHM= SHA
+AUTHENTICATION_METHOD= PRE_SHARED
+GROUP_DESCRIPTION= MODP_1024
+
+[BLF-SHA-M1024]
+ENCRYPTION_ALGORITHM= BLOWFISH
+HASH_ALGORITHM= SHA
+AUTHENTICATION_METHOD= PRE_SHARED
+GROUP_DESCRIPTION= MODP_1024
+
+[BLF-SHA-EC155]
+ENCRYPTION_ALGORITHM= BLOWFISH
+HASH_ALGORITHM= SHA
+AUTHENTICATION_METHOD= PRE_SHARED
+GROUP_DESCRIPTION= EC2N_155
+
+[BLF-SHA-EC185]
+ENCRYPTION_ALGORITHM= BLOWFISH
+HASH_ALGORITHM= SHA
+AUTHENTICATION_METHOD= PRE_SHARED
+GROUP_DESCRIPTION= EC2N_185
+
+[Quick mode initiator]
+Offered-suites= QM-ESP-DES-MD5-SUITE,QM-AH-MD5-ESP-DES-SUITE
+
+[Quick mode responder]
+# XXX Not yet supported.
+#Accepted-suites= QM-ESP-DES-MD5-SUITE,QM-AH-MD5-ESP-DES-SUITE
+
+[QM-ESP-DES-MD5-SUITE]
+Protocols= QM-ESP-DES-MD5
+
+[QM-ESP-DES-MD5]
+PROTOCOL_ID= IPSEC_ESP
+Transforms= QM-ESP-DES-MD5-XF
+
+[QM-ESP-DES-MD5-XF]
+TRANSFORM_ID= DES
+ENCAPSULATION_MODE= TUNNEL
+AUTHENTICATION_ALGORITHM= HMAC_MD5
+Life= LIFE_600_SECS,LIFE_32_MB
+
+[LIFE_600_SECS]
+SA_LIFE_TYPE= SECONDS
+SA_LIFE_DURATION= 600
+
+[LIFE_32_MB]
+SA_LIFE_TYPE= KILOBYTES
+SA_LIFE_DURATION= 32768
+
+[QM-AH-MD5-ESP-DES-SUITE]
+Protocols= QM-AH-MD5,QM-ESP-DES
+
+[QM-AH-MD5]
+PROTOCOL_ID= IPSEC_AH
+Transforms= QM-AH-MD5-XF
+
+[QM-AH-MD5-XF]
+TRANSFORM_ID= MD5
+ENCAPSULATION_MODE= TUNNEL
+
+[QM-ESP-DES]
+PROTOCOL_ID= IPSEC_ESP
+Transforms= QM-ESP-DES-XF
+
+[QM-ESP-DES-XF]
+TRANSFORM_ID= DES
+ENCAPSULATION_MODE= TUNNEL
+
+[PRE_SHARED]
+# A general pre-shared key used for everyone. XXX Should be per-peer later.
+KEY= mekmitasdigoat
+
+[RSA_SIG]
+CERT= /etc/isakmpd_cert
+PRIVKEY= /etc/isakmpd_key
+PUBKEY= /etc/isakmpd_key.pub
+.Ed
+.Pp
+.Sh SEE ALSO
+.Xr isakmpd 8 .
+
diff --git a/sbin/isakmpd/isakmpd.conf.sample b/sbin/isakmpd/isakmpd.conf.sample
new file mode 100644
index 00000000000..60eb1bf3a04
--- /dev/null
+++ b/sbin/isakmpd/isakmpd.conf.sample
@@ -0,0 +1,111 @@
+# $Id: isakmpd.conf.sample,v 1.1 1998/11/15 00:03:49 niklas Exp $
+
+# A configuration sample for the isakmpd ISAKMP/Oakley (aka IKE) daemon.
+
+[General]
+Retransmits= 10
+
+[Main mode initiator]
+Offered-transforms= BLF-SHA-16,DES-MD5
+
+[Main mode responder]
+# XXX Not yet supported.
+#Accepted-transforms= BLF-SHA-M1024,BLF-SHA-EC185,BLF-SHA-EC155,DES-MD5
+
+[DES-MD5]
+ENCRYPTION_ALGORITHM= DES_CBC
+HASH_ALGORITHM= MD5
+AUTHENTICATION_METHOD= PRE_SHARED
+GROUP_DESCRIPTION= MODP_768
+Life= LIFE_600_SECS
+
+[BLF-SHA-16]
+ENCRYPTION_ALGORITHM= BLOWFISH_CBC
+KEY_LENGTH= 128
+HASH_ALGORITHM= SHA
+AUTHENTICATION_METHOD= PRE_SHARED
+GROUP_DESCRIPTION= MODP_1024
+Life= LIFE_600_SECS
+
+[BLF-SHA-M1024]
+ENCRYPTION_ALGORITHM= BLOWFISH
+HASH_ALGORITHM= SHA
+AUTHENTICATION_METHOD= PRE_SHARED
+GROUP_DESCRIPTION= MODP_1024
+Life= LIFE_600_SECS
+
+[BLF-SHA-EC155]
+ENCRYPTION_ALGORITHM= BLOWFISH
+HASH_ALGORITHM= SHA
+AUTHENTICATION_METHOD= PRE_SHARED
+GROUP_DESCRIPTION= EC2N_155
+Life= LIFE_600_SECS
+
+[BLF-SHA-EC185]
+ENCRYPTION_ALGORITHM= BLOWFISH
+HASH_ALGORITHM= SHA
+AUTHENTICATION_METHOD= PRE_SHARED
+GROUP_DESCRIPTION= EC2N_185
+Life= LIFE_600_SECS
+
+[Quick mode initiator]
+#Offered-suites= QM-ESP-DES-SUITE,\
+# QM-ESP-DES-MD5-SUITE,QM-AH-MD5-ESP-DES-SUITE
+Offered-suites= QM-ESP-DES-SUITE
+
+[Quick mode responder]
+# XXX Not yet supported.
+#Accepted-suites= QM-ESP-DES-MD5-SUITE,QM-AH-MD5-ESP-DES-SUITE
+
+[QM-ESP-DES-SUITE]
+Protocols= QM-ESP-DES
+
+[QM-ESP-DES-MD5-SUITE]
+Protocols= QM-ESP-DES-MD5
+
+[QM-ESP-DES-MD5]
+PROTOCOL_ID= IPSEC_ESP
+Transforms= QM-ESP-DES-MD5-XF
+
+[QM-ESP-DES-MD5-XF]
+TRANSFORM_ID= DES
+ENCAPSULATION_MODE= TUNNEL
+AUTHENTICATION_ALGORITHM= HMAC_MD5
+Life= LIFE_600_SECS,LIFE_32_MB
+
+[LIFE_600_SECS]
+SA_LIFE_TYPE= SECONDS
+SA_LIFE_DURATION= 600
+
+[LIFE_32_MB]
+SA_LIFE_TYPE= KILOBYTES
+SA_LIFE_DURATION= 32768
+
+[QM-AH-MD5-ESP-DES-SUITE]
+Protocols= QM-AH-MD5,QM-ESP-DES
+
+[QM-AH-MD5]
+PROTOCOL_ID= IPSEC_AH
+Transforms= QM-AH-MD5-XF
+
+[QM-AH-MD5-XF]
+TRANSFORM_ID= MD5
+ENCAPSULATION_MODE= TUNNEL
+
+[QM-ESP-DES]
+PROTOCOL_ID= IPSEC_ESP
+Transforms= QM-ESP-DES-XF
+
+[QM-ESP-DES-XF]
+TRANSFORM_ID= DES
+ENCAPSULATION_MODE= TUNNEL
+Life= LIFE_600_SECS,LIFE_32_MB
+
+[PRE_SHARED]
+# A general pre-shared key used for everyone. XXX Should be per-peer later.
+KEY= mekmitasdigoat
+
+[RSA_SIG]
+CERT= /etc/isakmpd_cert
+PRIVKEY= /etc/isakmpd_key
+PUBKEY= /etc/isakmpd_key.pub
diff --git a/sbin/isakmpd/isakmpd_cert.sample b/sbin/isakmpd/isakmpd_cert.sample
new file mode 100644
index 00000000000..b573cb0152f
--- /dev/null
+++ b/sbin/isakmpd/isakmpd_cert.sample
Binary files differ
diff --git a/sbin/isakmpd/isakmpd_key.pub.sample b/sbin/isakmpd/isakmpd_key.pub.sample
new file mode 100644
index 00000000000..edce091937c
--- /dev/null
+++ b/sbin/isakmpd/isakmpd_key.pub.sample
Binary files differ
diff --git a/sbin/isakmpd/isakmpd_key.sample b/sbin/isakmpd/isakmpd_key.sample
new file mode 100644
index 00000000000..e022e420842
--- /dev/null
+++ b/sbin/isakmpd/isakmpd_key.sample
Binary files differ
diff --git a/sbin/isakmpd/log.c b/sbin/isakmpd/log.c
new file mode 100644
index 00000000000..587198b75ec
--- /dev/null
+++ b/sbin/isakmpd/log.c
@@ -0,0 +1,240 @@
+/* $Id: log.c,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include "log.h"
+
+/*
+ * We cannot do the log strings dynamically sizeable as out of memory is one
+ * of the situations we need to report about.
+ */
+#define LOG_SIZE 200
+
+static void _log_print (int, int, const char *, va_list);
+
+static FILE *log_output = stderr;
+static int log_level[LOG_ENDCLASS];
+
+void
+log_to (FILE *f)
+{
+ if (!log_output && f)
+ closelog ();
+ log_output = f;
+ if (!f)
+ openlog ("isakmpd", 0, LOG_DAEMON);
+}
+
+static void
+_log_print (int error, int level, const char *fmt, va_list ap)
+{
+ char buffer[LOG_SIZE];
+ int len;
+
+ len = vsnprintf (buffer, LOG_SIZE, fmt, ap);
+ if (len < LOG_SIZE - 1 && error)
+ snprintf (buffer + len, LOG_SIZE - len, ": %s", strerror (errno));
+ if (log_output)
+ {
+ fputs (buffer, log_output);
+ fputc ('\n', log_output);
+ }
+ else
+ syslog (level, buffer);
+}
+
+void
+#ifdef __STDC__
+log_debug (int cls, int level, const char *fmt, ...)
+#else
+log_debug (cls, level, clfmt, va_alist)
+ int cls;
+ int level;
+ const char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+ /*
+ * If we are not debugging this class, or the level is too low, just return.
+ */
+ if (log_level[cls] == 0 || level > log_level[cls])
+ return;
+#ifdef __STDC__
+ va_start (ap, fmt);
+#else
+ va_start (ap);
+ fmt = va_arg (ap, const char *);
+#endif
+ _log_print (0, LOG_DEBUG, fmt, ap);
+ va_end (ap);
+}
+
+void
+log_debug_buf (int cls, int level, const char *header, const u_int8_t *buf,
+ size_t sz)
+{
+ char s[73];
+ int i, j;
+
+ /*
+ * If we are not debugging this class, or the level is too low, just return.
+ */
+ if (log_level[cls] == 0 || level > log_level[cls])
+ return;
+
+ log_debug (cls, level, "%s:", header);
+ for (i = j = 0; i < sz;)
+ {
+ sprintf (s + j, "%02x", buf[i++]);
+ j += 2;
+ if (i % 4 == 0)
+ {
+ if (i % 32 == 0)
+ {
+ s[j] = '\0';
+ log_debug (cls, level, "%s", s);
+ j = 0;
+ }
+ else
+ s[j++] = ' ';
+ }
+ }
+ if (j)
+ {
+ s[j] = '\0';
+ log_debug (cls, level, "%s", s);
+ }
+}
+
+void
+#ifdef __STDC__
+log_print (const char *fmt, ...)
+#else
+log_print (fmt, va_alist)
+ const char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+#ifdef __STDC__
+ va_start (ap, fmt);
+#else
+ va_start (ap);
+ fmt = va_arg (ap, const char *);
+#endif
+ _log_print (0, LOG_NOTICE, fmt, ap);
+ va_end (ap);
+}
+
+void
+#ifdef __STDC__
+log_error (const char *fmt, ...)
+#else
+log_error (fmt, va_alist)
+ const char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+#ifdef __STDC__
+ va_start (ap, fmt);
+#else
+ va_start (ap);
+ fmt = va_arg (ap, const char *);
+#endif
+ _log_print (1, LOG_ERR, fmt, ap);
+ va_end (ap);
+}
+
+void
+#ifdef __STDC__
+log_fatal (const char *fmt, ...)
+#else
+log_fatal (fmt, va_alist)
+ const char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+#ifdef __STDC__
+ va_start (ap, fmt);
+#else
+ va_start (ap);
+ fmt = va_arg (ap, const char *);
+#endif
+ _log_print (1, LOG_CRIT, fmt, ap);
+ va_end (ap);
+ exit (1);
+}
+
+void
+log_debug_cmd (int cls, int level)
+{
+ if (cls < 0 || cls >= LOG_ENDCLASS)
+ {
+ log_print ("log_debug_cmd: invalid debugging class %d", cls);
+ return;
+ }
+
+ if (level < 0)
+ {
+ log_print ("log_debug_cmd: invalid debugging level %d for class %d",
+ level, cls);
+ return;
+ }
+
+ if (level == log_level[cls])
+ log_print ("log_debug_cmd: log level unchanged for class %d", cls);
+ else
+ {
+ log_print ("log_debug_cmd: log level changed from %d to %d for class %d",
+ log_level[cls], level, cls);
+ log_level[cls] = level;
+ }
+}
diff --git a/sbin/isakmpd/log.h b/sbin/isakmpd/log.h
new file mode 100644
index 00000000000..14679c41ccf
--- /dev/null
+++ b/sbin/isakmpd/log.h
@@ -0,0 +1,55 @@
+/* $Id: log.h,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _LOG_H_
+#define _LOG_H_
+
+#include <sys/types.h>
+#include <stdio.h>
+
+enum log_classes {
+ LOG_MISC, LOG_TRANSPORT, LOG_MESSAGE, LOG_CRYPTO, LOG_TIMER, LOG_PF_ENCAP,
+ LOG_ENDCLASS
+};
+
+extern void log_debug (int, int, const char *, ...);
+extern void log_debug_buf (int, int, const char *, const u_int8_t *, size_t);
+extern void log_debug_cmd (int, int);
+extern void log_error (const char *, ...);
+extern void log_fatal (const char *, ...);
+extern void log_print (const char *, ...);
+extern void log_to (FILE *);
+
+#endif /* _LOG_H_ */
diff --git a/sbin/isakmpd/math_2n.c b/sbin/isakmpd/math_2n.c
new file mode 100644
index 00000000000..fa5df464d49
--- /dev/null
+++ b/sbin/isakmpd/math_2n.c
@@ -0,0 +1,1045 @@
+/* $Id: math_2n.c,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+/*
+ * B2N is a module for doing arithmetic on the Field GF(2**n) which is
+ * isomorph to ring of polynomials GF(2)[x]/p(x) where p(x) is an
+ * irreduciable polynomial over GF(2)[x] with grade n.
+ *
+ * First we need functions which operate on GF(2)[x], operation
+ * on GF(2)[x]/p(x) can be done as for Z_p then.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "util.h"
+#include "math_2n.h"
+
+u_int8_t hex2int (char);
+
+static char int2hex[] = "0123456789abcdef";
+CHUNK_TYPE b2n_mask[CHUNK_BITS] = {
+ 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,
+#if CHUNK_BITS > 8
+ 0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000,
+#if CHUNK_BITS > 16
+ 0x00010000,0x00020000,0x00040000,0x00080000,
+ 0x00100000,0x00200000,0x00400000,0x00800000,
+ 0x01000000,0x02000000,0x04000000,0x08000000,
+ 0x10000000,0x20000000,0x40000000,0x80000000,
+#endif
+#endif
+};
+
+/* Misc */
+u_int8_t
+hex2int (char c)
+{
+ if (c <= '9')
+ return c - '0';
+ if (c <= 'f')
+ return 10 + c - 'a';
+
+ return 0;
+}
+
+
+void
+b2n_random (b2n_ptr n, u_int32_t bits)
+{
+ b2n_resize (n, (CHUNK_MASK + bits) >> CHUNK_SHIFTS);
+
+ getrandom ((u_int8_t *)n->limp, CHUNK_BYTES * n->chunks);
+
+ /* Get the number of significant bits right */
+ if (bits & CHUNK_MASK)
+ {
+ CHUNK_TYPE m = (((1 << ((bits & CHUNK_MASK)-1)) - 1) << 1) | 1;
+ n->limp[n->chunks-1] &= m;
+ }
+
+ n->dirty = 1;
+}
+
+/* b2n management functions */
+
+void
+b2n_init (b2n_ptr n)
+{
+ n->chunks = 0;
+ n->limp = NULL;
+}
+
+void
+b2n_clear (b2n_ptr n)
+{
+ /* XXX Does all systems deal with free (NULL) nicely? */
+ free (n->limp);
+}
+
+void
+b2n_resize (b2n_ptr n, unsigned int chunks)
+{
+ int old = n->chunks;
+ int size;
+ CHUNK_TYPE *new;
+
+ if (chunks == 0)
+ chunks = 1;
+
+ if (chunks == old)
+ return;
+
+ size = CHUNK_BYTES * chunks;
+
+ /* XXX - is there anything I can do here? */
+ new = realloc (n->limp, size);
+ if (new == NULL)
+ return ;
+
+ n->limp = new;
+ n->chunks = chunks;
+ n->bits = chunks << CHUNK_SHIFTS;
+ n->dirty = 1;
+
+ if (chunks > old)
+ memset (n->limp + old, 0, size - CHUNK_BYTES*old);
+}
+
+/* Simple assignment functions */
+
+void
+b2n_set (b2n_ptr d, b2n_ptr s)
+{
+ if (d == s)
+ return;
+
+ b2n_sigbit (s);
+ b2n_resize (d, (CHUNK_MASK + s->bits) >> CHUNK_SHIFTS);
+ memcpy (d->limp, s->limp, CHUNK_BYTES*d->chunks);
+ d->bits = s->bits;
+ d->dirty = s->dirty;
+}
+
+void
+b2n_set_null (b2n_ptr n)
+{
+ b2n_resize (n , 1);
+ n->limp[0] = n->bits = n->dirty = 0;
+}
+
+void
+b2n_set_ui (b2n_ptr n, unsigned int val)
+{
+#if CHUNK_BITS < 32
+ int i, chunks;
+
+ chunks = (CHUNK_BYTES - 1 + sizeof (val))/CHUNK_BYTES;
+
+ b2n_resize (n, chunks );
+
+ for (i = 0; i < chunks; i++)
+ {
+ n->limp[i] = val & CHUNK_BMASK;
+ val >>= CHUNK_BITS;
+ }
+#else
+ b2n_resize (n, 1);
+ n->limp[0] = val;
+#endif
+ n->dirty = 1;
+}
+
+/* Only takes hex at the moment */
+
+void
+b2n_set_str (b2n_ptr n, char *str)
+{
+ int i, j, w, len, chunks;
+ CHUNK_TYPE tmp;
+
+ if (strncasecmp (str, "0x", 2))
+ return;
+
+ /* Make the hex string even lengthed */
+ len = strlen (str) - 2;
+ if (len & 1)
+ {
+ len ++;
+ str ++;
+ }
+ else
+ str += 2;
+
+ len /= 2;
+
+ chunks = (CHUNK_BYTES - 1 + len)/CHUNK_BYTES;
+ b2n_resize (n, chunks);
+ memset (n->limp, 0, CHUNK_BYTES * n->chunks);
+
+ for (w = 0, i = 0; i < chunks; i++)
+ {
+ tmp = 0;
+ for (j = (i == 0 ? ((len-1) % CHUNK_BYTES)+1 : CHUNK_BYTES); j > 0; j--)
+ {
+ tmp <<= 8;
+ tmp |= (hex2int(str[w]) << 4) | hex2int(str[w+1]);
+ w += 2;
+ }
+ n->limp[chunks-1-i] = tmp;
+ }
+
+ n->dirty = 1;
+}
+
+/* Output function, mainly for debugging perpurses */
+
+void
+b2n_print (b2n_ptr n)
+{
+ int i, j, w, flag = 0;
+ int left;
+ char buffer[2*CHUNK_BYTES];
+ CHUNK_TYPE tmp;
+
+ left = ((((7 + b2n_sigbit (n)) >> 3) - 1) % CHUNK_BYTES) + 1;
+ printf("0x");
+ for (i = 0; i < n->chunks; i++)
+ {
+ tmp = n->limp[n->chunks-1-i];
+ memset (buffer, '0', sizeof (buffer));
+ for (w = 0, j = (i == 0 ? left : CHUNK_BYTES); j > 0; j--)
+ {
+ buffer[w++] = int2hex[(tmp >> 4) & 0xF];
+ buffer[w++] = int2hex[tmp & 0xF];
+ tmp >>= 8;
+ }
+
+ for (j = (i == 0 ? left - 1: CHUNK_BYTES - 1); j >= 0; j--)
+ if (flag || (i == n->chunks - 1 && j == 0) ||
+ buffer[2*j] != '0' || buffer[2*j+1] != '0')
+ {
+ putchar (buffer[2*j]);
+ putchar (buffer[2*j+1]);
+ flag = 1;
+ }
+ }
+ printf("\n");
+}
+
+int
+b2n_sprint (char *buf, b2n_ptr n)
+{
+ int i, k, j, w, flag = 0;
+ int left;
+ char buffer[2*CHUNK_BYTES];
+ CHUNK_TYPE tmp;
+
+ left = ((((7 + b2n_sigbit (n)) >> 3) - 1) % CHUNK_BYTES) + 1;
+
+ strcpy (buf, "0x"); k = 2;
+ for (i = 0; i < n->chunks; i++)
+ {
+ tmp = n->limp[n->chunks-1-i];
+ memset (buffer, '0', sizeof (buffer));
+ for (w = 0, j = (i == 0 ? left : CHUNK_BYTES); j > 0; j--)
+ {
+ buffer[w++] = int2hex[(tmp >> 4) & 0xF];
+ buffer[w++] = int2hex[tmp & 0xF];
+ tmp >>= 8;
+ }
+
+ for (j = (i == 0 ? left - 1: CHUNK_BYTES - 1); j >= 0; j--)
+ if (flag || (i == n->chunks - 1 && j == 0) ||
+ buffer[2*j] != '0' || buffer[2*j+1] != '0')
+ {
+ buf[k++] = buffer[2*j];
+ buf[k++] = buffer[2*j+1];
+ flag = 1;
+ }
+ }
+
+ buf [k++] = 0;
+ return k;
+}
+
+/* Arithmetic functions */
+
+u_int32_t
+b2n_sigbit (b2n_ptr n)
+{
+ int i, j;
+
+ if (!n->dirty)
+ return n->bits;
+
+ for (i = n->chunks-1; i > 0; i--)
+ if (n->limp[i])
+ break;
+
+ if (!n->limp[i])
+ return 0;
+
+ for (j = CHUNK_MASK; j > 0; j--)
+ if (n->limp[i] & b2n_mask[j])
+ break;
+
+ n->bits = (i << CHUNK_SHIFTS) + j + 1;
+ n->dirty = 0;
+ return n->bits;
+}
+
+
+/*
+ * Addition on GF(2)[x] is nice, its just an XOR.
+ */
+
+void
+b2n_add (b2n_ptr d, b2n_ptr a, b2n_ptr b)
+{
+ int i;
+ b2n_ptr bmin, bmax;
+
+ if (!b2n_cmp_null (a))
+ {
+ b2n_set (d, b);
+ return;
+ }
+
+ if (!b2n_cmp_null (b))
+ {
+ b2n_set (d, a);
+ return;
+ }
+
+ bmin = B2N_MIN (a,b);
+ bmax = B2N_MAX (a,b);
+
+ b2n_resize (d, bmax->chunks);
+
+ for (i = 0; i < bmin->chunks; i++)
+ d->limp[i] = bmax->limp[i] ^ bmin->limp[i];
+
+ /*
+ * If d is not bmax, we have to copy the rest of the bytes, and also
+ * need to adjust to number of relevant bits.
+ */
+ if (d != bmax)
+ {
+ for ( ; i < bmax->chunks; i++)
+ d->limp[i] = bmax->limp[i];
+
+ d->bits = bmax->bits;
+ }
+
+ /*
+ * Help to converse memory. When the result of the addition is zero
+ * truncate the used amount of memory.
+ */
+ if (d != bmax && !b2n_cmp_null (d))
+ b2n_set_null (d);
+ else
+ d->dirty = 1;
+}
+
+
+/*
+ * Compare two polynomials.
+ */
+
+int
+b2n_cmp (b2n_ptr n, b2n_ptr m)
+{
+ int sn, sm;
+ int i;
+
+ sn = b2n_sigbit (n);
+ sm = b2n_sigbit (m);
+
+ if (sn > sm)
+ return 1;
+ if (sn < sm)
+ return -1;
+
+ for (i = n->chunks-1; i >= 0; i--)
+ if (n->limp[i] > m->limp[i])
+ return 1;
+ else if (n->limp[i] < m->limp[i])
+ return -1;
+
+ return 0;
+}
+
+int
+b2n_cmp_null (b2n_ptr a)
+{
+ int i = 0;
+
+ do
+ {
+ if (a->limp[i])
+ return 1;
+ } while (++i < a->chunks);
+
+ return 0;
+}
+
+/*
+ * Left shift, needed for polynomial multiplication.
+ */
+
+void
+b2n_lshift (b2n_ptr d, b2n_ptr n, unsigned int s)
+{
+ int i, maj, min, chunks;
+ u_int16_t bits = b2n_sigbit (n), add;
+ CHUNK_TYPE *p, *op;
+
+ if (!s)
+ {
+ b2n_set (d, n);
+ return;
+ }
+
+ maj = s >> CHUNK_SHIFTS;
+ min = s & CHUNK_MASK;
+
+ add = (!(bits&CHUNK_MASK) || ((bits&CHUNK_MASK) + min) > CHUNK_MASK) ? 1 : 0;
+ chunks = n->chunks;
+ b2n_resize (d, chunks + maj + add);
+ memmove (d->limp + maj, n->limp, CHUNK_BYTES * chunks);
+
+ if (maj)
+ memset (d->limp, 0, CHUNK_BYTES * maj);
+ if (add)
+ d->limp[d->chunks-1] = 0;
+
+ /* If !min there are no bit shifts, we are done */
+ if (!min)
+ return;
+
+ op = p = &d->limp[d->chunks-1];
+ for (i = d->chunks-2; i >= maj; i--)
+ {
+ op--;
+ *p-- = (*p << min) | (*op >> (CHUNK_BITS - min));
+ }
+ *p <<= min;
+
+ d->dirty = 0;
+ d->bits = bits + (maj << CHUNK_SHIFTS) + min;
+}
+
+/*
+ * Right shift, needed for polynomial division.
+ */
+
+void
+b2n_rshift (b2n_ptr d, b2n_ptr n, unsigned int s)
+{
+ int maj, min, size = n->chunks, newsize;
+ b2n_ptr tmp;
+
+ if (!s)
+ {
+ b2n_set (d, n);
+ return;
+ }
+
+ maj = s >> CHUNK_SHIFTS;
+
+ newsize = size - maj;
+
+ if (size < maj)
+ {
+ b2n_set_null (d);
+ return;
+ }
+
+ min = (CHUNK_BITS - (s & CHUNK_MASK)) & CHUNK_MASK;
+ if (min)
+ {
+ if ((b2n_sigbit (n) & CHUNK_MASK) > min)
+ newsize++;
+
+ b2n_lshift (d, n, min);
+ tmp = d;
+ }
+ else
+ tmp = n;
+
+ memmove (d->limp, tmp->limp+maj+(min ? 1 : 0), CHUNK_BYTES * newsize);
+ b2n_resize (d, newsize);
+
+ d->bits = tmp->bits - ((maj + (min ? 1 : 0)) << CHUNK_SHIFTS);
+}
+
+/*
+ * Normal polynomial multiplication.
+ */
+
+void
+b2n_mul (b2n_ptr d, b2n_ptr n, b2n_ptr m)
+{
+ int i, j;
+ b2n_t tmp, tmp2;
+
+ if (!b2n_cmp_null (m) || !b2n_cmp_null (n))
+ {
+ b2n_set_null (d);
+ return;
+ }
+
+ if (b2n_sigbit (m) == 1)
+ {
+ b2n_set (d, n);
+ return;
+ }
+
+ if (b2n_sigbit (n) == 1)
+ {
+ b2n_set (d, m);
+ return;
+ }
+
+ b2n_init (tmp);
+ b2n_init (tmp2);
+
+ b2n_set (tmp, B2N_MAX (n, m));
+ b2n_set (tmp2, B2N_MIN (n, m));
+
+ b2n_set_null (d);
+
+ for (i = 0; i < tmp2->chunks; i++)
+ if (tmp2->limp[i])
+ for (j = 0; j < CHUNK_BITS; j++)
+ {
+ if (tmp2->limp[i] & b2n_mask[j])
+ b2n_add (d, d, tmp);
+
+ b2n_lshift (tmp, tmp, 1);
+ }
+ else
+ b2n_lshift (tmp, tmp, CHUNK_BITS);
+
+ b2n_clear (tmp);
+ b2n_clear (tmp2);
+}
+
+/*
+ * Squaring in this polynomial ring is more efficient than normal
+ * multiplication.
+ */
+
+void
+b2n_square (b2n_ptr d, b2n_ptr n)
+{
+ int i, j, maj, min, bits, chunk;
+ b2n_t t;
+
+ maj = b2n_sigbit (n);
+ min = maj & CHUNK_MASK;
+ maj = (maj + CHUNK_MASK) >> CHUNK_SHIFTS;
+
+ b2n_init (t);
+ b2n_resize (t, 2*maj + ((CHUNK_MASK + 2*min) >> CHUNK_SHIFTS));
+
+ chunk = 0;
+ bits = 0;
+
+ for (i = 0; i < maj; i++)
+ if (n->limp[i])
+ for (j = 0; j < CHUNK_BITS; j++)
+ {
+ if (n->limp[i] & b2n_mask[j])
+ t->limp[chunk] ^= b2n_mask[bits];
+
+ bits += 2;
+ if (bits >= CHUNK_BITS)
+ {
+ chunk++;
+ bits &= CHUNK_MASK;
+ }
+ }
+ else
+ chunk += 2;
+
+ t->dirty = 1;
+ B2N_SWAP (d, t);
+ b2n_clear (t);
+}
+
+/*
+ * Normal polynomial division.
+ * These functions are far from optimal in speed.
+ */
+
+void
+b2n_div_q (b2n_ptr d, b2n_ptr n, b2n_ptr m)
+{
+ b2n_t r;
+
+ b2n_init (r);
+ b2n_div (d, r, n, m);
+ b2n_clear (r);
+}
+
+void
+b2n_div_r (b2n_ptr r, b2n_ptr n, b2n_ptr m)
+{
+ b2n_t q;
+
+ b2n_init (q);
+ b2n_div (q, r, n, m);
+ b2n_clear (q);
+}
+
+void
+b2n_div (b2n_ptr q, b2n_ptr r, b2n_ptr n, b2n_ptr m)
+{
+ int sn, sm, i, j, len, bits;
+ b2n_t nenn, div, shift, mask;
+
+ /* If Teiler > Zaehler, the result is 0 */
+ if ((sm = b2n_sigbit (m)) > (sn = b2n_sigbit (n)))
+ {
+ b2n_set_null (q);
+ b2n_set (r, n);
+ return;
+ }
+
+ if (sm == 0)
+ /* Division by Zero */
+ return;
+ else if (sm == 1)
+ {
+ /* Division by the One-Element */
+ b2n_set (q, n);
+ b2n_set_null (r);
+ return;
+ }
+
+ b2n_init (nenn);
+ b2n_init (div);
+ b2n_init (shift);
+ b2n_init (mask);
+
+ b2n_set (nenn, n);
+ b2n_set (div, m);
+ b2n_set (shift, m);
+ b2n_set_ui (mask, 1);
+
+ b2n_resize (q, (sn - sm + CHUNK_MASK) >> CHUNK_SHIFTS);
+ memset (q->limp, 0, CHUNK_BYTES * q->chunks);
+
+ b2n_lshift (shift, shift, sn - sm);
+ b2n_lshift (mask, mask, sn - sm);
+
+ /* Number of significant octets */
+ len = (sn - 1) >> CHUNK_SHIFTS;
+ /* The first iteration is done over the relevant bits */
+ bits = (CHUNK_MASK + sn) & CHUNK_MASK;
+ for (i = len; i >= 0 && b2n_sigbit (nenn) >= sm; i--)
+ for (j = (i == len ? bits : CHUNK_MASK); j >= 0 && b2n_sigbit (nenn) >= sm; j--)
+ {
+ if (nenn->limp[i] & b2n_mask[j])
+ {
+ b2n_sub (nenn, nenn, shift);
+ b2n_add (q, q, mask);
+ }
+ b2n_rshift (shift, shift, 1);
+ b2n_rshift (mask, mask, 1);
+ }
+
+
+ B2N_SWAP (r, nenn);
+
+ b2n_clear (nenn);
+ b2n_clear (div);
+ b2n_clear (shift);
+}
+
+
+/*
+ * Functions for Operation on GF(2**n) ~= GF(2)[x]/p(x).
+ */
+
+void
+b2n_mod (b2n_ptr m, b2n_ptr n, b2n_ptr p)
+{
+ int bits, size;
+ b2n_div_r (m, n, p);
+
+ bits = b2n_sigbit (m);
+ size = ((CHUNK_MASK + bits) >> CHUNK_SHIFTS);
+ if (size == 0)
+ size = 1;
+ if (m->chunks > size)
+ b2n_resize (m, size);
+
+ m->bits = bits;
+ m->dirty = 0;
+}
+
+void
+b2n_gcd (b2n_ptr e, b2n_ptr go, b2n_ptr ho)
+{
+ b2n_t g, h;
+
+ b2n_init (g); b2n_set (g, go);
+ b2n_init (h); b2n_set (h, ho);
+
+ while (b2n_cmp_null (h))
+ {
+ b2n_mod (g, g, h);
+ B2N_SWAP (g,h);
+ }
+
+ B2N_SWAP (e, g);
+
+ b2n_clear (g);
+ b2n_clear (h);
+}
+
+void
+b2n_mul_inv (b2n_ptr ga, b2n_ptr be, b2n_ptr p)
+{
+ b2n_t a;
+
+ b2n_init (a);
+ b2n_set_ui (a,1);
+
+ b2n_div_mod (ga, a, be, p);
+
+ b2n_clear (a);
+}
+
+void
+b2n_div_mod (b2n_ptr ga, b2n_ptr a, b2n_ptr be, b2n_ptr p)
+{
+ b2n_t s0, s1, s2, q, r0, r1;
+
+ /* There is no multiplicative inverse to Null */
+ if (!b2n_cmp_null(be))
+ {
+ b2n_set_null (ga);
+ return;
+ }
+
+ b2n_init (s0); b2n_init (s1); b2n_init (s2);
+ b2n_init (r0); b2n_init (r1);
+ b2n_init (q);
+
+ b2n_set (r0, p);
+ b2n_set (r1, be);
+
+ b2n_set_null (s0);
+ b2n_set (s1, a);
+
+ while (b2n_cmp_null (r1))
+ {
+ b2n_div(q, r0, r0, r1);
+ B2N_SWAP (r0, r1);
+
+ b2n_mul (s2, q, s1);
+ b2n_mod (s2, s2, p);
+ b2n_sub (s2, s0, s2);
+
+ B2N_SWAP (s0, s1);
+ B2N_SWAP (s1, s2);
+ }
+ B2N_SWAP (ga, s0);
+
+ b2n_clear (s0); b2n_clear (s1); b2n_clear (s2);
+ b2n_clear (r0); b2n_clear (r1);
+ b2n_clear (q);
+}
+
+/*
+ * The trace tells us if there do exist any square roots
+ * for 'a' in GF(2)[x]/p(x). The number of square roots is
+ * 2 - 2*Trace.
+ * If z is a square root, z + 1 is the other.
+ */
+
+void
+b2n_trace (b2n_ptr ho, b2n_ptr a, b2n_ptr p)
+{
+ int i, m = b2n_sigbit (p) - 1;
+ b2n_t h;
+
+ b2n_init (h);
+ b2n_set (h, a);
+
+ for (i = 0; i < m - 1; i++)
+ {
+ b2n_square (h, h);
+ b2n_mod (h, h, p);
+
+ b2n_add (h, h, a);
+ }
+ B2N_SWAP (ho, h);
+
+ b2n_clear (h);
+}
+
+/*
+ * The halftrace yields the square root if the degree of the
+ * irreduceable polynomial is odd.
+ */
+
+void
+b2n_halftrace (b2n_ptr ho, b2n_ptr a, b2n_ptr p)
+{
+ int i, m = b2n_sigbit (p) - 1;
+ b2n_t h;
+
+ b2n_init (h);
+ b2n_set (h, a);
+
+ for (i = 0; i < (m - 1)/2; i++)
+ {
+ b2n_square (h, h);
+ b2n_mod (h, h, p);
+ b2n_square (h, h);
+ b2n_mod (h, h, p);
+
+ b2n_add (h, h, a);
+ }
+
+ B2N_SWAP (ho, h);
+
+ b2n_clear (h);
+}
+
+/*
+ * Solving the equation: y**2 + y = b in GF(2**m) where ip is the
+ * irreduceable polynomial. If m is odd, use the half trace.
+ */
+
+void
+b2n_sqrt (b2n_ptr zo, b2n_ptr b, b2n_ptr ip)
+{
+ int i, m = b2n_sigbit (ip) - 1;
+ b2n_t w, p, temp, z;
+
+ if (!b2n_cmp_null (b))
+ {
+ b2n_set_null (z);
+ return;
+ }
+
+ if (m & 1)
+ {
+ b2n_halftrace (zo, b, ip);
+ return;
+ }
+
+ b2n_init (z);
+ b2n_init (w);
+ b2n_init (p);
+ b2n_init (temp);
+ do {
+ b2n_random (p, m);
+ b2n_set_null (z);
+ b2n_set (w, p);
+ for (i = 1; i < m; i++)
+ {
+ b2n_square (z, z); /* z**2 */
+ b2n_mod (z, z, ip);
+
+ b2n_square (w, w); /* w**2 */
+ b2n_mod (w, w, ip);
+
+ b2n_mul (temp, w, b); /* w**2 * b */
+ b2n_mod (temp, temp, ip);
+ b2n_add (z, z, temp); /* z**2 + w**2 + b */
+
+ b2n_add (w, w, p); /* w**2 + p */
+ }
+ } while (!b2n_cmp_null (w));
+
+ B2N_SWAP (zo, z);
+
+ b2n_clear (w);
+ b2n_clear (p);
+ b2n_clear (temp);
+ b2n_clear (z);
+}
+
+
+/*
+ * Exponentiation modulo a polynomial.
+ */
+
+void
+b2n_exp_mod (b2n_ptr d, b2n_ptr b0, u_int32_t e, b2n_ptr p)
+{
+ b2n_t u, b;
+
+ b2n_init (u);
+ b2n_set_ui (u, 1);
+ b2n_init (b);
+ b2n_mod (b, b0, p);
+
+ while (e)
+ {
+ if (e & 1)
+ {
+ b2n_mul (u, u, b);
+ b2n_mod (u, u, p);
+ }
+ b2n_square (b, b);
+ b2n_mod (b, b, p);
+ e >>= 1;
+ }
+
+ B2N_SWAP (d, u);
+ b2n_clear (u);
+ b2n_clear (b);
+}
+
+/*
+ * Low-level function to speed up scalar multiplication with
+ * elliptic curves.
+ * Multiplies a normal number by 3.
+ */
+
+/*
+ * Normal addition behaves as Z_{2**n} and not F_{2**n}.
+ */
+
+void
+b2n_nadd (b2n_ptr d0, b2n_ptr a0, b2n_ptr b0)
+{
+ int i, carry;
+
+ b2n_ptr a, b;
+ b2n_t d;
+
+ if (!b2n_cmp_null (a0))
+ {
+ b2n_set (d0, b0);
+ return;
+ }
+
+ if (!b2n_cmp_null (b0))
+ {
+ b2n_set (d0, a0);
+ return;
+ }
+
+ b2n_init (d);
+ a = B2N_MAX (a0, b0);
+ b = B2N_MIN (a0, b0);
+
+ b2n_resize (d, a->chunks + 1);
+
+ for (carry = i = 0; i < b->chunks; i++)
+ {
+ d->limp[i] = a->limp[i] + b->limp[i] + carry;
+ carry = (d->limp[i] < a->limp[i] ? 1 : 0);
+ }
+
+ for ( ; i < a->chunks && carry; i++)
+ {
+ d->limp[i] = a->limp[i] + carry;
+ carry = (d->limp[i] < a->limp[i] ? 1 : 0);
+ }
+
+ if (i < a->chunks)
+ memcpy (d->limp + i, a->limp + i, CHUNK_BYTES*(a->chunks - i));
+
+ d->dirty = 1;
+ B2N_SWAP (d0, d);
+
+ b2n_clear (d);
+}
+
+/*
+ * Very special sub, a > b.
+ */
+
+void
+b2n_nsub (b2n_ptr d0, b2n_ptr a, b2n_ptr b)
+{
+ int i, carry;
+ b2n_t d;
+
+ if (b2n_cmp (a, b) <= 0)
+ {
+ b2n_set_null (d0);
+ return;
+ }
+
+ b2n_init (d);
+ b2n_resize (d, a->chunks);
+
+ for (carry = i = 0; i < b->chunks; i++)
+ {
+ d->limp[i] = a->limp[i] - b->limp[i] - carry;
+ carry = (d->limp[i] > a->limp[i] ? 1 : 0);
+ }
+
+ for ( ; i < a->chunks && carry; i++)
+ {
+ d->limp[i] = a->limp[i] - carry;
+ carry = (d->limp[i] > a->limp[i] ? 1 : 0);
+ }
+
+ if (i < a->chunks)
+ memcpy (d->limp + i, a->limp + i, CHUNK_BYTES*(a->chunks - i));
+
+ d->dirty = 1;
+
+ B2N_SWAP (d0, d);
+
+ b2n_clear (d);
+}
+
+void
+b2n_3mul (b2n_ptr d0, b2n_ptr e)
+{
+ b2n_t d;
+
+ b2n_init (d);
+ b2n_lshift (d, e, 1);
+
+ b2n_nadd (d0, d, e);
+
+ b2n_clear (d);
+}
diff --git a/sbin/isakmpd/math_2n.h b/sbin/isakmpd/math_2n.h
new file mode 100644
index 00000000000..0d5365a2670
--- /dev/null
+++ b/sbin/isakmpd/math_2n.h
@@ -0,0 +1,133 @@
+/* $Id: math_2n.h,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _MATH_2N_H
+#define _MATH_2N_H_
+
+/*
+ * The chunk size we use is variable, this allows speed ups
+ * for processors like the Alpha with 64bit words.
+ * XXX - b2n_mask is only up to 32 bit at the moment.
+ */
+
+#define USE_32BIT /* XXX - This obviously needs fixing */
+
+#ifdef USE_32BIT
+#define CHUNK_TYPE u_int32_t
+#define CHUNK_BITS 32
+#define CHUNK_SHIFTS 5
+#define CHUNK_BMASK 0xffffffff
+#define CHUNK_MASK (CHUNK_BITS - 1)
+#define CHUNK_BYTES (CHUNK_BITS >> 3)
+#define CHUNK_NIBBLES (CHUNK_BITS >> 2)
+#else
+#define CHUNK_TYPE u_int8_t
+#define CHUNK_BITS 8
+#define CHUNK_SHIFTS 3
+#define CHUNK_BMASK 0xff
+#define CHUNK_MASK (CHUNK_BITS - 1)
+#define CHUNK_BYTES (CHUNK_BITS >> 3)
+#define CHUNK_NIBBLES (CHUNK_BITS >> 2)
+#endif
+
+extern CHUNK_TYPE b2n_mask[CHUNK_BITS];
+
+/* An element of GF(2**n), n = bits */
+
+typedef struct {
+ u_int16_t chunks;
+ u_int16_t bits;
+ u_int8_t dirty; /* Sig bits are dirty */
+ CHUNK_TYPE *limp;
+} _b2n;
+
+typedef _b2n *b2n_ptr;
+typedef _b2n b2n_t[1];
+
+#define B2N_SET(x,y) (x)->chunks = (y)->chunks; (x)->bits = (y)->bits; \
+ (x)->limp = (y)->limp; (x)->dirty = (y)->dirty;
+
+#define B2N_MIN(x,y) ((x)->chunks > (y)->chunks ? (y) : (x))
+#define B2N_MAX(x,y) ((x)->chunks > (y)->chunks ? (x) : (y))
+
+void b2n_init (b2n_ptr);
+void b2n_clear (b2n_ptr);
+void b2n_resize (b2n_ptr, unsigned int);
+
+void b2n_random (b2n_ptr, u_int32_t);
+
+void b2n_set (b2n_ptr, b2n_ptr);
+void b2n_set_null (b2n_ptr);
+void b2n_set_ui (b2n_ptr, unsigned int);
+void b2n_set_str (b2n_ptr, char *);
+
+void b2n_print (b2n_ptr);
+int b2n_sprint (char *, b2n_ptr);
+
+int b2n_cmp (b2n_ptr, b2n_ptr);
+int b2n_cmp_null (b2n_ptr);
+
+void b2n_add (b2n_ptr, b2n_ptr, b2n_ptr);
+#define b2n_sub b2n_add
+void b2n_lshift (b2n_ptr, b2n_ptr, unsigned int);
+void b2n_rshift (b2n_ptr, b2n_ptr, unsigned int);
+u_int32_t b2n_sigbit (b2n_ptr);
+
+void b2n_nadd (b2n_ptr, b2n_ptr, b2n_ptr);
+void b2n_nsub (b2n_ptr, b2n_ptr, b2n_ptr);
+void b2n_3mul (b2n_ptr, b2n_ptr);
+
+void b2n_mul (b2n_ptr, b2n_ptr, b2n_ptr);
+void b2n_square (b2n_ptr, b2n_ptr);
+
+void b2n_div (b2n_ptr, b2n_ptr, b2n_ptr, b2n_ptr);
+void b2n_div_q (b2n_ptr, b2n_ptr, b2n_ptr);
+void b2n_div_r (b2n_ptr, b2n_ptr, b2n_ptr);
+
+/* Operation on GF(2**n) */
+#define B2N_SWAP(x,y) {b2n_t _t_; B2N_SET(_t_, (x)); \
+ B2N_SET ((x), (y)); B2N_SET ((y),_t_); }
+
+void b2n_mod (b2n_ptr, b2n_ptr, b2n_ptr);
+
+void b2n_gcd (b2n_ptr, b2n_ptr, b2n_ptr);
+void b2n_mul_inv (b2n_ptr, b2n_ptr, b2n_ptr);
+void b2n_div_mod (b2n_ptr, b2n_ptr, b2n_ptr, b2n_ptr);
+void b2n_trace (b2n_ptr, b2n_ptr, b2n_ptr);
+void b2n_halftrace (b2n_ptr, b2n_ptr, b2n_ptr);
+void b2n_sqrt (b2n_ptr, b2n_ptr, b2n_ptr);
+void b2n_exp_mod (b2n_ptr, b2n_ptr, u_int32_t, b2n_ptr);
+
+#endif /* _MATH_2N_H_ */
diff --git a/sbin/isakmpd/math_ec2n.c b/sbin/isakmpd/math_ec2n.c
new file mode 100644
index 00000000000..f8232e21b65
--- /dev/null
+++ b/sbin/isakmpd/math_ec2n.c
@@ -0,0 +1,314 @@
+/* $Id: math_ec2n.c,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <stdio.h>
+
+#include "math_2n.h"
+#include "math_ec2n.h"
+
+void
+ec2np_init (ec2np_ptr n)
+{
+ b2n_init (n->x);
+ b2n_init (n->y);
+ n->inf = 0;
+}
+
+void
+ec2np_clear (ec2np_ptr n)
+{
+ b2n_clear (n->x);
+ b2n_clear (n->y);
+}
+
+void
+ec2np_set (ec2np_ptr d, ec2np_ptr n)
+{
+ if (d == n)
+ return;
+
+ d->inf = n->inf;
+ b2n_set (d->x, n->x);
+ b2n_set (d->y, n->y);
+}
+
+/* Group */
+
+void
+ec2ng_init (ec2ng_ptr n)
+{
+ b2n_init (n->a);
+ b2n_init (n->b);
+ b2n_init (n->p);
+}
+
+void
+ec2ng_clear (ec2ng_ptr n)
+{
+ b2n_clear (n->a);
+ b2n_clear (n->b);
+ b2n_clear (n->p);
+}
+
+void
+ec2ng_set (ec2ng_ptr d, ec2ng_ptr n)
+{
+ b2n_set (d->a, n->a);
+ b2n_set (d->b, n->b);
+ b2n_set (d->p, n->p);
+}
+
+/* Arithmetic functions */
+
+void
+ec2np_right (b2n_ptr n, ec2np_ptr p, ec2ng_ptr g)
+{
+ b2n_t temp;
+
+ b2n_init (temp);
+ /* First calc x**3 + ax**2 + b */
+ b2n_square (n, p->x);
+ b2n_mod (n, n, g->p);
+
+ b2n_mul (temp, g->a, n); /* a*x**2 */
+ b2n_mod (temp, temp, g->p);
+
+ b2n_mul (n, n, p->x); /* x**3 */
+ b2n_mod (n, n, g->p);
+
+ b2n_add (n, n, temp);
+ b2n_add (n, n, g->b);
+
+ b2n_clear (temp);
+}
+
+int
+ec2np_ison (ec2np_ptr p, ec2ng_ptr g)
+{
+ int res;
+
+ b2n_t x, y, temp;
+
+ if (p->inf)
+ return 1;
+
+ b2n_init (x);
+ b2n_init (y);
+ b2n_init (temp);
+
+ /* First calc x**3 + ax**2 + b */
+ ec2np_right (x, p, g);
+
+ /* Now calc y**2 + xy */
+ b2n_square (y, p->y);
+ b2n_mod (y, y, g->p);
+
+ b2n_mul (temp, p->y, p->x);
+ b2n_mod (temp, temp, g->p);
+
+ b2n_add (y, y, temp);
+
+ res = !b2n_cmp (x, y);
+
+ b2n_clear (x);
+ b2n_clear (y);
+ b2n_clear (temp);
+
+ return res;
+}
+
+int
+ec2np_find_y (ec2np_ptr p, ec2ng_ptr g)
+{
+ b2n_t right;
+
+ b2n_init (right);
+ ec2np_right (right, p, g); /* Right sight of equation */
+ b2n_mul_inv (p->y, p->x, g->p);
+
+ b2n_square (p->y, p->y);
+ b2n_mod (p->y, p->y, g->p);
+
+ b2n_mul (right, right, p->y); /* x^-2 * right */
+ b2n_mod (right, right, g->p);
+
+ b2n_sqrt (p->y, right, g->p); /* Find root */
+ b2n_mul (p->y, p->y, p->x);
+ b2n_mod (p->y, p->y, g->p);
+
+ return 1;
+}
+
+void
+ec2np_add (ec2np_ptr d, ec2np_ptr a, ec2np_ptr b, ec2ng_ptr g)
+{
+ b2n_t lambda, temp;
+ ec2np_t pn;
+
+ /* Check for Neutral Element */
+ if (b->inf)
+ {
+ ec2np_set (d, a);
+ return;
+ }
+ if (a->inf)
+ {
+ ec2np_set (d, b);
+ return;
+ }
+
+ if (!b2n_cmp (a->x, b->x) && (b2n_cmp (a->y, b->y) || !b2n_cmp_null (a->x)))
+ {
+ d->inf = 1;
+ b2n_set_null (d->x);
+ b2n_set_null (d->y);
+ return;
+ }
+
+ b2n_init (lambda);
+ b2n_init (temp);
+ ec2np_init (pn);
+
+ if (b2n_cmp (a->x, b->x))
+ {
+ b2n_add (temp, a->x, b->x);
+ b2n_add (lambda, a->y, b->y);
+ b2n_div_mod (lambda, lambda, temp, g->p);
+
+ b2n_square (pn->x, lambda);
+ b2n_mod (pn->x, pn->x, g->p);
+
+ b2n_add (pn->x, pn->x, lambda);
+ b2n_add (pn->x, pn->x, g->a);
+ b2n_add (pn->x, pn->x, a->x);
+ b2n_add (pn->x, pn->x, b->x);
+ }
+ else
+ {
+ b2n_div_mod (lambda, b->y, b->x, g->p);
+ b2n_add (lambda, lambda, b->x);
+
+ b2n_square (pn->x, lambda);
+ b2n_mod (pn->x, pn->x, g->p);
+ b2n_add (pn->x, pn->x, lambda);
+ b2n_add (pn->x, pn->x, g->a);
+ }
+
+ b2n_add (pn->y, b->x, pn->x);
+
+ b2n_mul (pn->y, pn->y, lambda);
+ b2n_mod (pn->y, pn->y, g->p);
+
+ b2n_add (pn->y, pn->y, pn->x);
+ b2n_add (pn->y, pn->y, b->y);
+
+ EC2NP_SWAP (d, pn);
+
+ ec2np_clear (pn);
+ b2n_clear (lambda);
+ b2n_clear (temp);
+}
+
+void
+ec2np_mul (ec2np_ptr d, ec2np_ptr a, b2n_ptr e, ec2ng_ptr g)
+{
+ int i, j, bits, start;
+ b2n_t h, k;
+ ec2np_t q, mina;
+
+ if (!b2n_cmp_null (e))
+ {
+ d->inf = 1;
+ b2n_set_null (d->x);
+ b2n_set_null (d->y);
+ return;
+ }
+
+ b2n_init (h);
+ b2n_init (k);
+
+ ec2np_init (q);
+ ec2np_init (mina);
+ ec2np_set (q, a);
+
+ /* Create the point -a */
+ ec2np_set (mina, a);
+ b2n_add (mina->y, mina->y, mina->x);
+
+ b2n_set (k, e);
+ b2n_3mul (h, k);
+ b2n_resize (k, h->chunks);
+
+ /*
+ * This is low level but can not be avoided, since we have to do single
+ * bit checks on h and k.
+ */
+ bits = b2n_sigbit (h);
+ if ((bits & CHUNK_MASK) == 1)
+ {
+ start = ((CHUNK_MASK + bits) >> CHUNK_SHIFTS) - 2;
+ bits = CHUNK_BITS;
+ }
+ else
+ {
+ start = ((CHUNK_MASK + bits) >> CHUNK_SHIFTS) - 1;
+ bits = ((bits - 1) & CHUNK_MASK);
+ }
+
+ /*
+ * This is the addition, subtraction method which is faster because
+ * we avoid one out of three additions (mean).
+ */
+
+ for (i = start; i >= 0; i--)
+ for (j = (i == start ? bits : CHUNK_BITS) - 1; j >= 0; j--)
+ if (i > 0 || j > 0)
+ {
+ ec2np_add (q, q, q, g);
+ if ((h->limp[i] & b2n_mask[j]) && !(k->limp[i] & b2n_mask[j]))
+ ec2np_add (q, q, a, g);
+ else if (!(h->limp[i] & b2n_mask[j]) && (k->limp[i] & b2n_mask[j]))
+ ec2np_add (q, q, mina, g);
+ }
+
+ EC2NP_SWAP (d, q);
+
+ b2n_clear (k);
+ b2n_clear (h);
+
+ ec2np_clear (q);
+ ec2np_clear (mina);
+}
diff --git a/sbin/isakmpd/math_ec2n.h b/sbin/isakmpd/math_ec2n.h
new file mode 100644
index 00000000000..22d5d9e5422
--- /dev/null
+++ b/sbin/isakmpd/math_ec2n.h
@@ -0,0 +1,89 @@
+/* $Id: math_ec2n.h,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _MATH_EC2N_H
+#define _MATH_EC2N_H_
+
+/* Definitions for points on an elliptic curve */
+
+typedef struct {
+ int inf; /* Are we the point at infinity ? */
+ b2n_t x, y;
+} _ec2n_point;
+
+typedef _ec2n_point *ec2np_ptr;
+typedef _ec2n_point ec2np_t[1];
+
+#define EC2NP_SWAP(k,n) {int _i_; _i_ = (k)->inf; (k)->inf = (n)->inf; \
+ (n)->inf = _i_; B2N_SWAP ((k)->x, (n)->x); B2N_SWAP ((k)->y, (n)->y);}
+
+void ec2np_init (ec2np_ptr);
+void ec2np_clear (ec2np_ptr);
+void ec2np_set (ec2np_ptr, ec2np_ptr);
+
+#define ec2np_set_x_ui(n, y) b2n_set_ui ((n)->x, y)
+#define ec2np_set_y_ui(n, x) b2n_set_ui ((n)->y, x)
+#define ec2np_set_x_str(n, y) b2n_set_str ((n)->x, y)
+#define ec2np_set_y_str(n, x) b2n_set_str ((n)->y, x)
+
+/* Definitions for the group to which the points to belong to */
+
+typedef struct {
+ b2n_t a, b, p;
+} _ec2n_group;
+
+typedef _ec2n_group *ec2ng_ptr;
+typedef _ec2n_group ec2ng_t[1];
+
+void ec2ng_init (ec2ng_ptr);
+void ec2ng_clear (ec2ng_ptr);
+void ec2ng_set (ec2ng_ptr, ec2ng_ptr);
+
+#define ec2ng_set_a_ui(n, x) b2n_set_ui ((n)->a, x)
+#define ec2ng_set_b_ui(n, x) b2n_set_ui ((n)->b, x)
+#define ec2ng_set_p_ui(n, x) b2n_set_ui ((n)->p, x)
+#define ec2ng_set_a_str(n, x) b2n_set_str ((n)->a, x)
+#define ec2ng_set_b_str(n, x) b2n_set_str ((n)->b, x)
+#define ec2ng_set_p_str(n, x) b2n_set_str ((n)->p, x)
+
+/* Functions for computing on the elliptic group */
+
+void ec2np_right (b2n_ptr n, ec2np_ptr, ec2ng_ptr);
+int ec2np_ison (ec2np_ptr, ec2ng_ptr);
+int ec2np_find_y (ec2np_ptr, ec2ng_ptr);
+void ec2np_add (ec2np_ptr, ec2np_ptr, ec2np_ptr, ec2ng_ptr);
+void ec2np_mul (ec2np_ptr, ec2np_ptr, b2n_ptr, ec2ng_ptr);
+
+#endif /* _MATH_2N_H_ */
diff --git a/sbin/isakmpd/math_group.c b/sbin/isakmpd/math_group.c
new file mode 100644
index 00000000000..048ec3977ad
--- /dev/null
+++ b/sbin/isakmpd/math_group.c
@@ -0,0 +1,533 @@
+/* $Id: math_group.c,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <gmp.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp_util.h"
+#include "math_2n.h"
+#include "math_ec2n.h"
+#include "math_group.h"
+
+#include "log.h"
+#include "sysdep.h"
+
+/* We do not want to export these definitions */
+int modp_getlen (struct group *);
+void modp_getraw (struct group *, mpz_ptr, u_int8_t *);
+void modp_setraw (struct group *, mpz_ptr, u_int8_t *, int);
+void modp_setrandom (struct group *, mpz_ptr);
+void modp_operation (struct group *, mpz_ptr, mpz_ptr, mpz_ptr);
+
+int ec2n_getlen (struct group *);
+void ec2n_getraw (struct group *, ec2np_ptr, u_int8_t *);
+void ec2n_setraw (struct group *, ec2np_ptr, u_int8_t *, int);
+void ec2n_setrandom (struct group *, ec2np_ptr);
+void ec2n_operation (struct group *, ec2np_ptr, ec2np_ptr, ec2np_ptr);
+
+struct ec2n_group {
+ ec2np_t gen; /* Generator */
+ ec2ng_t grp;
+ ec2np_t a, b, c, d;
+};
+
+struct modp_group {
+ mpz_t gen; /* Generator */
+ mpz_t p; /* Prime */
+ mpz_t a, b, c, d;
+};
+
+/*
+ * This module provides access to the operations on the specified group
+ * and is absolutly free of any cryptographic devices. This is math :-).
+ */
+
+#define OAKLEY_GRP_1 1
+#define OAKLEY_GRP_2 2
+#define OAKLEY_GRP_3 3
+#define OAKLEY_GRP_4 4
+
+/* Describe preconfigured MODP groups */
+
+/*
+ * The Generalized Number Field Sieve has an asymptotic running time
+ * of: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3))), where q is the
+ * group order, e.g. q = 2**768.
+ */
+
+struct modp_dscr oakley_modp[] =
+{
+ { OAKLEY_GRP_1, 72, /* This group is insecure, only sufficient for DES */
+ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF",
+ "0x02"
+ },
+ { OAKLEY_GRP_2, 82, /* This group is a bit better */
+ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
+ "FFFFFFFFFFFFFFFF",
+ "0x02"
+ }
+};
+
+/* Describe preconfigured EC2N groups */
+
+/*
+ * Related collision-search methods can compute discrete logarithmns
+ * in O(sqrt(r)), r being the subgroup order.
+ */
+
+struct ec2n_dscr oakley_ec2n[] = {
+ { OAKLEY_GRP_3, 76, /* This group is also considered insecure (P1363) */
+ "0x0800000000000000000000004000000000000001",
+ "0x7b",
+ "0x00",
+ "0x7338f" },
+ { OAKLEY_GRP_4, 91,
+ "0x020000000000000000000000000000200000000000000001",
+ "0x18",
+ "0x00",
+ "0x1ee9" },
+};
+
+struct group groups[] = {
+ {
+ MODP, OAKLEY_GRP_1, 0, &oakley_modp[0], NULL, NULL, NULL, NULL, NULL,
+ (int (*) (struct group *))modp_getlen,
+ (void (*) (struct group *, void *, u_int8_t *))modp_getraw,
+ (void (*) (struct group *, void *, u_int8_t *, int))modp_setraw,
+ (void (*) (struct group *, void *))modp_setrandom,
+ (void (*) (struct group *, void *, void *, void *))modp_operation
+ },
+ {
+ MODP, OAKLEY_GRP_2, 0, &oakley_modp[1], NULL, NULL, NULL, NULL, NULL,
+ (int (*) (struct group *))modp_getlen,
+ (void (*) (struct group *, void *, u_int8_t *))modp_getraw,
+ (void (*) (struct group *, void *, u_int8_t *, int))modp_setraw,
+ (void (*) (struct group *, void *))modp_setrandom,
+ (void (*) (struct group *, void *, void *, void *))modp_operation
+ },
+ {
+ EC2N, OAKLEY_GRP_3, 0, &oakley_ec2n[0], NULL, NULL, NULL, NULL, NULL,
+ (int (*) (struct group *))ec2n_getlen,
+ (void (*) (struct group *, void *, u_int8_t *))ec2n_getraw,
+ (void (*) (struct group *, void *, u_int8_t *, int))ec2n_setraw,
+ (void (*) (struct group *, void *))ec2n_setrandom,
+ (void (*) (struct group *, void *, void *, void *))ec2n_operation
+ },
+ {
+ EC2N, OAKLEY_GRP_4, 0, &oakley_ec2n[1], NULL, NULL, NULL, NULL, NULL,
+ (int (*) (struct group *))ec2n_getlen,
+ (void (*) (struct group *, void *, u_int8_t *))ec2n_getraw,
+ (void (*) (struct group *, void *, u_int8_t *, int))ec2n_setraw,
+ (void (*) (struct group *, void *))ec2n_setrandom,
+ (void (*) (struct group *, void *, void *, void *))ec2n_operation
+ }
+};
+
+
+/*
+ * Initalize the group structure for later use,
+ * this is done by converting the values given in the describtion
+ * and converting them to their native representation.
+ */
+
+void
+group_init (void)
+{
+ int i;
+
+ for (i = sizeof (groups)/sizeof (groups[0]) -1; i >= 0; i--)
+ switch (groups[i].type)
+ {
+ case EC2N: /* Initalize an Elliptic Curve over GF(2**n) */
+ ec2n_init (&groups[i]);
+ break;
+
+ case MODP: /* Initalize an over GF(p) */
+ modp_init (&groups[i]);
+ break;
+
+ default:
+ log_print ("Unknown group type %d at index %d in group_init().",
+ groups[i].type, i);
+ break;
+ }
+}
+
+struct group *
+group_get (int id)
+{
+ struct group *new, *clone;
+ if (id < 1 || id > (sizeof (groups)/sizeof (groups[0])))
+ return NULL;
+
+ clone = &groups[id-1];
+
+ if ((new = malloc (sizeof (struct group))) == NULL)
+ {
+ log_print ("group_get: Out of memory");
+ return (NULL);
+ }
+
+ switch (clone->type)
+ {
+ case EC2N:
+ new = ec2n_clone (new, clone);
+ break;
+ case MODP:
+ new = modp_clone (new, clone);
+ break;
+ default:
+ log_print ("group_get: Unknown group type %d", clone->type);
+ free (new);
+ return (NULL);
+ }
+ return (new);
+}
+
+void
+group_free (struct group *grp)
+{
+ switch (grp->type)
+ {
+ case EC2N:
+ ec2n_free (grp);
+ break;
+ case MODP:
+ modp_free (grp);
+ default:
+ log_print ("group_free: Unknown group type %d", grp->type);
+ break;
+ }
+ free (grp);
+}
+
+struct group *
+modp_clone (struct group *new, struct group *clone)
+{
+ struct modp_group *new_grp, *clone_grp = clone->group;
+
+ if ((new_grp = malloc (sizeof (struct modp_group))) == NULL)
+ {
+ log_print ("modp_clone: Out of memory");
+ free (new);
+ return (NULL);
+ }
+
+ memcpy (new, clone, sizeof (struct group));
+
+ new->group = new_grp;
+ mpz_init_set (new_grp->p, clone_grp->p);
+
+ mpz_init_set (new_grp->gen, clone_grp->gen);
+
+ mpz_init (new_grp->a);
+ mpz_init (new_grp->b);
+ mpz_init (new_grp->c);
+
+ new->gen = new_grp->gen;
+ new->a = new_grp->a;
+ new->b = new_grp->b;
+ new->c = new_grp->c;
+
+ return (new);
+}
+
+void
+modp_free (struct group *old)
+{
+ struct modp_group *grp = old->group;
+
+ mpz_clear (grp->p);
+ mpz_clear (grp->gen);
+ mpz_clear (grp->a);
+ mpz_clear (grp->b);
+ mpz_clear (grp->c);
+
+ free (grp);
+}
+
+void
+modp_init (struct group *group)
+{
+ struct modp_dscr *dscr = (struct modp_dscr *)group->group;
+
+ struct modp_group *grp;
+
+ if ((grp = malloc (sizeof (struct modp_group))) == NULL)
+ log_fatal ("modp_init: Out of memory");
+
+ group->bits = dscr->bits;
+
+ mpz_init_set_str (grp->p, dscr->prime, 0);
+
+ mpz_init_set_str (grp->gen, dscr->gen, 0);
+
+ mpz_init (grp->a);
+ mpz_init (grp->b);
+ mpz_init (grp->c);
+
+ group->gen = grp->gen;
+ group->a = grp->a;
+ group->b = grp->b;
+ group->c = grp->c;
+
+ group->group = grp;
+}
+
+struct group *
+ec2n_clone (struct group *new, struct group *clone)
+{
+ struct ec2n_group *new_grp, *clone_grp = clone->group;
+
+ if ((new_grp = malloc (sizeof (struct ec2n_group))) == NULL)
+ {
+ log_print ("ec2n_clone: Out of memory");
+ free (new);
+ return (NULL);
+ }
+
+ memcpy (new, clone, sizeof (struct group));
+
+ new->group = new_grp;
+ ec2ng_init (new_grp->grp);
+ ec2ng_set (new_grp->grp, clone_grp->grp);
+
+ ec2np_init (new_grp->gen);
+ ec2np_set (new_grp->gen, clone_grp->gen);
+
+ ec2np_init (new_grp->a);
+ ec2np_init (new_grp->b);
+ ec2np_init (new_grp->c);
+
+ new->gen = new_grp->gen;
+ new->a = new_grp->a;
+ new->b = new_grp->b;
+ new->c = new_grp->c;
+ new->d = ((ec2np_ptr)new->a)->x;
+
+ return (new);
+}
+
+void
+ec2n_free (struct group *old)
+{
+ struct ec2n_group *grp = old->group;
+
+ ec2ng_clear (grp->grp);
+ ec2np_clear (grp->gen);
+ ec2np_clear (grp->a);
+ ec2np_clear (grp->b);
+ ec2np_clear (grp->c);
+
+ free (grp);
+}
+
+void
+ec2n_init (struct group *group)
+{
+ struct ec2n_dscr *dscr = (struct ec2n_dscr *)group->group;
+
+ struct ec2n_group *grp;
+
+ if ((grp = malloc (sizeof (struct ec2n_group))) == NULL)
+ log_fatal ("ec2n_init: Out of memory");
+
+ group->bits = dscr->bits;
+
+ ec2ng_init (grp->grp);
+ ec2ng_set_p_str (grp->grp, dscr->polynomial);
+ grp->grp->p->bits = b2n_sigbit (grp->grp->p);
+ ec2ng_set_a_str (grp->grp, dscr->a);
+ ec2ng_set_b_str (grp->grp, dscr->b);
+
+ ec2np_init (grp->gen); ec2np_set_x_str (grp->gen, dscr->gen_x);
+ ec2np_find_y (grp->gen, grp->grp);
+
+ /* Sanity check */
+ if (!ec2np_ison (grp->gen, grp->grp))
+ log_fatal ("ec2n_init: Generator is not on curve");
+
+ ec2np_init (grp->a);
+ ec2np_init (grp->b);
+ ec2np_init (grp->c);
+
+ group->gen = grp->gen;
+ group->a = grp->a;
+ group->b = grp->b;
+ group->c = grp->c;
+ group->d = ((ec2np_ptr)group->a)->x;
+
+ group->group = grp;
+}
+
+int
+modp_getlen (struct group *group)
+{
+ struct modp_group *grp = (struct modp_group *)group->group;
+
+ return mpz_sizeinoctets (grp->p);
+}
+
+void
+modp_getraw (struct group *grp, mpz_ptr v, u_int8_t *d)
+{
+ mpz_getraw (d, v, grp->getlen (grp));
+}
+
+void
+modp_setraw (struct group *grp, mpz_ptr d, u_int8_t *s, int l)
+{
+ mpz_setraw (d, s, l);
+}
+
+void
+modp_setrandom (struct group *grp, mpz_ptr d)
+{
+ int i, l = grp->getlen (grp);
+ u_int32_t tmp = 0;
+
+ mpz_set_ui (d, 0);
+
+ for (i = 0; i < l; i++)
+ {
+ if (i % 4)
+ tmp = sysdep_random();
+
+ mpz_mul_2exp (d, d, 8);
+ mpz_add_ui (d, d, tmp & 0xFF);
+ tmp >>= 8;
+ }
+}
+
+void
+modp_operation (struct group *group, mpz_ptr d, mpz_ptr a, mpz_ptr e)
+{
+ struct modp_group *grp = (struct modp_group *)group->group;
+ mpz_powm (d, a, e, grp->p);
+}
+
+int
+ec2n_getlen (struct group *group)
+{
+ struct ec2n_group *grp = (struct ec2n_group *)group->group;
+ int bits = b2n_sigbit (grp->grp->p) - 1;
+
+ return (7 + bits) >> 3;
+}
+
+void
+ec2n_getraw (struct group *group, ec2np_ptr xo, u_int8_t *e)
+{
+ struct ec2n_group *grp = (struct ec2n_group *)group->group;
+ int chunks, bytes, i, j;
+ b2n_ptr x = xo->x;
+ CHUNK_TYPE tmp;
+
+ bytes = b2n_sigbit (grp->grp->p) - 1;
+ chunks = (CHUNK_MASK + bytes) >> CHUNK_SHIFTS;
+ bytes = ((7 + (bytes & CHUNK_MASK)) >> 3);
+
+ for (i = chunks-1; i >= 0; i--)
+ {
+ tmp = (i >= x->chunks ? 0 : x->limp[i]);
+ for (j = (i == chunks - 1 ? bytes : CHUNK_BYTES) - 1; j >= 0; j--)
+ {
+ e[j] = tmp & 0xFF;
+ tmp >>= 8;
+ }
+ e += (i == chunks - 1 ? bytes : CHUNK_BYTES);
+ }
+}
+
+void
+ec2n_setraw (struct group *grp, ec2np_ptr out, u_int8_t *s, int l)
+{
+ int len, bytes, i, j;
+ b2n_ptr outx = out->x;
+ CHUNK_TYPE tmp;
+
+ len = (CHUNK_BYTES - 1 + l)/CHUNK_BYTES;
+ b2n_resize (outx, len);
+
+ bytes = ((l - 1) % CHUNK_BYTES) + 1;
+
+ for (i = len - 1; i >= 0; i--)
+ {
+ tmp = 0;
+ for (j = (i == len - 1 ? bytes : CHUNK_BYTES); j > 0; j--)
+ {
+ tmp <<= 8;
+ tmp |= *s++;
+ }
+ outx->limp[i] = tmp;
+ }
+}
+
+void
+ec2n_setrandom (struct group *group, ec2np_ptr x)
+{
+ b2n_ptr d = x->x;
+ struct ec2n_group *grp = (struct ec2n_group *)group->group;
+ b2n_random (d, b2n_sigbit (grp->grp->p) - 1);
+}
+
+/*
+ * This is an attempt at operation abstraction. It can happen
+ * that we need to initalize the y variable for the operation
+ * to proceed correctly. When this is the case operation has
+ * to supply the variable 'a' with the chunks of the Y cooridnate
+ * set to zero.
+ */
+
+void
+ec2n_operation (struct group *grp, ec2np_ptr d, ec2np_ptr a, ec2np_ptr e)
+{
+ b2n_ptr ex = e->x;
+ struct ec2n_group *group = (struct ec2n_group *)grp->group;
+
+ if (a->y->chunks == 0)
+ ec2np_find_y (a, group->grp);
+
+ ec2np_mul (d, a, ex, group->grp);
+}
diff --git a/sbin/isakmpd/math_group.h b/sbin/isakmpd/math_group.h
new file mode 100644
index 00000000000..1005456db97
--- /dev/null
+++ b/sbin/isakmpd/math_group.h
@@ -0,0 +1,96 @@
+/* $Id: math_group.h,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _MATH_GROUP_H
+#define _MATH_GROUP_H_
+
+enum groups {
+ MODP, /* F_p, Z modulo a prime */
+ EC2N, /* Elliptic Curve over the Field GF(2**N) */
+ ECP, /* Elliptic Curve over the Field Z_p */
+};
+
+/*
+ * The group on which diffie hellmann calculations are done.
+ */
+
+struct group {
+ enum groups type;
+ int id; /* Group ID */
+ int bits; /* Number of key bits provided by this group */
+ void *group;
+ void *a, *b, *c, *d;
+ void *gen; /* Group Generator */
+ int (*getlen) (struct group *);
+ void (*getraw) (struct group *, void *, u_int8_t *);
+ void (*setraw) (struct group *, void *, u_int8_t *, int);
+ void (*setrandom) (struct group *, void *);
+ void (*operation) (struct group *, void *, void *, void *);
+};
+
+/* Description of an Elliptic Group over GF(2**n) for Boot-Strapping */
+
+struct ec2n_dscr {
+ int id;
+ int bits; /* Key Bits provided by this group */
+ char *polynomial; /* Irreduceable polynomial */
+ char *gen_x; /* X - Coord. of Generator */
+ char *a, *b; /* Curve Parameters */
+};
+
+/* Description of F_p for Boot-Strapping */
+
+struct modp_dscr {
+ int id;
+ int bits; /* Key Bits provided by this group */
+ char *prime; /* Prime */
+ char *gen; /* Generator */
+};
+
+/* Prototypes */
+
+void group_init (void);
+void group_free (struct group *);
+struct group *group_get (int);
+
+void ec2n_free (struct group *);
+struct group *ec2n_clone (struct group *, struct group *);
+void ec2n_init (struct group *);
+
+void modp_free (struct group *);
+struct group *modp_clone (struct group *, struct group *);
+void modp_init (struct group *);
+
+#endif /* _MATH_GROUP_H_ */
diff --git a/sbin/isakmpd/message.c b/sbin/isakmpd/message.c
new file mode 100644
index 00000000000..8e809cf4834
--- /dev/null
+++ b/sbin/isakmpd/message.c
@@ -0,0 +1,1765 @@
+/* $Id: message.c,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <machine/endian.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "attribute.h"
+#include "cert.h"
+#include "constants.h"
+#include "crypto.h"
+#include "doi.h"
+#include "exchange.h"
+#include "field.h"
+#include "isakmp.h"
+#include "log.h"
+#include "message.h"
+#include "sa.h"
+#include "timer.h"
+#include "transport.h"
+#include "util.h"
+
+#ifdef __GNUC__
+#define INLINE __inline
+#else
+#define INLINE
+#endif
+
+/* A local set datatype, coincidentally fd_set suits our purpose fine. */
+typedef fd_set set;
+#define ISSET FD_ISSET
+#define SET FD_SET
+#define ZERO FD_ZERO
+
+static int message_check_duplicate (struct message *);
+static void message_dump_raw (char *, struct message *);
+static int message_encrypt (struct message *);
+static int message_index_payload (struct message *, struct payload *, u_int8_t,
+ u_int8_t *);
+static int message_parse_transform (struct message *, struct payload *,
+ u_int8_t, u_int8_t *);
+static int message_validate_cert (struct message *, struct payload *);
+static int message_validate_cert_req (struct message *, struct payload *);
+static int message_validate_delete (struct message *, struct payload *);
+static int message_validate_hash (struct message *, struct payload *);
+static int message_validate_id (struct message *, struct payload *);
+static int message_validate_key_exch (struct message *, struct payload *);
+static int message_validate_nonce (struct message *, struct payload *);
+static int message_validate_notify (struct message *, struct payload *);
+static int message_validate_proposal (struct message *, struct payload *);
+static int message_validate_sa (struct message *, struct payload *);
+static int message_validate_sig (struct message *, struct payload *);
+static int message_validate_transform (struct message *, struct payload *);
+static int message_validate_vendor (struct message *, struct payload *);
+
+static int (*message_validate_payload[]) (struct message *, struct payload *) =
+{
+ message_validate_sa, message_validate_proposal, message_validate_transform,
+ message_validate_key_exch, message_validate_id, message_validate_cert,
+ message_validate_cert_req, message_validate_hash, message_validate_sig,
+ message_validate_nonce, message_validate_notify, message_validate_delete,
+ message_validate_vendor
+};
+
+static struct field *fields[] = {
+ isakmp_sa_fld, isakmp_prop_fld, isakmp_transform_fld, isakmp_ke_fld,
+ isakmp_id_fld, isakmp_cert_fld, isakmp_certreq_fld, isakmp_hash_fld,
+ isakmp_sig_fld, isakmp_nonce_fld, isakmp_notify_fld, isakmp_delete_fld,
+ isakmp_vendor_fld
+};
+
+/*
+ * Fields used for checking monotonic increasing of proposal and transform
+ * numbers.
+ */
+static u_int8_t *last_sa = 0;
+static int last_prop_no;
+static u_int8_t *last_prop = 0;
+static int last_xf_no;
+
+/*
+ * Allocate a message structure bound to transport T, and with a first
+ * segment buffer sized SZ, copied from BUF if given.
+ */
+struct message *
+message_alloc (struct transport *t, u_int8_t *buf, size_t sz)
+{
+ struct message *msg;
+ int i;
+
+ /*
+ * We use calloc(3) because it zeroes the structure which we rely on in
+ * message_free when determining what sub-allocations to free.
+ */
+ msg = (struct message *)calloc (1, sizeof *msg);
+ if (!msg)
+ return 0;
+ msg->iov = calloc (1, sizeof *msg->iov);
+ if (!msg->iov)
+ {
+ message_free (msg);
+ return 0;
+ }
+ msg->iov[0].iov_len = sz;
+ msg->iov[0].iov_base = malloc (sz);
+ if (!msg->iov[0].iov_base)
+ {
+ message_free (msg);
+ return 0;
+ }
+ msg->iovlen = 1;
+ if (buf)
+ memcpy (msg->iov[0].iov_base, buf, sz);
+ msg->nextp = msg->iov[0].iov_base + ISAKMP_HDR_NEXT_PAYLOAD_OFF;
+ msg->transport = t;
+ for (i = ISAKMP_PAYLOAD_SA; i < ISAKMP_PAYLOAD_RESERVED_MIN; i++)
+ TAILQ_INIT (&msg->payload[i]);
+ TAILQ_INIT (&msg->post_send);
+ log_debug (LOG_MESSAGE, 90, "message_alloc: allocated %p", msg);
+ return msg;
+}
+
+/*
+ * Allocate a message sutiable for a reply to MSG. Just allocate an empty
+ * ISAKMP header as the first segment.
+ */
+struct message *
+message_alloc_reply (struct message *msg)
+{
+ struct message *reply;
+
+ reply = message_alloc (msg->transport, 0, ISAKMP_HDR_SZ);
+ reply->exchange = msg->exchange;
+ reply->isakmp_sa = msg->isakmp_sa;
+ return reply;
+}
+
+/* Free up all resources used by the MSG message. */
+void
+message_free (struct message *msg)
+{
+ int i;
+ struct payload *payload, *next;
+ struct post_send *node;
+
+ log_debug (LOG_MESSAGE, 20, "message_free: freeing %p", msg);
+ if (!msg)
+ return;
+ if (msg->orig && msg->orig != msg->iov[0].iov_base)
+ free (msg->orig);
+ if (msg->iov)
+ {
+ for (i = 0; i < msg->iovlen; i++)
+ if (msg->iov[i].iov_base)
+ free (msg->iov[i].iov_base);
+ free (msg->iov);
+ }
+ if (msg->retrans)
+ timer_remove_event (msg->retrans);
+ for (i = ISAKMP_PAYLOAD_SA; i < ISAKMP_PAYLOAD_RESERVED_MIN; i++)
+ for (payload = TAILQ_FIRST (&msg->payload[i]); payload; payload = next)
+ {
+ next = TAILQ_NEXT (payload, link);
+ free (payload);
+ }
+ while ((node = TAILQ_FIRST (&msg->post_send)) != 0)
+ TAILQ_REMOVE (&msg->post_send, TAILQ_FIRST (&msg->post_send), link);
+ free (msg);
+}
+
+/*
+ * Generic ISAKMP parser.
+ * MSG is the ISAKMP message to be parsed. NEXT is the type of the first
+ * payload to be parsed, and it's pointed to by BUF. ACCEPTED_PAYLOADS
+ * tells what payloads are accepted and FUNC is a pointer to a function
+ * to be called for each payload found. Returns the total length of the
+ * parsed payloads.
+ */
+static int
+message_parse_payloads (struct message *msg, struct payload *p, u_int8_t next,
+ u_int8_t *buf, set *accepted_payloads,
+ int (*func) (struct message *, struct payload *,
+ u_int8_t, u_int8_t *))
+{
+ u_int8_t payload;
+ u_int16_t len;
+ int sz = 0;
+
+ do
+ {
+ log_debug (LOG_MESSAGE, 50,
+ "message_parse_payloads: offset 0x%x payload %s",
+ buf - (u_int8_t *)msg->iov[0].iov_base,
+ constant_name (isakmp_payload_cst, next));
+
+ /* Does this payload's header fit? */
+ if (buf + ISAKMP_GEN_SZ
+ > (u_int8_t *)msg->iov[0].iov_base + msg->iov[0].iov_len)
+ {
+ log_print ("message_parse_payloads: short message");
+ message_drop (msg, ISAKMP_NOTIFY_UNEQUAL_PAYLOAD_LENGTHS, 0, 0, 1);
+ return -1;
+ }
+
+ /* Ponder on the payload that is at BUF... */
+ payload = next;
+
+ /* Look at the next payload's type. */
+ next = GET_ISAKMP_GEN_NEXT_PAYLOAD (buf);
+ if (next >= ISAKMP_PAYLOAD_RESERVED_MIN)
+ {
+ log_print ("message_parse_payloads: invalid next payload type %d "
+ "in payload of type %d", next, payload);
+ message_drop (msg, ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE, 0, 0, 1);
+ return -1;
+ }
+
+ /* Reserved fields in ISAKMP messages should be zero. */
+ if (GET_ISAKMP_GEN_RESERVED (buf) != 0)
+ {
+ log_print ("message_parse_payloads: reserved field non-zero");
+ message_drop (msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 0, 1);
+ return -1;
+ }
+
+ /*
+ * Decode the payload length field.
+ */
+ len = GET_ISAKMP_GEN_LENGTH (buf);
+
+ /*
+ * Check if the current payload is one of the accepted ones at this
+ * stage.
+ */
+ if (!ISSET (payload, accepted_payloads))
+ {
+ log_print ("message_parse_payloads: payload type %d unexpected",
+ payload);
+ message_drop (msg, ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE, 0, 0, 1);
+ return -1;
+ }
+
+ /* Call the payload handler specified by the caller. */
+ if (func (msg, p, payload, buf))
+ return -1;
+
+ /* Advance to next payload. */
+ buf += len;
+ sz += len;
+ }
+ while (next != ISAKMP_PAYLOAD_NONE);
+ return sz;
+}
+
+/*
+ * Parse a proposal payload found in message MSG. PAYLOAD is always
+ * ISAKMP_PAYLOAD_PROPOSAL and ignored in here. It's needed as the API for
+ * message_parse_payloads requires it. BUF points to the proposal's
+ * generic payload header.
+ */
+static int
+message_parse_proposal (struct message *msg, struct payload *p,
+ u_int8_t payload, u_int8_t *buf)
+{
+ set payload_set;
+
+ /* Put the proposal into the proposal bucket. */
+ message_index_payload (msg, p, payload, buf);
+
+ ZERO (&payload_set);
+ SET (ISAKMP_PAYLOAD_TRANSFORM, &payload_set);
+ if (message_parse_payloads (msg,
+ TAILQ_LAST (&msg->payload
+ [ISAKMP_PAYLOAD_PROPOSAL],
+ payload_head),
+ ISAKMP_PAYLOAD_TRANSFORM,
+ buf + ISAKMP_PROP_SPI_OFF
+ + GET_ISAKMP_PROP_SPI_SZ (buf),
+ &payload_set, message_parse_transform) == -1)
+ return -1;
+
+ return 0;
+}
+
+static int
+message_parse_transform (struct message *msg, struct payload *p,
+ u_int8_t payload, u_int8_t *buf)
+{
+ /* Put the transform into the transform bucket. */
+ message_index_payload (msg, p, payload, buf);
+
+ log_debug (LOG_MESSAGE, 50, "Transform %d's attributes",
+ GET_ISAKMP_TRANSFORM_NO (buf));
+ attribute_map (buf + ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ GET_ISAKMP_GEN_LENGTH (buf) - ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ msg->exchange->doi->debug_attribute, msg);
+
+ return 0;
+}
+
+/* Validate the certificate payload P in message MSG. */
+static int
+message_validate_cert (struct message *msg, struct payload *p)
+{
+ if (GET_ISAKMP_CERT_ENCODING (p->p) >= ISAKMP_CERTENC_RESERVED_MIN)
+ {
+ message_drop (msg, ISAKMP_NOTIFY_INVALID_CERT_ENCODING, 0, 0, 1);
+ return -1;
+ }
+ return 0;
+}
+
+/* Validate the certificate request payload P in message MSG. */
+static int
+message_validate_cert_req (struct message *msg, struct payload *p)
+{
+ struct cert_handler *cert;
+ size_t len = GET_ISAKMP_GEN_LENGTH (p->p)- ISAKMP_CERTREQ_AUTHORITY_OFF;
+
+ if (GET_ISAKMP_CERTREQ_TYPE (p->p) >= ISAKMP_CERTENC_RESERVED_MIN)
+ {
+ message_drop (msg, ISAKMP_NOTIFY_INVALID_CERT_ENCODING, 0, 0, 1);
+ return -1;
+ }
+
+ /*
+ * Check the certificate types we support and if an acceptable authority
+ * is included in the payload check if it can be decoded
+ */
+ if ((cert = cert_get (GET_ISAKMP_CERTREQ_TYPE (p->p))) == NULL ||
+ (len && !cert->certreq_validate (p->p + ISAKMP_CERTREQ_AUTHORITY_OFF,
+ len)))
+ {
+ message_drop (msg, ISAKMP_NOTIFY_CERT_TYPE_UNSUPPORTED, 0, 0, 1);
+ return -1;
+ }
+ return 0;
+}
+
+/* Validate the delete payload P in message MSG. */
+static int
+message_validate_delete (struct message *msg, struct payload *p)
+{
+ u_int8_t proto = GET_ISAKMP_DELETE_PROTO (p->p);
+ struct doi *doi;
+
+ doi = doi_lookup (GET_ISAKMP_DELETE_DOI (p->p));
+ if (!doi)
+ {
+ log_print ("message_validate_delete: DOI not supported");
+ message_free (msg);
+ return -1;
+ }
+
+ if (proto != ISAKMP_PROTO_ISAKMP && doi->validate_proto (proto))
+ {
+ log_print ("message_validate_delete: protocol not supported");
+ message_free (msg);
+ return -1;
+ }
+
+ /* Validate the SPIs. */
+
+ return 0;
+}
+
+/*
+ * Validate the hash payload P in message MSG. */
+static int
+message_validate_hash (struct message *msg, struct payload *p)
+{
+ /* XXX Not implemented yet. */
+ return 0;
+}
+
+/* Validate the identification payload P in message MSG. */
+static int
+message_validate_id (struct message *msg, struct payload *p)
+{
+ struct exchange *exchange = msg->exchange;
+ size_t len = GET_ISAKMP_GEN_LENGTH (p->p);
+
+ if (exchange->doi
+ && exchange->doi->validate_id_information (GET_ISAKMP_ID_TYPE (p->p),
+ p->p + ISAKMP_ID_DOI_DATA_OFF,
+ p->p + ISAKMP_ID_DATA_OFF,
+ len - ISAKMP_ID_DATA_OFF,
+ exchange))
+ {
+ message_drop (msg, ISAKMP_NOTIFY_INVALID_ID_INFORMATION, 0, 0, 1);
+ return -1;
+ }
+ return 0;
+}
+
+/* Validate the key exchange payload P in message MSG. */
+static int
+message_validate_key_exch (struct message *msg, struct payload *p)
+{
+ struct exchange *exchange = msg->exchange;
+ size_t len = GET_ISAKMP_GEN_LENGTH (p->p);
+
+ if (exchange->doi
+ && exchange->doi->validate_key_information (p->p + ISAKMP_KE_DATA_OFF,
+ len - ISAKMP_KE_DATA_OFF))
+ {
+ message_drop (msg, ISAKMP_NOTIFY_INVALID_KEY_INFORMATION, 0, 0, 1);
+ return -1;
+ }
+ return 0;
+}
+
+/* Validate the nonce payload P in message MSG. */
+static int
+message_validate_nonce (struct message *msg, struct payload *p)
+{
+ /* Nonces require no specific validation. */
+ return 0;
+}
+
+/* Validate the notify payload P in message MSG. */
+static int
+message_validate_notify (struct message *msg, struct payload *p)
+{
+ u_int8_t proto = GET_ISAKMP_NOTIFY_PROTO (p->p);
+ u_int16_t type = GET_ISAKMP_NOTIFY_MSG_TYPE (p->p);
+ struct doi *doi;
+
+ doi = doi_lookup (GET_ISAKMP_NOTIFY_DOI (p->p));
+ if (!doi)
+ {
+ log_print ("message_validate_notify: DOI not supported");
+ message_free (msg);
+ return -1;
+ }
+
+ if (proto != ISAKMP_PROTO_ISAKMP && doi->validate_proto (proto))
+ {
+ log_print ("message_validate_notify: protocol not supported");
+ message_free (msg);
+ return -1;
+ }
+
+ /* XXX Validate the SPI. */
+
+ if (type < ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE
+ || (type >= ISAKMP_NOTIFY_RESERVED_MIN
+ && type < ISAKMP_NOTIFY_PRIVATE_MIN)
+ || (type >= ISAKMP_NOTIFY_STATUS_RESERVED1_MIN
+ && type <= ISAKMP_NOTIFY_STATUS_RESERVED1_MAX)
+ || (type >= ISAKMP_NOTIFY_STATUS_DOI_MIN
+ && type <= ISAKMP_NOTIFY_STATUS_DOI_MAX
+ && doi->validate_notification (type))
+ || type >= ISAKMP_NOTIFY_STATUS_RESERVED2_MIN)
+ {
+ log_print ("message_validate_notify: message type not supported");
+ message_free (msg);
+ return -1;
+ }
+ return 0;
+}
+
+/* Validate the proposal payload P in message MSG. */
+static int
+message_validate_proposal (struct message *msg, struct payload *p)
+{
+ u_int8_t proto = GET_ISAKMP_PROP_PROTO (p->p);
+ u_int8_t *sa = p->context->p;
+
+ if (proto != ISAKMP_PROTO_ISAKMP
+ && msg->exchange->doi->validate_proto (proto))
+ {
+ message_drop (msg, ISAKMP_NOTIFY_INVALID_PROTOCOL_ID, 0, 0, 1);
+ return -1;
+ }
+
+ /* Check that we get monotonically increasing proposal IDs per SA. */
+ if (sa != last_sa)
+ last_sa = sa;
+ else if (GET_ISAKMP_PROP_NO (p->p) < last_prop_no)
+ {
+ message_drop (msg, ISAKMP_NOTIFY_BAD_PROPOSAL_SYNTAX, 0, 0, 1);
+ return -1;
+ }
+ last_prop_no = GET_ISAKMP_PROP_NO (p->p);
+
+ /* XXX Validate the SPI, and other syntactic things. */
+
+ return 0;
+}
+
+/*
+ * Validate the SA payload P in message MSG.
+ * Aside from normal validation, note what DOI is in use for other
+ * validation routines to look at. Also index the proposal payloads
+ * on the fly.
+ * XXX This assumes PAYLOAD_SA is always the first payload
+ * to be validated, which is true for IKE, except for quick mode where
+ * a PAYLOAD_HASH comes first, but in that specific case it does not matter.
+ */
+static int
+message_validate_sa (struct message *msg, struct payload *p)
+{
+ set payload_set;
+ size_t len;
+ u_int32_t doi_id;
+ struct exchange *exchange = msg->exchange;
+ u_int8_t *pkt = msg->iov[0].iov_base;
+
+ doi_id = GET_ISAKMP_SA_DOI (p->p);
+ if (!doi_lookup (doi_id))
+ {
+ log_print ("message_validate_sa: DOI not supported");
+ message_drop (msg, ISAKMP_NOTIFY_DOI_NOT_SUPPORTED, 0, 0, 1);
+ return -1;
+ }
+
+ /*
+ * It's time to figure out what SA this message is about. If it is
+ * already set, then we are creating a new phase 1 SA. Otherwise, lookup
+ * the SA using the cookies and the message ID. If we cannot find
+ * it, setup a phase 2 SA.
+ * XXX Is this correct?
+ */
+ if (!exchange)
+ {
+ if (zero_test (pkt + ISAKMP_HDR_RCOOKIE_OFF, ISAKMP_HDR_RCOOKIE_LEN))
+ exchange = exchange_setup_p1 (msg, doi_id);
+ else
+ exchange = exchange_setup_p2 (msg, doi_id);
+ if (!exchange)
+ {
+ /* Log? */
+ message_free (msg);
+ return -1;
+ }
+ }
+ msg->exchange = exchange;
+
+ /*
+ * Create a struct sa for each SA payload handed to us unless we are the
+ * inititor where we only will count them.
+ */
+ if (exchange->initiator)
+ {
+ /* XXX Count SA payloads. */
+ }
+ else if (sa_create (exchange, msg->transport))
+ {
+ /* XXX Remove exchange if we just created it? */
+ message_free (msg);
+ return -1;
+ }
+
+ if (exchange->phase == 1)
+ msg->isakmp_sa = TAILQ_FIRST (&exchange->sa_list);
+
+ /*
+ * Let the DOI validate the situation, at the same time it tells us what
+ * the length of the situation field is.
+ */
+ if (exchange->doi->validate_situation (p->p + ISAKMP_SA_SIT_OFF, &len))
+ {
+ log_print ("message_validate_sa: situation not supported");
+ message_drop (msg, ISAKMP_NOTIFY_SITUATION_NOT_SUPPORTED, 0, 0, 1);
+ return -1;
+ }
+
+ /* Reset the fields we base our proposal & transform number checks on. */
+ last_sa = last_prop = 0;
+ last_prop_no = last_xf_no = 0;
+
+ /* Go through the PROPOSAL payloads. */
+ ZERO (&payload_set);
+ SET (ISAKMP_PAYLOAD_PROPOSAL, &payload_set);
+ if (message_parse_payloads (msg, p, ISAKMP_PAYLOAD_PROPOSAL,
+ p->p + ISAKMP_SA_SIT_OFF + len, &payload_set,
+ message_parse_proposal) == -1)
+ return -1;
+
+ return 0;
+}
+
+/* Validate the signature payload P in message MSG. */
+static int
+message_validate_sig (struct message *msg, struct payload *p)
+{
+ /* XXX Not implemented yet. */
+ return 0;
+}
+
+/* Validate the transform payload P in message MSG. */
+static int
+message_validate_transform (struct message *msg, struct payload *p)
+{
+ u_int8_t proto = GET_ISAKMP_PROP_PROTO (p->context->p);
+ u_int8_t *prop = p->context->p;
+
+ if (msg->exchange->doi
+ ->validate_transform_id (proto, GET_ISAKMP_TRANSFORM_ID (p->p)))
+ {
+ message_drop (msg, ISAKMP_NOTIFY_INVALID_TRANSFORM_ID, 0, 0, 1);
+ return -1;
+ }
+
+ /* Check that the reserved field is zero. */
+ if (!zero_test (p->p + ISAKMP_TRANSFORM_RESERVED_OFF,
+ ISAKMP_TRANSFORM_RESERVED_LEN))
+ {
+ message_drop (msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 0, 1);
+ return -1;
+ }
+
+ /*
+ * Check that we get monotonically increasing transform numbers per proposal.
+ */
+ if (prop != last_prop)
+ last_prop = prop;
+ else if (GET_ISAKMP_TRANSFORM_NO (p->p) <= last_xf_no)
+ {
+ message_drop (msg, ISAKMP_NOTIFY_BAD_PROPOSAL_SYNTAX, 0, 0, 1);
+ return -1;
+ }
+ last_xf_no = GET_ISAKMP_TRANSFORM_NO (p->p);
+
+ /* Validate the attributes. */
+ if (attribute_map (p->p + ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ GET_ISAKMP_GEN_LENGTH (p->p)
+ - ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ msg->exchange->doi->validate_attribute, msg))
+ {
+ message_drop (msg, ISAKMP_NOTIFY_ATTRIBUTES_NOT_SUPPORTED, 0, 0, 1);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Validate the vendor payload P in message MSG. */
+static int
+message_validate_vendor (struct message *msg, struct payload *p)
+{
+ /* Vendor IDs are only allowed in phase 1. */
+ if (msg->exchange->phase != 1)
+ {
+ message_drop (msg, ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE, 0, 0, 1);
+ return -1;
+ }
+
+ log_debug (LOG_MESSAGE, 40, "message_validate_vendor: vendor ID seen");
+ return 0;
+}
+
+/*
+ * Add an index-record pointing to the payload at BUF in message MSG
+ * to the PAYLOAD bucket of payloads. This allows us to quickly reference
+ * payloads by type. Also stash the parent payload P link into the new
+ * node so we can go from transforms -> payloads -> SAs.
+ */
+static int
+message_index_payload (struct message *msg, struct payload *p,
+ u_int8_t payload, u_int8_t *buf)
+{
+ struct payload *payload_node;
+
+ /* Put the payload pointer into the right bucket. */
+ payload_node = malloc (sizeof *payload_node);
+ if (!payload_node)
+ return -1;
+ payload_node->p = buf;
+ payload_node->context = p;
+ payload_node->flags = 0;
+ TAILQ_INSERT_TAIL (&msg->payload[payload], payload_node, link);
+ return 0;
+}
+
+/*
+ * Group each payload found in MSG by type for easy reference later.
+ * While doing this, validate the generic parts of the message structure too.
+ * NEXT is the 1st payload's type. This routine will also register the
+ * computed message length (i.e. without padding) in msg->iov[0].iov_len.
+ */
+static int
+message_sort_payloads (struct message *msg, u_int8_t next)
+{
+ set payload_set;
+ int i, sz;
+
+ ZERO (&payload_set);
+ for (i = ISAKMP_PAYLOAD_SA; i < ISAKMP_PAYLOAD_RESERVED_MIN; i++)
+ if (i != ISAKMP_PAYLOAD_PROPOSAL && i != ISAKMP_PAYLOAD_TRANSFORM)
+ SET (i, &payload_set);
+ sz = message_parse_payloads (msg, 0, next,
+ msg->iov[0].iov_base + ISAKMP_HDR_SZ,
+ &payload_set, message_index_payload);
+ if (sz == -1)
+ return -1;
+ msg->iov[0].iov_len = ISAKMP_HDR_SZ + sz;
+ SET_ISAKMP_HDR_LENGTH (msg->iov[0].iov_base, ISAKMP_HDR_SZ + sz);
+ return 0;
+}
+
+/* Run all the generic payload tests that the drafts specify. */
+static int
+message_validate_payloads (struct message *msg)
+{
+ int i;
+ struct payload *p;
+
+ for (i = ISAKMP_PAYLOAD_SA; i < ISAKMP_PAYLOAD_RESERVED_MIN; i++)
+ for (p = TAILQ_FIRST (&msg->payload[i]); p; p = TAILQ_NEXT (p, link))
+ {
+ log_debug (LOG_MESSAGE, 60,
+ "message_validate_payloads: payload %s at %p of message %p",
+ constant_name (isakmp_payload_cst, i), p->p, msg);
+ field_dump_payload (fields[i - ISAKMP_PAYLOAD_SA], p->p);
+ if (message_validate_payload[i - ISAKMP_PAYLOAD_SA] (msg, p))
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * All incoming messages go through here. We do generic validity checks
+ * and try to find or establish SAs. Last but not least we try to find
+ * the exchange this message, MSG, is part of, and feed it there.
+ */
+int
+message_recv (struct message *msg)
+{
+ u_int8_t *buf = msg->iov[0].iov_base;
+ size_t sz = msg->iov[0].iov_len;
+ u_int8_t exch_type;
+ int setup_isakmp_sa, msgid_is_zero;
+ u_int8_t flags;
+ struct keystate *ks = 0;
+
+ /* Possibly dump a raw hex image of the message to the log channel. */
+ message_dump_raw ("message_recv", msg);
+
+ /* Messages shorter than an ISAKMP header are bad. */
+ if (sz < ISAKMP_HDR_SZ || sz != GET_ISAKMP_HDR_LENGTH (buf))
+ {
+ log_print ("message_recv: bad message length");
+ message_drop (msg, ISAKMP_NOTIFY_UNEQUAL_PAYLOAD_LENGTHS, 0, 0, 1);
+ return -1;
+ }
+
+ /*
+ * If the responder cookie is zero, this is a request to setup an ISAKMP SA.
+ * Otherwise the cookies should refer to an existing ISAKMP SA.
+ *
+ * XXX This is getting ugly, please reread later to see if it can be made
+ * nicer.
+ */
+ setup_isakmp_sa = zero_test (buf + ISAKMP_HDR_RCOOKIE_OFF,
+ ISAKMP_HDR_RCOOKIE_LEN);
+ if (setup_isakmp_sa)
+ {
+ /*
+ * This might be a retransmission of a former ISAKMP SA setup message.
+ * If so, just drop it.
+ * XXX Must we really look in both the SA and exchange pools?
+ */
+ if (exchange_lookup_from_icookie (buf + ISAKMP_HDR_ICOOKIE_OFF)
+ || sa_lookup_from_icookie (buf + ISAKMP_HDR_ICOOKIE_OFF))
+ {
+ log_debug (LOG_MESSAGE, 90,
+ "message_recv: dropping setup for existing SA");
+ message_free (msg);
+ return -1;
+ }
+ }
+ else
+ {
+ msg->isakmp_sa = sa_lookup_by_header (buf, 0);
+
+ /*
+ * If we cannot find an ISAKMP SA out of the cookies, this is either
+ * a responder's first reply, and we need to upgrade our exchange,
+ * or it's just plain invalid cookies.
+ */
+ if (!msg->isakmp_sa)
+ {
+ msg->exchange
+ = exchange_lookup_from_icookie (buf + ISAKMP_HDR_ICOOKIE_OFF);
+ if (msg->exchange)
+ exchange_upgrade_p1 (msg);
+ else
+ {
+ log_print ("message_recv: invalid cookie");
+ message_drop (msg, ISAKMP_NOTIFY_INVALID_COOKIE, 0, 0, 1);
+ return -1;
+ }
+#if 0
+ msg->isakmp_sa
+ = sa_lookup_from_icookie (buf + ISAKMP_HDR_ICOOKIE_OFF);
+ if (msg->isakmp_sa)
+ sa_isakmp_upgrade (msg);
+#endif
+ }
+ msg->exchange = exchange_lookup (buf, 1);
+ }
+
+ if (message_check_duplicate (msg))
+ return -1;
+
+ if (GET_ISAKMP_HDR_NEXT_PAYLOAD (buf) >= ISAKMP_PAYLOAD_RESERVED_MIN)
+ {
+ log_print ("message_recv: invalid payload type %d in ISAKMP header",
+ GET_ISAKMP_HDR_NEXT_PAYLOAD (buf));
+ message_drop (msg, ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE, 0, 0, 1);
+ return -1;
+ }
+
+ /* Validate that the message is of version 1.0. */
+ if (ISAKMP_VERSION_MAJOR (GET_ISAKMP_HDR_VERSION (buf)) != 1)
+ {
+ log_print ("message_recv: invalid version major %d",
+ ISAKMP_VERSION_MAJOR (GET_ISAKMP_HDR_VERSION (buf)));
+ message_drop (msg, ISAKMP_NOTIFY_INVALID_MAJOR_VERSION, 0, 0, 1);
+ return -1;
+ }
+
+ if (ISAKMP_VERSION_MINOR (GET_ISAKMP_HDR_VERSION (buf)) != 0)
+ {
+ log_print ("message_recv: invalid version minor %d",
+ ISAKMP_VERSION_MINOR (GET_ISAKMP_HDR_VERSION (buf)));
+ message_drop (msg, ISAKMP_NOTIFY_INVALID_MINOR_VERSION, 0, 0, 1);
+ return -1;
+ }
+
+ /*
+ * Validate the exchange type. If it's a DOI-specified exchange wait until
+ * after all payloads have been seen for the validation as the SA payload
+ * might not yet have been parsed, thus the DOI might be unknown.
+ */
+ exch_type = GET_ISAKMP_HDR_EXCH_TYPE (buf);
+ if (exch_type == ISAKMP_EXCH_NONE
+ || (exch_type >= ISAKMP_EXCH_FUTURE_MIN &&
+ exch_type <= ISAKMP_EXCH_FUTURE_MAX)
+ || (setup_isakmp_sa && exch_type >= ISAKMP_EXCH_DOI_MIN))
+ {
+ log_print ("message_recv: invalid exchange type %s",
+ constant_name (isakmp_exch_cst, exch_type));
+ message_drop (msg, ISAKMP_NOTIFY_INVALID_EXCHANGE_TYPE, 0, 0, 1);
+ return -1;
+ }
+
+ /*
+ * Check for unrecognized flags, or the encryption flag when we don't
+ * have an ISAKMP SA to decrypt with.
+ */
+ flags = GET_ISAKMP_HDR_FLAGS (buf);
+ if (flags
+ & ~(ISAKMP_FLAGS_ENC | ISAKMP_FLAGS_COMMIT | ISAKMP_FLAGS_AUTH_ONLY))
+ {
+ log_print ("message_recv: invalid flags 0x%x",
+ GET_ISAKMP_HDR_FLAGS (buf));
+ message_drop (msg, ISAKMP_NOTIFY_INVALID_FLAGS, 0, 0, 1);
+ return -1;
+ }
+
+ /* If we are about to setup an ISAKMP SA, the message ID must be zero. */
+ msgid_is_zero = zero_test (buf + ISAKMP_HDR_MESSAGE_ID_OFF,
+ ISAKMP_HDR_MESSAGE_ID_LEN);
+ if (setup_isakmp_sa && !msgid_is_zero)
+ {
+ log_print ("message_recv: invalid message id");
+ message_drop (msg, ISAKMP_NOTIFY_INVALID_MESSAGE_ID, 0, 0, 1);
+ return -1;
+ }
+
+ if (!setup_isakmp_sa && msgid_is_zero)
+ {
+ msg->exchange = exchange_lookup (buf, 0);
+ if (!msg->exchange)
+ {
+ log_print ("message_recv: phase 1 message after ISAKMP SA is ready");
+
+ /*
+ * Retransmit final message of the exchange that set up the
+ * ISAKMP SA.
+ */
+ if (msg->isakmp_sa->last_sent_in_setup)
+ {
+ log_debug (LOG_MESSAGE, 80,
+ "message_recv: resending last message from phase 1");
+ message_send (msg->isakmp_sa->last_sent_in_setup);
+ }
+
+ return -1;
+ }
+ }
+
+ if (flags & ISAKMP_FLAGS_ENC)
+ {
+ /* Decrypt rest of message using a DOI-specified IV. */
+ ks = msg->isakmp_sa->doi->get_keystate (msg);
+ if (!ks)
+ {
+ message_free (msg);
+ return -1;
+ }
+ msg->orig = malloc (sz);
+ if (!msg->orig)
+ {
+ message_free (msg);
+ return -1;
+ }
+ memcpy (msg->orig, buf, sz);
+ crypto_decrypt (ks, buf + ISAKMP_HDR_SZ, sz - ISAKMP_HDR_SZ);
+ }
+ else
+ msg->orig = buf;
+ msg->orig_sz = sz;
+
+ /*
+ * Check the overall payload structure at the same time as indexing them by
+ * type.
+ */
+ if (GET_ISAKMP_HDR_NEXT_PAYLOAD (buf) != ISAKMP_PAYLOAD_NONE
+ && message_sort_payloads (msg, GET_ISAKMP_HDR_NEXT_PAYLOAD (buf)))
+ {
+ message_free (msg);
+ return -1;
+ }
+
+ /*
+ * Run generic payload tests now. If anything fails these checks, the
+ * message needs either to be retained for later duplicate checks or
+ * freed entirely.
+ * XXX Should SAs and even transports be cleaned up then too?
+ */
+ if (message_validate_payloads (msg))
+ return -1;
+
+ /*
+ * Now we can validate DOI-specific exchange types. If we have no SA
+ * DOI-specific exchange types are definitely wrong.
+ */
+ if (exch_type >= ISAKMP_EXCH_DOI_MIN && exch_type <= ISAKMP_EXCH_DOI_MAX
+ && (!msg->exchange || msg->exchange->doi->validate_exchange (exch_type)))
+ {
+ log_print ("message_recv: invalid DOI exchange type %d", exch_type);
+ message_drop (msg, ISAKMP_NOTIFY_INVALID_EXCHANGE_TYPE, 0, 0, 1);
+ return -1;
+ }
+
+ /* If we have not found an exchange by now something is definitely wrong. */
+ if (!msg->exchange)
+ {
+ log_print ("message_recv: no exchange");
+ message_drop (msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 0, 1);
+ return -1;
+ }
+
+ /* Make sure the IV we used gets saved in the proper SA. */
+ if (!msg->exchange->keystate && ks)
+ {
+ msg->exchange->keystate = ks;
+ msg->exchange->crypto = ks->xf;
+ }
+
+ /* Handle the flags. */
+ if (flags & ISAKMP_FLAGS_ENC)
+ msg->exchange->flags |= EXCHANGE_FLAG_ENCRYPT;
+ if ((msg->exchange->flags & EXCHANGE_FLAG_COMMITTED) == 0
+ && (flags & ISAKMP_FLAGS_COMMIT))
+ msg->exchange->flags |= EXCHANGE_FLAG_HE_COMMITTED;
+
+ /* OK let the exchange logic do the rest. */
+ exchange_run (msg);
+
+ return 0;
+}
+
+/* Queue up message MSG for transmittal. */
+void
+message_send (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+
+ /* Reset the retransmission event. */
+ msg->retrans = 0;
+
+ /*
+ * If the ISAKMP SA has set up encryption, encrypt the message.
+ * However, in a retransmit, it is already encrypted.
+ */
+ if ((msg->flags & MSG_ENCRYPTED) == 0
+ && exchange->flags & EXCHANGE_FLAG_ENCRYPT)
+ {
+ if (!exchange->keystate)
+ {
+ exchange->keystate = exchange->doi->get_keystate (msg);
+ exchange->crypto = exchange->keystate->xf;
+ exchange->flags |= EXCHANGE_FLAG_ENCRYPT;
+ }
+
+ if (message_encrypt (msg))
+ {
+ /* XXX Log. */
+ return;
+ }
+ }
+
+ /* Keep the COMMIT bit on. */
+ if (exchange && exchange->flags & EXCHANGE_FLAG_COMMITTED)
+ SET_ISAKMP_HDR_FLAGS (msg->iov[0].iov_base,
+ GET_ISAKMP_HDR_FLAGS (msg->iov[0].iov_base)
+ | ISAKMP_FLAGS_COMMIT);
+
+ message_dump_raw ("message_send", msg);
+ TAILQ_INSERT_TAIL (&msg->transport->sendq, msg, link);
+}
+
+/*
+ * Setup the ISAKMP message header for message MSG. EXCHANGE is the exchange
+ * type, FLAGS are the ISAKMP header flags and MSG_ID is message ID
+ * identifying the exchange.
+ */
+void
+message_setup_header (struct message *msg, u_int8_t exchange, u_int8_t flags,
+ u_int8_t *msg_id)
+{
+ u_int8_t *buf = msg->iov[0].iov_base;
+
+ SET_ISAKMP_HDR_ICOOKIE (buf, msg->exchange->cookies);
+ SET_ISAKMP_HDR_RCOOKIE (buf,
+ msg->exchange->cookies + ISAKMP_HDR_ICOOKIE_LEN);
+ SET_ISAKMP_HDR_NEXT_PAYLOAD (buf, ISAKMP_PAYLOAD_NONE);
+ SET_ISAKMP_HDR_VERSION (buf, ISAKMP_VERSION_MAKE (1, 0));
+ SET_ISAKMP_HDR_EXCH_TYPE (buf, exchange);
+ SET_ISAKMP_HDR_FLAGS (buf, flags);
+ SET_ISAKMP_HDR_MESSAGE_ID (buf, msg_id);
+ SET_ISAKMP_HDR_LENGTH (buf, msg->iov[0].iov_len);
+}
+
+/*
+ * Add the payload of type PAYLOAD in BUF sized SZ to the MSG message.
+ * The caller thereby is released from the responsibility of freeing BUF,
+ * unless we return a failure of course. If LINK is set the former
+ * payload's "next payload" field to PAYLOAD.
+ *
+ * XXX We might want to resize the iov array several slots at a time.
+ */
+int
+message_add_payload (struct message *msg, u_int8_t payload, u_int8_t *buf,
+ size_t sz, int link)
+{
+ struct iovec *new_iov;
+ struct payload *payload_node;
+
+ payload_node = malloc (sizeof *payload_node);
+ if (!payload_node)
+ return -1;
+ new_iov
+ = (struct iovec *)realloc (msg->iov, (msg->iovlen + 1) * sizeof *msg->iov);
+ if (!new_iov)
+ {
+ free (payload_node);
+ return -1;
+ }
+ msg->iov = new_iov;
+ new_iov[msg->iovlen].iov_base = buf;
+ new_iov[msg->iovlen].iov_len = sz;
+ msg->iovlen++;
+ if (link)
+ *msg->nextp = payload;
+ msg->nextp = buf + ISAKMP_GEN_NEXT_PAYLOAD_OFF;
+ *msg->nextp = ISAKMP_PAYLOAD_NONE;
+ SET_ISAKMP_GEN_RESERVED (buf, 0);
+ SET_ISAKMP_GEN_LENGTH (buf, sz);
+ SET_ISAKMP_HDR_LENGTH (msg->iov[0].iov_base,
+ GET_ISAKMP_HDR_LENGTH (msg->iov[0].iov_base) + sz);
+
+ /*
+ * For the sake of exchange_validate we index the payloads even in outgoing
+ * messages, however context and flags are uninteresting in this situation.
+ */
+ payload_node->p = buf;
+ TAILQ_INSERT_TAIL (&msg->payload[payload], payload_node, link);
+ return 0;
+}
+
+/* XXX Move up when ready. */
+struct info_args {
+ char discr;
+ u_int32_t doi;
+ u_int8_t proto;
+ u_int16_t spi_sz;
+ union {
+ struct {
+ u_int16_t msg_type;
+ u_int8_t *spi;
+ } n;
+ struct {
+ u_int16_t nspis;
+ u_int8_t **spi;
+ } d;
+ } u;
+};
+
+/*
+ * As a reaction to the incoming message MSG create an informational exchange
+ * protected by ISAKMP_SA and send a notify payload of type NOTIFY, with
+ * fields initialized from SA.
+ *
+ * XXX Should we handle sending multiple notify payloads? The draft allows
+ * it, but do we need it? Furthermore, should we not return a success
+ * status value?
+ */
+void
+message_send_notification (struct message *msg, struct sa *isakmp_sa,
+ u_int16_t notify, struct proto *proto,
+ int initiator)
+{
+ struct info_args args;
+
+ args.discr = 'N';
+ args.doi = proto ? proto->sa->doi->id : 0;
+ args.proto = proto ? proto->proto : 0;
+ args.spi_sz = proto ? proto->spi_sz[initiator] : 0;
+ args.u.n.msg_type = notify;
+ args.u.n.spi = proto ? proto->spi[initiator] : 0;
+ if (isakmp_sa->flags & SA_FLAG_READY)
+ exchange_establish_p2 (isakmp_sa, ISAKMP_EXCH_INFO, &args);
+ else
+ exchange_establish_p1 (msg->transport, ISAKMP_EXCH_INFO,
+ msg->exchange->doi->id, &args);
+}
+
+void
+message_send_info (struct message *msg)
+{
+ u_int8_t *buf;
+ size_t sz;
+ struct info_args *args = msg->extra;
+ u_int8_t payload;
+
+ sz = (args->discr == 'N' ? ISAKMP_NOTIFY_SPI_OFF + args->spi_sz
+ : ISAKMP_DELETE_SPI_OFF + args->u.d.nspis * args->spi_sz);
+ buf = calloc (1, sz);
+ switch (args->discr)
+ {
+ case 'N':
+ /* Build the NOTIFY payload. */
+ payload = ISAKMP_PAYLOAD_NOTIFY;
+ SET_ISAKMP_NOTIFY_DOI (buf, args->doi);
+ SET_ISAKMP_NOTIFY_PROTO (buf, args->proto);
+ SET_ISAKMP_NOTIFY_SPI_SZ (buf, args->spi_sz);
+ SET_ISAKMP_NOTIFY_MSG_TYPE (buf, args->u.n.msg_type);
+ memcpy (buf + ISAKMP_NOTIFY_SPI_OFF, args->u.n.spi, args->spi_sz);
+ break;
+
+ case 'D':
+ default: /* Silence GCC. */
+ /* Build the DELETE payload. */
+ payload = ISAKMP_PAYLOAD_DELETE;
+ SET_ISAKMP_DELETE_DOI (buf, args->doi);
+ SET_ISAKMP_DELETE_PROTO (buf, args->proto);
+ SET_ISAKMP_DELETE_SPI_SZ (buf, args->spi_sz);
+ SET_ISAKMP_DELETE_NSPIS (buf, args->u.d.nspis);
+ memcpy (buf + ISAKMP_DELETE_SPI_OFF, args->u.d.spi,
+ args->u.d.nspis * args->spi_sz);
+ break;
+ }
+
+ if (message_add_payload (msg, payload, buf, sz, 1))
+ {
+ /* Log! */
+ message_free (msg);
+ return;
+ }
+}
+
+/*
+ * Drop the MSG message due to reason given in NOTIFY. If NOTIFY is set
+ * send out a notification to the originator.
+ */
+void
+message_drop (struct message *msg, int notify, struct proto *proto,
+ int initiator, int clean)
+{
+ struct transport *t = msg->transport;
+ struct sockaddr *dst;
+ int dst_len;
+
+ t->vtbl->get_dst (t, &dst, &dst_len);
+
+ /* XXX Assumes IPv4. */
+ log_print ("dropped message from %s due to notification type %s",
+ inet_ntoa (((struct sockaddr_in *)dst)->sin_addr),
+ constant_name (isakmp_notify_cst, notify));
+
+ /*
+ * If specified and we have at least an ISAKMP SA, return a notification.
+ * XXX how to setup my SA.
+ */
+ if (notify && msg->isakmp_sa)
+ message_send_notification (msg, msg->isakmp_sa, notify, proto, initiator);
+ if (clean)
+ message_free (msg);
+}
+
+/*
+ * If the user demands debug printouts, printout MSG with as much detail
+ * as we can without resorting to per-payload handling.
+ */
+static void
+message_dump_raw (char *header, struct message *msg)
+{
+ int i, j, k = 0;
+ char buf[80], *p = buf;
+
+ /* XXX Should we use LOG_MESSAGE instead? */
+ log_debug (LOG_TRANSPORT, 10, "%s: message %p", header, msg);
+ field_dump_payload (isakmp_hdr_fld, msg->iov[0].iov_base);
+ for (i = 0; i < msg->iovlen; i++)
+ for (j = 0; j < msg->iov[i].iov_len; j++)
+ {
+ sprintf(p, "%02x", ((u_int8_t *)msg->iov[i].iov_base)[j]);
+ p += 2;
+ if (++k % 32 == 0)
+ {
+ *p = '\0';
+ log_debug (LOG_TRANSPORT, 10, "%s", buf);
+ p = buf;
+ }
+ else if (k % 4 == 0)
+ *p++ = ' ';
+ }
+ *p = '\0';
+ if (p != buf)
+ log_debug (LOG_TRANSPORT, 10, "%s", buf);
+}
+
+/*
+ * Encrypt an outgoing message MSG. As outgoing messages are represented
+ * with an iovec with one segment per payload, we need to coalesce them
+ * into just une buffer containing all payloads and some padding before
+ * we encrypt.
+ */
+static int
+message_encrypt (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ size_t sz = 0;
+ u_int8_t *buf;
+ int i;
+
+ /* If no payloads, nothing to do. */
+ if (msg->iovlen == 1)
+ return 0;
+
+ /*
+ * For encryption we need to put all payloads together in a single buffer.
+ * This buffer should be padded to the current crypto transform's blocksize.
+ */
+ for (i = 1; i < msg->iovlen; i++)
+ sz += msg->iov[i].iov_len;
+ sz = ((sz + exchange->crypto->blocksize - 1) / exchange->crypto->blocksize)
+ * exchange->crypto->blocksize;
+ buf = realloc (msg->iov[1].iov_base, sz);
+ if (!buf)
+ return -1;
+ msg->iov[1].iov_base = buf;
+ for (i = 2; i < msg->iovlen; i++)
+ {
+ memcpy (buf + msg->iov[1].iov_len, msg->iov[i].iov_base,
+ msg->iov[i].iov_len);
+ msg->iov[1].iov_len += msg->iov[i].iov_len;
+ free (msg->iov[i].iov_base);
+ }
+
+ /* Pad with zeroes. */
+ memset (buf + msg->iov[1].iov_len, '\0', sz - msg->iov[1].iov_len);
+ msg->iov[1].iov_len = sz;
+ msg->iovlen = 2;
+
+ SET_ISAKMP_HDR_FLAGS (msg->iov[0].iov_base,
+ GET_ISAKMP_HDR_FLAGS (msg->iov[0].iov_base)
+ | ISAKMP_FLAGS_ENC);
+ SET_ISAKMP_HDR_LENGTH (msg->iov[0].iov_base, ISAKMP_HDR_SZ + sz);
+ crypto_encrypt (exchange->keystate, buf, msg->iov[1].iov_len);
+ msg->flags |= MSG_ENCRYPTED;
+
+ /* Update the IV so we can decrypt the next incoming message. */
+ crypto_update_iv (exchange->keystate);
+
+ return 0;
+}
+
+/*
+ * Check whether the message MSG is a duplicate of the last one negotiating
+ * this specific SA.
+ */
+static int
+message_check_duplicate (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ size_t sz = msg->iov[0].iov_len;
+ u_int8_t *pkt = msg->iov[0].iov_base;
+
+ /* If no SA has been found, we cannot test, thus it's good. */
+ if (!exchange)
+ return 0;
+
+ log_debug (LOG_MESSAGE, 90, "message_check_duplicate: last_received 0x%x",
+ exchange->last_received);
+ if (exchange->last_received)
+ {
+ log_debug_buf (LOG_MESSAGE, 95, "message_check_duplicate: last_received",
+ exchange->last_received->orig,
+ exchange->last_received->orig_sz);
+ /* Is it a duplicate, lose the new one. */
+ if (sz == exchange->last_received->orig_sz
+ && memcmp (pkt, exchange->last_received->orig, sz) == 0)
+ {
+ log_debug (LOG_MESSAGE, 80, "message_check_duplicate: dropping dup");
+ /* XXX Should we do an early retransmit of our last message? */
+ message_free (msg);
+ return -1;
+ }
+ }
+
+ /*
+ * As this new message is an indication that state is moving forward
+ * at the peer, remove the retransmit timer on our last message.
+ */
+ if (exchange->last_sent)
+ {
+ message_free (exchange->last_sent);
+ exchange->last_sent = 0;
+ }
+
+ return 0;
+}
+
+/* Helper to message_negotiate_sa. */
+static INLINE struct payload *
+step_transform (struct payload *tp, struct payload **propp,
+ struct payload **sap)
+{
+ tp = TAILQ_NEXT (tp, link);
+ if (tp)
+ {
+ *propp = tp->context;
+ *sap = (*propp)->context;
+ }
+ return tp;
+}
+
+/*
+ * Pick out the first transforms out of MSG (which should contain at least one
+ * SA payload) we accept as a full protection suite.
+ */
+int
+message_negotiate_sa (struct message *msg)
+{
+ struct payload *tp, *propp, *sap, *next_tp = 0, *next_propp, *next_sap;
+ struct sa *sa;
+ struct proto *proto;
+ int suite_ok_so_far = 0;
+ struct exchange *exchange = msg->exchange;
+ u_int8_t *spi;
+ size_t spi_sz;
+
+ /*
+ * This algorithm is a weird bottom-up thing... mostly due to the
+ * payload links pointing upwards.
+ *
+ * The algorithm goes something like this:
+ * Foreach transform
+ * If transform is compatible
+ * Remember that this protocol can work
+ * Skip to last transform of this protocol
+ * If next transform belongs to a new protocol inside the same suite
+ * If no transform was found for the current protocol
+ * Forget all earlier transforms for protocols in this suite
+ * Skip to last transform of this suite
+ * If next transform belongs to a new suite
+ * If the current protocol had an OK transform
+ * Skip to the last transform of this SA
+ * If the next transform belongs to a new SA
+ * If no transforms have been chosen
+ * Issue a NO_PROPOSAL_CHOSEN notification
+ */
+
+ sa = TAILQ_FIRST (&exchange->sa_list);
+ for (tp = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_TRANSFORM]); tp;
+ tp = next_tp)
+ {
+ propp = tp->context;
+ sap = propp->context;
+ sap->flags |= PL_MARK;
+ next_tp = step_transform (tp, &next_propp, &next_sap);
+
+ /* For each transform, see if it is compatible. */
+ if (!attribute_map (tp->p + ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ GET_ISAKMP_GEN_LENGTH (tp->p)
+ - ISAKMP_TRANSFORM_SA_ATTRS_OFF,
+ exchange->doi->is_attribute_incompatible, msg))
+ {
+ log_debug (LOG_MESSAGE, 30,
+ "message_negotiate_sa: "
+ "transform %d proto %d proposal %d ok",
+ GET_ISAKMP_TRANSFORM_NO (tp->p),
+ GET_ISAKMP_PROP_PROTO (propp->p),
+ GET_ISAKMP_PROP_NO (propp->p));
+ if (sa_add_transform (sa, tp, exchange->initiator, &proto))
+ goto cleanup;
+ suite_ok_so_far = 1;
+
+ /* Skip to last transform of this protocol proposal. */
+ while ((next_tp = step_transform (tp, &next_propp, &next_sap))
+ && next_propp == propp)
+ tp = next_tp;
+ }
+
+ /*
+ * Figure out if we will be looking at a new protocol proposal
+ * inside the current protection suite.
+ */
+ if (next_tp && propp != next_propp && sap == next_sap
+ && (GET_ISAKMP_PROP_NO (propp->p)
+ == GET_ISAKMP_PROP_NO (next_propp->p)))
+ {
+ if (!suite_ok_so_far)
+ {
+ log_debug (LOG_MESSAGE, 30,
+ "message_negotiate_sa: proto %d proposal %d failed",
+ GET_ISAKMP_PROP_PROTO (propp->p),
+ GET_ISAKMP_PROP_NO (propp->p));
+ /* Remove potentially succeeded choices from the SA. */
+ while (TAILQ_FIRST (&sa->protos))
+ TAILQ_REMOVE (&sa->protos, TAILQ_FIRST (&sa->protos), link);
+
+ /* Skip to the last transform of this protection suite. */
+ while ((next_tp = step_transform (tp, &next_propp, &next_sap))
+ && (GET_ISAKMP_PROP_NO (next_propp->p)
+ == GET_ISAKMP_PROP_NO (propp->p))
+ && next_sap == sap)
+ tp = next_tp;
+ }
+ suite_ok_so_far = 0;
+ }
+
+ /* Figure out if we will be looking at a new protection suite. */
+ if (!next_tp
+ || (propp != next_propp
+ && (GET_ISAKMP_PROP_NO (propp->p)
+ != GET_ISAKMP_PROP_NO (next_propp->p)))
+ || sap != next_sap)
+ {
+ /*
+ * Check if the suite we just considered was OK, if so we're done.
+ */
+ if (suite_ok_so_far)
+ {
+ log_debug (LOG_MESSAGE, 30,
+ "message_negotiate_sa: proposal %d succeeded",
+ GET_ISAKMP_PROP_NO (propp->p));
+
+ /* Record the other guy's SPI. */
+ spi_sz = GET_ISAKMP_PROP_SPI_SZ (propp->p);
+ if (spi_sz)
+ {
+ spi = malloc (spi_sz);
+ if (!spi)
+ goto cleanup;
+ memcpy (spi, propp->p + ISAKMP_PROP_SPI_OFF, spi_sz);
+ }
+ else
+ spi = 0;
+ TAILQ_FIRST (&sa->protos)->spi[!msg->exchange->initiator]
+ = spi;
+ log_debug_buf (LOG_MESSAGE, 40, "message_negotiate_sa: SPI", spi,
+ spi_sz);
+
+ /* Skip to the last transform of this SA. */
+ while ((next_tp = step_transform (tp, &next_propp, &next_sap))
+ && next_sap == sap)
+ tp = next_tp;
+ }
+ }
+
+ /* Have we walked all the proposals of an SA? */
+ if (!next_tp || sap != next_sap)
+ {
+ if (!suite_ok_so_far)
+ {
+ /*
+ * XXX We cannot possibly call this a drop... seeing we just turn
+ * down one of the offers, can we? I suggest renaming
+ * message_drop to something else.
+ */
+ message_drop (msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 0, 0);
+ }
+ sa = TAILQ_NEXT (sa, next);
+ }
+ }
+ return 0;
+
+ cleanup:
+ /* Remove potentially succeeded choices from the SA. */
+ while (TAILQ_FIRST (&sa->protos))
+ TAILQ_REMOVE (&sa->protos, TAILQ_FIRST (&sa->protos), link);
+ return -1;
+}
+
+int
+message_add_sa_payload (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ u_int8_t *sa_buf, *saved_nextp_sa, *saved_nextp_prop;
+ size_t sa_len, extra_sa_len;
+ int i, nprotos = 0;
+ struct proto *proto;
+ u_int8_t **transforms = 0, **proposals = 0;
+ size_t *transform_lens = 0, *proposal_lens = 0;
+ struct sa *sa;
+ struct doi *doi = exchange->doi;
+ u_int8_t *spi = 0;
+ size_t spi_sz;
+
+ /*
+ * Generate SA payloads.
+ */
+ for (sa = TAILQ_FIRST (&exchange->sa_list); sa;
+ sa = TAILQ_NEXT (sa, next))
+ {
+ /* Setup a SA payload. */
+ sa_len = ISAKMP_SA_SIT_OFF + doi->situation_size ();
+ extra_sa_len = 0;
+ sa_buf = malloc (sa_len);
+ if (!sa_buf)
+ goto cleanup;
+ SET_ISAKMP_SA_DOI (sa_buf, doi->id);
+ doi->setup_situation (sa_buf);
+
+ /* Count transforms. */
+ nprotos = 0;
+ for (proto = TAILQ_FIRST (&sa->protos); proto;
+ proto = TAILQ_NEXT (proto, link))
+ nprotos++;
+
+ /* Allocate transient transform and proposal payload/size vectors. */
+ transforms = calloc (nprotos, sizeof *transforms);
+ if (!transforms)
+ goto cleanup;
+ transform_lens = calloc (nprotos, sizeof *transform_lens);
+ if (!transform_lens)
+ goto cleanup;
+ proposals = calloc (nprotos, sizeof *proposals);
+ if (!proposals)
+ goto cleanup;
+ proposal_lens = calloc (nprotos, sizeof *proposal_lens);
+ if (!proposal_lens)
+ goto cleanup;
+
+ /* Pick out the chosen transforms. */
+ for (proto = TAILQ_FIRST (&sa->protos), i = 0; proto;
+ proto = TAILQ_NEXT (proto, link), i++)
+ {
+ transform_lens[i] = GET_ISAKMP_GEN_LENGTH (proto->chosen->p);
+ transforms[i] = malloc (transform_lens[i]);
+ if (!transforms[i])
+ goto cleanup;
+
+ /* Get SPI from application. */
+ if (doi->get_spi)
+ {
+ spi = doi->get_spi (&spi_sz,
+ GET_ISAKMP_PROP_PROTO (proto->chosen
+ ->context->p),
+ msg);
+ if (spi_sz && !spi)
+ goto cleanup;
+ proto->spi[exchange->initiator] = spi;
+ proto->spi_sz[exchange->initiator] = spi_sz;
+ }
+ else
+ spi_sz = 0;
+
+ proposal_lens[i] = ISAKMP_PROP_SPI_OFF + spi_sz;
+ proposals[i] = malloc (proposal_lens[i]);
+ if (!proposals[i])
+ goto cleanup;
+
+ memcpy (transforms[i], proto->chosen->p, transform_lens[i]);
+ memcpy (proposals[i], proto->chosen->context->p,
+ ISAKMP_PROP_SPI_OFF);
+ SET_ISAKMP_PROP_NTRANSFORMS (proposals[i], 1);
+ SET_ISAKMP_PROP_SPI_SZ (proposals[i], spi_sz);
+ if (spi_sz)
+ memcpy (proposals[i] + ISAKMP_PROP_SPI_OFF, spi, spi_sz);
+ free (spi);
+ spi = 0;
+ extra_sa_len += proposal_lens[i] + transform_lens[i];
+ }
+
+ /*
+ * Add the payloads. As this is a SA, we need to recompute the
+ * lengths of the payloads containing others. We also need to
+ * reset these payload's "next payload type" field.
+ */
+ if (message_add_payload (msg, ISAKMP_PAYLOAD_SA, sa_buf, sa_len, 1))
+ goto cleanup;
+ SET_ISAKMP_GEN_LENGTH (sa_buf, sa_len + extra_sa_len);
+ sa_buf = 0;
+
+ saved_nextp_sa = msg->nextp;
+ for (proto = TAILQ_FIRST (&sa->protos), i = 0; proto;
+ proto = TAILQ_NEXT (proto, link), i++)
+ {
+ if (message_add_payload (msg, ISAKMP_PAYLOAD_PROPOSAL, proposals[i],
+ proposal_lens[i], i > 1))
+ goto cleanup;
+ SET_ISAKMP_GEN_LENGTH (proposals[i],
+ proposal_lens[i] + transform_lens[i]);
+ proposals[i] = 0;
+
+ saved_nextp_prop = msg->nextp;
+ if (message_add_payload (msg, ISAKMP_PAYLOAD_TRANSFORM,
+ transforms[i], transform_lens[i], 0))
+ goto cleanup;
+ msg->nextp = saved_nextp_prop;
+ transforms[i] = 0;
+ }
+ msg->nextp = saved_nextp_sa;
+
+ /* Free the temporary allocations made above. */
+ free (transforms);
+ free (transform_lens);
+ free (proposals);
+ free (proposal_lens);
+ }
+ return 0;
+
+ cleanup:
+ if (spi)
+ free (spi);
+ if (sa_buf)
+ free (sa_buf);
+ for (i = 0; i < nprotos; i++)
+ {
+ if (transforms[i])
+ free (transforms[i]);
+ if (proposals[i])
+ free (proposals[i]);
+ }
+ if (transforms)
+ free (transforms);
+ if (transform_lens)
+ free (transform_lens);
+ if (proposals)
+ free (proposals);
+ if (proposal_lens)
+ free (proposal_lens);
+ return -1;
+}
+
+/*
+ * Return a copy of MSG's constants starting from OFFSET and stash the size
+ * in SZP. It is the callers responsibility to free this up.
+ */
+u_int8_t *
+message_copy (struct message *msg, size_t offset, size_t *szp)
+{
+ int i, skip = -1;
+ size_t sz = 0;
+ ssize_t start = -1;
+ u_int8_t *buf, *p;
+
+ /* Calculate size of message and where we want to start to copy. */
+ for (i = 1; i < msg->iovlen; i++)
+ {
+ sz += msg->iov[i].iov_len;
+ if (sz <= offset)
+ skip = i;
+ else if (start < 0)
+ start = offset - (sz - msg->iov[i].iov_len);
+ }
+
+ /* Allocate and copy. */
+ *szp = sz - offset;
+ buf = malloc (*szp);
+ if (!buf)
+ return 0;
+ p = buf;
+ for (i = skip + 1; i < msg->iovlen; i++)
+ {
+ memcpy (p, msg->iov[i].iov_base + start, msg->iov[i].iov_len - start);
+ p += msg->iov[i].iov_len - start;
+ start = 0;
+ }
+ return buf;
+}
+
+/* Register a post-send function POST_SEND with message MSG. */
+int
+message_register_post_send (struct message *msg,
+ void (*post_send) (struct message *))
+{
+ struct post_send *node;
+
+ node = malloc (sizeof *node);
+ if (!node)
+ return -1;
+ node->func = post_send;
+ TAILQ_INSERT_TAIL (&msg->post_send, node, link);
+ return 0;
+}
+
+/* Run the post-send functions of message MSG. */
+void
+message_post_send (struct message *msg)
+{
+ struct post_send *node;
+
+ while ((node = TAILQ_FIRST (&msg->post_send)) != 0)
+ {
+ TAILQ_REMOVE (&msg->post_send, node, link);
+ node->func (msg);
+ free (node);
+ }
+}
diff --git a/sbin/isakmpd/message.h b/sbin/isakmpd/message.h
new file mode 100644
index 00000000000..30d202148b9
--- /dev/null
+++ b/sbin/isakmpd/message.h
@@ -0,0 +1,178 @@
+/* $Id: message.h,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _MESSAGE_H_
+#define _MESSAGE_H_
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include "isakmp.h"
+
+struct event;
+struct message;
+struct proto;
+struct sa;
+struct transport;
+
+struct payload {
+ /* Link all payloads of the same type through here. */
+ TAILQ_ENTRY (payload) link;
+
+ /* The pointer to the actual payload data. */
+ u_int8_t *p;
+
+ /*
+ * A pointer to the parent payload, used for proposal and transform payloads.
+ */
+ struct payload *context;
+
+ /* Payload flags described below. */
+ int flags;
+};
+
+/* Payload flags. */
+
+/*
+ * Set this when a payload has been handled, so we later can sweep over
+ * unhandled ones.
+ */
+#define PL_MARK 1
+
+/* A post-send chain of functions to be called. */
+struct post_send {
+ /* Link to the next function in the chain. */
+ TAILQ_ENTRY (post_send) link;
+
+ /* The actual function. */
+ void (*func) (struct message *);
+};
+
+struct message {
+ /* Link message in send queues via this link. */
+ TAILQ_ENTRY (message) link;
+
+ /* Message flags described below. */
+ u_int flags;
+
+ /*
+ * This is the transport the message either arrived on or will be sent to.
+ */
+ struct transport *transport;
+
+ /*
+ * This is the ISAKMP SA protecting this message.
+ * XXX Needs to be redone to some keystate pointer or something.
+ */
+ struct sa *isakmp_sa;
+
+ /* This is the exchange where this message appears. */
+ struct exchange *exchange;
+
+ /*
+ * A segmented buffer structure holding the messages raw contents. On input
+ * only segment 0 will be filled, holding all of the message. On output, as
+ * long as the message body is unencrypted each segment will be one payload,
+ * after encryption segment 0 will be the unencryptd header, and segment 1
+ * will be the encrypted payloads, all of them.
+ */
+ struct iovec *iov;
+
+ /* The segment count. */
+ u_int iovlen;
+
+ /* Pointer to the last "next payload" field. */
+ u_int8_t *nextp;
+
+ /* "Smart" pointers to each payload, sorted by type. */
+ TAILQ_HEAD (payload_head, payload) payload[ISAKMP_PAYLOAD_RESERVED_MIN];
+
+ /* Number of times this message has been sent. */
+ int xmits;
+
+ /* The timeout event causing retransmission of this message. */
+ struct event *retrans;
+
+ /* The (possibly encrypted) message text, used for duplicate testing. */
+ u_int8_t *orig;
+ size_t orig_sz;
+
+ /*
+ * Extra baggage needed to travel with the message. Used transiently
+ * in context sensitive ways.
+ */
+ void *extra;
+
+ /*
+ * Hooks for stuff needed to be done after the message has gone out to
+ * the wire.
+ */
+ TAILQ_HEAD (post_send_head, post_send) post_send;
+};
+
+/* Message flags. */
+
+/* Don't retransmit this message, ever. */
+#define MSG_NO_RETRANS 1
+
+/* Don't free message after sending */
+#define MSG_KEEP 2
+
+/* The message has already been encrypted. */
+#define MSG_ENCRYPTED 4
+
+extern int message_add_payload (struct message *, u_int8_t, u_int8_t *,
+ size_t, int);
+extern int message_add_sa_payload (struct message *);
+extern struct message *message_alloc (struct transport *, u_int8_t *, size_t);
+extern struct message *message_alloc_reply (struct message *);
+extern u_int8_t *message_copy (struct message *, size_t, size_t *);
+extern void message_drop (struct message *, int, struct proto *, int, int);
+extern void message_free (struct message *);
+extern int message_negotiate_sa (struct message *);
+extern int message_recv (struct message *);
+extern int message_register_post_send (struct message *,
+ void (*) (struct message *));
+extern void message_post_send (struct message *);
+extern void message_send (struct message *);
+extern void message_send_info (struct message *);
+extern void message_send_notification (struct message *, struct sa *,
+ u_int16_t, struct proto *, int);
+extern void message_setup_header (struct message *, u_int8_t, u_int8_t,
+ u_int8_t *);
+
+#endif /* _MESSAGE_H_ */
diff --git a/sbin/isakmpd/pf_encap.c b/sbin/isakmpd/pf_encap.c
new file mode 100644
index 00000000000..9f572036fed
--- /dev/null
+++ b/sbin/isakmpd/pf_encap.c
@@ -0,0 +1,654 @@
+/* $Id: pf_encap.c,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <net/encap.h>
+#include <netinet/ip_ah.h>
+#include <netinet/ip_esp.h>
+#include <netinet/ip_ip4.h>
+#include <netinet/ip_ipsp.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "app.h"
+#include "conf.h"
+#include "hash.h"
+#include "ipsec.h"
+#include "ipsec_num.h"
+#include "isakmp.h"
+#include "log.h"
+#include "pf_encap.h"
+#include "sa.h"
+#include "sysdep.h"
+#include "timer.h"
+#include "transport.h"
+
+void pf_encap_request_sa (struct encap_msghdr *);
+
+int
+pf_encap_open ()
+{
+ int fd;
+
+ fd = socket (PF_ENCAP, SOCK_RAW, PF_UNSPEC);
+ if (fd == -1)
+ {
+ log_error ("pf_encap_open: "
+ "socket (PF_ENCAP, SOCK_RAW, PF_UNSPEC) failed");
+ return -1;
+ }
+ return fd;
+}
+
+static void
+pf_encap_expire (struct encap_msghdr *emsg)
+{
+ /* XXX not implemented yet. */
+}
+
+static void
+pf_encap_notify (struct encap_msghdr *emsg)
+{
+ log_debug_buf (LOG_PF_ENCAP, 90, "pf_encap_notify: emsg", (u_int8_t *)emsg,
+ sizeof *emsg);
+
+ switch (emsg->em_not_type)
+ {
+ case NOTIFY_SOFT_EXPIRE:
+ case NOTIFY_HARD_EXPIRE:
+ log_debug (LOG_PF_ENCAP, 20,
+ "pf_encap_handler: NOTIFY_%s_EXPIRE dst %s spi %x sproto %d",
+ emsg->em_not_type == NOTIFY_SOFT_EXPIRE ? "SOFT" : "HARD",
+ inet_ntoa (emsg->em_not_dst), emsg->em_not_spi,
+ emsg->em_not_sproto);
+ pf_encap_expire (emsg);
+ break;
+
+ case NOTIFY_REQUEST_SA:
+ log_debug (LOG_PF_ENCAP, 10,
+ "pf_encap_handler: SA requested for %s type %d",
+ inet_ntoa (emsg->em_not_dst), emsg->em_not_satype);
+ pf_encap_request_sa (emsg);
+ break;
+
+ default:
+ log_print ("pf_encap_handler: unknown notify message type (%d)",
+ emsg->em_not_type);
+ break;
+ }
+ free (emsg);
+}
+
+void
+pf_encap_handler (int fd)
+{
+ u_int8_t *buf;
+ struct encap_msghdr *emsg;
+ ssize_t len;
+
+ /*
+ * PF_ENCAP version 1 has a max length equal to the notify length on
+ * upcoming packets.
+ */
+ buf = malloc (EMT_NOTIFY_FLEN);
+ if (!buf)
+ return;
+ emsg = (struct encap_msghdr *)buf;
+
+ len = read (fd, buf, EMT_NOTIFY_FLEN);
+ if (len == -1)
+ {
+ log_error ("pf_encap_handler: read (%d, ...) failed", fd);
+ free (emsg);
+ return;
+ }
+
+ if (emsg->em_version != PFENCAP_VERSION_1)
+ {
+ log_print ("pf_encap_handler: "
+ "unexpected message version (%d) from PF_ENCAP socket",
+ emsg->em_version);
+ free (emsg);
+ return;
+ }
+
+ if (emsg->em_type != EMT_NOTIFY)
+ {
+ log_print ("pf_encap_handler: "
+ "unexpected message type (%d) from PF_ENCAP socket",
+ emsg->em_type);
+ free (emsg);
+ return;
+ }
+
+ pf_encap_notify (emsg);
+}
+
+void
+pf_encap_request_sa (struct encap_msghdr *emsg)
+{
+ struct transport *transport;
+ struct sa *isakmp_sa;
+ char addr[20];
+ in_port_t port;
+ struct sockaddr *taddr;
+ int taddr_len;
+
+ /*
+ * XXX I'd really want some more flexible way to map the IPv4 address in
+ * this message to a general transport endpoint. For now we hardcode
+ * the ISAKMP peer to be at the same IP and talking UDP.
+ */
+ port = conf_get_num (inet_ntoa (emsg->em_not_dst), "port");
+ if (!port)
+ port = UDP_DEFAULT_PORT;
+ snprintf (addr, 20, "%s:%d", inet_ntoa (emsg->em_not_dst), port);
+ transport = transport_create ("udp", addr);
+ if (!transport)
+ {
+ log_print ("pf_encap_request_sa: "
+ "transport \"udp %s\" could not be created",
+ transport, addr);
+ return;
+ }
+
+ /* Check if we already have an ISAKMP SA setup. */
+ transport->vtbl->get_dst (transport, &taddr, &taddr_len);
+ isakmp_sa = sa_isakmp_lookup_by_peer (taddr, taddr_len);
+ if (!isakmp_sa)
+ /* XXX transport_free (transport) */ ;
+}
+
+/* Write a PF_ENCAP request down to the kernel. */
+static int
+pf_encap_write (struct encap_msghdr *em)
+{
+ ssize_t n;
+
+ em->em_version = PFENCAP_VERSION_1;
+
+ log_debug_buf (LOG_PF_ENCAP, 30, "pf_encap_write: em", (u_int8_t *)em,
+ em->em_msglen);
+ n = write (app_socket, em, em->em_msglen);
+ if (n == -1)
+ {
+ log_error ("write (%d, ...) failed", app_socket);
+ return -1;
+ }
+ if ((size_t)n != em->em_msglen)
+ {
+ log_error ("write (%d, ...) returned prematurely", app_socket);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Read a PF_ENCAP non-notify packet (e.g. an answer to a request of ours)
+ * If we see a notify queue it up as a timeout timing out NOW for the main
+ * loop to see.
+ */
+static struct encap_msghdr *
+pf_encap_read ()
+{
+ u_int8_t *buf;
+ ssize_t n;
+ struct encap_msghdr *emsg;
+ struct timeval now;
+
+ /*
+ * PF_ENCAP version 1 has a max length equal to the notify length on
+ * upcoming packets.
+ */
+ buf = malloc (EMT_NOTIFY_FLEN);
+ if (!buf)
+ goto cleanup;
+ emsg = (struct encap_msghdr *)buf;
+
+ while (1)
+ {
+ /* XXX Should we have a static pf_encap_socket instead? */
+ n = read (app_socket, buf, EMT_NOTIFY_FLEN);
+ if (n == -1)
+ {
+ log_error ("read (%d, ...) failed", app_socket);
+ goto cleanup;
+ }
+
+ if ((size_t)n < EMT_GENLEN || (size_t)n != emsg->em_msglen)
+ {
+ log_print ("read (%d, ...) returned short packet (%d bytes)",
+ app_socket, n);
+ goto cleanup;
+ }
+
+ /* We drop all messages that is not what we expect. */
+ if (emsg->em_version != PFENCAP_VERSION_1)
+ continue;
+
+ /*
+ * Enqueue notifications so they will be dealt with as soon as we get
+ * back to the main server loop.
+ */
+ if (emsg->em_type == EMT_NOTIFY)
+ {
+ gettimeofday (&now, 0);
+ timer_add_event ("pf_encap_notify",
+ (void (*) (void *))pf_encap_notify, emsg, &now);
+
+ /* We need a new buffer since we gave our former one away. */
+ buf = malloc (EMT_NOTIFY_FLEN);
+ if (!buf)
+ goto cleanup;
+ emsg = (struct encap_msghdr *)buf;
+ continue;
+ }
+
+ return emsg;
+ }
+
+ cleanup:
+ if (buf)
+ free (buf);
+ return 0;
+}
+
+u_int8_t *
+pf_encap_get_spi (size_t *sz, u_int8_t proto, void *id, size_t id_sz)
+{
+ struct encap_msghdr *emsg = 0;
+ u_int8_t *spi = 0;
+ struct sockaddr_in *ipv4_id = id;
+
+ emsg = calloc (1, EMT_RESERVESPI_FLEN);
+ if (!emsg)
+ return 0;
+
+ emsg->em_msglen = EMT_RESERVESPI_FLEN;
+ emsg->em_type = EMT_RESERVESPI;
+ emsg->em_gen_spi = 0;
+ memcpy (&emsg->em_gen_dst, &ipv4_id->sin_addr, sizeof ipv4_id->sin_addr);
+ emsg->em_gen_sproto =
+ proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH;
+
+ if (pf_encap_write (emsg))
+ goto cleanup;
+ free (emsg);
+ emsg = pf_encap_read ();
+ if (!emsg)
+ goto cleanup;
+
+ *sz = sizeof emsg->em_gen_spi;
+ spi = malloc (*sz);
+ if (!spi)
+ goto cleanup;
+ memcpy (spi, &emsg->em_gen_spi, *sz);
+ free (emsg);
+
+ log_debug_buf (LOG_MISC, 50, "pf_encap_get_spi: spi", spi, *sz);
+
+ return spi;
+
+ cleanup:
+ if (emsg)
+ free (emsg);
+ if (spi)
+ free (spi);
+ return 0;
+}
+
+/* Group 2 SPIs in a chain. XXX not implemented yet. */
+int
+pf_encap_group_spis (struct sa *sa, struct proto *proto1, struct proto *proto2,
+ int role)
+{
+ struct encap_msghdr *emsg = 0;
+ struct sockaddr *dst;
+ int dstlen;
+
+ emsg = calloc (1, EMT_GRPSPIS_FLEN);
+ if (!emsg)
+ return -1;
+
+ emsg->em_msglen = EMT_GRPSPIS_FLEN;
+ emsg->em_type = EMT_GRPSPIS;
+
+ memcpy (&emsg->em_rel_spi, proto1->spi[role], sizeof emsg->em_rel_spi);
+ memcpy (&emsg->em_rel_spi2, proto2->spi[role],
+ sizeof emsg->em_rel_spi2);
+ sa->transport->vtbl->get_dst (sa->transport, &dst, &dstlen);
+ emsg->em_rel_dst = emsg->em_rel_dst2 = ((struct sockaddr_in *)dst)->sin_addr;
+ /* XXX What if IPCOMP etc. comes along? */
+ emsg->em_rel_sproto
+ = proto1->proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH;
+ emsg->em_rel_sproto2
+ = proto2->proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH;
+
+ if (pf_encap_write (emsg))
+ goto cleanup;
+ free (emsg);
+
+ log_debug (LOG_MISC, 50, "pf_encap_group_spis: done");
+
+ return 0;
+
+ cleanup:
+ if (emsg)
+ free (emsg);
+ return -1;
+}
+
+/* Store/update a SPI with full information into the kernel. */
+int
+pf_encap_set_spi (struct sa *sa, struct proto *proto, int role, int initiator)
+{
+ struct encap_msghdr *emsg = 0;
+ struct ipsec_proto *iproto = proto->data;
+ struct sockaddr *dst, *src;
+ int dstlen, srclen, keylen, hashlen;
+ size_t len;
+ struct esp_new_xencap *edx;
+ struct ah_new_xencap *amx;
+
+ switch (proto->proto)
+ {
+ case IPSEC_PROTO_IPSEC_ESP:
+ keylen = ipsec_esp_enckeylength (proto);
+ hashlen = ipsec_esp_authkeylength (proto);
+ len = EMT_SETSPI_FLEN + ESP_NEW_XENCAP_LEN + keylen + hashlen + 8;
+ emsg = calloc (1, len);
+ if (!emsg)
+ return -1;
+
+ /* Whenever should the "old" transforms be used? Policy thing? */
+ emsg->em_alg = XF_NEW_ESP;
+ emsg->em_sproto = IPPROTO_ESP;
+
+ edx = (struct esp_new_xencap *)emsg->em_dat;
+
+ switch (proto->id)
+ {
+ case IPSEC_ESP_DES:
+ case IPSEC_ESP_DES_IV32:
+ case IPSEC_ESP_DES_IV64:
+ edx->edx_enc_algorithm = ALG_ENC_DES;
+ break;
+
+ case IPSEC_ESP_3DES:
+ edx->edx_enc_algorithm = ALG_ENC_3DES;
+ break;
+
+ case IPSEC_ESP_CAST:
+ edx->edx_enc_algorithm = ALG_ENC_CAST;
+ break;
+
+ case IPSEC_ESP_BLOWFISH:
+ edx->edx_enc_algorithm = ALG_ENC_BLF;
+ break;
+
+ default:
+ /* XXX Log? */
+ return -1;
+ }
+
+ switch (iproto->auth)
+ {
+ case IPSEC_AUTH_HMAC_MD5:
+ edx->edx_hash_algorithm = ALG_AUTH_MD5;
+ break;
+
+ case IPSEC_AUTH_HMAC_SHA:
+ edx->edx_hash_algorithm = ALG_AUTH_SHA1;
+ break;
+
+ case IPSEC_AUTH_DES_MAC:
+ case IPSEC_AUTH_KPDK:
+ /* XXX Log? */
+ return -1;
+
+ default:
+ edx->edx_hash_algorithm = 0;
+ }
+
+ /* XXX What if we have a protocol requiring IV? */
+ edx->edx_ivlen = 8;
+ edx->edx_confkeylen = keylen;
+ edx->edx_authkeylen = hashlen;
+ edx->edx_wnd = 16;
+ edx->edx_flags = iproto->auth ? ESP_NEW_FLAG_AUTH : 0;
+ memcpy (edx->edx_data + 8, iproto->keymat[role], keylen);
+ if (iproto->auth)
+ memcpy (edx->edx_data + keylen + 8, iproto->keymat[role] + keylen,
+ hashlen);
+ break;
+
+ case IPSEC_PROTO_IPSEC_AH:
+ hashlen = ipsec_ah_keylength (proto);
+ len = EMT_SETSPI_FLEN + AH_NEW_XENCAP_LEN + hashlen;
+ emsg = calloc (1, len);
+ if (!emsg)
+ return -1;
+
+ /* Whenever should the "old" transforms be used? Policy thing? */
+ emsg->em_alg = XF_NEW_AH;
+ emsg->em_sproto = IPPROTO_AH;
+
+ amx = (struct ah_new_xencap *)emsg->em_dat;
+
+ switch (proto->id)
+ {
+ case IPSEC_AH_MD5:
+ amx->amx_hash_algorithm = ALG_AUTH_MD5;
+ break;
+
+ case IPSEC_AH_SHA:
+ amx->amx_hash_algorithm = ALG_AUTH_SHA1;
+ break;
+
+ default:
+ /* XXX Log? */
+ goto cleanup;
+ }
+
+ amx->amx_keylen = hashlen;
+ amx->amx_wnd = 16;
+ memcpy (amx->amx_key, iproto->keymat[role], hashlen);
+ break;
+
+ default:
+ /* XXX Log? */
+ goto cleanup;
+ }
+
+ emsg->em_msglen = len;
+ emsg->em_type = EMT_SETSPI;
+ memcpy (&emsg->em_spi, proto->spi[role], sizeof emsg->em_spi);
+ emsg->em_ttl = IP4_DEFAULT_TTL;
+ /* Fill in a well-defined value in this reserved field. */
+ emsg->em_satype = 0;
+
+ /*
+ * XXX Addresses has to be thought through. Assumes IPv4.
+ */
+ sa->transport->vtbl->get_dst (sa->transport, &dst, &dstlen);
+ sa->transport->vtbl->get_src (sa->transport, &src, &srclen);
+ emsg->em_dst
+ = ((struct sockaddr_in *)((initiator ^ role) ? dst : src))->sin_addr;
+ emsg->em_src
+ = ((struct sockaddr_in *)((initiator ^ role) ? src : dst))->sin_addr;
+ if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL)
+ {
+ emsg->em_odst = emsg->em_dst;
+ emsg->em_osrc = emsg->em_src;
+ }
+
+ /* XXX I am not sure which one is best in security respect. */
+#if 0
+ emsg->em_first_use_hard = (u_int64_t)sa->seconds;
+ /* XXX Perhaps we could calculate something out of the last negotiation. */
+ emsg->em_first_use_soft = (u_int64_t)sa->seconds * 9 / 10;
+ emsg->em_expire_hard = 0;
+ emsg->em_expire_soft = 0;
+#else
+ emsg->em_expire_hard = time ((time_t *)0) + (u_int64_t)sa->seconds;
+ /* XXX Perhaps we could calculate something out of the last negotiation. */
+ emsg->em_expire_soft = time ((time_t *)0) + (u_int64_t)sa->seconds * 9 / 10;
+ emsg->em_first_use_hard = 0;
+ emsg->em_first_use_soft = 0;
+#endif
+ emsg->em_bytes_hard = (u_int64_t)sa->kilobytes * 1024;
+ /* XXX A configurable ratio would be better. */
+ emsg->em_bytes_soft = (u_int64_t)sa->kilobytes * 1024 * 9 / 10;
+ emsg->em_packets_hard = 0;
+ emsg->em_packets_soft = 0;
+
+ log_debug (LOG_PF_ENCAP, 10, "pf_encap_set_spi: proto %d dst %s SPI 0x%x",
+ emsg->em_sproto, inet_ntoa (emsg->em_dst), htonl (emsg->em_spi));
+ if (pf_encap_write (emsg))
+ goto cleanup;
+ free (emsg);
+
+ log_debug (LOG_PF_ENCAP, 50, "pf_encap_set_spi: done");
+
+ return 0;
+
+ cleanup:
+ if (emsg)
+ free (emsg);
+ return -1;
+}
+
+/* Delete a specific SPI from the IPSEC kernel subsystem. */
+int
+pf_encap_delete_spi (struct sa *sa, struct proto *proto, int initiator)
+{
+ struct encap_msghdr *emsg = 0;
+ struct sockaddr *dst;
+ int dstlen;
+
+ emsg = calloc (1, EMT_DELSPI_FLEN);
+ if (!emsg)
+ return -1;
+
+ emsg->em_msglen = EMT_DELSPI_FLEN;
+ emsg->em_type = EMT_DELSPI;
+
+ memcpy (&emsg->em_gen_spi, proto->spi[initiator], sizeof emsg->em_gen_spi);
+ sa->transport->vtbl->get_dst (sa->transport, &dst, &dstlen);
+ emsg->em_gen_dst = ((struct sockaddr_in *)dst)->sin_addr;
+ /* XXX What if IPCOMP etc. comes along? */
+ emsg->em_gen_sproto
+ = proto->proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH;
+
+ if (pf_encap_write (emsg))
+ goto cleanup;
+ free (emsg);
+
+ log_debug (LOG_MISC, 50, "pf_encap_delete_spi: done");
+
+ return 0;
+
+ cleanup:
+ if (emsg)
+ free (emsg);
+ return -1;
+}
+
+/* Enable a flow. */
+int
+pf_encap_enable_spi (struct sa *sa, int initiator)
+{
+ struct encap_msghdr *emsg = 0;
+ struct sockaddr *dst, *src;
+ int dstlen, srclen;
+ struct proto *proto = TAILQ_FIRST (&sa->protos);
+
+ emsg = calloc (1, EMT_ENABLESPI_FLEN);
+ if (!emsg)
+ return -1;
+
+ emsg->em_msglen = EMT_ENABLESPI_FLEN;
+ emsg->em_type = EMT_ENABLESPI;
+
+ sa->transport->vtbl->get_dst (sa->transport, &dst, &dstlen);
+ sa->transport->vtbl->get_src (sa->transport, &src, &srclen);
+
+ memcpy (&emsg->em_ena_spi, proto->spi[!initiator], sizeof emsg->em_ena_spi);
+ emsg->em_ena_dst = ((struct sockaddr_in *)dst)->sin_addr;
+
+ emsg->em_ena_isrc.s_addr = ((struct sockaddr_in *)src)->sin_addr.s_addr;
+ emsg->em_ena_ismask.s_addr = 0xffffffff;
+ emsg->em_ena_idst.s_addr = emsg->em_ena_dst.s_addr;
+ emsg->em_ena_idmask.s_addr = 0xffffffff;
+ /* XXX How to deduce if we need ENABLE_FLAG_LOCAL? */
+ emsg->em_ena_flags = ENABLE_FLAG_REPLACE;
+
+ /* XXX What if IPCOMP etc. comes along? */
+ emsg->em_ena_sproto
+ = proto->proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH;
+
+ if (pf_encap_write (emsg))
+ goto cleanup;
+
+ /*
+ * XXX The condition should be true if this machine is part of the source
+ * subnet.
+ */
+ if (1)
+ {
+ /*
+ * This "route" is used for packets from this host where the source
+ * address has not yet been decided.
+ */
+ emsg->em_ena_flags |= ENABLE_FLAG_LOCAL;
+ if (pf_encap_write (emsg))
+ goto cleanup;
+ }
+ free (emsg);
+
+ log_debug (LOG_MISC, 50, "pf_encap_enable_spi: done");
+
+ return 0;
+
+ cleanup:
+ if (emsg)
+ free (emsg);
+ return -1;
+}
diff --git a/sbin/isakmpd/pf_encap.h b/sbin/isakmpd/pf_encap.h
new file mode 100644
index 00000000000..7df50b06670
--- /dev/null
+++ b/sbin/isakmpd/pf_encap.h
@@ -0,0 +1,65 @@
+/* $Id: pf_encap.h,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _PF_ENCAP_H_
+#define _PF_ENCAP_H_
+
+#include <sys/queue.h>
+
+struct proto;
+struct sa;
+
+struct pf_encap_node {
+ /* Link to next node. */
+ TAILQ_ENTRY (pf_encap_node) link;
+
+ /* The message itself. */
+ struct encap_msghdr *emsg;
+
+ /* The callback function and its argument. */
+ void (*callback) (void *);
+ void *arg;
+};
+
+extern int pf_encap_delete_spi (struct sa *, struct proto *, int);
+extern int pf_encap_enable_spi (struct sa *, int);
+extern u_int8_t *pf_encap_get_spi (size_t *, u_int8_t, void *, size_t);
+extern int pf_encap_group_spis (struct sa *, struct proto *, struct proto *,
+ int);
+extern void pf_encap_handler (int);
+extern int pf_encap_open (void);
+extern int pf_encap_set_spi (struct sa *, struct proto *, int, int);
+
+#endif /* _PF_ENCAP_H_ */
diff --git a/sbin/isakmpd/pkcs.h b/sbin/isakmpd/pkcs.h
new file mode 100644
index 00000000000..88ba975f79a
--- /dev/null
+++ b/sbin/isakmpd/pkcs.h
@@ -0,0 +1,79 @@
+/* $Id: pkcs.h,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _PKCS_H_
+#define _PKCS_H_
+
+#include <gmp.h>
+
+#define PKCS_PRIVATE 1 /* Private Key Encryption */
+#define PKCS_PUBLIC 2 /* Public Key Encryption */
+
+struct rsa_public_key {
+ mpz_t n; /* Group Modulus */
+ mpz_t e; /* Public Exponent */
+};
+
+struct rsa_private_key {
+ mpz_t n; /* Group Modulus */
+ mpz_t p; /* Prime p */
+ mpz_t q; /* Prime q */
+ mpz_t e; /* Public Exponent */
+ mpz_t d; /* Private Exponent */
+};
+
+struct norm_type;
+
+int pkcs_mpz_to_norm_type (struct norm_type *obj, mpz_ptr n);
+
+u_int8_t *pkcs_public_key_to_asn (struct rsa_public_key *);
+int pkcs_public_key_from_asn (struct rsa_public_key *, u_int8_t *, u_int32_t);
+void pkcs_free_public_key (struct rsa_public_key *);
+
+u_int8_t *pkcs_private_key_to_asn (struct rsa_private_key *);
+int pkcs_private_key_from_asn (struct rsa_private_key *, u_int8_t *,
+ u_int32_t);
+void pkcs_free_private_key (struct rsa_private_key *);
+
+int pkcs_rsa_encrypt (int, mpz_ptr, mpz_ptr, u_int8_t *, u_int32_t,
+ u_int8_t **, u_int32_t *);
+int pkcs_rsa_decrypt (int, mpz_ptr, mpz_ptr, u_int8_t *, u_int8_t **,
+ u_int16_t *);
+
+int pkcs_generate_rsa_keypair (struct rsa_public_key *,
+ struct rsa_private_key *, u_int32_t);
+int pkcs_generate_prime (mpz_ptr, u_int32_t);
+
+#endif /* _PKCS_H_ */
diff --git a/sbin/isakmpd/prf.c b/sbin/isakmpd/prf.c
new file mode 100644
index 00000000000..b42911963f9
--- /dev/null
+++ b/sbin/isakmpd/prf.c
@@ -0,0 +1,165 @@
+/* $Id: prf.c,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "hash.h"
+#include "log.h"
+#include "prf.h"
+
+void prf_hash_init (struct prf_hash_ctx *);
+void prf_hash_update (struct prf_hash_ctx *, unsigned char *, unsigned int);
+void prf_hash_final (unsigned char *, struct prf_hash_ctx *);
+
+/* PRF behaves likes a hash */
+
+void
+prf_hash_init (struct prf_hash_ctx *ctx)
+{
+ memcpy (ctx->hash->ctx, ctx->ctx, ctx->hash->ctxsize);
+ memcpy (ctx->hash->ctx2, ctx->ctx2, ctx->hash->ctxsize);
+}
+
+void
+prf_hash_update (struct prf_hash_ctx *ctx, unsigned char *data,
+ unsigned int len)
+{
+ ctx->hash->Update (ctx->hash->ctx, data, len);
+}
+
+void
+prf_hash_final (unsigned char *digest, struct prf_hash_ctx *ctx)
+{
+ ctx->hash->HMACFinal (digest, ctx->hash);
+}
+
+/*
+ * Obtain a Pseudo-Random Function for us. At the moment this is
+ * the HMAC version of a hash. See RFC-2104 for reference.
+ */
+
+struct prf *
+prf_alloc (enum prfs type, int subtype, char *shared, int sharedsize)
+{
+ struct hash *hash;
+ struct prf *prf;
+
+ switch (type)
+ {
+ case PRF_HMAC:
+ hash = hash_get (subtype);
+ if (hash == NULL)
+ return NULL;
+ break;
+ default:
+ log_print ("Unkown PRF type %d in prf_alloc()", type);
+ return NULL;
+ }
+
+ if ((prf = malloc (sizeof (struct prf))) == NULL)
+ {
+ log_print ("Out of memory for struct prf in prf_alloc()");
+ return NULL;
+ }
+
+ if (type == PRF_HMAC)
+ {
+ struct prf_hash_ctx *prfctx;
+
+ /* Obtain needed memory */
+ prfctx = malloc (sizeof (struct prf_hash_ctx));
+ if (prfctx == NULL)
+ {
+ log_print ("Out of memory for struct prf_hash_ctx in prf_alloc()");
+ goto cleanprf;
+ }
+ prf->prfctx = prfctx;
+
+ prfctx->ctx = malloc (hash->ctxsize);
+ if (prfctx->ctx == NULL)
+ {
+ log_print ("Out of memory for ctx in prf_alloc()");
+ goto cleanprfctx;
+ }
+
+ prfctx->ctx2 = malloc (hash->ctxsize);
+ if (prfctx->ctx2 == NULL)
+ {
+ log_print ("Out of memory for ctx2 in prf_alloc()");
+ free (prfctx->ctx);
+ goto cleanprfctx;
+ }
+ prf->type = PRF_HMAC;
+ prf->blocksize = hash->hashsize;
+ prfctx->hash = hash;
+
+ /* Use the correct function pointers */
+ prf->Init = (void (*) (void *)) prf_hash_init;
+ prf->Update
+ = (void (*) (void *, unsigned char *, unsigned int)) prf_hash_update;
+ prf->Final = (void (*) (unsigned char *, void *)) prf_hash_final;
+
+ /* Init HMAC contexts */
+ hash->HMACInit (hash, shared, sharedsize);
+
+ /* Save contexts */
+ memcpy (prfctx->ctx, hash->ctx, hash->ctxsize);
+ memcpy (prfctx->ctx2, hash->ctx2, hash->ctxsize);
+ }
+
+ return prf;
+
+ cleanprfctx:
+ free (prf->prfctx);
+ cleanprf:
+ free (prf);
+ return NULL;
+}
+
+
+void
+prf_free (struct prf *prf)
+{
+ if (prf->type == PRF_HMAC)
+ {
+ struct prf_hash_ctx *prfctx = prf->prfctx;
+ free (prfctx->ctx2);
+ free (prfctx->ctx);
+ }
+ free (prf->prfctx);
+ free (prf);
+}
diff --git a/sbin/isakmpd/prf.h b/sbin/isakmpd/prf.h
new file mode 100644
index 00000000000..d6a9023a5b2
--- /dev/null
+++ b/sbin/isakmpd/prf.h
@@ -0,0 +1,61 @@
+/* $Id: prf.h,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _PRF_H_
+#define _PRF_H_
+
+/* Enumeration of possible PRF - Pseudo-Random Functions. */
+enum prfs {
+ PRF_HMAC = 0, /* No PRFs in drafts, this is the default */
+};
+
+struct prf {
+ enum prfs type; /* Type of PRF */
+ void *prfctx; /* Context for PRF */
+ u_int8_t blocksize; /* The blocksize of PRF */
+ void (*Init) (void *);
+ void (*Update) (void *, unsigned char *, unsigned int);
+ void (*Final) (unsigned char *, void *);
+};
+
+struct prf_hash_ctx {
+ struct hash *hash; /* Hash type to use */
+ void *ctx, *ctx2; /* Contexts we need for later */
+};
+
+struct prf *prf_alloc (enum prfs, int, char *, int);
+void prf_free (struct prf *);
+
+#endif /* _PRF_H_ */
diff --git a/sbin/isakmpd/regress/Makefile b/sbin/isakmpd/regress/Makefile
new file mode 100644
index 00000000000..8b102ccee45
--- /dev/null
+++ b/sbin/isakmpd/regress/Makefile
@@ -0,0 +1,38 @@
+# $Id: Makefile,v 1.1 1998/11/15 00:03:49 niklas Exp $
+
+#
+# Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Ericsson Radio Systems.
+# 4. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# This code was written under funding by Ericsson Radio Systems.
+#
+
+SUBDIR= asn b2n crypto dh ec2n exchange group hmac pkcs prf rsakeygen x509
+
+.include <bsd.subdir.mk>
diff --git a/sbin/isakmpd/regress/asn/Makefile b/sbin/isakmpd/regress/asn/Makefile
new file mode 100644
index 00000000000..62c5e1effaf
--- /dev/null
+++ b/sbin/isakmpd/regress/asn/Makefile
@@ -0,0 +1,14 @@
+# Test ASN
+
+PROG= asntest
+SRCS= asntest.c conf.c asn.c asn_useful.c gmp_util.c log.c pkcs.c \
+ sysdep.c hash.c x509.c
+TOPOBJ!= cd ${.CURDIR}/../..; printf "all:\n\t@pwd\n" |${MAKE} -f-
+.PATH: ${.CURDIR}/../.. ${TOPOBJ}
+LDADD+= -lgmp
+DPADD+= ${LIBDES}
+NOMAN=
+CFLAGS+= -I${.CURDIR}/../.. -I${TOPOBJ} -Wall
+DEBUG= -g
+
+.include <bsd.prog.mk>
diff --git a/sbin/isakmpd/regress/asn/asntest.c b/sbin/isakmpd/regress/asn/asntest.c
new file mode 100644
index 00000000000..2d254cfd764
--- /dev/null
+++ b/sbin/isakmpd/regress/asn/asntest.c
@@ -0,0 +1,147 @@
+/* $Id: asntest.c,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <stdio.h>
+#include <string.h>
+#include <gmp.h>
+
+#include "conf.h"
+#include "asn.h"
+#include "asn_useful.h"
+#include "pkcs.h"
+#include "x509.h"
+
+int
+main (void)
+{
+ char buf[1000];
+ char buf2[1000];
+ u_int32_t len;
+ struct norm_type test = SEQ("test", Signed);
+ struct norm_type test2 = SEQ("cert", Certificate);
+ struct norm_type *tmp, *tmp2;
+ struct rsa_public_key key;
+ struct x509_certificate cert;
+ int i, j;
+ u_int8_t *asn;
+ char *p;
+
+ FILE *f = fopen ("ssh-test-ca.pem", "r");
+ len = 0;
+ while (conf_get_line (f, buf + len, sizeof (buf) - len))
+ if (buf[len] != '-')
+ len = strlen (buf);
+
+ conf_decode_base64 (buf, &len, buf);
+
+ asn_template_clone (&test, 1);
+
+ asn_decode_sequence (buf, len, &test);
+
+ p = ASN_SIGNED_ALGORITHM(&test);
+
+ printf ("ObjectId: %s = %s\n", p, asn_parse_objectid (asn_ids, p));
+
+ asn_template_clone (&test2, 1);
+
+ len = asn_get_len (ASN_SIGNED_DATA(&test));
+ asn_decode_sequence (ASN_SIGNED_DATA(&test), len, &test2);
+
+ tmp = asn_decompose ("cert.version", &test2);
+ printf ("Version: "); mpz_out_str (stdout, 16, tmp->data);
+ tmp = asn_decompose ("cert.serialNumber", &test2);
+ printf ("\nSerialNumber: "); mpz_out_str (stdout, 16, tmp->data);
+ tmp = asn_decompose ("cert.signature.algorithm", &test2);
+ printf ("\nsignature: %s\n",
+ asn_parse_objectid (asn_ids, (char *)tmp->data));
+
+ tmp = ASN_CERT_VALIDITY(&test2);
+ printf ("Begin: %s, End: %s\n", ASN_VAL_BEGIN(tmp), ASN_VAL_END(tmp));
+
+ i = 0;
+ while (1)
+ {
+ sprintf (buf2, "cert.issuer.RelativeDistinguishedName[%d]", i++);
+ tmp = asn_decompose (buf2, &test2);
+ if (tmp == NULL)
+ break;
+
+ j = 0;
+ while (1)
+ {
+ sprintf (buf2, "RelativeDistinguishedName.AttributeValueAssertion[%d].AttributeType", j);
+ tmp2 = asn_decompose (buf2, tmp);
+ if (tmp2 == NULL)
+ break;
+
+ printf ("Issuer: (%s) ",
+ asn_parse_objectid (asn_ids, tmp2->data));
+ sprintf (buf2, "RelativeDistinguishedName.AttributeValueAssertion[%d].AttributeValue", j++);
+ tmp2 = asn_decompose (buf2, tmp);
+ printf ("%s\n", (char *)tmp2->data);
+ }
+ };
+
+ tmp = asn_decompose ("cert.subjectPublicKeyInfo.algorithm.algorithm", &test2);
+ printf ("Key: %s\n", asn_parse_objectid (asn_ids, tmp->data));
+
+ tmp = asn_decompose ("cert.subjectPublicKeyInfo.subjectPublicKey", &test2);
+ asn = tmp->data + 1;
+
+ pkcs_public_key_from_asn (&key, asn, asn_get_len (asn));
+ printf ("n (%u): 0x", (unsigned int)mpz_sizeinbase (key.n, 2));
+ mpz_out_str (stdout, 16, key.n);
+ printf ("\ne: 0x"); mpz_out_str (stdout, 16, key.e);
+ printf ("\n");
+
+ printf ("Validate SIGNED: ");
+ if (!x509_validate_signed (buf, asn_get_len (buf), &key, &asn, &len))
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+ printf ("\n");
+
+ memset (&cert, 0, sizeof (cert));
+ x509_decode_certificate (buf, asn_get_len (buf), &cert);
+
+ printf ("Encoding Certificiate: ");
+ if (!x509_encode_certificate(&cert, &asn, &len))
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+ printf ("\n");
+ return 1;
+}
diff --git a/sbin/isakmpd/regress/asn/ssh-test-ca.pem b/sbin/isakmpd/regress/asn/ssh-test-ca.pem
new file mode 100644
index 00000000000..4721db3bedb
--- /dev/null
+++ b/sbin/isakmpd/regress/asn/ssh-test-ca.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CERTIFICATE-----
+MIIB/DCCAWWgAwIBAgIDAeD0MA0GCSqGSIb3DQEBBAUAMDgxCzAJBgNVBAYTAkZJMSkwJwYDVQQ
+KEyBTc2ggQ29tbXVuaWNhdGlvbnMgU2VjdXJpdHkgTHRkLjAeFw05NzEyMzEwMDAwMDBaFw05OD
+EyMzEwMDAwMDBaMDgxCzAJBgNVBAYTAkZJMSkwJwYDVQQKEyBTc2ggQ29tbXVuaWNhdGlvbnMgU
+2VjdXJpdHkgTHRkLjCBnTANBgkqhkiG9w0BAQEFAAOBiwAwgYcCgYEAmxrZfHh3PXzt4STZ27xN
+v6ccHA5Zs2rJ/NmjTz+cDtJriGtfroPjPuI82H7QifrGAmG9+iHLP9bZKvs8Bur5avXTQmxg2kT
+/53K74Tiox2hJEPWKNAPWKf8Y/sCXKJF0TEYtFlFCzkm+lmBmtuSDixgD5Xa1DNl3Ket7m4vOhq
+8CASmjFjAUMBIGA1UdEwEB/wQIMAYBAf8CAQowDQYJKoZIhvcNAQEEBQADgYEAP66aK4rdFAT/H
+PKGTEM1UQgmo8b/fi7rB90jonodOI4Xros/3R1Nj8Z5zQcx2hG5xjIAl9YpHmmPSbgtYD1SIFxF
+0sWBa12FU7u/Sa8OjBvs9K0Ofnw/Sdp7on0M6f/xTVHKFCunfAbHsqFhieej6esDJBKODpbb2pJ
+c6VphrlE=
+-----END X509 CERTIFICATE-----
diff --git a/sbin/isakmpd/regress/b2n/Makefile b/sbin/isakmpd/regress/b2n/Makefile
new file mode 100644
index 00000000000..b84f0240a60
--- /dev/null
+++ b/sbin/isakmpd/regress/b2n/Makefile
@@ -0,0 +1,12 @@
+
+# Test HMAC:
+
+PROG= b2ntest
+SRCS= math_2n.c b2ntest.c util.c sysdep.c
+.PATH: ${.CURDIR}/../../
+NOMAN=
+TOPOBJ!= cd ${.CURDIR}/../..; printf "all:\n\t@pwd\n" |${MAKE} -f-
+CFLAGS+= -I${TOPOBJ} -I${.CURDIR}/../../ -Wall
+DEBUG= -g
+
+.include <bsd.prog.mk> \ No newline at end of file
diff --git a/sbin/isakmpd/regress/b2n/b2ntest.c b/sbin/isakmpd/regress/b2n/b2ntest.c
new file mode 100644
index 00000000000..94176384c0a
--- /dev/null
+++ b/sbin/isakmpd/regress/b2n/b2ntest.c
@@ -0,0 +1,367 @@
+/* $Id: b2ntest.c,v 1.1 1998/11/15 00:03:50 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+/*
+ * B2N is a module for doing arithmetic on the Field GF(2**n) which is
+ * isomorph to ring of polynomials GF(2)[x]/p(x) where p(x) is an
+ * irreduciable polynomial over GF(2)[x] with grade n.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "math_2n.h"
+
+#define CMP_FAIL(n,x) b2n_sprint (buf, n); if (strcmp (buf, (x))) \
+ printf ("FAILED: %s != %s ", buf, x); else printf ("OKAY ");
+
+int
+main (void)
+{
+ int i;
+ b2n_t n, m, d, r;
+ char buf[200];
+
+ b2n_init (n);
+ b2n_init (m);
+ b2n_init (d);
+ b2n_init (r);
+
+ printf ("Arithimetic Tests for GF(2)[x]:\n");
+ printf ("Testing: b2n_set*: ");
+ b2n_set_ui (n, 0xffc0);
+ CMP_FAIL (n, "0xffc0");
+
+ b2n_set_str (m, "0x180c0");
+ CMP_FAIL (m, "0x0180c0");
+ b2n_set_str (m, "0x808b8080c0");
+ CMP_FAIL (m, "0x808b8080c0");
+
+ printf ("\nTesting: b2n_add: ");
+ b2n_add (d, n, m);
+ CMP_FAIL (d, "0x808b807f00");
+ b2n_add (n, n, m);
+ CMP_FAIL (n, "0x808b807f00");
+ b2n_add (n, n, n);
+ CMP_FAIL (n, "0x00");
+ b2n_set_str (n, "0x9090900000000000000000");
+ b2n_set_ui (m, 0);
+ b2n_add (n, n, m);
+ CMP_FAIL (n, "0x9090900000000000000000");
+
+ printf ("\nTesting: b2n_lshift: ");
+ b2n_set_str (m, "0x808b8080c0");
+ b2n_lshift (n, m, 3);
+ CMP_FAIL (n, "0x04045c040600");
+ b2n_lshift (n, m, 11);
+ CMP_FAIL (n, "0x04045c04060000");
+ b2n_set (n, m);
+ for (i = 0; i < 11; i++)
+ b2n_lshift (n, n, 1);
+ CMP_FAIL (n, "0x04045c04060000");
+ b2n_lshift (d, m, 12);
+ CMP_FAIL (d, "0x0808b8080c0000");
+ b2n_set_str (m, "0xdeadbeef");
+ b2n_lshift (d, m, 103);
+ CMP_FAIL (d, "0x6f56df7780000000000000000000000000");
+
+ printf ("\nTesting: b2n_rshift: ");
+ b2n_rshift (m, n, 3);
+ CMP_FAIL (m, "0x808b8080c000");
+ b2n_rshift (m, m, 11);
+ CMP_FAIL (m, "0x1011701018");
+ b2n_set_str (m, "0x12381998713258186712365");
+ b2n_rshift (m, m, 23);
+ CMP_FAIL (m, "0x024703330e264b030c");
+ b2n_set_str (m, "0x12381998713258186712365");
+ for (i=0; i<23; i++)
+ b2n_rshift (m, m, 1);
+ CMP_FAIL (m, "0x024703330e264b030c");
+
+ printf ("\nTesting: b2n_mul: 0x9 o 0x5: ");
+ b2n_set_ui (n, 9);
+ b2n_set_ui (m, 5);
+ b2n_mul (d, n, m);
+ CMP_FAIL (d, "0x2d");
+ b2n_mul (n, n, m);
+ CMP_FAIL (d, "0x2d");
+
+ printf ("\nTesting: b2n_mul: 0x9 o 0x0: ");
+ b2n_set_ui (n, 9);
+ b2n_set_ui (m, 0);
+ b2n_mul (d, n, m);
+ CMP_FAIL (d, "0x00");
+ b2n_set_ui (n, 0);
+ b2n_set_ui (m, 9);
+ b2n_mul (d, n, m);
+ CMP_FAIL (d, "0x00");
+
+ printf ("\nTesting: b2n_mul: 0x9 o 0x1: ");
+ b2n_set_ui (n, 9);
+ b2n_set_ui (m, 1);
+ b2n_mul (d, n, m);
+ CMP_FAIL (d, "0x09");
+
+ printf ("\nTesting: b2n_mul: 0x12329 o 0x1235: ");
+ b2n_set_str (n, "0x12329");
+ b2n_set_str (m, "0x1235");
+ b2n_mul (d, n, m);
+ CMP_FAIL (d, "0x10473a3d");
+ b2n_mul (n, n, m);
+ CMP_FAIL (d, "0x10473a3d");
+
+ printf ("\nTesting: b2n_square: 0x1235 o 0x1235: ");
+ b2n_set_str (m, "0x1235");
+ b2n_square (n, m);
+ CMP_FAIL (n, "0x01040511");
+
+ printf ("\nTesting: b2n_square: 0x80c1235 o 0x80c1235: ");
+ b2n_set_str (m, "0x80c1235");
+ b2n_square (n, m);
+ CMP_FAIL (n, "0x40005001040511");
+
+ b2n_set_str (m, "0x12329");
+ printf ("\nTesting: sigbit: 0x12329: %d, %s",
+ b2n_sigbit(m), b2n_sigbit(m) == 17 ? "OKAY" : "FAILED");
+ b2n_set_ui (m, 0);
+ printf ("\nTesting: sigbit: 0x0: %d, %s",
+ b2n_sigbit(m), b2n_sigbit(m) == 0 ? "OKAY" : "FAILED");
+ b2n_set_str (m, "0x7f3290000");
+ printf ("\nTesting: sigbit: 0x7f3290000: %d, %s",
+ b2n_sigbit(m), b2n_sigbit(m) == 35 ? "OKAY" : "FAILED");
+
+ printf ("\nTesting: b2n_cmp: ");
+ b2n_set_str (m, "0x2234");
+ b2n_set_str (n, "0x1234");
+ printf ("%d <-> %d, ", b2n_sigbit (m), b2n_sigbit(n));
+ printf ("%d, %d ,%d: ", b2n_cmp (m,m), b2n_cmp (m,n), b2n_cmp (n,m));
+ if (b2n_cmp (m,m) || b2n_cmp (m,n) != 1 || b2n_cmp (n,m) != -1)
+ printf ("FAILED");
+ else
+ printf ("OKAY");
+ printf ("\nTesting: b2n_cmp_null: ");
+ b2n_set_str (m, "0x2234");
+ b2n_set_ui (n, 0);
+ printf ("%d, %d: ", b2n_cmp_null (m), b2n_cmp_null (n));
+ if (b2n_cmp_null (m) != 1 || b2n_cmp_null (n))
+ printf ("FAILED");
+ else
+ printf ("OKAY");
+
+ printf ("\nTesting: b2n_div: 0x2d / 0x5: ");
+ b2n_set_str (n, "0x2d");
+ b2n_set_ui (m, 5);
+ b2n_div (n, m, n, m);
+ CMP_FAIL (n, "0x09");
+ CMP_FAIL (m, "0x00");
+ printf ("\nTesting: b2n_div: 0x2d / 0x1: ");
+ b2n_set_str (n, "0x2d");
+ b2n_set_ui (m, 1);
+ b2n_div (n, m, n, m);
+ CMP_FAIL (n, "0x2d");
+ CMP_FAIL (m, "0x00");
+
+ printf ("\nTesting: b2n_div: 0x10473a3d / 0x1235: ");
+ b2n_set_str (n, "0x10473a3d");
+ b2n_set_str (m, "0x1235");
+ b2n_div (n, m, n, m);
+ CMP_FAIL (n, "0x012329");
+ CMP_FAIL (m, "0x00");
+
+ printf ("\nTesting: b2n_div: 0x10473a3d / 0x1536: ");
+ b2n_set_str (n, "0x10473a3d");
+ b2n_set_str (m, "0x1536");
+ b2n_div (n, m, n, m);
+ CMP_FAIL (n, "0x014331");
+ CMP_FAIL (m, "0xab");
+ b2n_set_str (n, "0x10473a3d");
+ b2n_set_str (m, "0x1536");
+ b2n_div_q (d, n, m);
+ CMP_FAIL (d, "0x014331");
+ b2n_div_r (d, n, m);
+ CMP_FAIL (d, "0xab");
+
+ printf ("\nTesting: b2n_div: 0x0800000000000000000000004000000000000001 / 0xffab09909a00: ");
+ b2n_set_str (n, "0x0800000000000000000000004000000000000001");
+ b2n_set_str (m, "0xffab09909a00");
+ b2n_div_q (d, n, m);
+ CMP_FAIL (d, "0x18083e83a98647cedae0b3e69a5e");
+ b2n_div_r (d, n, m);
+ CMP_FAIL (d, "0x5b8bf98cac01");
+ b2n_set (d, m);
+ b2n_div (n, m, n, m);
+ CMP_FAIL (n, "0x18083e83a98647cedae0b3e69a5e");
+ CMP_FAIL (m, "0x5b8bf98cac01");
+
+ printf ("\nTesting: b2n_div: 0x0800000000000000000000004000000000000001 / 0x7b: ");
+ b2n_set_str (n, "0x0800000000000000000000004000000000000001");
+ b2n_set_str (m, "0x7b");
+ b2n_div (n, m, n, m);
+ CMP_FAIL (n, "0x32dea27065bd44e0cb7a89c000000000000000");
+ CMP_FAIL (m, "0x01");
+
+ printf ("\n\nArithimetic Tests for GF(2**m) ~= GF(2)[x]/p(x):\n");
+ printf ("Testing: b2n_gcd: ");
+ b2n_set_str (d, "0x771");
+ b2n_set_str (m, "0x26d");
+ b2n_gcd (n, m, d);
+ CMP_FAIL (n, "0x0b");
+ b2n_set_str (d, "0x0800000000000000000000004000000000000001");
+ b2n_set_str (m, "0xffab09909a00");
+ b2n_gcd (n, m, d);
+ CMP_FAIL (n, "0x01");
+ b2n_set_str (d, "0x0800000000000000000000004000000000000001");
+ b2n_set_str (m, "0x7b");
+ b2n_gcd (n, m, d);
+ CMP_FAIL (n, "0x01");
+
+ printf ("\nTesting: b2n_mul_inv: ");
+ b2n_set_str (d, "0x0800000000000000000000004000000000000001");
+ b2n_set_str (m, "0xffab09909a00");
+ b2n_mul_inv (n, m, d);
+ CMP_FAIL (n, "0x074029149f69304174d28858ae5c60df208a22a8");
+ b2n_set_str (n, "0xffab09909a00");
+ b2n_mul_inv (n, n, d);
+ CMP_FAIL (n, "0x074029149f69304174d28858ae5c60df208a22a8");
+ b2n_mul (n, n, m);
+ b2n_mod (n, n, d);
+ CMP_FAIL (n, "0x01");
+ b2n_set_str (d, "0x0800000000000000000000004000000000000001");
+ b2n_set_str (m, "0x7b");
+ b2n_mul_inv (n, m, d);
+ CMP_FAIL (n, "0x32dea27065bd44e0cb7a89c000000000000000");
+ b2n_mul (n, n, m);
+ b2n_mod (n, n, d);
+ CMP_FAIL (n, "0x01");
+
+ printf ("\nTesting: b2n_random: ");
+ b2n_random (m, 155);
+ b2n_sprint (buf, m);
+ printf ("%s, %d", buf, b2n_sigbit(m));
+
+ printf ("\nTesting: b2n_sqrt: ");
+ b2n_set_str (n, "0x0800000000000000000000004000000000000001");
+ b2n_set_ui (d, 2);
+ b2n_sqrt (m, d, n);
+ b2n_square (d, m);
+ b2n_add (d, d, m);
+ b2n_mod (d, d, n);
+ CMP_FAIL (d, "0x02");
+
+ /* x**3 + b */
+ b2n_set_ui (n, 0x7b);
+ b2n_square (d, n);
+ b2n_mul (d, d, n);
+ b2n_set_str (n, "0x07338f");
+ b2n_add (d, d, n);
+ b2n_set_str (n, "0x0800000000000000000000004000000000000001");
+ b2n_mod (d, d, n);
+ /* \alpha = x**3 + b - end */
+
+ /* \beta = x**(-2)*\alpha */
+ b2n_set_ui (m, 0x7b);
+ b2n_mul_inv (m, m, n);
+ b2n_square (m, m);
+ b2n_mod (m, m, n);
+ b2n_mul (d, d, m);
+ b2n_mod (d, d, n);
+ b2n_set (r, d);
+ /* \beta = x**(-2)*\alpha - end */
+
+ b2n_sqrt (m, d, n);
+ CMP_FAIL (m, "0x0690aec7cd215d8f9a42bb1f0000000000000004");
+ b2n_square (d, m);
+ b2n_mod (d, d, n);
+ b2n_add (d, d, m);
+ b2n_mod (d, d, n);
+ printf ("Squaring Check: ");
+ CMP_FAIL (d, "0x03d5af92c8311d9e8f56be4b3e690aec7cd215cc");
+
+ printf ("\nTesting: b2n_trace: ");
+ b2n_set_ui (m, 2);
+ b2n_trace (d, m, n);
+ CMP_FAIL (d, "0x00");
+ b2n_set_ui (m, 0x11223);
+ b2n_trace (d, m, n);
+ CMP_FAIL (d, "0x01");
+
+ printf ("\nTesting: b2n_exp_mod: ");
+ b2n_set_ui (m, 0x7b);
+ b2n_exp_mod (d, m, 5, n);
+ CMP_FAIL (d, "0x7cccb7cb");
+ b2n_set_str (m, "0x123456789abcdef");
+ b2n_exp_mod (d, m, 13, n);
+ CMP_FAIL (d, "0x043f0a8550cb69b3c50d0340d1c6d5c97ecd60d4");
+
+ printf ("\nTesting: b2n_3mul: ");
+ b2n_set_ui (m, 0x7b);
+ b2n_3mul (m, m);
+ CMP_FAIL (m, "0x0171");
+
+ b2n_set_ui (m, 0x7fffffff);
+ b2n_3mul (m, m);
+ CMP_FAIL (m, "0x017ffffffd");
+
+ printf ("\nTesting: b2n_nadd: ");
+ b2n_set_str (m, "0x7fffffff");
+ b2n_set_str (n, "0x10203045");
+ b2n_nadd (d, n, m);
+ CMP_FAIL (d, "0x90203044");
+
+ b2n_set_str (m, "0x9a4a54d8b8dfa566112849991214329a233d");
+ b2n_set_str (n, "0x70ee40dd60c8657e58eda9a17ad9176e28b4b457e5a34a0948e335");
+ b2n_nadd (d, n, m);
+ CMP_FAIL (d, "0x70ee40dd60c8657e5987f3f65391f7138ec5dca17eb55e3be30672");
+
+ printf ("\nTesting: b2n_nsub: ");
+ b2n_set_str (n, "0x90203044");
+ b2n_set_str (m, "0x10203045");
+ b2n_nsub (d, n, m);
+ CMP_FAIL (d, "0x7fffffff");
+
+ b2n_set_str (n, "0x70ee40dd60c8657e5987f3f65391f7138ec5dca17eb55e3be30672");
+ b2n_set_str (m, "0x70ee40dd60c8657e58eda9a17ad9176e28b4b457e5a34a0948e335");
+ b2n_nsub (d, n, m);
+ CMP_FAIL (d, "0x9a4a54d8b8dfa566112849991214329a233d");
+
+ b2n_clear (n);
+ b2n_clear (m);
+ b2n_clear (d);
+ b2n_clear (r);
+
+ printf ("\n");
+ return 1;
+}
diff --git a/sbin/isakmpd/regress/check.sh b/sbin/isakmpd/regress/check.sh
new file mode 100644
index 00000000000..f5d1d128cad
--- /dev/null
+++ b/sbin/isakmpd/regress/check.sh
@@ -0,0 +1,92 @@
+#!/bin/sh
+# $Id: check.sh,v 1.1 1998/11/15 00:03:49 niklas Exp $
+
+#
+# Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Niklas Hallqvist.
+# 4. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# This code was written under funding by Ericsson.
+#
+
+PROGNAME=$0
+NC=/usr/bin/nc
+HOST=localhost
+ISAKMP_PORT=500
+
+set -- `getopt p: $*`
+if [ $? != 0 ]; then
+ echo 'usage: $PROGNAME [-p port] host' >&2
+ exit 2
+fi
+for i; do
+ case "$i" in
+ -p)
+ ISAKMP_PORT=$2; shift; shift;;
+ --)
+ shift; break;;
+ esac
+done
+
+if [ $# -gt 0 ]; then
+ HOST=$1
+fi
+
+send () {
+ ${NC} -u -w 1 ${HOST} ${ISAKMP_PORT}
+}
+
+# Short message
+printf "SHORT!" |send
+
+# (Most probably) invalid cookie
+printf "INVALID COOKIES!\0\x10\0\0\0\0\0\0\0\0\0\x1c" |send
+
+# Invalid next payload type
+printf "01234567\0\0\0\0\0\0\0\0!\x10\0\0\0\0\0\0\0\0\0\x1c" |send
+
+# Invalid major version
+printf "01234567\0\0\0\0\0\0\0\0\0\x20\0\0\0\0\0\0\0\0\0\x1c" |send
+
+# Invalid minor version
+printf "01234567\0\0\0\0\0\0\0\0\0\x11\0\0\0\0\0\0\0\0\0\x1c" |send
+
+# Invalid exchange type
+printf "01234567\0\0\0\0\0\0\0\0\0\x10!\0\0\0\0\0\0\0\0\x1c" |send
+
+# Invalid flags
+printf "01234567\0\0\0\0\0\0\0\0\0\x10\2\x80\0\0\0\0\0\0\0\x1c" |send
+
+# Invalid message ID
+printf "01234567\0\0\0\0\0\0\0\0\0\x10\2\0BAD!\0\0\0\x1c" |send
+
+# Short length
+printf "01234567\0\0\0\0\0\0\0\0\0\x10\2\0\0\0\0\0\0\0\0\x1b" |send
+
+# Long length
+printf "01234567\0\0\0\0\0\0\0\0\0\x10\2\0\0\0\0\0\0\0\0\x1d" |send
diff --git a/sbin/isakmpd/regress/crypto/Makefile b/sbin/isakmpd/regress/crypto/Makefile
new file mode 100644
index 00000000000..26ed4656086
--- /dev/null
+++ b/sbin/isakmpd/regress/crypto/Makefile
@@ -0,0 +1,12 @@
+# Test Crypto:
+
+PROG= cryptotest
+SRCS= log.c crypto.c cryptotest.c
+.PATH: ${.CURDIR}/../../
+LDADD+= -ldes
+DPADD+= ${LIBDES}
+NOMAN=
+CFLAGS+= -I${.CURDIR}/../../ -Wall
+DEBUG= -g
+
+.include <bsd.prog.mk>
diff --git a/sbin/isakmpd/regress/crypto/cryptotest.c b/sbin/isakmpd/regress/crypto/cryptotest.c
new file mode 100644
index 00000000000..05aaa533912
--- /dev/null
+++ b/sbin/isakmpd/regress/crypto/cryptotest.c
@@ -0,0 +1,167 @@
+/* $Id: cryptotest.c,v 1.1 1998/11/15 00:03:50 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "crypto.h"
+
+void test_crypto (enum transform);
+
+#define SET_KEY(x,y) {int i; for (i=0; i < (y); i++) (x)[i] = i;}
+
+int
+verify_buf (u_int8_t *buf, u_int16_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ if (buf[i] != i)
+ return 0;
+
+ return 1;
+}
+
+#define nibble2bin(y) (tolower((y)) < 'a' ? (y) - '0': tolower((y)) - 'a' + 10)
+#define hexchar2bin(x) ((nibble2bin((x)[0]) << 4) + nibble2bin((x)[1]))
+#define nibble2c(x) ((x) >= 10 ? ('a'-10+(x)) : ('0' + (x)))
+
+void asc2bin (u_int8_t *bin, u_int8_t *asc, u_int16_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i += 2, asc += 2)
+ {
+ *bin++ = hexchar2bin(asc);
+ }
+}
+
+void
+special_test_blf (void)
+{
+ u_int8_t *akey = "0123456789ABCDEFF0E1D2C3B4A59687";
+ u_int8_t *aiv = "FEDCBA9876543210";
+ u_int8_t data[] = "7654321 Now is the time for \0\0\0"; /* len 29 */
+ u_int8_t *acipher = "6B77B4D63006DEE605B156E27403979358DEB9E7154616D959F1652BD5FF92CCE7";
+ u_int8_t key[16], cipher[32], iv[8];
+ struct crypto_xf *xf;
+ struct keystate *ks;
+ enum cryptoerr err;
+ int i;
+
+ asc2bin (key, akey, strlen (akey));
+ asc2bin (iv, aiv, strlen (aiv));
+ asc2bin (cipher, acipher, 64);
+
+ xf = crypto_get (BLOWFISH_CBC);
+ printf ("Special Test-Case %s: ", xf->name);
+
+ ks = crypto_init (xf, key, 16, &err);
+ if (!ks)
+ {
+ printf ("FAILED (init %d)", err);
+ goto fail;
+ }
+
+ crypto_init_iv (ks, iv, xf->blocksize);
+ crypto_encrypt (ks, data, 32);
+
+ for (i = 0; i < 32; i++)
+ if (data[i] != cipher[i])
+ break;
+ if (i < 32)
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+
+ free (ks);
+
+fail:
+ printf ("\n");
+ return;
+}
+
+int
+main (void)
+{
+ test_crypto (DES_CBC);
+
+ test_crypto (TRIPLEDES_CBC);
+
+ test_crypto (BLOWFISH_CBC);
+
+ test_crypto (CAST_CBC);
+
+ special_test_blf ();
+
+ return 1;
+}
+
+void
+test_crypto (enum transform which)
+{
+ u_int8_t buf[256];
+ struct crypto_xf *xf;
+ struct keystate *ks;
+ enum cryptoerr err;
+
+ xf = crypto_get (which);
+ printf ("Testing %s: ", xf->name);
+
+ SET_KEY (buf, xf->keymax);
+ ks = crypto_init (xf, buf, xf->keymax, &err);
+ if (!ks)
+ {
+ printf ("FAILED (init %d)", err);
+ goto fail;
+ }
+ SET_KEY (buf, sizeof (buf));
+ crypto_init_iv (ks, buf, xf->blocksize);
+ crypto_encrypt (ks, buf, sizeof (buf));
+ crypto_decrypt (ks, buf, sizeof (buf));
+ if (!verify_buf (buf, sizeof (buf)))
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+
+ free (ks);
+
+ fail:
+ printf ("\n");
+ return;
+}
diff --git a/sbin/isakmpd/regress/dh/Makefile b/sbin/isakmpd/regress/dh/Makefile
new file mode 100644
index 00000000000..39a873f4cdb
--- /dev/null
+++ b/sbin/isakmpd/regress/dh/Makefile
@@ -0,0 +1,14 @@
+# Test DH:
+
+PROG= dhtest
+SRCS= math_2n.c math_ec2n.c math_group.c dh.c dhtest.c util.c \
+ log.c sysdep.c gmp_util.c
+.PATH: ${.CURDIR}/../../
+NOMAN=
+LDADD+= -lgmp
+DPADD+= ${LIBGMP}
+TOPOBJ!= cd ${.CURDIR}/../..; printf "all:\n\t@pwd\n" |${MAKE} -f-
+CFLAGS+= -I${.CURDIR}/../../ -I${TOPOBJ} -Wall
+DEBUG= -g
+
+.include <bsd.prog.mk>
diff --git a/sbin/isakmpd/regress/dh/dhtest.c b/sbin/isakmpd/regress/dh/dhtest.c
new file mode 100644
index 00000000000..cd9361177f9
--- /dev/null
+++ b/sbin/isakmpd/regress/dh/dhtest.c
@@ -0,0 +1,106 @@
+/* $Id: dhtest.c,v 1.1 1998/11/15 00:03:50 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+/*
+ * This module does a Diffie-Hellman Exchange
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "math_group.h"
+#include "dh.h"
+
+#define DUMP_X(_x_) point = (_x_); b2n_print (point->x);
+
+int
+main (void)
+{
+ int len;
+ char buf[100], buf2[100];
+ char sec[100], sec2[100];
+ struct group *group, *group2;
+
+ group_init ();
+ group = group_get (4);
+ group2 = group_get (4);
+
+ printf ("Testing DH (elliptic curve): \n");
+
+ printf ("dh_getlen\n");
+ len = dh_getlen (group);
+ printf ("dh_create_exchange\n");
+ dh_create_exchange (group, buf);
+ dh_create_exchange (group2, buf2);
+
+ printf ("dh_create_shared\n");
+ dh_create_shared (group, sec, buf2);
+ dh_create_shared (group2, sec2, buf);
+
+ printf ("Result: ");
+ if (memcmp (sec, sec2, len))
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+
+ group_free (group);
+ group_free (group2);
+
+ printf ("\nTesting DH (MODP): \n");
+
+ group = group_get (1);
+ group2 = group_get (1);
+
+ printf ("dh_getlen\n");
+ len = dh_getlen (group);
+ printf ("dh_create_exchange\n");
+ dh_create_exchange (group, buf);
+ dh_create_exchange (group2, buf2);
+
+ printf ("dh_create_shared\n");
+ dh_create_shared (group, sec, buf2);
+ dh_create_shared (group2, sec2, buf);
+
+ printf ("Result: ");
+ if (memcmp (sec, sec2, len))
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+
+
+ printf ("\n");
+ return 1;
+}
diff --git a/sbin/isakmpd/regress/ec2n/Makefile b/sbin/isakmpd/regress/ec2n/Makefile
new file mode 100644
index 00000000000..9b51dd07aa5
--- /dev/null
+++ b/sbin/isakmpd/regress/ec2n/Makefile
@@ -0,0 +1,12 @@
+
+# Test EC2N:
+
+PROG= ec2ntest
+SRCS= math_2n.c math_ec2n.c ec2ntest.c util.c sysdep.c
+.PATH: ${.CURDIR}/../../
+NOMAN=
+TOPOBJ!= cd ${.CURDIR}/../..; printf "all:\n\t@pwd\n" |${MAKE} -f-
+CFLAGS+= -I${TOPOBJ} -I${.CURDIR}/../../ -Wall
+DEBUG= -g
+
+.include <bsd.prog.mk>
diff --git a/sbin/isakmpd/regress/ec2n/ec2ntest.c b/sbin/isakmpd/regress/ec2n/ec2ntest.c
new file mode 100644
index 00000000000..cbc5863f1f8
--- /dev/null
+++ b/sbin/isakmpd/regress/ec2n/ec2ntest.c
@@ -0,0 +1,146 @@
+/* $Id: ec2ntest.c,v 1.1 1998/11/15 00:03:50 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+/*
+ * B2N is a module for doing arithmetic on the Field GF(2**n) which is
+ * isomorph to ring of polynomials GF(2)[x]/p(x) where p(x) is an
+ * irreduciable polynomial over GF(2)[x] with grade n.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "math_2n.h"
+#include "math_ec2n.h"
+
+#define CMP_FAIL(n,x) b2n_sprint (buf, n); if (strcmp (buf, (x))) \
+ printf ("FAILED: %s != %s ", buf, x); else printf ("OKAY ");
+
+int
+main (void)
+{
+ b2n_t k;
+ ec2np_t p, q, r;
+ ec2ng_t g;
+ char buf[200];
+
+ b2n_init (k);
+ ec2np_init (p);
+ ec2np_init (q);
+ ec2np_init (r);
+ ec2ng_init (g);
+
+ printf ("Testing: ec2ng_set* :");
+ /* Init Group */
+ ec2ng_set_p_str (g, "0x0800000000000000000000004000000000000001");
+ CMP_FAIL (g->p, "0x0800000000000000000000004000000000000001");
+ ec2ng_set_a_ui (g, 0);
+ CMP_FAIL (g->a, "0x00");
+ ec2ng_set_b_str (g, "0x07338f");
+ CMP_FAIL (g->b, "0x07338f");
+
+ printf ("\nTesting: ec2np_find_y: ");
+ /* Init Point */
+ ec2np_set_x_ui (p, 0x7b);
+ ec2np_find_y (p, g);
+
+ CMP_FAIL (p->y, "0x01c8");
+
+ printf ("\nTesting: ec2np_ison: ");
+ if (ec2np_ison (p, g))
+ printf ("OKAY ");
+ else
+ printf ("FAILED ");
+
+ ec2np_set_x_ui (q, 0x4);
+ ec2np_find_y (q, g);
+ if (ec2np_ison (q, g))
+ printf ("OKAY ");
+ else
+ printf ("FAILED ");
+
+ printf ("\nTesting: ec2np_add: ");
+ ec2np_set (r, p);
+ b2n_add (r->y, r->y, r->x);
+ ec2np_add (r, r, p, g);
+ if (!r->inf)
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+
+ ec2np_add (q, p, q, g);
+ CMP_FAIL (q->x, "0x06f32d7cc82cec8612a87a86e026350fb7595469");
+ CMP_FAIL (q->y, "0x4ab92e21e51358ca8deab3fbbc9f7d8a7d1575");
+ if (ec2np_ison (q, g))
+ printf ("OKAY ");
+ else
+ printf ("FAILED ");
+
+ ec2np_add (p, q, q, g);
+ CMP_FAIL (p->x, "0x0390001461385559a22ac9b6181c1e1889b38451");
+ CMP_FAIL (p->y, "0x0188e61f38d747d7813c6a8b33d14dfb7418b04c");
+ if (ec2np_ison (p, g))
+ printf ("OKAY ");
+ else
+ printf ("FAILED ");
+
+ printf ("\nTesting: ec2np_mul: ");
+ b2n_set_ui (k, 57);
+ ec2np_set (q, p);
+ ec2np_mul (q, q, k, g);
+ if (ec2np_ison (q, g))
+ printf ("OKAY ");
+ else
+ printf ("FAILED ");
+ CMP_FAIL (q->x, "0x06bcf88caab88f99399350c46559da3b91afbf9d");
+
+ b2n_set_str (k, "0x0800000000000000000057db5698537193aef943");
+ ec2np_set (q, p);
+ ec2np_mul (q, q, k, g);
+ if (ec2np_ison (q, g))
+ printf ("OKAY ");
+ else
+ printf ("FAILED ");
+ CMP_FAIL (q->x, "0x0390001461385559a22ac9b6181c1e1889b38451");
+
+ printf ("\n");
+ ec2np_clear (p);
+ ec2np_clear (q);
+ ec2np_clear (r);
+ ec2ng_clear (g);
+ b2n_clear (k);
+ return 1;
+}
diff --git a/sbin/isakmpd/regress/exchange/Makefile b/sbin/isakmpd/regress/exchange/Makefile
new file mode 100644
index 00000000000..b2e08338197
--- /dev/null
+++ b/sbin/isakmpd/regress/exchange/Makefile
@@ -0,0 +1,58 @@
+# $Id: Makefile,v 1.1 1998/11/15 00:03:50 niklas Exp $
+
+#
+# Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Ericsson Radio Systems.
+# 4. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# This code was written under funding by Ericsson Radio Systems.
+#
+
+TOPOBJ!= cd ${.CURDIR}/../..; printf "all:\n\t@pwd\n" |${MAKE} -f-
+RUN= ISAKMPD=${TOPOBJ}/isakmpd ${.CURDIR}/run.sh
+
+TESTS= def
+
+all:
+
+test: ${TESTS:S/^/test-/}
+
+.for TEST in ${TESTS}
+test-${TEST}:
+.ifdef ONLY_INIT
+ @echo Testing "${TEST}" test as initiator
+ @${RUN} ${RUNFLAGS} ${.CURDIR}/${TEST}
+.endif
+.ifdef ONLY_RESP
+ @echo Testing "${TEST}" test as responder
+ @${RUN} -r ${RUNFLAGS} ${.CURDIR}/${TEST}
+.endif
+.endfor
+
+.include <bsd.obj.mk>
+.include <bsd.subdir.mk>
diff --git a/sbin/isakmpd/regress/exchange/def-i.1 b/sbin/isakmpd/regress/exchange/def-i.1
new file mode 100644
index 00000000000..17122493534
--- /dev/null
+++ b/sbin/isakmpd/regress/exchange/def-i.1
Binary files differ
diff --git a/sbin/isakmpd/regress/exchange/def-r.1 b/sbin/isakmpd/regress/exchange/def-r.1
new file mode 100644
index 00000000000..56f5e627c8e
--- /dev/null
+++ b/sbin/isakmpd/regress/exchange/def-r.1
Binary files differ
diff --git a/sbin/isakmpd/regress/exchange/run.sh b/sbin/isakmpd/regress/exchange/run.sh
new file mode 100644
index 00000000000..eb26c066c9d
--- /dev/null
+++ b/sbin/isakmpd/regress/exchange/run.sh
@@ -0,0 +1,141 @@
+#!/bin/sh
+# $Id: run.sh,v 1.1 1998/11/15 00:03:50 niklas Exp $
+
+#
+# Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Niklas Hallqvist.
+# 4. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# This code was written under funding by Ericsson.
+#
+
+# Defaults
+SRCPORT=1500
+DSTPORT=1501
+FIFO=test.fifo
+TIMEOUT=2
+
+NC=${NC:-/usr/bin/nc}
+ISAKMPD=${ISAKMPD:-/usr/sbin/isakmpd}
+
+progname=`basename $0`
+indent=`echo -n $progname |sed 's/./ /g'`
+seed=980801
+initiator=yes
+retval=0
+verbose=no
+clean=yes
+
+usage ()
+{
+ echo "usage: $progname [-nrv] [-d dst-port] [-f fifo] [-s src-port]" >&2
+ echo " $indent [-t timeout] testsuite" >&2
+ exit 2
+}
+
+set -- `getopt d:f:nrs:t:v $*`
+if [ $? != 0 ]; then
+ usage
+fi
+for i; do
+ case "$i" in
+ -d)
+ DSTPORT=$2; shift; shift;;
+ -f)
+ FIFO=$2; shift; shift;;
+ -n)
+ clean=no; shift;;
+ -r)
+ initiator=no; shift;;
+ -s)
+ SRCPORT=$2; shift; shift;;
+ -t)
+ TIMEOUT=$2; shift; shift;;
+ -v)
+ verbose=yes; shift;;
+ --)
+ shift; break;;
+ esac
+done
+
+if [ $# -eq 1 ]; then
+ suite=$1
+else
+ usage
+fi
+
+[ ${verbose} = yes ] && set -x
+
+# Start isakmpd and wait for the fifo to get created
+rm -f ${FIFO}
+${ISAKMPD} -d -p${SRCPORT} -f${FIFO} -r${seed} &
+isakmpd_pid=$!
+trap 'kill $isakmpd_pid; rm -f${FIFO}; [ $clean = yes ] && rm -f packet' 1 2 15
+while [ ! -p ${FIFO} ]; do
+ sleep 1
+done
+
+# Start the exchange
+if [ $initiator = yes ]; then
+ ${NC} -nul -w${TIMEOUT} -p${DSTPORT} 127.0.0.1 </dev/null >packet &
+# ${NC} -nu -w${TIMEOUT} -p${DSTPORT} 127.0.0.1 ${SRCPORT} </dev/null >packet
+ sleep 1
+ echo "c udp 127.0.0.1:${DSTPORT} 2 1" >${FIFO}
+ in_packets=`ls ${suite}-i.* 2>/dev/null`
+ out_packets=`ls ${suite}-r.* 2>/dev/null`
+else
+ in_packets=`ls ${suite}-r.* 2>/dev/null`
+ out_packets=`ls ${suite}-i.* 2>/dev/null`
+fi
+his_turn=$initiator
+while [ \( $his_turn = yes -a X"$in_packets" != X \) \
+ -o \( $his_turn = no -a X"$out_packets" != X \) ]; do
+ if [ $his_turn = no ]; then
+ set $out_packets
+ packet=$1
+ shift
+ out_packets=$*
+ cat $packet |${NC} -nu -w${TIMEOUT} -p${DSTPORT} 127.0.0.1 ${SRCPORT} \
+ >packet
+ my_turn=no
+ else
+ set $in_packets
+ packet=$1
+ shift
+ in_packets=$*
+ if ! cmp $packet packet 2>/dev/null; then
+ retval=1
+ break
+ fi
+ my_turn=yes
+ fi
+done
+kill $isakmpd_pid
+rm -f ${FIFO}
+[ $clean = yes ] && rm -f packet
+exit $retval
diff --git a/sbin/isakmpd/regress/group/Makefile b/sbin/isakmpd/regress/group/Makefile
new file mode 100644
index 00000000000..85ac9019fab
--- /dev/null
+++ b/sbin/isakmpd/regress/group/Makefile
@@ -0,0 +1,14 @@
+# Test Group:
+
+PROG= grouptest
+SRCS= math_2n.c math_ec2n.c math_group.c grouptest.c util.c \
+ log.c sysdep.c gmp_util.c
+.PATH: ${.CURDIR}/../../
+NOMAN=
+TOPOBJ!= cd ${.CURDIR}/../..; printf "all:\n\t@pwd\n" |${MAKE} -f-
+CFLAGS+= -I${TOPOBJ} -I${.CURDIR}/../../ -Wall
+LDADD+= -lgmp
+DPADD+= ${LIBGMP}
+DEBUG= -g
+
+.include <bsd.prog.mk>
diff --git a/sbin/isakmpd/regress/group/grouptest.c b/sbin/isakmpd/regress/group/grouptest.c
new file mode 100644
index 00000000000..7d4b16bb612
--- /dev/null
+++ b/sbin/isakmpd/regress/group/grouptest.c
@@ -0,0 +1,125 @@
+/* $Id: grouptest.c,v 1.1 1998/11/15 00:03:50 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+/*
+ * This module exercises the operations supplied by the group abstraction.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "math_2n.h"
+#include "math_ec2n.h"
+#include "math_group.h"
+
+#define DUMP_X(_x_) point = (_x_); b2n_print (point->x);
+
+int
+main (void)
+{
+ int i;
+ char buf[100];
+ char buf2[100];
+ struct group *group, *group2;
+ ec2np_ptr point;
+
+ group_init ();
+ group = group_get (3);
+ group2 = group_get (3);
+
+ printf ("Testing: setraw, getraw: ");
+ for (i = 0; i < 20; i++)
+ buf[i] = i;
+
+ group->setraw (group, group->c, buf, 20);
+ if (group->getlen (group) != 20)
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+
+ group->getraw (group, group->c, buf2);
+ for (i = 0; i < 20; i++)
+ if (buf2[i] != i)
+ break;
+ if (i < 20)
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+
+ printf ("\nTesting: setrandom: ");
+ group->setrandom (group, group->c);
+ DUMP_X (group->c);
+ group2->setrandom (group2, group2->c);
+ DUMP_X (group2->c);
+
+ printf ("\nTesting: operation:\n");
+ group->operation (group, group->a, group->gen, group->c);
+ point = group->a;
+ printf ("\tX (%d): ", point->x->chunks); b2n_print (point->x);
+ printf ("\tY (%d): ", point->y->chunks); b2n_print (point->y);
+
+ group2->operation (group2, group2->a, group2->gen, group2->c);
+ point = group2->a;
+ printf ("\tX (%d): ", point->x->chunks); b2n_print (point->x);
+ printf ("\tY (%d): ", point->y->chunks); b2n_print (point->y);
+
+ printf ("Exchange Value 1: "); b2n_print (group->d);
+ printf ("Exchange Value 2: "); b2n_print (group2->d);
+
+ printf ("Testing: operation ...:\n");
+ group->getraw (group, group->a, buf);
+ group2->setraw (group2, group2->b, buf, 20);
+
+ group2->getraw (group2, group2->a, buf);
+ group->setraw (group, group->b, buf, 20);
+
+ group2->operation (group2, group2->a, group2->b, group2->c);
+ printf ("Exchange Value 21: "); DUMP_X (group2->a);
+
+ group->operation (group, group->a, group->b, group->c);
+ printf ("Exchange Value 12: "); DUMP_X (group->a);
+
+ group->getraw (group, group->a, buf);
+ group2->getraw (group2, group2->a, buf2);
+ printf ("Testing: operation ...: ");
+ if (memcmp(buf, buf2, 20))
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+
+ printf ("\n");
+ return 1;
+}
diff --git a/sbin/isakmpd/regress/hmac/Makefile b/sbin/isakmpd/regress/hmac/Makefile
new file mode 100644
index 00000000000..009bd692d33
--- /dev/null
+++ b/sbin/isakmpd/regress/hmac/Makefile
@@ -0,0 +1,10 @@
+# Test HMAC:
+
+PROG= hmactest
+SRCS= hash.c hmactest.c
+.PATH: ${.CURDIR}/../../
+NOMAN=
+CFLAGS+= -I${.CURDIR}/../../ -Wall
+DEBUG= -g
+
+.include <bsd.prog.mk> \ No newline at end of file
diff --git a/sbin/isakmpd/regress/hmac/hmactest.c b/sbin/isakmpd/regress/hmac/hmactest.c
new file mode 100644
index 00000000000..487f5a61c3d
--- /dev/null
+++ b/sbin/isakmpd/regress/hmac/hmactest.c
@@ -0,0 +1,97 @@
+/* $Id: hmactest.c,v 1.1 1998/11/15 00:03:50 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "hash.h"
+
+int test_hmac(char *, struct hash *, char *, int, char *, int, char *);
+
+#define nibble2c(x) ((x) >= 10 ? ('a'-10+(x)) : ('0' + (x)))
+
+int
+main (void)
+{
+ char key[100];
+
+ memset(key, 11, 20);
+ test_hmac ("HMAC-MD5 Test Case 1", hash_get (HASH_MD5),
+ key, 16, "Hi There", 8, "9294727a3638bb1c13f48ef8158bfc9d");
+ test_hmac ("HMAC-MD5 Test Case 2", hash_get (HASH_MD5),
+ "Jefe", 4,
+ "what do ya want for nothing?", 28,
+ "750c783e6ab0b503eaa86e310a5db738");
+ test_hmac ("HMAC-SHA1 Test Case 1", hash_get (HASH_SHA1),
+ key, 20, "Hi There", 8,
+ "b617318655057264e28bc0b6fb378c8ef146be00");
+ test_hmac ("HMAC-SHA1 Test Case 2", hash_get (HASH_SHA1),
+ "Jefe", 4, "what do ya want for nothing?", 28,
+ "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79");
+
+ return 1;
+}
+
+int
+test_hmac(char *test, struct hash *hash, char *key, int klen,
+ char *data, int dlen, char *cmp)
+{
+ char output[2*HASH_MAX+1];
+ int i;
+
+ printf("Testing %s: ", test);
+
+ hash->HMACInit(hash, key, klen);
+ hash->Update(hash->ctx, data, dlen);
+ hash->HMACFinal(hash->digest, hash);
+
+ for (i=0; i<hash->hashsize; i++)
+ {
+ output[2*i] = nibble2c((hash->digest[i] >> 4) & 0xf);
+ output[2*i+1] = nibble2c(hash->digest[i] & 0xf);
+ }
+ output[2*i] = 0;
+
+ if (!strcmp(output, cmp))
+ {
+ printf("OKAY\n");
+ return 1;
+ }
+
+ printf("%s <-> %s\n", output, cmp);
+ return 0;
+}
diff --git a/sbin/isakmpd/regress/pkcs/Makefile b/sbin/isakmpd/regress/pkcs/Makefile
new file mode 100644
index 00000000000..05a9566ca77
--- /dev/null
+++ b/sbin/isakmpd/regress/pkcs/Makefile
@@ -0,0 +1,13 @@
+# Test PKCS#1
+
+PROG= pkcstest
+SRCS= log.c asn.c gmp_util.c pkcs.c pkcstest.c sysdep.c \
+ asn_useful.c hash.c
+.PATH: ${.CURDIR}/../../
+LDADD+= -lgmp
+DPADD+= ${LIBDES}
+NOMAN=
+CFLAGS+= -I${.CURDIR}/../../ -Wall
+DEBUG= -g
+
+.include <bsd.prog.mk>
diff --git a/sbin/isakmpd/regress/pkcs/pkcstest.c b/sbin/isakmpd/regress/pkcs/pkcstest.c
new file mode 100644
index 00000000000..1e1f520c6b4
--- /dev/null
+++ b/sbin/isakmpd/regress/pkcs/pkcstest.c
@@ -0,0 +1,124 @@
+/* $Id: pkcstest.c,v 1.1 1998/11/15 00:03:50 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <gmp.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp_util.h"
+#include "asn.h"
+#include "pkcs.h"
+
+#define nibble2bin(y) (tolower((y)) < 'a' ? (y) - '0': tolower((y)) - 'a' + 10)
+#define hexchar2bin(x) ((nibble2bin((x)[0]) << 4) + nibble2bin((x)[1]))
+#define nibble2c(x) ((x) >= 10 ? ('a'-10+(x)) : ('0' + (x)))
+
+void asc2bin (u_int8_t *bin, u_int8_t *asc, u_int16_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i += 2, asc += 2)
+ {
+ *bin++ = hexchar2bin(asc);
+ }
+}
+
+int
+main (void)
+{
+ char buf[500];
+ char *publickey = "304702400a66791dc6988168de7ab77419bb7fb0c001c6271027"
+ "0075142942e19a8d8c51d053b3e3782a1de5dc5af4ebe99468170114a1dfe67cdc9a9"
+ "af55d655620bbab0203010001";
+ char *privatekey = "3082013602010002400a66791dc6988168de7ab77419bb7fb0c001"
+ "c62710270075142942e19a8d8c51d053b3e3782a1de5dc5af4ebe99468170114a1dfe67"
+ "cdc9a9af55d655620bbab020301000102400123c5b61ba36edb1d3679904199a89ea80c"
+ "09b9122e1400c09adcf7784676d01d23356a7d44d6bd8bd50e94bfc723fa87d8862b751"
+ "77691c11d757692df8881022033d48445c859e52340de704bcdda065fbb4058d740bd1d"
+ "67d29e9c146c11cf610220335e8408866b0fd38dc7002d3f972c67389a65d5d8306566d"
+ "5c4f2a5aa52628b0220045ec90071525325d3d46db79695e9afacc4523964360e02b119"
+ "baa366316241022015eb327360c7b60d12e5e2d16bdcd97981d17fba6b70db13b20b436"
+ "e24eada5902202ca6366d72781dfa24d34a9a24cbc2ae927a9958af426563ff63fb1165"
+ "8a461d";
+ char *data = "Niels ist ein Luser!";
+ u_int8_t *enc, *dec;
+ u_int16_t len;
+ u_int32_t enclen;
+ int erg = 0;
+
+ struct rsa_public_key key;
+ struct rsa_private_key priv;
+
+ asc2bin (buf, publickey, strlen (publickey));
+ pkcs_public_key_from_asn (&key, buf, sizeof (buf));
+
+ printf ("n: 0x"); mpz_out_str (stdout, 16, key.n);
+ printf ("\ne: 0x"); mpz_out_str (stdout, 16, key.e);
+ printf ("\n");
+
+ asc2bin (buf, privatekey, strlen (privatekey));
+ pkcs_private_key_from_asn (&priv, buf, sizeof (buf));
+
+ printf ("n: 0x"); mpz_out_str (stdout, 16, priv.n);
+ printf ("\ne: 0x"); mpz_out_str (stdout, 16, priv.e);
+ printf ("\nd: 0x"); mpz_out_str (stdout, 16, priv.d);
+ printf ("\np: 0x"); mpz_out_str (stdout, 16, priv.p);
+ printf ("\nq: 0x"); mpz_out_str (stdout, 16, priv.q);
+ printf ("\n");
+
+ printf ("Testing Signing/Verifying: ");
+ /* Sign with Private Key */
+ if (!pkcs_rsa_encrypt (PKCS_PRIVATE, priv.n, priv.d, data, strlen(data)+1,
+ &enc, &enclen))
+ printf ("FAILED ");
+ else
+ /* Decrypt/Verify with Public Key */
+ erg = pkcs_rsa_decrypt (PKCS_PRIVATE, key.n, key.e, enc, &dec, &len);
+
+ if (!erg || strcmp(data,dec))
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+
+ printf ("\n");
+
+ pkcs_free_public_key (&key);
+ pkcs_free_private_key (&priv);
+
+ return 1;
+}
diff --git a/sbin/isakmpd/regress/prf/Makefile b/sbin/isakmpd/regress/prf/Makefile
new file mode 100644
index 00000000000..7d58f825d23
--- /dev/null
+++ b/sbin/isakmpd/regress/prf/Makefile
@@ -0,0 +1,10 @@
+# Test HMAC:
+
+PROG= prftest
+SRCS= log.c prf.c hash.c prftest.c
+.PATH: ${.CURDIR}/../../
+NOMAN=
+CFLAGS+= -I${.CURDIR}/../../ -Wall
+DEBUG= -g
+
+.include <bsd.prog.mk>
diff --git a/sbin/isakmpd/regress/prf/prftest.c b/sbin/isakmpd/regress/prf/prftest.c
new file mode 100644
index 00000000000..1ba253865aa
--- /dev/null
+++ b/sbin/isakmpd/regress/prf/prftest.c
@@ -0,0 +1,115 @@
+/* $Id: prftest.c,v 1.1 1998/11/15 00:03:50 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "hash.h"
+#include "prf.h"
+
+int test_prf(char *, enum hashes, char *, int, char *, int, char *);
+
+#define nibble2c(x) ((x) >= 10 ? ('a'-10+(x)) : ('0' + (x)))
+
+/*
+ * Basically the same as the HMAC regress, but to keep with modularity
+ * prf seems to be useful. So here we just check the HMAC test cases,
+ * until there are more PRFs.
+ */
+
+int
+main (void)
+{
+ char key[100];
+
+ memset(key, 11, 20);
+ test_prf ("PRF MD5 Test Case 1", HASH_MD5,
+ key, 16, "Hi There", 8, "9294727a3638bb1c13f48ef8158bfc9d");
+ test_prf ("PRF MD5 Test Case 2", HASH_MD5,
+ "Jefe", 4,
+ "what do ya want for nothing?", 28,
+ "750c783e6ab0b503eaa86e310a5db738");
+ test_prf ("PRF SHA1 Test Case 1", HASH_SHA1,
+ key, 20, "Hi There", 8,
+ "b617318655057264e28bc0b6fb378c8ef146be00");
+ test_prf ("PRF SHA1 Test Case 2", HASH_SHA1,
+ "Jefe", 4, "what do ya want for nothing?", 28,
+ "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79");
+
+ return 1;
+}
+
+int
+test_prf(char *test, enum hashes hash, char *key, int klen,
+ char *data, int dlen, char *cmp)
+{
+ char output[2*HASH_MAX+1];
+ char digest[HASH_MAX];
+ struct prf *prf;
+ int i;
+
+ printf("Testing %s: ", test);
+
+ prf = prf_alloc(PRF_HMAC, hash, key, klen);
+ if (prf == NULL)
+ {
+ printf("prf_alloc() returned NULL\n");
+ return 0;
+ }
+
+ prf->Init(prf->prfctx);
+ prf->Update(prf->prfctx, data, dlen);
+ prf->Final(digest, prf->prfctx);
+
+ prf_free(prf);
+
+ for (i=0; i<prf->blocksize; i++)
+ {
+ output[2*i] = nibble2c((digest[i] >> 4) & 0xf);
+ output[2*i+1] = nibble2c(digest[i] & 0xf);
+ }
+ output[2*i] = 0;
+
+ if (!strcmp(output, cmp))
+ {
+ printf("OKAY\n");
+ return 1;
+ }
+
+ printf("%s <-> %s\n", output, cmp);
+ return 0;
+}
diff --git a/sbin/isakmpd/regress/rsakeygen/Makefile b/sbin/isakmpd/regress/rsakeygen/Makefile
new file mode 100644
index 00000000000..95db8b1c9a6
--- /dev/null
+++ b/sbin/isakmpd/regress/rsakeygen/Makefile
@@ -0,0 +1,12 @@
+# RSA Key Generation
+
+PROG= rsakeygen
+SRCS= log.c asn.c gmp_util.c pkcs.c rsakeygen.c sysdep.c
+.PATH: ${.CURDIR}/../../
+LDADD+= -lgmp
+DPADD+= ${LIBDES}
+NOMAN=
+CFLAGS+= -I${.CURDIR}/../../ -Wall
+DEBUG= -g
+
+.include <bsd.prog.mk>
diff --git a/sbin/isakmpd/regress/rsakeygen/rsakeygen.c b/sbin/isakmpd/regress/rsakeygen/rsakeygen.c
new file mode 100644
index 00000000000..665a5c25fe2
--- /dev/null
+++ b/sbin/isakmpd/regress/rsakeygen/rsakeygen.c
@@ -0,0 +1,121 @@
+/* $Id: rsakeygen.c,v 1.1 1998/11/15 00:03:50 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <gmp.h>
+
+#include "log.h"
+#include "gmp_util.h"
+#include "asn.h"
+#include "pkcs.h"
+
+#define nibble2bin(y) (tolower((y)) < 'a' ? (y) - '0': tolower((y)) - 'a' + 10)
+#define hexchar2bin(x) ((nibble2bin((x)[0]) << 4) + nibble2bin((x)[1]))
+#define nibble2c(x) ((x) >= 10 ? ('a'-10+(x)) : ('0' + (x)))
+
+void asc2bin (u_int8_t *bin, u_int8_t *asc, u_int16_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i += 2, asc += 2)
+ {
+ *bin++ = hexchar2bin(asc);
+ }
+}
+
+int
+main (void)
+{
+ char *data = "Niels ist ein Luser!";
+ u_int8_t *enc, *dec, *asn;
+ u_int32_t enclen;
+ u_int16_t len;
+ FILE *fd;
+ int erg = 0;
+
+ struct rsa_public_key key;
+ struct rsa_private_key priv;
+
+ log_debug_cmd ((enum log_classes)LOG_CRYPTO, 99);
+ pkcs_generate_rsa_keypair (&key, &priv, 1024);
+
+ printf ("n: 0x"); mpz_out_str (stdout, 16, key.n);
+ printf ("\ne: 0x"); mpz_out_str (stdout, 16, key.e);
+ printf ("\n");
+
+ printf ("n: 0x"); mpz_out_str (stdout, 16, priv.n);
+ printf ("\ne: 0x"); mpz_out_str (stdout, 16, priv.e);
+ printf ("\nd: 0x"); mpz_out_str (stdout, 16, priv.d);
+ printf ("\np: 0x"); mpz_out_str (stdout, 16, priv.p);
+ printf ("\nq: 0x"); mpz_out_str (stdout, 16, priv.q);
+ printf ("\n");
+
+ printf ("Testing Signing/Verifying: ");
+ /* Sign with Private Key */
+ if (!pkcs_rsa_encrypt (PKCS_PRIVATE, priv.n, priv.d, data, strlen(data)+1,
+ &enc, &enclen))
+ printf ("FAILED ");
+ else
+ /* Decrypt/Verify with Public Key */
+ erg = pkcs_rsa_decrypt (PKCS_PRIVATE, key.n, key.e, enc, &dec, &len);
+
+ if (!erg || strcmp(data,dec))
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+
+ printf ("\n");
+
+ asn = pkcs_public_key_to_asn (&key);
+ fd = fopen ("isakmpd_key.pub", "w");
+ fwrite (asn, asn_get_len (asn), 1, fd);
+ fclose (fd);
+ free (asn);
+
+ asn = pkcs_private_key_to_asn (&priv);
+ fd = fopen ("isakmpd_key", "w");
+ fwrite (asn, asn_get_len (asn), 1, fd);
+ fclose (fd);
+ free (asn);
+
+ pkcs_free_public_key (&key);
+ pkcs_free_private_key (&priv);
+
+ return 1;
+}
diff --git a/sbin/isakmpd/regress/x509/Makefile b/sbin/isakmpd/regress/x509/Makefile
new file mode 100644
index 00000000000..3a7bdc0a7b3
--- /dev/null
+++ b/sbin/isakmpd/regress/x509/Makefile
@@ -0,0 +1,14 @@
+# Test X509
+
+PROG= x509test
+SRCS= x509test.c conf.c asn.c asn_useful.c gmp_util.c log.c pkcs.c \
+ sysdep.c hash.c x509.c
+TOPOBJ!= cd ${.CURDIR}/../..; printf "all:\n\t@pwd\n" |${MAKE} -f-
+.PATH: ${.CURDIR}/../.. ${TOPOBJ}
+LDADD+= -lgmp
+DPADD+= ${LIBDES}
+NOMAN=
+CFLAGS+= -I${.CURDIR}/../.. -I${TOPOBJ} -Wall
+DEBUG= -g
+
+.include <bsd.prog.mk>
diff --git a/sbin/isakmpd/regress/x509/certificate.txt b/sbin/isakmpd/regress/x509/certificate.txt
new file mode 100644
index 00000000000..5ebe7b81482
--- /dev/null
+++ b/sbin/isakmpd/regress/x509/certificate.txt
@@ -0,0 +1,8 @@
+version: 2
+serialnumber: 0
+issuer1: SE
+issuer2: We, our grandmother and God himself
+subject1: SE
+subject2: We, our grandmother and God himself
+start: 980101000000Z
+end: 990101000000Z
diff --git a/sbin/isakmpd/regress/x509/x509test.c b/sbin/isakmpd/regress/x509/x509test.c
new file mode 100644
index 00000000000..f481029adf4
--- /dev/null
+++ b/sbin/isakmpd/regress/x509/x509test.c
@@ -0,0 +1,165 @@
+/* $Id: x509test.c,v 1.1 1998/11/15 00:03:50 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <gmp.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "conf.h"
+#include "asn.h"
+#include "asn_useful.h"
+#include "pkcs.h"
+#include "x509.h"
+#include "log.h"
+
+u_int32_t file_sz;
+
+#define LINECOL(x,y) (x) = strsep (&(y), "\n\r"); \
+ (x) = strchr ((x), ':') + 1; \
+ while (isspace((x)[0])) (x)++; \
+
+
+u_int8_t *
+open_file (char *name)
+{
+ int fd;
+ struct stat st;
+ u_int8_t *addr;
+
+ if (stat (name, &st) == -1)
+ log_fatal ("stat (\"%s\", &st)", name);
+ file_sz = st.st_size;
+ fd = open (name, O_RDONLY);
+ if (fd == -1)
+ log_fatal ("open (\"%s\", O_RDONLY)", name);
+ addr = mmap (0, file_sz, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE,
+ fd, 0);
+ if (!addr)
+ log_fatal ("mmap (0, %d, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE,"
+ "%d, 0)", file_sz, fd);
+ close (fd);
+
+ return addr;
+}
+
+int
+main (void)
+{
+ struct rsa_private_key priv;
+ struct x509_certificate cert;
+ FILE *fd;
+ char *p, *p2;
+ u_int8_t *addr, *asn;
+ u_int32_t asnlen, len;
+
+ addr = open_file ("isakmpd_key");
+ if (!pkcs_private_key_from_asn (&priv, addr, asn_get_len (addr)))
+ {
+ munmap (addr, file_sz);
+ exit (1);
+ }
+ munmap (addr, file_sz);
+
+ addr = open_file ("isakmpd_key.pub");
+ if (!pkcs_public_key_from_asn (&cert.key, addr, asn_get_len (addr)))
+ {
+ munmap (addr, file_sz);
+ exit (1);
+ }
+ munmap (addr, file_sz);
+
+ cert.signaturetype = strdup (ASN_ID_MD5WITHRSAENC);
+ cert.issuer1.type = strdup (ASN_ID_COUNTRY_NAME);
+ cert.issuer2.type = strdup (ASN_ID_ORGANIZATION_NAME);
+ cert.subject1.type = strdup (ASN_ID_COUNTRY_NAME);
+ cert.subject2.type = strdup (ASN_ID_ORGANIZATION_NAME);
+
+ addr = open_file ("certificate.txt");
+ p = addr;
+
+ LINECOL (p2, p); cert.version = atoi (p2);
+ LINECOL (p2, p); cert.serialnumber = atoi (p2);
+ LINECOL (p2, p); cert.issuer1.val = strdup (p2);
+ LINECOL (p2, p); cert.issuer2.val = strdup (p2);
+ LINECOL (p2, p); cert.subject1.val = strdup (p2);
+ LINECOL (p2, p); cert.subject2.val = strdup (p2);
+ LINECOL (p2, p); cert.start = strdup (p2);
+ LINECOL (p2, p); cert.end = strdup (p2);
+ munmap (addr, file_sz);
+
+ /* XXX - just put any IP number in there - XXX */
+ cert.extension.type = strdup (ASN_ID_SUBJECT_ALT_NAME);
+ cert.extension.val = p = malloc (8);
+ /* XXX - this could also be encoded as norm_type, but time is lacking */
+ p[0] = 0x30; p[1] = 0x06; p[2] = 0x87; p[3] = 0x04;
+ memset (p + 4, 0, 4);
+
+ printf ("Encoding Certificiate: ");
+ if (!x509_encode_certificate(&cert, &asn, &asnlen))
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+ printf ("\n");
+
+ printf ("Creating Signature: ");
+ if (!x509_create_signed (asn, asnlen, &priv, &addr, &len))
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+ printf ("\n");
+
+ printf ("Validate SIGNED: ");
+ if (!x509_validate_signed (addr, len, &cert.key, &asn, &asnlen))
+ printf ("FAILED ");
+ else
+ printf ("OKAY ");
+ printf ("\n");
+
+ fd = fopen ("cert.asn", "w");
+ fwrite (addr, len, 1, fd);
+ fclose (fd);
+
+ free (addr);
+
+ return 1;
+}
diff --git a/sbin/isakmpd/sa.c b/sbin/isakmpd/sa.c
new file mode 100644
index 00000000000..60e9b9b9770
--- /dev/null
+++ b/sbin/isakmpd/sa.c
@@ -0,0 +1,456 @@
+/* $Id: sa.c,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cookie.h"
+#include "doi.h"
+#include "exchange.h"
+#include "isakmp.h"
+#include "log.h"
+#include "message.h"
+#include "sa.h"
+#include "timer.h"
+#include "transport.h"
+#include "util.h"
+
+/* Initial number of bits from the cookies used as hash. */
+#define INITIAL_BUCKET_BITS 6
+
+/*
+ * Don't try to use more bits than this as a hash.
+ * We only XOR 16 bits so going above that means changing the code below
+ * too.
+ */
+#define MAX_BUCKET_BITS 16
+
+static void sa_dump (char *, struct sa *);
+
+static LIST_HEAD (sa_list, sa) *sa_tab;
+
+/* Works both as a maximum index and a mask. */
+static int bucket_mask;
+
+void
+sa_init ()
+{
+ int i;
+
+ bucket_mask = (1 << INITIAL_BUCKET_BITS) - 1;
+ sa_tab = malloc ((bucket_mask + 1) * sizeof (struct sa_list));
+ if (!sa_tab)
+ log_fatal ("init_sa: out of memory");
+ for (i = 0; i <= bucket_mask; i++)
+ {
+ LIST_INIT (&sa_tab[i]);
+ }
+
+}
+
+/* XXX Ww don't yet resize. */
+void
+sa_resize ()
+{
+ int new_mask = (bucket_mask + 1) * 2 - 1;
+ int i;
+ struct sa_list *new_tab;
+
+ new_tab = realloc (sa_tab, (new_mask + 1) * sizeof (struct sa_list));
+ if (!new_tab)
+ return;
+ sa_tab = new_tab;
+ for (i = bucket_mask + 1; i <= new_mask; i++)
+ {
+ LIST_INIT (&sa_tab[i]);
+ }
+ bucket_mask = new_mask;
+
+ /* XXX Rehash existing entries. */
+}
+
+/* Lookup an ISAKMP SA out of just the initiator cookie. */
+struct sa *
+sa_lookup_from_icookie (u_int8_t *cookie)
+{
+ int i;
+ struct sa *sa;
+
+ for (i = 0; i < bucket_mask; i++)
+ for (sa = LIST_FIRST (&sa_tab[i]); sa; sa = LIST_NEXT (sa, link))
+ if (memcmp (sa->cookies, cookie, ISAKMP_HDR_ICOOKIE_LEN) == 0
+ && sa->phase == 1)
+ return sa;
+ return 0;
+}
+
+int
+sa_enter (struct sa *sa)
+{
+ u_int16_t bucket = 0;
+ int i;
+ u_int8_t *cp;
+
+ /* XXX We might resize if we are crossing a certain threshold */
+
+ for (i = 0; i < ISAKMP_HDR_COOKIES_LEN; i += 2)
+ {
+ cp = sa->cookies + i;
+ /* Doing it this way avoids alignment problems. */
+ bucket ^= cp[0] | cp[1] << 8;
+ }
+ for (i = 0; i < ISAKMP_HDR_MESSAGE_ID_LEN; i += 2)
+ {
+ cp = sa->message_id + i;
+ /* Doing it this way avoids alignment problems. */
+ bucket ^= cp[0] | cp[1] << 8;
+ }
+ bucket &= bucket_mask;
+ LIST_INSERT_HEAD (&sa_tab[bucket], sa, link);
+ return 1;
+}
+
+/*
+ * Lookup the SA given by the header fields MSG. PHASE2 is false when
+ * looking for phase 1 SAa and true otherwise.
+ */
+struct sa *
+sa_lookup_by_header (u_int8_t *msg, int phase2)
+{
+ return sa_lookup (msg + ISAKMP_HDR_COOKIES_OFF,
+ phase2 ? msg + ISAKMP_HDR_MESSAGE_ID_OFF : 0);
+}
+
+/*
+ * Lookup the SA given by the COOKIES and possibly the MESSAGE_ID unless
+ * NULL, meaning we are looking for phase 1 SAs.
+ */
+struct sa *
+sa_lookup (u_int8_t *cookies, u_int8_t *message_id)
+{
+ u_int16_t bucket = 0;
+ int i;
+ struct sa *sa;
+ u_int8_t *cp;
+
+ /*
+ * We use the cookies to get bits to use as an index into sa_tab, as at
+ * least one (our cookie) is a good hash, xoring all the bits, 16 at a
+ * time, and then masking, should do. Doing it this way means we can
+ * validate cookies very fast thus delimiting the effects of "Denial of
+ * service"-attacks using packet flooding.
+ */
+ for (i = 0; i < ISAKMP_HDR_COOKIES_LEN; i += 2)
+ {
+ cp = cookies + i;
+ /* Doing it this way avoids alignment problems. */
+ bucket ^= cp[0] | cp[1] << 8;
+ }
+ if (message_id)
+ for (i = 0; i < ISAKMP_HDR_MESSAGE_ID_LEN; i += 2)
+ {
+ cp = message_id + i;
+ /* Doing it this way avoids alignment problems. */
+ bucket ^= cp[0] | cp[1] << 8;
+ }
+ bucket &= bucket_mask;
+ for (sa = LIST_FIRST (&sa_tab[bucket]);
+ sa && (memcmp (cookies, sa->cookies, ISAKMP_HDR_COOKIES_LEN) != 0
+ || (message_id && memcmp (message_id, sa->message_id,
+ ISAKMP_HDR_MESSAGE_ID_LEN)
+ != 0));
+ sa = LIST_NEXT (sa, link))
+ ;
+
+ return sa;
+}
+
+/* Create a SA. */
+int
+sa_create (struct exchange *exchange, struct transport *t)
+{
+ struct sa *sa;
+
+ /*
+ * We want the SA zeroed for sa_free to be able to find out what fields
+ * have been filled-in.
+ */
+ sa = calloc (1, sizeof *sa);
+ if (!sa)
+ return -1;
+ sa->transport = t;
+ sa->phase = exchange->phase;
+ memcpy (sa->cookies, exchange->cookies, ISAKMP_HDR_COOKIES_LEN);
+ memcpy (sa->message_id, exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN);
+ sa->doi = exchange->doi;
+
+ /* Allocate the DOI-specific structure and initialize it to zeroes. */
+ sa->data = calloc (1, sa->doi->sa_size);
+ if (!sa->data)
+ {
+ free (sa);
+ return 0;
+ }
+
+ TAILQ_INIT (&sa->protos);
+
+ sa_enter (sa);
+ TAILQ_INSERT_TAIL (&exchange->sa_list, sa, next);
+ return 0;
+}
+
+static void
+sa_dump (char *header, struct sa *sa)
+{
+ struct proto *proto;
+ char spi_header[80];
+ int i;
+
+ log_debug (LOG_MISC, 10, "%s: phase %d doi %d msgid %08x flags 0x%x",
+ header, sa->phase, sa->doi->id, decode_32 (sa->message_id),
+ sa->flags);
+ log_debug (LOG_MISC, 10,
+ "%s: icookie %08x%08x rcookie %08x%08x", header,
+ decode_32 (sa->cookies), decode_32 (sa->cookies + 4),
+ decode_32 (sa->cookies + 8), decode_32 (sa->cookies + 12));
+ for (proto = TAILQ_FIRST (&sa->protos); proto;
+ proto = TAILQ_NEXT (proto, link))
+ {
+ log_debug (LOG_MISC, 10,
+ "%s: suite %d proto %d "
+ "spi_sz[0] %d spi[0] %p spi_sz[1] %d spi[1] %p",
+ header, proto->no, proto->proto, proto->spi_sz[0],
+ proto->spi[0], proto->spi_sz[1], proto->spi[1]);
+ for (i = 0; i < 2; i++)
+ if (proto->spi[i])
+ {
+ snprintf (spi_header, 80, "%s: spi[%d]", header, i);
+ log_debug_buf (LOG_MISC, 10, spi_header, proto->spi[i],
+ proto->spi_sz[i]);
+ }
+ }
+}
+
+void
+sa_report (void)
+{
+ int i;
+ struct sa *sa;
+
+ for (i = 0; i < bucket_mask; i++)
+ for (sa = LIST_FIRST (&sa_tab[i]); sa; sa = LIST_NEXT (sa, link))
+ sa_dump ("sa_report", sa);
+}
+
+void
+proto_free (struct proto *proto)
+{
+ int i;
+ struct sa *sa = proto->sa;
+
+ for (i = 0; i < 2; i++)
+ if (proto->spi[i])
+ {
+ if (sa->doi->delete_spi)
+ sa->doi->delete_spi (sa, proto, i);
+ free (proto->spi[i]);
+ }
+ TAILQ_REMOVE (&sa->protos, proto, link);
+ if (proto->data)
+ {
+ if (sa->doi && sa->doi->free_proto_data)
+ sa->doi->free_proto_data (proto->data);
+ free (proto->data);
+ }
+ free (proto);
+}
+
+/* Release all resources this SA is using. */
+void
+sa_free (struct sa *sa)
+{
+ if (sa->death)
+ timer_remove_event (sa->death);
+ sa_free_aux (sa);
+}
+
+/* Release all resources this SA is using except the death timer. */
+void
+sa_free_aux (struct sa *sa)
+{
+ struct proto *proto;
+
+ if (sa->data)
+ {
+ if (sa->doi && sa->doi->free_sa_data)
+ sa->doi->free_sa_data (sa->data);
+ free (sa->data);
+ }
+ if (sa->last_sent_in_setup)
+ message_free (sa->last_sent_in_setup);
+ while ((proto = TAILQ_FIRST (&sa->protos)) != 0)
+ proto_free (proto);
+ LIST_REMOVE (sa, link);
+ free (sa);
+}
+
+/*
+ * Rehash the ISAKMP SA this MSG is negotiating with the responder cookie
+ * filled in.
+ */
+void
+sa_isakmp_upgrade (struct message *msg)
+{
+ struct sa *sa = TAILQ_FIRST (&msg->exchange->sa_list);
+
+ LIST_REMOVE (sa, link);
+ GET_ISAKMP_HDR_RCOOKIE (msg->iov[0].iov_base,
+ sa->cookies + ISAKMP_HDR_ICOOKIE_LEN);
+ /*
+ * We don't install a transport in the initiator case as we don't know
+ * what local address will be chosen. Do it now instead.
+ */
+ sa->transport = msg->transport;
+ sa_enter (sa);
+}
+
+/*
+ * Register the chosen transform into the SA. As a side effect set PROTOP
+ * to point at the corresponding proto structure.
+ */
+int
+sa_add_transform (struct sa *sa, struct payload *xf, int initiator,
+ struct proto **protop)
+{
+ struct proto *proto;
+ struct payload *prop = xf->context;
+
+ *protop = 0;
+ if (!initiator)
+ proto = calloc (1, sizeof *proto);
+ else
+ /* Find the protection suite that were chosen. */
+ for (proto = TAILQ_FIRST (&sa->protos);
+ proto && proto->no != GET_ISAKMP_PROP_NO (prop->p);
+ proto = TAILQ_NEXT (proto, link))
+ ;
+ if (!proto)
+ return -1;
+ *protop = proto;
+
+ /* Allocate DOI-specific part. */
+ if (!initiator)
+ {
+ proto->data = calloc (1, sa->doi->proto_size);
+ if (!proto->data)
+ goto cleanup;
+ }
+
+ proto->no = GET_ISAKMP_PROP_NO (prop->p);
+ proto->proto = GET_ISAKMP_PROP_PROTO (prop->p);
+ proto->spi_sz[!initiator] = GET_ISAKMP_PROP_SPI_SZ (prop->p);
+ if (proto->spi_sz[!initiator])
+ {
+ proto->spi[!initiator] = malloc (proto->spi_sz[!initiator]);
+ if (!proto->spi[!initiator])
+ goto cleanup;
+ memcpy (proto->spi[!initiator], prop->p + ISAKMP_PROP_SPI_OFF,
+ proto->spi_sz[!initiator]);
+ }
+ proto->chosen = xf;
+ proto->sa = sa;
+ proto->id = GET_ISAKMP_TRANSFORM_ID (xf->p);
+ if (!initiator)
+ TAILQ_INSERT_TAIL (&sa->protos, proto, link);
+ return 0;
+
+ cleanup:
+ if (!initiator)
+ {
+ if (proto->data)
+ free (proto->data);
+ free (proto);
+ }
+ *protop = 0;
+ return -1;
+}
+
+/* Lookup an ISAKMP SA given its peer address. */
+struct sa *
+sa_isakmp_lookup_by_peer (struct sockaddr *addr, size_t addr_len)
+{
+ int i;
+ struct sa *sa;
+ struct sockaddr *taddr;
+ int taddr_len;
+
+ for (i = 0; i < bucket_mask; i++)
+ for (sa = LIST_FIRST (&sa_tab[i]); sa; sa = LIST_NEXT (sa, link))
+ /*
+ * XXX We check the transport because it can be NULL until we fix
+ * the initiator case to set the transport always.
+ */
+ if (sa->phase == 1 && sa->transport)
+ {
+ sa->transport->vtbl->get_dst (sa->transport, &taddr, &taddr_len);
+ if (taddr_len == addr_len && memcmp (taddr, addr, addr_len) == 0)
+ return sa;
+ }
+ return 0;
+}
+
+/* Delete an SA. Tell the peer if NOTIFY is set. */
+void
+sa_delete (struct sa *sa, int notify)
+{
+ /* XXX we do not send DELETE payloads just yet. */
+
+ sa_free (sa);
+}
+
+/*
+ * Establish a new ISAKMP SA.
+ * XXX Whatif the peer initiated another SA negotiation?
+ */
+void
+sa_rekey_p1 (struct sa *sa)
+{
+ /* XXX Fill in the args argument. */
+ exchange_establish_p1 (sa->transport, sa->exch_type, sa->doi->id, 0);
+
+ /* XXX I want this sa_delete deferred until the new SA is ready. */
+ sa_delete (sa, 1);
+}
diff --git a/sbin/isakmpd/sa.h b/sbin/isakmpd/sa.h
new file mode 100644
index 00000000000..79ddbb2137c
--- /dev/null
+++ b/sbin/isakmpd/sa.h
@@ -0,0 +1,162 @@
+/* $Id: sa.h,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _SA_H_
+#define _SA_H_
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+
+#include "isakmp.h"
+
+/* Remove a SA if it has not been fully negotiated in this time. */
+#define SA_NEGOTIATION_MAX_TIME 120
+
+struct crypto_xf;
+struct doi;
+struct event;
+struct exchange;
+struct keystate;
+struct message;
+struct payload;
+struct sa;
+struct transport;
+
+/* A protection suite consists of a set of protocol descriptions like this. */
+struct proto {
+ /* Link to the next protocol in the suite. */
+ TAILQ_ENTRY (proto) link;
+
+ /* The SA we belong to. */
+ struct sa *sa;
+
+ /* The protocol number as found in the proposal payload. */
+ u_int8_t no;
+
+ /* The protocol this SA is for. */
+ u_int8_t proto;
+
+ /* Security parameter index info. Element 0 - responder, 1 - initiator. */
+ u_int8_t spi_sz[2];
+ u_int8_t *spi[2];
+
+ /*
+ * The chosen transform, only valid while the incoming SA payload that held
+ * it is available for duplicate testing.
+ */
+ struct payload *chosen;
+
+ /* The chosen transform's ID. */
+ u_int8_t id;
+
+ /* DOI-specific data. */
+ void *data;
+};
+
+struct sa {
+ /* Link to SAs with the same hash value. */
+ LIST_ENTRY (sa) link;
+
+ /*
+ * When several SA's are being negotiated in one message we connect them
+ * through this link.
+ */
+ TAILQ_ENTRY (sa) next;
+
+ /* What transport does this SA denote (ISAKMP SA only). */
+ struct transport *transport;
+
+ /* Both initiator and responder cookies. */
+ u_int8_t cookies[ISAKMP_HDR_COOKIES_LEN];
+
+ /* The message ID signifying non-ISAKMP SAs. */
+ u_int8_t message_id[ISAKMP_HDR_MESSAGE_ID_LEN];
+
+ /* The protection suite chosen. */
+ TAILQ_HEAD (proto_head, proto) protos;
+
+ /* The exchange type we should use when rekeying. */
+ u_int8_t exch_type;
+
+ /* Phase is 1 for ISAKMP SAs, and 2 for application ones. */
+ u_int8_t phase;
+
+ /* Save last message from setup, which can be retransmitted for dups */
+ struct message *last_sent_in_setup;
+
+ /* Various flags, look below for descriptions. */
+ u_int32_t flags;
+
+ /* The DOI that is to handle DOI-specific issues for this SA. */
+ struct doi *doi;
+
+ /* Crypto info needed to encrypt/decrypt packets protected by this SA. */
+ struct crypto_xf *crypto;
+ int key_length;
+ struct keystate *keystate;
+
+ /* DOI-specific opaque data. */
+ void *data;
+
+ /* Lifetime data. */
+ u_int64_t seconds;
+ u_int64_t kilobytes;
+
+ /* The event that will occur when an SA has timed out. */
+ struct event *death;
+};
+
+/* This SA is alive. */
+#define SA_FLAG_READY 1
+
+extern void proto_free (struct proto *proto);
+extern int sa_add_transform (struct sa *, struct payload *, int,
+ struct proto **);
+extern int sa_create (struct exchange *, struct transport *);
+extern void sa_delete (struct sa *, int);
+extern void sa_free (struct sa *);
+extern void sa_free_aux (struct sa *);
+extern void sa_init (void);
+extern struct sa *sa_isakmp_lookup_by_peer (struct sockaddr *, size_t addr);
+extern void sa_isakmp_upgrade (struct message *);
+extern struct sa *sa_lookup (u_int8_t *, u_int8_t *);
+extern struct sa *sa_lookup_by_header (u_int8_t *, int);
+extern struct sa *sa_lookup_from_icookie (u_int8_t *);
+extern void sa_rekey_p1 (struct sa *);
+extern void sa_report (void);
+
+#endif /* _SA_H_ */
diff --git a/sbin/isakmpd/sysdep-openbsd.c b/sbin/isakmpd/sysdep-openbsd.c
new file mode 100644
index 00000000000..988a41e3b55
--- /dev/null
+++ b/sbin/isakmpd/sysdep-openbsd.c
@@ -0,0 +1,167 @@
+/* $Id: sysdep-openbsd.c,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/encap.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef NEED_SYSDEP_APP
+#include "app.h"
+#include "ipsec.h"
+#include "pf_encap.h"
+#endif NEED_SYSDEP_APP
+#include "log.h"
+#include "sysdep.h"
+
+extern char *__progname;
+int regrand = 0;
+
+u_int32_t
+sysdep_random ()
+{
+ if (!regrand)
+ return arc4random ();
+ else
+ return random();
+}
+
+char *
+sysdep_progname ()
+{
+ return __progname;
+}
+
+/* As regress/ use this file I protect the sysdep_app_* stuff like this. */
+#ifdef NEED_SYSDEP_APP
+int
+sysdep_app_open ()
+{
+ return pf_encap_open ();
+}
+
+void
+sysdep_app_handler (int fd)
+{
+ pf_encap_handler (fd);
+}
+
+u_int8_t *
+sysdep_ipsec_get_spi (size_t *sz, u_int8_t proto, void *id, size_t id_sz)
+{
+ if (app_none)
+ {
+ *sz = IPSEC_SPI_SIZE;
+ /* XXX should be random instead I think. */
+ return strdup ("\x12\x34\x56\x78");
+ }
+ return pf_encap_get_spi (sz, proto, id, id_sz);
+}
+
+int
+sysdep_cleartext (int fd)
+{
+ int level;
+
+ if (app_none)
+ return 0;
+
+ /*
+ * Need to bypass system security policy, so I can send and
+ * receive key management datagrams in the clear.
+ */
+ level = IPSEC_LEVEL_BYPASS;
+ if (setsockopt (fd, IPPROTO_IP, IP_AUTH_LEVEL, (char *)&level, sizeof level)
+ == -1)
+ {
+ log_error ("sysdep_cleartext: "
+ "setsockopt (%d, IPPROTO_IP, IP_AUTH_LEVEL, ...) failed", fd);
+ return -1;
+ }
+ if (setsockopt (fd, IPPROTO_IP, IP_ESP_TRANS_LEVEL, (char *)&level,
+ sizeof level) == -1)
+ {
+ log_error ("sysdep_cleartext: "
+ "setsockopt (%d, IPPROTO_IP, IP_ESP_TRANS_LEVEL, ...) "
+ "failed", fd);
+ return -1;
+ }
+ if (setsockopt (fd, IPPROTO_IP, IP_ESP_NETWORK_LEVEL, (char *)&level,
+ sizeof level) == -1)
+ {
+ log_error("sysdep_cleartext: "
+ "setsockopt (%d, IPPROTO_IP, IP_ESP_NETWORK_LEVEL, ...) "
+ "failed", fd);
+ return -1;
+ }
+ return 0;
+}
+
+int
+sysdep_ipsec_delete_spi (struct sa *sa, struct proto *proto, int initiator)
+{
+ if (app_none)
+ return 0;
+ return pf_encap_delete_spi (sa, proto, initiator);
+}
+
+int
+sysdep_ipsec_enable_spi (struct sa *sa, int initiator)
+{
+ if (app_none)
+ return 0;
+ return pf_encap_enable_spi (sa, initiator);
+}
+
+int
+sysdep_ipsec_group_spis (struct sa *sa, struct proto *proto1,
+ struct proto *proto2, int role)
+{
+ if (app_none)
+ return 0;
+ return pf_encap_group_spis (sa, proto1, proto2, role);
+}
+
+int
+sysdep_ipsec_set_spi (struct sa *sa, struct proto *proto, int role,
+ int initiator)
+{
+ if (app_none)
+ return 0;
+ return pf_encap_set_spi (sa, proto, role, initiator);
+}
+#endif
diff --git a/sbin/isakmpd/sysdep.h b/sbin/isakmpd/sysdep.h
new file mode 100644
index 00000000000..3467ccb96b0
--- /dev/null
+++ b/sbin/isakmpd/sysdep.h
@@ -0,0 +1,56 @@
+/* $Id: sysdep.h,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _SYSDEP_H_
+#define _SYSDEP_H_
+
+#include <sys/types.h>
+
+struct proto;
+struct sa;
+
+extern void sysdep_app_handler (int);
+extern int sysdep_app_open (void);
+extern int sysdep_cleartext (int);
+extern int sysdep_ipsec_delete_spi (struct sa *, struct proto *, int);
+extern int sysdep_ipsec_enable_spi (struct sa *, int);
+extern u_int8_t *sysdep_ipsec_get_spi (size_t *, u_int8_t, void *, size_t);
+extern int sysdep_ipsec_group_spis (struct sa *, struct proto *,
+ struct proto *, int);
+extern int sysdep_ipsec_set_spi (struct sa *, struct proto *, int, int);
+extern char *sysdep_progname (void);
+extern u_int32_t sysdep_random (void);
+
+#endif /* _SYSDEP_H_ */
diff --git a/sbin/isakmpd/timer.c b/sbin/isakmpd/timer.c
new file mode 100644
index 00000000000..5a6ae9714a3
--- /dev/null
+++ b/sbin/isakmpd/timer.c
@@ -0,0 +1,126 @@
+/* $Id: timer.c,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/queue.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "log.h"
+#include "timer.h"
+
+static TAILQ_HEAD (event_list, event) events;
+
+void
+timer_init ()
+{
+ TAILQ_INIT (&events);
+}
+
+void
+timer_next_event (struct timeval **timeout)
+{
+ struct timeval now;
+
+ if (TAILQ_FIRST (&events))
+ {
+ gettimeofday (&now, 0);
+ if (timercmp (&now, &TAILQ_FIRST (&events)->expiration, >=))
+ timerclear (*timeout);
+ else
+ timersub (&TAILQ_FIRST (&events)->expiration, &now, *timeout);
+ }
+ else
+ *timeout = 0;
+}
+
+void
+timer_handle_expirations ()
+{
+ struct timeval now;
+ struct event *n;
+
+ gettimeofday (&now, 0);
+ for (n = TAILQ_FIRST (&events); n && timercmp (&now, &n->expiration, >=);
+ n = TAILQ_FIRST (&events))
+ {
+ log_debug (LOG_TIMER, 10,
+ "timer_handle_expirations: event %s(%p)", n->name, n->arg);
+ TAILQ_REMOVE (&events, n, link);
+ (*n->func) (n->arg);
+ free (n);
+ }
+}
+
+struct event *
+timer_add_event (char *name, void (*func) (void *), void *arg,
+ struct timeval *expiration)
+{
+ struct event *ev = (struct event *)malloc (sizeof *ev);
+ struct event *n;
+
+ if (!ev)
+ return 0;
+ ev->name = name;
+ ev->func = func;
+ ev->arg = arg;
+ memcpy (&ev->expiration, expiration, sizeof *expiration);
+ for (n = TAILQ_FIRST (&events);
+ n && timercmp (expiration, &n->expiration, >=);
+ n = TAILQ_NEXT (n, link))
+ ;
+ if (n)
+ {
+ log_debug (LOG_TIMER, 10,
+ "timer_add_event: event %s(%p) added before %s(%p)", name,
+ arg, n->name, n->arg);
+ TAILQ_INSERT_BEFORE (n, ev, link);
+ }
+ else
+ {
+ log_debug (LOG_TIMER, 10, "timer_add_event: event %s(%p) added last",
+ name, arg);
+ TAILQ_INSERT_TAIL (&events, ev, link);
+ }
+ return ev;
+}
+
+void
+timer_remove_event (struct event *ev)
+{
+ log_debug (LOG_TIMER, 10, "timer_remove_event: removing event %s(%p)",
+ ev->name, ev->arg);
+ TAILQ_REMOVE (&events, ev, link);
+ free (ev);
+}
diff --git a/sbin/isakmpd/timer.h b/sbin/isakmpd/timer.h
new file mode 100644
index 00000000000..50fe424f9d7
--- /dev/null
+++ b/sbin/isakmpd/timer.h
@@ -0,0 +1,58 @@
+/* $Id: timer.h,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _TIMER_H_
+#define _TIMER_H_
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+struct event {
+ TAILQ_ENTRY (event) link;
+ char *name;
+ void (*func) (void *);
+ void *arg;
+ struct timeval expiration;
+};
+
+extern void timer_init (void);
+extern void timer_next_event (struct timeval **);
+extern void timer_handle_expirations (void);
+extern struct event *timer_add_event (char *, void (*) (void *), void *,
+ struct timeval *);
+extern void timer_remove_event (struct event *);
+
+#endif /* _TIMER_H_ */
diff --git a/sbin/isakmpd/transport.c b/sbin/isakmpd/transport.c
new file mode 100644
index 00000000000..d523b1dcccf
--- /dev/null
+++ b/sbin/isakmpd/transport.c
@@ -0,0 +1,245 @@
+/* $Id: transport.c,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+
+#include "conf.h"
+#include "exchange.h"
+#include "log.h"
+#include "message.h"
+#include "sa.h"
+#include "timer.h"
+#include "transport.h"
+
+LIST_HEAD (transport_list, transport) transport_list;
+LIST_HEAD (transport_method_list, transport_vtbl) transport_method_list;
+
+/* Initialize the transport maintenance module. */
+void
+transport_init (void)
+{
+ LIST_INIT (&transport_list);
+ LIST_INIT (&transport_method_list);
+}
+
+/* Register another transport T. */
+void
+transport_add (struct transport *t)
+{
+ TAILQ_INIT (&t->sendq);
+ LIST_INSERT_HEAD (&transport_list, t, link);
+}
+
+/* Register another transport method T. */
+void
+transport_method_add (struct transport_vtbl *t)
+{
+ LIST_INSERT_HEAD (&transport_method_list, t, link);
+}
+
+/* Apply a function FUNC on all registered transports. */
+void
+transport_map (void (*func) (struct transport *))
+{
+ struct transport *t;
+
+ for (t = LIST_FIRST (&transport_list); t; t = LIST_NEXT (t, link))
+ (*func) (t);
+}
+
+/*
+ * Build up a file desciptor set FDS with all transport descriptors we want
+ * to read from. Return the number of file descriptors select(2) needs to
+ * check in order to cover the ones we setup in here.
+ */
+int
+transport_fd_set (fd_set *fds)
+{
+ int n;
+ int max = -1;
+ struct transport *t;
+
+ for (t = LIST_FIRST (&transport_list); t; t = LIST_NEXT (t, link))
+ if (t->flags & TRANSPORT_LISTEN)
+ {
+ n = (*t->vtbl->fd_set) (t, fds);
+ if (n > max)
+ max = n;
+ }
+ return max + 1;
+}
+
+/*
+ * Build up a file desciptor set FDS with all the descriptors belonging to
+ * transport where messages are queued for transmittal. Return the number
+ * of file descriptors select(2) needs to check in order to cover the ones
+ * we setup in here.
+ */
+int
+transport_pending_wfd_set (fd_set *fds)
+{
+ int n;
+ int max = -1;
+ struct transport *t;
+
+ for (t = LIST_FIRST (&transport_list); t; t = LIST_NEXT (t, link))
+ {
+ if (TAILQ_FIRST (&t->sendq))
+ {
+ n = (*t->vtbl->fd_set) (t, fds);
+ if (n > max)
+ max = n;
+ }
+ }
+ return max + 1;
+}
+
+/*
+ * For each transport with a file descriptor in FDS, try to get an
+ * incoming message and start processing it.
+ */
+void
+transport_handle_messages (fd_set *fds)
+{
+ struct transport *t;
+
+ for (t = LIST_FIRST (&transport_list); t; t = LIST_NEXT (t, link))
+ if ((t->flags & TRANSPORT_LISTEN) && (*t->vtbl->fd_isset) (t, fds))
+ (*t->vtbl->handle_message) (t);
+}
+
+/*
+ * Send the first queued message on the transports whose file descriptor
+ * is in FDS.
+ */
+void
+transport_send_messages (fd_set *fds)
+{
+ struct transport *t;
+ struct message *msg;
+ struct timeval expiration;
+ struct sa *sa, *next_sa;
+ int expiry;
+
+ for (t = LIST_FIRST (&transport_list); t; t = LIST_NEXT (t, link))
+ if (TAILQ_FIRST (&t->sendq) && (*t->vtbl->fd_isset) (t, fds))
+ {
+ msg = TAILQ_FIRST (&t->sendq);
+ TAILQ_REMOVE (&t->sendq, msg, link);
+
+ /*
+ * We disregard the potential error message here, hoping that the
+ * retransmit will go better.
+ * XXX Consider a retry/fatal error discriminator.
+ */
+ t->vtbl->send_message (msg);
+
+ /*
+ * If this is not a retransmit call post-send functions that allows
+ * parallel work to be done while the network and peer does their
+ * share of the job.
+ */
+ if (msg->xmits == 0)
+ message_post_send (msg);
+
+ msg->xmits++;
+
+ if ((msg->flags & MSG_NO_RETRANS) == 0)
+ {
+ /* XXX make this a configurable parameter. */
+ if (msg->xmits > conf_get_num ("General", "retransmits"))
+ {
+ log_print ("transport_send_messages: giving up on message %p",
+ msg);
+ msg->exchange->last_sent = 0;
+
+ /*
+ * As this exchange never went to a normal end, remove the
+ * SA's being negotiated too.
+ */
+ for (sa = TAILQ_FIRST (&msg->exchange->sa_list); sa;
+ sa = next_sa)
+ {
+ next_sa = TAILQ_NEXT (sa, next);
+ sa_free (sa);
+ }
+
+ exchange_free (msg->exchange);
+ message_free (msg);
+ return;
+ };
+
+ gettimeofday (&expiration, 0);
+ /* XXX Calculate from round trip timings and a backoff func. */
+ expiry = msg->xmits * 2 + 5;
+ expiration.tv_sec += expiry;
+ log_debug (LOG_TRANSPORT, 30,
+ "transport_send_messages: "
+ "message %p scheduled for retransmission %d in %d secs",
+ msg, msg->xmits, expiry);
+ msg->retrans = timer_add_event ("message_send",
+ (void (*) (void *))message_send,
+ msg, &expiration);
+ if (!msg->retrans)
+ {
+ /* If we can make no retransmission, we can't.... */
+ message_free (msg);
+ return;
+ }
+
+ msg->exchange->last_sent = msg;
+ }
+ else if ((msg->flags & MSG_KEEP) == 0)
+ message_free (msg);
+ }
+}
+
+/*
+ * Textual search after the transport method denoted by NAME, then create
+ * a transport connected to the peer with address ADDR, given in a transport-
+ * specific string format.
+ */
+struct transport *
+transport_create (char *name, char *addr)
+{
+ struct transport_vtbl *method;
+
+ for (method = LIST_FIRST (&transport_method_list); method;
+ method = LIST_NEXT (method, link))
+ if (strcmp (method->name, name) == 0)
+ return (*method->create) (addr);
+ return 0;
+}
diff --git a/sbin/isakmpd/transport.h b/sbin/isakmpd/transport.h
new file mode 100644
index 00000000000..8b6ee29fb60
--- /dev/null
+++ b/sbin/isakmpd/transport.h
@@ -0,0 +1,118 @@
+/* $Id: transport.h,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+/*
+ * The transport module tries to separate out details concerning the
+ * actual transferral of ISAKMP messages to other parties.
+ */
+
+#ifndef _TRANSPORT_H_
+#define _TRANSPORT_H_
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+struct message;
+struct transport;
+
+/* This describes a tranport "method" like UDP or similar. */
+struct transport_vtbl {
+ /* All transport methods are linked together. */
+ LIST_ENTRY (transport_vtbl) link;
+
+ /* A textual name of the transport method. */
+ char *name;
+
+ /* Create a transport instance of this method. */
+ struct transport *(*create) (char *);
+
+ /* Let the given transport set it's bit in the fd_set passed in. */
+ int (*fd_set) (struct transport *, fd_set *);
+
+ /* Is the given transport ready for I/O? */
+ int (*fd_isset) (struct transport *, fd_set *);
+
+ /*
+ * Read a message from the transport's incoming pipe and start
+ * handling it.
+ */
+ void (*handle_message) (struct transport *);
+
+ /* Send a message through the outgoing pipe. */
+ int (*send_message) (struct message *);
+
+ /*
+ * Fill out a sockaddr structure with the transport's destination end's
+ * address info. XXX Why not size_t * as last arg?
+ */
+ void (*get_dst) (struct transport *, struct sockaddr **, int *);
+
+ /*
+ * Fill out a sockaddr structure with the transport's source end's
+ * address info. XXX Why not size_t * as last arg?
+ */
+ void (*get_src) (struct transport *, struct sockaddr **, int *);
+};
+
+struct transport {
+ /* All transports used are linked together. */
+ LIST_ENTRY (transport) link;
+
+ /* What transport method is this an instance of? */
+ struct transport_vtbl *vtbl;
+
+ /* The queue holding messages to send on this transport. */
+ TAILQ_HEAD (msg_head, message) sendq;
+
+ /* Flags describing the transport. */
+ int flags;
+};
+
+/* Set if this is a transport we want to listen on. */
+#define TRANSPORT_LISTEN 1
+
+extern void transport_add (struct transport *);
+extern struct transport *transport_create (char *, char *);
+extern int transport_fd_set (fd_set *);
+extern void transport_handle_messages (fd_set *);
+extern void transport_init (void);
+extern void transport_map (void (*) (struct transport *));
+extern void transport_method_add (struct transport_vtbl *);
+extern int transport_pending_wfd_set (fd_set *);
+extern void transport_send_messages (fd_set *);
+
+#endif /* _TRANSPORT_H_ */
diff --git a/sbin/isakmpd/udp.c b/sbin/isakmpd/udp.c
new file mode 100644
index 00000000000..e8cf36e9a8d
--- /dev/null
+++ b/sbin/isakmpd/udp.c
@@ -0,0 +1,411 @@
+/* $Id: udp.c,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <err.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "if.h"
+#include "isakmp.h"
+#include "log.h"
+#include "message.h"
+#include "sysdep.h"
+#include "transport.h"
+#include "udp.h"
+#include "util.h"
+
+#define BACKLOG 16
+#define UDP_SIZE 65536
+
+/* XXX IPv4 specific. */
+struct udp_transport {
+ struct transport transport;
+ struct sockaddr_in src;
+ struct sockaddr_in dst;
+ int s;
+};
+
+static struct transport *udp_clone (struct udp_transport *,
+ struct sockaddr_in *);
+static struct transport *udp_create (char *);
+static int udp_fd_set (struct transport *, fd_set *);
+static int udp_fd_isset (struct transport *, fd_set *);
+static void udp_handle_message (struct transport *);
+static struct transport *udp_make (struct sockaddr_in *);
+static int udp_send_message (struct message *);
+static void udp_get_dst (struct transport *, struct sockaddr **, int *);
+static void udp_get_src (struct transport *, struct sockaddr **, int *);
+
+struct transport_vtbl udp_transport_vtbl = {
+ { 0 }, "udp",
+ udp_create,
+ udp_fd_set,
+ udp_fd_isset,
+ udp_handle_message,
+ udp_send_message,
+ udp_get_dst,
+ udp_get_src
+};
+
+in_port_t udp_default_port = 0;
+in_port_t udp_bind_port = 0;
+static int udp_proto;
+static struct transport *default_transport;
+
+/* Create a UDP transport structure bound to LADDR just for listening. */
+static struct transport *
+udp_make (struct sockaddr_in *laddr)
+{
+ struct udp_transport *t = 0;
+ int s;
+ int on;
+
+ t = malloc (sizeof *t);
+ if (!t)
+ {
+ log_print ("udp_make: malloc (%d) failed", sizeof *t);
+ return 0;
+ }
+
+ s = socket (AF_INET, SOCK_DGRAM, udp_proto);
+ if (s == -1)
+ {
+ log_error ("udp_make: socket (%d, %d, %d)", AF_INET, SOCK_DGRAM,
+ udp_proto);
+ goto err;
+ }
+
+ /* Make sure we don't get our traffic encrypted. */
+ sysdep_cleartext (s);
+
+ on = 1;
+ /* XXX Is this redundant considering SO_REUSEPORT below? */
+ if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof on) == -1)
+ {
+ log_error ("udp_make: setsockopt (%d, %d, %d, %p, %d)", s, SOL_SOCKET,
+ SO_REUSEADDR, &on, sizeof on);
+ goto err;
+ }
+
+ t->transport.vtbl = &udp_transport_vtbl;
+ memcpy (&t->src, laddr, sizeof t->src);
+ if (bind (s, (struct sockaddr *)&t->src, sizeof t->src))
+ {
+ log_error ("udp_make: bind (%d, %p, %d)", s, &t->src, sizeof t->src);
+ goto err;
+ }
+
+ memset (&t->dst, 0, sizeof t->dst);
+ t->s = s;
+ t->transport.flags |= TRANSPORT_LISTEN;
+
+ transport_add ((struct transport *)t);
+ return (struct transport *)t;
+
+err:
+ if (s != -1)
+ close (s);
+ if (t)
+ free (t);
+ return 0;
+}
+
+/* Clone a listen transport U, record a destination RADDR for outbound use. */
+static struct transport *
+udp_clone (struct udp_transport *u, struct sockaddr_in *raddr)
+{
+ struct transport *t;
+ struct udp_transport *u2;
+
+ t = malloc (sizeof *u);
+ if (!t)
+ return 0;
+ u2 = (struct udp_transport *)t;
+
+ memcpy (t, u, sizeof *u);
+ memcpy (&u2->dst, raddr, sizeof u2->dst);
+ t->flags &= ~TRANSPORT_LISTEN;
+
+ transport_add (t);
+
+ return t;
+}
+
+/*
+ * Initialize an object of the UDP transport class. Fill in the local
+ * IP address and port information and create a server socket bound to
+ * that specific port. Add the polymorphic transport structure to the
+ * system-wide pools of known ISAKMP transports.
+ */
+static struct transport *
+udp_bind (in_addr_t addr, in_port_t port)
+{
+ struct sockaddr_in src;
+
+ memset (&src, 0, sizeof src);
+ src.sin_len = sizeof src;
+ src.sin_family = AF_INET;
+ src.sin_addr.s_addr = addr;
+ src.sin_port = port;
+ return udp_make (&src);
+}
+
+/*
+ * When looking at a specific network interface address, if it's an INET one,
+ * create an UDP server socket bound to it.
+ */
+static void
+udp_bind_if (struct ifreq *ifrp, void *arg)
+{
+ in_port_t port = *(in_port_t *)arg;
+
+ /*
+ * Well UDP is an internet protocol after all so drop other ifreqs.
+ * XXX IPv6 support is missing.
+ */
+ if (ifrp->ifr_addr.sa_family != AF_INET
+ || ifrp->ifr_addr.sa_len != sizeof (struct sockaddr_in))
+ return;
+
+ /* XXX Deal with errors better. */
+ udp_bind (((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr, port);
+}
+
+/*
+ * ADDR is either a numeric IP address (we cannot risk doing DNS lookups
+ * which might take considerable time) or an address and a UDP port number
+ * separated by a colon. That address specifies a peer ISAKMP daemon we
+ * will talk to. Setup and return a transport useable to talk to that
+ * service.
+ */
+static struct transport *
+udp_create (char *addr_arg)
+{
+ struct sockaddr_in dst;
+ char *addr_str, *port_str;
+ in_addr_t addr;
+ in_port_t port;
+
+ addr_str = strdup (addr_arg);
+ if (!addr_str)
+ {
+ log_print ("udp_create: strdup (\"%s\") failed", addr_arg);
+ return 0;
+ }
+ port_str = strchr (addr_str, ':');
+ if (port_str)
+ {
+ *port_str++ = '\0';
+ port = atoi (port_str);
+ if (!port)
+ log_print ("udp_create: connection to port 0 not allowed");
+ }
+ else
+ port = UDP_DEFAULT_PORT;
+ addr = inet_addr (addr_str);
+ if (addr == INADDR_NONE)
+ {
+ log_print ("udp_create: inet_addr (\"%s\") failed", addr_str);
+ return 0;
+ }
+
+ memset (&dst, 0, sizeof dst);
+ dst.sin_len = sizeof dst;
+ dst.sin_family = AF_INET;
+ dst.sin_addr.s_addr = addr;
+ dst.sin_port = htons (port);
+
+ return udp_clone ((struct udp_transport *)default_transport, &dst);
+}
+
+/*
+ * Find out the magic numbers for the UDP protocol as well as the UDP port
+ * to use. Setup an UDP server for each address of this machine, and one
+ * for the generic case when we are the initiator.
+ */
+void
+udp_init ()
+{
+ struct protoent *p;
+ struct servent *s;
+ in_port_t port;
+
+ /* Initialize the protocol and port numbers. */
+ p = getprotobyname ("udp");
+ udp_proto = p ? p->p_proto : IPPROTO_UDP;
+ if (udp_default_port)
+ port = htons (udp_default_port);
+ else
+ {
+ s = getservbyname("isakmp", "udp");
+ port = s ? s->s_port : htons (UDP_DEFAULT_PORT);
+ }
+
+ /* Bind the ISAKMP UDP port on all network interfaces we have. */
+ /* XXX need to check errors */
+ if_map (udp_bind_if, &port);
+
+ /*
+ * Bind to INADDR_ANY in case of new addresses popping up.
+ * XXX We should use packets coming in on this socket as a signal
+ * to reprobe for new interfaces.
+ */
+ default_transport = udp_bind (INADDR_ANY, port);
+ if (!default_transport)
+ log_error ("udp_init: could not allocate default ISAKMP UDP port");
+
+ transport_method_add (&udp_transport_vtbl);
+}
+
+/*
+ * Set transport T's socket in FDS, return a value useable by select(2)
+ * as the number of file descriptors to check.
+ */
+static int
+udp_fd_set (struct transport *t, fd_set *fds)
+{
+ struct udp_transport *u = (struct udp_transport *)t;
+
+ FD_SET (u->s, fds);
+ return u->s + 1;
+}
+
+/* Check if transport T's socket is set in FDS. */
+static int
+udp_fd_isset (struct transport *t, fd_set *fds)
+{
+ struct udp_transport *u = (struct udp_transport *)t;
+
+ return FD_ISSET (u->s, fds);
+}
+
+/*
+ * A message has arrived on transport T's socket. If T is single-ended,
+ * clone it into a double-ended transport which we will use from now on.
+ * Package the message as we want it and continue processing in the message
+ * module.
+ * XXX We will be leaking transports unless we kill them after last
+ * probable use, i.e. when ISAKMP SA's gets torn down.
+ */
+static void
+udp_handle_message (struct transport *t)
+{
+ struct udp_transport *u = (struct udp_transport *)t;
+ u_int8_t buf[UDP_SIZE];
+ struct sockaddr_in from;
+ int len = sizeof from;
+ ssize_t n;
+ struct message *msg;
+
+ n = recvfrom (u->s, buf, UDP_SIZE, 0, (struct sockaddr *)&from, &len);
+ if (n == -1)
+ {
+ log_error ("recvfrom (%d, %p, %d, %d, %p, %p)", u->s, buf, UDP_SIZE, 0,
+ &from, &len);
+ return;
+ }
+
+ /*
+ * Make a specialized UDP transport structure out of the incoming
+ * transport and the address information we got from recvfrom(2).
+ */
+ t = udp_clone (u, &from);
+ if (!t)
+ /* XXX Should we do more here? */
+ return;
+
+ msg = message_alloc (t, buf, n);
+ if (!msg)
+ /* XXX Log. */
+ return;
+ message_recv (msg);
+}
+
+/* Physically send the message MSG over its associated transport. */
+static int
+udp_send_message (struct message *msg)
+{
+ struct udp_transport *u = (struct udp_transport *)msg->transport;
+ ssize_t n;
+ struct msghdr m;
+
+ /*
+ * Sending on connected sockets requires that no destination address is
+ * given, or else EISCONN will occur.
+ */
+ m.msg_name = (caddr_t)&u->dst;
+ m.msg_namelen = sizeof u->dst;
+ m.msg_iov = msg->iov;
+ m.msg_iovlen = msg->iovlen;
+ m.msg_control = 0;
+ m.msg_controllen = 0;
+ m.msg_flags = 0;
+ n = sendmsg (u->s, &m, 0);
+ if (n == -1)
+ {
+ log_error ("sendmsg (%d, %p, %d)", u->s, &m, 0);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Get transport T's peer address and stuff it into the sockaddr pointed
+ * to by DST. Put its length into DST_LEN.
+ */
+static void
+udp_get_dst (struct transport *t, struct sockaddr **dst, int *dst_len)
+{
+ *dst = (struct sockaddr *)&((struct udp_transport *)t)->dst;
+ *dst_len = sizeof ((struct udp_transport *)t)->dst;
+}
+
+/*
+ * Get transport T's local address and stuff it into the sockaddr pointed
+ * to by SRC. Put its length into SRC_LEN.
+ */
+static void
+udp_get_src (struct transport *t, struct sockaddr **src, int *src_len)
+{
+ *src = (struct sockaddr *)&((struct udp_transport *)t)->src;
+ *src_len = sizeof ((struct udp_transport *)t)->src;
+}
diff --git a/sbin/isakmpd/udp.h b/sbin/isakmpd/udp.h
new file mode 100644
index 00000000000..de615f6e3ca
--- /dev/null
+++ b/sbin/isakmpd/udp.h
@@ -0,0 +1,44 @@
+/* $Id: udp.h,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _UDP_H_
+#define _UDP_H_
+
+extern in_port_t udp_default_port;
+extern in_port_t udp_bind_port;
+
+extern void udp_init (void);
+
+#endif /* _UDP_H_ */
diff --git a/sbin/isakmpd/ui.c b/sbin/isakmpd/ui.c
new file mode 100644
index 00000000000..f86fd0c5c65
--- /dev/null
+++ b/sbin/isakmpd/ui.c
@@ -0,0 +1,307 @@
+/* $Id: ui.c,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define BUF_SZ 256
+
+#include "doi.h"
+#include "exchange.h"
+#include "isakmp.h"
+#include "log.h"
+#include "sa.h"
+#include "transport.h"
+#include "ui.h"
+#include "util.h"
+
+char *ui_fifo = FIFO;
+int ui_socket;
+
+/* Create and open the FIFO used for user control. */
+void
+ui_init ()
+{
+ /* -f- means control messages comes in via stdin. */
+ if (strcmp (ui_fifo, "-") == 0)
+ ui_socket = 0;
+ else
+ {
+ /* No need to know about errors. */
+ unlink (ui_fifo);
+ if (mkfifo (ui_fifo, 0600) == -1)
+ log_fatal ("mkfifo");
+
+ /* XXX Is O_RDWR needed on some OSes? Photurisd seems to imply that. */
+ ui_socket = open (ui_fifo, O_RDONLY | O_NONBLOCK, 0);
+ if (ui_socket == -1)
+ log_fatal (ui_fifo);
+ }
+}
+
+/* Parse the connect command found in CMD. */
+static void
+ui_connect (char *cmd)
+{
+ char trpt[11];
+ char addr[81];
+ struct transport *transport = 0;
+ int exchange, doi;
+ struct sa *isakmp_sa = 0;
+ u_int8_t cookies[ISAKMP_HDR_COOKIES_LEN];
+
+ if (sscanf (cmd, "c %10s %80s %d %d", trpt, addr, &exchange, &doi) != 4)
+ {
+ log_print ("ui_connect: command \"%s\" malformed", cmd);
+ return;
+ }
+
+ if (strcasecmp (trpt, "isakmp") == 0)
+ {
+ if (hex2raw (addr, cookies, ISAKMP_HDR_COOKIES_LEN) == -1)
+ {
+ log_print ("ui_connect: cookiepair \"%s\" malformed", addr);
+ return;
+ }
+ isakmp_sa = sa_lookup (cookies, 0);
+ if (!isakmp_sa)
+ {
+ log_print ("ui_connect: transport \"%s %s\" could not be found",
+ trpt, addr);
+ return;
+ }
+
+ /* XXX Fill in the args argument. */
+ exchange_establish_p2 (isakmp_sa, exchange, 0);
+ }
+ else
+ {
+ transport = transport_create (trpt, addr);
+ if (!transport)
+ {
+ log_print ("ui_connect: transport \"%s %s\" could not be created",
+ trpt, addr);
+ return;
+ }
+
+ /* XXX This validity check seems to be a bit dumb. */
+#if 0
+ /* Only ISAKMP exchange types can be given. */
+ if (exchange < ISAKMP_EXCH_BASE || exchange >= ISAKMP_EXCH_FUTURE_MIN)
+ {
+ log_print ("exchange %d is not valid", exchange);
+ return;
+ }
+#endif
+
+ /* Only valid DOIs can be given. XXX Uninteresting for phase 2. */
+ if (!doi_lookup (doi))
+ {
+ log_print ("DOI %d is not valid", doi);
+ return;
+ }
+
+ /* XXX Fill in the args argument. */
+ exchange_establish_p1 (transport, exchange, doi, 0);
+ }
+}
+
+static void
+ui_delete (char *cmd)
+{
+ char cookies_str[ISAKMP_HDR_COOKIES_LEN * 2 + 1];
+ char message_id_str[ISAKMP_HDR_MESSAGE_ID_LEN * 2 + 1];
+ u_int8_t cookies[ISAKMP_HDR_COOKIES_LEN];
+ u_int8_t message_id_buf[ISAKMP_HDR_MESSAGE_ID_LEN];
+ u_int8_t *message_id = message_id_buf;
+ struct sa *sa;
+
+ if (sscanf (cmd, "d %32s %8s", cookies_str, message_id_str) != 2)
+ {
+ log_print ("ui_delete: command \"%s\" malformed", cmd);
+ return;
+ }
+
+ if (strcmp (message_id_str, "-") == 0)
+ message_id = 0;
+
+ if (hex2raw (cookies_str, cookies, ISAKMP_HDR_COOKIES_LEN) == -1
+ || (message_id && hex2raw (message_id_str, message_id_buf,
+ ISAKMP_HDR_MESSAGE_ID_LEN) == -1))
+ {
+ log_print ("ui_delete: command \"%s\" has bad arguments", cmd);
+ return;
+ }
+
+ sa = sa_lookup (cookies, message_id);
+ if (!sa)
+ {
+ log_print ("ui_delete: command \"%s\" found no SA", cmd);
+ return;
+ }
+ sa_delete (sa, 1);
+}
+
+/* Parse the debug command found in CMD. */
+static void
+ui_debug (char *cmd)
+{
+ int cls, level;
+
+ if (sscanf (cmd, "d %d %d", &cls, &level) != 2)
+ {
+ log_print ("ui_debug: command \"%s\" malformed", cmd);
+ return;
+ }
+ log_debug_cmd (cls, level);
+}
+
+/* Report SAs and ongoing exchanges. */
+static void
+ui_report (char *cmd)
+{
+ sa_report ();
+ exchange_report ();
+}
+
+/*
+ * Call the relevant command handler based on the first character of the
+ * line (the command).
+ */
+static void
+ui_handle_command (char *line)
+{
+ /* Find out what one-letter command was sent. */
+ switch (line[0])
+ {
+ case 'c':
+ ui_connect (line);
+ break;
+
+ case 'd':
+ ui_delete (line);
+ break;
+
+ case 'D':
+ ui_debug (line);
+ break;
+
+ case 'r':
+ ui_report (line);
+ break;
+
+ default:
+ log_print ("ui_handle_messages: unrecognized command: '%c'", line[0]);
+ }
+}
+
+/*
+ * A half-complex implementation of reading from a file descriptor
+ * line by line without resorting to stdio which apparently have
+ * troubles with non-blocking fifos.
+ */
+void
+ui_handler ()
+{
+ static char *buf = 0;
+ static char *p;
+ static size_t sz;
+ static size_t resid;
+ size_t n;
+ char *new_buf;
+
+ /* If no buffer, set it up. */
+ if (!buf)
+ {
+ sz = BUF_SZ;
+ buf = malloc (sz);
+ if (!buf)
+ {
+ log_print ("malloc (%d) failed", sz);
+ return;
+ }
+ p = buf;
+ resid = sz;
+ }
+
+ /* If no place left in the buffer reallocate twice as large. */
+ if (!resid)
+ {
+ new_buf = realloc (buf, sz * 2);
+ if (!new_buf)
+ {
+ log_print ("realloc (%p, %d) failed", buf, sz * 2);
+ free (buf);
+ buf = 0;
+ return;
+ }
+ buf = new_buf;
+ p = buf + sz;
+ resid = sz;
+ sz *= 2;
+ }
+
+ n = read (ui_socket, p, resid);
+ if (n == -1)
+ {
+ log_error ("read (%d, %p, %d)", ui_socket, p, resid);
+ return;
+ }
+
+ if (!n)
+ return;
+ resid -= n;
+ while (n--)
+ {
+ /*
+ * When we find a newline, cut off the line and feed it to the
+ * command processor. Then move the rest up-front.
+ */
+ if (*p == '\n')
+ {
+ *p = '\0';
+ ui_handle_command (buf);
+ memcpy (buf, p + 1, n);
+ p = buf;
+ resid = sz - n;
+ continue;
+ }
+ p++;
+ }
+}
diff --git a/sbin/isakmpd/ui.h b/sbin/isakmpd/ui.h
new file mode 100644
index 00000000000..e78dd557985
--- /dev/null
+++ b/sbin/isakmpd/ui.h
@@ -0,0 +1,47 @@
+/* $Id: ui.h,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _UI_H_
+#define _UI_H_
+
+#define FIFO "/var/run/isakmpd.fifo"
+
+extern char *ui_fifo;
+extern int ui_socket;
+
+extern void ui_handler (void);
+extern void ui_init (void);
+
+#endif /* _UI_H_ */
diff --git a/sbin/isakmpd/util.c b/sbin/isakmpd/util.c
new file mode 100644
index 00000000000..dd27b9c2eab
--- /dev/null
+++ b/sbin/isakmpd/util.c
@@ -0,0 +1,152 @@
+/* $Id: util.c,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/types.h>
+#include <stdlib.h>
+
+#include "log.h"
+#include "message.h"
+#include "sysdep.h"
+#include "transport.h"
+#include "util.h"
+
+/*
+ * XXX These might be turned into inlines or macros, maybe even
+ * machine-dependent ones, for performance reasons.
+ */
+u_int16_t
+decode_16 (u_int8_t *cp)
+{
+ return cp[0] << 8 | cp[1];
+}
+
+u_int32_t
+decode_32 (u_int8_t *cp)
+{
+ return cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3];
+}
+
+void
+encode_16 (u_int8_t *cp, u_int16_t x)
+{
+ *cp++ = x >> 8;
+ *cp = x & 0xff;
+}
+
+void
+encode_32 (u_int8_t *cp, u_int32_t x)
+{
+ *cp++ = x >> 24;
+ *cp++ = (x >> 16) & 0xff;
+ *cp++ = (x >> 8) & 0xff;
+ *cp = x & 0xff;
+}
+
+/* Check a buffer for all zeroes. */
+int
+zero_test (const u_int8_t *p, size_t sz)
+{
+ while (sz-- > 0)
+ if (*p++ != 0)
+ return 0;
+ return 1;
+}
+
+/*
+ * Generate a random data, len bytes long.
+ */
+u_int8_t *
+getrandom (u_int8_t *buf, size_t len)
+{
+ u_int32_t tmp = 0;
+ int i;
+
+ for (i = 0; i < len; i++)
+ {
+ if (i % sizeof tmp == 0)
+ tmp = sysdep_random ();
+
+ buf[i] = tmp & 0xff;
+ tmp >>= 8;
+ }
+
+ return buf;
+}
+
+static __inline int
+hex2nibble (char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return -1;
+}
+
+/*
+ * Convert hexadecimal string in S to raw binary buffer at BUF sized SZ
+ * bytes. Return 0 if everything is OK, -1 otherwise.
+ */
+int
+hex2raw (char *s, u_int8_t *buf, size_t sz)
+{
+ char *p;
+ u_int8_t *bp;
+ int tmp;
+
+ if (strlen (s) > sz * 2)
+ return -1;
+ for (p = s + strlen (s) - 1, bp = &buf[sz - 1]; bp >= buf; bp--)
+ {
+ *bp = 0;
+ if (p >= s)
+ {
+ tmp = hex2nibble (*p--);
+ if (tmp == -1)
+ return -1;
+ *bp = tmp;
+ }
+ if (p >= s)
+ {
+ tmp = hex2nibble (*p--);
+ if (tmp == -1)
+ return -1;
+ *bp |= tmp << 4;
+ }
+ }
+ return 0;
+}
diff --git a/sbin/isakmpd/util.h b/sbin/isakmpd/util.h
new file mode 100644
index 00000000000..3fd89742d38
--- /dev/null
+++ b/sbin/isakmpd/util.h
@@ -0,0 +1,53 @@
+/* $Id: util.h,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _UTIL_H_
+#define _UTIL_H_
+
+#include <sys/types.h>
+
+#define ROUNDUP_32(x) (((x) + 3) & ~4)
+
+struct message;
+
+extern u_int16_t decode_16 (u_int8_t *);
+extern u_int32_t decode_32 (u_int8_t *);
+extern void encode_16 (u_int8_t *, u_int16_t);
+extern void encode_32 (u_int8_t *, u_int32_t);
+extern u_int8_t *getrandom (u_int8_t *, size_t);
+extern int hex2raw (char *, u_int8_t *, size_t);
+extern int zero_test (const u_int8_t *, size_t);
+
+#endif /* _UTIL_H_ */
diff --git a/sbin/isakmpd/x509.c b/sbin/isakmpd/x509.c
new file mode 100644
index 00000000000..9316a603255
--- /dev/null
+++ b/sbin/isakmpd/x509.c
@@ -0,0 +1,844 @@
+/* $Id: x509.c,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <gmp.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "conf.h"
+#include "exchange.h"
+#include "hash.h"
+#include "ike_auth.h"
+#include "sa.h"
+#include "ipsec.h"
+#include "log.h"
+#include "asn.h"
+#include "asn_useful.h"
+#include "pkcs.h"
+#include "x509.h"
+
+/* X509 Certificate Handling functions */
+
+/* Validate the BER Encoding of a RDNSequence in the CERT_REQ payload */
+
+int
+x509_certreq_validate (u_int8_t *asn, u_int32_t len)
+{
+ struct norm_type name = SEQOF ("issuer", RDNSequence);
+ int res = 1;
+
+ if (asn_template_clone (&name, 1) == NULL ||
+ (asn = asn_decode_sequence (asn, len, &name)) == NULL)
+ {
+ log_print ("x509_certreq_validate: can not decode 'acceptable CA' info");
+ res = 0;
+ }
+ asn_free (&name);
+
+ return res;
+}
+
+/* Decode the BER Encoding of a RDNSequence in the CERT_REQ payload */
+
+void *
+x509_certreq_decode (u_int8_t *asn, u_int32_t len)
+{
+ struct norm_type aca = SEQOF ("aca", RDNSequence);
+ struct norm_type *tmp;
+ struct x509_aca naca, *ret;
+
+ if (asn_template_clone (&aca, 1) == NULL ||
+ (asn = asn_decode_sequence (asn, len, &aca)) == NULL)
+ {
+ log_print ("x509_certreq_validate: can not decode 'acceptable CA' info");
+ goto fail;
+ }
+ memset (&naca, 0, sizeof (naca));
+
+ tmp = asn_decompose ("aca.RelativeDistinguishedName.AttributeValueAssertion", &aca);
+ if (tmp == NULL)
+ goto fail;
+ x509_get_attribval (tmp, &naca.name1);
+
+ tmp = asn_decompose ("aca.RelativeDistinguishedName[1].AttributeValueAssertion", &aca);
+ if (tmp != NULL)
+ x509_get_attribval (tmp, &naca.name2);
+
+ asn_free (&aca);
+
+ if ((ret = malloc (sizeof (struct x509_aca))) != NULL)
+ memcpy (ret, &naca, sizeof (struct x509_aca));
+ else
+ x509_free_aca (&aca);
+
+ return ret;
+
+ fail:
+ asn_free (&aca);
+ return NULL;
+}
+
+void
+x509_free_aca (void *blob)
+{
+ struct x509_aca *aca = blob;
+
+ if (aca->name1.type != NULL)
+ free (aca->name1.type);
+ if (aca->name1.val != NULL)
+ free (aca->name1.val);
+
+ if (aca->name2.type != NULL)
+ free (aca->name2.type);
+ if (aca->name2.val != NULL)
+ free (aca->name2.val);
+}
+
+/*
+ * Obtain a Certificate from an acceptable Certification Authority.
+ * XXX - this is where all the magic should happen, but yet here
+ * you will find nothing :-\
+ */
+
+int
+x509_cert_obtain (struct exchange *exchange, void *data, u_int8_t **cert,
+ u_int32_t *certlen)
+{
+ struct x509_aca *aca = data;
+ struct ipsec_exch *ie = exchange->data;
+ char *certfile;
+ int fd, res = 0;
+ struct stat st;
+
+ if (aca != NULL)
+ log_debug (LOG_CRYPTO, 60, "x509_cert_obtain: (%s) %s, (%s) %s",
+ asn_parse_objectid (asn_ids, aca->name1.type), aca->name1.val,
+ asn_parse_objectid (asn_ids, aca->name2.type), aca->name2.val);
+
+ /* XXX - this needs to be changed - but how else shoud I know */
+ switch (ie->ike_auth->id)
+ {
+ case IKE_AUTH_RSA_SIG:
+ if ((certfile = conf_get_str ("rsa_sig", "cert")) == NULL)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+
+ if (stat (certfile, &st) == -1)
+ {
+ log_error ("x509_cert_obtain: failed to state %s", certfile);
+ return 0;
+ }
+
+ *certlen = st.st_size;
+
+ if ((fd = open (certfile, O_RDONLY)) == -1)
+ {
+ log_error ("x509_cert_obtain: failed to open %s", certfile);
+ return 0;
+ }
+
+ if ((*cert = malloc (st.st_size)) == NULL)
+ {
+ log_print ("x509_cert_obtain: out of memory");
+ res = 0;
+ goto done;
+ }
+
+ if (read (fd, *cert, st.st_size) != st.st_size)
+ {
+ log_print ("x509_cert_obtain: cert file ended early");
+ free (*cert);
+ res = 0;
+ goto done;
+ }
+
+ {
+ /*
+ * XXX - assumes IPv4 here, assumes a certificate with an extension
+ * type of subjectAltName at the end - this can go once the saved
+ * certificate is only used with one host with a fixed IP address
+ */
+ u_int8_t *id_cert, *asn, *id;
+ size_t id_len;
+ u_int32_t id_cert_len;
+
+ /* XXX - assumes IPv4 */
+ id = exchange->initiator ? exchange->id_i : exchange->id_r;
+ id_len = exchange->initiator ? exchange->id_i_len : exchange->id_r_len;
+
+ /* XXX - we need our ID to set that in the cert */
+ if (id != NULL)
+ {
+ /* XXX - get to address ? */
+ id += 4; id_len -= 4;
+
+ /* Get offset into data structure where the IP is saved */
+ asn = *cert;
+ id_cert_len = asn_get_data_len (NULL, &asn, &id_cert);
+ asn = id_cert;
+ id_cert_len = asn_get_data_len (NULL, &asn, &id_cert);
+ id_cert += id_cert_len - 4;
+ memcpy (id_cert, id, 4);
+ }
+ }
+
+ res = 1;
+
+ done:
+ close (fd);
+
+ return res;
+}
+
+/* Retrieve the public key from a X509 Certificate */
+int
+x509_cert_get_key (u_int8_t *asn, u_int32_t asnlen, void *blob)
+{
+ struct rsa_public_key *key = blob;
+ struct x509_certificate cert;
+
+ if (!x509_decode_certificate (asn, asnlen, &cert))
+ return 0;
+
+ /* XXX - perhaps put into pkcs ? */
+ mpz_init_set (key->n, cert.key.n);
+ mpz_init_set (key->e, cert.key.e);
+
+ x509_free_certificate (&cert);
+
+ return 1;
+}
+
+/*
+ * Retrieve the public key from a X509 Certificate
+ * XXX - look at XXX below.
+ */
+
+int
+x509_cert_get_subject (u_int8_t *asn, u_int32_t asnlen,
+ u_int8_t **subject, u_int32_t *subjectlen)
+{
+ struct x509_certificate cert;
+
+ if (!x509_decode_certificate (asn, asnlen, &cert))
+ return 0;
+
+ if (cert.extension.type == NULL || cert.extension.val == NULL)
+ goto fail;
+
+ log_debug (LOG_CRYPTO, 60, "x509_cert_get_subject: Extension Type %s = %s",
+ cert.extension.type,
+ asn_parse_objectid (asn_ids, cert.extension.type));
+
+ if (strcmp (ASN_ID_SUBJECT_ALT_NAME, cert.extension.type))
+ {
+ log_print ("x509_cert_get_subject: extension type != subjectAltName");
+ goto fail;
+ }
+
+ /*
+ * XXX Evil**3, due to lack of time the IP encoding of subjectAltName
+ * is supposed to be: 0x30 0x06 0x087 0x04 aa bb cc dd, where the IPV4
+ * IP number is aa.bb.cc.dd.
+ */
+
+ if (asn_get_len (cert.extension.val) != 8 || cert.extension.val[3] != 4)
+ {
+ log_print ("x509_cert_get_subject: subjectAltName uses "
+ "unhandled encoding");
+ goto fail;
+ }
+
+ /* XXX - 4 bytes for IPV4 address */
+ *subject = malloc (4);
+ if (*subject == NULL)
+ {
+ log_print ("x509_cert_get_subject: out of memory");
+ goto fail;
+ }
+ *subjectlen = 4;
+ memcpy (*subject, cert.extension.val + 4, *subjectlen);
+
+ x509_free_certificate (&cert);
+
+ return 1;
+
+ fail:
+ x509_free_certificate (&cert);
+ return 0;
+}
+
+/* Initalizes the struct x509_attribval from a AtributeValueAssertion */
+
+void
+x509_get_attribval (struct norm_type *obj, struct x509_attribval *a)
+{
+ struct norm_type *tmp;
+
+ tmp = asn_decompose ("AttributeValueAssertion.AttributeType", obj);
+ if (tmp != NULL && tmp->data != NULL)
+ a->type = strdup ((char *)tmp->data);
+
+ tmp = asn_decompose ("AttributeValueAssertion.AttributeValue", obj);
+ if (tmp != NULL && tmp->data != NULL)
+ a->val = strdup ((char *)tmp->data);
+}
+
+/* Set's norm_type with values from x509_attribval */
+
+void
+x509_set_attribval (struct norm_type *obj, struct x509_attribval *a)
+{
+ struct norm_type *tmp;
+
+ tmp = asn_decompose ("AttributeValueAssertion.AttributeType", obj);
+ tmp->data = strdup (a->type);
+ tmp->len = strlen (tmp->data);
+ tmp = asn_decompose ("AttributeValueAssertion.AttributeValue", obj);
+ tmp->type = TAG_PRINTSTRING;
+ tmp->data = strdup (a->val);
+ tmp->len = strlen (tmp->data);
+}
+
+void
+x509_free_attribval (struct x509_attribval *a)
+{
+ if (a->type != NULL)
+ free (a->type);
+ if (a->val != NULL)
+ free (a->val);
+}
+
+void
+x509_free_certificate (struct x509_certificate *cert)
+{
+ pkcs_free_public_key (&cert->key);
+ if (cert->signaturetype != NULL)
+ free (cert->signaturetype);
+ if (cert->start != NULL)
+ free (cert->start);
+ if (cert->end != NULL)
+ free (cert->end);
+
+ x509_free_attribval (&cert->issuer1);
+ x509_free_attribval (&cert->issuer2);
+ x509_free_attribval (&cert->subject1);
+ x509_free_attribval (&cert->subject2);
+ x509_free_attribval (&cert->extension);
+}
+
+int
+x509_decode_certificate (u_int8_t *asn, u_int32_t asnlen,
+ struct x509_certificate *rcert)
+{
+ struct norm_type cert = SEQ ("cert", Certificate);
+ struct norm_type *tmp;
+ u_int8_t *data;
+ u_int32_t datalen;
+
+ /* Get access to the inner Certificate */
+ if (!x509_validate_signed (asn, asnlen, NULL, &data, &datalen))
+ return 0;
+
+ memset (rcert, 0, sizeof (*rcert));
+
+ if (asn_template_clone (&cert, 1) == NULL ||
+ asn_decode_sequence (data, datalen, &cert) == NULL)
+ goto fail;
+
+ tmp = asn_decompose ("cert.subjectPublicKeyInfo.subjectPublicKey", &cert);
+ if (!pkcs_public_key_from_asn (&rcert->key, tmp->data + 1, tmp->len - 1))
+ goto fail;
+
+ tmp = asn_decompose ("cert.version", &cert);
+ rcert->version = mpz_get_ui (tmp->data);
+ tmp = asn_decompose ("cert.serialNumber", &cert);
+ rcert->serialnumber = mpz_get_ui (tmp->data);
+ tmp = asn_decompose ("cert.signature.algorithm", &cert);
+ rcert->signaturetype = strdup ((char *)tmp->data);
+
+ tmp = asn_decompose ("cert.issuer.RelativeDistinguishedName."
+ "AttributeValueAssertion", &cert);
+ x509_get_attribval (tmp, &rcert->issuer1);
+ tmp = asn_decompose ("cert.issuer.RelativeDistinguishedName[1]."
+ "AttributeValueAssertion", &cert);
+ if (tmp != NULL)
+ x509_get_attribval (tmp, &rcert->issuer2);
+ else
+ rcert->issuer2.type = NULL;
+
+ tmp = asn_decompose ("cert.subject.RelativeDistinguishedName."
+ "AttributeValueAssertion", &cert);
+ x509_get_attribval (tmp, &rcert->subject1);
+ tmp = asn_decompose ("cert.subject.RelativeDistinguishedName[1]."
+ "AttributeValueAssertion", &cert);
+ if (tmp != NULL)
+ x509_get_attribval (tmp, &rcert->subject2);
+ else
+ rcert->subject2.type = NULL;
+
+ tmp = asn_decompose ("cert.validity.notBefore", &cert);
+ rcert->start = strdup ((char *)tmp->data);
+ tmp = asn_decompose ("cert.validity.notAfter", &cert);
+ rcert->end = strdup ((char *)tmp->data);
+
+ /* For x509v3 there might be an extension, try to decode it */
+ tmp = asn_decompose ("cert.extension", &cert);
+ if (tmp && tmp->data && rcert->version == 2)
+ x509_decode_cert_extension (tmp->data, tmp->len, rcert);
+
+ asn_free (&cert);
+ return 1;
+
+ fail:
+ x509_free_certificate (rcert);
+ asn_free (&cert);
+ return 0;
+}
+
+int
+x509_encode_certificate (struct x509_certificate *rcert,
+ u_int8_t **asn, u_int32_t *asnlen)
+{
+ struct norm_type cert = SEQ ("cert", Certificate);
+ struct norm_type *tmp;
+ u_int8_t *data, *new_buf;
+ mpz_t num;
+
+ if (asn_template_clone (&cert, 1) == NULL)
+ goto fail;
+
+ if (rcert->extension.type != NULL && rcert->extension.val != NULL)
+ {
+ u_int8_t *asn;
+ u_int32_t asnlen;
+
+ tmp = asn_decompose ("cert.extension", &cert);
+ if (x509_encode_cert_extension (rcert, &asn, &asnlen))
+ {
+ tmp->data = asn;
+ tmp->len = asnlen;
+ }
+ }
+
+ tmp = asn_decompose ("cert.subjectPublicKeyInfo.algorithm.parameters",
+ &cert);
+ tmp->type = TAG_NULL;
+ tmp = asn_decompose ("cert.subjectPublicKeyInfo.algorithm.algorithm",
+ &cert);
+ tmp->data = strdup (ASN_ID_RSAENCRYPTION);
+ tmp->len = strlen (tmp->data);
+
+ tmp = asn_decompose ("cert.subjectPublicKeyInfo.subjectPublicKey", &cert);
+ data = pkcs_public_key_to_asn (&rcert->key);
+ if (data == NULL)
+ goto fail;
+
+ /* This is a BIT STRING add 0 octet for padding */
+ tmp->len = asn_get_len (data);
+ new_buf = realloc (data, tmp->len + 1);
+ if (new_buf == NULL)
+ {
+ free (data);
+ goto fail;
+ }
+ data = new_buf;
+ memmove (data + 1, data, tmp->len);
+ data[0] = 0;
+ tmp->data = data;
+ tmp->len++;
+
+ mpz_init (num);
+ tmp = asn_decompose ("cert.version", &cert);
+ mpz_set_ui (num, rcert->version);
+ if (!pkcs_mpz_to_norm_type (tmp, num))
+ {
+ mpz_clear (num);
+ goto fail;
+ }
+
+ tmp = asn_decompose ("cert.serialNumber", &cert);
+ mpz_set_ui (num, rcert->serialnumber);
+ if (!pkcs_mpz_to_norm_type (tmp, num))
+ {
+ mpz_clear (num);
+ goto fail;
+ }
+ mpz_clear (num);
+
+ tmp = asn_decompose ("cert.signature.parameters", &cert);
+ tmp->type = TAG_NULL;
+ tmp = asn_decompose ("cert.signature.algorithm", &cert);
+ tmp->data = strdup (rcert->signaturetype);
+ tmp->len = strlen ((char *)tmp->data);
+
+ tmp = asn_decompose ("cert.issuer.RelativeDistinguishedName."
+ "AttributeValueAssertion", &cert);
+ x509_set_attribval (tmp, &rcert->issuer1);
+ tmp = asn_decompose ("cert.issuer.RelativeDistinguishedName[1]."
+ "AttributeValueAssertion", &cert);
+ x509_set_attribval (tmp, &rcert->issuer2);
+
+ tmp = asn_decompose ("cert.subject.RelativeDistinguishedName."
+ "AttributeValueAssertion", &cert);
+ x509_set_attribval (tmp, &rcert->subject1);
+ tmp = asn_decompose ("cert.subject.RelativeDistinguishedName[1]."
+ "AttributeValueAssertion", &cert);
+ x509_set_attribval (tmp, &rcert->subject2);
+
+ tmp = asn_decompose ("cert.validity.notBefore", &cert);
+ tmp->data = strdup (rcert->start);
+ tmp->len = strlen ((char *)tmp->data);
+
+ tmp = asn_decompose ("cert.validity.notAfter", &cert);
+ tmp->data = strdup (rcert->end);
+ tmp->len = strlen ((char *)tmp->data);
+
+ *asn = asn_encode_sequence (&cert, NULL);
+ if (*asn == NULL)
+ goto fail;
+
+ *asnlen = asn_get_len (*asn);
+
+ asn_free (&cert);
+ return 1;
+
+ fail:
+ asn_free (&cert);
+ return 0;
+}
+
+/*
+ * Decode an Extension to a X509 certificate.
+ * XXX - We ignore the critical boolean
+ */
+
+int
+x509_decode_cert_extension (u_int8_t *asn, u_int32_t asnlen,
+ struct x509_certificate *cert)
+{
+ struct norm_type *tmp;
+ struct norm_type ex = SEQOF ("ex", Extensions);
+
+ /* Implicit tagging for extension */
+ ex.class = ADD_EXP (3, UNIVERSAL);
+
+ if (asn_template_clone (&ex, 1) == NULL ||
+ asn_decode_sequence (asn, asnlen, &ex) == NULL)
+ {
+ asn_free (&ex);
+ return 0;
+ }
+
+ tmp = asn_decompose ("ex.extension.extnValue", &ex);
+ if (!tmp || tmp->data == NULL || asn_get_len (tmp->data) != tmp->len)
+ goto fail;
+ cert->extension.val = malloc (tmp->len);
+ if (cert->extension.val == 0)
+ goto fail;
+ memcpy (cert->extension.val, tmp->data, tmp->len);
+
+ tmp = asn_decompose ("ex.extension.extnId", &ex);
+ if (!tmp || tmp->data == NULL)
+ goto fail;
+ cert->extension.type = strdup (tmp->data);
+ if (cert->extension.type == NULL)
+ {
+ free (cert->extension.val);
+ cert->extension.val = NULL;
+ goto fail;
+ }
+
+ asn_free (&ex);
+ return 1;
+
+ fail:
+ asn_free (&ex);
+ return 0;
+}
+
+/*
+ * Encode a Cert Extension - XXX - only one extension per certificate
+ * XXX - We tag everything as critical
+ */
+
+int
+x509_encode_cert_extension (struct x509_certificate *cert,
+ u_int8_t **asn, u_int32_t *asnlen)
+{
+ struct norm_type ex = SEQ ("ex", Extensions);
+ struct norm_type *tmp;
+ ex.class = ADD_EXP (3, UNIVERSAL);
+
+ if (asn_template_clone (&ex ,1) == NULL)
+ goto fail;
+
+ tmp = asn_decompose ("ex.extension.extnId", &ex);
+ tmp->data = strdup (cert->extension.type);
+ tmp->len = strlen (tmp->data);
+
+ /* XXX - we mark every extension as critical */
+ tmp = asn_decompose ("ex.extension.critical", &ex);
+ if ((tmp->data = malloc (1)) == NULL)
+ goto fail;
+ *(u_int8_t *)tmp->data = 0xFF;
+ tmp->len = 1;
+
+ tmp = asn_decompose ("ex.extension.extnValue", &ex);
+ if ((tmp->data = malloc (asn_get_len (cert->extension.val))) == NULL)
+ goto fail;
+ tmp->len = asn_get_len (cert->extension.val);
+ memcpy (tmp->data, cert->extension.val, tmp->len);
+
+ *asn = asn_encode_sequence (&ex, NULL);
+ if (*asn == NULL)
+ goto fail;
+
+ *asnlen = asn_get_len (*asn);
+
+ asn_free (&ex);
+ return 1;
+ fail:
+ asn_free (&ex);
+ return 0;
+}
+
+/*
+ * Checks the signature on an ASN.1 Signed Type. If the passed Key is
+ * NULL we just unwrap the inner object and return it.
+ */
+
+int
+x509_validate_signed (u_int8_t *asn, u_int32_t asnlen,
+ struct rsa_public_key *key, u_int8_t **data,
+ u_int32_t *datalen)
+{
+ struct norm_type sig = SEQ("signed", Signed);
+ struct norm_type digest = SEQ("digest", DigestInfo);
+ struct norm_type *tmp;
+ struct hash *hash = NULL;
+ int res;
+ u_int8_t *dec;
+ u_int16_t declen;
+
+ if (asn_template_clone (&sig, 1) == NULL)
+ /* Failed, probably memory allocation, free what we got anyway */
+ goto fail;
+
+ if (asn_decode_sequence (asn, asnlen, &sig) == NULL)
+ {
+ log_print ("x509_validate_signed: input data could not be decoded");
+ goto fail;
+ }
+
+ tmp = asn_decompose ("signed.algorithm.algorithm", &sig);
+
+ if (!strcmp ((char *)tmp->data, ASN_ID_MD5WITHRSAENC))
+ {
+ hash = hash_get (HASH_MD5);
+ }
+ else
+ {
+ char *id = asn_parse_objectid (asn_ids, tmp->data);
+ log_print ("x509_validate_signed: can not handle SigType %s",
+ id == NULL ? tmp->data : id);
+ goto fail;
+ }
+
+ if (hash == NULL)
+ goto fail;
+
+ tmp = asn_decompose ("signed.data", &sig);
+ /* Hash the data */
+ hash->Init (hash->ctx);
+ hash->Update (hash->ctx, tmp->data, tmp->len);
+ hash->Final (hash->digest, hash->ctx);
+
+ *data = tmp->data;
+ *datalen = tmp->len;
+
+ /* Used to unwrap the SIGNED object around the Certificate */
+ if (key == NULL)
+ {
+ asn_free (&sig);
+ return 1;
+ }
+
+ tmp = asn_decompose ("signed.encrypted", &sig);
+ /*
+ * tmp->data is a BIT STRING, the first octet in the BIT STRING gives
+ * the padding bits at the end. Per definition there are no padding
+ * bits at the end in this case, so just skip it.
+ */
+ if (!pkcs_rsa_decrypt (PKCS_PRIVATE, key->n, key->e, tmp->data + 1,
+ &dec, &declen))
+ goto fail;
+
+ if (asn_template_clone (&digest, 1) == NULL ||
+ asn_decode_sequence (dec, declen, &digest) == NULL)
+ {
+ asn_free (&digest);
+ goto fail;
+ }
+ tmp = asn_decompose ("digest.digestAlgorithm.algorithm", &digest);
+ if (strcmp (ASN_ID_MD5, (char *)tmp->data))
+ {
+ log_print ("x509_validate_signed: DigestAlgorithm is not MD5");
+ res = 0;
+ }
+ else
+ {
+ tmp = asn_decompose ("digest.digest", &digest);
+ if (tmp->len != hash->hashsize ||
+ memcmp (tmp->data, hash->digest, tmp->len))
+ {
+ log_print ("x509_validate_signed: Digest does not match Data");
+ res = 0;
+ }
+ else
+ res = 1;
+ }
+
+ asn_free (&digest);
+ asn_free (&sig);
+ return res;
+
+ fail:
+ asn_free (&sig);
+ return 0;
+}
+
+/*
+ * Create an ASN Signed Structure from the data passed in data
+ * and return the result in asn.
+ * At the moment the used hash is MD5, this is the only common
+ * hash between us and X509.
+ */
+
+int
+x509_create_signed (u_int8_t *data, u_int32_t datalen,
+ struct rsa_private_key *key, u_int8_t **asn,
+ u_int32_t *asnlen)
+{
+ struct norm_type digest = SEQ ("digest", DigestInfo);
+ struct norm_type sig = SEQ ("signed", Signed);
+ struct norm_type *tmp;
+ struct hash *hash;
+ u_int8_t *diginfo, *enc;
+ u_int32_t enclen;
+ int res = 0;
+
+ /* Hash the Data */
+ hash = hash_get (HASH_MD5);
+ hash->Init (hash->ctx);
+ hash->Update (hash->ctx, data, datalen);
+ hash->Final (hash->digest, hash->ctx);
+
+ if (asn_template_clone (&digest, 1) == NULL)
+ goto fail;
+
+ tmp = asn_decompose ("digest.digest", &digest);
+ tmp->len = hash->hashsize;
+ tmp->data = malloc (hash->hashsize);
+ if (tmp->data == NULL)
+ goto fail;
+ memcpy (tmp->data, hash->digest, hash->hashsize);
+
+ tmp = asn_decompose ("digest.digestAlgorithm.parameters", &digest);
+ tmp->type = TAG_NULL;
+ tmp = asn_decompose ("digest.digestAlgorithm.algorithm", &digest);
+ tmp->data = strdup (ASN_ID_MD5);
+ tmp->len = strlen (tmp->data);
+
+ /* ASN encode Digest Information */
+ if ((diginfo = asn_encode_sequence (&digest, NULL)) == NULL)
+ goto fail;
+
+ /* Encrypt the Digest Info with Private Key */
+ res = pkcs_rsa_encrypt (PKCS_PRIVATE, key->n, key->d, diginfo,
+ asn_get_len (diginfo), &enc, &enclen);
+ free (diginfo);
+ if (!res)
+ goto fail;
+ res = 0;
+
+ if (asn_template_clone (&sig, 1) == NULL)
+ goto fail2;
+
+ tmp = asn_decompose ("signed.algorithm.parameters", &sig);
+ tmp->type = TAG_NULL;
+ tmp = asn_decompose ("signed.algorithm.algorithm", &sig);
+ tmp->data = strdup (ASN_ID_MD5WITHRSAENC);
+ tmp->len = strlen (tmp->data);
+
+ /* The type is BITSTING, i.e. first octet need to be zero */
+ tmp = asn_decompose ("signed.encrypted", &sig);
+ tmp->data = malloc (enclen + 1);
+ if (tmp->data == NULL)
+ {
+ free (enc);
+ goto fail2;
+ }
+ tmp->len = enclen + 1;
+ memcpy (tmp->data + 1, enc, enclen);
+ *(char *)tmp->data = 0;
+ free (enc);
+
+ tmp = asn_decompose ("signed.data", &sig);
+ tmp->data = data;
+ tmp->len = datalen;
+
+ *asn = asn_encode_sequence (&sig, NULL);
+ if (*asn == NULL)
+ goto fail2;
+ *asnlen = asn_get_len (*asn);
+
+ /* This is the data we have been given, we can not free it in asn_free */
+ tmp->data = NULL;
+ res = 1; /* Successfull */
+ fail2:
+ asn_free (&sig);
+ fail:
+ asn_free (&digest);
+ return res;
+}
diff --git a/sbin/isakmpd/x509.h b/sbin/isakmpd/x509.h
new file mode 100644
index 00000000000..577f858749a
--- /dev/null
+++ b/sbin/isakmpd/x509.h
@@ -0,0 +1,98 @@
+/* $Id: x509.h,v 1.1 1998/11/15 00:03:49 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998 Niels Provos. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ericsson Radio Systems.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _X509_H_
+#define _X509_H_
+
+#include "pkcs.h" /* for struct rsa_public_key */
+
+struct x509_attribval {
+ char *type;
+ char *val;
+};
+
+/*
+ * The acceptable certification authority
+ * XXX we only support two names at the moment, as of ASN this can
+ * be dynamic but we dont care for now.
+ */
+
+struct x509_aca {
+ struct x509_attribval name1;
+ struct x509_attribval name2;
+};
+
+struct exchange;
+
+struct x509_certificate {
+ u_int32_t version;
+ u_int32_t serialnumber;
+ char *signaturetype;
+ struct x509_attribval issuer1; /* At the moment Country */
+ struct x509_attribval issuer2; /* At the moment Organization */
+ struct x509_attribval subject1; /* At the moment Country */
+ struct x509_attribval subject2; /* At the moment Organization */
+ struct x509_attribval extension; /* Raw Extension */
+ char *start; /* Certificate Validity Start and End */
+ char *end;
+ struct rsa_public_key key;
+};
+
+int x509_certreq_validate (u_int8_t *, u_int32_t);
+void *x509_certreq_decode (u_int8_t *, u_int32_t);
+void x509_free_aca (void *);
+int x509_cert_obtain (struct exchange *, void *, u_int8_t **, u_int32_t *);
+int x509_cert_get_key (u_int8_t *, u_int32_t, void *);
+int x509_cert_get_subject (u_int8_t *, u_int32_t, u_int8_t **, u_int32_t *);
+
+void x509_get_attribval (struct norm_type *, struct x509_attribval *);
+void x509_set_attribval (struct norm_type *, struct x509_attribval *);
+void x509_free_attrbival (struct x509_attribval *);
+
+int x509_validate_signed (u_int8_t *, u_int32_t, struct rsa_public_key *,
+ u_int8_t **, u_int32_t *);
+int x509_create_signed (u_int8_t *, u_int32_t, struct rsa_private_key *,
+ u_int8_t **, u_int32_t *);
+int x509_decode_certificate (u_int8_t *, u_int32_t, struct x509_certificate *);
+int x509_encode_certificate (struct x509_certificate *, u_int8_t **,
+ u_int32_t *);
+void x509_free_certificate (struct x509_certificate *);
+
+int x509_decode_cert_extension (u_int8_t *, u_int32_t,
+ struct x509_certificate *);
+int x509_encode_cert_extension (struct x509_certificate *, u_int8_t **,
+ u_int32_t *);
+
+#endif /* _X509_H_ */