diff options
Diffstat (limited to 'keyexchange/isakmpd-20041012')
245 files changed, 58357 insertions, 0 deletions
diff --git a/keyexchange/isakmpd-20041012/.depend b/keyexchange/isakmpd-20041012/.depend new file mode 100644 index 0000000..42dbda6 --- /dev/null +++ b/keyexchange/isakmpd-20041012/.depend @@ -0,0 +1,211 @@ +app.o: app.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + app.h log.h +attribute.o: attribute.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + attribute.h conf.h log.h isakmp.h isakmp_fld.h field.h isakmp_num.h \ + constants.h util.h +cert.o: cert.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + isakmp_num.h constants.h log.h cert.h +connection.o: connection.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + conf.h connection.h doi.h ipsec.h ipsec_doi.h ipsec_fld.h field.h \ + ipsec_num.h constants.h isakmp.h isakmp_fld.h isakmp_num.h log.h \ + timer.h util.h +constants.o: constants.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + constants.h +conf.o: conf.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + app.h conf.h log.h util.h +cookie.o: cookie.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + cookie.h exchange.h exchange_num.h constants.h isakmp.h isakmp_fld.h \ + field.h isakmp_num.h hash.h transport.h message.h util.h +crypto.o: crypto.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + crypto.h log.h +dh.o: dh.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + math_group.h dh.h log.h +doi.o: doi.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + doi.h +exchange.o: exchange.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + cert.h conf.h connection.h constants.h cookie.h crypto.h doi.h \ + exchange.h exchange_num.h isakmp.h isakmp_fld.h field.h isakmp_num.h \ + ipsec_num.h libcrypto.h log.h message.h timer.h transport.h ipsec.h \ + ipsec_doi.h ipsec_fld.h sa.h util.h key.h +exchange_num.o: exchange_num.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + constants.h exchange_num.h +field.o: field.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + constants.h field.h log.h util.h +gmp_util.o: gmp_util.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + gmp_util.h math_mp.h +hash.o: hash.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + hash.h log.h +if.o: if.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + log.h if.h +ike_auth.o: ike_auth.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + cert.h conf.h constants.h exchange.h exchange_num.h isakmp.h \ + isakmp_fld.h field.h isakmp_num.h gmp_util.h math_mp.h hash.h \ + ike_auth.h ipsec.h ipsec_doi.h ipsec_fld.h ipsec_num.h libcrypto.h \ + log.h message.h prf.h transport.h util.h key.h +ike_main_mode.o: ike_main_mode.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + attribute.h conf.h constants.h crypto.h dh.h doi.h exchange.h \ + exchange_num.h isakmp.h isakmp_fld.h field.h isakmp_num.h hash.h \ + ike_auth.h ike_main_mode.h ike_phase_1.h ipsec.h ipsec_doi.h \ + ipsec_fld.h ipsec_num.h log.h math_group.h message.h prf.h sa.h \ + transport.h util.h +ike_phase_1.o: ike_phase_1.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + attribute.h conf.h constants.h crypto.h dh.h doi.h exchange.h \ + exchange_num.h isakmp.h isakmp_fld.h field.h isakmp_num.h hash.h \ + ike_auth.h ike_phase_1.h ipsec.h ipsec_doi.h ipsec_fld.h ipsec_num.h \ + log.h math_group.h message.h prf.h sa.h transport.h util.h +ike_quick_mode.o: ike_quick_mode.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + attribute.h conf.h connection.h dh.h doi.h exchange.h exchange_num.h \ + constants.h isakmp.h isakmp_fld.h field.h isakmp_num.h hash.h \ + ike_quick_mode.h ipsec.h ipsec_doi.h ipsec_fld.h ipsec_num.h log.h \ + math_group.h message.h policy.h prf.h sa.h transport.h util.h key.h +init.o: init.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + app.h cert.h conf.h connection.h doi.h exchange.h exchange_num.h \ + constants.h isakmp.h isakmp_fld.h field.h isakmp_num.h init.h ipsec.h \ + ipsec_doi.h ipsec_fld.h ipsec_num.h isakmp_doi.h libcrypto.h log.h \ + math_group.h sa.h timer.h transport.h message.h udp.h ui.h util.h +ipsec.o: ipsec.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + attribute.h conf.h constants.h crypto.h dh.h doi.h exchange.h \ + exchange_num.h isakmp.h isakmp_fld.h field.h isakmp_num.h hash.h \ + ike_aggressive.h ike_auth.h ike_main_mode.h ike_quick_mode.h ipsec.h \ + ipsec_doi.h ipsec_fld.h ipsec_num.h isakmp_cfg.h log.h math_group.h \ + message.h prf.h sa.h timer.h transport.h util.h x509.h libcrypto.h +ipsec_fld.o: ipsec_fld.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + constants.h field.h ipsec_fld.h isakmp_num.h ipsec_num.h +ipsec_num.o: ipsec_num.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + constants.h ipsec_num.h +isakmpd.o: isakmpd.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + app.h conf.h connection.h init.h libcrypto.h log.h sa.h isakmp.h \ + isakmp_fld.h field.h isakmp_num.h constants.h timer.h transport.h \ + message.h udp.h ui.h util.h cert.h +isakmp_doi.o: isakmp_doi.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + doi.h exchange.h exchange_num.h constants.h isakmp.h isakmp_fld.h \ + field.h isakmp_num.h isakmp_doi.h ipsec.h ipsec_doi.h ipsec_fld.h \ + ipsec_num.h log.h message.h sa.h util.h +isakmp_fld.o: isakmp_fld.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + constants.h field.h isakmp_fld.h isakmp_num.h ipsec_num.h +isakmp_num.o: isakmp_num.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + constants.h isakmp_num.h +key.o: key.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + key.h libcrypto.h log.h util.h x509.h +libcrypto.o: libcrypto.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + libcrypto.h +log.o: log.c sysdep/common/pcap.h isakmp_num.h sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + constants.h log.h +message.o: message.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + attribute.h cert.h constants.h crypto.h doi.h exchange.h \ + exchange_num.h isakmp.h isakmp_fld.h field.h isakmp_num.h ipsec_num.h \ + log.h message.h sa.h timer.h transport.h util.h +math_2n.o: math_2n.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + math_2n.h util.h +math_group.o: math_group.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + gmp_util.h math_mp.h log.h math_2n.h math_ec2n.h math_group.h +prf.o: prf.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + hash.h log.h prf.h +sa.o: sa.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + connection.h cookie.h doi.h exchange.h exchange_num.h constants.h \ + isakmp.h isakmp_fld.h field.h isakmp_num.h log.h message.h sa.h \ + timer.h transport.h util.h cert.h policy.h key.h ipsec.h ipsec_doi.h \ + ipsec_fld.h ipsec_num.h +sysdep.o: \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep.c \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/app.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/conf.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec_doi.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec_fld.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/field.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec_num.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/constants.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/klips.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/log.h +timer.o: timer.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + log.h timer.h +transport.o: transport.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + conf.h exchange.h exchange_num.h constants.h isakmp.h isakmp_fld.h \ + field.h isakmp_num.h log.h message.h sa.h timer.h transport.h +udp.o: udp.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + conf.h if.h isakmp.h isakmp_fld.h field.h isakmp_num.h constants.h \ + log.h message.h transport.h udp.h util.h +ui.o: ui.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + conf.h connection.h doi.h exchange.h exchange_num.h constants.h \ + isakmp.h isakmp_fld.h field.h isakmp_num.h init.h log.h sa.h timer.h \ + transport.h message.h ui.h util.h +util.o: util.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + log.h message.h isakmp.h isakmp_fld.h field.h isakmp_num.h \ + constants.h transport.h util.h +klips.o: \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/klips.c \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/conf.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/exchange.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/exchange_num.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/constants.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/isakmp.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/isakmp_fld.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/field.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/isakmp_num.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/hash.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec_doi.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec_fld.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec_num.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/log.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/klips.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sa.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/timer.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/transport.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/message.h +math_ec2n.o: ./math_ec2n.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + math_2n.h math_ec2n.h +ike_aggressive.o: ./ike_aggressive.c sysdep.h \ + /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ + attribute.h conf.h constants.h crypto.h dh.h doi.h exchange.h \ + exchange_num.h isakmp.h isakmp_fld.h field.h isakmp_num.h hash.h \ + ike_auth.h ike_aggressive.h ike_phase_1.h ipsec.h ipsec_doi.h \ + ipsec_fld.h ipsec_num.h log.h math_group.h message.h prf.h sa.h \ + transport.h util.h diff --git a/keyexchange/isakmpd-20041012/BUGS b/keyexchange/isakmpd-20041012/BUGS new file mode 100644 index 0000000..170282c --- /dev/null +++ b/keyexchange/isakmpd-20041012/BUGS @@ -0,0 +1,100 @@ +$OpenBSD: BUGS,v 1.14 2002/06/09 08:13:06 todd Exp $ +$EOM: BUGS,v 1.38 2000/02/18 08:47:35 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 terminates 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. [fixed] + +* IKE mandates that a HASH should be added to informational exchanges in + phase 2. [fixed] + +* 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. + +* Phase 1 rekey event removal seems to be done twice. [fixed] + +* PF_ENCAP expirations does not find the proper phase 2 SA to remove. [fixed] + +* ISAKMP SA expirations should have a soft/hard timeout just like IPsec ones. + The soft one should put a watchdog on the SA, and start a renegotiation as + soon as something used the SA. Hard ones should just clean it up, no + renegotiation at all. [fixed] + +* ISAKMP SAs does not get removed after rekeying. [fixed] + +* On-demand PF_ENCAP SAs does not get reestablished. [fixed] + +* Rekeying is now done automatically on expirations, it should not. The + SAs should be brought up on-demand just like the first time. + +* Notifications regarding exchange errors seems to not have the right SPI, + at least not in phase 1, in NO_PROPOSAL_CHOSEN. + +* Outgoing informational exchanges when we use INVALID_PAYLOAD_TYPE + cause a DOI error. + +* In Linux select(2) of named pipes seems broken as they will return as + readable even when nothing is there after one read has succeeded. + +* I have seen INITIAL-CONTACT sent on the second Main Mode. + +* When ID mismatches occur, coredumps may follow, investigate! + +* ESP+AH does not work properly + +* Looping QM seen (due to lost sendpackets from other participant?) + +* Teardown from UI does not remove exchanges. + +* Wrong error message when policy check fails. + +* Restransmit of QM (packet 1) after INFO/PAYLOAD_MALFORMED was received. + +* SIGSEGV after sa_enter: sa added to sa list, trigged by DELETE notify (Linux) + +* Passive connections, undefined local&remote IDs will cause IKE peer IDs + to be used. + +* host route support in KLIPS does not work properly + +* When not having compiled in support for a certain crypto algorithm and + the config file still tells us to propose it, we segfault. diff --git a/keyexchange/isakmpd-20041012/DESIGN-NOTES b/keyexchange/isakmpd-20041012/DESIGN-NOTES new file mode 100644 index 0000000..b47e80b --- /dev/null +++ b/keyexchange/isakmpd-20041012/DESIGN-NOTES @@ -0,0 +1,414 @@ +$OpenBSD: DESIGN-NOTES,v 1.22 2003/06/04 07:27:31 ho Exp $ +$EOM: DESIGN-NOTES,v 1.48 1999/08/12 22:34:25 niklas Exp $ + +General coding conventions +-------------------------- +GNU indentation, Max 80 characters per line, KNF comments, mem* instead of b*, +BSD copyright, 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. + +GCC -Wall clean, ANSI prototypes. System dependent facilities should be +named sysdep_* and be placed in sysdep.c. Every C file should include +sysdep.h as the first isakmpd include file. Primary target systems are OpenBSD +and Linux, but porting to Microsoft Windows variants should not be made +overly difficult. + +Note places which need reconsiderations with comments starting with the +string "XXX", e.g. + +/* XXX Not implemented yet. */ + +TOC +--- +app.c Application support. +attribute.c Attribute handling. +cert.c Dispatching certificate related functions to the according + module based on the encoding. +conf.c Interface to isakmpd configuration. +connection.c Handle the high-level connection concept. +constants.c Value to name map of constants. +cookie.c Cookie generation. +crypto.c Generic cryptography. +dh.c Diffie-Hellman exchange logic. +dnssec.c IKE authentication using signed DNS KEY RRs. +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_aggressive.c + IKE's aggressive mode exchange logic. +ike_auth.c IKE authentication method abstraction. +ike_main_mode.c IKE's main mode exchange logic. +ike_phase_1.c Common parts IKE's main & aggressive modes' 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. +key.c Generic key handling. +libcrypto.c Initialize crypto (OpenSSL). +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_key_v2.c Interface with PF_KEY sockets (for use with IPsec). +policy.c Keynote glue. +prf.c Pseudo random functions. +sa.c Handling of Security Associations (SAs). +sysdep/*/sysdep.c + System dependent stuff. +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 connection Persistent connections. +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 deleting 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. Right now I have introduced a name +for SAs, non-unique, that binds together SAs and their configuration +parameters. This means both manual exchange runs and rekeying are simpler. +Both struct exchange and struct sa does hold a reference count, but this is +not entirely like a reference count in the traditional meaning where +every reference gets counted. Perhaps it will be in the future, but for now +we increment the count at allocation time and at times we schedule events +tha might happen sometime in the future where we will need the structure. +These events then realeases its reference when done. This way intermediate +deallocation of these structures are OK. + +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. As the code looks now, exchanges +*are* an abstraction in the code, and it has proven to be a rather nice +way of having things. + +When the exchange has been found the exchange engine "runs" a script which +steps forward for each incoming message, and on each reply to them. + +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, eleven such commands are implemented: + +c connect Establish a connection with a peer +C configure Add or remove configuration entries +d delete Delete an SA given cookies and message-IDs +D debug Change logging level for a debug class +p packet capture Enable/disable packet capture feature +r report Report status information of the daemon +t teardown Teardown a connection +Q quit Quit the isakmpd process +R reinitialize Reinitialize isakmpd (re-read configuration file) +S report SA Report SA information to file /var/run/isakmp_sa +T teardown all Teardown all Phase 2 connections + +For example you can do: + +c ISAKMP-peer + +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 "C" command takes 3 subcommands: set, rm and rms, for adding and removing +entries + remove complete sections respectively. Examples: + +C set [Net-A]:Address=192.168.0.0 +C rm [Net-A]:Address +C rms [Net-A] + +All these commands are atomic, i.e. they are not collected into larger +transactions, which there should be a way to do, but currently isn't. + +The FIFO UI is also described in the isakmpd(8) man page. + +In addition to giving commands over the FIFO, you may send signals to the +daemon. Currently two such signals are implemented: + +SIGHUP Re-initialize isakmpd (not fully implemented yet) +SIGUSR1 Generate a report, much as the "r" FIFO command. + +For example, to generate a report, you do: + +unix# kill -USR1 <PID of isakmpd process> + +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 lengths. +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. + +Configuration +------------- + +Internally isakmpd uses a section-tag-value triplet database for +configuration. Currently this happen to map really well to the +configuration file format, which on the other hand does not map +equally well to humans. It is envisioned that the configuration +database should be dynamically modifiable, and through a lot of +differnet mechanisms. Therefore we have designed an API for this +purpose. + +int conf_begin (); +int conf_set (int transaction, char *section, char *tag, char *value, + int override); +int conf_remove (int transaction, char *section, char *tag); +int conf_remove_section (int transaction, char *section); +int conf_end (int transaction, int commit); + +The caller will always be responsible for the memory management of the +passed strings, conf_set will copy the values, and not use the original +strings after it has returned. Return value will be zero on success and +non-zero otherwise. Note that the conf_remove* functions consider not +finding anything to remove as failure. + +Identification +-------------- + +ISAKMP supports a lot of identity types, and we should too of course. + +* Phase 1, Main mode or Aggressive 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. + +* Phase 2, 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. +Otherwise we today support IPV4_ADDR & IPV4_ADDR_SUBNET as ID types. + +X509-Certificates +----------------- +To use RSA Signature mode you are required to generate certificates. +This can be done with ssleay, see man ssl. But the X509 certificates +require a subjectAltname extension that can either be an IPV4 address, +a User-FQDN or just FQDN. ssleay can not create those extension, +insead use the x509test program in regress/x509 to modify an existing +certificate. It will insert the subjectAltname extension and sign it +with the provided private Key. The resulting certificate then needs +to be stored in the directory pointed to by "Certs-directory" in +section "X509-certificates". + +License to use +-------------- +/* + * Copyright (c) 1999 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. + * + * 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. + */ + diff --git a/keyexchange/isakmpd-20041012/GNUmakefile b/keyexchange/isakmpd-20041012/GNUmakefile new file mode 100644 index 0000000..838194c --- /dev/null +++ b/keyexchange/isakmpd-20041012/GNUmakefile @@ -0,0 +1,244 @@ +# $OpenBSD: GNUmakefile,v 1.9 2004/08/08 19:11:06 deraadt Exp $ + +# +# Copyright (c) 1998, 1999, 2000 Niklas Hallqvist. All rights reserved. +# Copyright (c) 2000 Håkan Olsson. 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. +# +# 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 makefile is a GNU makefile, which is generally available on most +# systems, either as "make" or (often) "gmake". It has been converted from +# a 'pmake' makefile (OpenBSDs 'make'), and some care has been taken to +# produce similar behaviour. +# + +# openbsd means 2.5 or newer, freeswan is the name for Linux with FreeS/WAN +# integrated, freebsd/netbsd means FreeBSD/NetBSD with KAME IPsec. +# darwin means MacOS X 10.2 and later with KAME IPsec. linux means Linux-2.5 +# and later with native IPSec support. +#OS= openbsd +#OS= netbsd +#OS= freebsd +#OS= freeswan +#OS= darwin +OS= linux + +.CURDIR:= $(shell pwd) +VPATH= ${.CURDIR}/sysdep/${OS} + +PROG= isakmpd + +ifndef BINDIR +BINDIR= /sbin +endif + +#ifndef LDSTATIC +#LDSTATIC= -static +#endif + +SRCS= app.c attribute.c cert.c connection.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_phase_1.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 key.c libcrypto.c log.c message.c \ + math_2n.c math_group.c prf.c sa.c sysdep.c timer.c \ + transport.c udp.c ui.c util.c virtual.c + +GENERATED= exchange_num.h ipsec_fld.h ipsec_num.h isakmp_fld.h \ + isakmp_num.h +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 isakmpd.policy.5 + +CFLAGS+= -O2 ${DEBUG} -Wall -DNEED_SYSDEP_APP \ + -I${.CURDIR} -I${.CURDIR}/sysdep/${OS} -I. \ + +# Different debugging & profiling suggestions + +# Include symbolic debugging info +DEBUG= -g + +# Do execution time profiles +#CFLAGS+= -pg + +# If you have ElectricFence available, you can spot abuses of the heap. +# (/usr/ports/devel/ElectricFence) +#LDADD+= -L/usr/local/lib -lefence +#DPADD+= /usr/local/lib/libefence.a + +# If you like to use Boehm's garbage collector (/usr/ports/devel/boehm-gc). +#LDADD+= -L/usr/local/lib -lgc +#DPADD+= /usr/local/lib/libgc.a + +# You can also use Boehm's garbage collector as a means to find leaks. +# XXX The defines below are GCC-specific. I think it is OK to require +# XXX GCC if you are debugging isakmpd in this way. +#LDADD+= -L/usr/local/lib -lleak +#DPADD+= /usr/local/lib/libleak.a +#CFLAGS+= -D'malloc(x)=({ \ +# void *GC_debug_malloc (size_t, char *, int); \ +# GC_debug_malloc ((x), __FILE__, __LINE__); \ +# })' \ +# -D'realloc(x,y)=({ \ +# void *GC_debug_realloc (void *, size_t, char *, int); \ +# GC_debug_realloc ((x), (y), __FILE__, __LINE__); \ +# })' \ +# -D'free(x)=({ \ +# void GC_debug_free (void *); \ +# GC_debug_free (x); \ +# })' \ +# -D'calloc(x,y)=malloc((x) * (y))' \ +# -D'strdup(x)=({ \ +# char *strcpy (char *, const char *); \ +# const char *_x_ = (x); \ +# char *_y_ = malloc (strlen (_x_) + 1); \ +# strcpy (_y_, _x_); \ +# })' + +# Ignore any files with these names... +.PHONY: mksubdirs all clean cleandir cleandepend beforedepend \ + afterdepend realclean realcleandepend + +# Default target, it needs to be the first target in makefile... :( + +all: ${PROG} mksubdirs + +ifneq ($(findstring install,$(MAKECMDGOALS)),install) +# Skip 'regress' until the regress/ structure has gmake makefiles for it. +#SUBDIR:= regress +SUBDIR:= apps/certpatch +mksubdirs: + $(foreach DIR, ${SUBDIR}, \ + cd ${.CURDIR}/${DIR}; ${MAKE} ${MAKECMDGOALS};) + +# $(foreach DIR, ${SUBDIR}, \ +# cd ${DIR}; ${MAKE} CFLAGS="${CFLAGS}" \ +# MKDEP="${MKDEP}" ${MAKECMDGOALS}) +else +mksubdirs: +endif + +# DEPSRCS handling is *ugly*, I know... +# What is does; keep orig SRCS in ORIGSRCS; potentially add stuff to +# SRCS (include); let DEPSRCS be ORIGSRCS (sysdep.c -> sysdep/<os>/sysdep.c) +# _plus_ any new sources, located either in cwd or sysdep/<os>. Phew. + +ORIGSRCS:= ${SRCS} +-include sysdep/${OS}/GNUmakefile.sysdep + +FEATURES_UC= $(shell echo ${FEATURES} | tr '[:lower:]' '[:upper:]') +CFLAGS+= $(foreach F, ${FEATURES_UC}, -DUSE_${F}) +-include $(foreach F, ${FEATURES}, features/${F}) + +ifdef USE_KEYNOTE +USE_LIBCRYPTO= yes +LDADD+= -lkeynote -lm +DPADD+= ${LIBKEYNOTE} ${LIBM} +POLICY= policy.c +CFLAGS+= -DUSE_KEYNOTE +endif + +ifdef USE_LIBCRYPTO +X509= x509.c +CFLAGS+= -DUSE_LIBCRYPTO +LDADD+= -lcrypto +DPADD+= ${LIBCRYPTO} +endif + +ifdef USE_RAWKEY +USE_LIBCRYPTO= yes +CFLAGS+= -DUSE_RAWKEY +endif + +SRCS+= ${IPSEC_SRCS} ${X509} ${POLICY} ${EC} ${AGGRESSIVE} ${DNSSEC} \ + $(ISAKMP_CFG) ${DPD} ${NAT_TRAVERSAL} +CFLAGS+= ${IPSEC_CFLAGS} +LDADD+= ${DESLIB} +DPADD+= ${DESLIBDEP} + +DEPSRCS:= $(subst sysdep.c,${VPATH}/sysdep.c,${ORIGSRCS}) \ + $(foreach FILE, $(filter-out ${ORIGSRCS},${SRCS}), \ + $(wildcard ./${FILE} ${VPATH}/${FILE})) +OBJS:= $(SRCS:%.c=%.o) + +# Generated targets +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 + +# Program rules +${PROG} beforedepend: ${GENERATED} + +${PROG}: ${OBJS} ${DPADD} + ${CC} ${DEBUG} ${LDFLAGS} ${LDSTATIC} -o $@ ${OBJS} ${LDADD} + +# Depend rules +depend: beforedepend .depend mksubdirs afterdepend + @true + +# Since 'mkdep' et al maybe doesn't exist... +MKDEP:= ${CC} -MM + +.depend: ${SRCS} + @rm -f .depend + ${MKDEP} ${CFLAGS} ${DEPSRCS} > .depend + +afterdepend: + +ifneq ($(findstring clean, $(MAKECMDGOALS)), clean) +# This will initially fail (when .depend does not exist), continue +# to create .depend, then make will automatically restart to include +# the generated .depend correctly. The '-' inhibits the warning msg. +-include .depend +endif + +# Clean rules + +cleandir: realclean realcleandepend mksubdirs + +clean: realclean mksubdirs + +cleandepend: realcleandepend mksubdirs + +realclean: + rm -f a.out core *.core ${PROG} ${OBJS} ${CLEANFILES} + +realcleandepend: + rm -f .depend tags diff --git a/keyexchange/isakmpd-20041012/Makefile b/keyexchange/isakmpd-20041012/Makefile new file mode 100644 index 0000000..2c04d8b --- /dev/null +++ b/keyexchange/isakmpd-20041012/Makefile @@ -0,0 +1,187 @@ +# $OpenBSD: Makefile,v 1.57 2004/08/23 11:16:49 ho Exp $ +# $EOM: Makefile,v 1.78 2000/10/15 21:33:42 niklas Exp $ + +# +# Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. +# Copyright (c) 2000, 2001 Håkan Olsson. 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. +# +# 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 makefile is a "pmake" one, i.e. the make variant commonly found in +# BSD derived systems, where it is indeed named "make". Other systems +# may provide this make variant as "pmake" or maybe "bsdmake". +# + +# openbsd means OpenBSD 2.5 or newer. freeswan is the name for Linux with +# FreeS/WAN integrated, freebsd/netbsd means FreeBSD/NetBSD with KAME IPsec. +OS= openbsd +#OS= netbsd +#OS= freebsd +#OS= freeswan +#OS= bsdi + +# Compile-time configuration of otherwise optional features +#FEATURES= tripledes des blowfish cast aes +#FEATURES+= policy x509 ec aggressive debug gmp +#FEATURES+= rawkey isakmp_cfg dnssec privsep nat_traversal dpd +FEATURES= tripledes des blowfish cast aes +FEATURES+= policy x509 ec aggressive debug +FEATURES+= rawkey isakmp_cfg privsep nat_traversal dpd + +.PATH: ${.CURDIR}/sysdep/${OS} + +PROG= isakmpd +BINDIR?= /sbin +LDSTATIC?= -static +SRCS= app.c attribute.c cert.c connection.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_phase_1.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 \ + key.c libcrypto.c log.c message.c math_2n.c math_group.c \ + prf.c sa.c sysdep.c timer.c transport.c virtual.c udp.c \ + ui.c util.c + +GENERATED= exchange_num.h ipsec_fld.h ipsec_num.h isakmp_fld.h \ + isakmp_num.h +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 isakmpd.policy.5 +CFLAGS+= -Wall -Wstrict-prototypes -Wmissing-prototypes \ + -Wmissing-declarations -DNEED_SYSDEP_APP \ + -I${.CURDIR} -I${.CURDIR}/sysdep/${OS} -I. +#CFLAGS+= -Wsign-compare -Werror + +# Different debugging & profiling suggestions + +# Include symbolic debugging info +#DEBUG= -g # OpenBSD +#DEBUG_FLAGS= -g # FreeBSD +#CFLAGS+= -g # NetBSD and others +#STRIPFLAG= # NETBSD + +# Do execution time profiles +#CFLAGS+= -pg + +# If you have ElectricFence available, you can spot abuses of the heap. +# (/usr/ports/devel/ElectricFence) +#LDADD+= -L/usr/local/lib -lefence +#DPADD+= /usr/local/lib/libefence.a + +# If you like to use Boehm's garbage collector (/usr/ports/devel/boehm-gc). +#LDADD+= -L/usr/local/lib -lgc +#DPADD+= /usr/local/lib/libgc.a +#CFLAGS+= -DUSE_BOEHM_GC -DGC_DEBUG +# You can also use Boehm's garbage collector as a means to find leaks. +# # setenv GC_FIND_LEAK + +SUBDIR= apps + +.include "sysdep/${OS}/Makefile.sysdep" + +.if ${FEATURES} != "" +FEATURES_UC!= echo ${FEATURES} | tr '[:lower:]' '[:upper:]' +CFLAGS+= ${FEATURES_UC:S/^/-DUSE_/g} +.endif + +.if make(install) +SUBDIR+= samples +.endif + +.if !make(install) && !defined(NO_REGRESS) +SUBDIR+= regress +.endif + +.for FEATURE in ${FEATURES} +.if exists(features/${FEATURE}) +.include "features/${FEATURE}" +.endif +.endfor + +.if ${FEATURES:Mgmp} == "gmp" +CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_GMP +LDADD+= -lgmp +DPADD+= ${LIBGMP} +.else +CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL +.endif + +.ifdef USE_KEYNOTE +USE_LIBCRYPTO= yes +USE_LIBDES= yes +LDADD+= -lkeynote -lm +DPADD+= ${LIBKEYNOTE} ${LIBM} +CFLAGS+= -DUSE_KEYNOTE +.endif + +.ifdef USE_RAWKEY +USE_LIBCRYPTO= yes +CFLAGS+= -DUSE_RAWKEY +.endif + +.ifdef USE_LIBCRYPTO +CFLAGS+= -DUSE_LIBCRYPTO +LDADD+= -lcrypto +DPADD+= ${LIBCRYPTO} +.endif + +.ifdef USE_LIBDES +CFLAGS+= -DUSE_LIBDES +LDADD+= -ldes +DPADD+= ${LIBDES} +.endif + +SRCS+= ${IPSEC_SRCS} ${X509} ${POLICY} ${EC} ${AGGRESSIVE} ${DNSSEC} \ + ${ISAKMP_CFG} ${PRIVSEP} ${DPD} ${NAT_TRAVERSAL} +CFLAGS+= ${IPSEC_CFLAGS} ${DNSSEC_CFLAGS} + +LDADD+= ${DESLIB} ${LWRESLIB} +DPADD+= ${DESLIBDEP} ${LWRESLIB} + +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 + +${PROG} beforedepend: ${GENERATED} + +.include <bsd.prog.mk> +.include <bsd.subdir.mk> + +debug: + (cd ${.CURDIR}; ${MAKE} DEBUG="-g -Werror") diff --git a/keyexchange/isakmpd-20041012/QUESTIONS b/keyexchange/isakmpd-20041012/QUESTIONS new file mode 100644 index 0000000..91225cc --- /dev/null +++ b/keyexchange/isakmpd-20041012/QUESTIONS @@ -0,0 +1,34 @@ +$OpenBSD: QUESTIONS,v 1.5 2003/11/05 12:31:21 jmc Exp $ +$EOM: QUESTIONS,v 1.12 1998/10/11 17:11:06 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/1363/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/keyexchange/isakmpd-20041012/README b/keyexchange/isakmpd-20041012/README new file mode 100644 index 0000000..13df6a1 --- /dev/null +++ b/keyexchange/isakmpd-20041012/README @@ -0,0 +1,68 @@ +$OpenBSD: README,v 1.19 2003/02/22 06:57:07 kjell Exp $ +$EOM: README,v 1.28 1999/10/10 22:53:24 angelos 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. Isakmpd's home is in the +OpenBSD main source tree under src/sbin/isakmpd. Look at +http://www.openbsd.org/ for details on how to get OpenBSD source. + +Isakmpd is being developed under OpenBSD, with OpenBSD as its primary +target, however, it is ported to Linux with FreeS/WAN IPsec. The +makefile support assumes a BSD environment nonetheless as it is not too +hard to get such an environment to work under other operating systems. +For example, Red Hat 5.2 shipped with pmake installed. Read sysdep/README +for further details about this issue. Other systems isakmpd has been +ported to, but no code has been made available for, includes Solaris +and Win32s. I mention this just because it shows that the code is +fairly portable. + +First edit the Makefile in a manner you see fit. Specifically the OS +define is important to get right of course. +Assuming you have an OpenBSD /usr/share/mk and use the OpenBSD (or +similar) make(1), you build isakmpd this way: + +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 -DA=99 -f/tmp/isakmpd.fifo -csamples/VPN-east.conf + +That will run isakmpd in the foreground, not connected to any application +(like an IPsec implementation) logging to stderr with full debugging output, +listening on UDP port 5000, accepting control commands via the named pipe +called /tmp/isakmpd.fifo and reading its configuration from the +VPN-east.conf file (found in the isakmpd/samples 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. + +The logging classes are Miscellaneous = 0, Transports = 1, Messages = 2, +Crypto = 3, Timers = 4, System Dependencies = 5, Security Associations = 6, +and Exchanges = 7. The debug levels increase in verbosity from 0 (off) to +99 (max). 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 edit the config +file to have some peer descriptions that fit your need and issue a +command like this: + +$ echo "c IPsec-east-west" >/tmp/other.fifo + +and watch. You can turn on debugging on that isakmpd too of course, for +greater fun. This rudimentary user interface is slightly described in +DESIGN-NOTES. If you are going to look at the config file, don't be scared, +the man page isakmpd.conf(5) covers every detail, and the flexibility will +be hidden under a userfriendlier layer in a later release. I did this +first config-file syntax just because it should be easy to parse. The man +page isakmpd.policy(5) describes the policy model used in conjunction with +KeyNote. + +Happy IKEing! + +Niklas Hallqvist <niklas@openbsd.org> +Niels Provos <provos@openbsd.org> +Håkan Olsson <ho@openbsd.org> diff --git a/keyexchange/isakmpd-20041012/README.PKI b/keyexchange/isakmpd-20041012/README.PKI new file mode 100644 index 0000000..4b7d9f1 --- /dev/null +++ b/keyexchange/isakmpd-20041012/README.PKI @@ -0,0 +1,60 @@ +$OpenBSD: README.PKI,v 1.7 1999/10/01 14:10:45 niklas Exp $ +$EOM: README.PKI,v 1.7 1999/09/30 13:40:38 niklas Exp $ + +1 Make sure you have an RSA-enabled isakmpd. An easy way to do this + is to install a dynamically linkable version of libcrypto from + OpenSSL and install it where the run-time linker can find it. + +2 Create your own CA as root. + + openssl genrsa -out /etc/ssl/private/ca.key 1024 + openssl req -new -key /etc/ssl/private/ca.key \ + -out /etc/ssl/private/ca.csr + + You are now being asked to enter information that will be incorporated + into your certificate request. What you are about to enter is what is + called a Distinguished Name or a DN. There are quite a few fields but + you can leave some blank. For some fields there will be a default + value, if you enter '.', the field will be left blank. + + openssl x509 -req -days 365 -in /etc/ssl/private/ca.csr \ + -signkey /etc/ssl/private/ca.key \ + -out /etc/ssl/ca.crt + +3 Create keys and certificates for your isakmpd peers. This step as well + as the next one, needs to be done for every peer. Furthermore the + last step will need to be done once for each ID you want the peer + to have. The 10.0.0.1 below symbolizes that ID, and should be + changed for each invocation. You will be asked for a DN for each + run too. See to encode the ID in the common name too, so it gets + unique. + + openssl genrsa -out /etc/isakmpd/private/local.key 1024 + openssl req -new -key /etc/isakmpd/private/local.key \ + -out /etc/isakmpd/private/10.0.0.1.csr + + Now take these certificate signing requests to your CA and process + them like below. You have to add some extensions to the certificate + in order to make it usable for isakmpd, which is why you will need + to run certpatch. Replace 10.0.0.1 with the IP-address which isakmpd + will be using for identity. + + openssl x509 -req -days 365 -in 10.0.0.1.csr -CA /etc/ssl/ca.crt \ + -CAkey /etc/ssl/private/ca.key -CAcreateserial \ + -out 10.0.0.1.crt + certpatch -i 10.0.0.1 -k /etc/ssl/private/ca.key \ + 10.0.0.1.crt 10.0.0.1.crt + + Put the certificate (the file ending in .crt) in /etc/isakmpd/certs/ + on your local system. Also carry over the CA cert /etc/ssl/ca.crt + and put it in /etc/isakmpd/ca/. + +4 See to that your config files will point out the directories where + you keep certificates. I.e. add something like this to + /etc/isakmpd/isakmpd.conf: + + # Certificates stored in PEM format + [X509-certificates] + CA-directory= /etc/isakmpd/ca/ + Cert-directory= /etc/isakmpd/certs/ + Private-key= /etc/isakmpd/private/local.key diff --git a/keyexchange/isakmpd-20041012/TO-DO b/keyexchange/isakmpd-20041012/TO-DO new file mode 100644 index 0000000..7e397e4 --- /dev/null +++ b/keyexchange/isakmpd-20041012/TO-DO @@ -0,0 +1,145 @@ +$OpenBSD: TO-DO,v 1.26 2003/08/28 14:43:35 markus Exp $ +$EOM: TO-DO,v 1.45 2000/04/07 22:47:38 niklas Exp $ + +This file mixes small nitpicks with large projects to be done. + +* 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?). [done] + +* 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. [done] + +* Retransmission timing & count adaptivity and configurability. + [configurability done] + +* Quick mode exchanges [done] + +* Aggressive mode exchange. [done] + +* 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. [done] + +* 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. [generation done] + +* Deal well with incoming informational exchanges. [done] + +* Generate all possible SA attributes in quick mode. [done] + +* Validate incoming attribute according to policy, main mode. [done] + +* Validate incoming attribute according to policy, quick mode. [done] + +* 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. [done] + +* Validate the configuration file. + +* Do a soft-limit on ISAKMP SA lifetime. [done] + +* Let the hard-limit on ISAKMP SA lifetime destroy the SA ASAP. [done] + +* IPsec rekeying. [done] + +* Store tunnels into SPD, and handle acquire SA events. [done] + +* If an exchange is on-going when a rekey event happens, drop the request. + [done] + +* INITIAL CONTACT notification sending when appropriate. [done] + +* INITIAL CONTACT notification handling. [done] + +* IPsec SAs could also do with timers protecting its lifetime, if say, + someone changed the lifetime of the IPsec SA in stack under us. [done] + +* Handle notifications showing the peer did not want to continue this exchange. + +* Flexible identification. + +* Remove referring flows when a SPI is removed. [done] + +* IPCOMP. + +* Acknowledged notification exchange. + +* Tiger hash. + +* El-Gamal public key encryption. + +* Check of attributes not being changed by the responder in phase 2. + +* See to the commit bit will never be used in phase 1. Give INVALID-FLAGS + if seeing it. + +* Base mode. + +* IKECFG [protocol done, configuration controls remain] + +* XAUTH framework. + +* PKCS#11 + +* XAUTH hybrid frame work. + +* Specify extra certificates to send somehow. + +* Handle CERTs anywhere in an exchange. + +* Add a way to do multiple configuration commands via ui. + +* Replace ui's fifo with a slightly more versatile interface. + +* Report current configuration. [done] + +* IPv6 [done] + +* AES in phase 1 [done] + +* x509_certreq_validate needs implementing. + +* Smartcard support. diff --git a/keyexchange/isakmpd-20041012/app.c b/keyexchange/isakmpd-20041012/app.c new file mode 100644 index 0000000..a04aa14 --- /dev/null +++ b/keyexchange/isakmpd-20041012/app.c @@ -0,0 +1,63 @@ +/* $OpenBSD: app.c,v 1.9 2004/04/15 18:39:25 deraadt Exp $ */ +/* $EOM: app.c,v 1.6 1999/05/01 20:21:06 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999 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. + * + * 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 "sysdep.h" + +#include "app.h" +#include "log.h" + +int app_socket; + +/* Set this to not get any applications setup. */ +int app_none = 0; + +/* Initialize applications. */ +void +app_init(void) +{ + 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(void) +{ + sysdep_app_handler(app_socket); +} diff --git a/keyexchange/isakmpd-20041012/app.h b/keyexchange/isakmpd-20041012/app.h new file mode 100644 index 0000000..96a2864 --- /dev/null +++ b/keyexchange/isakmpd-20041012/app.h @@ -0,0 +1,42 @@ +/* $OpenBSD: app.h,v 1.7 2004/04/15 18:39:25 deraadt Exp $ */ +/* $EOM: app.h,v 1.4 1999/04/02 00:58:16 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999 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. + * + * 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_conf_init_hook(void); +extern void app_handler(void); +extern void app_init(void); + +#endif /* _APP_H_ */ diff --git a/keyexchange/isakmpd-20041012/apps/Makefile b/keyexchange/isakmpd-20041012/apps/Makefile new file mode 100644 index 0000000..7d1bbe9 --- /dev/null +++ b/keyexchange/isakmpd-20041012/apps/Makefile @@ -0,0 +1,34 @@ +# $OpenBSD: Makefile,v 1.2 2003/06/03 14:35:00 ho Exp $ +# $EOM: Makefile,v 1.2 1999/07/17 20:44:12 niklas Exp $ + +# +# Copyright (c) 1999 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. +# +# 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= certpatch + +#.include <bsd.subdir.mk> diff --git a/keyexchange/isakmpd-20041012/apps/certpatch/.cvsignore b/keyexchange/isakmpd-20041012/apps/certpatch/.cvsignore new file mode 100644 index 0000000..6203864 --- /dev/null +++ b/keyexchange/isakmpd-20041012/apps/certpatch/.cvsignore @@ -0,0 +1,3 @@ +certpatch +certpatch.cat8 +obj diff --git a/keyexchange/isakmpd-20041012/apps/certpatch/GNUmakefile b/keyexchange/isakmpd-20041012/apps/certpatch/GNUmakefile new file mode 100644 index 0000000..3cd8e3a --- /dev/null +++ b/keyexchange/isakmpd-20041012/apps/certpatch/GNUmakefile @@ -0,0 +1,55 @@ +# $OpenBSD: Makefile,v 1.7 2003/06/03 14:35:00 ho Exp $ +# $EOM: Makefile,v 1.6 2000/03/28 21:22:06 ho Exp $ + +# +# Copyright (c) 1999 Niels Provos. All rights reserved. +# Copyright (c) 2001 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. +# +# 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= certpatch +SRCS= certpatch.c +BINDIR?= /usr/sbin +TOPSRC= ${.CURDIR}../.. +TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- +OS= linux +FEATURES!= awk '/^FEATURES=/ { print $$0 }' ${.CURDIR}/../../Makefile | sed 's/FEATURES=.//' +.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} +CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall +LDFLAGS+= -lcrypto -lssl -lgmp +MAN= certpatch.8 + +CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_GMP +LDADD+= -lgmp +DPADD+= ${LIBGMP} + +# Override LIBSYSDEPDIR definition from Makefile.sysdep +LIBSYSDEPDIR= ${TOPSRC}/sysdep/common/libsysdep + +all: ${PROG} + +clean: + rm -f ${PROG} diff --git a/keyexchange/isakmpd-20041012/apps/certpatch/Makefile b/keyexchange/isakmpd-20041012/apps/certpatch/Makefile new file mode 100644 index 0000000..c422938 --- /dev/null +++ b/keyexchange/isakmpd-20041012/apps/certpatch/Makefile @@ -0,0 +1,58 @@ +# $OpenBSD: Makefile,v 1.7 2003/06/03 14:35:00 ho Exp $ +# $EOM: Makefile,v 1.6 2000/03/28 21:22:06 ho Exp $ + +# +# Copyright (c) 1999 Niels Provos. All rights reserved. +# Copyright (c) 2001 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. +# +# 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= certpatch +SRCS= certpatch.c +BINDIR?= /usr/sbin +TOPSRC= ${.CURDIR}/../.. +TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- +OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile +FEATURES!= awk '/^FEATURES=/ { print $$0 }' ${.CURDIR}/../../Makefile | sed 's/FEATURES=.//' +.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} +CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall +LDADD+= -lcrypto +DPADD+= ${LIBCRYPTO} +MAN= certpatch.8 + +.if ${FEATURES:Mgmp} == "gmp" +CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_GMP +LDADD+= -lgmp +DPADD+= ${LIBGMP} +.else +CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL +.endif + +.include "${TOPSRC}/sysdep/${OS}/Makefile.sysdep" +# Override LIBSYSDEPDIR definition from Makefile.sysdep +LIBSYSDEPDIR= ${TOPSRC}/sysdep/common/libsysdep + +.include <bsd.prog.mk> diff --git a/keyexchange/isakmpd-20041012/apps/certpatch/certpatch.8 b/keyexchange/isakmpd-20041012/apps/certpatch/certpatch.8 new file mode 100644 index 0000000..1c1b629 --- /dev/null +++ b/keyexchange/isakmpd-20041012/apps/certpatch/certpatch.8 @@ -0,0 +1,85 @@ +.\" $OpenBSD: certpatch.8,v 1.8 2003/06/04 07:31:17 ho Exp $ +.\" $EOM: certpatch.8,v 1.5 2000/04/07 22:17:11 niklas Exp $ +.\" +.\" Copyright (c) 1999 Niklas Hallqvist. All rights reserved. +.\" Copyright (c) 1999 Angelos D. Keromytis. 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. +.\" +.\" 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 18, 1999 +.Dt CERTPATCH 8 +.Os +.Sh NAME +.Nm certpatch +.Nd add subjectAltName identities to X.509 certificates +.Sh SYNOPSIS +.Nm certpatch +.Op Fl t Ar identity-type +.Fl i +.Ar identity +.Fl k +.Ar signing-key +.Ar input-certificate output-certificate +.Sh DESCRIPTION +.Nm +alters PEM-encoded X.509 certificates by adding a subjectAltName extension +containing an identity used by the signature-based authentication schemes +of the ISAKMP protocol. +After the addition the certificate will be signed +once again with the supplied CA signing key. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl t Ar identity-type +If given, the +.Fl t +option specifies the type of the given identity. +Currently +.Li ip , +.Li fqdn , +and +.Li ufqdn +are recognized. +The default is +.Li ip . +.It Fl i Ar identity +The +.Fl i +option takes an argument which is the identity to put into the +subjectAltName field of the certificate. +If the identity-type is +.Li ip , +this argument should be an IPv4 address in dotted decimal notation. +.It Fl k Ar signing-key +The +.Fl k +option specifies the key used for signing the certificate once the +subjectAltName extension has been added. +The key is specified by +the filename where it is stored in PEM format. +.El +.Sh SEE ALSO +.Xr isakmpd 8 , +.Xr ssl 8 diff --git a/keyexchange/isakmpd-20041012/apps/certpatch/certpatch.c b/keyexchange/isakmpd-20041012/apps/certpatch/certpatch.c new file mode 100644 index 0000000..0a0125a --- /dev/null +++ b/keyexchange/isakmpd-20041012/apps/certpatch/certpatch.c @@ -0,0 +1,317 @@ +/* $OpenBSD: certpatch.c,v 1.21 2003/06/04 07:31:17 ho Exp $ */ +/* $EOM: certpatch.c,v 1.11 2000/12/21 14:50:09 ho Exp $ */ + +/* + * Copyright (c) 1999 Niels Provos. All rights reserved. + * Copyright (c) 1999, 2000 Angelos D. Keromytis. All rights reserved. + * Copyright (c) 2000, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2001 Håkan Olsson. 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. + * + * 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 program takes a certificate generated by ssleay and a + * private key. It encodes a new id as subject alt name + * extension into the certifcate. The result gets written as + * new certificate that can be used by isakmpd. + */ + +#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 <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include "sysdep.h" + +#ifdef KAME +# ifdef CRYPTO +# include <openssl/rsa.h> +# endif +#else +# include <openssl/rsa.h> +#endif + +#include <openssl/x509.h> +#include <openssl/pem.h> + +#include "conf.h" +#include "ipsec_num.h" +#include "log.h" +#include "math_mp.h" +#include "x509.h" + +#define IDTYPE_IP "ip" +#define IDTYPE_FQDN "fqdn" +#define IDTYPE_UFQDN "ufqdn" + +int +main (int argc, char **argv) +{ + char *usage = "%s [-t idtype] -i id -k keyfile certin certout\n\n" + "This programs takes a certificate and adds a subjectAltName extension\n" + "with the identication given as command line argument. Be sure that \n" + "the signing key matches the issuer.\n"; + EVP_PKEY *pkey_priv; + X509 *cert; + BIO *file; + const EVP_MD *digest; + X509_EXTENSION *ex = NULL; + ASN1_OCTET_STRING *data = NULL; + struct in_addr saddr; + unsigned char ipaddr[6], *new_id; + char *type = IDTYPE_IP, *keyfile = NULL, *id = NULL; + char *certin, *certout; + int ch, err; + +#if SSLEAY_VERSION_NUMBER >= 0x00904100L + unsigned char *p; + ASN1_STRING str; + int i; +#endif + + + /* read command line arguments */ + while ((ch = getopt (argc, argv, "t:k:i:")) != -1) + switch (ch) { + case 't': + type = optarg; + break; + case 'k': + keyfile = optarg; + break; + case 'i': + id = optarg; + break; + default: + fprintf (stderr, usage, argv[0]); + return (1); + } + + argc -= optind; + + if (argc != 2) { + fprintf (stderr, usage, argv[0]); + return (1); + } + + argv += optind; + + certin = argv[0]; + certout = argv[1]; + + /* Check ID */ + + if ((strcasecmp (IDTYPE_IP, type) != 0 && + strcasecmp (IDTYPE_FQDN, type) != 0 && + strcasecmp (IDTYPE_UFQDN, type) != 0) || id == NULL) + { + printf ("wrong id type or missing id\n"); + return (1); + } + + /* + * X509_verify will fail, as will all other functions that call + * EVP_get_digest_byname. + */ + + SSLeay_add_all_algorithms (); + + /* Use a certificate created by ssleay and add the appr. extension */ + printf ("Reading ssleay created certificate %s and modify it\n", + certin); + file = BIO_new (BIO_s_file ()); + if (BIO_read_filename (file, certin) == -1) + { + perror ("read"); + return (1); + } +#if SSLEAY_VERSION_NUMBER >= 0x00904100L + cert = PEM_read_bio_X509 (file, NULL, NULL, NULL); +#else + cert = PEM_read_bio_X509 (file, NULL, NULL); +#endif + BIO_free (file); + if (cert == NULL) + { + printf ("PEM_read_bio_X509 () failed\n"); + return (1); + } + + /* Get the digest for the actual signing */ + digest = EVP_get_digestbyname (OBJ_nid2sn (OBJ_obj2nid (cert->sig_alg->algorithm))); + + if (!X509_set_version (cert, 2)) + { + printf ("X509 failed to set version number\n"); + return (1); + } + + if (!strcasecmp (IDTYPE_IP, type)) + { + if (inet_aton (id, &saddr) == 0) + { + printf ("inet_aton () failed\n"); + return (1); + } + + saddr.s_addr = htonl (saddr.s_addr); + ipaddr[0] = 0x87; + ipaddr[1] = 0x04; + ipaddr[2] = saddr.s_addr >> 24; + ipaddr[3] = (saddr.s_addr >> 16) & 0xff; + ipaddr[4] = (saddr.s_addr >> 8) & 0xff; + ipaddr[5] = saddr.s_addr & 0xff; + +#if SSLEAY_VERSION_NUMBER >= 0x00904100L + str.length = 6; + str.type = V_ASN1_OCTET_STRING; + str.data = ipaddr; + data = ASN1_OCTET_STRING_new (); + if (!data) + { + perror ("ASN1_OCTET_STRING_new() failed"); + return (1); + } + + i = i2d_ASN1_OCTET_STRING ((ASN1_OCTET_STRING *)&str, NULL); + if (!ASN1_STRING_set ((ASN1_STRING *)data,NULL,i)) + { + perror ("ASN1_STRING_set() failed"); + return (1); + } + p = (unsigned char *)data->data; + i2d_ASN1_OCTET_STRING ((ASN1_OCTET_STRING *)&str, &p); + data->length = i; +#else + data = X509v3_pack_string (NULL, V_ASN1_OCTET_STRING, ipaddr, 6); +#endif + } + else if (!strcasecmp (IDTYPE_FQDN, type) || !strcasecmp (IDTYPE_UFQDN, type)) + { + new_id = malloc (strlen (id) + 2); + if (new_id == NULL) + { + printf ("malloc () failed\n"); + return (1); + } + + if (!strcasecmp (IDTYPE_FQDN, type)) + new_id[0] = 0x82; + else + new_id[0] = 0x81; /* IDTYPE_UFQDN */ + + memcpy (new_id + 2, id, strlen(id)); + new_id[1] = strlen (id); +#if SSLEAY_VERSION_NUMBER >= 0x00904100L + str.length = strlen (id) + 2; + str.type = V_ASN1_OCTET_STRING; + str.data = new_id; + data = ASN1_OCTET_STRING_new (); + if (!data) + { + perror ("ASN1_OCTET_STRING_new() failed"); + return (1); + } + + i = i2d_ASN1_OCTET_STRING ((ASN1_OCTET_STRING *)&str, NULL); + if (!ASN1_STRING_set ((ASN1_STRING *)data,NULL,i)) + { + perror ("ASN1_STRING_set() failed"); + return (1); + } + p = (unsigned char *)data->data; + i2d_ASN1_OCTET_STRING ((ASN1_OCTET_STRING *)&str, &p); + data->length = i; +#else + data = X509v3_pack_string (NULL, V_ASN1_OCTET_STRING, new_id, + strlen (id) + 2); +#endif + free (new_id); + } + + /* XXX This is a hack, how to do better? */ + data->type = 0x30; + data->data[0] = 0x30; + ex = X509_EXTENSION_create_by_NID (NULL, NID_subject_alt_name, 1, data); + + if (ex == NULL) + { + printf ("X509_EXTENSION_create ()\n"); + return (1); + } + + X509_add_ext (cert, ex, -1); + + file = BIO_new (BIO_s_file ()); + if (BIO_read_filename (file, keyfile) == -1) + { + perror ("open"); + return (1); + } +#if SSLEAY_VERSION_NUMBER >= 0x00904100L + if ((pkey_priv = PEM_read_bio_PrivateKey (file, NULL, NULL, NULL)) == NULL) +#else + if ((pkey_priv = PEM_read_bio_PrivateKey (file, NULL, NULL)) == NULL) +#endif + { + printf ("Can not read private key %s\n", keyfile); + return (1); + } + BIO_free (file); + + printf ("Creating Signature: PKEY_TYPE = %s: ", + pkey_priv->type == EVP_PKEY_RSA ? "RSA" : "unknown"); + err = X509_sign (cert, pkey_priv, digest); + printf ("X509_sign: %d ", err); + if (!err) + printf ("FAILED "); + else + printf ("OKAY "); + printf ("\n"); + + file = BIO_new (BIO_s_file ()); + if (BIO_write_filename (file, certout) == -1) + { + perror ("open"); + return (1); + } + + printf ("Writing new certificate to %s\n", certout); + PEM_write_bio_X509 (file, cert); + BIO_free (file); + + return (0); +} diff --git a/keyexchange/isakmpd-20041012/attribute.c b/keyexchange/isakmpd-20041012/attribute.c new file mode 100644 index 0000000..362805b --- /dev/null +++ b/keyexchange/isakmpd-20041012/attribute.c @@ -0,0 +1,112 @@ +/* $OpenBSD: attribute.c,v 1.11 2004/05/14 08:42:56 hshoexer Exp $ */ +/* $EOM: attribute.c,v 1.10 2000/02/20 19:58:36 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999 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. + * + * 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 "sysdep.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; +} + +/* + * Execute a function FUNC taking an attribute type, value, length and ARG + * as arguments for each attribute in the area of ISAKMP attributes located + * at BUF, sized SZ. If any invocation fails, the processing aborts with a + * -1 return value. If all goes well return zero. + */ +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) { + LOG_DBG((LOG_MISC, 70, + "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/keyexchange/isakmpd-20041012/attribute.h b/keyexchange/isakmpd-20041012/attribute.h new file mode 100644 index 0000000..aa835cf --- /dev/null +++ b/keyexchange/isakmpd-20041012/attribute.h @@ -0,0 +1,47 @@ +/* $OpenBSD: attribute.h,v 1.6 2004/05/14 08:42:56 hshoexer Exp $ */ +/* $EOM: attribute.h,v 1.2 1998/09/29 21:51:07 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. + * + * 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/keyexchange/isakmpd-20041012/cert.c b/keyexchange/isakmpd-20041012/cert.c new file mode 100644 index 0000000..d04b964 --- /dev/null +++ b/keyexchange/isakmpd-20041012/cert.c @@ -0,0 +1,160 @@ +/* $OpenBSD: cert.c,v 1.28 2004/06/14 09:55:41 ho Exp $ */ +/* $EOM: cert.c,v 1.18 2000/09/28 12:53:27 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999 Niels Provos. All rights reserved. + * Copyright (c) 1999, 2000 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. + * + * 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 "sysdep.h" + +#include "isakmp_num.h" +#include "log.h" +#include "cert.h" + +#ifdef USE_X509 +#include "x509.h" +#endif + +#ifdef USE_KEYNOTE +#include "policy.h" +#endif + +struct cert_handler cert_handler[] = { +#ifdef USE_X509 + { + ISAKMP_CERTENC_X509_SIG, + x509_cert_init, x509_crl_init, x509_cert_get, x509_cert_validate, + x509_cert_insert, x509_cert_free, + x509_certreq_validate, x509_certreq_decode, x509_free_aca, + x509_cert_obtain, x509_cert_get_key, x509_cert_get_subjects, + x509_cert_dup, x509_serialize, x509_printable, x509_from_printable + }, +#endif +#ifdef USE_KEYNOTE + { + ISAKMP_CERTENC_KEYNOTE, + keynote_cert_init, NULL, keynote_cert_get, keynote_cert_validate, + keynote_cert_insert, keynote_cert_free, + keynote_certreq_validate, keynote_certreq_decode, keynote_free_aca, + keynote_cert_obtain, keynote_cert_get_key, keynote_cert_get_subjects, + keynote_cert_dup, keynote_serialize, keynote_printable, + keynote_from_printable + }, +#endif +}; + +/* Initialize all certificate handlers */ +int +cert_init(void) +{ + size_t i; + int err = 1; + + for (i = 0; i < sizeof cert_handler / sizeof cert_handler[0]; i++) + if (cert_handler[i].cert_init && + !(*cert_handler[i].cert_init)()) + err = 0; + + return err; +} + +int +crl_init(void) +{ + size_t i; + int err = 1; + + for (i = 0; i < sizeof cert_handler / sizeof cert_handler[0]; i++) + if (cert_handler[i].crl_init && !(*cert_handler[i].crl_init)()) + err = 0; + + return err; +} + +struct cert_handler * +cert_get(u_int16_t id) +{ + size_t i; + + for (i = 0; i < sizeof cert_handler / sizeof cert_handler[0]; i++) + if (id == cert_handler[i].id) + return &cert_handler[i]; + return 0; +} + +/* + * Decode the certificate request of type TYPE contained in DATA extending + * DATALEN bytes. Return a certreq_aca structure which the caller is + * responsible for deallocating. + */ +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; + + handler = cert_get(type); + if (!handler) + return 0; + + aca.id = type; + aca.handler = handler; + + if (datalen > 0) { + aca.data = handler->certreq_decode(data, datalen); + if (!aca.data) + return 0; + } else + aca.data = 0; + + ret = malloc(sizeof aca); + if (!ret) { + log_error("certreq_decode: malloc (%lu) failed", + (unsigned long)sizeof aca); + handler->free_aca(aca.data); + return 0; + } + memcpy(ret, &aca, sizeof aca); + return ret; +} + +void +cert_free_subjects(int n, u_int8_t **id, u_int32_t *len) +{ + int i; + + for (i = 0; i < n; i++) + free(id[i]); + free(id); + free(len); +} diff --git a/keyexchange/isakmpd-20041012/cert.h b/keyexchange/isakmpd-20041012/cert.h new file mode 100644 index 0000000..151b2f9 --- /dev/null +++ b/keyexchange/isakmpd-20041012/cert.h @@ -0,0 +1,96 @@ +/* $OpenBSD: cert.h,v 1.14 2004/05/14 08:42:56 hshoexer Exp $ */ +/* $EOM: cert.h,v 1.8 2000/09/28 12:53:27 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999 Niels Provos. All rights reserved. + * Copyright (c) 2000, 2001 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. + * + * 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> + +/* + * CERT handler for each kind of certificate: + * + * cert_init - initialize CERT handler. + * crl_init - initialize CRLs, if applicable. + * cert_get - get a certificate in internal representation from raw data. + * cert_validate - validated a certificate, if it returns != 0 we can use it. + * cert_insert - inserts cert into memory storage, we can retrieve with + * cert_obtain. + * cert_dup - duplicate a certificate + * cert_serialize - convert to a "serialized" form; KeyNote stays the same, + * X509 is converted to the ASN1 notation. + * cert_printable - for X509, the hex representation of the serialized form; + * for KeyNote, itself. + * cert_from_printable - the reverse of cert_printable + */ + +struct cert_handler { + u_int16_t id; /* ISAKMP Cert Encoding ID */ + int (*cert_init)(void); + int (*crl_init)(void); + void *(*cert_get)(u_int8_t *, u_int32_t); + int (*cert_validate)(void *); + int (*cert_insert)(int, void *); + void (*cert_free)(void *); + 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)(u_int8_t *, size_t, void *, u_int8_t **, + u_int32_t *); + int (*cert_get_key) (void *, void *); + int (*cert_get_subjects) (void *, int *, u_int8_t ***, + u_int32_t **); + void *(*cert_dup) (void *); + void (*cert_serialize) (void *, u_int8_t **, u_int32_t *); + char *(*cert_printable) (void *); + void *(*cert_from_printable) (char *); +}; + +/* The acceptable authority of cert request. */ +struct certreq_aca { + TAILQ_ENTRY(certreq_aca) link; + + u_int16_t id; + struct cert_handler *handler; + + /* If data is a null pointer, everything is acceptable. */ + void *data; +}; + +struct certreq_aca *certreq_decode(u_int16_t, u_int8_t *, u_int32_t); +void cert_free_subjects(int, u_int8_t **, u_int32_t *); +struct cert_handler *cert_get(u_int16_t); +int cert_init(void); +int crl_init(void); + +#endif /* _CERT_H_ */ diff --git a/keyexchange/isakmpd-20041012/conf.c b/keyexchange/isakmpd-20041012/conf.c new file mode 100644 index 0000000..0eaa1e9 --- /dev/null +++ b/keyexchange/isakmpd-20041012/conf.c @@ -0,0 +1,1123 @@ +/* $OpenBSD: conf.c,v 1.73 2004/08/08 19:11:06 deraadt Exp $ */ +/* $EOM: conf.c,v 1.48 2000/12/04 02:04:29 angelos Exp $ */ + +/* + * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2000, 2001, 2002 Håkan Olsson. 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. + * + * 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/mman.h> +#include <sys/queue.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <ctype.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +#include "sysdep.h" + +#include "app.h" +#include "conf.h" +#include "log.h" +#include "monitor.h" +#include "util.h" + +static char *conf_get_trans_str(int, char *, char *); +static void conf_load_defaults(int); +#if 0 +static int conf_find_trans_xf(int, char *); +#endif + +struct conf_trans { + TAILQ_ENTRY(conf_trans) link; + int trans; + enum conf_op { + CONF_SET, CONF_REMOVE, CONF_REMOVE_SECTION + } op; + char *section; + char *tag; + char *value; + int override; + int is_default; +}; + +#define CONF_SECT_MAX 256 + +TAILQ_HEAD(conf_trans_head, conf_trans) conf_trans_queue; + +/* + * 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; + int is_default; +}; + +char *conf_path = CONFIG_FILE; +LIST_HEAD(conf_bindings, conf_binding) conf_bindings[256]; + +static char *conf_addr; +static __inline__ u_int8_t +conf_hash(char *s) +{ + u_int8_t hash = 0; + + while (*s) { + hash = ((hash << 1) | (hash >> 7)) ^ tolower(*s); + s++; + } + return hash; +} + +/* + * Insert a tag-value combination from LINE (the equal sign is at POS) + */ +static int +conf_remove_now(char *section, char *tag) +{ + struct conf_binding *cb, *next; + + for (cb = LIST_FIRST(&conf_bindings[conf_hash(section)]); cb; + cb = next) { + next = LIST_NEXT(cb, link); + if (strcasecmp(cb->section, section) == 0 + && strcasecmp(cb->tag, tag) == 0) { + LIST_REMOVE(cb, link); + LOG_DBG((LOG_MISC, 95, "[%s]:%s->%s removed", section, + tag, cb->value)); + free(cb->section); + free(cb->tag); + free(cb->value); + free(cb); + return 0; + } + } + return 1; +} + +static int +conf_remove_section_now(char *section) +{ + struct conf_binding *cb, *next; + int unseen = 1; + + for (cb = LIST_FIRST(&conf_bindings[conf_hash(section)]); cb; + cb = next) { + next = LIST_NEXT(cb, link); + if (strcasecmp(cb->section, section) == 0) { + unseen = 0; + LIST_REMOVE(cb, link); + LOG_DBG((LOG_MISC, 95, "[%s]:%s->%s removed", section, + cb->tag, cb->value)); + free(cb->section); + free(cb->tag); + free(cb->value); + free(cb); + } + } + return unseen; +} + +/* + * Insert a tag-value combination from LINE (the equal sign is at POS) + * into SECTION of our configuration database. + */ +static int +conf_set_now(char *section, char *tag, char *value, int override, + int is_default) +{ + struct conf_binding *node = 0; + + if (override) + conf_remove_now(section, tag); + else if (conf_get_str(section, tag)) { + if (!is_default) + log_print("conf_set_now: duplicate tag [%s]:%s, " + "ignoring...\n", section, tag); + return 1; + } + node = calloc(1, sizeof *node); + if (!node) { + log_error("conf_set_now: calloc (1, %lu) failed", + (unsigned long)sizeof *node); + return 1; + } + node->section = strdup(section); + node->tag = strdup(tag); + node->value = strdup(value); + node->is_default = is_default; + + LIST_INSERT_HEAD(&conf_bindings[conf_hash(section)], node, link); + LOG_DBG((LOG_MISC, 95, "conf_set_now: [%s]:%s->%s", node->section, + node->tag, node->value)); + return 0; +} + +/* + * 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(int trans, char *line, size_t sz) +{ + char *val; + size_t i; + int j; + static char *section = 0; + static int ln = 0; + + ln++; + + /* 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 (section) + free(section); + if (i == sz) { + log_print("conf_parse_line: %d:" + "unmatched ']', ignoring until next section", ln); + section = 0; + return; + } + section = malloc(i); + if (!section) { + log_print("conf_parse_line: %d: malloc (%lu) failed", + ln, (unsigned long)i); + return; + } + strlcpy(section, line + 1, i); + return; + } + /* Deal with assignments. */ + for (i = 0; i < sz; i++) + if (line[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; + } + line[strcspn(line, " \t=")] = '\0'; + val = line + i + 1 + strspn(line + i + 1, " \t"); + /* Skip trailing whitespace, if any */ + for (j = sz - (val - line) - 1; j > 0 && + isspace(val[j]); j--) + val[j] = '\0'; + /* XXX Perhaps should we not ignore errors? */ + conf_set(trans, section, line, val, 0, 0); + return; + } + /* Other non-empty lines are weird. */ + i = strspn(line, " \t"); + if (line[i]) + log_print("conf_parse_line: %d: syntax error", ln); +} + +/* Parse the mapped configuration file. */ +static void +conf_parse(int trans, char *buf, size_t sz) +{ + char *cp = buf; + char *bufend = buf + sz; + char *line; + + line = cp; + while (cp < bufend) { + if (*cp == '\n') { + /* Check for escaped newlines. */ + if (cp > buf && *(cp - 1) == '\\') + *(cp - 1) = *cp = ' '; + else { + *cp = '\0'; + conf_parse_line(trans, line, cp - line); + line = cp + 1; + } + } + cp++; + } + if (cp != line) + log_print("conf_parse: last line unterminated, ignored."); +} + +/* + * Auto-generate default configuration values for the transforms and + * suites the user wants. + * + * Resulting section names can be: + * For main mode: + * {DES,BLF,3DES,CAST,AES}-{MD5,SHA}[-GRP{1,2,5,14}][-{DSS,RSA_SIG}] + * For quick mode: + * QM-{proto}[-TRP]-{cipher}[-{hash}][-PFS[-{group}]]-SUITE + * where + * {proto} = ESP, AH + * {cipher} = DES, 3DES, CAST, BLF, AES + * {hash} = MD5, SHA, RIPEMD, SHA2-{-256,384,512} + * {group} = GRP1, GRP2, GRP5, GRP14 + * + * DH group defaults to MODP_1024. + * + * XXX We may want to support USE_BLOWFISH, USE_TRIPLEDES, etc... + * XXX No EC2N DH support here yet. + */ + +/* Find the value for a section+tag in the transaction list. */ +static char * +conf_get_trans_str(int trans, char *section, char *tag) +{ + struct conf_trans *node, *nf = 0; + + for (node = TAILQ_FIRST(&conf_trans_queue); node; + node = TAILQ_NEXT(node, link)) + if (node->trans == trans && strcasecmp(section, node->section) + == 0 && strcasecmp(tag, node->tag) == 0) { + if (!nf) + nf = node; + else if (node->override) + nf = node; + } + return nf ? nf->value : 0; +} + +#if 0 +/* XXX Currently unused. */ +static int +conf_find_trans_xf(int phase, char *xf) +{ + struct conf_trans *node; + char *p; + + /* Find the relevant transforms and suites, if any. */ + for (node = TAILQ_FIRST(&conf_trans_queue); node; + node = TAILQ_NEXT(node, link)) + if ((phase == 1 && strcmp("Transforms", node->tag) == 0) || + (phase == 2 && strcmp("Suites", node->tag) == 0)) { + p = node->value; + while ((p = strstr(p, xf)) != NULL) + if (*(p + strlen(p)) && + *(p + strlen(p)) != ',') + p += strlen(p); + else + return 1; + } + return 0; +} +#endif + +static void +conf_load_defaults_mm(int tr, char *mme, char *mmh, char *mma, char *dhg, + char *mme_p, char *mma_p, char *dhg_p) +{ + char sect[CONF_SECT_MAX]; + + snprintf(sect, sizeof sect, "%s-%s%s%s", mme_p, mmh, dhg_p, mma_p); + + LOG_DBG((LOG_MISC, 95, "conf_load_defaults_mm: main mode %s", sect)); + + conf_set(tr, sect, "ENCRYPTION_ALGORITHM", mme, 0, 1); + if (strcmp(mme, "BLOWFISH_CBC") == 0) + conf_set(tr, sect, "KEY_LENGTH", CONF_DFLT_VAL_BLF_KEYLEN, 0, + 1); + else if (strcmp(mme, "AES_CBC") == 0) + conf_set(tr, sect, "KEY_LENGTH", CONF_DFLT_VAL_AES_KEYLEN, 0, + 1); + + conf_set(tr, sect, "HASH_ALGORITHM", mmh, 0, 1); + conf_set(tr, sect, "AUTHENTICATION_METHOD", mma, 0, 1); + conf_set(tr, sect, "GROUP_DESCRIPTION", dhg, 0, 1); + conf_set(tr, sect, "Life", CONF_DFLT_TAG_LIFE_MAIN_MODE, 0, 1); +} + +static void +conf_load_defaults_qm(int tr, char *qme, char *qmh, char *dhg, char *qme_p, + char *qmh_p, char *dhg_p, int proto, int mode, int pfs) +{ + char sect[CONF_SECT_MAX], tmp[CONF_SECT_MAX]; + + /* Helper #defines, incl abbreviations. */ +#define PROTO(x) ((x) ? "AH" : "ESP") +#define PFS(x) ((x) ? "-PFS" : "") +#define MODE(x) ((x) ? "TRANSPORT" : "TUNNEL") +#define MODE_p(x) ((x) ? "-TRP" : "") + + if (proto == 1 && strcmp(qmh, "NONE") == 0) /* AH */ + return; + + snprintf(tmp, sizeof tmp, "QM-%s%s%s%s%s%s", PROTO(proto), + MODE_p(mode), qme_p, qmh_p, PFS(pfs), dhg_p); + + strlcpy(sect, tmp, CONF_SECT_MAX); + strlcat(sect, "-SUITE", CONF_SECT_MAX); + + LOG_DBG((LOG_MISC, 95, "conf_load_defaults_qm: quick mode %s", sect)); + + conf_set(tr, sect, "Protocols", tmp, 0, 1); + snprintf(sect, sizeof sect, "IPSEC_%s", PROTO(proto)); + conf_set(tr, tmp, "PROTOCOL_ID", sect, 0, 1); + strlcpy(sect, tmp, CONF_SECT_MAX); + strlcat(sect, "-XF", CONF_SECT_MAX); + conf_set(tr, tmp, "Transforms", sect, 0, 1); + + /* + * XXX For now, defaults + * contain one xf per protocol. + */ + conf_set(tr, sect, "TRANSFORM_ID", qme, 0, 1); + if (strcmp(qme ,"BLOWFISH") == 0) + conf_set(tr, sect, "KEY_LENGTH", CONF_DFLT_VAL_BLF_KEYLEN, 0, + 1); + else if (strcmp(qme ,"AES") == 0) + conf_set(tr, sect, "KEY_LENGTH", CONF_DFLT_VAL_AES_KEYLEN, 0, + 1); + conf_set(tr, sect, "ENCAPSULATION_MODE", MODE(mode), 0, 1); + if (strcmp(qmh, "NONE")) { + conf_set(tr, sect, "AUTHENTICATION_ALGORITHM", qmh, 0, 1); + + /* XXX Another shortcut to keep length down */ + if (pfs) + conf_set(tr, sect, "GROUP_DESCRIPTION", dhg, 0, 1); + } + + /* XXX Lifetimes depending on enc/auth strength? */ + conf_set(tr, sect, "Life", CONF_DFLT_TAG_LIFE_QUICK_MODE, 0, 1); +} + +static void +conf_load_defaults(int tr) +{ + int enc, auth, hash, group, proto, mode, pfs; + char *dflt; + + char *mm_auth[] = {"PRE_SHARED", "DSS", "RSA_SIG", 0}; + char *mm_auth_p[] = {"", "-DSS", "-RSA_SIG", 0}; + char *mm_hash[] = {"MD5", "SHA", 0}; + char *mm_enc[] = {"DES_CBC", "BLOWFISH_CBC", "3DES_CBC", "CAST_CBC", + "AES_CBC", 0}; + char *mm_enc_p[] = {"DES", "BLF", "3DES", "CAST", "AES", 0}; + char *dhgroup[] = {"MODP_1024", "MODP_768", "MODP_1024", + "MODP_1536", "MODP_2048", 0}; + char *dhgroup_p[] = {"", "-GRP1", "-GRP2", "-GRP5", "-GRP14", 0}; + char *qm_enc[] = {"DES", "3DES", "CAST", "BLOWFISH", "AES", 0}; + char *qm_enc_p[] = {"-DES", "-3DES", "-CAST", "-BLF", "-AES", 0}; + char *qm_hash[] = {"HMAC_MD5", "HMAC_SHA", "HMAC_RIPEMD", + "HMAC_SHA2_256", "HMAC_SHA2_384", "HMAC_SHA2_512", "NONE", + 0}; + char *qm_hash_p[] = {"-MD5", "-SHA", "-RIPEMD", "-SHA2-256", + "-SHA2-384", "-SHA2-512", "", 0}; + + /* General and X509 defaults */ + conf_set(tr, "General", "Retransmits", CONF_DFLT_RETRANSMITS, 0, 1); + conf_set(tr, "General", "Exchange-max-time", CONF_DFLT_EXCH_MAX_TIME, + 0, 1); + conf_set(tr, "General", "Use-Keynote", CONF_DFLT_USE_KEYNOTE, 0, 1); + conf_set(tr, "General", "Policy-file", CONF_DFLT_POLICY_FILE, 0, 1); + conf_set(tr, "General", "Pubkey-directory", CONF_DFLT_PUBKEY_DIR, 0, + 1); + +#ifdef USE_X509 + conf_set(tr, "X509-certificates", "CA-directory", + CONF_DFLT_X509_CA_DIR, 0, 1); + conf_set(tr, "X509-certificates", "Cert-directory", + CONF_DFLT_X509_CERT_DIR, 0, 1); + conf_set(tr, "X509-certificates", "Private-key", + CONF_DFLT_X509_PRIVATE_KEY, 0, 1); + conf_set(tr, "X509-certificates", "CRL-directory", + CONF_DFLT_X509_CRL_DIR, 0, 1); +#endif + +#ifdef USE_KEYNOTE + conf_set(tr, "KeyNote", "Credential-directory", + CONF_DFLT_KEYNOTE_CRED_DIR, 0, 1); +#endif + + /* Lifetimes. XXX p1/p2 vs main/quick mode may be unclear. */ + dflt = conf_get_trans_str(tr, "General", "Default-phase-1-lifetime"); + conf_set(tr, CONF_DFLT_TAG_LIFE_MAIN_MODE, "LIFE_TYPE", + CONF_DFLT_TYPE_LIFE_MAIN_MODE, 0, 1); + conf_set(tr, CONF_DFLT_TAG_LIFE_MAIN_MODE, "LIFE_DURATION", + (dflt ? dflt : CONF_DFLT_VAL_LIFE_MAIN_MODE), 0, 1); + + dflt = conf_get_trans_str(tr, "General", "Default-phase-2-lifetime"); + conf_set(tr, CONF_DFLT_TAG_LIFE_QUICK_MODE, "LIFE_TYPE", + CONF_DFLT_TYPE_LIFE_QUICK_MODE, 0, 1); + conf_set(tr, CONF_DFLT_TAG_LIFE_QUICK_MODE, "LIFE_DURATION", + (dflt ? dflt : CONF_DFLT_VAL_LIFE_QUICK_MODE), 0, 1); + + /* Default Phase-1 Configuration section */ + conf_set(tr, CONF_DFLT_TAG_PHASE1_CONFIG, "EXCHANGE_TYPE", + CONF_DFLT_PHASE1_EXCH_TYPE, 0, 1); + conf_set(tr, CONF_DFLT_TAG_PHASE1_CONFIG, "Transforms", + CONF_DFLT_PHASE1_TRANSFORMS, 0, 1); + + /* Main modes */ + for (enc = 0; mm_enc[enc]; enc++) + for (hash = 0; mm_hash[hash]; hash++) + for (auth = 0; mm_auth[auth]; auth++) + for (group = 0; dhgroup_p[group]; group++) + conf_load_defaults_mm (tr, mm_enc[enc], + mm_hash[hash], mm_auth[auth], + dhgroup[group], mm_enc_p[enc], + mm_auth_p[auth], dhgroup_p[group]); + + /* Setup a default Phase 1 entry */ + conf_set(tr, "Phase 1", "Default", "Default-phase-1", 0, 1); + conf_set(tr, "Default-phase-1", "Phase", "1", 0, 1); + conf_set(tr, "Default-phase-1", "Configuration", + "Default-phase-1-configuration", 0, 1); + dflt = conf_get_trans_str(tr, "General", "Default-phase-1-ID"); + if (dflt) + conf_set(tr, "Default-phase-1", "ID", dflt, 0, 1); + + /* Quick modes */ + for (enc = 0; qm_enc[enc]; enc++) + for (proto = 0; proto < 2; proto++) + for (mode = 0; mode < 2; mode++) + for (pfs = 0; pfs < 2; pfs++) + for (hash = 0; qm_hash[hash]; hash++) + for (group = 0; + dhgroup_p[group]; group++) + conf_load_defaults_qm( + tr, qm_enc[enc], + qm_hash[hash], + dhgroup[group], + qm_enc_p[enc], + qm_hash_p[hash], + dhgroup_p[group], + proto, mode, pfs); +} + +void +conf_init(void) +{ + unsigned int i; + + for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) + LIST_INIT(&conf_bindings[i]); + TAILQ_INIT(&conf_trans_queue); + conf_reinit(); +} + +/* Open the config file and map it into our address space, then parse it. */ +void +conf_reinit(void) +{ + struct conf_binding *cb = 0; + int fd, trans; + unsigned int i; + size_t sz; + char *new_conf_addr = 0; + + if ((fd = monitor_open(conf_path, O_RDONLY, 0)) != -1) { + if (check_file_secrecy_fd(fd, conf_path, &sz)) + goto fail; + + new_conf_addr = malloc(sz); + if (!new_conf_addr) { + log_error("conf_reinit: malloc (%lu) failed", + (unsigned long)sz); + goto fail; + } + /* XXX I assume short reads won't happen here. */ + if (read(fd, new_conf_addr, sz) != (int)sz) { + log_error("conf_reinit: read (%d, %p, %lu) failed", + fd, new_conf_addr, (unsigned long)sz); + goto fail; + } + close(fd); + + trans = conf_begin(); + + /* XXX Should we not care about errors and rollback? */ + conf_parse(trans, new_conf_addr, sz); + } else { + if (errno != ENOENT) + log_error("conf_reinit: open(\"%s\", O_RDONLY, 0) " + "failed", conf_path); + + trans = conf_begin(); + } + + /* Load default configuration values. */ + conf_load_defaults(trans); + + /* Free potential existing configuration. */ + if (conf_addr) { + for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; + i++) + for (cb = LIST_FIRST(&conf_bindings[i]); cb; + cb = LIST_FIRST(&conf_bindings[i])) + conf_remove_now(cb->section, cb->tag); + free(conf_addr); + } + conf_end(trans, 1); + conf_addr = new_conf_addr; + return; + +fail: + if (new_conf_addr) + free(new_conf_addr); + close(fd); +} + +/* + * Return the numeric value denoted by TAG in section SECTION or DEF + * if that tag does not exist. + */ +int +conf_get_num(char *section, char *tag, int def) +{ + char *value = conf_get_str(section, tag); + + if (value) + return atoi(value); + return def; +} + +/* + * Return the socket endpoint address denoted by TAG in SECTION as a + * struct sockaddr. It is the callers responsibility to deallocate + * this structure when it is finished with it. + */ +struct sockaddr * +conf_get_address(char *section, char *tag) +{ + char *value = conf_get_str(section, tag); + struct sockaddr *sa; + + if (!value) + return 0; + if (text2sockaddr(value, 0, &sa) == -1) + return 0; + return sa; +} + +/* Validate X according to the range denoted by TAG in section SECTION. */ +int +conf_match_num(char *section, char *tag, int x) +{ + char *value = conf_get_str(section, tag); + int val, min, max, n; + + if (!value) + return 0; + n = sscanf(value, "%d,%d:%d", &val, &min, &max); + switch (n) { + case 1: + LOG_DBG((LOG_MISC, 95, "conf_match_num: %s:%s %d==%d?", + section, tag, val, x)); + return x == val; + case 3: + LOG_DBG((LOG_MISC, 95, "conf_match_num: %s:%s %d<=%d<=%d?", + section, tag, min, x, max)); + return min <= x && max >= x; + default: + log_error("conf_match_num: section %s tag %s: invalid number " + "spec %s", section, tag, 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[conf_hash(section)]); cb; + cb = LIST_NEXT(cb, link)) + if (strcasecmp(section, cb->section) == 0 && + strcasecmp(tag, cb->tag) == 0) { + LOG_DBG((LOG_MISC, 95, "conf_get_str: [%s]:%s->%s", + section, tag, cb->value)); + return cb->value; + } + LOG_DBG((LOG_MISC, 95, + "conf_get_str: configuration value not found [%s]:%s", section, + tag)); + return 0; +} + +/* + * Build a list of string values out of the comma separated value denoted by + * TAG in SECTION. + */ +struct conf_list * +conf_get_list(char *section, char *tag) +{ + char *liststr = 0, *p, *field, *t; + 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, ",")) != NULL) { + /* Skip leading whitespace */ + while (isspace(*field)) + field++; + /* Skip trailing whitespace */ + if (p) + for (t = p - 1; t > field && isspace(*t); t--) + *t = '\0'; + if (*field == '\0') { + log_print("conf_get_list: empty field, ignoring..."); + continue; + } + list->cnt++; + node = calloc(1, sizeof *node); + if (!node) + goto cleanup; + node->field = strdup(field); + if (!node->field) + goto cleanup; + TAILQ_INSERT_TAIL(&list->fields, node, link); + } + free(liststr); + return list; + +cleanup: + if (list) + conf_free_list(list); + if (liststr) + free(liststr); + return 0; +} + +struct conf_list * +conf_get_tag_list(char *section) +{ + struct conf_list *list = 0; + struct conf_list_node *node; + struct conf_binding *cb; + + list = malloc(sizeof *list); + if (!list) + goto cleanup; + TAILQ_INIT(&list->fields); + list->cnt = 0; + for (cb = LIST_FIRST(&conf_bindings[conf_hash(section)]); cb; + cb = LIST_NEXT(cb, link)) + if (strcasecmp(section, cb->section) == 0) { + list->cnt++; + node = calloc(1, sizeof *node); + if (!node) + goto cleanup; + node->field = strdup(cb->tag); + if (!node->field) + goto cleanup; + TAILQ_INSERT_TAIL(&list->fields, node, link); + } + return list; + +cleanup: + if (list) + conf_free_list(list); + 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((char *)buf, "==") == 0) + 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((char *)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; + +} + +void +conf_free_list(struct conf_list *list) +{ + struct conf_list_node *node = TAILQ_FIRST(&list->fields); + + while (node) { + TAILQ_REMOVE(&list->fields, node, link); + if (node->field) + free(node->field); + free(node); + node = TAILQ_FIRST(&list->fields); + } + free(list); +} + +int +conf_begin(void) +{ + static int seq = 0; + + return ++seq; +} + +static struct conf_trans * +conf_trans_node(int transaction, enum conf_op op) +{ + struct conf_trans *node; + + node = calloc(1, sizeof *node); + if (!node) { + log_error("conf_trans_node: calloc (1, %lu) failed", + (unsigned long)sizeof *node); + return 0; + } + node->trans = transaction; + node->op = op; + TAILQ_INSERT_TAIL(&conf_trans_queue, node, link); + return node; +} + +/* Queue a set operation. */ +int +conf_set(int transaction, char *section, char *tag, char *value, int override, + int is_default) +{ + struct conf_trans *node; + + node = conf_trans_node(transaction, CONF_SET); + if (!node) + return 1; + node->section = strdup(section); + if (!node->section) { + log_error("conf_set: strdup (\"%s\") failed", section); + goto fail; + } + node->tag = strdup(tag); + if (!node->tag) { + log_error("conf_set: strdup (\"%s\") failed", tag); + goto fail; + } + node->value = strdup(value); + if (!node->value) { + log_error("conf_set: strdup (\"%s\") failed", value); + goto fail; + } + node->override = override; + node->is_default = is_default; + return 0; + +fail: + if (node->tag) + free(node->tag); + if (node->section) + free(node->section); + if (node) + free(node); + return 1; +} + +/* Queue a remove operation. */ +int +conf_remove(int transaction, char *section, char *tag) +{ + struct conf_trans *node; + + node = conf_trans_node(transaction, CONF_REMOVE); + if (!node) + goto fail; + node->section = strdup(section); + if (!node->section) { + log_error("conf_remove: strdup (\"%s\") failed", section); + goto fail; + } + node->tag = strdup(tag); + if (!node->tag) { + log_error("conf_remove: strdup (\"%s\") failed", tag); + goto fail; + } + return 0; + +fail: + if (node->section) + free(node->section); + if (node) + free(node); + return 1; +} + +/* Queue a remove section operation. */ +int +conf_remove_section(int transaction, char *section) +{ + struct conf_trans *node; + + node = conf_trans_node(transaction, CONF_REMOVE_SECTION); + if (!node) + goto fail; + node->section = strdup(section); + if (!node->section) { + log_error("conf_remove_section: strdup (\"%s\") failed", + section); + goto fail; + } + return 0; + +fail: + if (node) + free(node); + return 1; +} + +/* Execute all queued operations for this transaction. Cleanup. */ +int +conf_end(int transaction, int commit) +{ + struct conf_trans *node, *next; + + for (node = TAILQ_FIRST(&conf_trans_queue); node; node = next) { + next = TAILQ_NEXT(node, link); + if (node->trans == transaction) { + if (commit) + switch (node->op) { + case CONF_SET: + conf_set_now(node->section, node->tag, + node->value, node->override, + node->is_default); + break; + case CONF_REMOVE: + conf_remove_now(node->section, + node->tag); + break; + case CONF_REMOVE_SECTION: + conf_remove_section_now(node->section); + break; + default: + log_print("conf_end: unknown " + "operation: %d", node->op); + } + TAILQ_REMOVE(&conf_trans_queue, node, link); + if (node->section) + free(node->section); + if (node->tag) + free(node->tag); + if (node->value) + free(node->value); + free(node); + } + } + return 0; +} + +/* + * Dump running configuration upon SIGUSR1. + * Configuration is "stored in reverse order", so reverse it again. + */ +struct dumper { + char *s, *v; + struct dumper *next; +}; + +static void +conf_report_dump(struct dumper *node) +{ + /* Recursive, cleanup when we're done. */ + + if (node->next) + conf_report_dump(node->next); + + if (node->v) + LOG_DBG((LOG_REPORT, 0, "%s=\t%s", node->s, node->v)); + else if (node->s) { + LOG_DBG((LOG_REPORT, 0, "%s", node->s)); + if (strlen(node->s) > 0) + free(node->s); + } + free(node); +} + +void +conf_report(void) +{ + struct conf_binding *cb, *last = 0; + unsigned int i, len; + char *current_section = (char *)0; + struct dumper *dumper, *dnode; + + dumper = dnode = (struct dumper *)calloc(1, sizeof *dumper); + if (!dumper) + goto mem_fail; + + LOG_DBG((LOG_REPORT, 0, "conf_report: dumping running configuration")); + + for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) + for (cb = LIST_FIRST(&conf_bindings[i]); cb; + cb = LIST_NEXT(cb, link)) { + if (!cb->is_default) { + /* Dump this entry. */ + if (!current_section || strcmp(cb->section, + current_section)) { + if (current_section) { + len = strlen(current_section) + + 3; + dnode->s = malloc(len); + if (!dnode->s) + goto mem_fail; + + snprintf(dnode->s, len, "[%s]", + current_section); + dnode->next = (struct dumper *) + calloc(1, + sizeof(struct dumper)); + dnode = dnode->next; + if (!dnode) + goto mem_fail; + + dnode->s = ""; + dnode->next = (struct dumper *) + calloc(1, + sizeof(struct dumper)); + dnode = dnode->next; + if (!dnode) + goto mem_fail; + } + current_section = cb->section; + } + dnode->s = cb->tag; + dnode->v = cb->value; + dnode->next = (struct dumper *) + calloc(1, sizeof(struct dumper)); + dnode = dnode->next; + if (!dnode) + goto mem_fail; + last = cb; + } + } + + if (last) { + len = strlen(last->section) + 3; + dnode->s = malloc(len); + if (!dnode->s) + goto mem_fail; + snprintf(dnode->s, len, "[%s]", last->section); + } + conf_report_dump(dumper); + + return; + +mem_fail: + log_error("conf_report: malloc/calloc failed"); + while ((dnode = dumper) != 0) { + dumper = dumper->next; + if (dnode->s) + free(dnode->s); + free(dnode); + } +} diff --git a/keyexchange/isakmpd-20041012/conf.h b/keyexchange/isakmpd-20041012/conf.h new file mode 100644 index 0000000..7c66620 --- /dev/null +++ b/keyexchange/isakmpd-20041012/conf.h @@ -0,0 +1,103 @@ +/* $OpenBSD: conf.h,v 1.30 2004/06/25 20:25:34 hshoexer Exp $ */ +/* $EOM: conf.h,v 1.13 2000/09/18 00:01:47 ho Exp $ */ + +/* + * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2000, 2003 Håkan Olsson. 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. + * + * 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/types.h> +#include <sys/queue.h> +#include <sys/socket.h> +#include <stdio.h> + +#define ISAKMPD_ROOT "/etc/isakmpd/" + +#define CONFIG_FILE ISAKMPD_ROOT "isakmpd.conf" + +/* Default values for autogenerated part of our configuration. */ +#define CONF_DFLT_TAG_LIFE_MAIN_MODE "LIFE_MAIN_MODE" +#define CONF_DFLT_TYPE_LIFE_MAIN_MODE "SECONDS" +#define CONF_DFLT_VAL_LIFE_MAIN_MODE "3600,60:86400" + +#define CONF_DFLT_TAG_LIFE_QUICK_MODE "LIFE_QUICK_MODE" +#define CONF_DFLT_TYPE_LIFE_QUICK_MODE "SECONDS" +#define CONF_DFLT_VAL_LIFE_QUICK_MODE "1200,60:86400" + +#define CONF_DFLT_VAL_BLF_KEYLEN "128,96:192" +#define CONF_DFLT_VAL_AES_KEYLEN "128,128:256" + +#define CONF_DFLT_RETRANSMITS "3" +#define CONF_DFLT_EXCH_MAX_TIME "120" + +#define CONF_DFLT_USE_KEYNOTE "yes" +#define CONF_DFLT_POLICY_FILE ISAKMPD_ROOT "isakmpd.policy" + +#define CONF_DFLT_X509_CA_DIR ISAKMPD_ROOT "ca/" +#define CONF_DFLT_X509_CERT_DIR ISAKMPD_ROOT "certs/" +#define CONF_DFLT_X509_PRIVATE_KEY ISAKMPD_ROOT "private/local.key" +#define CONF_DFLT_X509_CRL_DIR ISAKMPD_ROOT "crls/" +#define CONF_DFLT_PUBKEY_DIR ISAKMPD_ROOT "pubkeys/" +#define CONF_DFLT_KEYNOTE_CRED_DIR ISAKMPD_ROOT "keynote/" + +#define CONF_DFLT_TAG_PHASE1_CONFIG "Default-phase-1-configuration" +#define CONF_DFLT_PHASE1_EXCH_TYPE "ID_PROT" +#define CONF_DFLT_PHASE1_TRANSFORMS "3DES-SHA-RSA_SIG" + +struct conf_list_node { + TAILQ_ENTRY(conf_list_node) link; + char *field; +}; + +struct conf_list { + size_t cnt; + TAILQ_HEAD(conf_list_fields_head, conf_list_node) fields; +}; + +extern char *conf_path; + +extern int conf_begin(void); +extern int conf_decode_base64(u_int8_t *, u_int32_t *, u_char *); +extern int conf_end(int, int); +extern void conf_free_list(struct conf_list *); +extern struct sockaddr *conf_get_address(char *, char *); +extern struct conf_list *conf_get_list(char *, char *); +extern struct conf_list *conf_get_tag_list(char *); +extern int conf_get_num(char *, char *, int); +extern char *conf_get_str(char *, char *); +extern void conf_init(void); +extern int conf_match_num(char *, char *, int); +extern void conf_reinit(void); +extern int conf_remove(int, char *, char *); +extern int conf_remove_section(int, char *); +extern int conf_set(int, char *, char *, char *, int, int); +extern void conf_report(void); + +#endif /* _CONF_H_ */ diff --git a/keyexchange/isakmpd-20041012/connection.c b/keyexchange/isakmpd-20041012/connection.c new file mode 100644 index 0000000..94373ad --- /dev/null +++ b/keyexchange/isakmpd-20041012/connection.c @@ -0,0 +1,449 @@ +/* $OpenBSD: connection.c,v 1.29 2004/06/14 09:55:41 ho Exp $ */ +/* $EOM: connection.c,v 1.28 2000/11/23 12:21:18 niklas Exp $ */ + +/* + * Copyright (c) 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 1999 Hakan Olsson. 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. + * + * 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 <sys/time.h> +#include <sys/socket.h> +#include <stdlib.h> +#include <string.h> + +#include "sysdep.h" + +#include "conf.h" +#include "connection.h" +#include "doi.h" +#include "ipsec.h" + +/* XXX isakmp.h only required for compare_ids(). */ +#include "isakmp.h" + +#include "log.h" +#include "timer.h" +#include "util.h" + +/* How often should we check that connections we require to be up, are up? */ +#define CHECK_INTERVAL 60 + +static void connection_passive_teardown(char *); + +struct connection { + TAILQ_ENTRY(connection) link; + char *name; + struct event *ev; +}; + +struct connection_passive { + TAILQ_ENTRY(connection_passive) link; + char *name; + u_int8_t *local_id, *remote_id; + size_t local_sz, remote_sz; + +#if 0 + /* XXX Potential additions to 'connection_passive'. */ + char *isakmp_peer; + struct sa *sa; /* XXX "Soft" ref to active sa? */ + struct timeval sa_expiration; /* XXX *sa may expire. */ +#endif +}; + +TAILQ_HEAD(connection_head, connection) connections; +TAILQ_HEAD(passive_head, connection_passive) connections_passive; + +/* + * This is where we setup all the connections we want there right from the + * start. + */ +void +connection_init(void) +{ + struct conf_list *conns, *attrs; + struct conf_list_node *conn, *attr = NULL; + + /* + * Passive connections normally include: all "active" connections that + * are not flagged "Active-Only", plus all connections listed in + * the 'Passive-Connections' list. + */ + TAILQ_INIT(&connections); + TAILQ_INIT(&connections_passive); + + conns = conf_get_list("Phase 2", "Connections"); + if (conns) { + for (conn = TAILQ_FIRST(&conns->fields); conn; + conn = TAILQ_NEXT(conn, link)) { + if (connection_setup(conn->field)) + log_print("connection_init: could not setup " + "\"%s\"", conn->field); + + /* XXX Break/abort here if connection_setup failed? */ + + /* + * XXX This code (i.e. the attribute lookup) seems + * like a likely candidate for factoring out into a + * function of its own. + */ + attrs = conf_get_list(conn->field, "Flags"); + if (attrs) + for (attr = TAILQ_FIRST(&attrs->fields); attr; + attr = TAILQ_NEXT(attr, link)) + if (strcasecmp("active-only", + attr->field) == 0) + break; + if (!attrs || (attrs && !attr)) + if (connection_record_passive(conn->field)) + log_print("connection_init: could not " + "record connection \"%s\"", + conn->field); + if (attrs) + conf_free_list(attrs); + + } + conf_free_list(conns); + } + conns = conf_get_list("Phase 2", "Passive-Connections"); + if (conns) { + for (conn = TAILQ_FIRST(&conns->fields); conn; + conn = TAILQ_NEXT(conn, link)) + if (connection_record_passive(conn->field)) + log_print("connection_init: could not record " + "passive connection \"%s\"", conn->field); + conf_free_list(conns); + } +} + +/* Check the connection in VCONN and schedule another check later. */ +static void +connection_checker(void *vconn) +{ + struct timeval now; + struct connection *conn = vconn; + + gettimeofday(&now, 0); + now.tv_sec += conf_get_num("General", "check-interval", + CHECK_INTERVAL); + conn->ev = timer_add_event("connection_checker", + connection_checker, conn, &now); + if (!conn->ev) + log_print("connection_checker: could not add timer event"); + sysdep_connection_check(conn->name); +} + +/* Find the connection named NAME. */ +static struct connection * +connection_lookup(char *name) +{ + struct connection *conn; + + for (conn = TAILQ_FIRST(&connections); conn; + conn = TAILQ_NEXT(conn, link)) + if (strcasecmp(conn->name, name) == 0) + return conn; + return 0; +} + +/* Does the connection named NAME exist? */ +int +connection_exist(char *name) +{ + return (connection_lookup(name) != 0); +} + +/* Find the passive connection named NAME. */ +static struct connection_passive * +connection_passive_lookup_by_name(char *name) +{ + struct connection_passive *conn; + + for (conn = TAILQ_FIRST(&connections_passive); conn; + conn = TAILQ_NEXT(conn, link)) + if (strcasecmp(conn->name, name) == 0) + return conn; + return 0; +} + +/* + * IDs of different types cannot be the same. + * XXX Rename to ipsec_compare_id, and move to ipsec.c ? + */ +static int +compare_ids(u_int8_t *id1, u_int8_t *id2, size_t idlen) +{ + int id1_type, id2_type; + + id1_type = GET_ISAKMP_ID_TYPE(id1); + id2_type = GET_ISAKMP_ID_TYPE(id2); + + return id1_type == id2_type ? memcmp(id1 + ISAKMP_ID_DATA_OFF, + id2 + ISAKMP_ID_DATA_OFF, idlen - ISAKMP_ID_DATA_OFF) : -1; +} + +/* Find the connection named with matching IDs. */ +char * +connection_passive_lookup_by_ids(u_int8_t *id1, u_int8_t *id2) +{ + struct connection_passive *conn; + + for (conn = TAILQ_FIRST(&connections_passive); conn; + conn = TAILQ_NEXT(conn, link)) { + if (!conn->remote_id) + continue; + + /* + * If both IDs match what we have saved, return the name. + * Don't bother in which order they are. + */ + if ((compare_ids(id1, conn->local_id, conn->local_sz) == 0 && + compare_ids(id2, conn->remote_id, conn->remote_sz) == 0) || + (compare_ids(id1, conn->remote_id, conn->remote_sz) == 0 && + compare_ids(id2, conn->local_id, conn->local_sz) == 0)) { + LOG_DBG((LOG_MISC, 60, + "connection_passive_lookup_by_ids: " + "returned \"%s\"", conn->name)); + return conn->name; + } + } + + /* + * In the road warrior case, we do not know the remote ID. In that + * case we will just match against the local ID. + */ + for (conn = TAILQ_FIRST(&connections_passive); conn; + conn = TAILQ_NEXT(conn, link)) { + if (!conn->remote_id) + continue; + + if (compare_ids(id1, conn->local_id, conn->local_sz) == 0 || + compare_ids(id2, conn->local_id, conn->local_sz) == 0) { + LOG_DBG((LOG_MISC, 60, + "connection passive_lookup_by_ids: returned \"%s\"" + " only matched local id", conn->name)); + return conn->name; + } + } + LOG_DBG((LOG_MISC, 60, + "connection_passive_lookup_by_ids: no match")); + return 0; +} + +/* + * Setup NAME to be a connection that should be up "always", i.e. if it dies, + * for whatever reason, it should be tried to be brought up, over and over + * again. + */ +int +connection_setup(char *name) +{ + struct connection *conn = 0; + struct timeval now; + + /* Check for trials to add duplicate connections. */ + if (connection_lookup(name)) { + LOG_DBG((LOG_MISC, 10, + "connection_setup: cannot add \"%s\" twice", name)); + return 0; + } + conn = calloc(1, sizeof *conn); + if (!conn) { + log_error("connection_setup: calloc (1, %lu) failed", + (unsigned long)sizeof *conn); + goto fail; + } + conn->name = strdup(name); + if (!conn->name) { + log_error("connection_setup: strdup (\"%s\") failed", name); + goto fail; + } + gettimeofday(&now, 0); + conn->ev = timer_add_event("connection_checker", connection_checker, + conn, &now); + if (!conn->ev) { + log_print("connection_setup: could not add timer event"); + goto fail; + } + TAILQ_INSERT_TAIL(&connections, conn, link); + return 0; + +fail: + if (conn) { + if (conn->name) + free(conn->name); + free(conn); + } + return -1; +} + +int +connection_record_passive(char *name) +{ + struct connection_passive *conn; + char *local_id, *remote_id; + + if (connection_passive_lookup_by_name(name)) { + LOG_DBG((LOG_MISC, 10, + "connection_record_passive: cannot add \"%s\" twice", + name)); + return 0; + } + local_id = conf_get_str(name, "Local-ID"); + if (!local_id) { + log_print("connection_record_passive: " + "\"Local-ID\" is missing from section [%s]", name); + return -1; + } + /* If the remote id lookup fails we defer it to later */ + remote_id = conf_get_str(name, "Remote-ID"); + + conn = calloc(1, sizeof *conn); + if (!conn) { + log_error("connection_record_passive: calloc (1, %lu) failed", + (unsigned long)sizeof *conn); + return -1; + } + conn->name = strdup(name); + if (!conn->name) { + log_error("connection_record_passive: strdup (\"%s\") failed", + name); + goto fail; + } + /* XXX IPsec DOI-specific. */ + conn->local_id = ipsec_build_id(local_id, &conn->local_sz); + if (!conn->local_id) + goto fail; + + if (remote_id) { + conn->remote_id = ipsec_build_id(remote_id, &conn->remote_sz); + if (!conn->remote_id) + goto fail; + } else + conn->remote_id = 0; + + TAILQ_INSERT_TAIL(&connections_passive, conn, link); + + LOG_DBG((LOG_MISC, 60, + "connection_record_passive: passive connection \"%s\" added", + conn->name)); + return 0; + +fail: + if (conn->local_id) + free(conn->local_id); + if (conn->name) + free(conn->name); + free(conn); + return -1; +} + +/* Remove the connection named NAME. */ +void +connection_teardown(char *name) +{ + struct connection *conn; + + conn = connection_lookup(name); + if (!conn) + return; + + TAILQ_REMOVE(&connections, conn, link); + timer_remove_event(conn->ev); + free(conn->name); + free(conn); +} + +/* Remove the passive connection named NAME. */ +static void +connection_passive_teardown(char *name) +{ + struct connection_passive *conn; + + conn = connection_passive_lookup_by_name(name); + if (!conn) + return; + + TAILQ_REMOVE(&connections_passive, conn, link); + free(conn->name); + free(conn->local_id); + free(conn->remote_id); + free(conn); +} + +void +connection_report(void) +{ + struct connection *conn; + struct timeval now; +#ifdef USE_DEBUG + struct connection_passive *pconn; + struct doi *doi = doi_lookup(ISAKMP_DOI_ISAKMP); +#endif + + gettimeofday(&now, 0); + for (conn = TAILQ_FIRST(&connections); conn; + conn = TAILQ_NEXT(conn, link)) + LOG_DBG((LOG_REPORT, 0, + "connection_report: connection %s next check %ld seconds", + (conn->name ? conn->name : "<unnamed>"), + conn->ev->expiration.tv_sec - now.tv_sec)); +#ifdef USE_DEBUG + for (pconn = TAILQ_FIRST(&connections_passive); pconn; + pconn = TAILQ_NEXT(pconn, link)) + LOG_DBG((LOG_REPORT, 0, + "connection_report: passive connection %s %s", pconn->name, + doi->decode_ids("local_id: %s, remote_id: %s", + pconn->local_id, pconn->local_sz, + pconn->remote_id, pconn->remote_sz, 1))); +#endif +} + +/* Reinitialize all connections (SIGHUP handling). */ +void +connection_reinit(void) +{ + struct connection *conn, *next; + struct connection_passive *pconn, *pnext; + + LOG_DBG((LOG_MISC, 30, + "connection_reinit: reinitializing connection list")); + + /* Remove all present connections. */ + for (conn = TAILQ_FIRST(&connections); conn; conn = next) { + next = TAILQ_NEXT(conn, link); + connection_teardown(conn->name); + } + + for (pconn = TAILQ_FIRST(&connections_passive); pconn; pconn = pnext) { + pnext = TAILQ_NEXT(pconn, link); + connection_passive_teardown(pconn->name); + } + + /* Setup new connections, as the (new) config directs. */ + connection_init(); +} diff --git a/keyexchange/isakmpd-20041012/connection.h b/keyexchange/isakmpd-20041012/connection.h new file mode 100644 index 0000000..41ee533 --- /dev/null +++ b/keyexchange/isakmpd-20041012/connection.h @@ -0,0 +1,51 @@ +/* $OpenBSD: connection.h,v 1.5 2004/04/15 18:39:25 deraadt Exp $ */ +/* $EOM: connection.h,v 1.6 1999/06/07 00:10:48 ho Exp $ */ + +/* + * Copyright (c) 1999 Niklas Hallqvist. All rights reserved. + * Copyright (c) 1999 Hakan Olsson. 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. + * + * 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 connection module deals with connections that should always be up. + */ + +#ifndef _CONNECTION_H_ +#define _CONNECTION_H_ + +#include <sys/types.h> + +extern int connection_exist(char *); +extern void connection_init(void); +extern char *connection_passive_lookup_by_ids(u_int8_t *, u_int8_t *); +extern void connection_reinit(void); +extern void connection_report(void); +extern int connection_setup(char *); +extern int connection_record_passive(char *); +extern void connection_teardown(char *); + +#endif /* _CONNECTION_H_ */ diff --git a/keyexchange/isakmpd-20041012/constants.c b/keyexchange/isakmpd-20041012/constants.c new file mode 100644 index 0000000..ec0d0f4 --- /dev/null +++ b/keyexchange/isakmpd-20041012/constants.c @@ -0,0 +1,99 @@ +/* $OpenBSD: constants.c,v 1.9 2004/04/15 18:39:25 deraadt Exp $ */ +/* $EOM: constants.c,v 1.7 1999/04/02 00:57:31 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999 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. + * + * 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 "sysdep.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; +} + +struct constant_map * +constant_link_lookup(struct constant_map *map, int value) +{ + struct constant_map *entry = map; + + for (entry = map; entry->name; entry++) + if (entry->value == value) + return entry->link; + 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, sizeof tmp, "<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, sizeof tmp, "<Unknown %d>", value); + return tmp; +} diff --git a/keyexchange/isakmpd-20041012/constants.h b/keyexchange/isakmpd-20041012/constants.h new file mode 100644 index 0000000..e3dd439 --- /dev/null +++ b/keyexchange/isakmpd-20041012/constants.h @@ -0,0 +1,47 @@ +/* $OpenBSD: constants.h,v 1.6 2004/04/15 18:39:25 deraadt Exp $ */ +/* $EOM: constants.h,v 1.5 1998/11/20 07:17:01 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. + * + * 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; + struct constant_map *link; +}; + +struct constant_map *constant_link_lookup(struct constant_map *, int); +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/keyexchange/isakmpd-20041012/cookie.c b/keyexchange/isakmpd-20041012/cookie.c new file mode 100644 index 0000000..ec8f826 --- /dev/null +++ b/keyexchange/isakmpd-20041012/cookie.c @@ -0,0 +1,74 @@ +/* $OpenBSD: cookie.c,v 1.14 2004/05/14 08:42:56 hshoexer Exp $ */ +/* $EOM: cookie.c,v 1.21 1999/08/05 15:00:04 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999 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. + * + * 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 <stdlib.h> +#include <string.h> + +#include "sysdep.h" + +#include "cookie.h" +#include "exchange.h" +#include "hash.h" +#include "transport.h" +#include "util.h" + +#define COOKIE_SECRET_SIZE 16 + +/* + * 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); + u_int8_t tmpsecret[COOKIE_SECRET_SIZE]; + struct sockaddr *name; + + hash->Init(hash->ctx); + (*t->vtbl->get_dst)(t, &name); + hash->Update(hash->ctx, (u_int8_t *)name, sysdep_sa_len(name)); + (*t->vtbl->get_src)(t, &name); + hash->Update(hash->ctx, (u_int8_t *)name, sysdep_sa_len(name)); + if (exchange->initiator == 0) + hash->Update(hash->ctx, exchange->cookies + + ISAKMP_HDR_ICOOKIE_OFF, ISAKMP_HDR_ICOOKIE_LEN); + getrandom(tmpsecret, COOKIE_SECRET_SIZE); + hash->Update(hash->ctx, tmpsecret, COOKIE_SECRET_SIZE); + hash->Final(hash->digest, hash->ctx); + memcpy(buf, hash->digest, len); +} diff --git a/keyexchange/isakmpd-20041012/cookie.h b/keyexchange/isakmpd-20041012/cookie.h new file mode 100644 index 0000000..bfbcc01 --- /dev/null +++ b/keyexchange/isakmpd-20041012/cookie.h @@ -0,0 +1,44 @@ +/* $OpenBSD: cookie.h,v 1.7 2004/05/14 08:42:56 hshoexer Exp $ */ +/* $EOM: cookie.h,v 1.5 1998/08/05 09:21:43 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. + * + * 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); + +#endif /* _COOKIE_H_ */ diff --git a/keyexchange/isakmpd-20041012/crypto.c b/keyexchange/isakmpd-20041012/crypto.c new file mode 100644 index 0000000..d74191e --- /dev/null +++ b/keyexchange/isakmpd-20041012/crypto.c @@ -0,0 +1,413 @@ +/* $OpenBSD: crypto.c,v 1.22 2004/06/14 09:55:41 ho Exp $ */ +/* $EOM: crypto.c,v 1.32 2000/03/07 20:08:51 niklas Exp $ */ + +/* + * Copyright (c) 1998 Niels Provos. All rights reserved. + * Copyright (c) 1999, 2000 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. + * + * 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 "sysdep.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); +enum cryptoerr aes_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); +void aes_encrypt(struct keystate *, u_int8_t *, u_int16_t); +void aes_decrypt(struct keystate *, u_int8_t *, u_int16_t); + +struct crypto_xf transforms[] = { +#ifdef USE_DES + { + DES_CBC, "Data Encryption Standard (CBC-Mode)", 8, 8, + BLOCKSIZE, 0, + des1_init, + des1_encrypt, des1_decrypt + }, +#endif +#ifdef USE_TRIPLEDES + { + TRIPLEDES_CBC, "Triple-DES (CBC-Mode)", 24, 24, + BLOCKSIZE, 0, + des3_init, + des3_encrypt, des3_decrypt + }, +#endif +#ifdef USE_BLOWFISH + { + BLOWFISH_CBC, "Blowfish (CBC-Mode)", 12, 56, + BLOCKSIZE, 0, + blf_init, + blf_encrypt, blf_decrypt + }, +#endif +#ifdef USE_CAST + { + CAST_CBC, "CAST (CBC-Mode)", 12, 16, + BLOCKSIZE, 0, + cast_init, + cast1_encrypt, cast1_decrypt + }, +#endif +#ifdef USE_AES + { + AES_CBC, "AES (CBC-Mode)", 16, 32, + AES_BLOCK_SIZE, 0, + aes_init, + aes_encrypt, aes_decrypt + }, +#endif +}; + +/* Hmm, the function prototypes for des are really dumb */ +#ifdef __OpenBSD__ +#define DC (des_cblock *) +#else +#define DC (void *) +#endif + +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); +} + +#ifdef USE_TRIPLEDES +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 + 8)); + des_set_odd_parity(DC(key + 16)); + + /* 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 + 8), ks->ks_des[1]); + des_set_key(DC(key + 16), 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 +#endif /* USE_TRIPLEDES */ + +#ifdef USE_BLOWFISH +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); +} +#endif /* USE_BLOWFISH */ + +#ifdef USE_CAST +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); +} +#endif /* USE_CAST */ + +#ifdef USE_AES +enum cryptoerr +aes_init(struct keystate *ks, u_int8_t *key, u_int16_t len) +{ + AES_set_encrypt_key(key, len << 3, &ks->ks_aes[0]); + AES_set_decrypt_key(key, len << 3, &ks->ks_aes[1]); + return EOKAY; +} + +void +aes_encrypt(struct keystate *ks, u_int8_t *data, u_int16_t len) +{ + u_int8_t iv[MAXBLK]; + + memcpy(iv, ks->riv, ks->xf->blocksize); + AES_cbc_encrypt(data, data, len, &ks->ks_aes[0], iv, AES_ENCRYPT); +} + +void +aes_decrypt(struct keystate *ks, u_int8_t *data, u_int16_t len) +{ + u_int8_t iv[MAXBLK]; + + memcpy(iv, ks->riv, ks->xf->blocksize); + AES_cbc_encrypt(data, data, len, &ks->ks_aes[1], iv, AES_DECRYPT); +} +#endif /* USE_AES */ + +struct crypto_xf * +crypto_get(enum transform id) +{ + size_t 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; + + if (len < xf->keymin || len > xf->keymax) { + LOG_DBG((LOG_CRYPTO, 10, "crypto_init: invalid key length %d", + len)); + *err = EKEYLEN; + return 0; + } + ks = calloc(1, sizeof *ks); + if (!ks) { + log_error("crypto_init: calloc (1, %lu) failed", + (unsigned long)sizeof *ks); + *err = ENOCRYPTO; + return 0; + } + ks->xf = xf; + + /* Setup the IV. */ + ks->riv = ks->iv; + ks->liv = ks->iv2; + + LOG_DBG_BUF((LOG_CRYPTO, 40, "crypto_init: key", key, len)); + + *err = xf->init(ks, key, len); + if (*err != EOKAY) { + LOG_DBG((LOG_CRYPTO, 30, "crypto_init: weak key found for %s", + xf->name)); + free(ks); + return 0; + } + return ks; +} + +void +crypto_update_iv(struct keystate *ks) +{ + u_int8_t *tmp; + + tmp = ks->riv; + ks->riv = ks->liv; + ks->liv = tmp; + + LOG_DBG_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_DBG_BUF((LOG_CRYPTO, 50, "crypto_init_iv: initialized IV", ks->riv, + len)); +} + +void +crypto_encrypt(struct keystate *ks, u_int8_t *buf, u_int16_t len) +{ + LOG_DBG_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_DBG_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_DBG_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_DBG_BUF((LOG_CRYPTO, 30, "crypto_decrypt: after decryption", buf, + len)); +} + +/* Make a copy of the keystate pointed to by OKS. */ +struct keystate * +crypto_clone_keystate(struct keystate *oks) +{ + struct keystate *ks; + + ks = malloc(sizeof *ks); + if (!ks) { + log_error("crypto_clone_keystate: malloc (%lu) failed", + (unsigned long)sizeof *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/keyexchange/isakmpd-20041012/crypto.h b/keyexchange/isakmpd-20041012/crypto.h new file mode 100644 index 0000000..1095c7e --- /dev/null +++ b/keyexchange/isakmpd-20041012/crypto.h @@ -0,0 +1,175 @@ +/* $OpenBSD: crypto.h,v 1.14 2004/05/14 08:42:56 hshoexer Exp $ */ +/* $EOM: crypto.h,v 1.12 2000/10/15 21:56:41 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. + * + * 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_ + +#if defined (__APPLE__) + +#include <openssl/des.h> +#ifdef USE_BLOWFISH +#include <openssl/blowfish.h> +#endif +#ifdef USE_CAST +#include <openssl/cast.h> +#endif + +#else + +#include <des.h> +#ifdef USE_BLOWFISH +#include <blf.h> +#endif +#ifdef USE_CAST +#include <cast.h> +#endif + +#endif /* __APPLE__ */ + +#ifdef USE_AES +#include <openssl/aes.h> +#endif + +#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. + * Keep MAXBLK uptodate. + */ +#define BLOCKSIZE 8 + +#ifdef USE_AES +#define MAXBLK AES_BLOCK_SIZE +#else +#define MAXBLK BLOCKSIZE +#endif + +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]; +#ifdef USE_BLOWFISH + blf_ctx blfks; +#endif +#ifdef USE_CAST + cast_key castks; +#endif +#ifdef USE_AES + AES_KEY aesks[2]; +#endif + } keydata; +}; + +#define ks_des keydata.desks +#define ks_blf keydata.blfks +#define ks_cast keydata.castks +#define ks_aes keydata.aesks + +/* + * 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, + AES_CBC = 7 +}; + +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/keyexchange/isakmpd-20041012/debian/ChangeLog b/keyexchange/isakmpd-20041012/debian/ChangeLog new file mode 100644 index 0000000..bae602d --- /dev/null +++ b/keyexchange/isakmpd-20041012/debian/ChangeLog @@ -0,0 +1,1668 @@ +End of changelog debian package isakmpd.20041012-1 +-------------------------------------------------- + +2004-10-08 17:18 hshoexer + + * sysdep/common/libsysdep/arc4random.c: pull in some changes from + libc arc4random (only relevant for non-OpenBSD systems): ansify, + discard first 256 output bytes, make key schedule more arc4 + stream ciper like. + + ok djm ho + +2004-10-01 06:08 jsg + + * monitor_fdpass.c: add some missing $, ok djm@ 'That looks fine to + me' millert@ + +2004-09-24 15:31 ho + + * udp_encap.c: Don't process NAT-T keepalives. Noted by Kamel + Messaoudi. hshoexer@ ok + +2004-09-20 23:36 hshoexer + + * virtual.c: compile cleanly with -Wsign-compare ok ho + +2004-09-20 23:35 hshoexer + + * monitor_fdpass.c: Remove __func__ ok ho deraadt + +2004-09-17 16:54 hshoexer + + * isakmpd.c: avoid signal race. + + ok ho@ otto@ + +2004-09-17 15:53 ho + + * exchange.c, ike_quick_mode.c, ipsec.c, key.c, pf_key_v2.c: + Missing #ifdefs. + +2004-09-17 15:46 ho + + * init.c: #include <stdlib.h> for srandom(). + +2004-09-17 15:45 ho + + * message.c: Permit next payload type NAT-OA. Noted by Kamel + Messaoudi. + +2004-08-23 13:53 ho + + * exchange.c: We need to set sa->initiator before checking if the + newly created SA replaces an old one, or the id_i/id_r check will + mismatch. Previous behaviour was mostly harmless, but wasted some + resources (until normal SA expiration). hshoexer@ "haven't tried, + but think it's ok" + +2004-08-23 13:16 ho + + * Makefile: Default enable DPD (Dead Peer Detection) support. + hshoexer@ ok + +2004-08-23 13:13 ho + + * exchange.h: Indent nit. + +2004-08-17 16:48 hshoexer + + * message.c: check for msg->isakmpg_sa being NULL before + referencing ok ho@ + +2004-08-14 15:29 hshoexer + + * ike_quick_mode.c: When using -K (keynote disabled), check peers' + proposal against isakmpd.conf. + + ok ho@ henning@ + +2004-08-13 04:51 djm + + * monitor_fdpass.c: extra check for no message case; ok markus, + deraadt, hshoexer, henning + +2004-08-12 13:21 hshoexer + + * monitor.c: Fix compiler warning on alpha. Noted by and ok ho@ + +2004-08-12 13:08 ho + + * pf_key_v2.c: Avoid memleak on error (Linux/KAME). Found by + Benjamin Pineau. + +2004-08-10 21:21 deraadt + + * virtual.c, x509.c: spacing + +2004-08-10 17:59 ho + + * dpd.c, dpd.h, exchange.c, ipsec.c, isakmp_num.cst, + isakmpd.conf.5, message.c, message.h, pf_key_v2.c, pf_key_v2.h, + sa.c, sa.h, sysdep.h, udp_encap.c, sysdep/bsdi/sysdep.c, + sysdep/darwin/sysdep.c, sysdep/freebsd/sysdep.c, + sysdep/freeswan/sysdep.c, sysdep/linux/sysdep.c, + sysdep/netbsd/sysdep.c, sysdep/openbsd/sysdep.c: Better + implementation of the Dead Peer Detection protocol, RFC 3706. + hshoexer@ ok. + +2004-08-10 11:49 ho + + * sysdep/linux/GNUmakefile.sysdep: Linux has AES (and DES). From + Benjamin Pineau. + +2004-08-10 11:47 ho + + * sysdep/common/libsysdep/arc4random.c: If opening /dev/arandom + fails, try /dev/random. Suggested by Benjamin Pineau. + +2004-08-08 21:11 deraadt + + * GNUmakefile, conf.c, dpd.c, exchange.c, ike_auth.c, + ike_phase_1.c, ike_quick_mode.c, ipsec.c, isakmp_cfg.c, log.c, + message.c, monitor.c, nat_traversal.c, pf_key_v2.c, policy.c, + sa.c, sysdep.h, transport.c, udp.c, udp_encap.c, ui.c, util.c, + virtual.c, x509.c: spacing + +2004-08-03 12:54 ho + + * nat_traversal.c, transport.c, udp.c, udp.h, udp_encap.c, + virtual.c: Rewrite the transport reference count code to avoid + leaks. hshoexer@ ok. + +2004-08-02 17:48 hshoexer + + * sa.c: Do not expire unestablished phase 2 SAs on SIGHUP. + + ok ho@ + +2004-08-02 17:30 ho + + * GNUmakefile: Missed to add virtual.c here. Noted by Benjamin + Pineau. + +2004-07-30 12:45 ho + + * Makefile, sysdep.h, util.c: Style. + +2004-07-29 22:02 ho + + * conf.c: Less noise while debugging. + +2004-07-29 10:54 ho + + * ike_aggressive.c, ike_phase_1.c, nat_traversal.c: Repair NAT-T + using Aggressive mode, NAT-D checks were in the wrong place. + Noted by Yvan VANHULLEBUS. + +2004-07-09 18:06 deraadt + + * doi.c, exchange.c: ansi + +2004-07-08 21:53 hshoexer + + * virtual.c: free() and close() in error path. + + ok ho@ + +2004-07-08 12:37 jmc + + * isakmpd.8, isakmpd.conf.5: typo, and line adjustment; + +2004-07-08 00:25 hshoexer + + * isakmpd.8, isakmpd.conf.5: document -a/-K and + "Acquire-Only"/"Use-Keynote". + + ok markus@ henning@ ho@ english polish and mdoc help and ok jmc@ + +2004-07-07 11:16 hshoexer + + * message.c: plug memleak when receiving an + INVALID_HASH_INFORMATION notify. Found by Patrick Latifi, + thanks! + + ok ho@ + +2004-07-07 11:13 hshoexer + + * udp_encap.c: compile cleanly with -Wsign-compare; while around, + kill a space + + ok ho@ + +2004-07-05 19:33 pvalchev + + * ike_phase_1.c: %lu and cast to unsigned long to print a size_t; + ok ho + +2004-06-30 12:07 hshoexer + + * nat_traversal.c: Compile cleanly with gcc3.3.2. + + ok ho@ + +2004-06-26 13:32 jmc + + * isakmpd.conf.5: new sentence, new line; + +2004-06-26 08:07 hshoexer + + * monitor.c, monitor.h, pf_key_v2.c, pf_key_v2.h, + sysdep/openbsd/sysdep.c: Narrow down privsep interface. Move + pf_key_v2_open() to monitor. + + Work in progress. + + ok ho@ + +2004-06-26 05:40 mcbride + + * sysdep/: bsdi/Makefile.sysdep, darwin/GNUmakefile.sysdep, + darwin/Makefile.sysdep, freebsd/GNUmakefile.sysdep, + freebsd/Makefile.sysdep, linux/GNUmakefile.sysdep, + netbsd/GNUmakefile.sysdep, netbsd/Makefile.sysdep, + openbsd/GNUmakefile.sysdep, openbsd/Makefile.sysdep: Remove + -DHAVE_GETNAMEINFO frome makefiles. + + Pointed out by ho@ + +2004-06-25 22:25 hshoexer + + * conf.c, conf.h, ike_quick_mode.c, isakmpd.c, policy.c, policy.h: + Keynote policy checking can now be disabled by "-K" switch and + config tag "Use-Keynote". Default is to use keynote. + + ok henning@ ho@ + +2004-06-25 21:42 mcbride + + * udp.c, util.c: Remove HAVE_GETNAMEINFO alternate code. Compiled + binary is unchanged. + + ok msf@ hshoexer@ itojun@ ho@ + +2004-06-25 02:58 hshoexer + + * init.c, log.c, monitor.c, monitor.h, ui.c: Narrow down privsep + interface. Remove ui_init to monitor. So we can get rid of + monitor_mkfifo. + + Work in progress. + + ok ho@ + +2004-06-24 19:02 hshoexer + + * monitor.c: Remove some unused code. Fix handling of sigchild. + Now it's possible to sigstop/sigcont isakmpd correclty. + + ok ho@ + +2004-06-24 17:58 hshoexer + + * policy.c: Also handle keys from x509-certificates embedded in + keynote credentials. + + with msf@ ok ho@ + +2004-06-24 01:36 ho + + * pf_key_v2.c: Print corrent prefix. Found and tested by alex at + vbone.net. + +2004-06-23 05:01 hshoexer + + * ike_auth.c, util.c, util.h: Avoid stat before open. Do open and + fstat instead. Remove check_file_secrecy() as it is obsoleted be + check_file_secrecy_fd(). + + ok ho@ + +2004-06-23 03:17 ho + + * Makefile, sysdep.h, util.c: Make compiling with Boehm's gc + possible again. + +2004-06-23 02:56 ho + + * ike_phase_1.c: Support IPV{4,6}_ADDR_SUBNET IDs in Phase 1, just + like the man page says we do. Noted and tested by alex at + vbone.net. Also avoid a potential SEGV here. hshoexer@ok + +2004-06-23 02:55 hshoexer + + * ipsec.c, isakmpd.c: Add commandline switch -a / config tag + "Acquire-Only" to tell isakmpd to not touch flows. + + initial work by markus ok markus@ ho@ henning@ + +2004-06-22 20:22 hshoexer + + * ike_auth.c: kn_get_string() may return NULL on failure. Handle + this corrctly. + + with msf@, ok ho@ markus@ + +2004-06-22 05:44 ho + + * virtual.c: The NAT-T drafts suggest we should drop incoming + messages arriving on the old port (500) after we've switched to + the new one. + +2004-06-22 01:42 ho + + * isakmpd.conf.5: Describe the [Default]:NAT-T-Keepalive + configuration parameter. + +2004-06-22 01:28 ho + + * Makefile: Enable NAT-T support. + +2004-06-22 01:27 ho + + * ipsec.c, nat_traversal.c, nat_traversal.h, sa.c, sa.h, + udp_encap.c: Implement NAT-T keepalive messages. + +2004-06-21 20:41 ho + + * pf_key_v2.c: udpencap_port should be taken from dst transport + +2004-06-21 20:40 ho + + * virtual.c: When switching from main to encap transport, copy dst + port if translated (NAT). + +2004-06-21 20:34 ho + + * monitor.c: Strip away umask bits in monitor_fopen(). hshoexer@ + ok. + +2004-06-21 20:29 ho + + * ipsec.c: style nit + +2004-06-21 19:02 markus + + * features/nat_traversal: undo double-patch; Dries Schellekens + +2004-06-21 18:37 ho + + * log.c: Don't write too much IKE data in packet capture + +2004-06-21 18:01 ho + + * log.c, message.c: Packet capture should add the ESP-marker when + NAT-T is active. + +2004-06-21 17:15 ho + + * pf_key_v2.c: Tell the kernel to enable ESP-in-UDP encapsulation + when we have SAs negotiated with NAT-T. + +2004-06-21 15:09 ho + + * exchange.c, sa.h, transport.c, udp.c, udp_encap.c, virtual.c: + Port floating (500->4500) for p1 and p2 exchanges. + +2004-06-20 19:44 ho + + * message.c: message_parse_payloads should accept payloads in the + private range. While here, also cleanup some messages. + +2004-06-20 19:17 ho + + * dpd.c, exchange.c, ike_auth.c, ike_phase_1.c, ike_quick_mode.c, + init.c, ipsec.c, isakmp_cfg.c, isakmp_doi.c, message.c, + message.h, nat_traversal.c: Make the payload array in struct + message dynamic, since we need to handle payloads in the private + range, such as the pre-RFC NAT-D/NAT-OA. Replace + TAILQ_FIRST(&msg->payload[i]) instances with function calls. + +2004-06-20 17:24 ho + + * Makefile, exchange.h, ike_phase_1.c, init.c, ipsec.c, isakmp.h, + isakmp_fld.fld, message.c, nat_traversal.c, nat_traversal.h, + policy.c, transport.c, transport.h, udp.c, udp.h, udp_encap.c, + udp_encap.h, util.c, util.h, virtual.c, virtual.h, + features/nat_traversal: NAT-Traversal for isakmpd. Work in + progress... hshoexer@ ok. + +2004-06-20 17:20 ho + + * dpd.c, dpd.h, exchange.c, isakmp_num.cst, sa.h, features/dpd: A + start towards Dead Peer Detection (DPD) support, as specified in + RFC 3706 + +2004-06-20 17:11 ho + + * message.c: Some vendors send the last Aggressive Mode message + unencrypted, which we should accept. Problem noted by alex at + vbone.net. hshoexer@ ok. + +2004-06-20 17:03 ho + + * isakmpd.c, monitor.c, monitor.h: To make debugging the + unprivileged child process easier, make 'isakmpd -dd' pause just + after privsep; print the PIDs and wait for SIGCONT. hshoexer@ ok + +2004-06-17 21:39 hshoexer + + * ipsec.c: Yet another bunch of memleask found and fixed by Patrick + Latifi. Thanks! + + ok ho@ + +2004-06-17 21:36 hshoexer + + * udp.c: Plug a memleak. Found and fixed (and some cleanup) by + Patrick Latifi. Thanks! + + ok ho@ + +2004-06-17 21:32 hshoexer + + * x509.c: Evaluate result of X509_verify_cert() more carefully. + + ok cloder@ + +2004-06-16 17:08 hshoexer + + * util.c: Fix wrong pointer dereference and plug memleak. Found + and patch by Patrick Latifi. Thanks! + + ok ho@ + +2004-06-16 17:05 hshoexer + + * ipsec.c: fix ipv6-address and ipv6-address-mask mixup. Found by + Patrick Latifi. Thanks! + + ok ho@ + +2004-06-15 17:53 hshoexer + + * ike_quick_mode.c, isakmp_cfg.c: also use MSG_AUTHENTICATED flag. + + ok ho@ + +2004-06-14 15:53 hshoexer + + * conf.c, ike_auth.c, x509.c: avoid stat before open + + ok ho@ + +2004-06-14 12:04 hshoexer + + * message.c: added a missing message_free(). + + ok ho@ + +2004-06-14 11:55 ho + + * cert.c, conf.c, connection.c, crypto.c, dnssec.c, exchange.c, + field.c, hash.c, if.c, ike_auth.c, ike_main_mode.c, + ike_phase_1.c, ike_quick_mode.c, ipsec.c, isakmp_cfg.c, + isakmp_doi.c, isakmpd.c, key.c, log.c, math_2n.c, math_group.c, + message.c, monitor.c, pf_key_v2.c, policy.c, timer.c, + transport.c, udp.c, util.c, x509.c: KNF, style, 80c, etc. + hshoexer@ ok + +2004-06-11 12:17 brad + + * message.c: typo in comment + +2004-06-11 05:08 brad + + * ike_phase_1.c, ike_quick_mode.c, ipsec.c, message.c, message.h: + MFC: Fix by hshoexer@ + + Mark authenticated messages explicitly. Better check for + authentication before deleteing SAs. + + This fix is needed to solve the problems reported by Thomas + Walpuski, previous diff was not sufficient. Pointed out by + Thomas. Thanks! + +2004-06-11 04:34 brad + + * ike_phase_1.c, ike_quick_mode.c, ipsec.c, message.c, message.h: + MFC: Fix by hshoexer@ + + Mark authenticated messages explicitly. Better check for + authentication before deleteing SAs. + + This fix is needed to solve the problems reported by Thomas + Walpuski, previous diff was not sufficient. Pointed out by + Thomas. Thanks! + +2004-06-10 14:54 hshoexer + + * ike_phase_1.c, ike_quick_mode.c, ipsec.c, message.c, message.h: + Mark authenticated messages explicitly. Better check for + authentication before deleteing SAs. + + This fix is needed to solve the problems reported by Thomas + Walpuski, previous diff was not sufficient. Pointed out by + Thomas. Thanks! + + ok ho@ niklas@, testing and spellcheck by todd@ msf@ + +2004-06-09 23:15 brad + + * message.c: MFC: Fix by hshoexer@ + + only accept DELETEs during an authenticated INFORMATIONAL + exchange. Fix for recent problem disclosed by Thomas Walpuski. + +2004-06-09 22:48 brad + + * message.c: MFC: Fix by hshoexer@ + + only accept DELETEs during an authenticated INFORMATIONAL + exchange. Fix for recent problem disclosed by Thomas Walpuski. + +2004-06-09 16:02 ho + + * conf.c, exchange.c, ike_phase_1.c, ike_quick_mode.c, ipsec.c, + isakmp_cfg.c, message.c, pf_key_v2.c, transport.c, udp.c: Style + nits. hshoexer@ ok + +2004-06-09 14:59 hshoexer + + * message.c: only accept DELETEs during an authenticated + INFORMATIONAL exchange. Fix for recent problem disclosed by + Thomas Walpuski. + + ok ho@ + +2004-06-06 15:05 ho + + * ike_phase_1.c: Style (KNF, 80c). No binary change. + +2004-06-02 18:19 hshoexer + + * ike_auth.c, x509.c: remove unused BIO-functions. + + ok markus@ ho@ + +2004-05-27 00:17 hshoexer + + * ike_auth.c: do not leak fd on error path. + + ok ho@ + +2004-05-24 16:54 hshoexer + + * util.c: Use correct function names in log messages. Kill some + spaces. + + ok deraadt@ ho@ + +2004-05-23 20:17 hshoexer + + * field.c, field.h, hash.c, if.c, ike_aggressive.c, + ike_aggressive.h, ike_auth.c, ike_main_mode.c, ike_main_mode.h, + ipsec.c, ipsec.h, isakmp_cfg.c, isakmp_cfg.h, isakmp_doi.c, + isakmpd.c, key.c, log.c, log.h, math_2n.c, math_ec2n.c, + math_ec2n.h, math_group.c, message.c, message.h, monitor.c, + monitor_fdpass.c, pf_key_v2.h, policy.c, prf.c, sa.c, sa.h, + timer.c, timer.h, udp.c, ui.c, util.c, x509.c, x509.h: More KNF. + Mainly spaces and line-wraps, no binary change. + + ok ho@ + +2004-05-23 18:14 deraadt + + * if.c, udp.c: remove excessive monitor_ prefixes + +2004-05-23 18:14 deraadt + + * policy.c, util.c, util.h: stat before open is flawed + +2004-05-23 18:13 deraadt + + * key.c: greater care with arguments + +2004-05-19 16:30 ho + + * ipsec.c, isakmpd.c: Permit symbolic protocol and service names, + such as "Protocol= tcp", in the <IPsec-ID> sections. hshoexer@ ok + +2004-05-14 10:42 hshoexer + + * attribute.c, attribute.h, cert.c, cert.h, conf.c, conf.h, + connection.c, cookie.c, cookie.h, crypto.c, crypto.h, dh.h, + dnssec.c, dnssec.h, doi.c, doi.h: Some more KNF, no binary + change. + + ok ho@ + +2004-05-13 08:56 ho + + * connection.c, isakmpd.8, sa.c, sa.h, ui.c, ui.h: Extensions to + the FIFO interface: "C get [section]:tag" fetches a configuration + value. "C add [section]:tag=value" adds 'value' to a list, + typically for the [Phase 2]:Connections tag. FIFO "S" command + destination file changed. Various KNF cleanups. hshoexer@ ok. + +2004-05-10 20:34 deraadt + + * monitor.c: 64bit gcc saw missing cast + +2004-05-06 12:40 ho + + * exchange.c: KNF cleanup. hshoexer@ ok + +2004-05-03 23:23 hshoexer + + * exchange.c, exchange.h: KNF. ok ho@ + +2004-04-30 00:36 hshoexer + + * message.c: Better checking of minimum payload lengths. Drop out + safely when an unknown payload type is encountered. While + around, do some KNF. + + ok ho@ + +2004-04-28 22:20 hshoexer + + * ike_quick_mode.c, policy.c, policy.h: remove unused variable and + shorten names of two other. Removed some spaces while around. + + ok ho@ markus@ + +2004-04-28 16:40 ho + + * ipsec_num.cst, isakmp_num.cst: Reserve some payload numbers for + RFC 3547 and the earlier NAT-T drafts. hshoexer@ ok. + +2004-04-23 16:15 ho + + * conf.c, conf.h: Make sure KEY_LENGTH attribute is present when + checking AES proposals, required when acting as responder to + SafeNet peers. Also make conf_load_defaults() readable again + (KNF). hshoexer@ ok. + +2004-04-15 22:20 deraadt + + * conf.c: more knf; ok hshoexer + +2004-04-15 20:53 deraadt + + * conf.c: knf + +2004-04-15 20:39 deraadt + + * app.c, app.h, attribute.c, attribute.h, cert.c, cert.h, conf.c, + conf.h, connection.c, connection.h, constants.c, constants.h, + cookie.c, cookie.h, crypto.c, crypto.h, dh.c, dh.h, dnssec.c, + dnssec.h, doi.c, doi.h, exchange.h, field.c, field.h, + genconstants.sh, genfields.sh, gmp_util.c, gmp_util.h, hash.c, + hash.h, if.c, if.h, ike_aggressive.c, ike_aggressive.h, + ike_auth.c, ike_auth.h, ike_main_mode.c, ike_main_mode.h, + ike_phase_1.c, ike_phase_1.h, ike_quick_mode.c, ike_quick_mode.h, + init.c, init.h, ipsec.c, ipsec.h, ipsec_doi.h, isakmp.h, + isakmp_cfg.c, isakmp_cfg.h, isakmp_doi.c, isakmp_doi.h, + isakmpd.c, key.c, key.h, libcrypto.c, libcrypto.h, log.c, log.h, + math_2n.c, math_2n.h, math_ec2n.c, math_ec2n.h, math_group.c, + math_group.h, math_mp.h, message.c, message.h, monitor.c, + monitor.h, monitor_fdpass.c, pf_key_v2.c, pf_key_v2.h, policy.c, + policy.h, prf.c, prf.h, sa.c, sa.h, sysdep.h, timer.c, timer.h, + transport.c, transport.h, udp.c, udp.h, ui.c, ui.h, util.c, + util.h, x509.c, x509.h, sysdep/openbsd/keynote_compat.c, + sysdep/openbsd/sysdep.c: partial move to KNF. More to come. + This has happened because there are a raft of source code + auditors who are willing to help improve this code only if this + is done, and hey, isakmpd does need our standard auditing + process. ok ho hshoexer + +2004-04-15 02:27 deraadt + + * isakmpd.8: spaces + +2004-04-13 23:48 hshoexer + + * if.c: Add missing #include. Found by Stefan Paletta. + + ok henning@ ho@ + +2004-04-08 18:08 henning + + * sysdep/linux/sys/queue.h: swap the last two parameters to + TAILQ_FOREACH_REVERSE. matches what FreeBSD and NetBSD do. ok + millert@ mcbride@ markus@ ho@, checked to not affect ports by + naddy@ + +2004-04-08 12:05 hshoexer + + * init.c, isakmpd.c: Set timezone before privsep, child uses now + correct timezone. Noticed by david@ + + ok ho@ david@ + +2004-04-08 00:45 ho + + * conf.h, exchange.h, ike_auth.c, ike_phase_1.c, ike_quick_mode.c, + ipsec.c, log.c, math_2n.c, math_group.c, math_group.h, message.c, + monitor.c, pf_key_v2.c, policy.c, sa.c, udp.c, ui.c, util.c, + x509.c, regress/crypto/cryptotest.c: -Wsign-compare nits. + hshoexer@ ok. + +2004-04-08 00:45 ho + + * key.c: Reset *data in case of unknown key types + +2004-04-08 00:43 ho + + * Makefile: -Wmissing-declarations + +2004-04-07 22:04 ho + + * sa.c: More careful when walking LIST queues. hshoexer@, david@ + ok. + +2004-03-31 12:54 ho + + * cert.c, crypto.c, exchange.c, hash.c, ike_auth.c: -Wsign-compare + nits. hshoexer@ ok. + +2004-03-31 12:53 ho + + * monitor.c: Use sysdep_sa_len() instead of sa->sa_len, also + correct a log_fatal() message. hshoexer@ ok. + +2004-03-31 12:47 ho + + * isakmpd.c, sysdep/openbsd/Makefile.sysdep: Don't assume + closefrom(2) exists everywhere. hshoexer@, markus@ ok. + +2004-03-29 19:07 deraadt + + * monitor.c: use malloc (oops) + +2004-03-29 18:32 deraadt + + * monitor.c: wrong FD_ZERO(); from ho, hshoexer, markus + +2004-03-29 18:32 deraadt + + * udp.c: memory mishandling; from ho + +2004-03-24 17:44 hshoexer + + * isakmpd.8: Add some notes about privsep to manpage. + + ok ho@ jmc@ deraadt@ + +2004-03-23 19:20 hshoexer + + * monitor.c: Remove erroneous null termination. + + ok ho@ deraadt@ + +2004-03-19 15:04 hshoexer + + * Makefile, conf.c, conf.h, if.c, ike_auth.c, isakmpd.c, log.c, + monitor.c, monitor.h, policy.c, sa.c, udp.c, ui.c, x509.c: Add + missing bits to make already present privsep code work. Enable + privsep. + + ok ho@ deraadt@ markus@ + +2004-03-17 16:05 brad + + * doi.h, ike_quick_mode.c, ipsec.c, isakmp_cfg.c, isakmp_doi.c, + message.c, util.h: MFC: Fix by hshoexer@ + + Fix payload handling flaws found by cloder@. Based on initial + patch by cloder@. + + ok deraadt@ hshoexer@ + +2004-03-17 15:59 brad + + * doi.h, ike_quick_mode.c, ipsec.c, isakmp_cfg.c, isakmp_doi.c, + message.c, util.h: MFC: Fix by hshoexer@ + + Fix payload handling flaws found by cloder@. Based on initial + patch by cloder@. + + ok deraadt@ hshoexer@ + +2004-03-17 12:10 ho + + * ike_auth.c: For consistency and to avoid a rare memory leak, the + result from ike_auth_get_key() should always be released after + use. Found and ok hshoexer@. + +2004-03-15 17:34 hshoexer + + * monitor.c: Properly check succes of chroot(). + + ok ho@ + +2004-03-15 17:29 hshoexer + + * monitor.c, monitor.h: Remove unused code. + + ok ho@ + +2004-03-11 17:56 hshoexer + + * isakmp_cfg.c: Fix a memleak. + + ok ho@ + +2004-03-11 00:08 hshoexer + + * doi.h, ipsec.c, isakmp_doi.c, message.c, util.h: Fix payload + handling flaws found by cloder@. Based on initial patch by + cloder@. Testing by markus@ cloder@ hshoexer@. + + ok ho@ + +2004-03-10 17:10 hshoexer + + * message.c: Plug up memory leak. + + ok ho@ + +2004-03-10 12:17 hshoexer + + * message.c: Reduce some noise on receipt of an invalid spi. + + ok ho@ + +2004-03-10 10:28 ho + + * pf_key_v2.c: Fix for PR2429, from Clemens Wittinger. + +2004-03-09 22:42 hshoexer + + * message.c: Plug memleaks, found by cloder@. + + ok ho@ + +2004-02-27 20:14 hshoexer + + * ipsec.c: Remove dead code. + + ok ho@ + +2004-02-27 20:07 hshoexer + + * conf.c, isakmpd.conf.5: Add group 14 (modp2048) to predefined + suites. Manpage also updated. ok ho@ + +2004-02-27 11:16 ho + + * ike_phase_1.c, ike_quick_mode.c, sa.c, sa.h: (C)-2004 + +2004-02-27 10:01 ho + + * ike_phase_1.c, ike_quick_mode.c, sa.c, sa.h: Follow RFC 2408 more + closely regarding how to better check the proposal returned by + the other peer (the responder). Some implementations (notably the + Cisco PIX) does not follow a SHOULD in section 4.2 of the RFC. + With certain proposal combinations this caused us to setup the + wrong SA resulting in us being unable to process incoming IPsec + traffic (over this tunnel). + + Tested against a number of different IKE implementations. + hshoexer@ ok. + +2004-02-26 16:27 hshoexer + + * regress/rsakeygen/rsakeygen.c: remove unused code. noticed by + ho@ ok ho@ + +2004-02-26 06:52 jmc + + * isakmpd.conf.5: tweak; ok hshoexer@ + +2004-02-25 17:01 hshoexer + + * init.c, isakmpd.conf.5, log.c, log.h, regress/b2n/Makefile, + regress/crypto/Makefile, regress/crypto/cryptotest.c, + regress/dh/Makefile, regress/ec2n/Makefile, + regress/group/Makefile, regress/prf/Makefile, + regress/rsakeygen/Makefile, regress/rsakeygen/rsakeygen.c, + regress/util/Makefile: Add and document configuration options + Logverbose and Loglevel. As log.c now depends on conf.c and some + regression tests use log.c, add conf.c to Makefiles where + necessary. + + ok ho@ + +2004-02-20 12:31 hshoexer + + * ike_quick_mode.c: More small adjustments of log messages. + +2004-02-20 10:46 hshoexer + + * ike_quick_mode.c: Fix some double free errors. While around, + adjust a log message. ok ho@ + +2004-02-19 16:35 hshoexer + + * isakmpd.c: small cleanup of log messages. ok ho@ + +2004-02-19 10:54 ho + + * isakmpd.c, log.c, log.h: With -d, SIGINT should do a clean + shutdown. Without -d, logs should be sent to syslog, level + LOG_INFO. + +2004-02-19 10:46 ho + + * isakmpd.c: Cleanup. + +2004-02-16 21:40 markus + + * exchange.c: check for isakmp_sa->transport != NULL; noticed by + bluhm at genua.de ok hshoexer@ + +2004-02-11 09:55 jmc + + * samples/VPN-3way-template.conf: typo; from Olivier Cherrier; + +2004-02-05 12:01 hshoexer + + * exchange.c: small logging cleanup and improvement requested by + markus ok ho@ markus@ + +2004-01-26 15:56 niklas + + * regress/exchange/run.pl: Added 2-clause license + +2004-01-24 00:08 jmc + + * isakmpd.8: `Ns' implies `No', so `Ns No' -> `Ns'; (even simpler + in adduser(8)) discussed with todd@ + +2004-01-16 11:51 hshoexer + + * exchange.c, ike_quick_mode.c, isakmpd.8, isakmpd.c, log.c, log.h: + Added -v option. Enables logging of successful exchange + completion. ok ho@ + +2004-01-16 01:00 brad + + * exchange.c, ipsec.c, message.c: Fixes a few message handling + flaws in isakmpd as reported by Thomas Walpuski. + + ok deraadt@ hshoexer@ + +2004-01-13 23:50 brad + + * crypto.c, crypto.h, exchange.c, ipsec.c, message.c: Fixes a few + message handling flaws in isakmpd as reported by Thomas Walpuski. + + ok deraadt@ hshoexer@ + +2004-01-09 11:03 hshoexer + + * regress/exchange/run.sh: call nc correctly (nc has changed a + while ago). ok markus@ + +2004-01-06 01:22 hshoexer + + * conf.c, sa.c: small typos fixed. + + ok markus@ + +2004-01-06 01:09 hshoexer + + * x509.c: Remove redundant test for file types. Noted by Stefan + Paletta. While around, fix typos in log messages. + + Both ok markus@ + +2004-01-03 17:38 ho + + * ipsec.c: Be more careful with INITIAL-CONTACT and do not delete + SPIs when getting an INVALID-SPI notification. Issues noted by + Thomas Walpuski. markus@ ok. + +2003-12-22 19:13 markus + + * crypto.h: use AES_BLOCK_SIZE only for USE_AES; report + martti.kuparinen@iki.fi; ok ho@ + +2003-12-18 03:03 ho + + * transport.c: Mention the exchange name when giving up on a + message. Suggested by Michael Coulter. + +2003-12-15 11:06 hshoexer + + * ipsec.c, ipsec_num.cst, math_group.c, math_group.h: Support for + groups modp2048, modp3072, modp4096, modp6144 and modp8192 (IDs + 14 to 18). + + ok ho@ + +2003-12-14 15:50 ho + + * log.c, util.c, util.h: Log the actual port for src and dst, don't + assume it's always 500. + +2003-12-14 15:34 ho + + * sysdep/linux/sysdep.c: Make isakmpd work on big endian linux + machines. From Sebastian Klemke. Also, a few style nits and a + better error message text. + +2003-12-05 14:17 ho + + * message.c: Style nits + +2003-12-04 23:44 hshoexer + + * message.c: Validate SPIs presented in DELETE messages of the + informational exchange. ok markus@ + +2003-12-04 22:13 miod + + * ike_phase_1.c, isakmp_cfg.c: Typos + +2003-11-20 12:23 jmc + + * isakmpd.8: use .Dv for AF_INET and AF_INET6 (kills ugly line + break); spotted by Alexey E. Suslikov; + + also kill some .Pp's before displays/lists for better PostScript + output; + +2003-11-08 20:17 jmc + + * init.c: typos from Jonathon Gray; + +2003-11-07 11:16 jmc + + * x509.c, samples/VPN-3way-template.conf: adress -> address, and a + few more; all from Jonathon Gray; + + (mvme68k/mvme88k) vs.c and (vax) if_le.c ok miod@ isakmpd ones ok + ho@ +End of changelog debian package isakmpd.20031107-1 +-------------------------------------------------- + +2003-11-06 17:12 ho + + * dnssec.c, exchange.c, field.c, if.c, ike_auth.c, ipsec.c, key.c, + log.c, message.c, message.h, monitor_fdpass.c, pf_key_v2.c, + policy.c, ui.c, x509.c, x509.h: Style nits. + +2003-11-06 16:55 ho + + * exchange.c, message.c: Require encrypted messages are soon as we + have the keystate for it. Require DELETE payloads to be + accompanied by HASHes, and add validation for HASH payloads + without active exchanges. From Hans-Joerg Hoexer with various + modifications and suggestions from me and markus@. Ok markus@. + +2003-11-06 16:50 ho + + * ipsec.c: spis[] type tweak. From Hans-Joerg Hoexer. + +2003-11-05 13:55 jmc + + * isakmpd.conf.5: PFS: Perfect Forward Secrecy (RFC 2409); from + misc@ and ok markus@ + +2003-11-05 13:31 jmc + + * QUESTIONS: updated URL from Jared Yanovich; + +2003-10-25 22:47 mcbride + + * isakmpd.policy.5: OpenSSL generates DNs with emailAddress, not + Email. + +2003-10-25 09:47 jmc + + * isakmpd.8: receiveing -> receiving; from Jared Yanovich; + +2003-10-14 16:29 ho + + * exchange.c, ike_auth.c, ike_phase_1.c, ipsec.c, isakmp_doi.c: + constant_lookup() to constant_name() cleanup. markus@ ok. + +2003-10-13 15:57 ho + + * isakmpd.8, log.h, ui.c: Add a UI FIFO debug class. ok markus@ + plus I think henning@ + +2003-10-04 19:29 cloder + + * ike_phase_1.c: Avoid crash on invalid config file (missing value + for LIFE_DURATION). OK ho@ + +2003-09-26 17:59 aaron + + * sysdep/freeswan/klips.c: Fix off-by-ones in format string for 's' + specifier; millert@, deraadt@ ok + +2003-09-26 13:29 cedric + + * udp.c: don't listen to INADDR_ANY if Listen-on is specified. + patch from markus@, ok ho@ + +2003-09-26 00:28 aaron + + * monitor.c: Fix off-by-one out-of-bounds write; millert@ ok + +2003-09-25 16:15 cloder + + * exchange.c, if.c: Fix one case of set length before realloc. Fix + another case of foo = realloc(foo...) and avoid possible memory + leaks. Avoid leaving things pointing to freed memory on failure. + +2003-09-24 13:12 markus + + * crypto.c, crypto.h, regress/crypto/cryptotest.c: re-add AES, but + without using EVP; patch from Hans-Joerg.Hoexer at + yerbouti.franken.de; ok ho@ (interops with isakmpd+AES in OpenBSD + 3.4) + +2003-09-24 12:13 markus + + * crypto.c, crypto.h, regress/crypto/cryptotest.c: back out EVP + change; causes fd leaks; ok cedric@ + +End of changelog debian package isakmpd.20030907-1 +-------------------------------------------------- + +2003-09-05 09:50 tedu + + * monitor.c: socket leak on error paths. from Patrick Latifi. ok + deraadt@ ho@ + +2003-09-02 20:15 ho + + * conf.c, ipsec.c: A couple of nits. deraadt@ ok. + +2003-09-02 20:14 ho + + * message.c: Require ISAKMP_FLAGS_ENC on phase 2 messages. ok + markus@, deraadt@. + +2003-09-02 20:11 ho + + * sysdep/linux/: bitstring.h, sys/queue.h: For easier compilation + on linux systems. Requested by Thomas Walpuski. + +2003-08-28 16:43 markus + + * Makefile, TO-DO, conf.c, crypto.c, crypto.h, isakmpd.conf.5, + regress/crypto/Makefile, regress/crypto/cryptotest.c: support AES + in phase 1, too. switch to OpenSSL EVP interface; with + Hans-Joerg.Hoexer at yerbouti.franken.de; ok ho@ + +2003-08-20 16:43 ho + + * samples/singlehost-west.conf: Zap an old "Identification" tag in + this sample config. I have no idea what it was supposed to do and + in any case there is no reference to this tag in current code. + Pointed out by Fridtjof Busse. + +2003-08-20 14:25 ho + + * isakmpd.8: certpatch(8) can be used to create FQDN X509v3 + extensions too. From Fridtjof Busse, via henning@. Thanks. + + +End of changelog debian package isakmpd.20030820-1 +-------------------------------------------------- + +2003-07-09 10:16 jmc + + * isakmpd.conf.5, isakmpd.policy.5: - remove some .Ss's that worked + around the old blank line bug - remove some unnecessary .Pp's - + mdoc a list + + ok ho@ + +2003-06-20 11:14 ho + + * transport.c: Be a bit more verbose when we give up on ever seeing + a response to the last message we sent out. In case we initiated + the exchange, one possible and common reason is a network level + problem (pf, routing, whatnot), if we're the responder, there is + also the possibility we were scanned by something like ike-scan. + markus@ ok. + +2003-06-17 23:56 millert + + * sysdep/common/libsysdep/: strlcat.c, strlcpy.c: Sync with + share/misc/license.template and add missing DARPA credit where + applicable. + +2003-06-15 12:32 ho + + * exchange.c: ID copying should happen earlier in exchange_finalize + so that we won't lose data during rekeying. From Jean-Francois + Dive. + +2003-06-14 13:47 ho + + * message.c: allocate payload_node with calloc instead of malloc + +2003-06-13 05:50 brad + + * ipsec.c: MFC: Fix from ho@ + + Do not crash on unsupported IPSec ID types, as noted by Eric + Boudrand. + + deraadt@ millert@ ok + +2003-06-13 05:34 brad + + * ipsec.c: MFC: Fix from ho@ + + Do not crash on unsupported IPSec ID types, as noted by Eric + Boudrand. + + deraadt@ millert@ ok + +2003-06-10 18:41 deraadt + + * conf.c, exchange.c, ike_auth.c, ike_phase_1.c, ike_quick_mode.c, + isakmp_cfg.c, log.c, monitor.c, monitor.h, pf_key_v2.c, policy.c, + transport.c, udp.c, x509.c: boring cleanups + +2003-06-10 14:21 ho + + * ipsec.c: Do not crash on unsupported IPSec ID types, as noted by + Eric Boudrand. + +2003-06-04 09:31 ho + + * exchange.c, ike_aggressive.c, ike_auth.c, ike_phase_1.c, + ike_quick_mode.c, init.c, ipsec.c, ipsec.h, isakmpd.8, isakmpd.c, + isakmpd.policy.5, libcrypto.c, libcrypto.h, message.c, message.h, + pf_key_v2.c, policy.c, policy.h, sa.c, sa.h, udp.c, x509.c, + x509.h, apps/certpatch/certpatch.8, apps/certpatch/certpatch.c, + regress/ec2n/ec2ntest.c, regress/hmac/hmactest.c: Remove the rest + of clauses 3 and 4. Approved by Niklas Hallqvist, Angelos D. + Keromytis and Niels Provos. + +2003-06-04 09:27 ho + + * DESIGN-NOTES: Remove 3 and 4 from the "license to use" + +2003-06-03 17:20 ho + + * sysdep/linux/: GNUmakefile.sysdep, sysdep-os.h, sysdep.c: Remove + clause 3. Approved by niklas@ and Thomas Walpuski. + +2003-06-03 17:02 ho + + * sysdep/linux/README: Obsolete. + +2003-06-03 16:53 ho + + * sysdep/: bsdi/GNUmakefile.sysdep, bsdi/Makefile.sysdep, + bsdi/sysdep-os.h, bsdi/sysdep.c, darwin/GNUmakefile.sysdep, + darwin/Makefile.sysdep, darwin/sysdep-os.h, darwin/sysdep.c, + freebsd/GNUmakefile.sysdep, freebsd/Makefile.sysdep, + freebsd/sysdep-os.h, freebsd/sysdep.c, + freeswan/GNUmakefile.sysdep, freeswan/Makefile.sysdep, + freeswan/klips.c, freeswan/klips.h, freeswan/sysdep-os.h, + freeswan/sysdep.c, netbsd/GNUmakefile.sysdep, + netbsd/Makefile.sysdep, netbsd/sysdep-os.h, netbsd/sysdep.c, + openbsd/GNUmakefile.sysdep, openbsd/Makefile.sysdep, + openbsd/keynote_compat.c, openbsd/sysdep-os.h, openbsd/sysdep.c: + Remove clauses 3 and 4. Approved by markus@ and niklas@. + +2003-06-03 16:52 ho + + * sysdep/common/: blf.h, libsysdep/GNUmakefile, libsysdep/Makefile, + libsysdep/blowfish.c: Remove clauses 3 and 4. Approved by Niklas + Hallqvist and Niels Provos. + +2003-06-03 16:39 ho + + * regress/Makefile, regress/check.sh, regress/b2n/b2ntest.c, + regress/crypto/cryptotest.c, regress/dh/dhtest.c, + regress/exchange/Makefile, regress/exchange/run.sh, + samples/Makefile, regress/group/grouptest.c, + regress/prf/prftest.c, regress/rsakeygen/Makefile, + regress/rsakeygen/rsakeygen.c, regress/util/utiltest.c, + regress/x509/Makefile, regress/x509/x509test.c: Remove clauses 3 + and 4. Approved by Niklas Hallqvist and Niels Provos. + +2003-06-03 16:35 ho + + * apps/: Makefile, certpatch/Makefile: Remove clauses 3 and 4. + Approved by Niklas Hallqvist and Niels Provos. + +2003-06-03 16:34 ho + + * apps/keyconv/: Makefile, keyconv.8, keyconv.c, keyvalues.h: + Remove clause 3. + +2003-06-03 16:29 ho + + * features/: aggressive, dnssec, ec, isakmp_cfg, policy, privsep, + x509: Remove clause 3. Approved by niklas@ + +2003-06-03 16:28 ho + + * GNUmakefile, Makefile, app.c, app.h, attribute.c, attribute.h, + cert.c, cert.h, conf.c, conf.h, connection.c, connection.h, + constants.c, constants.h, cookie.c, cookie.h, crypto.c, crypto.h, + dh.c, dh.h, dnssec.c, dnssec.h, doi.c, doi.h, exchange.h, + exchange_num.cst, field.c, field.h, genconstants.sh, + genfields.sh, gmp_util.c, gmp_util.h, hash.c, hash.h, if.c, if.h, + ike_aggressive.h, ike_auth.c, ike_auth.h, ike_main_mode.c, + ike_main_mode.h, ike_phase_1.h, ike_quick_mode.h, init.c, init.h, + ipsec_doi.h, ipsec_fld.fld, ipsec_num.cst, isakmp.h, + isakmp_cfg.c, isakmp_cfg.h, isakmp_doi.c, isakmp_doi.h, + isakmp_fld.fld, isakmp_num.cst, isakmpd.conf.5, log.c, log.h, + math_2n.c, math_2n.h, math_ec2n.c, math_ec2n.h, math_group.c, + math_group.h, math_mp.h, monitor.c, monitor.h, pf_key_v2.h, + prf.c, prf.h, sysdep.h, timer.c, timer.h, transport.c, + transport.h, udp.h, ui.c, ui.h, util.c, util.h: Remove clauses 3 + and 4. With approval from Niklas Hallqvist and Niels Provos. + +2003-06-03 15:16 jmc + + * isakmpd.8, isakmpd.conf.5, isakmpd.policy.5: - section reorder - + some mdoc fixes + +2003-06-03 14:51 ho + + * conf.c, constants.c, dnssec.c, exchange.c, ike_auth.c, + ike_phase_1.c, ike_quick_mode.c, ipsec.c, log.c, message.c, + policy.c, sa.c, udp.c, x509.c: Cleanup. Use 'sizeof variable' + instead of magic constants. + +2003-06-03 03:52 millert + + * sysdep/common/libsysdep/: strlcat.c, strlcpy.c: Use an ISC-tyle + license for all my code; it is simpler and more permissive. + +2003-06-02 22:06 millert + + * sysdep/freeswan/sys/queue.h: Remove the advertising clause in the + UCB license which Berkeley rescinded 22 July 1999. Proofed by + myself and Theo. + +2003-05-18 23:26 ho + + * monitor.c: Add some path sanitation; only permit write operations + to /tmp, /var/tmp and /var/run. Opens in /etc/isakmpd/ are + read-only. Any other path is invalid. markus@ ok. + +2003-05-18 22:46 ho + + * init.c: Style tweak. + +2003-05-18 22:39 ho + + * sa.c: Add a debug message to sa_reinit() to indicate when we + renegotiate active connections. + +2003-05-18 22:09 ho + + * monitor_fdpass.c: Forgot to remove a couple of debug messages + +2003-05-18 22:06 ho + + * udp.c: struct sockaddr is not large enough in itself to contain + the address value. Switching to sockaddr_storage makes interface + rescanning work properly. niklas@ ok. + +2003-05-18 21:37 ho + + * conf.c, ike_auth.c, isakmpd.c, log.c, monitor.c, monitor.h, + monitor_fdpass.c, pf_key_v2.c, policy.c: More isakmpd privsep + work. X509 private keys are now kept in the privileged process + only. Various cleanup and bugfixes. markus@ ok + +2003-05-18 20:16 ho + + * GNUmakefile, pf_key_v2.c, udp.c, sysdep/linux/GNUmakefile.sysdep, + sysdep/linux/sysdep-os.h, sysdep/linux/sysdep.c: Sysdep for + native Linux IPSec, 2.5 and later. From Thomas Walpuski, with + various tweaks by me. niklas@ ok. + +2003-05-17 19:39 ho + + * monitor.h, monitor_fdpass.c: Better return codes from mm_send_fd + and mm_receive_fd + +2003-05-17 19:32 ho + + * monitor_fdpass.c: Use log_error(), not log_fatal(). Style. + +2003-05-17 19:26 jmc + + * isakmpd.conf.5: tweak; ok ho@ + +2003-05-16 22:31 ho + + * init.c, isakmpd.conf.5, sa.c, sa.h: If the "Renegotiate-on-HUP" + tag is defined in the [General] section, a HUP signal (or "R" to + the FIFO) will also renegotiate all Phase 2 SAs, i.e all + connections. ok niklas@, tested and ok kjell@. + +2003-05-15 05:20 ho + + * ike_auth.c: Correct a two year old typo, which might actually + make setsockopt(..., IP_IPSEC_LOCAL_AUTH, ...) start working. + +2003-05-15 04:28 ho + + * exchange.c, ike_auth.c, sa.c, sa.h: Cleanup. Do not store the + private key in either the exchange or sa structs. + +2003-05-15 04:08 ho + + * ike_auth.c: Work around some OpenSSL BIO "features" to read the + key correctly. + +2003-05-15 04:04 ho + + * monitor.c: Proper exit of the monitor process. + +2003-05-15 03:51 ho + + * monitor.c: wait() for the child process + +2003-05-15 02:28 ho + + * Makefile, conf.c, conf.h, ike_auth.c, init.c, isakmpd.c, log.c, + monitor.c, monitor.h, monitor_fdpass.c, pf_key_v2.c, policy.c, + udp.c, ui.c, util.c, features/privsep, sysdep/openbsd/sysdep.c: + Start of privilege separation for isakmpd. There are some kinks + left, so keep it default disabled for now. markus@ says ok to + commit. + +2003-05-15 02:24 ho + + * log.h: (c) + +2003-05-15 01:44 kjell + + * pf_key_v2.c: properly terminate debug string (levels >=40) Use + "%.*s" as suggested by Niklas. ok ho@. Lost by kjell. oked ho@. + lost by kjell again. oked ho@ + +2003-05-15 01:29 ho + + * features/policy: Remove the .if/.endif stuff that gmake does not + understand. Replace with a comment about needing keynote for + policy. + +2003-05-14 22:49 ho + + * GNUmakefile, Makefile, sysdep/freeswan/GNUmakefile.sysdep, + sysdep/freeswan/Makefile.sysdep, sysdep/freeswan/README, + sysdep/freeswan/klips.c, sysdep/freeswan/klips.h, + sysdep/freeswan/sysdep-os.h, sysdep/freeswan/sysdep.c, + sysdep/freeswan/sys/queue.h, sysdep/linux/GNUmakefile.sysdep, + sysdep/linux/Makefile.sysdep, sysdep/linux/README, + sysdep/linux/klips.c, sysdep/linux/klips.h, + sysdep/linux/sysdep-os.h, sysdep/linux/sysdep.c: Call the + FreeS/WAN sysdep 'freeswan'. The 'linux' sysdep will be native + Linux IPSec. + +2003-05-14 20:11 ho + + * conf.c, conf.h, ike_auth.c: Default public key directory + definition sanity. + +2003-05-14 20:10 ho + + * policy.c, policy.h: Policy file default defined twice, kill the + local copy. + +2003-05-14 20:08 ho + + * isakmpd.c: Fix a typo (in unused code). + +2003-05-14 19:37 ho + + * ipsec.c, ipsec_num.cst, pf_key_v2.c, policy.c, sa.c: I did not + test this enough. Unbreak. + +2003-05-12 23:48 ho + + * isakmp_num.cst: Update with some data for NAT-T specific payload + types, IKEv2 notifications, ISAKMP EAP code and types, plus fix + an old typo. + +2003-05-12 23:43 ho + + * ipsec.c, pf_key_v2.c, policy.c, sa.c: AES -> AES_128_CBC + +2003-05-12 23:42 ho + + * ipsec_num.cst: Add two more encapsulation types (UDP encap, + potential future NAT-T) Add BLOCK_SIZE attribute Rename + IPSEC_ESP_AES -> IPSEC_ESP_AES_128_CBC. + +2003-05-12 01:17 ho + + * genconstants.sh: Slight style fix for .cst files. Permit comments + also after a definition. + +2003-05-11 04:16 markus + + * pf_key_v2.c: fix ID-type for ipv6; ok niklas; report fries + +2003-05-10 23:13 jmc + + * isakmpd.8, isakmpd.conf.5: typos; + +2003-04-30 17:15 jason + + * conf.c: cast size_t to unsigned long and use %lu;ok ho + +2003-04-27 13:17 ho + + * isakmpd.8: Describe the 'C set' FIFO command better. (PR#3148, + also) + +2003-04-27 13:16 ho + + * ui.c: Make the 'C set' FIFO command work as expected. PR#3148. + +2003-04-14 15:08 ho + + * isakmpd.c: Unlink FIFO and pid files on clean shutdown. PR#3199 + +2003-04-14 12:22 ho + + * pf_key_v2.c: More snprintf style + +2003-04-14 12:14 ho + + * pf_key_v2.c: A "%d" is 12 chars, not 10. Use sizeof num instead + of '10' in snprintf. From Theo. + +2003-04-09 17:46 ho + + * x509.c: Less noise for missing crl dir, demoted to debug message. + +2003-03-21 16:13 markus + + * isakmpd.conf.5: document [initiator-id] section; + richb@timestone.com.au; ok ho@, jmc@ + +2003-03-20 20:39 margarida + + * isakmp_cfg.c: Pull patch from current: Fix by ho@. Proper + id_string for SET/ACK responder, plus attr payload fixes. + + ok millert@ markus@ ho@ + +2003-03-16 09:13 matthieu + + * samples/: VPN-east.conf, VPN-west.conf: secrity -> security. Ok + ho@ + +2003-03-14 15:49 ho + + * math_group.c, transport.c, sysdep/common/blf.h, + sysdep/common/libsysdep/blowfish.c: Spelling fixes from david@. + jmc@ ok. + +2003-03-13 14:24 ho + + * ike_auth.c: Might as well do blinding here too. + +2003-03-13 11:31 ho + + * util.c: Avoid "j += snprintf()". niklas@ ok. + +2003-03-06 21:29 jmc + + * isakmpd.conf.5, isakmpd.policy.5: .Xr typos; + + ok deraadt@ + +2003-03-06 15:22 cedric + + * util.c: fix text2sockaddr() when HAVE_GETNAMEINFO is false and + port is NULL. ok ho@ + +2003-03-06 14:48 cedric + + * field.c: "len" is decremented too early, so the second argument + of the snprintf call is too small on last run of the loop. ok + ho@ + +2003-03-06 14:32 ho + + * exchange.c: Bad cut'n'paste msg plus style fixes. + +2003-03-06 10:56 ho + + * util.c: Less ambiguous l-value usage. Noted by cedric@ + +2003-03-06 05:07 david + + * apps/keyconv/keyconv.8: date should be written formally: .Dd + Month day, year ok henning@ jmc@ + +2003-03-03 17:51 ho + + * isakmpd.conf.5: Re-add the BUGS section; the RFCs still do not + permit differing DH groups in the same proposal. This time, + mention that this also applies to mixing PFS and non-PFS suites. + +2003-02-26 23:55 ho + + * samples/VPN-west.conf: Typo/pasto. Spotted by Tim Donahue. + +2003-02-26 09:17 david + + * exchange.c: IPsec is written ``IPsec'', not ``IPSec''. ok ho@ + +2003-02-24 13:01 markus + + * pf_key_v2.c: pf_key_v2_flow: typo in debug msg (KAME) + +2003-02-22 07:57 kjell + + * README: typo: noneheless->nontheless + +2003-02-22 07:56 kjell + + * isakmpd.8, isakmpd.conf.5: Clarify some language, grammar. ho@ + okayed this many moons ago, and I forgot all about it. + +2003-02-12 16:11 markus + + * if.c, if.h, udp.c: better error checking on bind(); from + Alexander_Bluhm at genua.de; ok ho@ + +2003-02-05 11:29 jmc + + * isakmpd.8: typos; isakmpd(8) ok niklas@, mailwrapper(8) help + kjell@ + +2003-02-04 21:02 markus + + * conf.c: don't set the Transform for Default-phase-1-configuration + twice, ok ho@ + +2003-02-04 21:02 markus + + * conf.h: default to 3DES-SHA-RSA_SIG (same as in OpenBSD 3.2); ok + ho@ + +2003-01-22 16:13 ho + + * ike_auth.c: Typo. + +2003-01-20 20:52 deraadt + + * isakmpd.policy.5: typos; alan@alanday.com diff --git a/keyexchange/isakmpd-20041012/debian/README.Debian b/keyexchange/isakmpd-20041012/debian/README.Debian new file mode 100644 index 0000000..5ed5128 --- /dev/null +++ b/keyexchange/isakmpd-20041012/debian/README.Debian @@ -0,0 +1,17 @@ +State of the package / isakmpd port to linux +-------------------------------------------- +The port is operational and is included in upstream, from various sources. + + +Where to start +-------------- +- isakmpd.conf man pages. +- configuration examples. +- openbsd isakmpd documentation. + +caution note +------------ +- keynote is used to check for all policy components. For exemple, if acting + as initiator, isakmpd will send the isakmpd.conf configured proposals but + will only check the received proposal with the rules enforced in isakmpd.policy. + diff --git a/keyexchange/isakmpd-20041012/debian/changelog b/keyexchange/isakmpd-20041012/debian/changelog new file mode 100644 index 0000000..1883efc --- /dev/null +++ b/keyexchange/isakmpd-20041012/debian/changelog @@ -0,0 +1,153 @@ +isakmpd (20041012-4) unstable; urgency=high + + * Fix replay protection (CVE-2006-4436) + Thanks to Stefan Fritsch <sf@fritsch.de> (Closes: #385894) + + -- Jochen Friedrich <jochen@scram.de> Mon, 4 Sep 2006 18:41:00 +0200 + +isakmpd (20041012-3) unstable; urgency=low + + * Fix NAT-T RFC support. + * Remove superfluos header from packet dump so tcpdump and ethereal + can read the dump. + + -- Jochen Friedrich <jochen@scram.de> Mon, 28 Aug 2006 17:14:47 +0200 + +sakmpd (20041012-2) unstable; urgency=low + + * New maintainer (Closes: #358800) + * Replace SADB_X_SPDADD by SADB_X_SPDUPDATE (Closes: #346214) + * Fix NAT-T (Closes: #324753) + * Fix openssl incompatibility with version 0.9.8b (Closes: #334624) + * Fix dependencies (Closes: #320393, #325849) + * gcc compiler fixes (Closes: #318241) + * Update standards version to 3.7.2 + + -- Jochen Friedrich <jochen@scram.de> Tue, 21 Feb 2006 14:26:40 +0100 + +isakmpd (20041012-1) unstable; urgency=high + + * new upstream cvs merge. + * add setsockopt to properly configure udp encap socket. + * add proper source port in nat-t sadb set (thanks to Thomas Walpuski). + * DPD now works (closes: #258479). + * NAT-T now works (closes: #269851). + * remove double dependency on libkeynote0 (closes: #272377). + + -- Jean-Francois Dive <jef@debian.org> Tue, 7 Sep 2004 11:28:18 +0200 + +isakmpd (20040628-1) unstable; urgency=high + + * New upstream cvs merge. + * Enabled DPD. + * Enabled NAT-T + added support for linux nat-t pfkey msgs. + * Fix payload handling denial-of-service vuln (closes: #239739); + * Add spd cleartext entry (thanks to Vincent Bernat). (closes: #243990). + * Add dependency on linux-kernel-headers (closes: #238793). + * Add man page for isakmpd.policy. + * No issue with Renegotiate-on-HUP (closes: #255507). + * x509v3.cnf provided (closes: #238542). + * Added certpatch utility (closes: #231743). + * Fixed pcap support (closes: #238543). + + -- Jean-Francois Dive <jef@debian.org> Mon, 5 Jul 2004 23:32:47 +0200 + +isakmpd (20040204-1) unstable; urgency=low + + * Provide ike-server (closes: #223784). + * Fixes for big indian systems (thanks to Sebastian Klemke). + (closes: #223845). + * Fix for certificates file access on non ext2 enabled kernel + systems, thanks to jochen. (closes: #225474). + * Update kernel version informations. (closes: #229795). + * New upstream cvs merge. + * Added missing man page isakmpd.policy(5) (thanks to Toni Mueller). + (closes: #231123). + + -- Jean-Francois Dive <jef@debian.org> Sun, 8 Feb 2004 20:55:34 +0100 + +isakmpd (20031107-2) unstable; urgency=high + + * SECURITY fix for INITIAL_CONTACT handeling. (previous + release actually did fixed INVALID_SPI informational exchange + security issue). The problem is the exact same nature for both + type of informational messages: because the end result is SA + deletation, the HASH payload should be in the message and checked. + + -- Jean-Francois Dive <jef@debian.org> Thu, 13 Nov 2003 14:54:01 +0100 + +isakmpd (20031107-1) unstable; urgency=high + + * new upstream cvs merge. + * SECURITY fix for HASH payload handeling (closes: #219864). + * SECURITY fix handeling of quick mode exchange encryption (it now + does require quick mode to be encrypted both Rx/Tx). + * SECURITY fix for INITIAL_CONTACT handeling (did not check for + mandatory HASH payload). + * Updated linux kernel header for interop with debian x86 kernels. + * Fix issues with policy handeling in keynote. + + -- Jean-Francois Dive <jef@debian.org> Thu, 13 Nov 2003 11:05:09 +0100 + +isakmpd (20030907-1) unstable; urgency=high + + * new upstream cvs merge. + * Fixed kernel interface due to ABI changes in linux IPSec. + * Fixed keynote issue. + + -- Jean-Francois Dive <jef@debian.org> Wed, 10 Sep 2003 22:47:17 +0200 + +isakmpd (20030718-1) unstable; urgency=high + + * New upstream version. + * Merged new upstream linux native build support. + * Added fine grained selector support to upstream linux native sysdep. + * Removed useless libc and kernel headers. + * Removed libdes. + * Added generated upstream changelog (generated by cvs2cl.pl). + + -- Jean-Francois Dive <jef@debian.org> Tue, 22 Jul 2003 12:15:30 +0200 + +isakmpd (20030119-2) unstable; urgency=low + + * Fixed init script (closes: #188086). + * Added support for Protocol and Port text definition in ID handeling. + (expl: Protocol = icmp instead of Protocol = 1). + + -- Jean-Francois Dive <jef@debian.org> Mon, 9 Jun 2003 14:11:02 +0200 + +isakmpd (20030119-1) unstable; urgency=low + + * Changed version number to a sane format. + + -- Jean-Francois Dive <jef@debian.org> Thu, 20 Mar 2003 18:46:56 +0100 + +isakmpd (19012003-4) unstable; urgency=low + + * Fixed source tree clean issues (libdes, libsysdep) (closes: #184295). + * Added diff to package upload. + + -- Jean-Francois Dive <jef@debian.org> Tue, 18 Mar 2003 17:30:57 +0100 + +isakmpd (19012003-3) unstable; urgency=low + + * switched libdes copyright from copyright.libdes to + copyright file. + + -- Jean-Francois Dive <jef@debian.org> Thu, 20 Feb 2003 13:10:54 +1100 + +isakmpd (19012003-2) unstable; urgency=low + + * Added reference to BSD license and libdes license. + * Renmoved double dependency on libssl. + * Removed /usr/doc link. + * Added lintian overrides. + + -- Jean-Francois Dive <jef@debian.org> Sun, 26 Jan 2003 00:36:40 +1100 + +isakmpd (19012003-1) unstable; urgency=low + + * Inital debianization (Closes: #163904). + + -- Jean-Francois Dive <jef@debian.org> Sun, 26 Jan 2003 00:36:40 +1100 + diff --git a/keyexchange/isakmpd-20041012/debian/control b/keyexchange/isakmpd-20041012/debian/control new file mode 100644 index 0000000..ba34296 --- /dev/null +++ b/keyexchange/isakmpd-20041012/debian/control @@ -0,0 +1,17 @@ +Source: isakmpd +Maintainer: Jochen Friedrich <jochen@scram.de> +Priority: optional +Section: net +Standards-Version: 3.7.2 +Build-Depends: debhelper (>= 5), libkeynote-dev, libssl-dev, libgmp3-dev, libpcap-dev, linux-kernel-headers + +Package: isakmpd +Priority: optional +Section: net +Architecture: any +Provides: ike-server +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: The Internet Key Exchange protocol openbsd implementation + IKE is a protocol which allow to exchange security information between + to peers. This implementation requires the native linux ipsec support. + diff --git a/keyexchange/isakmpd-20041012/debian/copyright b/keyexchange/isakmpd-20041012/debian/copyright new file mode 100644 index 0000000..f418b06 --- /dev/null +++ b/keyexchange/isakmpd-20041012/debian/copyright @@ -0,0 +1,21 @@ +This package have been packaged by Jean-Francois Dive <jef@debian.org> as +isakmpd. The upstream source of isakmpd can be found at www.openbsd.org + +This package is now maintained by Jochen Friedrich <jochen@scram.de> + +- This package links against openssl. +- This package include linux kernel include files for interface definition + purposes. This should mean that GPL does not apply for this distribution. +- This package include libdes from the openbsd tree which have the same + license as openssl, please refer to the following license statement for details. + +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. Isakmpd's home is in the +OpenBSD main source tree under src/sbin/isakmpd. Look at +http://www.openbsd.org/ for details on how to get OpenBSD source. + +The isakmpd license is the BSD license, please refer to +/usr/share/common-license/BSD for details. The few code modification in isakmpd +(linux support) are authored by Jean-Francois Dive and Jochen Friedrich +and are release on the same license as isakmpd itself. diff --git a/keyexchange/isakmpd-20041012/debian/isakmpd.dirs b/keyexchange/isakmpd-20041012/debian/isakmpd.dirs new file mode 100644 index 0000000..de7adf9 --- /dev/null +++ b/keyexchange/isakmpd-20041012/debian/isakmpd.dirs @@ -0,0 +1,13 @@ +usr/sbin +usr/bin +etc/isakmpd +etc/isakmpd/certs +etc/isakmpd/crls +etc/isakmpd/ca +etc/isakmpd/pubkeys/ipv4 +etc/isakmpd/pubkeys/ipv6 +etc/isakmpd/pubkeys/fqdn +etc/isakmpd/pubkeys/ufqdn +etc/isakmpd/private +usr/share/doc/isakmpd/samples +usr/share/lintian/overrides diff --git a/keyexchange/isakmpd-20041012/debian/isakmpd.init b/keyexchange/isakmpd-20041012/debian/isakmpd.init new file mode 100644 index 0000000..57de3d4 --- /dev/null +++ b/keyexchange/isakmpd-20041012/debian/isakmpd.init @@ -0,0 +1,32 @@ +#!/bin/sh +# +PATH=/bin:/usr/bin:/sbin:/usr/sbin +DAEMON=/usr/sbin/isakmpd +PIDFILE=/var/run/isakmpd.pid + +test -f $DAEMON || exit 0 + +case "$1" in + start) + echo -n "Starting OpenBSD isakmpd: " + start-stop-daemon --start --verbose --pidfile $PIDFILE --exec $DAEMON > /dev/null 2>&1 + echo "done" + ;; + stop) + echo -n "Stopping OpenBSD isakmpd: " + start-stop-daemon --stop --verbose --pidfile $PIDFILE --exec $DAEMON > /dev/null 2>&1 + echo "done" + ;; + restart|force-reload) + echo -n "Restarting OpenBSD isakmpd: " + start-stop-daemon --stop --verbose --pidfile $PIDFILE --exec $DAEMON > /dev/null 2>&1 + start-stop-daemon --start --verbose --pidfile $PIDFILE --exec $DAEMON > /dev/null 2>&1 + echo "done" + ;; + *) + echo "Usage: /etc/init.d/isakmpd {start|stop|restart|force-reload}" + exit 1 + ;; +esac + +exit 0 diff --git a/keyexchange/isakmpd-20041012/debian/isakmpd.lintian b/keyexchange/isakmpd-20041012/debian/isakmpd.lintian new file mode 100644 index 0000000..7d9b585 --- /dev/null +++ b/keyexchange/isakmpd-20041012/debian/isakmpd.lintian @@ -0,0 +1,3 @@ +isakmpd: copyright-should-refer-to-common-license-file-for-gpl +isakmpd: non-standard-dir-perm +isakmpd: non-standard-file-perm diff --git a/keyexchange/isakmpd-20041012/debian/rules b/keyexchange/isakmpd-20041012/debian/rules new file mode 100755 index 0000000..d15e56a --- /dev/null +++ b/keyexchange/isakmpd-20041012/debian/rules @@ -0,0 +1,73 @@ +#!/usr/bin/make -f + +export DH_COMPAT := 5 + +b := $(CURDIR)/debian/isakmpd + +arrange: arrange-stamp +arrange-stamp: install + dh_testdir + touch arrange-stamp + +binary: binary-stamp +binary-stamp: binary-indep binary-arch + dh_testdir + touch binary-stamp + +binary-arch: binary-arch-stamp +binary-arch-stamp: arrange + dh_testdir + dh_testroot + dh_installdocs -n DESIGN-NOTES QUESTIONS README README.PKI TO-DO $(CURDIR)/debian/README.Debian x509v3.cnf + cp $(CURDIR)/samples/*.conf $(b)/usr/share/doc/isakmpd/samples/ + cp $(CURDIR)/samples/VPN-east.conf $(b)/etc/isakmpd/isakmpd.conf + cp $(CURDIR)/samples/policy $(b)/etc/isakmpd/isakmpd.policy + cp $(CURDIR)/isakmpd $(b)/usr/sbin/ + cp $(CURDIR)/apps/certpatch/certpatch $(b)/usr/bin + cp $(CURDIR)/debian/isakmpd.lintian $(b)/usr/share/lintian/overrides/isakmpd + dh_installman isakmpd.8 isakmpd.conf.5 isakmpd.policy.5 apps/certpatch/certpatch.8 + dh_installinit + dh_installchangelogs $(CURDIR)/debian/ChangeLog upstream + dh_compress + dh_fixperms + find $(b)/etc/isakmpd -type d | xargs chmod 0700 + find $(b)/etc/isakmpd -type f | xargs chmod 0600 + dh_strip + dh_installdeb + dh_perl + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + touch binary-arch-stamp + +binary-indep: binary-indep-stamp +binary-indep-stamp: arrange + dh_testdir + touch binary-indep-stamp + +build: build-stamp +build-stamp: config + dh_testdir + $(MAKE) + touch build-stamp + +clean: + dh_testdir + dh_testroot + $(MAKE) clean + dh_clean arrange-stamp binary-stamp binary-arch-stamp binary-indep-stamp build-stamp config-stamp install-stamp + find $(CURDIR) -type f -name ".depend" | xargs rm -f + +config: config-stamp +config-stamp: + dh_testdir + touch config-stamp + +install: install-stamp +install-stamp: build + dh_testdir + dh_installdirs + touch install-stamp + +.PHONY: arrange binary binary-arch binary-indep build clean config install diff --git a/keyexchange/isakmpd-20041012/dh.c b/keyexchange/isakmpd-20041012/dh.c new file mode 100644 index 0000000..afb41ba --- /dev/null +++ b/keyexchange/isakmpd-20041012/dh.c @@ -0,0 +1,82 @@ +/* $OpenBSD: dh.c,v 1.9 2004/04/15 18:39:25 deraadt Exp $ */ +/* $EOM: dh.c,v 1.5 1999/04/17 23:20:22 niklas Exp $ */ + +/* + * Copyright (c) 1998 Niels Provos. All rights reserved. + * Copyright (c) 1999 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. + * + * 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 "sysdep.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. + */ +int +dh_create_exchange(struct group *group, u_int8_t *buf) +{ + if (group->setrandom(group, group->c)) + return -1; + if (group->operation(group, group->a, group->gen, group->c)) + return -1; + group->getraw(group, group->a, buf); + return 0; +} + +/* + * 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. + */ +int +dh_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange) +{ + if (group->setraw(group, group->b, exchange, group->getlen(group))) + return -1; + if (group->operation(group, group->a, group->b, group->c)) + return -1; + group->getraw(group, group->a, secret); + return 0; +} diff --git a/keyexchange/isakmpd-20041012/dh.h b/keyexchange/isakmpd-20041012/dh.h new file mode 100644 index 0000000..afd00ad --- /dev/null +++ b/keyexchange/isakmpd-20041012/dh.h @@ -0,0 +1,43 @@ +/* $OpenBSD: dh.h,v 1.7 2004/05/14 08:42:56 hshoexer Exp $ */ +/* $EOM: dh.h,v 1.4 1999/04/17 23:20:24 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. + * + * 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 *); +int dh_create_exchange(struct group *, u_int8_t *); +int dh_create_shared(struct group *, u_int8_t *, u_int8_t *); + +#endif /* _DH_H_ */ diff --git a/keyexchange/isakmpd-20041012/dnssec.c b/keyexchange/isakmpd-20041012/dnssec.c new file mode 100644 index 0000000..b7ee75f --- /dev/null +++ b/keyexchange/isakmpd-20041012/dnssec.c @@ -0,0 +1,293 @@ +/* $OpenBSD: dnssec.c,v 1.20 2004/06/14 09:55:41 ho Exp $ */ + +/* + * Copyright (c) 2001 Håkan Olsson. 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. + * + * 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. + */ + +#include <sys/types.h> +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> +#include <stdlib.h> + +#include <openssl/rsa.h> + +#ifdef LWRES +#include <lwres/netdb.h> +#include <dns/keyvalues.h> +#else +#include <netdb.h> +#endif + +#include "sysdep.h" + +#include "dnssec.h" +#include "exchange.h" +#include "ipsec_num.h" +#include "libcrypto.h" +#include "log.h" +#include "message.h" +#include "transport.h" +#include "util.h" + +#ifndef DNS_UFQDN_SEPARATOR +#define DNS_UFQDN_SEPARATOR "._ipsec." +#endif + +/* adapted from <dns/rdatastruct.h> / RFC 2535 */ +struct dns_rdata_key { + u_int16_t flags; + u_int8_t protocol; + u_int8_t algorithm; + u_int16_t datalen; + unsigned char *data; +}; + +void * +dns_get_key(int type, struct message *msg, int *keylen) +{ + struct exchange *exchange = msg->exchange; + struct rrsetinfo *rr; + struct dns_rdata_key key_rr; + char name[MAXHOSTNAMELEN]; + in_addr_t ip4; + u_int8_t algorithm, *id, *umark; + size_t id_len; + int ret, i; + + switch (type) { + case IKE_AUTH_RSA_SIG: + algorithm = DNS_KEYALG_RSA; + break; + + case IKE_AUTH_RSA_ENC: + case IKE_AUTH_RSA_ENC_REV: + /* XXX Not yet. */ + /* algorithm = DNS_KEYALG_RSA; */ + return 0; + + case IKE_AUTH_DSS: + /* XXX Not yet. */ + /* algorithm = DNS_KEYALG_DSS; */ + return 0; + + case IKE_AUTH_PRE_SHARED: + default: + return 0; + } + + id = exchange->initiator ? exchange->id_r : exchange->id_i; + id_len = exchange->initiator ? exchange->id_r_len : exchange->id_i_len; + memset(name, 0, sizeof name); + + if (!id || id_len == 0) { + log_print("dns_get_key: ID is missing"); + return 0; + } + /* Exchanges (and SAs) don't carry the ID in ISAKMP form */ + id -= ISAKMP_GEN_SZ; + id_len += ISAKMP_GEN_SZ - ISAKMP_ID_DATA_OFF; + + switch (GET_ISAKMP_ID_TYPE(id)) { + case IPSEC_ID_IPV4_ADDR: + /* We want to lookup a KEY RR in the reverse zone. */ + if (id_len < sizeof ip4) + return 0; + memcpy(&ip4, id + ISAKMP_ID_DATA_OFF, sizeof ip4); + snprintf(name, sizeof name, "%d.%d.%d.%d.in-addr.arpa.", ip4 + >> 24, (ip4 >> 16) & 0xFF, (ip4 >> 8) & 0xFF, ip4 & 0xFF); + break; + + case IPSEC_ID_IPV6_ADDR: + /* XXX Not yet. */ + return 0; + break; + + case IPSEC_ID_FQDN: + if ((id_len + 1) >= sizeof name) + return 0; + /* ID is not NULL-terminated. Add trailing dot and NULL. */ + memcpy(name, id + ISAKMP_ID_DATA_OFF, id_len); + *(name + id_len) = '.'; + *(name + id_len + 1) = '\0'; + break; + + case IPSEC_ID_USER_FQDN: + /* + * Some special handling here. We want to convert the ID + * 'user@host.domain' string into 'user._ipsec.host.domain.'. + */ + if ((id_len + sizeof(DNS_UFQDN_SEPARATOR)) >= sizeof name) + return 0; + /* Look for the '@' separator. */ + for (umark = id + ISAKMP_ID_DATA_OFF; (umark - id) < id_len; + umark++) + if (*umark == '@') + break; + if (*umark != '@') { + LOG_DBG((LOG_MISC, 50, "dns_get_key: bad UFQDN ID")); + return 0; + } + *umark++ = '\0'; + /* id is now terminated. 'umark', however, is not. */ + snprintf(name, sizeof name, "%s%s", id + ISAKMP_ID_DATA_OFF, + DNS_UFQDN_SEPARATOR); + memcpy(name + strlen(name), umark, id_len - strlen(id) - 1); + *(name + id_len + sizeof(DNS_UFQDN_SEPARATOR) - 2) = '.'; + *(name + id_len + sizeof(DNS_UFQDN_SEPARATOR) - 1) = '\0'; + break; + + default: + return 0; + } + + LOG_DBG((LOG_MISC, 50, "dns_get_key: trying KEY RR for %s", name)); + ret = getrrsetbyname(name, C_IN, T_KEY, 0, &rr); + + if (ret) { + LOG_DBG((LOG_MISC, 30, "dns_get_key: no DNS responses " + "(error %d)", ret)); + return 0; + } + LOG_DBG((LOG_MISC, 80, + "dns_get_key: rrset class %d type %d ttl %d nrdatas %d nrsigs %d", + rr->rri_rdclass, rr->rri_rdtype, rr->rri_ttl, rr->rri_nrdatas, + rr->rri_nsigs)); + + /* We don't accept unvalidated data. */ + if (!(rr->rri_flags & RRSET_VALIDATED)) { + LOG_DBG((LOG_MISC, 10, "dns_get_key: " + "got unvalidated response")); + freerrset(rr); + return 0; + } + /* Sanity. */ + if (rr->rri_nrdatas == 0 || rr->rri_rdtype != T_KEY) { + LOG_DBG((LOG_MISC, 30, "dns_get_key: no KEY RRs received")); + freerrset(rr); + return 0; + } + memset(&key_rr, 0, sizeof key_rr); + + /* + * Find a key with the wanted algorithm, if any. + * XXX If there are several keys present, we currently only find the + * first. + */ + for (i = 0; i < rr->rri_nrdatas && key_rr.datalen == 0; i++) { + key_rr.flags = ntohs((u_int16_t) * rr->rri_rdatas[i].rdi_data); + key_rr.protocol = *(rr->rri_rdatas[i].rdi_data + 2); + key_rr.algorithm = *(rr->rri_rdatas[i].rdi_data + 3); + + if (key_rr.protocol != DNS_KEYPROTO_IPSEC) { + LOG_DBG((LOG_MISC, 50, "dns_get_key: ignored " + "non-IPsec key")); + continue; + } + if (key_rr.algorithm != algorithm) { + LOG_DBG((LOG_MISC, 50, "dns_get_key: ignored " + "key with other alg")); + continue; + } + key_rr.datalen = rr->rri_rdatas[i].rdi_length - 4; + if (key_rr.datalen <= 0) { + LOG_DBG((LOG_MISC, 50, "dns_get_key: " + "ignored bad key")); + key_rr.datalen = 0; + continue; + } + /* This key seems to fit our requirements... */ + key_rr.data = (char *)malloc(key_rr.datalen); + if (!key_rr.data) { + log_error("dns_get_key: malloc (%d) failed", + key_rr.datalen); + freerrset(rr); + return 0; + } + memcpy(key_rr.data, rr->rri_rdatas[i].rdi_data + 4, + key_rr.datalen); + *keylen = key_rr.datalen; + } + + freerrset(rr); + + if (key_rr.datalen) + return key_rr.data; + return 0; +} + +int +dns_RSA_dns_to_x509(u_int8_t *key, int keylen, RSA **rsa_key) +{ + RSA *rsa; + int key_offset; + u_int8_t e_len; + + if (!key || keylen <= 0) { + log_print("dns_RSA_dns_to_x509: invalid public key"); + return -1; + } + rsa = RSA_new(); + if (rsa == NULL) { + log_error("dns_RSA_dns_to_x509: " + "failed to allocate new RSA struct"); + return -1; + } + e_len = *key; + key_offset = 1; + + if (e_len == 0) { + if (keylen < 3) { + log_print("dns_RSA_dns_to_x509: invalid public key"); + RSA_free(rsa); + return -1; + } + e_len = *(key + key_offset++) << 8; + e_len += *(key + key_offset++); + } + if (e_len > (keylen - key_offset)) { + log_print("dns_RSA_dns_to_x509: invalid public key"); + RSA_free(rsa); + return -1; + } + rsa->e = BN_bin2bn(key + key_offset, e_len, NULL); + key_offset += e_len; + + /* XXX if (keylen <= key_offset) -> "invalid public key" ? */ + + rsa->n = BN_bin2bn(key + key_offset, keylen - key_offset, NULL); + + *rsa_key = rsa; + + LOG_DBG((LOG_MISC, 30, "dns_RSA_dns_to_x509: got %d bits RSA key", + BN_num_bits(rsa->n))); + return 0; +} + +#if notyet +int +dns_RSA_x509_to_dns(RSA *rsa_key, u_int8_t *key, int *keylen) +{ + return 0; +} +#endif diff --git a/keyexchange/isakmpd-20041012/dnssec.h b/keyexchange/isakmpd-20041012/dnssec.h new file mode 100644 index 0000000..90a78df --- /dev/null +++ b/keyexchange/isakmpd-20041012/dnssec.h @@ -0,0 +1,46 @@ +/* $OpenBSD: dnssec.h,v 1.7 2004/05/14 08:42:56 hshoexer Exp $ */ + +/* + * Copyright (c) 2001 Håkan Olsson. 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. + * + * 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. + */ + +#include "libcrypto.h" +#include "message.h" + +void *dns_get_key(int, struct message *, int *); +int dns_RSA_dns_to_x509(u_int8_t *, int, RSA **); + +#ifndef DNS_KEYALG_RSA +#define DNS_KEYALG_RSA 1 +#endif + +#ifndef DNS_KEYPROTO_IPSEC +#define DNS_KEYPROTO_IPSEC 4 +#endif +#ifndef DNS_KEYALG_RSA +#define DNS_KEYALG_RSA 1 +#endif + +#ifndef DNS_KEYPROTO_IPSEC +#define DNS_KEYPROTO_IPSEC 4 +#endif diff --git a/keyexchange/isakmpd-20041012/doi.c b/keyexchange/isakmpd-20041012/doi.c new file mode 100644 index 0000000..e9a5030 --- /dev/null +++ b/keyexchange/isakmpd-20041012/doi.c @@ -0,0 +1,61 @@ +/* $OpenBSD: doi.c,v 1.9 2004/07/09 16:06:48 deraadt Exp $ */ +/* $EOM: doi.c,v 1.4 1999/04/02 00:57:36 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999 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. + * + * 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 "sysdep.h" + +#include "doi.h" + +static +LIST_HEAD(doi_list, doi) doi_tab; + +void +doi_init(void) +{ + 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/keyexchange/isakmpd-20041012/doi.h b/keyexchange/isakmpd-20041012/doi.h new file mode 100644 index 0000000..f2bcc68 --- /dev/null +++ b/keyexchange/isakmpd-20041012/doi.h @@ -0,0 +1,101 @@ +/* $OpenBSD: doi.h,v 1.14 2004/05/14 08:42:56 hshoexer Exp $ */ +/* $EOM: doi.h,v 1.29 2000/07/02 18:47:15 provos Exp $ */ + +/* + * Copyright (c) 1998, 1999 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. + * + * 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 payload; +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; + +#ifdef USE_DEBUG + int (*debug_attribute)(u_int16_t, u_int8_t *, u_int16_t, + void *); +#endif + void (*delete_spi)(struct sa *, struct proto *, int); + 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 (*handle_leftover_payload)(struct message *, u_int8_t, + struct payload *); + int (*informational_post_hook)(struct message *); + int (*informational_pre_hook)(struct message *); + int (*is_attribute_incompatible)(u_int16_t, u_int8_t *, + u_int16_t, void *); + void (*proto_init)(struct proto *, char *); + 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 *, size_t); + int (*validate_transform_id)(u_int8_t, u_int8_t); + int (*initiator)(struct message * msg); + int (*responder)(struct message * msg); + char *(*decode_ids)(char *, u_int8_t *, size_t, u_int8_t *, + size_t, int); +}; + +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/keyexchange/isakmpd-20041012/dpd.c b/keyexchange/isakmpd-20041012/dpd.c new file mode 100644 index 0000000..4351637 --- /dev/null +++ b/keyexchange/isakmpd-20041012/dpd.c @@ -0,0 +1,374 @@ +/* $OpenBSD: dpd.c,v 1.4 2004/08/10 15:59:10 ho Exp $ */ + +/* + * Copyright (c) 2004 Håkan Olsson. 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. + * + * 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. + */ + +#include <sys/types.h> +#include <stdlib.h> +#include <memory.h> + +#include "sysdep.h" + +#include "conf.h" +#include "dpd.h" +#include "exchange.h" +#include "hash.h" +#include "ipsec.h" +#include "isakmp_fld.h" +#include "log.h" +#include "message.h" +#include "sa.h" +#include "timer.h" +#include "transport.h" +#include "util.h" + +/* From RFC 3706. */ +#define DPD_MAJOR 0x01 +#define DPD_MINOR 0x00 +#define DPD_SEQNO_SZ 4 + +static const char dpd_vendor_id[] = { + 0xAF, 0xCA, 0xD7, 0x13, 0x68, 0xA1, 0xF1, /* RFC 3706 */ + 0xC9, 0x6B, 0x86, 0x96, 0xFC, 0x77, 0x57, + DPD_MAJOR, + DPD_MINOR +}; + +#define DPD_RETRANS_MAX 5 /* max number of retries. */ +#define DPD_RETRANS_WAIT 5 /* seconds between retries. */ + +/* DPD Timer State */ +enum dpd_tstate { DPD_TIMER_NORMAL, DPD_TIMER_CHECK }; + +static void dpd_check_event(void *); +static void dpd_event(void *); +static u_int32_t dpd_timer_interval(u_int32_t); +static void dpd_timer_reset(struct sa *, u_int32_t, enum dpd_tstate); + +/* Add the DPD VENDOR ID payload. */ +int +dpd_add_vendor_payload(struct message *msg) +{ + u_int8_t *buf; + size_t buflen = sizeof dpd_vendor_id + ISAKMP_GEN_SZ; + + buf = malloc(buflen); + if (!buf) { + log_error("dpd_add_vendor_payload: malloc(%lu) failed", + (unsigned long)buflen); + return -1; + } + + SET_ISAKMP_GEN_LENGTH(buf, buflen); + memcpy(buf + ISAKMP_VENDOR_ID_OFF, dpd_vendor_id, + sizeof dpd_vendor_id); + if (message_add_payload(msg, ISAKMP_PAYLOAD_VENDOR, buf, buflen, 1)) { + free(buf); + return -1; + } + + return 0; +} + +/* + * Check an incoming message for DPD capability markers. + */ +void +dpd_check_vendor_payload(struct message *msg, struct payload *p) +{ + u_int8_t *pbuf = p->p; + size_t vlen; + + /* Already checked? */ + if (msg->exchange->flags & EXCHANGE_FLAG_DPD_CAP_PEER) { + /* Just mark it as handled and return. */ + p->flags |= PL_MARK; + return; + } + + vlen = GET_ISAKMP_GEN_LENGTH(pbuf) - ISAKMP_GEN_SZ; + if (vlen != sizeof dpd_vendor_id) { + LOG_DBG((LOG_EXCHANGE, 90, + "dpd_check_vendor_payload: bad size %d != %d", vlen, + sizeof dpd_vendor_id)); + return; + } + + if (memcmp(dpd_vendor_id, pbuf + ISAKMP_GEN_SZ, vlen) == 0) { + /* This peer is DPD capable. */ + if (msg->isakmp_sa) { + msg->exchange->flags |= EXCHANGE_FLAG_DPD_CAP_PEER; + LOG_DBG((LOG_EXCHANGE, 10, "dpd_check_vendor_payload: " + "DPD capable peer detected")); + if (dpd_timer_interval(0) != 0) { + LOG_DBG((LOG_EXCHANGE, 10, + "dpd_check_vendor_payload: enabling")); + msg->isakmp_sa->flags |= SA_FLAG_DPD; + dpd_timer_reset(msg->isakmp_sa, 0, + DPD_TIMER_NORMAL); + } + } + p->flags |= PL_MARK; + } + return; +} + +/* + * All incoming DPD Notify messages enter here. Message has been validated. + */ +void +dpd_handle_notify(struct message *msg, struct payload *p) +{ + struct sa *isakmp_sa = msg->isakmp_sa; + u_int16_t notify = GET_ISAKMP_NOTIFY_MSG_TYPE(p->p); + u_int32_t p_seq; + + /* Extract the sequence number. */ + memcpy(&p_seq, p->p + ISAKMP_NOTIFY_SPI_OFF + ISAKMP_HDR_COOKIES_LEN, + sizeof p_seq); + p_seq = ntohl(p_seq); + + LOG_DBG((LOG_MESSAGE, 40, "dpd_handle_notify: got %s seq %u", + constant_name(isakmp_notify_cst, notify), p_seq)); + + switch (notify) { + case ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE: + /* The other peer wants to know we're alive. */ + if (p_seq <= isakmp_sa->dpd_rseq) { + log_print("dpd_handle_notify: bad R_U_THERE seqno " + "%u <= %u", p_seq, isakmp_sa->dpd_rseq); + return; + } + isakmp_sa->dpd_rseq = p_seq; + message_send_dpd_notify(isakmp_sa, + ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE_ACK, p_seq); + break; + + case ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE_ACK: + /* This should be a response to a R_U_THERE we've sent. */ + if (isakmp_sa->dpd_seq != p_seq) { + log_print("dpd_handle_notify: got bad ACK seqno %u, " + "expected %u", p_seq, isakmp_sa->dpd_seq); + /* XXX Give up? Retry? */ + return; + } + break; + default: + ; + } + + /* Mark handled. */ + p->flags |= PL_MARK; + + /* The other peer is alive, so we can safely wait a while longer. */ + if (isakmp_sa->flags & SA_FLAG_DPD) + dpd_timer_reset(isakmp_sa, 0, DPD_TIMER_NORMAL); +} + +/* Calculate the time until next DPD exchange. */ +static u_int32_t +dpd_timer_interval(u_int32_t offset) +{ + int32_t v = 0; + +#ifdef notyet + v = ...; /* XXX Per-peer specified DPD intervals? */ +#endif + if (!v) + v = conf_get_num("General", "DPD-check-interval", 0); + if (v < 1) + return 0; /* DPD-Check-Interval < 1 means disable DPD */ + + v -= offset; + return v < 1 ? 1 : v; +} + +static void +dpd_timer_reset(struct sa *sa, u_int32_t time_passed, enum dpd_tstate mode) +{ + struct timeval tv; + + if (sa->dpd_event) + timer_remove_event(sa->dpd_event); + + gettimeofday(&tv, 0); + switch (mode) { + case DPD_TIMER_NORMAL: + tv.tv_sec += dpd_timer_interval(time_passed); + sa->dpd_event = timer_add_event("dpd_event", dpd_event, sa, + &tv); + break; + case DPD_TIMER_CHECK: + tv.tv_sec += DPD_RETRANS_WAIT; + sa->dpd_event = timer_add_event("dpd_check_event", + dpd_check_event, sa, &tv); + break; + default: + ; + } + if (!sa->dpd_event) + log_print("dpd_timer_reset: timer_add_event failed"); +} + +/* Helper function for dpd_exchange_finalization(). */ +static int +dpd_find_sa(struct sa *sa, void *v_sa) +{ + struct sa *isakmp_sa = v_sa; + + return (sa->phase == 2 && + memcmp(sa->id_i, isakmp_sa->id_i, sa->id_i_len) == 0 && + memcmp(sa->id_r, isakmp_sa->id_r, sa->id_r_len) == 0); +} + +struct dpd_args { + struct sa *isakmp_sa; + u_int32_t interval; +}; + +/* Helper function for dpd_event(). */ +static int +dpd_check_time(struct sa *sa, void *v_arg) +{ + struct dpd_args *args = v_arg; + struct sockaddr *dst; + struct proto *proto; + struct sa_kinfo *ksa; + struct timeval tv; + + if (sa->phase == 1 || (args->isakmp_sa->flags & SA_FLAG_DPD) == 0 || + dpd_find_sa(sa, args->isakmp_sa) == 0) + return 0; + + proto = TAILQ_FIRST(&sa->protos); + if (!proto || !proto->data) + return 0; + sa->transport->vtbl->get_src(sa->transport, &dst); + + gettimeofday(&tv, 0); + ksa = sysdep_ipsec_get_kernel_sa(proto->spi[1], proto->spi_sz[1], + proto->proto, dst); + + if (!ksa || !ksa->last_used) + return 0; + + LOG_DBG((LOG_MESSAGE, 80, "dpd_check_time: " + "SA %p last use %u second(s) ago", sa, + (u_int32_t)(tv.tv_sec - ksa->last_used))); + + if ((u_int32_t)(tv.tv_sec - ksa->last_used) < args->interval) { + args->interval = (u_int32_t)(tv.tv_sec - ksa->last_used); + return 1; + } + + return 0; +} + +/* Called by the timer. */ +static void +dpd_event(void *v_sa) +{ + struct sa *isakmp_sa = v_sa; + struct dpd_args args; +#if defined (USE_DEBUG) + struct sockaddr *dst; + char *addr; +#endif + + isakmp_sa->dpd_event = 0; + + /* Check if there's been any incoming SA activity since last time. */ + args.isakmp_sa = isakmp_sa; + args.interval = dpd_timer_interval(0); + if (sa_find(dpd_check_time, &args)) { + if (args.interval > dpd_timer_interval(0)) + args.interval = 0; + dpd_timer_reset(isakmp_sa, args.interval, DPD_TIMER_NORMAL); + return; + } + + /* No activity seen, do a DPD exchange. */ + if (isakmp_sa->dpd_seq == 0) { + /* + * RFC 3706: first seq# should be random, with MSB zero, + * otherwise we just increment it. + */ + getrandom((u_int8_t *)&isakmp_sa->dpd_seq, + sizeof isakmp_sa->dpd_seq); + isakmp_sa->dpd_seq &= 0x7FFF; + } else + isakmp_sa->dpd_seq++; + +#if defined (USE_DEBUG) + isakmp_sa->transport->vtbl->get_dst(isakmp_sa->transport, &dst); + if (sockaddr2text(dst, &addr, 0) == -1) + addr = 0; + LOG_DBG((LOG_MESSAGE, 30, "dpd_event: sending R_U_THERE to %s seq %u", + addr ? addr : "<unknown>", isakmp_sa->dpd_seq)); + if (addr) + free(addr); +#endif + message_send_dpd_notify(isakmp_sa, ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE, + isakmp_sa->dpd_seq); + + /* And set the short timer. */ + dpd_timer_reset(isakmp_sa, 0, DPD_TIMER_CHECK); +} + +/* + * Called by the timer. If this function is called, it means we did not + * recieve any R_U_THERE_ACK confirmation from the other peer. + */ +static void +dpd_check_event(void *v_sa) +{ + struct sa *isakmp_sa = v_sa; + struct sa *sa; + + isakmp_sa->dpd_event = 0; + + if (++isakmp_sa->dpd_failcount < DPD_RETRANS_MAX) { + LOG_DBG((LOG_MESSAGE, 10, "dpd_check_event: " + "peer not responding, retry %u of %u", + isakmp_sa->dpd_failcount, DPD_RETRANS_MAX)); + message_send_dpd_notify(isakmp_sa, + ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE, isakmp_sa->dpd_seq); + dpd_timer_reset(isakmp_sa, 0, DPD_TIMER_CHECK); + return; + } + + /* + * Peer is considered dead. Delete all SAs created under isakmp_sa. + */ + LOG_DBG((LOG_MESSAGE, 10, "dpd_check_event: peer is dead, " + "deleting all SAs connected to SA %p", isakmp_sa)); + while ((sa = sa_find(dpd_find_sa, isakmp_sa)) != 0) { + LOG_DBG((LOG_MESSAGE, 30, "dpd_check_event: deleting SA %p", + sa)); + sa_delete(sa, 0); + } + LOG_DBG((LOG_MESSAGE, 30, "dpd_check_event: deleting ISAKMP SA %p", + isakmp_sa)); + sa_delete(isakmp_sa, 0); +} diff --git a/keyexchange/isakmpd-20041012/dpd.h b/keyexchange/isakmpd-20041012/dpd.h new file mode 100644 index 0000000..fa62c5b --- /dev/null +++ b/keyexchange/isakmpd-20041012/dpd.h @@ -0,0 +1,38 @@ +/* $OpenBSD: dpd.h,v 1.2 2004/08/10 15:59:10 ho Exp $ */ + +/* + * Copyright (c) 2004 Håkan Olsson. 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. + * + * 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. + */ + +#ifndef _DPD_H_ +#define _DPD_H_ + +struct message; +struct payload; +struct sa; + +int dpd_add_vendor_payload(struct message *); +void dpd_check_vendor_payload(struct message *, struct payload *); +void dpd_handle_notify(struct message *, struct payload *); + +#endif /* _DPD_H_ */ diff --git a/keyexchange/isakmpd-20041012/exchange.c b/keyexchange/isakmpd-20041012/exchange.c new file mode 100644 index 0000000..1c4ef1f --- /dev/null +++ b/keyexchange/isakmpd-20041012/exchange.c @@ -0,0 +1,1799 @@ +/* $OpenBSD: exchange.c,v 1.104 2004/09/17 13:53:08 ho Exp $ */ +/* $EOM: exchange.c,v 1.143 2000/12/04 00:02:25 angelos Exp $ */ + +/* + * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 1999, 2001 Angelos D. Keromytis. All rights reserved. + * Copyright (c) 1999, 2000, 2002 Håkan Olsson. 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. + * + * 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 <stdlib.h> +#include <string.h> + +#include "sysdep.h" + +#include "cert.h" +#include "conf.h" +#include "connection.h" +#include "constants.h" +#include "cookie.h" +#include "crypto.h" +#include "doi.h" +#include "exchange.h" +#include "ipsec_num.h" +#include "isakmp.h" +#ifdef USE_ISAKMP_CFG +#include "isakmp_cfg.h" +#endif +#include "libcrypto.h" +#include "log.h" +#include "message.h" +#include "timer.h" +#include "transport.h" +#include "ipsec.h" +#include "sa.h" +#include "util.h" +#include "key.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 + +#ifdef USE_DEBUG +static void exchange_dump(char *, struct exchange *); +#endif +static void exchange_free_aux(void *); +#if 0 +static void exchange_resize(void); +#endif +static struct exchange *exchange_lookup_active(char *, int); + +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 +}; + +#ifdef USE_AGGRESSIVE +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 +}; +#endif /* USE_AGGRESSIVE */ + +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. + */ +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; +#ifdef USE_AGGRESSIVE + case ISAKMP_EXCH_AGGRESSIVE: + return script_aggressive; +#endif + case ISAKMP_EXCH_INFO: + return script_informational; +#ifdef USE_ISAKMP_CFG + case ISAKMP_EXCH_TRANSACTION: + return script_transaction; +#endif + 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_DBG((LOG_EXCHANGE, 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 && !payload_first(msg, *pc)) + || (*pc == EXCHANGE_SCRIPT_AUTH + && !payload_first(msg, ISAKMP_PAYLOAD_HASH) + && !payload_first(msg, ISAKMP_PAYLOAD_SIG)) + || (*pc == EXCHANGE_SCRIPT_INFO + && ((!payload_first(msg, ISAKMP_PAYLOAD_NOTIFY) + && !payload_first(msg, ISAKMP_PAYLOAD_DELETE)) + || (payload_first(msg, ISAKMP_PAYLOAD_DELETE) + && !payload_first(msg, ISAKMP_PAYLOAD_HASH))))) { + /* Missing payload. */ + LOG_DBG((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; +} + +/* Feed unhandled payloads to the DOI for handling. Help for exchange_run(). */ +static void +exchange_handle_leftover_payloads(struct message *msg) +{ + struct exchange *exchange = msg->exchange; + struct doi *doi = exchange->doi; + struct payload *p; + int i; + + for (i = ISAKMP_PAYLOAD_SA; i < payload_index_max; i++) { + if (i == ISAKMP_PAYLOAD_PROPOSAL || + i == ISAKMP_PAYLOAD_TRANSFORM) + continue; + for (p = payload_first(msg, i); p; + p = TAILQ_NEXT(p, link)) { + if (p->flags & PL_MARK) + continue; + if (!doi->handle_leftover_payload || + doi->handle_leftover_payload(msg, i, p)) + LOG_DBG((LOG_EXCHANGE, 10, + "exchange_run: unexpected payload %s", + constant_name(isakmp_payload_cst, i))); + } + } +} + +/* + * 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) +{ + struct exchange *exchange = msg->exchange; + struct doi *doi = exchange->doi; + int (*handler)(struct message *) = exchange->initiator ? + doi->initiator : doi->responder; + int done = 0; + + 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: doi->%s (%p) failed", + exchange->initiator ? "initiator" : + "responder", msg); + message_free(msg); + return; + } + switch (exchange_validate(msg)) { + case 1: + /* + * The last message of a multi-message + * exchange should not be retransmitted other + * than "on-demand", i.e. if we see + * retransmits of the last message of the peer + * later. + */ + msg->flags |= MSG_LAST; + if (exchange->step > 0) { + if (exchange->last_sent) + message_free(exchange->last_sent); + exchange->last_sent = 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. + */ + exchange_handle_leftover_payloads(msg); + + /* + * 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, 1, 1); + return; + } + } + + LOG_DBG((LOG_EXCHANGE, 40, + "exchange_run: exchange %p finished step %d, advancing...", + exchange, 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(void) +{ + 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]); +} + +#if 0 +/* XXX Currently unused. */ +static void +exchange_resize(void) +{ + struct exchange_list *new_tab; + int new_mask = (bucket_mask + 1) * 2 - 1; + int i; + + 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. */ +} +#endif + +/* Lookup a phase 1 exchange out of just the initiator cookie. */ +struct exchange * +exchange_lookup_from_icookie(u_int8_t * cookie) +{ + struct exchange *exchange; + int i; + + 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; +} + +/* Lookup an exchange out of the name and phase. */ +struct exchange * +exchange_lookup_by_name(char *name, int phase) +{ + struct exchange *exchange; + int i; + + /* If we search for nothing, we will find nothing. */ + if (!name) + return 0; + + for (i = 0; i <= bucket_mask; i++) + for (exchange = LIST_FIRST(&exchange_tab[i]); exchange; + exchange = LIST_NEXT(exchange, link)) { + LOG_DBG((LOG_EXCHANGE, 90, + "exchange_lookup_by_name: %s == %s && %d == %d?", + name, exchange->name ? exchange->name : + "<unnamed>", phase, exchange->phase)); + + /* + * Match by name, but don't select finished exchanges, + * i.e where MSG_LAST are set in last_sent msg. + */ + if (exchange->name && + strcasecmp(exchange->name, name) == 0 && + exchange->phase == phase && + (!exchange->last_sent || + (exchange->last_sent->flags & MSG_LAST) == 0)) + return exchange; + } + return 0; +} + +/* Lookup an exchange out of the name, phase and step > 1. */ +static struct exchange * +exchange_lookup_active(char *name, int phase) +{ + struct exchange *exchange; + int i; + + /* XXX Almost identical to exchange_lookup_by_name. */ + + if (!name) + return 0; + + for (i = 0; i <= bucket_mask; i++) + for (exchange = LIST_FIRST(&exchange_tab[i]); exchange; + exchange = LIST_NEXT(exchange, link)) { + LOG_DBG((LOG_EXCHANGE, 90, + "exchange_lookup_active: %s == %s && %d == %d?", + name, exchange->name ? exchange->name : + "<unnamed>", phase, exchange->phase)); + if (exchange->name && + strcasecmp(exchange->name, name) == 0 && + exchange->phase == phase) { + if (exchange->step > 1) + return exchange; + else + LOG_DBG((LOG_EXCHANGE, 80, + "exchange_lookup_active: avoided " + "early (pre-step 1) exchange %p", + exchange)); + } + } + return 0; +} + +static void +exchange_enter(struct exchange *exchange) +{ + u_int16_t bucket = 0; + u_int8_t *cp; + int i; + + /* 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); +} + +/* + * 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) +{ + struct exchange *exchange; + u_int16_t bucket = 0; + u_int8_t *cp; + int i; + + /* + * 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) || + (!phase2 && !zero_test(msg + ISAKMP_HDR_MESSAGE_ID_OFF, + ISAKMP_HDR_MESSAGE_ID_LEN))); + 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; + int delta; + + /* + * 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) { + log_error("exchange_create: calloc (1, %lu) failed", + (unsigned long)sizeof *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->policy_id = -1; + 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. */ + if (exchange->doi->exchange_size) { + exchange->data = calloc(1, exchange->doi->exchange_size); + if (!exchange->data) { + log_error("exchange_create: calloc (1, %lu) failed", + (unsigned long)exchange->doi->exchange_size); + exchange_free(exchange); + return 0; + } + } + gettimeofday(&expiration, 0); + delta = conf_get_num("General", "Exchange-max-time", + EXCHANGE_MAX_TIME); + expiration.tv_sec += delta; + exchange->death = timer_add_event("exchange_free_aux", + exchange_free_aux, exchange, &expiration); + if (!exchange->death) { + /* If we don't give up we might start leaking... */ + exchange_free_aux(exchange); + return 0; + } + return exchange; +} + +struct exchange_finalization_node { + void (*first)(struct exchange *, void *, int); + void *first_arg; + void (*second)(struct exchange *, void *, int); + void *second_arg; +}; + +/* Run the finalization functions of ARG. */ +static void +exchange_run_finalizations(struct exchange *exchange, void *arg, int fail) +{ + struct exchange_finalization_node *node = arg; + + node->first(exchange, node->first_arg, fail); + node->second(exchange, node->second_arg, fail); + free(node); +} + +/* + * Add a finalization function FINALIZE with argument ARG to the tail + * of the finalization function list of EXCHANGE. + */ +static void +exchange_add_finalization(struct exchange *exchange, + void (*finalize)(struct exchange *, void *, int), void *arg) +{ + struct exchange_finalization_node *node; + + if (!finalize) + return; + + if (!exchange->finalize) { + exchange->finalize = finalize; + exchange->finalize_arg = arg; + return; + } + node = malloc(sizeof *node); + if (!node) { + log_error("exchange_add_finalization: malloc (%lu) failed", + (unsigned long)sizeof *node); + free(arg); + return; + } + node->first = exchange->finalize; + node->first_arg = exchange->finalize_arg; + node->second = finalize; + node->second_arg = arg; + exchange->finalize = exchange_run_finalizations; + exchange->finalize_arg = node; +} + +#ifdef USE_ISAKMP_CFG +static void +exchange_establish_transaction(struct exchange *exchange, void *arg, int fail) +{ + /* Establish a TRANSACTION exchange. */ + struct exchange_finalization_node *node = + (struct exchange_finalization_node *)arg; + struct sa *isakmp_sa = sa_lookup_by_name((char *) node->second_arg, 1); + + if (isakmp_sa && !fail) + exchange_establish_p2(isakmp_sa, ISAKMP_EXCH_TRANSACTION, 0, 0, + node->first, node->first_arg); + + free(node); +} +#endif /* USE_ISAKMP_CFG */ + +/* Establish a phase 1 exchange. */ +void +exchange_establish_p1(struct transport *t, u_int8_t type, u_int32_t doi, + char *name, void *args, void (*finalize)(struct exchange *, void *, int), + void *arg) +{ + struct exchange *exchange; + struct message *msg; +#ifdef USE_ISAKMP_CFG + struct conf_list *flags; + struct conf_list_node *flag; +#endif + char *tag = 0; + char *str; + + if (name) { + /* If no exchange type given, fetch from the configuration. */ + if (type == 0) { + /* + * XXX Similar code can be found in + * exchange_setup_p1. Share? + */ + + /* Find out our phase 1 mode. */ + tag = conf_get_str(name, "Configuration"); + if (!tag) { + /* Use default setting. */ + tag = CONF_DFLT_TAG_PHASE1_CONFIG; + } + /* Figure out the DOI. XXX Factor out? */ + str = conf_get_str(tag, "DOI"); + if (!str || strcasecmp(str, "IPSEC") == 0) + doi = IPSEC_DOI_IPSEC; + else if (strcasecmp(str, "ISAKMP") == 0) + doi = ISAKMP_DOI_ISAKMP; + else { + log_print("exchange_establish_p1: " + "DOI \"%s\" unsupported", str); + return; + } + + /* What exchange type do we want? */ + str = conf_get_str(tag, "EXCHANGE_TYPE"); + if (!str) { + log_print("exchange_establish_p1: " + "no \"EXCHANGE_TYPE\" tag in [%s] section", + tag); + return; + } + type = constant_value(isakmp_exch_cst, str); + if (!type) { + log_print("exchange_setup_p1: " + "unknown exchange type %s", str); + return; + } + } + } + exchange = exchange_create(1, 1, doi, type); + if (!exchange) { + /* XXX Do something here? */ + return; + } + if (name) { + exchange->name = strdup(name); + if (!exchange->name) { + log_error("exchange_establish_p1: " + "strdup (\"%s\") failed", name); + exchange_free(exchange); + return; + } + } + exchange->policy = name ? conf_get_str(name, "Configuration") : 0; + if (!exchange->policy && name) + exchange->policy = CONF_DFLT_TAG_PHASE1_CONFIG; + +#ifdef USE_ISAKMP_CFG + if (name && (flags = conf_get_list(name, "Flags")) != NULL) { + for (flag = TAILQ_FIRST(&flags->fields); flag; + flag = TAILQ_NEXT(flag, link)) + if (strcasecmp(flag->field, "ikecfg") == 0) { + struct exchange_finalization_node *node; + + node = calloc(1, (unsigned long)sizeof *node); + if (!node) { + log_print("exchange_establish_p1: " + "calloc (1, %lu) failed", + (unsigned long)sizeof(*node)); + exchange_free(exchange); + return; + } + /* + * Insert this finalization inbetween + * the original. + */ + node->first = finalize; + node->first_arg = arg; + node->second_arg = name; + exchange_add_finalization(exchange, + exchange_establish_transaction, + node); + finalize = 0; + } + conf_free_list(flags); + } +#endif /* USE_ISAKMP_CFG */ + + exchange_add_finalization(exchange, finalize, arg); + cookie_gen(t, exchange, exchange->cookies, ISAKMP_HDR_ICOOKIE_LEN); + exchange_enter(exchange); +#ifdef USE_DEBUG + exchange_dump("exchange_establish_p1", exchange); +#endif + + msg = message_alloc(t, 0, ISAKMP_HDR_SZ); + if (!msg) { + log_print("exchange_establish_p1: message_alloc () failed"); + exchange_free(exchange); + return; + } + msg->exchange = exchange; + + /* Do not create SA for an information or transaction exchange. */ + if (exchange->type != ISAKMP_EXCH_INFO + && exchange->type != ISAKMP_EXCH_TRANSACTION) { + /* + * 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? */ + message_free(msg); + exchange_free(exchange); + return; + } + sa_reference(msg->isakmp_sa); + } + 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, char *name, + void *args, void (*finalize)(struct exchange *, void *, int), void *arg) +{ + struct exchange *exchange; + struct message *msg; + u_int32_t doi = ISAKMP_DOI_ISAKMP; + u_int32_t seq = 0; + int i; + char *tag, *str; + + if (isakmp_sa) + doi = isakmp_sa->doi->id; + + if (name) { + /* Find out our phase 2 modes. */ + tag = conf_get_str(name, "Configuration"); + if (!tag) { + log_print("exchange_establish_p2: " + "no configuration for peer \"%s\"", name); + return; + } + seq = (u_int32_t)conf_get_num(name, "Acquire-ID", 0); + + /* Figure out the DOI. */ + str = conf_get_str(tag, "DOI"); + if (!str || strcasecmp(str, "IPSEC") == 0) + doi = IPSEC_DOI_IPSEC; + else if (strcasecmp(str, "ISAKMP") == 0) + doi = ISAKMP_DOI_ISAKMP; + else { + log_print("exchange_establish_p2: " + "DOI \"%s\" unsupported", str); + return; + } + + /* What exchange type do we want? */ + if (!type) { + str = conf_get_str(tag, "EXCHANGE_TYPE"); + if (!str) { + log_print("exchange_establish_p2: " + "no \"EXCHANGE_TYPE\" tag in [%s] section", + tag); + return; + } + /* XXX IKE dependent. */ + type = constant_value(ike_exch_cst, str); + if (!type) { + log_print("exchange_establish_p2: unknown " + "exchange type %s", str); + return; + } + } + } + exchange = exchange_create(2, 1, doi, type); + if (!exchange) { + /* XXX Do something here? */ + return; + } + if (name) { + exchange->name = strdup(name); + if (!exchange->name) { + log_error("exchange_establish_p2: " + "strdup (\"%s\") failed", name); + exchange_free(exchange); + return; + } + } + exchange->policy = name ? conf_get_str(name, "Configuration") : 0; + exchange->finalize = finalize; + exchange->finalize_arg = arg; + exchange->seq = seq; + memcpy(exchange->cookies, isakmp_sa->cookies, ISAKMP_HDR_COOKIES_LEN); + getrandom(exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN); + exchange->flags |= EXCHANGE_FLAG_ENCRYPT; +#if defined (USE_NAT_TRAVERSAL) + if (isakmp_sa->flags & SA_FLAG_NAT_T_ENABLE) + exchange->flags |= EXCHANGE_FLAG_NAT_T_ENABLE; + if (isakmp_sa->flags & SA_FLAG_NAT_T_KEEPALIVE) + exchange->flags |= EXCHANGE_FLAG_NAT_T_KEEPALIVE; +#endif + exchange_enter(exchange); +#ifdef USE_DEBUG + exchange_dump("exchange_establish_p2", exchange); +#endif + + /* + * Do not create SA's for informational exchanges. + * XXX How to handle new group mode? + */ + if (exchange->type != ISAKMP_EXCH_INFO && + exchange->type != ISAKMP_EXCH_TRANSACTION) { + /* XXX Number of SAs should come from the args structure. */ + for (i = 0; i < 1; i++) + if (sa_create(exchange, isakmp_sa->transport)) { + exchange_free(exchange); + return; + } + } + msg = message_alloc(isakmp_sa->transport, 0, ISAKMP_HDR_SZ); + msg->isakmp_sa = isakmp_sa; + sa_reference(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 transport *t = msg->transport; + struct exchange *exchange; + struct sockaddr *dst; +#ifdef USE_ISAKMP_CFG + struct conf_list *flags; + struct conf_list_node *flag; +#endif + char *name = 0, *policy = 0, *str; + u_int32_t want_doi; + u_int8_t type; + + /* XXX Similar code can be found in exchange_establish_p1. Share? */ + + /* + * Unless this is an informational exchange, look up our policy for + * this peer. + */ + type = GET_ISAKMP_HDR_EXCH_TYPE(msg->iov[0].iov_base); + if (type != ISAKMP_EXCH_INFO) { + /* + * Find out our inbound phase 1 mode. + */ + t->vtbl->get_dst(t, &dst); + if (sockaddr2text(dst, &str, 0) == -1) + return 0; + name = conf_get_str("Phase 1", str); + free(str); + if (name) { + /* + * If another phase 1 exchange is ongoing don't bother + * returning the call. However, we will need to + * continue responding if our phase 1 exchange is + * still waiting for step 1 (i.e still half-open). + */ + if (exchange_lookup_active(name, 1)) + return 0; + } else { + name = conf_get_str("Phase 1", "Default"); + if (!name) { + log_print("exchange_setup_p1: no \"Default\" " + "tag in [Phase 1] section"); + return 0; + } + } + + policy = conf_get_str(name, "Configuration"); + if (!policy) + policy = CONF_DFLT_TAG_PHASE1_CONFIG; + + /* Figure out the DOI. */ + str = conf_get_str(policy, "DOI"); + if (!str || strcasecmp(str, "IPSEC") == 0) + want_doi = IPSEC_DOI_IPSEC; + else if (strcasecmp(str, "ISAKMP") == 0) + want_doi = ISAKMP_DOI_ISAKMP; + else { + log_print("exchange_setup_p1: " + "DOI \"%s\" unsupported", str); + return 0; + } + if (want_doi != doi) { + /* XXX Should I tell what DOI I got? */ + log_print("exchange_setup_p1: expected %s DOI", str); + return 0; + } + /* What exchange type do we want? */ + str = conf_get_str(policy, "EXCHANGE_TYPE"); + if (!str) { + log_print("exchange_setup_p1: no \"EXCHANGE_TYPE\" " + "tag in [%s] section", policy); + return 0; + } + type = constant_value(isakmp_exch_cst, str); + if (!type) { + log_print("exchange_setup_p1: " + "unknown exchange type %s", str); + return 0; + } + if (type != GET_ISAKMP_HDR_EXCH_TYPE(msg->iov[0].iov_base)) { + log_print("exchange_setup_p1: " + "expected exchange type %s got %s", str, + constant_name(isakmp_exch_cst, + GET_ISAKMP_HDR_EXCH_TYPE(msg->iov[0].iov_base))); + return 0; + } + } + exchange = exchange_create(1, 0, doi, type); + if (!exchange) + return 0; + + exchange->name = name ? strdup(name) : 0; + if (name && !exchange->name) { + log_error("exchange_setup_p1: strdup (\"%s\") failed", name); + exchange_free(exchange); + return 0; + } + exchange->policy = policy; + +#ifdef USE_ISAKMP_CFG + if (name && (flags = conf_get_list(name, "Flags")) != NULL) { + for (flag = TAILQ_FIRST(&flags->fields); flag; + flag = TAILQ_NEXT(flag, link)) + if (strcasecmp(flag->field, "ikecfg") == 0) { + struct exchange_finalization_node *node; + + node = calloc(1, (unsigned long)sizeof *node); + if (!node) { + log_print("exchange_establish_p1: " + "calloc (1, %lu) failed", + (unsigned long)sizeof(*node)); + exchange_free(exchange); + return 0; + } + /* + * Insert this finalization inbetween + * the original. + */ + node->first = 0; + node->first_arg = 0; + node->second_arg = name; + exchange_add_finalization(exchange, + exchange_establish_transaction, + node); + } + conf_free_list(flags); + } +#endif + + 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); +#ifdef USE_DEBUG + exchange_dump("exchange_setup_p1", exchange); +#endif + 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); +#if defined (USE_NAT_TRAVERSAL) + if (msg->isakmp_sa->flags & SA_FLAG_NAT_T_ENABLE) + exchange->flags |= EXCHANGE_FLAG_NAT_T_ENABLE; + if (msg->isakmp_sa->flags & SA_FLAG_NAT_T_KEEPALIVE) + exchange->flags |= EXCHANGE_FLAG_NAT_T_KEEPALIVE; +#endif + exchange_enter(exchange); +#ifdef USE_DEBUG + exchange_dump("exchange_setup_p2", exchange); +#endif + return exchange; +} + +/* Dump interesting data about an exchange. */ +static void +exchange_dump_real(char *header, struct exchange *exchange, int class, + int level) +{ + struct sa *sa; + char buf[LOG_SIZE]; + /* Don't risk overflowing the final log buffer. */ + size_t bufsize_max = LOG_SIZE - strlen(header) - 32; + + LOG_DBG((class, level, + "%s: %p %s %s policy %s phase %d doi %d exchange %d step %d", + header, exchange, exchange->name ? exchange->name : "<unnamed>", + exchange->policy ? exchange->policy : "<no policy>", + exchange->initiator ? "initiator" : "responder", exchange->phase, + exchange->doi->id, exchange->type, exchange->step)); + LOG_DBG((class, level, "%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))); + + /* Include phase 2 SA list for this exchange */ + if (exchange->phase == 2) { + snprintf(buf, bufsize_max, "sa_list "); + for (sa = TAILQ_FIRST(&exchange->sa_list); + sa && strlen(buf) < bufsize_max; sa = TAILQ_NEXT(sa, next)) + snprintf(buf + strlen(buf), bufsize_max - strlen(buf), + "%p ", sa); + if (sa) + strlcat(buf, "...", bufsize_max); + } else + buf[0] = '\0'; + + LOG_DBG((class, level, "%s: msgid %08x %s", header, + decode_32(exchange->message_id), buf)); +} + +#ifdef USE_DEBUG +static void +exchange_dump(char *header, struct exchange *exchange) +{ + exchange_dump_real(header, exchange, LOG_EXCHANGE, 10); +} +#endif + +void +exchange_report(void) +{ + struct exchange *exchange; + int i; + + for (i = 0; i <= bucket_mask; i++) + for (exchange = LIST_FIRST(&exchange_tab[i]); exchange; + exchange = LIST_NEXT(exchange, link)) + exchange_dump_real("exchange_report", exchange, + LOG_REPORT, 0); +} + +/* + * 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(void *v_exch) +{ + struct exchange *exchange = v_exch; + struct sa *sa, *next_sa; + struct cert_handler *handler; + + LOG_DBG((LOG_EXCHANGE, 80, "exchange_free_aux: freeing exchange %p", + exchange)); + + if (exchange->last_received) + message_free(exchange->last_received); + if (exchange->last_sent) + message_free(exchange->last_sent); + if (exchange->in_transit && + exchange->in_transit != exchange->last_sent) + message_free(exchange->in_transit); + 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); + if (exchange->name) + free(exchange->name); + if (exchange->recv_cert) { + handler = cert_get(exchange->recv_certtype); + if (handler) + handler->cert_free(exchange->recv_cert); + } + if (exchange->sent_cert) { + handler = cert_get(exchange->sent_certtype); + if (handler) + handler->cert_free(exchange->sent_cert); + } + if (exchange->recv_key) + key_free(exchange->recv_keytype, ISAKMP_KEYTYPE_PUBLIC, + exchange->recv_key); + if (exchange->keynote_key) + free(exchange->keynote_key); /* This is just a string */ + +#if defined (POLICY) || defined (KEYNOTE) + if (exchange->policy_id != -1) + kn_close(exchange->policy_id); +#endif + + exchange_free_aca_list(exchange); + LIST_REMOVE(exchange, link); + + /* Tell potential finalize routine we never got there. */ + if (exchange->finalize) + exchange->finalize(exchange, exchange->finalize_arg, 1); + + /* Remove any SAs that have not been disassociated from us. */ + for (sa = TAILQ_FIRST(&exchange->sa_list); sa; sa = next_sa) { + next_sa = TAILQ_NEXT(sa, next); + /* One for the reference in exchange->sa_list. */ + sa_release(sa); + /* And two more for the expiration and SA linked list. */ + sa_free(sa); + } + + 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); +} + +static int +exchange_check_old_sa(struct sa *sa, void *v_arg) +{ + struct sa *new_sa = v_arg; + char res1[1024]; + + if (sa == new_sa || !sa->name || !(sa->flags & SA_FLAG_READY) || + (sa->flags & SA_FLAG_REPLACED)) + return 0; + + if (sa->phase != new_sa->phase || new_sa->name == 0 || + strcasecmp(sa->name, new_sa->name)) + return 0; + + if (sa->initiator) + strlcpy(res1, ipsec_decode_ids("%s %s", sa->id_i, sa->id_i_len, + sa->id_r, sa->id_r_len, 0), sizeof res1); + else + strlcpy(res1, ipsec_decode_ids("%s %s", sa->id_r, sa->id_r_len, + sa->id_i, sa->id_i_len, 0), sizeof res1); + + LOG_DBG((LOG_EXCHANGE, 30, + "checking whether new SA replaces existing SA with IDs %s", res1)); + + if (new_sa->initiator) + return strcasecmp(res1, ipsec_decode_ids("%s %s", new_sa->id_i, + new_sa->id_i_len, new_sa->id_r, new_sa->id_r_len, 0)) == 0; + else + return strcasecmp(res1, ipsec_decode_ids("%s %s", new_sa->id_r, + new_sa->id_r_len, new_sa->id_i, new_sa->id_i_len, 0)) == 0; +} + +void +exchange_finalize(struct message *msg) +{ + struct exchange *exchange = msg->exchange; + struct sa *sa, *old_sa; + struct proto *proto; + struct conf_list *attrs; + struct conf_list_node *attr; + struct cert_handler *handler; + int i; + char *id_doi, *id_trp; + +#ifdef USE_DEBUG + exchange_dump("exchange_finalize", exchange); +#endif + + /* Copy the ID from phase 1 to exchange or phase 2 SA. */ + if (msg->isakmp_sa) { + if (exchange->id_i && exchange->id_r) { + ipsec_clone_id(&msg->isakmp_sa->id_i, + &msg->isakmp_sa->id_i_len, exchange->id_i, + exchange->id_i_len); + ipsec_clone_id(&msg->isakmp_sa->id_r, + &msg->isakmp_sa->id_r_len, exchange->id_r, + exchange->id_r_len); + } else if (msg->isakmp_sa->id_i && msg->isakmp_sa->id_r) { + ipsec_clone_id(&exchange->id_i, &exchange->id_i_len, + msg->isakmp_sa->id_i, msg->isakmp_sa->id_i_len); + ipsec_clone_id(&exchange->id_r, &exchange->id_r_len, + msg->isakmp_sa->id_r, msg->isakmp_sa->id_r_len); + } + } + /* + * 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)) { + /* Move over the name to the SA. */ + sa->name = exchange->name ? strdup(exchange->name) : 0; + + 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); + } + /* + * Locate any old SAs and mark them replaced + * (SA_FLAG_REPLACED). + */ + sa->initiator = exchange->initiator; + while ((old_sa = sa_find(exchange_check_old_sa, sa)) != 0) + sa_mark_replaced(old_sa); + + /* Setup the SA flags. */ + sa->flags |= SA_FLAG_READY; + if (exchange->name) { + attrs = conf_get_list(exchange->name, "Flags"); + if (attrs) { + for (attr = TAILQ_FIRST(&attrs->fields); attr; + attr = TAILQ_NEXT(attr, link)) + sa->flags |= sa_flag(attr->field); + conf_free_list(attrs); + } + /* 'Connections' should stay alive. */ + if (connection_exist(exchange->name)) { + sa->flags |= SA_FLAG_STAYALIVE; + + /* + * ISAKMP SA of this connection should also + * stay alive. + */ + if (exchange->phase == 2 && msg->isakmp_sa) + msg->isakmp_sa->flags |= + SA_FLAG_STAYALIVE; + } + } + sa->seq = exchange->seq; + 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. Also save the Phase 1 ID and authentication + * information. + */ + if (exchange->phase == 1 && msg->isakmp_sa) { + msg->isakmp_sa->keystate = exchange->keystate; + exchange->keystate = 0; + + msg->isakmp_sa->recv_certtype = exchange->recv_certtype; + msg->isakmp_sa->sent_certtype = exchange->sent_certtype; + msg->isakmp_sa->recv_keytype = exchange->recv_keytype; + msg->isakmp_sa->recv_key = exchange->recv_key; + msg->isakmp_sa->keynote_key = exchange->keynote_key; + /* Reset. */ + exchange->recv_key = 0; + exchange->keynote_key = 0; + msg->isakmp_sa->policy_id = exchange->policy_id; + exchange->policy_id = -1; + msg->isakmp_sa->initiator = exchange->initiator; + + if (exchange->recv_certtype && exchange->recv_cert) { + handler = cert_get(exchange->recv_certtype); + if (handler) + msg->isakmp_sa->recv_cert = + handler->cert_dup(exchange->recv_cert); + } + if (exchange->sent_certtype) { + handler = cert_get(exchange->sent_certtype); + if (handler) + msg->isakmp_sa->sent_cert = + handler->cert_dup(exchange->sent_cert); + } + if (exchange->doi) + id_doi = exchange->doi->decode_ids( + "initiator id %s, responder id %s", + exchange->id_i, exchange->id_i_len, + exchange->id_r, exchange->id_r_len, 0); + else + id_doi = "<no doi>"; + + if (msg->isakmp_sa->transport) + id_trp = + msg->isakmp_sa->transport->vtbl->decode_ids(msg->isakmp_sa->transport); + else + id_trp = "<no transport>"; + +#if defined (USE_NAT_TRAVERSAL) + if (exchange->flags & EXCHANGE_FLAG_NAT_T_ENABLE) + msg->isakmp_sa->flags |= SA_FLAG_NAT_T_ENABLE; + if (exchange->flags & EXCHANGE_FLAG_NAT_T_KEEPALIVE) + msg->isakmp_sa->flags |= SA_FLAG_NAT_T_KEEPALIVE; +#endif + + LOG_DBG((LOG_EXCHANGE, 10, + "exchange_finalize: phase 1 done: %s, %s", id_doi, + id_trp)); + + log_verbose("isakmpd: phase 1 done: %s, %s", id_doi, id_trp); + } + exchange->doi->finalize_exchange(msg); + if (exchange->finalize) + exchange->finalize(exchange, exchange->finalize_arg, 0); + exchange->finalize = 0; + + /* + * There is no reason to keep the SAs connected to us anymore, in fact + * it can hurt us if we have short lifetimes on the SAs and we try + * to call exchange_report, where the SA list will be walked and + * references to freed SAs can occur. + */ + while (TAILQ_FIRST(&exchange->sa_list)) { + sa = TAILQ_FIRST(&exchange->sa_list); + + if (exchange->id_i && exchange->id_r) { + ipsec_clone_id(&sa->id_i, &sa->id_i_len, + exchange->id_i, exchange->id_i_len); + ipsec_clone_id(&sa->id_r, &sa->id_r_len, + exchange->id_r, exchange->id_r_len); + } + TAILQ_REMOVE(&exchange->sa_list, sa, next); + sa_release(sa); + } + + /* If we have nothing to retransmit we can safely remove ourselves. */ + if (!exchange->last_sent) + 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) +{ + u_int8_t **nonce; + size_t *nonce_len; + int initiator = exchange->initiator ^ peer; + 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) { + log_error("exchange_nonce: malloc (%lu) failed", + (unsigned long)nonce_sz); + return -1; + } + memcpy(*nonce, buf, nonce_sz); + snprintf(header, sizeof header, "exchange_nonce: NONCE_%c", + initiator ? 'i' : 'r'); + LOG_DBG_BUF((LOG_EXCHANGE, 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) { + log_error("exchange_gen_nonce: malloc (%lu) failed", + ISAKMP_NONCE_SZ + (unsigned long)nonce_sz); + 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 = payload_first(msg, 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 = payload_first(msg, ISAKMP_PAYLOAD_CERT_REQ); + struct exchange *exchange = msg->exchange; + struct certreq_aca *aca; + + for (; cp; cp = TAILQ_NEXT(cp, link)) { + cp->flags |= PL_MARK; + aca = 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 (aca) + TAILQ_INSERT_TAIL(&exchange->aca_list, aca, link); + } + + return 0; +} + +/* Free the list of pending CERTREQs. */ +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) { + if (aca->handler) + 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 = 0, *new_cert = 0; + u_int32_t certlen; + u_int8_t *id; + size_t id_len; + + id = exchange->initiator ? exchange->id_r : exchange->id_i; + id_len = exchange->initiator ? exchange->id_r_len : exchange->id_i_len; + + /* + * Without IDs we cannot handle this yet. Keep the aca_list around for + * a later step/retry to see if we got the ID by then. + * Note: A 'return -1' breaks X509-auth interop in the responder case + * with some IPsec clients that send CERTREQs early (such as + * the SSH Sentinel). + */ + if (!id) + return 0; + + 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(id, id_len, aca->data, &cert, + &certlen)) { + log_print("exchange_add_certs: could not obtain cert " + "for a type %d cert request", aca->id); + if (cert) + free(cert); + return -1; + } + new_cert = realloc(cert, ISAKMP_CERT_SZ + certlen); + if (!new_cert) { + log_error("exchange_add_certs: realloc (%p, %d) " + "failed", cert, ISAKMP_CERT_SZ + certlen); + if (cert) + free(cert); + return -1; + } + cert = new_cert; + 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 answered. */ + exchange_free_aca_list(exchange); + + return 0; +} + +static void +exchange_establish_finalize(struct exchange *exchange, void *arg, int fail) +{ + char *name = arg; + + LOG_DBG((LOG_EXCHANGE, 20, "exchange_establish_finalize: " + "finalizing exchange %p with arg %p (%s) & fail = %d", + exchange, arg, name ? name : "<unnamed>", fail)); + + if (!fail) + exchange_establish(name, 0, 0); + free(name); +} + +/* + * Establish an exchange named NAME, and record the FINALIZE function + * taking ARG as an argument to be run after the exchange is ready. + */ +void +exchange_establish(char *name, void (*finalize)(struct exchange *, void *, + int), void *arg) +{ + struct transport *transport; + struct sa *isakmp_sa; + struct exchange *exchange; + int phase; + char *trpt, *peer; + + phase = conf_get_num(name, "Phase", 0); + + /* + * First of all, never try to establish anything if another exchange + * of the same kind is running. + */ + exchange = exchange_lookup_by_name(name, phase); + if (exchange) { + LOG_DBG((LOG_EXCHANGE, 40, + "exchange_establish: %s exchange already exists as %p", + name, exchange)); + exchange_add_finalization(exchange, finalize, arg); + return; + } + switch (phase) { + case 1: + trpt = conf_get_str(name, "Transport"); + if (!trpt) { + /* Phase 1 transport defaults to "udp". */ + trpt = ISAKMP_DEFAULT_TRANSPORT; + } + transport = transport_create(trpt, name); + if (!transport) { + log_print("exchange_establish: transport \"%s\" for " + "peer \"%s\" could not be created", trpt, name); + return; + } + exchange_establish_p1(transport, 0, 0, name, 0, finalize, arg); + break; + + case 2: + peer = conf_get_str(name, "ISAKMP-peer"); + if (!peer) { + log_print("exchange_establish: No ISAKMP-peer given " + "for \"%s\"", name); + return; + } + isakmp_sa = sa_lookup_by_name(peer, 1); + if (!isakmp_sa) { + name = strdup(name); + if (!name) { + log_error("exchange_establish: " + "strdup (\"%s\") failed", name); + return; + } + if (conf_get_num(peer, "Phase", 0) != 1) { + log_print("exchange_establish: " + "[%s]:ISAKMP-peer's (%s) phase is not 1", + name, peer); + return; + } + /* + * XXX We're losing information here (what the + * original finalize routine was. As a result, if an + * exchange does not manage to get through, there may + * be application-specific information that won't get + * cleaned up, since no error signalling will be done. + * This is the case with dynamic SAs and PFKEY. + */ + exchange_establish(peer, exchange_establish_finalize, + name); + exchange = exchange_lookup_by_name(peer, 1); + /* + * If the exchange was correctly initialized, add the + * original finalization routine; otherwise, call it + * directly. + */ + if (exchange) + exchange_add_finalization(exchange, finalize, + arg); + else + finalize(0, arg, 1); /* Indicate failure */ + return; + } else + exchange_establish_p2(isakmp_sa, 0, name, 0, finalize, + arg); + break; + + default: + log_print("exchange_establish: " + "peer \"%s\" does not have a correct phase (%d)", + name, phase); + break; + } +} diff --git a/keyexchange/isakmpd-20041012/exchange.h b/keyexchange/isakmpd-20041012/exchange.h new file mode 100644 index 0000000..67061c0 --- /dev/null +++ b/keyexchange/isakmpd-20041012/exchange.h @@ -0,0 +1,252 @@ +/* $OpenBSD: exchange.h,v 1.28 2004/08/23 11:13:14 ho Exp $ */ +/* $EOM: exchange.h,v 1.28 2000/09/28 12:54:28 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999, 2001 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. + * + * 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; + + /* A name of the SAs this exchange will result in. XXX non unique? */ + char *name; + + /* + * A name of the major policy deciding offers and acceptable + * proposals. + */ + char *policy; + + /* + * A function with a polymorphic argument called after the exchange + * has been run to its end, successfully. The 2nd argument is true + * if the finalization hook is called due to the exchange not running + * to its end normally. + */ + void (*finalize)(struct exchange *, void *, int); + void *finalize_arg; + + /* 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; + + /* + * If some message is queued up for sending, we want to be able to + * remove it from the queue, when the exchange is deleted. + */ + struct message *in_transit; + + /* + * 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; + + /* + * The ID payload contents for the initiator & responder, + * respectively. + */ + u_int8_t *id_i; + size_t id_i_len; + u_int8_t *id_r; + size_t id_r_len; + + /* Policy session identifier, where applicable. */ + int policy_id; + + /* Crypto info needed to encrypt/decrypt packets in this exchange. */ + struct crypto_xf *crypto; + size_t key_length; + struct keystate *keystate; + + /* + * Used only by KeyNote, to cache the key used to authenticate Phase + * 1 + */ + char *keynote_key; /* printable format */ + + /* + * Received certificate - used to verify signatures on packet, + * stored here for later policy processing. + * + * The rules for the recv_* and sent_* fields are: + * - recv_cert stores the credential (if any) received from the peer; + * the kernel may pass us one, but we ignore it. We pass it to the + * kernel so processes can peek at it. When doing passphrase + * authentication in Phase 1, this is empty. + * - recv_key stores the key (public or private) used by the peer + * to authenticate. Otherwise, same properties as recv_cert except + * that we don't tell the kernel about passphrases (so we don't + * reveal system-wide passphrases). Processes that used passphrase + * authentication already know the passphrase! We ignore it if/when + * received from the kernel (meaningless). + * - sent_cert stores the credential, if any, we used to authenticate + * with the peer. It may be passed to us by the kernel, or we may + * have found it in our certificate storage. In either case, there's + * no point passing it to the kernel, so we don't. + * - sent key stores the private key we used for authentication with + * the peer (private key or passphrase). This may have been received + * from the kernel, or may be a system-wide setting. In either case, + * we don't pass it to the kernel, to avoid revealing such information + * to processes (processes either already know it, or have no business + * knowing it). + */ + int recv_certtype, recv_keytype; + void *recv_cert; /* Certificate received from peer, + * native format */ + void *recv_key; /* Key peer used to authenticate, + * native format */ + + /* Likewise, for certificates/keys we use. */ + int sent_certtype, sent_keytype; + void *sent_cert; /* Certificate (to be) sent to peer, + * native format */ + void *sent_key; /* Key we'll use to authenticate to + * peer, native format */ + + /* ACQUIRE sequence number. */ + u_int32_t seq; + + /* XXX This is no longer necessary, it is covered by policy. */ + + /* 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 0x01 +#define EXCHANGE_FLAG_HE_COMMITTED 0x02 +#define EXCHANGE_FLAG_COMMITTED (EXCHANGE_FLAG_I_COMMITTED \ + | EXCHANGE_FLAG_HE_COMMITTED) +#define EXCHANGE_FLAG_ENCRYPT 0x04 +#define EXCHANGE_FLAG_NAT_T_CAP_PEER 0x08 /* Peer is NAT capable. */ +#define EXCHANGE_FLAG_NAT_T_ENABLE 0x10 /* We are doing NAT-T. */ +#define EXCHANGE_FLAG_NAT_T_KEEPALIVE 0x20 /* We are the NAT:ed peer. */ +#define EXCHANGE_FLAG_DPD_CAP_PEER 0x40 /* Peer is DPD capable. */ +#define EXCHANGE_FLAG_NAT_T_RFC 0x0080 /* Peer does RFC NAT-T. */ +#define EXCHANGE_FLAG_NAT_T_DRAFT 0x0100 /* Peer does draft NAT-T.*/ + +extern int exchange_add_certs(struct message *); +extern void exchange_finalize(struct message *); +extern void exchange_free(struct exchange *); +extern void exchange_free_aca_list(struct exchange *); +extern void exchange_establish(char *name, void (*)(struct exchange *, + void *, int), void *); +extern void exchange_establish_p1(struct transport *, u_int8_t, u_int32_t, + char *, void *, void (*)(struct exchange *, void *, int), + void *); +extern void exchange_establish_p2(struct sa *, u_int8_t, char *, void *, + void (*)(struct exchange *, void *, int), 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_by_name(char *, 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 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/keyexchange/isakmpd-20041012/exchange_num.cst b/keyexchange/isakmpd-20041012/exchange_num.cst new file mode 100644 index 0000000..7f61568 --- /dev/null +++ b/keyexchange/isakmpd-20041012/exchange_num.cst @@ -0,0 +1,42 @@ +# $OpenBSD: exchange_num.cst,v 1.4 2003/06/03 14:28:16 ho Exp $ +# $EOM: exchange_num.cst,v 1.1 1998/08/05 09:23:32 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. +# +# 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/keyexchange/isakmpd-20041012/features/aggressive b/keyexchange/isakmpd-20041012/features/aggressive new file mode 100644 index 0000000..945678c --- /dev/null +++ b/keyexchange/isakmpd-20041012/features/aggressive @@ -0,0 +1,32 @@ +# $OpenBSD: aggressive,v 1.4 2003/06/03 14:29:41 ho Exp $ +# $EOM: aggressive,v 1.3 2000/02/20 16:38:15 niklas Exp $ + +# +# Copyright (c) 2000 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. +# +# 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 Wireless Networks Inc. +# + +AGGRESSIVE= ike_aggressive.c diff --git a/keyexchange/isakmpd-20041012/features/dnssec b/keyexchange/isakmpd-20041012/features/dnssec new file mode 100644 index 0000000..aab768d --- /dev/null +++ b/keyexchange/isakmpd-20041012/features/dnssec @@ -0,0 +1,30 @@ +# $OpenBSD: dnssec,v 1.3 2003/06/03 14:29:41 ho Exp $ + +# +# Copyright (c) 2001 Håkan Olsson. 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. +# +# 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. +# + +DNSSEC= dnssec.c + +#LWRESLIB= /usr/local/lib/liblwres.a +#DNSSEC_CFLAGS= -I/usr/local/include -DLWRES diff --git a/keyexchange/isakmpd-20041012/features/dpd b/keyexchange/isakmpd-20041012/features/dpd new file mode 100644 index 0000000..155ce68 --- /dev/null +++ b/keyexchange/isakmpd-20041012/features/dpd @@ -0,0 +1,27 @@ +# $OpenBSD: dpd,v 1.1 2004/06/20 15:20:07 ho Exp $ + +# +# Copyright (c) 2004 Håkan Olsson. 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. +# +# 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. +# + +DPD= dpd.c diff --git a/keyexchange/isakmpd-20041012/features/ec b/keyexchange/isakmpd-20041012/features/ec new file mode 100644 index 0000000..6452a8e --- /dev/null +++ b/keyexchange/isakmpd-20041012/features/ec @@ -0,0 +1,32 @@ +# $OpenBSD: ec,v 1.4 2003/06/03 14:29:41 ho Exp $ +# $EOM: ec,v 1.3 2000/02/20 16:38:15 niklas Exp $ + +# +# Copyright (c) 2000 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. +# +# 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 Wireless Networks Inc. +# + +EC= math_ec2n.c diff --git a/keyexchange/isakmpd-20041012/features/isakmp_cfg b/keyexchange/isakmpd-20041012/features/isakmp_cfg new file mode 100644 index 0000000..55710fc --- /dev/null +++ b/keyexchange/isakmpd-20041012/features/isakmp_cfg @@ -0,0 +1,31 @@ +# $OpenBSD: isakmp_cfg,v 1.2 2003/06/03 14:29:41 ho Exp $ + +# +# Copyright (c) 2001 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. +# +# 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 Gatespace (http://www.gatespace.com/). +# + +ISAKMP_CFG= isakmp_cfg.c diff --git a/keyexchange/isakmpd-20041012/features/nat_traversal b/keyexchange/isakmpd-20041012/features/nat_traversal new file mode 100644 index 0000000..590b4bf --- /dev/null +++ b/keyexchange/isakmpd-20041012/features/nat_traversal @@ -0,0 +1,27 @@ +# $OpenBSD: nat_traversal,v 1.2 2004/06/21 17:02:53 markus Exp $ + +# +# Copyright (c) 2004 Håkan Olsson. 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. +# +# 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. +# + +NAT_TRAVERSAL= nat_traversal.c udp_encap.c diff --git a/keyexchange/isakmpd-20041012/features/policy b/keyexchange/isakmpd-20041012/features/policy new file mode 100644 index 0000000..680cc37 --- /dev/null +++ b/keyexchange/isakmpd-20041012/features/policy @@ -0,0 +1,33 @@ +# $OpenBSD: policy,v 1.6 2003/06/03 14:29:41 ho Exp $ +# $EOM: policy,v 1.4 2000/02/20 16:38:15 niklas Exp $ + +# +# Copyright (c) 2000 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. +# +# 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 Wireless Networks Inc. +# + +# NOTE: KeyNote policy support requires the keynote library +POLICY= policy.c diff --git a/keyexchange/isakmpd-20041012/features/privsep b/keyexchange/isakmpd-20041012/features/privsep new file mode 100644 index 0000000..20690a0 --- /dev/null +++ b/keyexchange/isakmpd-20041012/features/privsep @@ -0,0 +1,27 @@ +# $OpenBSD: privsep,v 1.2 2003/06/03 14:29:41 ho Exp $ + +# +# Copyright (c) 2003 Håkan Olsson. 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. +# +# 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. +# + +PRIVSEP= monitor.c monitor_fdpass.c diff --git a/keyexchange/isakmpd-20041012/features/x509 b/keyexchange/isakmpd-20041012/features/x509 new file mode 100644 index 0000000..be1b2aa --- /dev/null +++ b/keyexchange/isakmpd-20041012/features/x509 @@ -0,0 +1,32 @@ +# $OpenBSD: x509,v 1.5 2003/06/03 14:29:41 ho Exp $ +# $EOM: x509,v 1.4 2000/02/20 16:38:15 niklas Exp $ + +# +# Copyright (c) 2000 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. +# +# 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 Wireless Networks Inc. +# + +X509= x509.c diff --git a/keyexchange/isakmpd-20041012/field.c b/keyexchange/isakmpd-20041012/field.c new file mode 100644 index 0000000..0cc96d2 --- /dev/null +++ b/keyexchange/isakmpd-20041012/field.c @@ -0,0 +1,252 @@ +/* $OpenBSD: field.c,v 1.16 2004/06/14 09:55:41 ho Exp $ */ +/* $EOM: field.c,v 1.11 2000/02/20 19:58:37 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999 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. + * + * 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 "sysdep.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; + strlcpy(retval, "0x", 3 + len * 2); + p = retval + 2; + for (; len > 0; len--) { + snprintf(p, 1 + len * 2, "%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; + /* 3 decimal digits are enough to represent each byte. */ + retval = malloc(3 * len); + snprintf(retval, 3 * len, "%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 = 4; + retval = malloc(buf_sz); + if (!retval) + return 0; + + strlcpy(retval, "[ ", buf_sz); + for (bit = 1; bit; bit <<= 1) { + if (val & bit) { + name = constant_name_maps(maps, bit); + buf_sz += strlen(name) + 1; + new_buf = realloc(retval, buf_sz); + if (!new_buf) { + free(retval); + return 0; + } + retval = new_buf; + strlcat(retval, name, buf_sz); + strlcat(retval, " ", buf_sz); + } + } + strlcat(retval, "]", buf_sz); + 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_DBG((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/keyexchange/isakmpd-20041012/field.h b/keyexchange/isakmpd-20041012/field.h new file mode 100644 index 0000000..428d417 --- /dev/null +++ b/keyexchange/isakmpd-20041012/field.h @@ -0,0 +1,54 @@ +/* $OpenBSD: field.h,v 1.6 2004/05/23 18:17:55 hshoexer Exp $ */ +/* $EOM: field.h,v 1.3 1998/08/02 20:25:01 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. + * + * 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/keyexchange/isakmpd-20041012/genconstants.sh b/keyexchange/isakmpd-20041012/genconstants.sh new file mode 100644 index 0000000..8332209 --- /dev/null +++ b/keyexchange/isakmpd-20041012/genconstants.sh @@ -0,0 +1,114 @@ +# $OpenBSD: genconstants.sh,v 1.12 2004/04/15 18:39:25 deraadt Exp $ +# $EOM: genconstants.sh,v 1.6 1999/04/02 01:15:53 niklas Exp $ + +# +# Copyright (c) 1998, 1999, 2001 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. +# +# 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 \"sysdep.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 \"sysdep.h\"\n" + print "#include \"constants.h\"" + 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\", %s },\n", prefix, $1, $1, + ($3 && substr($3,1,1) != "#") ? $3 : 0) + next +} + +{ + print +} +' <$1.cst >$base.c diff --git a/keyexchange/isakmpd-20041012/genfields.sh b/keyexchange/isakmpd-20041012/genfields.sh new file mode 100644 index 0000000..74909e1 --- /dev/null +++ b/keyexchange/isakmpd-20041012/genfields.sh @@ -0,0 +1,185 @@ +# $OpenBSD: genfields.sh,v 1.9 2004/04/15 18:39:25 deraadt Exp $ +# $EOM: genfields.sh,v 1.5 1999/04/02 01:15:55 niklas Exp $ + +# +# Copyright (c) 1998, 1999, 2001 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. +# +# 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 \"sysdep.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 \"sysdep.h\"\n" + print "#include \"constants.h\"" + print "#include \"field.h\"" + print "#include \"'$base'.h\"" + print "#include \"isakmp_num.h\"" + print "#include \"ipsec_num.h\"\n" +} + +/^#/ { + next +} + +/^\./ { + print " { 0, 0, 0, 0, 0 }\n};\n" + size[prefix] = off + for (map in maps) + { + printf ("struct constant_map *%s_%s_maps[] = {\n", locase(prefix), + locase(map)) + printf (" %s, 0\n};\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/keyexchange/isakmpd-20041012/gmp_util.c b/keyexchange/isakmpd-20041012/gmp_util.c new file mode 100644 index 0000000..2a338d2 --- /dev/null +++ b/keyexchange/isakmpd-20041012/gmp_util.c @@ -0,0 +1,105 @@ +/* $OpenBSD: gmp_util.c,v 1.11 2004/04/15 18:39:25 deraadt Exp $ */ +/* $EOM: gmp_util.c,v 1.7 2000/09/18 00:01:47 ho Exp $ */ + +/* + * Copyright (c) 1998 Niels Provos. All rights reserved. + * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2000 Håkan Olsson. 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. + * + * 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 "sysdep.h" + +#include "gmp_util.h" +#include "math_mp.h" + +/* Various utility functions for gmp, used in more than one module */ + +u_int32_t +mpz_sizeinoctets(math_mp_t a) +{ +#if MP_FLAVOUR == MP_FLAVOUR_GMP + return (7 + mpz_sizeinbase(a, 2)) >> 3; +#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL + return BN_num_bytes(a); +#endif +} + +void +mpz_getraw(u_int8_t *raw, math_mp_t v, u_int32_t len) +{ + math_mp_t a; + +#if MP_FLAVOUR == MP_FLAVOUR_GMP + math_mp_t tmp; + + /* XXX mpz_get_str (raw, BASE, v); ? */ + mpz_init_set(a, v); + mpz_init(tmp); +#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL + /* XXX bn2bin? */ + a = BN_dup(v); +#endif + + while (len-- > 0) +#if MP_FLAVOUR == MP_FLAVOUR_GMP + raw[len] = mpz_fdiv_qr_ui(a, tmp, a, 256); +#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL + raw[len] = BN_div_word(a, 256); +#endif + +#if MP_FLAVOUR == MP_FLAVOUR_GMP + mpz_clear(a); + mpz_clear(tmp); +#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL + BN_clear_free(a); +#endif +} + +void +mpz_setraw(math_mp_t d, u_int8_t *s, u_int32_t l) +{ + u_int32_t i; + +#if MP_FLAVOUR == MP_FLAVOUR_GMP + /* XXX mpz_set_str (d, s, 0); */ + mpz_set_si(d, 0); +#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL + /* XXX bin2bn? */ + BN_set_word(d, 0); +#endif + for (i = 0; i < l; i++) { +#if MP_FLAVOUR == MP_FLAVOUR_GMP + mpz_mul_ui(d, d, 256); + mpz_add_ui(d, d, s[i]); +#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL + BN_mul_word(d, 256); + BN_add_word(d, s[i]); +#endif + } +} diff --git a/keyexchange/isakmpd-20041012/gmp_util.h b/keyexchange/isakmpd-20041012/gmp_util.h new file mode 100644 index 0000000..826c6ca --- /dev/null +++ b/keyexchange/isakmpd-20041012/gmp_util.h @@ -0,0 +1,42 @@ +/* $OpenBSD: gmp_util.h,v 1.8 2004/04/15 18:39:25 deraadt Exp $ */ +/* $EOM: gmp_util.h,v 1.4 2000/05/08 13:42:11 ho Exp $ */ + +/* + * Copyright (c) 1998 Niels Provos. All rights reserved. + * Copyright (c) 2000 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. + * + * 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_ + +#include "math_mp.h" + +u_int32_t mpz_sizeinoctets(math_mp_t); +void mpz_getraw(u_int8_t *, math_mp_t, u_int32_t); +void mpz_setraw(math_mp_t, u_int8_t *, u_int32_t); + +#endif /* _GMP_UTIL_H_ */ diff --git a/keyexchange/isakmpd-20041012/hash.c b/keyexchange/isakmpd-20041012/hash.c new file mode 100644 index 0000000..84773f8 --- /dev/null +++ b/keyexchange/isakmpd-20041012/hash.c @@ -0,0 +1,145 @@ +/* $OpenBSD: hash.c,v 1.17 2004/06/14 09:55:41 ho Exp $ */ +/* $EOM: hash.c,v 1.10 1999/04/17 23:20:34 niklas Exp $ */ + +/* + * Copyright (c) 1998 Niels Provos. All rights reserved. + * Copyright (c) 1999 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. + * + * 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> +#if defined (__APPLE__) +#include <openssl/md5.h> +#include <openssl/sha.h> +#else +#include <md5.h> +#include <sha1.h> +#endif /* __APPLE__ */ + +#include "sysdep.h" + +#include "hash.h" +#include "log.h" + +void hmac_init(struct hash *, unsigned char *, unsigned 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) +{ + size_t i; + + LOG_DBG((LOG_CRYPTO, 60, "hash_get: requested algorithm %d", + hashtype)); + + for (i = 0; i < sizeof hashes / sizeof hashes[0]; i++) + if (hashtype == hashes[i].type) + return &hashes[i]; + + return 0; +} + +/* + * 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, unsigned int len) +{ + unsigned int i, blocklen = HMAC_BLOCKLEN; + unsigned char key[HMAC_BLOCKLEN]; + + memset(key, 0, 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 { + 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 *dgst, struct hash *hash) +{ + hash->Final(dgst, hash->ctx); + hash->Update(hash->ctx2, dgst, hash->hashsize); + hash->Final(dgst, hash->ctx2); +} diff --git a/keyexchange/isakmpd-20041012/hash.h b/keyexchange/isakmpd-20041012/hash.h new file mode 100644 index 0000000..3af2350 --- /dev/null +++ b/keyexchange/isakmpd-20041012/hash.h @@ -0,0 +1,70 @@ +/* $OpenBSD: hash.h,v 1.7 2004/04/15 18:39:25 deraadt Exp $ */ +/* $EOM: hash.h,v 1.6 1998/07/25 22:04:36 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. + * + * 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 */ + unsigned 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 *, unsigned 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 *, unsigned int); + +#endif /* _HASH_H_ */ diff --git a/keyexchange/isakmpd-20041012/if.c b/keyexchange/isakmpd-20041012/if.c new file mode 100644 index 0000000..b9cf927 --- /dev/null +++ b/keyexchange/isakmpd-20041012/if.c @@ -0,0 +1,152 @@ +/* $OpenBSD: if.c,v 1.22 2004/06/14 09:55:41 ho Exp $ */ +/* $EOM: if.c,v 1.12 1999/10/01 13:45:20 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999 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. + * + * 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> +#ifdef HAVE_GETIFADDRS +#include <ifaddrs.h> +#endif + +#include "sysdep.h" + +#include "log.h" +#include "monitor.h" +#include "if.h" + +#ifndef HAVE_GETIFADDRS +/* XXX Unsafe if either x or y has side-effects. */ +#ifndef MAX +#define MAX(x, y) ((x) > (y) ? (x) : (y)) +#endif + +/* 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) +{ + caddr_t buf, new_buf; + int s, len; + + /* Get a socket to ask for the network interface configurations. */ + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s == -1) { + log_error("siocgifconf: " + "socket (AF_INET, SOCK_DGRAM, 0) failed"); + 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. + */ + new_buf = realloc(buf, len); + if (!new_buf) { + log_error("siocgifconf: realloc (%p, %d) failed", buf, + len); + goto err; + } + ifcp->ifc_len = len; + ifcp->ifc_buf = buf = new_buf; + if (ioctl(s, SIOCGIFCONF, ifcp) == -1) { + log_error("siocgifconf: ioctl (%d, SIOCGIFCONF, ...) " + "failed", s); + 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); + ifcp->ifc_len = 0; + ifcp->ifc_buf = 0; + close(s); + return -1; +} +#endif + +int +if_map(int (*func)(char *, struct sockaddr *, void *), void *arg) +{ + int err = 0; + +#ifdef HAVE_GETIFADDRS + struct ifaddrs *ifap, *ifa; + + if (getifaddrs(&ifap) < 0) + return -1; + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) + if ((*func)(ifa->ifa_name, ifa->ifa_addr, arg) == -1) + err = -1; + freeifaddrs(ifap); +#else + 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; + if ((*func)(ifrp->ifr_name, &ifrp->ifr_addr, arg) == -1) + err = -1; + len = sizeof ifrp->ifr_name + + MAX(sysdep_sa_len(&ifrp->ifr_addr), sizeof ifrp->ifr_addr); + } + free(ifc.ifc_buf); +#endif + return err; +} diff --git a/keyexchange/isakmpd-20041012/if.h b/keyexchange/isakmpd-20041012/if.h new file mode 100644 index 0000000..82d574d --- /dev/null +++ b/keyexchange/isakmpd-20041012/if.h @@ -0,0 +1,43 @@ +/* $OpenBSD: if.h,v 1.7 2004/04/15 18:39:25 deraadt Exp $ */ +/* $EOM: if.h,v 1.2 1998/07/07 23:35:58 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. + * + * 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(int (*) (char *, struct sockaddr *, void *), void *); +extern int siocgifconf(struct ifconf *); + +#endif /* _IF_H_ */ diff --git a/keyexchange/isakmpd-20041012/ike_aggressive.c b/keyexchange/isakmpd-20041012/ike_aggressive.c new file mode 100644 index 0000000..48ec10f --- /dev/null +++ b/keyexchange/isakmpd-20041012/ike_aggressive.c @@ -0,0 +1,184 @@ +/* $OpenBSD: ike_aggressive.c,v 1.8 2004/07/29 08:54:08 ho Exp $ */ +/* $EOM: ike_aggressive.c,v 1.4 2000/01/31 22:33:45 niklas Exp $ */ + +/* + * Copyright (c) 1999 Niklas Hallqvist. All rights reserved. + * Copyright (c) 1999 Angelos D. Keromytis. 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. + * + * 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 "sysdep.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_aggressive.h" +#include "ike_phase_1.h" +#include "ipsec.h" +#include "ipsec_doi.h" +#include "isakmp.h" +#include "log.h" +#include "math_group.h" +#include "message.h" +#if defined (USE_NAT_TRAVERSAL) +#include "nat_traversal.h" +#endif +#include "prf.h" +#include "sa.h" +#include "transport.h" +#include "util.h" + +static int initiator_recv_SA_KE_NONCE_ID_AUTH(struct message *); +static int initiator_send_SA_KE_NONCE_ID(struct message *); +static int initiator_send_AUTH(struct message *); +static int responder_recv_SA_KE_NONCE_ID(struct message *); +static int responder_send_SA_KE_NONCE_ID_AUTH(struct message *); +static int responder_recv_AUTH(struct message *); + +int (*ike_aggressive_initiator[])(struct message *) = { + initiator_send_SA_KE_NONCE_ID, + initiator_recv_SA_KE_NONCE_ID_AUTH, + initiator_send_AUTH +}; + +int (*ike_aggressive_responder[])(struct message *) = { + responder_recv_SA_KE_NONCE_ID, + responder_send_SA_KE_NONCE_ID_AUTH, + responder_recv_AUTH +}; + +/* Offer a set of transforms to the responder in the MSG message. */ +static int +initiator_send_SA_KE_NONCE_ID(struct message *msg) +{ + if (ike_phase_1_initiator_send_SA(msg)) + return -1; + + if (ike_phase_1_initiator_send_KE_NONCE(msg)) + return -1; + + return ike_phase_1_send_ID(msg); +} + +/* Figure out what transform the responder chose. */ +static int +initiator_recv_SA_KE_NONCE_ID_AUTH(struct message *msg) +{ + if (ike_phase_1_initiator_recv_SA(msg)) + return -1; + + if (ike_phase_1_initiator_recv_KE_NONCE(msg)) + return -1; + + return ike_phase_1_recv_ID_AUTH(msg); +} + +static int +initiator_send_AUTH(struct message *msg) +{ + msg->exchange->flags |= EXCHANGE_FLAG_ENCRYPT; + + if (ike_phase_1_send_AUTH(msg)) + return -1; + + /* + * RFC 2407 4.6.3 says that, among others, INITIAL-CONTACT MUST NOT + * be sent in Aggressive Mode. This leaves us with the choice of + * doing it in an informational exchange of its own with no delivery + * guarantee or in the first Quick Mode, or not at all. + * draft-jenkins-ipsec-rekeying-01.txt has some text that requires + * INITIAL-CONTACT in phase 1, thus contradicting what we learned + * above. I will bring this up in the IPsec list. For now we don't + * do INITIAL-CONTACT at all when using aggressive mode. + */ + return 0; +} + +/* + * Accept a set of transforms offered by the initiator and chose one we can + * handle. Also accept initiator's public DH value, nonce and ID. + */ +static int +responder_recv_SA_KE_NONCE_ID(struct message *msg) +{ + if (ike_phase_1_responder_recv_SA(msg)) + return -1; + + if (ike_phase_1_recv_ID(msg)) + return -1; + + return ike_phase_1_recv_KE_NONCE(msg); +} + +/* + * Reply with the transform we chose. Send our public DH value and a nonce + * to the initiator. + */ +static int +responder_send_SA_KE_NONCE_ID_AUTH(struct message *msg) +{ + /* Add the SA payload with the transform that was chosen. */ + if (ike_phase_1_responder_send_SA(msg)) + return -1; + + /* XXX Should we really just use the initiator's nonce size? */ + if (ike_phase_1_send_KE_NONCE(msg, msg->exchange->nonce_i_len)) + return -1; + + if (ike_phase_1_post_exchange_KE_NONCE(msg)) + return -1; + + return ike_phase_1_responder_send_ID_AUTH(msg); +} + +/* + * Reply with the transform we chose. Send our public DH value and a nonce + * to the initiator. + */ +static int +responder_recv_AUTH(struct message *msg) +{ + if (ike_phase_1_recv_AUTH(msg)) + return -1; + +#if defined (USE_NAT_TRAVERSAL) + /* Aggressive: Check for NAT-D payloads and contents. */ + if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_CAP_PEER) + (void)nat_t_exchange_check_nat_d(msg); +#endif + return 0; +} diff --git a/keyexchange/isakmpd-20041012/ike_aggressive.h b/keyexchange/isakmpd-20041012/ike_aggressive.h new file mode 100644 index 0000000..f2af524 --- /dev/null +++ b/keyexchange/isakmpd-20041012/ike_aggressive.h @@ -0,0 +1,40 @@ +/* $OpenBSD: ike_aggressive.h,v 1.5 2004/05/23 18:17:55 hshoexer Exp $ */ +/* $EOM: ike_aggressive.h,v 1.1 1999/04/16 21:24:43 niklas Exp $ */ + +/* + * Copyright (c) 1999 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. + * + * 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_AGGRESSIVE_H_ +#define _IKE_AGGRESSIVE_H_ + +struct message; + +extern int (*ike_aggressive_initiator[])(struct message *msg); +extern int (*ike_aggressive_responder[])(struct message *msg); + +#endif /* _IKE_AGGRESSIVE_H_ */ diff --git a/keyexchange/isakmpd-20041012/ike_auth.c b/keyexchange/isakmpd-20041012/ike_auth.c new file mode 100644 index 0000000..dcacb0e --- /dev/null +++ b/keyexchange/isakmpd-20041012/ike_auth.c @@ -0,0 +1,1167 @@ +/* $OpenBSD: ike_auth.c,v 1.95 2004/08/08 19:11:06 deraadt Exp $ */ +/* $EOM: ike_auth.c,v 1.59 2000/11/21 00:21:31 angelos Exp $ */ + +/* + * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 1999 Niels Provos. All rights reserved. + * Copyright (c) 1999 Angelos D. Keromytis. All rights reserved. + * Copyright (c) 2000, 2001, 2003 Håkan Olsson. 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. + * + * 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 <netinet/in.h> +#include <arpa/inet.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <regex.h> +#if defined (USE_KEYNOTE) +#include <keynote.h> +#endif +#include <policy.h> + +#include "sysdep.h" + +#include "cert.h" +#include "conf.h" +#include "constants.h" +#if defined (USE_DNSSEC) +#include "dnssec.h" +#endif +#include "exchange.h" +#include "gmp_util.h" +#include "hash.h" +#include "ike_auth.h" +#include "ipsec.h" +#include "ipsec_doi.h" +#include "libcrypto.h" +#include "log.h" +#include "message.h" +#include "monitor.h" +#include "prf.h" +#include "transport.h" +#include "util.h" +#include "key.h" +#if defined (USE_X509) +#include "x509.h" +#endif + +#ifdef notyet +static u_int8_t *enc_gen_skeyid(struct exchange *, size_t *); +#endif +static u_int8_t *pre_shared_gen_skeyid(struct exchange *, size_t *); + +static int pre_shared_decode_hash(struct message *); +static int pre_shared_encode_hash(struct message *); + +#if defined (USE_X509) || defined (USE_KEYNOTE) +static u_int8_t *sig_gen_skeyid(struct exchange *, size_t *); +static int rsa_sig_decode_hash(struct message *); +static int rsa_sig_encode_hash(struct message *); +#endif + +#if defined (USE_RAWKEY) +static int get_raw_key_from_file(int, u_int8_t *, size_t, RSA **); +#endif + +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 + }, +#ifdef notdef + { + IKE_AUTH_DSS, sig_gen_skeyid, + pre_shared_decode_hash, + pre_shared_encode_hash + }, +#endif +#if defined (USE_X509) || defined (USE_KEYNOTE) + { + IKE_AUTH_RSA_SIG, sig_gen_skeyid, + rsa_sig_decode_hash, + rsa_sig_encode_hash + }, +#endif +#ifdef notdef + { + 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 + }, +#endif +}; + +struct ike_auth * +ike_auth_get(u_int16_t id) +{ + size_t 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; +} + +/* + * Find and decode the configured key (pre-shared or public) for the + * peer denoted by ID. Stash the len in KEYLEN. + */ +static void * +ike_auth_get_key(int type, char *id, char *local_id, size_t *keylen) +{ + char *key, *buf; +#if defined (USE_X509) || defined (USE_KEYNOTE) + int fd; + char *keyfile; +#if defined (USE_X509) + FILE *keyfp; + RSA *rsakey; + size_t fsize; +#endif +#endif + + switch (type) { + case IKE_AUTH_PRE_SHARED: + /* Get the pre-shared key for our peer. */ + key = conf_get_str(id, "Authentication"); + if (!key && local_id) + key = conf_get_str(local_id, "Authentication"); + + if (!key) { + log_print("ike_auth_get_key: " + "no key found for peer \"%s\" or local ID \"%s\"", + id, local_id); + return 0; + } + /* If the key starts with 0x it is in hex format. */ + if (strncasecmp(key, "0x", 2) == 0) { + *keylen = (strlen(key) - 1) / 2; + buf = malloc(*keylen); + if (!buf) { + log_error("ike_auth_get_key: malloc (%lu) " + "failed", (unsigned long)*keylen); + return 0; + } + if (hex2raw(key + 2, (unsigned char *)buf, *keylen)) { + free(buf); + log_print("ike_auth_get_key: invalid hex key " + "%s", key); + return 0; + } + key = buf; + } else { + buf = key; + key = strdup(buf); + if (!key) { + log_error("ike_auth_get_key: strdup() failed"); + return 0; + } + *keylen = strlen(key); + } + break; + + case IKE_AUTH_RSA_SIG: +#if defined (USE_X509) || defined (USE_KEYNOTE) +#if defined (USE_KEYNOTE) + if (local_id && (keyfile = conf_get_str("KeyNote", + "Credential-directory")) != 0) { + struct stat sb; + struct keynote_deckey dc; + char *privkeyfile, *buf2; + int pkflen; + size_t size; + + pkflen = strlen(keyfile) + strlen(local_id) + + sizeof PRIVATE_KEY_FILE + sizeof "//" - 1; + privkeyfile = calloc(pkflen, sizeof(char)); + if (!privkeyfile) { + log_print("ike_auth_get_key: failed to " + "allocate %d bytes", pkflen); + return 0; + } + snprintf(privkeyfile, pkflen, "%s/%s/%s", keyfile, + local_id, PRIVATE_KEY_FILE); + keyfile = privkeyfile; + + fd = monitor_open(keyfile, O_RDONLY, 0); + if (fd < 0) { + free(keyfile); + goto ignorekeynote; + } + + if (fstat(fd, &sb) < 0) { + log_print("ike_auth_get_key: fstat failed"); + free(keyfile); + close(fd); + return 0; + } + size = (size_t)sb.st_size; + + buf = calloc(size + 1, sizeof(char)); + if (!buf) { + log_print("ike_auth_get_key: failed allocating" + " %lu bytes", (unsigned long)size + 1); + free(keyfile); + close(fd); + return 0; + } + if (read(fd, buf, size) != (ssize_t)size) { + free(buf); + log_print("ike_auth_get_key: " + "failed reading %lu bytes from \"%s\"", + (unsigned long)size, keyfile); + free(keyfile); + close(fd); + return 0; + } + close(fd); + + /* Parse private key string */ + buf2 = kn_get_string(buf); + free(buf); + + if (!buf2 || kn_decode_key(&dc, buf2, + KEYNOTE_PRIVATE_KEY) == -1) { + if (buf2) + free(buf2); + log_print("ike_auth_get_key: failed decoding " + "key in \"%s\"", keyfile); + free(keyfile); + return 0; + } + free(buf2); + + if (dc.dec_algorithm != KEYNOTE_ALGORITHM_RSA) { + log_print("ike_auth_get_key: wrong algorithm " + "type %d in \"%s\"", dc.dec_algorithm, + keyfile); + free(keyfile); + kn_free_key(&dc); + return 0; + } + free(keyfile); + return dc.dec_key; + } +ignorekeynote: +#endif /* USE_KEYNOTE */ +#ifdef USE_X509 + /* Otherwise, try X.509 */ + keyfile = conf_get_str("X509-certificates", "Private-key"); + + fd = monitor_open(keyfile, O_RDONLY, 0); + if (fd < 0) { + log_print("ike_auth_get_key: failed opening \"%s\"", + keyfile); + return 0; + } + + if (check_file_secrecy_fd(fd, keyfile, &fsize) < 0) { + close(fd); + return 0; + } + + if ((keyfp = fdopen(fd, "r")) == NULL) { + log_print("ike_auth_get_key: fdopen failed"); + close(fd); + return 0; + } +#if SSLEAY_VERSION_NUMBER >= 0x00904100L + rsakey = PEM_read_RSAPrivateKey(keyfp, NULL, NULL, NULL); +#else + rsakey = PEM_read_RSAPrivateKey(keyfp, NULL, NULL); +#endif + fclose(keyfp); + + if (!rsakey) { + log_print("ike_auth_get_key: " + "PEM_read_bio_RSAPrivateKey failed"); + return 0; + } + return rsakey; +#endif /* USE_X509 */ +#endif /* USE_X509 || USE_KEYNOTE */ + + default: + log_print("ike_auth_get_key: unknown key type %d", type); + return 0; + } + + return key; +} + +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, *buf = 0; + unsigned char *key; + size_t keylen; + + /* + * If we're the responder and have the initiator's ID (which is the + * case in Aggressive mode), try to find the preshared key in the + * section of the initiator's Phase 1 ID. This allows us to do + * mobile user support with preshared keys. + */ + if (!exchange->initiator && exchange->id_i) { + switch (exchange->id_i[0]) { + case IPSEC_ID_IPV4_ADDR: + case IPSEC_ID_IPV6_ADDR: + util_ntoa((char **) &buf, + exchange->id_i[0] == IPSEC_ID_IPV4_ADDR ? AF_INET : + AF_INET6, exchange->id_i + ISAKMP_ID_DATA_OFF - + ISAKMP_GEN_SZ); + if (!buf) + return 0; + break; + + case IPSEC_ID_FQDN: + case IPSEC_ID_USER_FQDN: + buf = calloc(exchange->id_i_len - ISAKMP_ID_DATA_OFF + + ISAKMP_GEN_SZ + 1, sizeof(char)); + if (!buf) { + log_print("pre_shared_gen_skeyid: malloc (%lu" + ") failed", + (unsigned long)exchange->id_i_len - + ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1); + return 0; + } + memcpy(buf, + exchange->id_i + ISAKMP_ID_DATA_OFF - + ISAKMP_GEN_SZ, + exchange->id_i_len - ISAKMP_ID_DATA_OFF + + ISAKMP_GEN_SZ); + break; + + /* XXX Support more ID types ? */ + default: + break; + } + } + /* + * Get the pre-shared key for our peer. This will work even if the key + * has been passed to us through a mechanism like PFKEYv2. + */ + key = ike_auth_get_key(IKE_AUTH_PRE_SHARED, exchange->name, + (char *) buf, &keylen); + if (buf) + free(buf); + + /* Fail if no key could be found. */ + if (!key) + return 0; + + /* Store the secret key for later policy processing. */ + exchange->recv_key = calloc(keylen + 1, sizeof(char)); + exchange->recv_keytype = ISAKMP_KEY_PASSPHRASE; + if (!exchange->recv_key) { + log_error("pre_shared_gen_skeyid: malloc (%lu) failed", + (unsigned long)keylen); + free(key); + return 0; + } + memcpy(exchange->recv_key, key, keylen); + exchange->recv_certtype = ISAKMP_CERTENC_NONE; + free(key); + + prf = prf_alloc(ie->prf_type, ie->hash->type, exchange->recv_key, + keylen); + if (!prf) + return 0; + + *sz = prf->blocksize; + skeyid = malloc(*sz); + if (!skeyid) { + log_error("pre_shared_gen_skeyid: malloc (%lu) failed", + (unsigned long)*sz); + 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; +} + +#if defined (USE_X509) || defined (USE_KEYNOTE) +/* Both DSS & RSA signature authentication use 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; + unsigned char *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); + + LOG_DBG((LOG_NEGOTIATION, 80, "sig_gen_skeyid: PRF type %d, hash %d", + ie->prf_type, ie->hash->type)); + LOG_DBG_BUF((LOG_NEGOTIATION, 80, + "sig_gen_skeyid: SKEYID initialized with", + (u_int8_t *)key, exchange->nonce_i_len + 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) { + log_error("sig_gen_skeyid: malloc (%lu) failed", + (unsigned long)*sz); + prf_free(prf); + return 0; + } + LOG_DBG((LOG_NEGOTIATION, 80, "sig_gen_skeyid: g^xy length %lu", + (unsigned long) ie->g_x_len)); + LOG_DBG_BUF((LOG_NEGOTIATION, 80, + "sig_gen_skeyid: SKEYID fed with g^xy", ie->g_xy, ie->g_x_len)); + + 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; +} +#endif /* USE_X509 || USE_KEYNOTE */ + +#ifdef notdef +/* + * Both standard and revised RSA encryption authentication use 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) { + log_error("enc_gen_skeyid: malloc (%d) failed", *sz); + 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; +} +#endif /* notdef */ + +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 = payload_first(msg, ISAKMP_PAYLOAD_HASH); + if (!payload) { + log_print("pre_shared_decode_hash: no HASH payload found"); + 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) { + log_error("pre_shared_decode_hash: malloc (%lu) failed", + (unsigned long)hashsize); + return -1; + } + memcpy(*hash_p, payload->p + ISAKMP_HASH_DATA_OFF, hashsize); + snprintf(header, sizeof header, "pre_shared_decode_hash: HASH_%c", + initiator ? 'R' : 'I'); + LOG_DBG_BUF((LOG_MISC, 80, header, *hash_p, hashsize)); + + payload->flags |= PL_MARK; + return 0; +} + +#if defined (USE_X509) || defined (USE_KEYNOTE) +/* 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; + void *cert = 0; + u_int8_t *rawcert = 0, **hash_p, **id_cert, *id; + u_int32_t rawcertlen, *id_cert_len; + RSA *key = 0; + size_t hashsize = ie->hash->hashsize, id_len; + char header[80]; + int len, initiator = exchange->initiator; + int found = 0, n, i, id_found; +#if defined (USE_DNSSEC) + u_int8_t *rawkey = 0; + u_int32_t rawkeylen; +#endif + + /* 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 || id_len == 0) { + log_print("rsa_sig_decode_hash: ID is missing"); + return -1; + } + /* + * XXX Assume we should use the same kind of certification as the + * remote... moreover, just use the first CERT payload to decide what + * to use. + */ + p = payload_first(msg, ISAKMP_PAYLOAD_CERT); + if (!p) + handler = cert_get(ISAKMP_CERTENC_KEYNOTE); + else + handler = cert_get(GET_ISAKMP_CERT_ENCODING(p->p)); + if (!handler) { + log_print("rsa_sig_decode_hash: cert_get (%d) failed", + p ? GET_ISAKMP_CERT_ENCODING(p->p) : -1); + return -1; + } +#if defined (USE_POLICY) || defined (USE_KEYNOTE) + /* + * We need the policy session initialized now, so we can add + * credentials etc. + */ + exchange->policy_id = kn_init(); + if (exchange->policy_id == -1) { + log_print("rsa_sig_decode_hash: failed to initialize policy " + "session"); + return -1; + } +#endif /* USE_POLICY || USE_KEYNOTE */ + + /* Obtain a certificate from our certificate storage. */ + if (handler->cert_obtain(id, id_len, 0, &rawcert, &rawcertlen)) { + if (handler->id == ISAKMP_CERTENC_X509_SIG) { + cert = handler->cert_get(rawcert, rawcertlen); + if (!cert) + LOG_DBG((LOG_CRYPTO, 50, "rsa_sig_decode_hash:" + " certificate malformed")); + else { + if (!handler->cert_get_key(cert, &key)) { + log_print("rsa_sig_decode_hash: " + "decoding certificate failed"); + handler->cert_free(cert); + } else { + found++; + LOG_DBG((LOG_CRYPTO, 40, + "rsa_sig_decode_hash: using cert " + "of type %d", handler->id)); + exchange->recv_cert = cert; + exchange->recv_certtype = handler->id; +#if defined (USE_POLICY) + x509_generate_kn(exchange->policy_id, + cert); +#endif /* USE_POLICY */ + } + } + } else if (handler->id == ISAKMP_CERTENC_KEYNOTE) + handler->cert_insert(exchange->policy_id, rawcert); + free(rawcert); + } + /* + * Walk over potential CERT payloads in this message. + * XXX I believe this is the wrong spot for this. CERTs can appear + * anytime. + */ + for (p = payload_first(msg, ISAKMP_PAYLOAD_CERT); p; + p = TAILQ_NEXT(p, link)) { + p->flags |= PL_MARK; + + /* + * When we have found a key, just walk over the rest, marking + * them. + */ + if (found) + continue; + + handler = cert_get(GET_ISAKMP_CERT_ENCODING(p->p)); + if (!handler) { + LOG_DBG((LOG_MISC, 30, "rsa_sig_decode_hash: " + "no handler for %s CERT encoding", + constant_name(isakmp_certenc_cst, + GET_ISAKMP_CERT_ENCODING(p->p)))); + continue; + } + cert = handler->cert_get(p->p + ISAKMP_CERT_DATA_OFF, + GET_ISAKMP_GEN_LENGTH(p->p) - ISAKMP_CERT_DATA_OFF); + if (!cert) { + log_print("rsa_sig_decode_hash: " + "can not get data from CERT"); + continue; + } + if (!handler->cert_validate(cert)) { + handler->cert_free(cert); + log_print("rsa_sig_decode_hash: received CERT can't " + "be validated"); + continue; + } + if (GET_ISAKMP_CERT_ENCODING(p->p) == + ISAKMP_CERTENC_X509_SIG) { + if (!handler->cert_get_subjects(cert, &n, &id_cert, + &id_cert_len)) { + handler->cert_free(cert); + log_print("rsa_sig_decode_hash: can not get " + "subject from CERT"); + continue; + } + id_found = 0; + for (i = 0; i < n; i++) + if (id_cert_len[i] == id_len && + id[0] == id_cert[i][0] && + memcmp(id + 4, id_cert[i] + 4, id_len - 4) + == 0) { + id_found++; + break; + } + if (!id_found) { + handler->cert_free(cert); + log_print("rsa_sig_decode_hash: no CERT " + "subject match the ID"); + free(id_cert); + continue; + } + cert_free_subjects(n, id_cert, id_cert_len); + } + if (!handler->cert_get_key(cert, &key)) { + handler->cert_free(cert); + log_print("rsa_sig_decode_hash: decoding payload CERT " + "failed"); + continue; + } + /* We validated the cert, cache it for later use. */ + handler->cert_insert(exchange->policy_id, cert); + + exchange->recv_cert = cert; + exchange->recv_certtype = GET_ISAKMP_CERT_ENCODING(p->p); + +#if defined (USE_POLICY) || defined (USE_KEYNOTE) + if (exchange->recv_certtype == ISAKMP_CERTENC_KEYNOTE) { + struct keynote_deckey dc; + char *pp; + int dclen; + + dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA; + dc.dec_key = key; + + pp = kn_encode_key(&dc, INTERNAL_ENC_PKCS1, + ENCODING_HEX, KEYNOTE_PUBLIC_KEY); + if (pp == NULL) { + kn_free_key(&dc); + log_print("rsa_sig_decode_hash: failed to " + "ASCII-encode key"); + return -1; + } + dclen = strlen(pp) + sizeof "rsa-hex:"; + exchange->keynote_key = calloc(dclen, sizeof(char)); + if (!exchange->keynote_key) { + free(pp); + kn_free_key(&dc); + log_print("rsa_sig_decode_hash: failed to " + "allocate %d bytes", dclen); + return -1; + } + snprintf(exchange->keynote_key, dclen, "rsa-hex:%s", + pp); + free(pp); + } +#endif + + found++; + } + +#if defined (USE_DNSSEC) + /* + * If no certificate provided a key, try to find a validated DNSSEC + * KEY. + */ + if (!found) { + rawkey = dns_get_key(IKE_AUTH_RSA_SIG, msg, &rawkeylen); + + /* We need to convert 'void *rawkey' into 'RSA *key'. */ + if (dns_RSA_dns_to_x509(rawkey, rawkeylen, &key) == 0) + found++; + else + log_print("rsa_sig_decode_hash: KEY to RSA key " + "conversion failed"); + + if (rawkey) + free(rawkey); + } +#endif /* USE_DNSSEC */ + +#if defined (USE_RAWKEY) + /* If we still have not found a key, try to read it from a file. */ + if (!found) + if (get_raw_key_from_file(IKE_AUTH_RSA_SIG, id, id_len, &key) + != -1) + found++; +#endif + + if (!found) { + log_print("rsa_sig_decode_hash: no public key found"); + return -1; + } + p = payload_first(msg, ISAKMP_PAYLOAD_SIG); + if (!p) { + log_print("rsa_sig_decode_hash: missing signature payload"); + RSA_free(key); + return -1; + } + /* Check that the sig is of the correct size. */ + len = GET_ISAKMP_GEN_LENGTH(p->p) - ISAKMP_SIG_SZ; + if (len != RSA_size(key)) { + RSA_free(key); + log_print("rsa_sig_decode_hash: " + "SIG payload length does not match public key"); + return -1; + } + *hash_p = malloc(len); + if (!*hash_p) { + RSA_free(key); + log_error("rsa_sig_decode_hash: malloc (%d) failed", len); + return -1; + } + len = RSA_public_decrypt(len, p->p + ISAKMP_SIG_DATA_OFF, *hash_p, key, + RSA_PKCS1_PADDING); + if (len == -1) { + RSA_free(key); + log_print("rsa_sig_decode_hash: RSA_public_decrypt () failed"); + return -1; + } + /* Store key for later use */ + exchange->recv_key = key; + exchange->recv_keytype = ISAKMP_KEY_RSA; + + if (len != (int) hashsize) { + free(*hash_p); + *hash_p = 0; + log_print("rsa_sig_decode_hash: len %lu != hashsize %lu", + (unsigned long)len, (unsigned long)hashsize); + return -1; + } + snprintf(header, sizeof header, "rsa_sig_decode_hash: HASH_%c", + initiator ? 'R' : 'I'); + LOG_DBG_BUF((LOG_MISC, 80, header, *hash_p, hashsize)); + + p->flags |= PL_MARK; + return 0; +} +#endif /* USE_X509 || USE_KEYNOTE */ + +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; + + buf = ipsec_add_hash_payload(msg, hashsize); + if (!buf) + return -1; + + if (ike_auth_hash(exchange, buf + ISAKMP_HASH_DATA_OFF) == -1) + return -1; + + snprintf(header, sizeof header, "pre_shared_encode_hash: HASH_%c", + initiator ? 'I' : 'R'); + LOG_DBG_BUF((LOG_MISC, 80, header, buf + ISAKMP_HASH_DATA_OFF, + hashsize)); + return 0; +} + +#if defined (USE_X509) || defined (USE_KEYNOTE) +/* 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, id_len; + struct cert_handler *handler; + char header[80]; + int initiator = exchange->initiator, idtype; + u_int8_t *buf, *data, *buf2, *id; + u_int32_t datalen; + int32_t sigsize; + void *sent_key; + + id = initiator ? exchange->id_i : exchange->id_r; + id_len = initiator ? exchange->id_i_len : exchange->id_r_len; + + /* We may have been provided these by the kernel */ + buf = (u_int8_t *) conf_get_str(exchange->name, "Credentials"); + if (buf && (idtype = conf_get_num(exchange->name, "Credential_Type", + -1) != -1)) { + exchange->sent_certtype = idtype; + handler = cert_get(idtype); + if (!handler) { + log_print("rsa_sig_encode_hash: cert_get (%d) failed", + idtype); + return -1; + } + exchange->sent_cert = + handler->cert_from_printable((char *)buf); + if (!exchange->sent_cert) { + log_print("rsa_sig_encode_hash: failed to retrieve " + "certificate"); + return -1; + } + handler->cert_serialize(exchange->sent_cert, &data, &datalen); + if (!data) { + log_print("rsa_sig_encode_hash: cert serialization " + "failed"); + return -1; + } + goto aftercert; /* Skip all the certificate discovery */ + } + /* XXX This needs to be configurable. */ + idtype = ISAKMP_CERTENC_KEYNOTE; + + /* Find a certificate with subjectAltName = id. */ + handler = cert_get(idtype); + if (!handler) { + idtype = ISAKMP_CERTENC_X509_SIG; + handler = cert_get(idtype); + if (!handler) { + log_print("rsa_sig_encode_hash: cert_get(%d) failed", + idtype); + return -1; + } + } + if (handler->cert_obtain(id, id_len, 0, &data, &datalen) == 0) { + if (idtype == ISAKMP_CERTENC_KEYNOTE) { + idtype = ISAKMP_CERTENC_X509_SIG; + handler = cert_get(idtype); + if (!handler) { + log_print("rsa_sig_encode_hash: cert_get(%d) " + "failed", idtype); + return -1; + } + if (handler->cert_obtain(id, id_len, 0, &data, + &datalen) == 0) { + LOG_DBG((LOG_MISC, 10, "rsa_sig_encode_hash: " + "no certificate to send")); + goto skipcert; + } + } else { + LOG_DBG((LOG_MISC, 10, + "rsa_sig_encode_hash: no certificate to send")); + goto skipcert; + } + } + /* Let's store the certificate we are going to use */ + exchange->sent_certtype = idtype; + exchange->sent_cert = handler->cert_get(data, datalen); + if (!exchange->sent_cert) { + free(data); + log_print("rsa_sig_encode_hash: failed to get certificate " + "from wire encoding"); + return -1; + } +aftercert: + + buf = realloc(data, ISAKMP_CERT_SZ + datalen); + if (!buf) { + log_error("rsa_sig_encode_hash: realloc (%p, %d) failed", data, + ISAKMP_CERT_SZ + datalen); + free(data); + return -1; + } + memmove(buf + ISAKMP_CERT_SZ, buf, datalen); + SET_ISAKMP_CERT_ENCODING(buf, idtype); + if (message_add_payload(msg, ISAKMP_PAYLOAD_CERT, buf, + ISAKMP_CERT_SZ + datalen, 1)) { + free(buf); + return -1; + } +skipcert: + + /* Again, we may have these from the kernel */ + buf = (u_int8_t *) conf_get_str(exchange->name, "PKAuthentication"); + if (buf) { + key_from_printable(ISAKMP_KEY_RSA, ISAKMP_KEYTYPE_PRIVATE, + (char *)buf, &data, &datalen); + if (!data) { + log_print("rsa_sig_encode_hash: badly formatted RSA " + "private key"); + return 0; + } + sent_key = key_internalize(ISAKMP_KEY_RSA, + ISAKMP_KEYTYPE_PRIVATE, data, datalen); + if (!sent_key) { + log_print("rsa_sig_encode_hash: bad RSA private key " + "from dynamic SA acquisition subsystem"); + return 0; + } + } else { + /* Try through the regular means. */ + switch (id[ISAKMP_ID_TYPE_OFF - ISAKMP_GEN_SZ]) { + case IPSEC_ID_IPV4_ADDR: + case IPSEC_ID_IPV6_ADDR: + util_ntoa((char **)&buf2, + id[ISAKMP_ID_TYPE_OFF - ISAKMP_GEN_SZ] == + IPSEC_ID_IPV4_ADDR ? AF_INET : AF_INET6, + id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ); + if (!buf2) + return 0; + break; + + case IPSEC_ID_FQDN: + case IPSEC_ID_USER_FQDN: + buf2 = calloc(id_len - ISAKMP_ID_DATA_OFF + + ISAKMP_GEN_SZ + 1, sizeof(char)); + if (!buf2) { + log_print("rsa_sig_encode_hash: malloc (%lu) " + "failed", (unsigned long)id_len - + ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1); + return 0; + } + memcpy(buf2, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, + id_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ); + break; + + /* XXX Support more ID types? */ + default: + buf2 = 0; + return 0; + } + + sent_key = ike_auth_get_key(IKE_AUTH_RSA_SIG, exchange->name, + (char *)buf2, 0); + free(buf2); + + /* Did we find a key? */ + if (!sent_key) { + log_print("rsa_sig_encode_hash: " + "could not get private key"); + return -1; + } + } + + /* Enable RSA blinding. */ + if (RSA_blinding_on(sent_key, NULL) != 1) { + log_error("rsa_sig_encode_hash: RSA_blinding_on () failed."); + return -1; + } + /* XXX hashsize is not necessarily prf->blocksize. */ + buf = malloc(hashsize); + if (!buf) { + log_error("rsa_sig_encode_hash: malloc (%lu) failed", + (unsigned long)hashsize); + return -1; + } + if (ike_auth_hash(exchange, buf) == -1) { + free(buf); + return -1; + } + snprintf(header, sizeof header, "rsa_sig_encode_hash: HASH_%c", + initiator ? 'I' : 'R'); + LOG_DBG_BUF((LOG_MISC, 80, header, buf, hashsize)); + + data = malloc(RSA_size(sent_key)); + if (!data) { + log_error("rsa_sig_encode_hash: malloc (%d) failed", + RSA_size(sent_key)); + return -1; + } + sigsize = RSA_private_encrypt(hashsize, buf, data, sent_key, + RSA_PKCS1_PADDING); + if (sigsize == -1) { + log_print("rsa_sig_encode_hash: " + "RSA_private_encrypt () failed"); + if (data) + free(data); + free(buf); + RSA_free(sent_key); + return -1; + } + datalen = (u_int32_t) sigsize; + + free(buf); + + buf = realloc(data, ISAKMP_SIG_SZ + datalen); + if (!buf) { + log_error("rsa_sig_encode_hash: realloc (%p, %d) failed", data, + ISAKMP_SIG_SZ + datalen); + free(data); + return -1; + } + memmove(buf + ISAKMP_SIG_SZ, buf, datalen); + + snprintf(header, sizeof header, "rsa_sig_encode_hash: SIG_%c", + initiator ? 'I' : 'R'); + LOG_DBG_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)) { + free(buf); + return -1; + } + return 0; +} +#endif /* USE_X509 || USE_KEYNOTE */ + +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; +} + +#if defined (USE_RAWKEY) +static int +get_raw_key_from_file(int type, u_int8_t *id, size_t id_len, RSA **rsa) +{ + char filename[FILENAME_MAX]; + char *fstr; + FILE *keyfp; + + if (type != IKE_AUTH_RSA_SIG) { /* XXX More types? */ + LOG_DBG((LOG_NEGOTIATION, 20, "get_raw_key_from_file: " + "invalid auth type %d\n", type)); + return -1; + } + *rsa = 0; + + fstr = conf_get_str("General", "Pubkey-directory"); + if (!fstr) + fstr = CONF_DFLT_PUBKEY_DIR; + + if (snprintf(filename, sizeof filename, "%s/", fstr) > + (int)sizeof filename - 1) + return -1; + + fstr = ipsec_id_string(id, id_len); + if (!fstr) { + LOG_DBG((LOG_NEGOTIATION, 50, "get_raw_key_from_file: " + "ipsec_id_string failed")); + return -1; + } + strlcat(filename, fstr, sizeof filename - strlen(filename)); + free(fstr); + + /* If the file does not exist, fail silently. */ + keyfp = monitor_fopen(filename, "r"); + if (keyfp) { + *rsa = PEM_read_RSA_PUBKEY(keyfp, NULL, NULL, NULL); + fclose(keyfp); + } else if (errno != ENOENT) { + log_error("get_raw_key_from_file: monitor_fopen " + "(\"%s\", \"r\") failed", filename); + return -1; + } else + LOG_DBG((LOG_NEGOTIATION, 50, + "get_raw_key_from_file: file %s not found", filename)); + + return (*rsa ? 0 : -1); +} +#endif /* USE_RAWKEY */ diff --git a/keyexchange/isakmpd-20041012/ike_auth.h b/keyexchange/isakmpd-20041012/ike_auth.h new file mode 100644 index 0000000..39b0923 --- /dev/null +++ b/keyexchange/isakmpd-20041012/ike_auth.h @@ -0,0 +1,48 @@ +/* $OpenBSD: ike_auth.h,v 1.5 2004/04/15 18:39:25 deraadt Exp $ */ +/* $EOM: ike_auth.h,v 1.5 1998/08/16 19:55:24 provos 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. + * + * 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/keyexchange/isakmpd-20041012/ike_main_mode.c b/keyexchange/isakmpd-20041012/ike_main_mode.c new file mode 100644 index 0000000..1308564 --- /dev/null +++ b/keyexchange/isakmpd-20041012/ike_main_mode.c @@ -0,0 +1,124 @@ +/* $OpenBSD: ike_main_mode.c,v 1.15 2004/06/14 09:55:41 ho Exp $ */ +/* $EOM: ike_main_mode.c,v 1.77 1999/04/25 22:12:34 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999 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. + * + * 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 "sysdep.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 "ike_phase_1.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_ID_AUTH(struct message *); +static int responder_send_ID_AUTH(struct message *); +static int responder_send_KE_NONCE(struct message *); + +int (*ike_main_mode_initiator[]) (struct message *) = { + ike_phase_1_initiator_send_SA, + ike_phase_1_initiator_recv_SA, + ike_phase_1_initiator_send_KE_NONCE, + ike_phase_1_initiator_recv_KE_NONCE, + initiator_send_ID_AUTH, + ike_phase_1_recv_ID_AUTH +}; + +int (*ike_main_mode_responder[]) (struct message *) = { + ike_phase_1_responder_recv_SA, + ike_phase_1_responder_send_SA, + ike_phase_1_recv_KE_NONCE, + responder_send_KE_NONCE, + ike_phase_1_recv_ID_AUTH, + responder_send_ID_AUTH +}; + +static int +initiator_send_ID_AUTH(struct message *msg) +{ + msg->exchange->flags |= EXCHANGE_FLAG_ENCRYPT; + + if (ike_phase_1_send_ID(msg)) + return -1; + + if (ike_phase_1_send_AUTH(msg)) + return -1; + + return ipsec_initial_contact(msg); +} + +/* Send our public DH value and a nonce to the initiator. */ +int +responder_send_KE_NONCE(struct message *msg) +{ + /* XXX Should we really just use the initiator's nonce size? */ + if (ike_phase_1_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 *))ike_phase_1_post_exchange_KE_NONCE); + + return 0; +} + +static int +responder_send_ID_AUTH(struct message *msg) +{ + msg->exchange->flags |= EXCHANGE_FLAG_ENCRYPT; + + if (ike_phase_1_responder_send_ID_AUTH(msg)) + return -1; + + return ipsec_initial_contact(msg); +} diff --git a/keyexchange/isakmpd-20041012/ike_main_mode.h b/keyexchange/isakmpd-20041012/ike_main_mode.h new file mode 100644 index 0000000..3e0d173 --- /dev/null +++ b/keyexchange/isakmpd-20041012/ike_main_mode.h @@ -0,0 +1,40 @@ +/* $OpenBSD: ike_main_mode.h,v 1.6 2004/05/23 18:17:56 hshoexer Exp $ */ +/* $EOM: ike_main_mode.h,v 1.1 1998/07/25 11:22:07 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. + * + * 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/keyexchange/isakmpd-20041012/ike_phase_1.c b/keyexchange/isakmpd-20041012/ike_phase_1.c new file mode 100644 index 0000000..7f72a25 --- /dev/null +++ b/keyexchange/isakmpd-20041012/ike_phase_1.c @@ -0,0 +1,1396 @@ +/* $OpenBSD: ike_phase_1.c,v 1.56 2004/08/08 19:11:06 deraadt Exp $ */ +/* $EOM: ike_phase_1.c,v 1.31 2000/12/11 23:47:56 niklas Exp $ */ + +/* + * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved. + * Copyright (c) 1999, 2000 Angelos D. Keromytis. All rights reserved. + * Copyright (c) 2001, 2004 Håkan Olsson. 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. + * + * 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 <arpa/inet.h> +#include <stdlib.h> +#include <string.h> + +#include "sysdep.h" + +#include "attribute.h" +#include "conf.h" +#include "constants.h" +#include "crypto.h" +#include "dh.h" +#include "doi.h" +#ifdef USE_DPD +#include "dpd.h" +#endif +#include "exchange.h" +#include "hash.h" +#include "ike_auth.h" +#include "ike_phase_1.h" +#include "ipsec.h" +#include "ipsec_doi.h" +#include "isakmp.h" +#include "log.h" +#include "math_group.h" +#include "message.h" +#if defined (USE_NAT_TRAVERSAL) +#include "nat_traversal.h" +#endif +#include "prf.h" +#include "sa.h" +#include "transport.h" +#include "util.h" + +static int attribute_unacceptable(u_int16_t, u_int8_t *, u_int16_t, + void *); +static int ike_phase_1_validate_prop(struct exchange *, struct sa *, + struct sa *); + +/* Offer a set of transforms to the responder in the MSG message. */ +int +ike_phase_1_initiator_send_SA(struct message *msg) +{ + struct exchange *exchange = msg->exchange; + struct ipsec_exch *ie = exchange->data; + u_int8_t *proposal = 0, *sa_buf = 0, *saved_nextp, *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 value, update_nextp; + size_t i; + struct payload *p; + struct proto *proto; + struct proto_attr *pa; + int group_desc = -1, new_group_desc; + + /* Get the list of transforms. */ + conf = conf_get_list(exchange->policy, "Transforms"); + if (!conf) + return -1; + + transform = calloc(conf->cnt, sizeof *transform); + if (!transform) { + log_error("ike_phase_1_initiator_send_SA: calloc (%lu, %lu) " + "failed", (u_long)conf->cnt, (u_long) sizeof *transform); + goto bail_out; + } + transform_len = calloc(conf->cnt, sizeof *transform_len); + if (!transform_len) { + log_error("ike_phase_1_initiator_send_SA: calloc (%lu, %lu) " + "failed", (u_long)conf->cnt, + (u_long) sizeof *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]) { + log_error("ike_phase_1_initiator_send_SA: malloc (%d) " + "failed", ISAKMP_TRANSFORM_SA_ATTRS_OFF + + 16 * ISAKMP_ATTR_VALUE_OFF); + 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 Deals with 16 and 32 bit lifetimes + * only + */ + value = conf_get_num(life->field, + "LIFE_DURATION", 0); + if (value) { + if (value <= 0xffff) + attr = attribute_set_basic( + attr, + IKE_ATTR_LIFE_DURATION, + value); + else { + value = htonl(value); + attr = attribute_set_var(attr, + IKE_ATTR_LIFE_DURATION, + (u_int8_t *)&value, + sizeof value); + } + } + } + conf_free_list(life_conf); + } + attribute_set_constant(xf->field, "PRF", ike_prf_cst, + IKE_ATTR_PRF, &attr); + + value = conf_get_num(xf->field, "KEY_LENGTH", 0); + if (value) + attr = attribute_set_basic(attr, IKE_ATTR_KEY_LENGTH, + value); + + value = conf_get_num(xf->field, "FIELD_SIZE", 0); + if (value) + attr = attribute_set_basic(attr, IKE_ATTR_FIELD_SIZE, + value); + + value = conf_get_num(xf->field, "GROUP_ORDER", 0); + 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]; + + /* XXX I don't like exchange-specific stuff in here. */ + if (exchange->type == ISAKMP_EXCH_AGGRESSIVE) { + /* + * Make sure that if a group description is specified, + * it is specified for all transforms equally. + */ + attr = (u_int8_t *) conf_get_str(xf->field, + "GROUP_DESCRIPTION"); + new_group_desc = + attr ? constant_value(ike_group_desc_cst, + (char *) attr) : 0; + if (group_desc == -1) + group_desc = new_group_desc; + else if (group_desc != new_group_desc) { + log_print("ike_phase_1_initiator_send_SA: " + "differing group descriptions in a " + "proposal"); + goto bail_out; + } + } + /* + * We need to check that we actually support our + * configuration. + */ + if (attribute_map(transform[i] + ISAKMP_TRANSFORM_SA_ATTRS_OFF, + transform_len[i] - ISAKMP_TRANSFORM_SA_ATTRS_OFF, + exchange->doi->is_attribute_incompatible, msg)) { + log_print("ike_phase_1_initiator_send_SA: " + "section [%s] has unsupported attribute(s)", + xf->field); + goto bail_out; + } + } + + /* XXX I don't like exchange-specific stuff in here. */ + if (exchange->type == ISAKMP_EXCH_AGGRESSIVE) + ie->group = group_get(group_desc); + + proposal_len = ISAKMP_PROP_SPI_OFF; + proposal = malloc(proposal_len); + if (!proposal) { + log_error("ike_phase_1_initiator_send_SA: malloc (%lu) failed", + (unsigned long) proposal_len); + 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) { + log_error("ike_phase_1_initiator_send_SA: " + "calloc (1, %lu) failed", (unsigned long) sizeof *proto); + goto bail_out; + } + proto->no = 1; + proto->proto = ISAKMP_PROTO_ISAKMP; + proto->sa = TAILQ_FIRST(&exchange->sa_list); + proto->xf_cnt = conf->cnt; + TAILQ_INIT(&proto->xfs); + for (i = 0; i < proto->xf_cnt; i++) { + pa = (struct proto_attr *) calloc(1, sizeof *pa); + if (!pa) + goto bail_out; + pa->len = transform_len[i]; + pa->attrs = (u_int8_t *) malloc(pa->len); + if (!pa->attrs) { + free(pa); + goto bail_out; + } + memcpy(pa->attrs, transform[i], pa->len); + TAILQ_INSERT_TAIL(&proto->xfs, pa, next); + } + TAILQ_INSERT_TAIL(&TAILQ_FIRST(&exchange->sa_list)->protos, proto, + link); + + sa_len = ISAKMP_SA_SIT_OFF + IPSEC_SIT_SIT_LEN; + sa_buf = malloc(sa_len); + if (!sa_buf) { + log_error("ike_phase_1_initiator_send_SA: malloc (%lu) failed", + (unsigned long) sa_len); + 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; + + saved_nextp = msg->nextp; + 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; + } + msg->nextp = saved_nextp; + + /* 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) { + log_error("ike_phase_1_initiator_send_SA: malloc (%lu) failed", + (unsigned long) ie->sa_i_b_len); + goto bail_out; + } + memcpy(ie->sa_i_b, + payload_first(msg, ISAKMP_PAYLOAD_SA)->p + ISAKMP_GEN_SZ, + sa_len - ISAKMP_GEN_SZ); + memcpy(ie->sa_i_b + sa_len - ISAKMP_GEN_SZ, + payload_first(msg, ISAKMP_PAYLOAD_PROPOSAL)->p, proposal_len); + transforms_len = 0; + for (i = 0, p = payload_first(msg, 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]; + } + +#if defined (USE_NAT_TRAVERSAL) + /* Advertise NAT-T capability. */ + if (nat_t_add_vendor_payloads(msg)) + goto bail_out; +#endif + +#if defined (USE_DPD) + /* Advertise DPD capability. */ + if (dpd_add_vendor_payload(msg)) + goto bail_out; +#endif + + conf_free_list(conf); + free(transform); + free(transform_len); + 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); + conf_free_list(conf); + return -1; +} + +/* Figure out what transform the responder chose. */ +int +ike_phase_1_initiator_recv_SA(struct message *msg) +{ + struct exchange *exchange = msg->exchange; + struct sa *sa = TAILQ_FIRST(&exchange->sa_list); + struct ipsec_exch *ie = exchange->data; + struct ipsec_sa *isa = sa->data; + struct payload *sa_p = payload_first(msg, ISAKMP_PAYLOAD_SA); + struct payload *prop = payload_first(msg, ISAKMP_PAYLOAD_PROPOSAL); + struct payload *xf = payload_first(msg, 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("ike_phase_1_initiator_recv_SA: " + "multiple SA, proposal or transform payloads in phase 1"); + /* XXX Is there a better notification type? */ + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); + return -1; + } + /* Check that the chosen transform matches an offer. */ + if (message_negotiate_sa(msg, ike_phase_1_validate_prop) || + !TAILQ_FIRST(&sa->protos)) + return -1; + + ipsec_decode_transform(msg, sa, TAILQ_FIRST(&sa->protos), xf->p); + + /* XXX I don't like exchange-specific stuff in here. */ + if (exchange->type != ISAKMP_EXCH_AGGRESSIVE) + ie->group = group_get(isa->group_desc); + + /* Mark the SA as handled. */ + sa_p->flags |= PL_MARK; + + return 0; +} + +/* Send our public DH value and a nonce to the responder. */ +int +ike_phase_1_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 ike_phase_1_send_KE_NONCE(msg, 16); +} + +/* Accept responder's public DH value and nonce. */ +int +ike_phase_1_initiator_recv_KE_NONCE(struct message *msg) +{ + if (ike_phase_1_recv_KE_NONCE(msg)) + return -1; + + return ike_phase_1_post_exchange_KE_NONCE(msg); +} + +/* + * Accept a set of transforms offered by the initiator and chose one we can + * handle. + */ +int +ike_phase_1_responder_recv_SA(struct message *msg) +{ + struct exchange *exchange = msg->exchange; + struct sa *sa = TAILQ_FIRST(&exchange->sa_list); + struct ipsec_sa *isa = sa->data; + struct payload *sa_p = payload_first(msg, ISAKMP_PAYLOAD_SA); + struct payload *prop = payload_first(msg, 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("ike_phase_1_responder_recv_SA: " + "multiple SA or proposal payloads in phase 1"); + /* XXX Is there a better notification type? */ + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); + return -1; + } + /* Chose a transform from the SA. */ + if (message_negotiate_sa(msg, ike_phase_1_validate_prop) || + !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); + + ie->group = group_get(isa->group_desc); + + /* + * 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, 1, 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 notify peer? */ + log_error("ike_phase_1_responder_recv_SA: malloc (%lu) failed", + (unsigned long) ie->sa_i_b_len); + 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. */ +int +ike_phase_1_responder_send_SA(struct message *msg) +{ + /* Add the SA payload with the transform that was chosen. */ + if (message_add_sa_payload(msg)) + return -1; + +#if defined (USE_NAT_TRAVERSAL) + /* Advertise NAT-T capability. */ + if (nat_t_add_vendor_payloads(msg)) + return -1; +#endif + +#if defined (USE_DPD) + /* Advertise DPD capability. */ + if (dpd_add_vendor_payload(msg)) + return -1; +#endif + return 0; +} + +/* Send our public DH value and a nonce to the peer. */ +int +ike_phase_1_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; + } +#if defined (USE_NAT_TRAVERSAL) + /* If this exchange uses NAT-Traversal, add NAT-D payloads now. */ + if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_CAP_PEER) + if (nat_t_exchange_add_nat_d(msg)) { + /* XXX Log? */ + return -1; + } +#endif + return 0; +} + +/* Receive our peer's public DH value and nonce. */ +int +ike_phase_1_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; + } +#if defined (USE_NAT_TRAVERSAL) + /* MainMode: Check for NAT-D payloads and contents. */ + if (msg->exchange->type == ISAKMP_EXCH_ID_PROT && + msg->exchange->flags & EXCHANGE_FLAG_NAT_T_CAP_PEER) + (void)nat_t_exchange_check_nat_d(msg); +#endif + 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. + */ +int +ike_phase_1_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 notify peer? */ + log_error("ike_phase_1_post_exchange_KE_NONCE: " + "malloc (%lu) failed", (unsigned long) ie->g_x_len); + return -1; + } + if (dh_create_shared(ie->group, ie->g_xy, + exchange->initiator ? ie->g_xr : ie->g_xi)) { + log_print("ike_phase_1_post_exchange_KE_NONCE: " + "dh_create_shared failed"); + return -1; + } + LOG_DBG_BUF((LOG_NEGOTIATION, 80, + "ike_phase_1_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_DBG_BUF((LOG_NEGOTIATION, 80, + "ike_phase_1_post_exchange_KE_NONCE: SKEYID", ie->skeyid, + ie->skeyid_len)); + + /* SKEYID_d. */ + ie->skeyid_d = malloc(ie->skeyid_len); + if (!ie->skeyid_d) { + /* XXX How to notify peer? */ + log_error("ike_phase_1_post_exchange_KE_NONCE: " + "malloc (%lu) failed", (unsigned long) ie->skeyid_len); + 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, (unsigned char *) "\0", 1); + prf->Final(ie->skeyid_d, prf->prfctx); + LOG_DBG_BUF((LOG_NEGOTIATION, 80, + "ike_phase_1_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) { + log_error("ike_phase_1_post_exchange_KE_NONCE: " + "malloc (%lu) failed", (unsigned long) ie->skeyid_len); + 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, (unsigned char *) "\1", 1); + prf->Final(ie->skeyid_a, prf->prfctx); + LOG_DBG_BUF((LOG_NEGOTIATION, 80, + "ike_phase_1_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 How to notify peer? */ + log_error("ike_phase_1_post_exchange_KE_NONCE: " + "malloc (%lu) failed", (unsigned long) ie->skeyid_len); + 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, (unsigned char *) "\2", 1); + prf->Final(ie->skeyid_e, prf->prfctx); + prf_free(prf); + LOG_DBG_BUF((LOG_NEGOTIATION, 80, + "ike_phase_1_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); + + key = malloc(keylen); + if (!key) { + /* XXX - Notify peer. */ + log_error("ike_phase_1_post_exchange_KE_NONCE: " + "malloc (%d) failed", keylen); + return -1; + } + prf->Init(prf->prfctx); + prf->Update(prf->prfctx, (unsigned char *) "\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); + + /* Setup our keystate using the derived encryption key. */ + exchange->keystate = crypto_init(exchange->crypto, key, + exchange->key_length, &err); + + free(key); + } else + /* Setup 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("ike_phase_1_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("ike_phase_1_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; +} + +int +ike_phase_1_responder_send_ID_AUTH(struct message *msg) +{ + if (ike_phase_1_send_ID(msg)) + return -1; + + return ike_phase_1_send_AUTH(msg); +} + +int +ike_phase_1_send_ID(struct message *msg) +{ + struct exchange *exchange = msg->exchange; + u_int8_t *buf; + char header[80]; + ssize_t sz; + struct sockaddr *src; + int initiator = exchange->initiator; + u_int8_t **id; + size_t *id_len; + char *my_id = 0, *data; + u_int8_t id_type; + + /* 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; + + if (exchange->name) + my_id = conf_get_str(exchange->name, "ID"); + + if (!my_id) + my_id = conf_get_str("General", "Default-phase-1-ID"); + + msg->transport->vtbl->get_src(msg->transport, &src); + sz = my_id ? ipsec_id_size(my_id, &id_type) : sockaddr_addrlen(src); + if (sz == -1) + return -1; + + sz += ISAKMP_ID_DATA_OFF; + buf = malloc(sz); + if (!buf) { + log_error("ike_phase_1_send_ID: malloc (%lu) failed", + (unsigned long) sz); + return -1; + } + SET_IPSEC_ID_PROTO(buf + ISAKMP_ID_DOI_DATA_OFF, 0); + SET_IPSEC_ID_PORT(buf + ISAKMP_ID_DOI_DATA_OFF, 0); + if (my_id) { + SET_ISAKMP_ID_TYPE(buf, id_type); + switch (id_type) { + case IPSEC_ID_IPV4_ADDR: + case IPSEC_ID_IPV6_ADDR: + /* Already in network byteorder. */ + memcpy(buf + ISAKMP_ID_DATA_OFF, + sockaddr_addrdata(src), sockaddr_addrlen(src)); + break; + + case IPSEC_ID_IPV4_ADDR_SUBNET: + case IPSEC_ID_IPV6_ADDR_SUBNET: + /* Network */ + data = conf_get_str(my_id, "Network"); + if (!data) { + log_print("ike_phase_1_send_ID: section %s " + "has no \"Network\" tag", my_id); + return -1; + } + if (text2sockaddr(data, NULL, &src)) { + log_error("ike_phase_1_send_ID: " + "text2sockaddr() failed"); + return -1; + } + memcpy(buf + ISAKMP_ID_DATA_OFF, + sockaddr_addrdata(src), sockaddr_addrlen(src)); + free(src); + /* Netmask */ + data = conf_get_str(my_id, "Netmask"); + if (!data) { + log_print("ike_phase_1_send_ID: section %s " + "has no \"Netmask\" tag", my_id); + return -1; + } + if (text2sockaddr(data, NULL, &src)) { + log_error("ike_phase_1_send_ID: " + "text2sockaddr() failed"); + return -1; + } + memcpy(buf + ISAKMP_ID_DATA_OFF + + sockaddr_addrlen(src), sockaddr_addrdata(src), + sockaddr_addrlen(src)); + free(src); + break; + + case IPSEC_ID_FQDN: + case IPSEC_ID_USER_FQDN: + case IPSEC_ID_KEY_ID: + data = conf_get_str(my_id, "Name"); + if (!data) { + log_print("ike_phase_1_send_ID: section %s " + "has no \"Name\" tag", my_id); + return -1; + } + memcpy(buf + ISAKMP_ID_DATA_OFF, data, + sz - ISAKMP_ID_DATA_OFF); + break; + + default: + log_print("ike_phase_1_send_ID: " + "unsupported ID type %d", id_type); + free(buf); + return -1; + } + } else { + switch (src->sa_family) { + case AF_INET: + SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV4_ADDR); + break; + case AF_INET6: + SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV6_ADDR); + break; + } + /* Already in network byteorder. */ + memcpy(buf + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(src), + sockaddr_addrlen(src)); + } + + if (message_add_payload(msg, ISAKMP_PAYLOAD_ID, buf, sz, 1)) { + free(buf); + return -1; + } + *id_len = sz - ISAKMP_GEN_SZ; + *id = malloc(*id_len); + if (!*id) { + log_error("ike_phase_1_send_ID: malloc (%lu) failed", + (unsigned long) *id_len); + return -1; + } + memcpy(*id, buf + ISAKMP_GEN_SZ, *id_len); + snprintf(header, sizeof header, "ike_phase_1_send_ID: %s", + constant_name(ipsec_id_cst, GET_ISAKMP_ID_TYPE(buf))); + LOG_DBG_BUF((LOG_NEGOTIATION, 40, header, buf + ISAKMP_ID_DATA_OFF, + sz - ISAKMP_ID_DATA_OFF)); + return 0; +} + +int +ike_phase_1_send_AUTH(struct message *msg) +{ + struct exchange *exchange = msg->exchange; + struct ipsec_exch *ie = exchange->data; + + if (ie->ike_auth->encode_hash(msg)) { + /* 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. */ +int +ike_phase_1_recv_ID_AUTH(struct message *msg) +{ + if (ike_phase_1_recv_ID(msg)) + return -1; + + return ike_phase_1_recv_AUTH(msg); +} + +/* Receive ID. */ +int +ike_phase_1_recv_ID(struct message *msg) +{ + struct exchange *exchange = msg->exchange; + struct payload *payload; + char header[80], *rs = 0, *rid = 0, *p; + int initiator = exchange->initiator; + u_int8_t **id, id_type; + size_t *id_len; + ssize_t sz; + struct sockaddr *sa; + + payload = payload_first(msg, ISAKMP_PAYLOAD_ID); + + if (exchange->name) + rs = conf_get_str(exchange->name, "Remote-ID"); + + if (rs) { + sz = ipsec_id_size(rs, &id_type); + if (sz == -1) { + log_print("ike_phase_1_recv_ID: could not handle " + "specified Remote-ID [%s]", rs); + return -1; + } + rid = malloc(sz); + if (!rid) { + log_error("ike_phase_1_recv_ID: malloc (%lu) failed", + (unsigned long) sz); + return -1; + } + switch (id_type) { + case IPSEC_ID_IPV4_ADDR: + case IPSEC_ID_IPV6_ADDR: + p = conf_get_str(rs, "Address"); + if (!p) { + log_print("ike_phase_1_recv_ID: failed to get " + "Address in Remote-ID section [%s]", rs); + free(rid); + return -1; + } + if (text2sockaddr(p, 0, &sa) == -1) { + log_print("ike_phase_1_recv_ID: " + "failed to parse address %s", p); + free(rid); + return -1; + } + if ((id_type == IPSEC_ID_IPV4_ADDR && + sa->sa_family != AF_INET) || + (id_type == IPSEC_ID_IPV6_ADDR && + sa->sa_family != AF_INET6)) { + log_print("ike_phase_1_recv_ID: " + "address %s not of expected family", p); + free(rid); + free(sa); + return -1; + } + memcpy(rid, sockaddr_addrdata(sa), + sockaddr_addrlen(sa)); + free(sa); + break; + + case IPSEC_ID_FQDN: + case IPSEC_ID_USER_FQDN: + case IPSEC_ID_KEY_ID: + p = conf_get_str(rs, "Name"); + if (!p) { + log_print("ike_phase_1_recv_ID: failed to " + "get Name in Remote-ID section [%s]", rs); + free(rid); + return -1; + } + memcpy(rid, p, sz); + break; + + default: + log_print("ike_phase_1_recv_ID: " + "unsupported ID type %d", id_type); + free(rid); + return -1; + } + + /* Compare expected/desired and received remote ID */ + if (bcmp(rid, payload->p + ISAKMP_ID_DATA_OFF, sz)) { + log_print("ike_phase_1_recv_ID: " + "received remote ID other than expected %s - %s", p, payload->p); + free(rid); + return -1; + } + free(rid); + } + /* Choose the right fields to fill in */ + id = initiator ? &exchange->id_r : &exchange->id_i; + id_len = initiator ? &exchange->id_r_len : &exchange->id_i_len; + + *id_len = GET_ISAKMP_GEN_LENGTH(payload->p) - ISAKMP_GEN_SZ; + *id = malloc(*id_len); + if (!*id) { + log_error("ike_phase_1_recv_ID: malloc (%lu) failed", + (unsigned long) *id_len); + return -1; + } + memcpy(*id, payload->p + ISAKMP_GEN_SZ, *id_len); + snprintf(header, sizeof header, "ike_phase_1_recv_ID: %s", + constant_name(ipsec_id_cst, GET_ISAKMP_ID_TYPE(payload->p))); + LOG_DBG_BUF((LOG_NEGOTIATION, 40, header, + payload->p + ISAKMP_ID_DATA_OFF, + *id_len + ISAKMP_GEN_SZ - ISAKMP_ID_DATA_OFF)); + payload->flags |= PL_MARK; + return 0; +} + +/* Receive HASH and check that the exchange has been consistent. */ +int +ike_phase_1_recv_AUTH(struct message *msg) +{ + struct exchange *exchange = msg->exchange; + struct ipsec_exch *ie = exchange->data; + 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; + + /* The decoded hash will be in ie->hash_r or ie->hash_i */ + if (ie->ike_auth->decode_hash(msg)) { + message_drop(msg, ISAKMP_NOTIFY_INVALID_ID_INFORMATION, 0, 1, + 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, sizeof header, "ike_phase_1_recv_AUTH: " + "computed HASH_%c", initiator ? 'R' : 'I'); + LOG_DBG_BUF((LOG_NEGOTIATION, 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; + } + + /* Mark message as authenticated. */ + msg->flags |= MSG_AUTHENTICATED; + + return 0; +} + +struct attr_node { + LIST_ENTRY(attr_node) link; + u_int16_t type; +}; + +struct validation_state { + struct conf_list_node *xf; + LIST_HEAD(attr_head, attr_node) attrs; + char *life; +}; + +/* Validate a proposal inside SA according to EXCHANGE's policy. */ +static int +ike_phase_1_validate_prop(struct exchange *exchange, struct sa *sa, + struct sa *isakmp_sa) +{ + struct conf_list *conf, *tags; + struct conf_list_node *xf, *tag; + struct proto *proto; + struct validation_state vs; + struct attr_node *node, *next_node; + + /* Get the list of transforms. */ + conf = conf_get_list(exchange->policy, "Transforms"); + if (!conf) + return 0; + + for (xf = TAILQ_FIRST(&conf->fields); xf; xf = TAILQ_NEXT(xf, link)) { + for (proto = TAILQ_FIRST(&sa->protos); proto; + proto = TAILQ_NEXT(proto, link)) { + /* Mark all attributes in our policy as unseen. */ + LIST_INIT(&vs.attrs); + vs.xf = xf; + vs.life = 0; + if (attribute_map(proto->chosen->p + + ISAKMP_TRANSFORM_SA_ATTRS_OFF, + GET_ISAKMP_GEN_LENGTH(proto->chosen->p) - + ISAKMP_TRANSFORM_SA_ATTRS_OFF, + attribute_unacceptable, &vs)) + goto try_next; + + /* Sweep over unseen tags in this section. */ + tags = conf_get_tag_list(xf->field); + if (tags) { + for (tag = TAILQ_FIRST(&tags->fields); tag; + tag = TAILQ_NEXT(tag, link)) + /* + * XXX Should we care about attributes + * we have, they do not provide? + */ + for (node = LIST_FIRST(&vs.attrs); + node; node = next_node) { + next_node = + LIST_NEXT(node, link); + if (node->type == + constant_value(ike_attr_cst, + tag->field)) { + LIST_REMOVE(node, link); + free(node); + } + } + conf_free_list(tags); + } + /* Are there leftover tags in this section? */ + node = LIST_FIRST(&vs.attrs); + if (node) + goto try_next; + } + + /* All protocols were OK, we succeeded. */ + LOG_DBG((LOG_NEGOTIATION, 20, "ike_phase_1_validate_prop: " + "success")); + conf_free_list(conf); + if (vs.life) + free(vs.life); + return 1; + +try_next: + /* Are there leftover tags in this section? */ + node = LIST_FIRST(&vs.attrs); + while (node) { + LIST_REMOVE(node, link); + free(node); + node = LIST_FIRST(&vs.attrs); + } + if (vs.life) + free(vs.life); + } + + LOG_DBG((LOG_NEGOTIATION, 20, "ike_phase_1_validate_prop: failure")); + conf_free_list(conf); + return 0; +} + +/* + * Look at the attribute of type TYPE, located at VALUE for LEN bytes forward. + * The VVS argument holds a validation state kept across invocations. + * If the attribute is unacceptable to use, return non-zero, otherwise zero. + */ +static int +attribute_unacceptable(u_int16_t type, u_int8_t *value, u_int16_t len, + void *vvs) +{ + struct validation_state *vs = vvs; + struct conf_list *life_conf; + struct conf_list_node *xf = vs->xf, *life; + char *tag = constant_lookup(ike_attr_cst, type); + char *str; + struct constant_map *map; + struct attr_node *node; + int rv; + + if (!tag) { + LOG_DBG((LOG_NEGOTIATION, 60, "attribute_unacceptable: " + "attribute type %d not known", type)); + return 1; + } + switch (type) { + case IKE_ATTR_ENCRYPTION_ALGORITHM: + case IKE_ATTR_HASH_ALGORITHM: + case IKE_ATTR_AUTHENTICATION_METHOD: + case IKE_ATTR_GROUP_DESCRIPTION: + case IKE_ATTR_GROUP_TYPE: + case IKE_ATTR_PRF: + str = conf_get_str(xf->field, tag); + if (!str) { + /* This attribute does not exist in this policy. */ + LOG_DBG((LOG_NEGOTIATION, 70, + "attribute_unacceptable: attr %s does not exist " + "in %s", tag, xf->field)); + return 1; + } + map = constant_link_lookup(ike_attr_cst, type); + if (!map) + return 1; + + if ((constant_value(map, str) == decode_16(value)) || + (!strcmp(str, "ANY"))) { + /* Mark this attribute as seen. */ + node = malloc(sizeof *node); + if (!node) { + log_error("attribute_unacceptable: " + "malloc (%lu) failed", + (unsigned long) sizeof *node); + return 1; + } + node->type = type; + LIST_INSERT_HEAD(&vs->attrs, node, link); + return 0; + } + LOG_DBG((LOG_NEGOTIATION, 70, + "attribute_unacceptable: %s: got %s, expected %s", tag, + constant_name(map, decode_16(value)), str)); + return 1; + + case IKE_ATTR_GROUP_PRIME: + case IKE_ATTR_GROUP_GENERATOR_1: + case IKE_ATTR_GROUP_GENERATOR_2: + case IKE_ATTR_GROUP_CURVE_A: + case IKE_ATTR_GROUP_CURVE_B: + /* XXX Bignums not handled yet. */ + return 1; + + case IKE_ATTR_LIFE_TYPE: + case IKE_ATTR_LIFE_DURATION: + life_conf = conf_get_list(xf->field, "Life"); + if (life_conf && + !strcmp(conf_get_str(xf->field, "Life"), "ANY")) + return 0; + + rv = 1; + if (!life_conf) { + /* Life attributes given, but not in our policy. */ + LOG_DBG((LOG_NEGOTIATION, 70, + "attribute_unacceptable: received unexpected life " + "attribute")); + return 1; + } + /* + * Each lifetime type must match, otherwise we turn the + * proposal down. In order to do this we need to find the + * specific section of our policy's "Life" list and match + * its duration. + */ + switch (type) { + case IKE_ATTR_LIFE_TYPE: + for (life = TAILQ_FIRST(&life_conf->fields); life; + life = TAILQ_NEXT(life, link)) { + str = conf_get_str(life->field, "LIFE_TYPE"); + if (!str) { + LOG_DBG((LOG_NEGOTIATION, 70, + "attribute_unacceptable: " + "section [%s] has no LIFE_TYPE", + life->field)); + continue; + } + + /* + * If this is the type we are looking at, + * to save a pointer this section in vs->life. + */ + if (constant_value(ike_duration_cst, str) == + decode_16(value)) { + vs->life = strdup(life->field); + rv = 0; + goto bail_out; + } + } + LOG_DBG((LOG_NEGOTIATION, 70, "attribute_unacceptable:" + " unrecognized LIFE_TYPE %d", decode_16(value))); + vs->life = 0; + break; + + case IKE_ATTR_LIFE_DURATION: + if (!vs->life) { + LOG_DBG((LOG_NEGOTIATION, 70, + "attribute_unacceptable: " + "LIFE_DURATION without LIFE_TYPE")); + rv = 1; + goto bail_out; + } + str = conf_get_str(vs->life, "LIFE_DURATION"); + if (str) { + if (!strcmp(str, "ANY")) + rv = 0; + else + rv = !conf_match_num(vs->life, + "LIFE_DURATION", + len == 4 ? decode_32(value) : + decode_16(value)); + } else { + LOG_DBG((LOG_NEGOTIATION, 70, + "attribute_unacceptable: section [%s] has " + "no LIFE_DURATION", vs->life)); + rv = 1; + } + + free(vs->life); + vs->life = 0; + break; + } + +bail_out: + conf_free_list(life_conf); + return rv; + + case IKE_ATTR_KEY_LENGTH: + case IKE_ATTR_FIELD_SIZE: + case IKE_ATTR_GROUP_ORDER: + if (conf_match_num(xf->field, tag, decode_16(value))) { + /* Mark this attribute as seen. */ + node = malloc(sizeof *node); + if (!node) { + log_error("attribute_unacceptable: " + "malloc (%lu) failed", + (unsigned long) sizeof *node); + return 1; + } + node->type = type; + LIST_INSERT_HEAD(&vs->attrs, node, link); + return 0; + } + return 1; + } + return 1; +} diff --git a/keyexchange/isakmpd-20041012/ike_phase_1.h b/keyexchange/isakmpd-20041012/ike_phase_1.h new file mode 100644 index 0000000..1252664 --- /dev/null +++ b/keyexchange/isakmpd-20041012/ike_phase_1.h @@ -0,0 +1,53 @@ +/* $OpenBSD: ike_phase_1.h,v 1.4 2004/04/15 18:39:25 deraadt Exp $ */ + +/* + * Copyright (c) 1999 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. + * + * 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_PHASE_1_H_ +#define _IKE_PHASE_1_H_ + +struct message; + +extern int ike_phase_1_initiator_recv_KE_NONCE(struct message *); +extern int ike_phase_1_initiator_recv_SA(struct message *); +extern int ike_phase_1_initiator_send_KE_NONCE(struct message *); +extern int ike_phase_1_initiator_send_SA(struct message *); +extern int ike_phase_1_post_exchange_KE_NONCE(struct message *); +extern int ike_phase_1_recv_AUTH(struct message *); +extern int ike_phase_1_recv_ID(struct message *); +extern int ike_phase_1_recv_ID_AUTH(struct message *); +extern int ike_phase_1_recv_KE_NONCE(struct message *); +extern int ike_phase_1_responder_recv_SA(struct message *); +extern int ike_phase_1_responder_send_SA(struct message *); +extern int ike_phase_1_responder_send_ID_AUTH(struct message *); +extern int ike_phase_1_send_AUTH(struct message *); +extern int ike_phase_1_send_ID(struct message *); +extern int ike_phase_1_send_ID_AUTH(struct message *); +extern int ike_phase_1_send_KE_NONCE(struct message *, size_t); + +#endif /* _IKE_PHASE_1_H_ */ diff --git a/keyexchange/isakmpd-20041012/ike_quick_mode.c b/keyexchange/isakmpd-20041012/ike_quick_mode.c new file mode 100644 index 0000000..75bec87 --- /dev/null +++ b/keyexchange/isakmpd-20041012/ike_quick_mode.c @@ -0,0 +1,1989 @@ +/* $OpenBSD: ike_quick_mode.c,v 1.87 2004/09/17 13:53:08 ho Exp $ */ +/* $EOM: ike_quick_mode.c,v 1.139 2001/01/26 10:43:17 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 1999, 2000, 2001 Angelos D. Keromytis. All rights reserved. + * Copyright (c) 2000, 2001, 2004 Håkan Olsson. 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. + * + * 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> + +#if defined (USE_POLICY) || defined (USE_KEYNOTE) +#include <sys/types.h> +#include <regex.h> +#include <keynote.h> +#endif + +#include "sysdep.h" + +#include "attribute.h" +#include "conf.h" +#include "connection.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 "policy.h" +#include "prf.h" +#include "sa.h" +#include "transport.h" +#include "util.h" +#include "key.h" + +#ifdef USE_X509 +#include "x509.h" +#endif + +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 *); + +#ifdef USE_POLICY +static int check_policy(struct exchange *, struct sa *, struct sa *); +#endif + +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 +}; + +#ifdef USE_POLICY + +/* How many return values will policy handle -- true/false for now */ +#define RETVALUES_NUM 2 + +/* + * Given an exchange and our policy, check whether the SA and IDs are + * acceptable. + */ +static int +check_policy(struct exchange *exchange, struct sa *sa, struct sa *isakmp_sa) +{ + char *return_values[RETVALUES_NUM]; + char **principal = 0; + int i, len, result = 0, nprinc = 0; + int *x509_ids = 0, *keynote_ids = 0; + unsigned char hashbuf[20]; /* Set to the largest digest result */ +#ifdef USE_X509 + struct keynote_deckey dc; + X509_NAME *subject; +#endif + + /* Do we want to use keynote policies? */ + if (ignore_policy || + strncmp("yes", conf_get_str("General", "Use-Keynote"), 3)) + return 1; + + /* Initialize if necessary -- e.g., if pre-shared key auth was used */ + if (isakmp_sa->policy_id < 0) { + if ((isakmp_sa->policy_id = kn_init()) == -1) { + log_print("check_policy: " + "failed to initialize policy session"); + return 0; + } + } + /* Add the callback that will handle attributes. */ + if (kn_add_action(isakmp_sa->policy_id, ".*", (char *)policy_callback, + ENVIRONMENT_FLAG_FUNC | ENVIRONMENT_FLAG_REGEX) == -1) { + log_print("check_policy: " + "kn_add_action (%d, \".*\", %p, FUNC | REGEX) failed", + isakmp_sa->policy_id, policy_callback); + kn_close(isakmp_sa->policy_id); + isakmp_sa->policy_id = -1; + return 0; + } + if (policy_asserts_num) { + keynote_ids = calloc(policy_asserts_num, sizeof *keynote_ids); + if (!keynote_ids) { + log_error("check_policy: calloc (%d, %lu) failed", + policy_asserts_num, + (unsigned long)sizeof *keynote_ids); + return 0; + } + } + /* Add the policy assertions */ + for (i = 0; i < policy_asserts_num; i++) + keynote_ids[i] = kn_add_assertion(isakmp_sa->policy_id, + policy_asserts[i], + strlen(policy_asserts[i]), ASSERT_FLAG_LOCAL); + + /* Initialize -- we'll let the callback do all the work. */ + policy_exchange = exchange; + policy_sa = sa; + policy_isakmp_sa = isakmp_sa; + + /* Set the return values; true/false for now at least. */ + return_values[0] = "false"; /* Order of values in array is + * important. */ + return_values[1] = "true"; + + /* Create a principal (authorizer) for the SA/ID request. */ + switch (isakmp_sa->recv_certtype) { + case ISAKMP_CERTENC_NONE: + /* + * For shared keys, just duplicate the passphrase with the + * appropriate prefix tag. + */ + nprinc = 3; + principal = calloc(nprinc, sizeof *principal); + if (!principal) { + log_error("check_policy: calloc (%d, %lu) failed", + nprinc, (unsigned long)sizeof *principal); + goto policydone; + } + len = strlen(isakmp_sa->recv_key) + sizeof "passphrase:"; + principal[0] = calloc(len, sizeof(char)); + if (!principal[0]) { + log_error("check_policy: calloc (%d, %lu) failed", len, + (unsigned long)sizeof(char)); + goto policydone; + } + /* + * XXX Consider changing the magic hash lengths with + * constants. + */ + strlcpy(principal[0], "passphrase:", len); + memcpy(principal[0] + sizeof "passphrase:" - 1, + isakmp_sa->recv_key, strlen(isakmp_sa->recv_key)); + + len = sizeof "passphrase-md5-hex:" + 2 * 16; + principal[1] = calloc(len, sizeof(char)); + if (!principal[1]) { + log_error("check_policy: calloc (%d, %lu) failed", len, + (unsigned long)sizeof(char)); + goto policydone; + } + strlcpy(principal[1], "passphrase-md5-hex:", len); + MD5(isakmp_sa->recv_key, strlen(isakmp_sa->recv_key), hashbuf); + for (i = 0; i < 16; i++) + snprintf(principal[1] + 2 * i + + sizeof "passphrase-md5-hex:" - 1, 3, "%02x", + hashbuf[i]); + + len = sizeof "passphrase-sha1-hex:" + 2 * 20; + principal[2] = calloc(len, sizeof(char)); + if (!principal[2]) { + log_error("check_policy: calloc (%d, %lu) failed", len, + (unsigned long)sizeof(char)); + goto policydone; + } + strlcpy(principal[2], "passphrase-sha1-hex:", len); + SHA1(isakmp_sa->recv_key, strlen(isakmp_sa->recv_key), + hashbuf); + for (i = 0; i < 20; i++) + snprintf(principal[2] + 2 * i + + sizeof "passphrase-sha1-hex:" - 1, 3, "%02x", + hashbuf[i]); + break; + + case ISAKMP_CERTENC_KEYNOTE: +#ifdef USE_KEYNOTE + nprinc = 1; + + principal = calloc(nprinc, sizeof *principal); + if (!principal) { + log_error("check_policy: calloc (%d, %lu) failed", + nprinc, (unsigned long)sizeof *principal); + goto policydone; + } + /* Dup the keys */ + principal[0] = strdup(isakmp_sa->keynote_key); + if (!principal[0]) { + log_error("check_policy: calloc (%lu, %lu) failed", + (unsigned long)strlen(isakmp_sa->keynote_key), + (unsigned long)sizeof(char)); + goto policydone; + } +#endif + break; + + case ISAKMP_CERTENC_X509_SIG: +#ifdef USE_X509 + principal = calloc(2, sizeof *principal); + if (!principal) { + log_error("check_policy: calloc (2, %lu) failed", + (unsigned long)sizeof *principal); + goto policydone; + } + if (isakmp_sa->recv_keytype == ISAKMP_KEY_RSA) + dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA; + else { + log_error("check_policy: " + "unknown/unsupported public key algorithm %d", + isakmp_sa->recv_keytype); + goto policydone; + } + + dc.dec_key = isakmp_sa->recv_key; + principal[0] = kn_encode_key(&dc, INTERNAL_ENC_PKCS1, + ENCODING_HEX, KEYNOTE_PUBLIC_KEY); + if (keynote_errno == ERROR_MEMORY) { + log_print("check_policy: " + "failed to get memory for public key"); + goto policydone; + } + if (!principal[0]) { + log_print("check_policy: " + "failed to allocate memory for principal"); + goto policydone; + } + len = strlen(principal[0]) + sizeof "rsa-hex:"; + principal[1] = calloc(len, sizeof(char)); + if (!principal[1]) { + log_error("check_policy: calloc (%d, %lu) failed", len, + (unsigned long)sizeof(char)); + goto policydone; + } + snprintf(principal[1], len, "rsa-hex:%s", principal[0]); + free(principal[0]); + principal[0] = principal[1]; + principal[1] = 0; + + /* Generate a "DN:" principal. */ + subject = X509_get_subject_name(isakmp_sa->recv_cert); + if (subject) { + principal[1] = calloc(259, sizeof(char)); + if (!principal[1]) { + log_error("check_policy: " + "calloc (259, %lu) failed", + (unsigned long)sizeof(char)); + goto policydone; + } + strlcpy(principal[1], "DN:", 259); + X509_NAME_oneline(subject, principal[1] + 3, 256); + nprinc = 2; + } else { + nprinc = 1; + } + break; +#endif + + /* XXX Eventually handle these. */ + case ISAKMP_CERTENC_PKCS: + case ISAKMP_CERTENC_PGP: + case ISAKMP_CERTENC_DNS: + case ISAKMP_CERTENC_X509_KE: + case ISAKMP_CERTENC_KERBEROS: + case ISAKMP_CERTENC_CRL: + case ISAKMP_CERTENC_ARL: + case ISAKMP_CERTENC_SPKI: + case ISAKMP_CERTENC_X509_ATTR: + default: + log_print("check_policy: " + "unknown/unsupported certificate/authentication method %d", + isakmp_sa->recv_certtype); + goto policydone; + } + + /* + * Add the authorizer (who is requesting the SA/ID); + * this may be a public or a secret key, depending on + * what mode of authentication we used in Phase 1. + */ + for (i = 0; i < nprinc; i++) { + LOG_DBG((LOG_POLICY, 40, "check_policy: " + "adding authorizer [%s]", principal[i])); + + if (kn_add_authorizer(isakmp_sa->policy_id, principal[i]) + == -1) { + int j; + + for (j = 0; j < i; j++) + kn_remove_authorizer(isakmp_sa->policy_id, + principal[j]); + log_print("check_policy: kn_add_authorizer failed"); + goto policydone; + } + } + + /* Ask policy */ + result = kn_do_query(isakmp_sa->policy_id, return_values, + RETVALUES_NUM); + LOG_DBG((LOG_POLICY, 40, "check_policy: kn_do_query returned %d", + result)); + + /* Cleanup environment */ + kn_cleanup_action_environment(isakmp_sa->policy_id); + + /* Remove authorizers from the session */ + for (i = 0; i < nprinc; i++) { + kn_remove_authorizer(isakmp_sa->policy_id, principal[i]); + free(principal[i]); + } + + free(principal); + principal = 0; + nprinc = 0; + + /* Check what policy said. */ + if (result < 0) { + LOG_DBG((LOG_POLICY, 40, "check_policy: proposal refused")); + result = 0; + goto policydone; + } +policydone: + for (i = 0; i < nprinc; i++) + if (principal && principal[i]) + free(principal[i]); + + if (principal) + free(principal); + + /* Remove the policies */ + for (i = 0; i < policy_asserts_num; i++) { + if (keynote_ids[i] != -1) + kn_remove_assertion(isakmp_sa->policy_id, + keynote_ids[i]); + } + + if (keynote_ids) + free(keynote_ids); + + if (x509_ids) + free(x509_ids); + + /* + * XXX Currently, check_policy() is only called from + * message_negotiate_sa(), and so this log message reflects this. + * Change to something better? + */ + if (result == 0) + log_print("check_policy: negotiated SA failed policy check"); + + /* + * Given that we have only 2 return values from policy (true/false) + * we can just return the query result directly (no pre-processing + * needed). + */ + return result; +} +#endif /* USE_POLICY */ + +/* + * 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; + 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, + *id, *spi; + size_t spi_sz, sz; + 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; + u_int32_t *transform_cnt = 0, *new_transform_cnt; + u_int32_t suite_no, prop_no, prot_no, xf_no, prop_cnt = 0; + u_int32_t i; + int value, update_nextp, protocol_num, proto_id; + struct proto *proto; + struct conf_list *suite_conf, *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; + char *local_id, *remote_id; + int group_desc = -1, new_group_desc; + struct ipsec_sa *isa = msg->isakmp_sa->data; + struct hash *hash = hash_get(isa->hash); + struct sockaddr *src; + struct proto_attr *pa; + + if (!ipsec_add_hash_payload(msg, hash->hashsize)) + return -1; + + /* Get the list of protocol suites. */ + suite_conf = conf_get_list(exchange->policy, "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) { + log_error( + "initiator_send_HASH_SA_NONCE: " + "realloc (%p, %lu) failed", + proposal, + prop_cnt * (unsigned long)sizeof *proposal); + goto bail_out; + } + proposal = new_proposal; + + new_transforms_len = realloc(transforms_len, + prop_cnt * sizeof *transforms_len); + if (!new_transforms_len) { + log_error( + "initiator_send_HASH_SA_NONCE: " + "realloc (%p, %lu) failed", + transforms_len, + prop_cnt * (unsigned long)sizeof *transforms_len); + goto bail_out; + } + transforms_len = new_transforms_len; + + new_transform = realloc(transform, + prop_cnt * sizeof *transform); + if (!new_transform) { + log_error( + "initiator_send_HASH_SA_NONCE: " + "realloc (%p, %lu) failed", + transform, + prop_cnt * (unsigned long)sizeof *transform); + goto bail_out; + } + transform = new_transform; + + new_transform_cnt = realloc(transform_cnt, + prop_cnt * sizeof *transform_cnt); + if (!new_transform_cnt) { + log_error( + "initiator_send_HASH_SA_NONCE: " + "realloc (%p, %lu) failed", + transform_cnt, + prop_cnt * (unsigned long)sizeof *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) { + log_error( + "initiator_send_HASH_SA_NONCE: " + "realloc (%p, %lu) failed", + transform_len, + prop_cnt * (unsigned long)sizeof *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; + + proto_id = constant_value(ipsec_proto_cst, + protocol_id); + switch (proto_id) { + case IPSEC_PROTO_IPSEC_AH: + id_map = ipsec_ah_cst; + break; + + case IPSEC_PROTO_IPSEC_ESP: + id_map = ipsec_esp_cst; + break; + + case IPSEC_PROTO_IPCOMP: + id_map = ipsec_ipcomp_cst; + break; + + default: + { + log_print("initiator_send_HASH_SA_NONCE: " + "invalid PROTCOL_ID: %s", protocol_id); + 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]) { + log_error("initiator_send_HASH_SA_NONCE: " + "calloc (%d, %lu) failed", + transform_cnt[prop_no], + (unsigned long)sizeof **transform); + goto bail_out; + } + transform_len[prop_no] = calloc(transform_cnt[prop_no], + sizeof **transform_len); + if (!transform_len[prop_no]) { + log_error("initiator_send_HASH_SA_NONCE: " + "calloc (%d, %lu) failed", + transform_cnt[prop_no], + (unsigned long)sizeof **transform_len); + 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]) { + log_error( + "initiator_send_HASH_SA_NONCE: " + "calloc (%d, 1) failed", + ISAKMP_TRANSFORM_SA_ATTRS_OFF + + 9 * ISAKMP_ATTR_VALUE_OFF); + 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, "LIFE_TYPE", + ipsec_duration_cst, + IPSEC_ATTR_SA_LIFE_TYPE, + &attr); + + /* + * XXX Deals with 16 and 32 + * bit lifetimes only + */ + value = + conf_get_num(life->field, + "LIFE_DURATION", 0); + if (value) { + if (value <= 0xffff) + attr = + attribute_set_basic( + attr, + IPSEC_ATTR_SA_LIFE_DURATION, + value); + else { + value = htonl(value); + attr = + attribute_set_var( + attr, + IPSEC_ATTR_SA_LIFE_DURATION, + (u_int8_t *)&value, + sizeof value); + } + } + } + conf_free_list(life_conf); + } + attribute_set_constant(xf->field, + "ENCAPSULATION_MODE", ipsec_encap_cst, + IPSEC_ATTR_ENCAPSULATION_MODE, &attr); + + if (proto_id != IPSEC_PROTO_IPCOMP) { + 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, + IPSEC_ATTR_GROUP_DESCRIPTION, &attr); + + value = conf_get_num(xf->field, + "KEY_LENGTH", 0); + if (value) + attr = attribute_set_basic( + attr, + IPSEC_ATTR_KEY_LENGTH, + value); + + value = conf_get_num(xf->field, + "KEY_ROUNDS", 0); + if (value) + attr = attribute_set_basic( + attr, + IPSEC_ATTR_KEY_ROUNDS, + value); + } else { + value = conf_get_num(xf->field, + "COMPRESS_DICTIONARY_SIZE", 0); + if (value) + attr = attribute_set_basic( + attr, + IPSEC_ATTR_COMPRESS_DICTIONARY_SIZE, + value); + + value = conf_get_num(xf->field, + "COMPRESS_PRIVATE_ALGORITHM", 0); + if (value) + attr = attribute_set_basic( + attr, + IPSEC_ATTR_COMPRESS_PRIVATE_ALGORITHM, + value); + } + + value = conf_get_num(xf->field, "ECN_TUNNEL", + 0); + if (value) + attr = attribute_set_basic(attr, + IPSEC_ATTR_ECN_TUNNEL, value); + + /* Record the real transform size. */ + transforms_len[prop_no] += + (transform_len[prop_no][xf_no] + = attr - transform[prop_no][xf_no]); + + if (proto_id != IPSEC_PROTO_IPCOMP) { + /* + * Make sure that if a group + * description is specified, it is + * specified for all transforms + * equally. + */ + attr = + (u_int8_t *)conf_get_str(xf->field, + "GROUP_DESCRIPTION"); + new_group_desc + = attr ? constant_value(ike_group_desc_cst, + (char *)attr) : 0; + if (group_desc == -1) + group_desc = new_group_desc; + else if (group_desc != new_group_desc) { + log_print("initiator_send_HASH_SA_NONCE: " + "differing group descriptions in a proposal"); + goto bail_out; + } + } + } + conf_free_list(xf_conf); + xf_conf = 0; + + /* + * 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) { + log_print("initiator_send_HASH_SA_NONCE: " + "doi->get_spi failed"); + 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]) { + log_error("initiator_send_HASH_SA_NONCE: " + "malloc (%lu) failed", + (unsigned long)proposal_len); + 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) { + log_error("initiator_send_HASH_SA_NONCE: " + "calloc (1, %lu) failed", + (unsigned long)sizeof *proto); + goto bail_out; + } + if (doi->proto_size) { + proto->data = calloc(1, doi->proto_size); + if (!proto->data) { + log_error( + "initiator_send_HASH_SA_NONCE: " + "calloc (1, %lu) failed", + (unsigned long)doi->proto_size); + goto bail_out; + } + } + proto->no = suite_no + 1; + proto->proto = protocol_num; + proto->sa = TAILQ_FIRST(&exchange->sa_list); + proto->xf_cnt = transform_cnt[prop_no]; + TAILQ_INIT(&proto->xfs); + for (xf_no = 0; xf_no < proto->xf_cnt; xf_no++) { + pa = (struct proto_attr *)calloc(1, + sizeof *pa); + if (!pa) + goto bail_out; + pa->len = transform_len[prop_no][xf_no]; + pa->attrs = (u_int8_t *)malloc(pa->len); + if (!pa->attrs) { + free(pa); + goto bail_out; + } + memcpy(pa->attrs, transform[prop_no][xf_no], + pa->len); + TAILQ_INSERT_TAIL(&proto->xfs, pa, next); + } + TAILQ_INSERT_TAIL(&TAILQ_FIRST(&exchange->sa_list)->protos, + proto, link); + + /* Setup the incoming SPI. */ + SET_ISAKMP_PROP_SPI_SZ(proposal[prop_no], spi_sz); + memcpy(proposal[prop_no] + ISAKMP_PROP_SPI_OFF, spi, + spi_sz); + proto->spi_sz[1] = spi_sz; + proto->spi[1] = spi; + + /* + * Let the DOI get at proto for initializing its own + * data. + */ + if (doi->proto_init) + doi->proto_init(proto, prot->field); + + SET_ISAKMP_PROP_NTRANSFORMS(proposal[prop_no], + transform_cnt[prop_no]); + prop_no++; + } + conf_free_list(prot_conf); + prot_conf = 0; + } + + sa_len = ISAKMP_SA_SIT_OFF + IPSEC_SIT_SIT_LEN; + sa_buf = malloc(sa_len); + if (!sa_buf) { + log_error("initiator_send_HASH_SA_NONCE: malloc (%lu) failed", + (unsigned long)sa_len); + 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)) + return -1; + + /* Generate optional KEY_EXCH payload. */ + if (group_desc > 0) { + ie->group = group_get(group_desc); + ie->g_x_len = dh_getlen(ie->group); + + if (ipsec_gen_g_x(msg)) { + group_free(ie->group); + ie->group = 0; + return -1; + } + } + /* Generate optional client ID payloads. XXX Share with responder. */ + local_id = conf_get_str(exchange->name, "Local-ID"); + remote_id = conf_get_str(exchange->name, "Remote-ID"); + if (local_id && remote_id) { + id = ipsec_build_id(local_id, &sz); + if (!id) + return -1; + LOG_DBG_BUF((LOG_NEGOTIATION, 90, + "initiator_send_HASH_SA_NONCE: IDic", id, sz)); + if (message_add_payload(msg, ISAKMP_PAYLOAD_ID, id, sz, 1)) { + free(id); + return -1; + } + id = ipsec_build_id(remote_id, &sz); + if (!id) + return -1; + LOG_DBG_BUF((LOG_NEGOTIATION, 90, + "initiator_send_HASH_SA_NONCE: IDrc", id, sz)); + if (message_add_payload(msg, ISAKMP_PAYLOAD_ID, id, sz, 1)) { + free(id); + return -1; + } + } + /* XXX I do not judge these as errors, are they? */ + else if (local_id) + log_print("initiator_send_HASH_SA_NONCE: " + "Local-ID given without Remote-ID for \"%s\"", + exchange->name); + else if (remote_id) + /* + * This code supports the "road warrior" case, where the + * initiator doesn't have a fixed IP address, but wants to + * specify a particular remote network to talk to. -- Adrian + * Close <adrian@esec.com.au> + */ + { + log_print("initiator_send_HASH_SA_NONCE: " + "Remote-ID given without Local-ID for \"%s\"", + exchange->name); + + /* + * If we're here, then we are the initiator, so use initiator + * address for local ID + */ + msg->transport->vtbl->get_src(msg->transport, &src); + sz = ISAKMP_ID_SZ + sockaddr_addrlen(src); + + id = calloc(sz, sizeof(char)); + if (!id) { + log_error("initiator_send_HASH_SA_NONCE: " + "calloc (%lu, %lu) failed", (unsigned long)sz, + (unsigned long)sizeof(char)); + return -1; + } + switch (src->sa_family) { + case AF_INET6: + SET_ISAKMP_ID_TYPE(id, IPSEC_ID_IPV6_ADDR); + break; + case AF_INET: + SET_ISAKMP_ID_TYPE(id, IPSEC_ID_IPV4_ADDR); + break; + default: + log_error("initiator_send_HASH_SA_NONCE: " + "unknown sa_family %d", src->sa_family); + free(id); + return -1; + } + memcpy(id + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(src), + sockaddr_addrlen(src)); + + LOG_DBG_BUF((LOG_NEGOTIATION, 90, + "initiator_send_HASH_SA_NONCE: IDic", id, sz)); + if (message_add_payload(msg, ISAKMP_PAYLOAD_ID, id, sz, 1)) { + free(id); + return -1; + } + /* Send supplied remote_id */ + id = ipsec_build_id(remote_id, &sz); + if (!id) + return -1; + LOG_DBG_BUF((LOG_NEGOTIATION, 90, + "initiator_send_HASH_SA_NONCE: IDrc", id, sz)); + if (message_add_payload(msg, ISAKMP_PAYLOAD_ID, id, sz, 1)) { + free(id); + return -1; + } + } + if (ipsec_fill_in_hash(msg)) + goto bail_out; + + conf_free_list(suite_conf); + for (i = 0; i < prop_no; i++) { + free(transform[i]); + free(transform_len[i]); + } + free(proposal); + free(transform); + free(transforms_len); + free(transform_len); + free(transform_cnt); + 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 < transform_cnt[i]; + 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); + 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, *next_proto; + struct payload *sa_p = payload_first(msg, ISAKMP_PAYLOAD_SA); + struct payload *xf, *idp; + struct payload *hashp = payload_first(msg, ISAKMP_PAYLOAD_HASH); + struct payload *kep = payload_first(msg, 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; + struct sockaddr *src, *dst; + + /* Allocate the prf and start calculating our HASH(1). XXX Share? */ + LOG_DBG_BUF((LOG_NEGOTIATION, 90, "initiator_recv_HASH_SA_NONCE: " + "SKEYID_a", (u_int8_t *)isa->skeyid_a, isa->skeyid_len)); + prf = prf_alloc(isa->prf_type, hash->type, isa->skeyid_a, + isa->skeyid_len); + if (!prf) + return -1; + + prf->Init(prf->prfctx); + LOG_DBG_BUF((LOG_NEGOTIATION, 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_DBG_BUF((LOG_NEGOTIATION, 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_DBG_BUF((LOG_NEGOTIATION, 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_DBG_BUF((LOG_NEGOTIATION, 80, + "initiator_recv_HASH_SA_NONCE: computed HASH(2)", hash->digest, + hashsize)); + if (memcmp(hashp->p + ISAKMP_HASH_DATA_OFF, hash->digest, hashsize) + != 0) { + message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, 0, 1, + 0); + return -1; + } + /* Mark the HASH as handled. */ + hashp->flags |= PL_MARK; + + /* Mark message as authenticated. */ + msg->flags |= MSG_AUTHENTICATED; + + /* + * 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 not supported yet"); + return -1; + } + sa = TAILQ_FIRST(&exchange->sa_list); + + /* This is here for the policy check */ + if (kep) + ie->pfs = 1; + + /* Handle optional client ID payloads. */ + idp = payload_first(msg, ISAKMP_PAYLOAD_ID); + if (idp) { + /* If IDci is there, IDcr must be too. */ + if (!TAILQ_NEXT(idp, link)) { + /* XXX Is this a good notify type? */ + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, + 1, 0); + return -1; + } + /* XXX We should really compare, not override. */ + ie->id_ci_sz = GET_ISAKMP_GEN_LENGTH(idp->p); + ie->id_ci = malloc(ie->id_ci_sz); + if (!ie->id_ci) { + log_error("initiator_recv_HASH_SA_NONCE: " + "malloc (%lu) failed", + (unsigned long)ie->id_ci_sz); + return -1; + } + memcpy(ie->id_ci, idp->p, ie->id_ci_sz); + idp->flags |= PL_MARK; + LOG_DBG_BUF((LOG_NEGOTIATION, 90, + "initiator_recv_HASH_SA_NONCE: IDci", + ie->id_ci + ISAKMP_GEN_SZ, ie->id_ci_sz - ISAKMP_GEN_SZ)); + + idp = TAILQ_NEXT(idp, link); + ie->id_cr_sz = GET_ISAKMP_GEN_LENGTH(idp->p); + ie->id_cr = malloc(ie->id_cr_sz); + if (!ie->id_cr) { + log_error("initiator_recv_HASH_SA_NONCE: " + "malloc (%lu) failed", + (unsigned long)ie->id_cr_sz); + return -1; + } + memcpy(ie->id_cr, idp->p, ie->id_cr_sz); + idp->flags |= PL_MARK; + LOG_DBG_BUF((LOG_NEGOTIATION, 90, + "initiator_recv_HASH_SA_NONCE: IDcr", + ie->id_cr + ISAKMP_GEN_SZ, ie->id_cr_sz - ISAKMP_GEN_SZ)); + } else { + /* + * If client identifiers are not present in the exchange, + * we fake them. RFC 2409 states: + * The identities of the SAs negotiated in Quick Mode are + * implicitly assumed to be the IP addresses of the ISAKMP + * peers, without any constraints on the protocol or port + * numbers allowed, unless client identifiers are specified + * in Quick Mode. + * + * -- Michael Paddon (mwp@aba.net.au) + */ + + ie->flags = IPSEC_EXCH_FLAG_NO_ID; + + /* Get initiator and responder addresses. */ + msg->transport->vtbl->get_src(msg->transport, &src); + msg->transport->vtbl->get_dst(msg->transport, &dst); + ie->id_ci_sz = ISAKMP_ID_DATA_OFF + sockaddr_addrlen(src); + ie->id_cr_sz = ISAKMP_ID_DATA_OFF + sockaddr_addrlen(dst); + ie->id_ci = calloc(ie->id_ci_sz, sizeof(char)); + ie->id_cr = calloc(ie->id_cr_sz, sizeof(char)); + + if (!ie->id_ci || !ie->id_cr) { + log_error("initiator_recv_HASH_SA_NONCE: " + "calloc (%lu, %lu) failed", + (unsigned long)ie->id_cr_sz, + (unsigned long)sizeof(char)); + if (ie->id_ci) { + free(ie->id_ci); + ie->id_ci = 0; + } + if (ie->id_cr) { + free(ie->id_cr); + ie->id_cr = 0; + } + return -1; + } + if (src->sa_family != dst->sa_family) { + log_error("initiator_recv_HASH_SA_NONCE: " + "sa_family mismatch"); + free(ie->id_ci); + ie->id_ci = 0; + free(ie->id_cr); + ie->id_cr = 0; + return -1; + } + switch (src->sa_family) { + case AF_INET: + SET_ISAKMP_ID_TYPE(ie->id_ci, IPSEC_ID_IPV4_ADDR); + SET_ISAKMP_ID_TYPE(ie->id_cr, IPSEC_ID_IPV4_ADDR); + break; + + case AF_INET6: + SET_ISAKMP_ID_TYPE(ie->id_ci, IPSEC_ID_IPV6_ADDR); + SET_ISAKMP_ID_TYPE(ie->id_cr, IPSEC_ID_IPV6_ADDR); + break; + + default: + log_error("initiator_recv_HASH_SA_NONCE: " + "unknown sa_family %d", src->sa_family); + free(ie->id_ci); + ie->id_ci = 0; + free(ie->id_cr); + ie->id_cr = 0; + return -1; + } + memcpy(ie->id_ci + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(src), + sockaddr_addrlen(src)); + memcpy(ie->id_cr + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(dst), + sockaddr_addrlen(dst)); + } + + /* Build the protection suite in our SA. */ + for (xf = payload_first(msg, 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)) + 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 = next_proto) { + next_proto = TAILQ_NEXT(proto, link); + if (!proto->chosen) + proto_free(proto); + } + +#ifdef USE_POLICY + if (!check_policy(exchange, sa, msg->isakmp_sa)) { + message_drop(msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0); + log_print("initiator_recv_HASH_SA_NONCE: policy check failed"); + return -1; + } +#endif + + /* Mark the SA as handled. */ + sa_p->flags |= PL_MARK; + + isa = sa->data; + if ((isa->group_desc && + (!ie->group || ie->group->id != isa->group_desc)) || + (!isa->group_desc && ie->group)) { + log_print("initiator_recv_HASH_SA_NONCE: disagreement on PFS"); + return -1; + } + /* Copy out the initiator's nonce. */ + if (exchange_save_nonce(msg)) + return -1; + + /* Handle the optional KEY_EXCH payload. */ + if (kep && ipsec_save_g_x(msg)) + return -1; + + 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) { + log_error("initiator_send_HASH: malloc (%lu) failed", + ISAKMP_HASH_SZ + (unsigned long)hashsize); + return -1; + } + if (message_add_payload(msg, ISAKMP_PAYLOAD_HASH, buf, + ISAKMP_HASH_SZ + hashsize, 1)) { + free(buf); + return -1; + } + /* Allocate the prf and start calculating our HASH(3). XXX Share? */ + LOG_DBG_BUF((LOG_NEGOTIATION, 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) + return -1; + prf->Init(prf->prfctx); + prf->Update(prf->prfctx, (unsigned char *)"\0", 1); + LOG_DBG_BUF((LOG_NEGOTIATION, 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_DBG_BUF((LOG_NEGOTIATION, 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_DBG_BUF((LOG_NEGOTIATION, 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_DBG_BUF((LOG_NEGOTIATION, 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; + 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)) { + if (proto->proto == IPSEC_PROTO_IPCOMP) + continue; + + 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]) { + log_error("post_quick_mode: " + "malloc (%lu) failed", + (((unsigned long)ie->keymat_len + + prf->blocksize - 1) / prf->blocksize) * + prf->blocksize); + /* XXX What more 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_DBG_BUF((LOG_NEGOTIATION, + 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_DBG_BUF((LOG_NEGOTIATION, + 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_DBG((LOG_NEGOTIATION, 90, + "post_quick_mode: " + "suite %d proto %d", proto->no, + proto->proto)); + prf->Update(prf->prfctx, &proto->proto, + 1); + LOG_DBG_BUF((LOG_NEGOTIATION, 90, + "post_quick_mode: SPI", + proto->spi[i], proto->spi_sz[i])); + prf->Update(prf->prfctx, + proto->spi[i], proto->spi_sz[i]); + LOG_DBG_BUF((LOG_NEGOTIATION, 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_DBG_BUF((LOG_NEGOTIATION, 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_DBG_BUF((LOG_NEGOTIATION, 90, + "post_quick_mode: KEYMAT", + iproto->keymat[i], ie->keymat_len)); + } + } + } + + log_verbose("isakmpd: quick mode done: %s", + !msg->isakmp_sa || !msg->isakmp_sa->transport ? "<no transport>" + : msg->isakmp_sa->transport->vtbl->decode_ids + (msg->isakmp_sa->transport)); +} + +/* + * 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, *idp; + 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 = 0; + 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; + struct sockaddr *src, *dst; + char *name; + + hashp = payload_first(msg, 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, 1, 0); + goto cleanup; + } + hash_len = GET_ISAKMP_GEN_LENGTH(hash); + my_hash = malloc(hash_len - ISAKMP_GEN_SZ); + if (!my_hash) { + log_error("responder_recv_HASH_SA_NONCE: malloc (%lu) failed", + (unsigned long)hash_len - ISAKMP_GEN_SZ); + goto cleanup; + } + /* + * Check the payload's integrity. + * XXX Share with ipsec_fill_in_hash? + */ + LOG_DBG_BUF((LOG_NEGOTIATION, 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) + goto cleanup; + prf->Init(prf->prfctx); + LOG_DBG_BUF((LOG_NEGOTIATION, 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_DBG_BUF((LOG_NEGOTIATION, 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_DBG_BUF((LOG_NEGOTIATION, 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) { + message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, 0, + 1, 0); + goto cleanup; + } + free(my_hash); + my_hash = 0; + + /* Mark message as authenticated. */ + msg->flags |= MSG_AUTHENTICATED; + + kep = payload_first(msg, ISAKMP_PAYLOAD_KEY_EXCH); + if (kep) + ie->pfs = 1; + + /* Handle optional client ID payloads. */ + idp = payload_first(msg, ISAKMP_PAYLOAD_ID); + if (idp) { + /* If IDci is there, IDcr must be too. */ + if (!TAILQ_NEXT(idp, link)) { + /* XXX Is this a good notify type? */ + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, + 1, 0); + goto cleanup; + } + ie->id_ci_sz = GET_ISAKMP_GEN_LENGTH(idp->p); + ie->id_ci = malloc(ie->id_ci_sz); + if (!ie->id_ci) { + log_error("responder_recv_HASH_SA_NONCE: " + "malloc (%lu) failed", + (unsigned long)ie->id_ci_sz); + goto cleanup; + } + memcpy(ie->id_ci, idp->p, ie->id_ci_sz); + idp->flags |= PL_MARK; + LOG_DBG_BUF((LOG_NEGOTIATION, 90, + "responder_recv_HASH_SA_NONCE: IDci", + ie->id_ci + ISAKMP_GEN_SZ, ie->id_ci_sz - ISAKMP_GEN_SZ)); + + idp = TAILQ_NEXT(idp, link); + ie->id_cr_sz = GET_ISAKMP_GEN_LENGTH(idp->p); + ie->id_cr = malloc(ie->id_cr_sz); + if (!ie->id_cr) { + log_error("responder_recv_HASH_SA_NONCE: " + "malloc (%lu) failed", + (unsigned long)ie->id_cr_sz); + goto cleanup; + } + memcpy(ie->id_cr, idp->p, ie->id_cr_sz); + idp->flags |= PL_MARK; + LOG_DBG_BUF((LOG_NEGOTIATION, 90, + "responder_recv_HASH_SA_NONCE: IDcr", + ie->id_cr + ISAKMP_GEN_SZ, ie->id_cr_sz - ISAKMP_GEN_SZ)); + } else { + /* + * If client identifiers are not present in the exchange, + * we fake them. RFC 2409 states: + * The identities of the SAs negotiated in Quick Mode are + * implicitly assumed to be the IP addresses of the ISAKMP + * peers, without any constraints on the protocol or port + * numbers allowed, unless client identifiers are specified + * in Quick Mode. + * + * -- Michael Paddon (mwp@aba.net.au) + */ + + ie->flags = IPSEC_EXCH_FLAG_NO_ID; + + /* Get initiator and responder addresses. */ + msg->transport->vtbl->get_src(msg->transport, &src); + msg->transport->vtbl->get_dst(msg->transport, &dst); + ie->id_ci_sz = ISAKMP_ID_DATA_OFF + sockaddr_addrlen(src); + ie->id_cr_sz = ISAKMP_ID_DATA_OFF + sockaddr_addrlen(dst); + ie->id_ci = calloc(ie->id_ci_sz, sizeof(char)); + ie->id_cr = calloc(ie->id_cr_sz, sizeof(char)); + + if (!ie->id_ci || !ie->id_cr) { + log_error("responder_recv_HASH_SA_NONCE: " + "calloc (%lu, %lu) failed", + (unsigned long)ie->id_ci_sz, + (unsigned long)sizeof(char)); + goto cleanup; + } + if (src->sa_family != dst->sa_family) { + log_error("initiator_recv_HASH_SA_NONCE: " + "sa_family mismatch"); + goto cleanup; + } + switch (src->sa_family) { + case AF_INET: + SET_ISAKMP_ID_TYPE(ie->id_ci, IPSEC_ID_IPV4_ADDR); + SET_ISAKMP_ID_TYPE(ie->id_cr, IPSEC_ID_IPV4_ADDR); + break; + + case AF_INET6: + SET_ISAKMP_ID_TYPE(ie->id_ci, IPSEC_ID_IPV6_ADDR); + SET_ISAKMP_ID_TYPE(ie->id_cr, IPSEC_ID_IPV6_ADDR); + break; + + default: + log_error("initiator_recv_HASH_SA_NONCE: " + "unknown sa_family %d", src->sa_family); + goto cleanup; + } + + memcpy(ie->id_cr + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(src), + sockaddr_addrlen(src)); + memcpy(ie->id_ci + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(dst), + sockaddr_addrlen(dst)); + } + +#ifdef USE_POLICY +#ifdef USE_KEYNOTE + if (message_negotiate_sa(msg, check_policy)) + goto cleanup; +#else + if (message_negotiate_sa(msg, 0)) + goto cleanup; +#endif +#else + if (message_negotiate_sa(msg, 0)) + goto cleanup; +#endif /* USE_POLICY */ + + 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); + if (proto->proto == IPSEC_PROTO_IPSEC_AH + && !((struct ipsec_proto *)proto->data)->auth) { + log_print("responder_recv_HASH_SA_NONCE: " + "AH proposed without an algorithm " + "attribute"); + message_drop(msg, + ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0); + goto next_sa; + } + } + + isa = sa->data; + + /* + * The group description is mandatory if we got a KEY_EXCH + * payload. + */ + if (kep) { + if (!isa->group_desc) { + log_print("responder_recv_HASH_SA_NONCE: " + "KEY_EXCH payload without a group " + "desc. attribute"); + message_drop(msg, + ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0); + continue; + } + /* Also, all SAs must have equal groups. */ + if (!group_desc) + group_desc = isa->group_desc; + else if (group_desc != isa->group_desc) { + log_print("responder_recv_HASH_SA_NONCE: " + "differing group descriptions in one QM"); + message_drop(msg, + ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0); + continue; + } + } + /* At least one SA was accepted. */ + retval = 0; + +next_sa: + ; /* XXX gcc3 wants this. */ + } + + if (kep) { + ie->group = group_get(group_desc); + if (!ie->group) { + /* + * XXX If the error was due to an out-of-range group + * description we should notify our peer, but this + * should probably be done by the attribute + * validation. Is it? + */ + goto cleanup; + } + } + /* Copy out the initiator's nonce. */ + if (exchange_save_nonce(msg)) + goto cleanup; + + /* Handle the optional KEY_EXCH payload. */ + if (kep && ipsec_save_g_x(msg)) + goto cleanup; + + /* + * Try to find and set the connection name on the exchange. + */ + + /* + * Check for accepted identities as well as lookup the connection + * name and set it on the exchange. + * + * When not using policies make sure the peer proposes sane IDs. + * Otherwise this is done by KeyNote. + */ + name = connection_passive_lookup_by_ids(ie->id_ci, ie->id_cr); + if (name) { + exchange->name = strdup(name); + if (!exchange->name) { + log_error("responder_recv_HASH_SA_NONCE: " + "strdup (\"%s\") failed", name); + goto cleanup; + } + } else if ( +#ifdef USE_X509 + ignore_policy || +#endif + strncmp("yes", conf_get_str("General", "Use-Keynote"), 3)) { + log_print("responder_recv_HASH_SA_NONCE: peer proposed " + "invalid phase 2 IDs: %s", + (exchange->doi->decode_ids("initiator id %s, responder" + " id %s", ie->id_ci, ie->id_ci_sz, ie->id_cr, + ie->id_cr_sz, 1))); + message_drop(msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0); + goto cleanup; + } + + return retval; + +cleanup: + /* Remove all potential protocols that have been added to the SAs. */ + for (sa = TAILQ_FIRST(&exchange->sa_list); sa; + sa = TAILQ_NEXT(sa, next)) + while ((proto = TAILQ_FIRST(&sa->protos)) != 0) + proto_free(proto); + if (my_hash) + free(my_hash); + if (ie->id_ci) { + free(ie->id_ci); + ie->id_ci = 0; + } + if (ie->id_cr) { + free(ie->id_cr); + ie->id_cr = 0; + } + return -1; +} + +/* 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]; + u_int32_t i; + u_int8_t *id; + size_t sz; + + /* + * We want a HASH payload to start with. XXX Share with + * ike_main_mode.c? + */ + buf = malloc(ISAKMP_HASH_SZ + hashsize); + if (!buf) { + log_error("responder_send_HASH_SA_NONCE: malloc (%lu) failed", + ISAKMP_HASH_SZ + (unsigned long)hashsize); + return -1; + } + if (message_add_payload(msg, ISAKMP_PAYLOAD_HASH, buf, + ISAKMP_HASH_SZ + hashsize, 1)) { + free(buf); + return -1; + } + /* Add the SA payload(s) with the transform(s) that was/were chosen. */ + if (message_add_sa_payload(msg)) + return -1; + + /* Generate a nonce, and add it to the message. */ + if (exchange_gen_nonce(msg, nonce_sz)) + return -1; + + /* Generate optional KEY_EXCH payload. This is known as PFS. */ + if (ie->group && ipsec_gen_g_x(msg)) + return -1; + + /* + * If the initiator client ID's were acceptable, just mirror them + * back. + */ + if (!(ie->flags & IPSEC_EXCH_FLAG_NO_ID)) { + sz = ie->id_ci_sz; + id = malloc(sz); + if (!id) { + log_error("responder_send_HASH_SA_NONCE: " + "malloc (%lu) failed", (unsigned long)sz); + return -1; + } + memcpy(id, ie->id_ci, sz); + LOG_DBG_BUF((LOG_NEGOTIATION, 90, + "responder_send_HASH_SA_NONCE: IDic", id, sz)); + if (message_add_payload(msg, ISAKMP_PAYLOAD_ID, id, sz, 1)) { + free(id); + return -1; + } + sz = ie->id_cr_sz; + id = malloc(sz); + if (!id) { + log_error("responder_send_HASH_SA_NONCE: " + "malloc (%lu) failed", (unsigned long)sz); + return -1; + } + memcpy(id, ie->id_cr, sz); + LOG_DBG_BUF((LOG_NEGOTIATION, 90, + "responder_send_HASH_SA_NONCE: IDrc", id, sz)); + if (message_add_payload(msg, ISAKMP_PAYLOAD_ID, id, sz, 1)) { + free(id); + return -1; + } + } + /* Allocate the prf and start calculating our HASH(2). XXX Share? */ + LOG_DBG((LOG_NEGOTIATION, 90, "responder_recv_HASH: " + "isakmp_sa %p isa %p", isakmp_sa, isa)); + LOG_DBG_BUF((LOG_NEGOTIATION, 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) + return -1; + prf->Init(prf->prfctx); + LOG_DBG_BUF((LOG_NEGOTIATION, 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_DBG_BUF((LOG_NEGOTIATION, 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, sizeof header, + "responder_send_HASH_SA_NONCE: payload %d after HASH(2)", + i - 1); + LOG_DBG_BUF((LOG_NEGOTIATION, 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, sizeof header, "responder_send_HASH_SA_NONCE: " + "HASH_%c", initiator ? 'I' : 'R'); + LOG_DBG_BUF((LOG_NEGOTIATION, 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) { + log_error("gen_g_xy: malloc (%lu) failed", + (unsigned long)ie->g_x_len); + return; + } + if (dh_create_shared(ie->group, ie->g_xy, + exchange->initiator ? ie->g_xr : ie->g_xi)) { + log_print("gen_g_xy: dh_create_shared failed"); + return; + } + LOG_DBG_BUF((LOG_NEGOTIATION, 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 = 0; + size_t hash_len; + struct payload *hashp; + + /* Find HASH(3) and create our own hash, just as big. */ + hashp = payload_first(msg, 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) { + log_error("responder_recv_HASH: malloc (%lu) failed", + (unsigned long)hash_len - ISAKMP_GEN_SZ); + goto cleanup; + } + /* Allocate the prf and start calculating our HASH(3). XXX Share? */ + LOG_DBG((LOG_NEGOTIATION, 90, "responder_recv_HASH: " + "isakmp_sa %p isa %p", isakmp_sa, isa)); + LOG_DBG_BUF((LOG_NEGOTIATION, 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) + goto cleanup; + prf->Init(prf->prfctx); + prf->Update(prf->prfctx, (unsigned char *)"\0", 1); + LOG_DBG_BUF((LOG_NEGOTIATION, 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_DBG_BUF((LOG_NEGOTIATION, 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_DBG_BUF((LOG_NEGOTIATION, 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_DBG_BUF((LOG_NEGOTIATION, 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) { + message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, 0, + 1, 0); + goto cleanup; + } + free(my_hash); + + /* Mark message as authenticated. */ + msg->flags |= MSG_AUTHENTICATED; + + post_quick_mode(msg); + + return 0; + +cleanup: + if (my_hash) + free(my_hash); + return -1; +} diff --git a/keyexchange/isakmpd-20041012/ike_quick_mode.h b/keyexchange/isakmpd-20041012/ike_quick_mode.h new file mode 100644 index 0000000..32b1523 --- /dev/null +++ b/keyexchange/isakmpd-20041012/ike_quick_mode.h @@ -0,0 +1,40 @@ +/* $OpenBSD: ike_quick_mode.h,v 1.6 2004/04/15 18:39:25 deraadt Exp $ */ +/* $EOM: ike_quick_mode.h,v 1.1 1998/08/02 20:22:44 niklas Exp $ */ + +/* + * Copyright (c) 1998, 2001 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. + * + * 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 *); +extern int (*ike_quick_mode_responder[]) (struct message *); + +#endif /* _IKE_QUICK_MODE_H_ */ diff --git a/keyexchange/isakmpd-20041012/init.c b/keyexchange/isakmpd-20041012/init.c new file mode 100644 index 0000000..5ee6682 --- /dev/null +++ b/keyexchange/isakmpd-20041012/init.c @@ -0,0 +1,158 @@ +/* $OpenBSD: init.c,v 1.33 2004/09/17 13:46:34 ho Exp $ */ +/* $EOM: init.c,v 1.25 2000/03/30 14:27:24 ho Exp $ */ + +/* + * Copyright (c) 1998, 1999, 2000 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2000 Angelos D. Keromytis. All rights reserved. + * Copyright (c) 2003, 2004 Håkan Olsson. 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. + * + * 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 <stdlib.h> + +#include "sysdep.h" + +#include "app.h" +#include "cert.h" +#include "conf.h" +#include "connection.h" +#include "doi.h" +#include "exchange.h" +#include "init.h" +#include "ipsec.h" +#include "isakmp_doi.h" +#include "libcrypto.h" +#include "log.h" +#include "math_group.h" +#include "monitor.h" +#include "sa.h" +#include "timer.h" +#include "transport.h" +#include "virtual.h" +#include "udp.h" +#include "ui.h" +#include "util.h" + +#if defined (USE_POLICY) +#include "policy.h" +#endif + +#if defined (USE_NAT_TRAVERSAL) +#include "nat_traversal.h" +#include "udp_encap.h" +#endif + +void +init(void) +{ + app_init(); + doi_init(); + exchange_init(); + group_init(); + ipsec_init(); + isakmp_doi_init(); + message_init(); + libcrypto_init(); + + timer_init(); + + /* The following group are depending on timer_init having run. */ + conf_init(); + connection_init(); + + /* This depends on conf_init, thus check as soon as possible. */ + log_reinit(); + +#if defined (USE_POLICY) + /* policy_init depends on conf_init having run. */ + policy_init(); +#endif + + /* Depends on conf_init and policy_init having run */ + cert_init(); + crl_init(); + + sa_init(); + transport_init(); + virtual_init(); + udp_init(); +#if defined (USE_NAT_TRAVERSAL) + nat_t_init(); + udp_encap_init(); +#endif + monitor_ui_init(); +} + +/* Reinitialize, either after a SIGHUP reception or by FIFO UI cmd. */ +void +reinit(void) +{ + log_print("isakmpd: reinitializing daemon"); + + /* + * XXX Remove all(/some?) pending exchange timers? - they may not be + * possible to complete after we've re-read the config file. + * User-initiated SIGHUP's maybe "authorizes" a wait until + * next connection-check. + * XXX This means we discard exchange->last_msg, is this really ok? + */ + + /* Reinitialize PRNG if we are in deterministic mode. */ + if (regrand) + srandom(seed); + + /* Reread config file. */ + conf_reinit(); + + log_reinit(); + +#if defined (USE_POLICY) + /* Reread the policies. */ + policy_init(); +#endif + + /* Reinitialize certificates */ + cert_init(); + crl_init(); + + /* Reinitialize our connection list. */ + connection_reinit(); + + /* + * Rescan interfaces (call reinit() in all transports). + */ + transport_reinit(); + + /* + * XXX "These" (non-existent) reinitializations should not be done. + * cookie_reinit (); + * ui_reinit (); + */ + + sa_reinit(); +} diff --git a/keyexchange/isakmpd-20041012/init.h b/keyexchange/isakmpd-20041012/init.h new file mode 100644 index 0000000..cbcd46a --- /dev/null +++ b/keyexchange/isakmpd-20041012/init.h @@ -0,0 +1,38 @@ +/* $OpenBSD: init.h,v 1.6 2004/04/15 18:39:25 deraadt Exp $ */ +/* $EOM: init.h,v 1.2 1998/07/07 23:36:00 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. + * + * 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); +extern void reinit(void); + +#endif /* _INIT_H_ */ diff --git a/keyexchange/isakmpd-20041012/ipsec.c b/keyexchange/isakmpd-20041012/ipsec.c new file mode 100644 index 0000000..46cb8d9 --- /dev/null +++ b/keyexchange/isakmpd-20041012/ipsec.c @@ -0,0 +1,2523 @@ +/* $OpenBSD: ipsec.c,v 1.104 2004/09/17 13:53:08 ho Exp $ */ +/* $EOM: ipsec.c,v 1.143 2000/12/11 23:57:42 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2001 Angelos D. Keromytis. All rights reserved. + * Copyright (c) 2001 Håkan Olsson. 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. + * + * 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 <netdb.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdlib.h> +#include <string.h> + +#include "sysdep.h" + +#include "attribute.h" +#include "conf.h" +#include "constants.h" +#include "crypto.h" +#include "dh.h" +#include "doi.h" +#if defined (USE_DPD) +#include "dpd.h" +#endif +#include "exchange.h" +#include "hash.h" +#include "ike_aggressive.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 "isakmp_cfg.h" +#include "isakmp_fld.h" +#include "isakmp_num.h" +#include "log.h" +#include "math_group.h" +#include "message.h" +#if defined (USE_NAT_TRAVERSAL) +#include "nat_traversal.h" +#endif +#include "prf.h" +#include "sa.h" +#include "timer.h" +#include "transport.h" +#include "util.h" +#ifdef USE_X509 +#include "x509.h" +#endif + +extern int acquire_only; + +/* Backwards compatibility. */ +#ifndef NI_MAXHOST +#define NI_MAXHOST 1025 +#endif + +/* The replay window size used for all IPsec protocols if not overridden. */ +#define DEFAULT_REPLAY_WINDOW 16 + +struct ipsec_decode_arg { + struct message *msg; + struct sa *sa; + struct proto *proto; +}; + +/* These variables hold the contacted peers ADT state. */ +struct contact { + struct sockaddr *addr; + socklen_t len; +} *contacts = 0; +int contact_cnt = 0, contact_limit = 0; + +static int addr_cmp(const void *, const void *); +static int ipsec_add_contact(struct message *); +static int ipsec_contacted(struct message *); +#ifdef USE_DEBUG +static int ipsec_debug_attribute(u_int16_t, u_int8_t *, u_int16_t, + void *); +#endif +static void ipsec_delete_spi(struct sa *, struct proto *, int); +static 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_handle_leftover_payload(struct message *, u_int8_t, + struct payload *); +static int ipsec_informational_post_hook(struct message *); +static int ipsec_informational_pre_hook(struct message *); +static int ipsec_initiator(struct message *); +static void ipsec_proto_init(struct proto *, char *); +static int ipsec_responder(struct message *); +static void ipsec_setup_situation(u_int8_t *); +static int ipsec_set_network(u_int8_t *, u_int8_t *, struct ipsec_sa *); +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 *, 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), +#ifdef USE_DEBUG + ipsec_debug_attribute, +#endif + 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_handle_leftover_payload, + ipsec_informational_post_hook, + ipsec_informational_pre_hook, + ipsec_is_attribute_incompatible, + ipsec_proto_init, + 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, + ipsec_decode_ids +}; + +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 +}; + +struct dst_spi_proto_arg { + struct sockaddr *dst; + u_int32_t spi; + u_int8_t proto; +}; + +/* + * Check if SA matches what we are asking for through V_ARG. It has to + * be a finished phase 2 SA. + * if "proto" arg is 0, match any proto + */ +static int +ipsec_sa_check(struct sa *sa, void *v_arg) +{ + struct dst_spi_proto_arg *arg = v_arg; + struct proto *proto; + struct sockaddr *dst, *src; + int incoming; + + if (sa->phase != 2 || !(sa->flags & SA_FLAG_READY)) + return 0; + + sa->transport->vtbl->get_dst(sa->transport, &dst); + if (memcmp(sockaddr_addrdata(dst), sockaddr_addrdata(arg->dst), + sockaddr_addrlen(dst)) == 0) + incoming = 0; + else { + sa->transport->vtbl->get_src(sa->transport, &src); + if (memcmp(sockaddr_addrdata(src), sockaddr_addrdata(arg->dst), + sockaddr_addrlen(src)) == 0) + incoming = 1; + else + return 0; + } + + for (proto = TAILQ_FIRST(&sa->protos); proto; + proto = TAILQ_NEXT(proto, link)) + if ((arg->proto == 0 || proto->proto == arg->proto) && + memcmp(proto->spi[incoming], &arg->spi, sizeof arg->spi) + == 0) + return 1; + return 0; +} + +/* Find an SA with a "name" of DST, SPI & PROTO. */ +struct sa * +ipsec_sa_lookup(struct sockaddr *dst, u_int32_t spi, u_int8_t proto) +{ + struct dst_spi_proto_arg arg; + + arg.dst = dst; + arg.spi = spi; + arg.proto = proto; + return sa_find(ipsec_sa_check, &arg); +} + +/* + * Check if SA matches the flow of another SA in V_ARG. It has to + * be a finished non-replaced phase 2 SA. + * XXX At some point other selectors will matter here too. + */ +static int +ipsec_sa_check_flow(struct sa *sa, void *v_arg) +{ + struct sa *sa2 = v_arg; + struct ipsec_sa *isa = sa->data, *isa2 = sa2->data; + + if (sa == sa2 || sa->phase != 2 || + (sa->flags & (SA_FLAG_READY | SA_FLAG_REPLACED)) != SA_FLAG_READY) + return 0; + + if (isa->tproto != isa2->tproto || isa->sport != isa2->sport || + isa->dport != isa2->dport) + return 0; + + return isa->src_net->sa_family == isa2->src_net->sa_family && + memcmp(sockaddr_addrdata(isa->src_net), + sockaddr_addrdata(isa2->src_net), + sockaddr_addrlen(isa->src_net)) == 0 && + memcmp(sockaddr_addrdata(isa->src_mask), + sockaddr_addrdata(isa2->src_mask), + sockaddr_addrlen(isa->src_mask)) == 0 && + memcmp(sockaddr_addrdata(isa->dst_net), + sockaddr_addrdata(isa2->dst_net), + sockaddr_addrlen(isa->dst_net)) == 0 && + memcmp(sockaddr_addrdata(isa->dst_mask), + sockaddr_addrdata(isa2->dst_mask), + sockaddr_addrlen(isa->dst_mask)) == 0; +} + +/* + * Do IPsec DOI specific finalizations task for the exchange where MSG was + * the final message. + */ +static void +ipsec_finalize_exchange(struct message *msg) +{ + struct sa *isakmp_sa = msg->isakmp_sa; + struct ipsec_sa *isa; + struct exchange *exchange = msg->exchange; + struct ipsec_exch *ie = exchange->data; + struct sa *sa = 0, *old_sa; + struct proto *proto, *last_proto = 0; +#ifdef USE_DEBUG + char *addr1, *addr2, *mask1, *mask2; +#endif + + switch (exchange->phase) { + case 1: + switch (exchange->type) { + case ISAKMP_EXCH_ID_PROT: + case ISAKMP_EXCH_AGGRESSIVE: + isa = isakmp_sa->data; + 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; + + /* + * If a lifetime was negotiated setup the expiration + * timers. + */ + if (isakmp_sa->seconds) + sa_setup_expirations(isakmp_sa); + +#if defined (USE_NAT_TRAVERSAL) + if (isakmp_sa->flags & SA_FLAG_NAT_T_KEEPALIVE) + nat_t_setup_keepalive(isakmp_sa); +#endif + break; + } + 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)) { + isa = sa->data; + + if (exchange->initiator) { + /* + * Initiator is source, responder is + * destination. + */ + if (ipsec_set_network(ie->id_ci, + ie->id_cr, isa)) { + log_print( + "ipsec_finalize_exchange: " + "ipsec_set_network " + "failed"); + return; + } + } else { + /* + * Responder is source, initiator is + * destination. + */ + if (ipsec_set_network(ie->id_cr, + ie->id_ci, isa)) { + log_print( + "ipsec_finalize_exchange: " + "ipsec_set_network " + "failed"); + return; + } + } + + for (proto = TAILQ_FIRST(&sa->protos), + last_proto = 0; proto; + proto = TAILQ_NEXT(proto, link)) { + if (sysdep_ipsec_set_spi(sa, proto, + 0, isakmp_sa) || + (last_proto && + sysdep_ipsec_group_spis(sa, + last_proto, proto, 0)) || + sysdep_ipsec_set_spi(sa, proto, + 1, isakmp_sa) || + (last_proto && + sysdep_ipsec_group_spis(sa, + last_proto, proto, 1))) + /* + * XXX Tear down this + * exchange. + */ + return; + last_proto = proto; + } + +#ifdef USE_DEBUG + if (sockaddr2text(isa->src_net, &addr1, 0)) + addr1 = 0; + if (sockaddr2text(isa->src_mask, &mask1, 0)) + mask1 = 0; + if (sockaddr2text(isa->dst_net, &addr2, 0)) + addr2 = 0; + if (sockaddr2text(isa->dst_mask, &mask2, 0)) + mask2 = 0; + + LOG_DBG((LOG_EXCHANGE, 50, + "ipsec_finalize_exchange: src %s %s " + "dst %s %s tproto %u sport %u dport %u", + addr1 ? addr1 : "<??\?>", + mask1 ? mask1 : "<??\?>", + addr2 ? addr2 : "<??\?>", + mask2 ? mask2 : "<??\?>", + isa->tproto, ntohs(isa->sport), + ntohs(isa->dport))); + + if (addr1) + free(addr1); + if (mask1) + free(mask1); + if (addr2) + free(addr2); + if (mask2) + free(mask2); + +#endif /* USE_DEBUG */ + + /* + * If this is not an SA acquired by the + * kernel, it needs to have a SPD entry + * (a.k.a. flow) set up. + */ + if (!(sa->flags & SA_FLAG_ONDEMAND || + conf_get_str("General", "Acquire-Only") + || acquire_only) + && sysdep_ipsec_enable_sa(sa, isakmp_sa)) + /* XXX Tear down this exchange. */ + return; + + /* + * Mark elder SAs with the same flow + * information as replaced. + */ + while ((old_sa = sa_find(ipsec_sa_check_flow, + sa)) != 0) + sa_mark_replaced(old_sa); + } + break; + } + } +} + +/* Set the client addresses in ISA from SRC_ID and DST_ID. */ +static int +ipsec_set_network(u_int8_t *src_id, u_int8_t *dst_id, struct ipsec_sa *isa) +{ + int id; + + /* Set source address/mask. */ + id = GET_ISAKMP_ID_TYPE(src_id); + switch (id) { + case IPSEC_ID_IPV4_ADDR: + case IPSEC_ID_IPV4_ADDR_SUBNET: + isa->src_net = (struct sockaddr *)calloc(1, + sizeof(struct sockaddr_in)); + if (!isa->src_net) + goto memfail; + isa->src_net->sa_family = AF_INET; +#ifndef USE_OLD_SOCKADDR + isa->src_net->sa_len = sizeof(struct sockaddr_in); +#endif + + isa->src_mask = (struct sockaddr *)calloc(1, + sizeof(struct sockaddr_in)); + if (!isa->src_mask) + goto memfail; + isa->src_mask->sa_family = AF_INET; +#ifndef USE_OLD_SOCKADDR + isa->src_mask->sa_len = sizeof(struct sockaddr_in); +#endif + break; + + case IPSEC_ID_IPV6_ADDR: + case IPSEC_ID_IPV6_ADDR_SUBNET: + isa->src_net = (struct sockaddr *)calloc(1, + sizeof(struct sockaddr_in6)); + if (!isa->src_net) + goto memfail; + isa->src_net->sa_family = AF_INET6; +#ifndef USE_OLD_SOCKADDR + isa->src_net->sa_len = sizeof(struct sockaddr_in6); +#endif + + isa->src_mask = (struct sockaddr *)calloc(1, + sizeof(struct sockaddr_in6)); + if (!isa->src_mask) + goto memfail; + isa->src_mask->sa_family = AF_INET6; +#ifndef USE_OLD_SOCKADDR + isa->src_mask->sa_len = sizeof(struct sockaddr_in6); +#endif + break; + + case IPSEC_ID_IPV4_RANGE: + case IPSEC_ID_IPV6_RANGE: + case IPSEC_ID_DER_ASN1_DN: + case IPSEC_ID_DER_ASN1_GN: + case IPSEC_ID_KEY_ID: + default: + log_print("ipsec_set_network: ID type %d (%s) not supported", + id, constant_name(ipsec_id_cst, id)); + return -1; + } + + /* Net */ + memcpy(sockaddr_addrdata(isa->src_net), src_id + ISAKMP_ID_DATA_OFF, + sockaddr_addrlen(isa->src_net)); + + /* Mask */ + switch (id) { + case IPSEC_ID_IPV4_ADDR: + case IPSEC_ID_IPV6_ADDR: + memset(sockaddr_addrdata(isa->src_mask), 0xff, + sockaddr_addrlen(isa->src_mask)); + break; + case IPSEC_ID_IPV4_ADDR_SUBNET: + case IPSEC_ID_IPV6_ADDR_SUBNET: + memcpy(sockaddr_addrdata(isa->src_mask), src_id + + ISAKMP_ID_DATA_OFF + sockaddr_addrlen(isa->src_net), + sockaddr_addrlen(isa->src_mask)); + break; + } + + memcpy(&isa->sport, + src_id + ISAKMP_ID_DOI_DATA_OFF + IPSEC_ID_PORT_OFF, + IPSEC_ID_PORT_LEN); + + /* Set destination address. */ + id = GET_ISAKMP_ID_TYPE(dst_id); + switch (id) { + case IPSEC_ID_IPV4_ADDR: + case IPSEC_ID_IPV4_ADDR_SUBNET: + isa->dst_net = (struct sockaddr *)calloc(1, + sizeof(struct sockaddr_in)); + if (!isa->dst_net) + goto memfail; + isa->dst_net->sa_family = AF_INET; +#ifndef USE_OLD_SOCKADDR + isa->dst_net->sa_len = sizeof(struct sockaddr_in); +#endif + + isa->dst_mask = (struct sockaddr *)calloc(1, + sizeof(struct sockaddr_in)); + if (!isa->dst_mask) + goto memfail; + isa->dst_mask->sa_family = AF_INET; +#ifndef USE_OLD_SOCKADDR + isa->dst_mask->sa_len = sizeof(struct sockaddr_in); +#endif + break; + + case IPSEC_ID_IPV6_ADDR: + case IPSEC_ID_IPV6_ADDR_SUBNET: + isa->dst_net = (struct sockaddr *)calloc(1, + sizeof(struct sockaddr_in6)); + if (!isa->dst_net) + goto memfail; + isa->dst_net->sa_family = AF_INET6; +#ifndef USE_OLD_SOCKADDR + isa->dst_net->sa_len = sizeof(struct sockaddr_in6); +#endif + + isa->dst_mask = (struct sockaddr *)calloc(1, + sizeof(struct sockaddr_in6)); + if (!isa->dst_mask) + goto memfail; + isa->dst_mask->sa_family = AF_INET6; +#ifndef USE_OLD_SOCKADDR + isa->dst_mask->sa_len = sizeof(struct sockaddr_in6); +#endif + break; + } + + /* Net */ + memcpy(sockaddr_addrdata(isa->dst_net), dst_id + ISAKMP_ID_DATA_OFF, + sockaddr_addrlen(isa->dst_net)); + + /* Mask */ + switch (id) { + case IPSEC_ID_IPV4_ADDR: + case IPSEC_ID_IPV6_ADDR: + memset(sockaddr_addrdata(isa->dst_mask), 0xff, + sockaddr_addrlen(isa->dst_mask)); + break; + case IPSEC_ID_IPV4_ADDR_SUBNET: + case IPSEC_ID_IPV6_ADDR_SUBNET: + memcpy(sockaddr_addrdata(isa->dst_mask), dst_id + + ISAKMP_ID_DATA_OFF + sockaddr_addrlen(isa->dst_net), + sockaddr_addrlen(isa->dst_mask)); + break; + } + + memcpy(&isa->tproto, dst_id + ISAKMP_ID_DOI_DATA_OFF + + IPSEC_ID_PROTO_OFF, IPSEC_ID_PROTO_LEN); + memcpy(&isa->dport, + dst_id + ISAKMP_ID_DOI_DATA_OFF + IPSEC_ID_PORT_OFF, + IPSEC_ID_PORT_LEN); + return 0; + +memfail: + log_error("ipsec_set_network: calloc () failed"); + return -1; +} + +/* Free the DOI-specific exchange data pointed to by VIE. */ +static void +ipsec_free_exchange_data(void *vie) +{ + struct ipsec_exch *ie = vie; +#ifdef USE_ISAKMP_CFG + struct isakmp_cfg_attr *attr; +#endif + + if (ie->sa_i_b) + free(ie->sa_i_b); + if (ie->id_ci) + free(ie->id_ci); + if (ie->id_cr) + free(ie->id_cr); + 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); + if (ie->group) + group_free(ie->group); +#ifdef USE_ISAKMP_CFG + for (attr = LIST_FIRST(&ie->attrs); attr; + attr = LIST_FIRST(&ie->attrs)) { + LIST_REMOVE(attr, link); + if (attr->length) + free(attr->value); + free(attr); + } +#endif +} + +/* Free the DOI-specific SA data pointed to by VISA. */ +static void +ipsec_free_sa_data(void *visa) +{ + struct ipsec_sa *isa = visa; + + if (isa->src_net) + free(isa->src_net); + if (isa->src_mask) + free(isa->src_mask); + if (isa->dst_net) + free(isa->dst_net); + if (isa->dst_mask) + free(isa->dst_mask); + if (isa->skeyid_a) + free(isa->skeyid_a); + if (isa->skeyid_d) + free(isa->skeyid_d); +} + +/* Free the DOI-specific protocol data of an SA pointed to by VIPROTO. */ +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]); +} + +/* Return exchange script based on TYPE. */ +static int16_t * +ipsec_exchange_script(u_int8_t type) +{ + switch (type) { +#ifdef USE_ISAKMP_CFG + case ISAKMP_EXCH_TRANSACTION: + return script_transaction; +#endif + case IKE_EXCH_QUICK_MODE: + return script_quick_mode; + case IKE_EXCH_NEW_GROUP_MODE: + return script_new_group_mode; + } + return 0; +} + +/* Initialize this DOI, requires doi_init to already have been called. */ +void +ipsec_init(void) +{ + 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) { + ks = malloc(sizeof *ks); + if (!ks) { + log_error("ipsec_get_keystate: malloc (%lu) failed", + (unsigned long) sizeof *ks); + return 0; + } + memcpy(ks, msg->exchange->keystate, sizeof *ks); + return ks; + } + /* + * 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. + */ + if (!msg->isakmp_sa->keystate) { + log_print("ipsec_get_keystate: no keystate in ISAKMP SA %p", + msg->isakmp_sa); + return 0; + } + 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_DBG_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_DBG_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_DBG_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_ECN_TUNNEL))) + 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_DBG((LOG_MESSAGE, 40, + "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; + + switch (type) { + case IPSEC_ID_IPV4_ADDR: + LOG_DBG_BUF((LOG_MESSAGE, 40, + "ipsec_validate_id_information: IPv4", buf, + sizeof(struct in_addr))); + break; + + case IPSEC_ID_IPV6_ADDR: + LOG_DBG_BUF((LOG_MESSAGE, 40, + "ipsec_validate_id_information: IPv6", buf, + sizeof(struct in6_addr))); + break; + + case IPSEC_ID_IPV4_ADDR_SUBNET: + LOG_DBG_BUF((LOG_MESSAGE, 40, + "ipsec_validate_id_information: IPv4 network/netmask", + buf, 2 * sizeof(struct in_addr))); + break; + + case IPSEC_ID_IPV6_ADDR_SUBNET: + LOG_DBG_BUF((LOG_MESSAGE, 40, + "ipsec_validate_id_information: IPv6 network/netmask", + buf, 2 * sizeof(struct in6_addr))); + break; + + default: + break; + } + + 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, size_t len) +{ + if (len < IPSEC_SIT_SIT_OFF + IPSEC_SIT_SIT_LEN) { + log_print("ipsec_validate_situation: payload too short: %u", + (unsigned int) len); + return -1; + } + /* Currently only "identity only" situations are supported. */ + if (GET_IPSEC_SIT_SIT(buf) != IPSEC_SIT_IDENTITY_ONLY) + return 1; + + *sz = IPSEC_SIT_SIT_LEN; + + 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_AES_128_CTR + && transform_id < IPSEC_ESP_AES_MARS) + || transform_id > IPSEC_ESP_AES_TWOFISH ? -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 *) = 0; + + /* Check that the SA is coherent with the IKE rules. */ + if (exchange->type != ISAKMP_EXCH_TRANSACTION + && ((exchange->phase == 1 && + exchange->type != ISAKMP_EXCH_ID_PROT && + exchange->type != ISAKMP_EXCH_AGGRESSIVE && + exchange->type != ISAKMP_EXCH_INFO) + || (exchange->phase == 2 && + exchange->type != IKE_EXCH_QUICK_MODE && + exchange->type != ISAKMP_EXCH_INFO))) { + log_print("ipsec_initiator: unsupported exchange type %d " + "in phase %d", exchange->type, exchange->phase); + return -1; + } + switch (exchange->type) { + case ISAKMP_EXCH_ID_PROT: + script = ike_main_mode_initiator; + break; +#ifdef USE_AGGRESSIVE + case ISAKMP_EXCH_AGGRESSIVE: + script = ike_aggressive_initiator; + break; +#endif +#ifdef USE_ISAKMP_CFG + case ISAKMP_EXCH_TRANSACTION: + script = isakmp_cfg_initiator; + break; +#endif + case ISAKMP_EXCH_INFO: + return message_send_info(msg); + case IKE_EXCH_QUICK_MODE: + script = ike_quick_mode_initiator; + break; + default: + log_print("ipsec_initiator: unsupported exchange type %d", + exchange->type); + return -1; + } + + /* Run the script code for this step. */ + if (script) + return script[exchange->step] (msg); + + return 0; +} + +/* + * delete all SA's from addr with the associated proto and SPI's + * + * spis[] is an array of SPIs of size 16-octet for proto ISAKMP + * or 4-octet otherwise. + */ +static void +ipsec_delete_spi_list(struct sockaddr *addr, u_int8_t proto, u_int8_t *spis, + int nspis, char *type) +{ + struct sa *sa; + int i; + + for (i = 0; i < nspis; i++) { + if (proto == ISAKMP_PROTO_ISAKMP) { + u_int8_t *spi = spis + i * ISAKMP_HDR_COOKIES_LEN; + + /* + * This really shouldn't happen in IPSEC DOI + * code, but Cisco VPN 3000 sends ISAKMP DELETE's + * this way. + */ + sa = sa_lookup_isakmp_sa(addr, spi); + } else { + u_int32_t spi = ((u_int32_t *)spis)[i]; + + sa = ipsec_sa_lookup(addr, spi, proto); + } + + if (sa == NULL) { + LOG_DBG((LOG_SA, 30, "ipsec_delete_spi_list: could " + "not locate SA (SPI %08x, proto %u)", + ((u_int32_t *)spis)[i], proto)); + continue; + } + /* Delete the SA and search for the next */ + LOG_DBG((LOG_SA, 30, "ipsec_delete_spi_list: " + "%s made us delete SA %p (%d references) for proto %d", + type, sa, sa->refcnt, proto)); + + sa_free(sa); + } +} + +/* + * deal with a NOTIFY of INVALID_SPI + */ +static void +ipsec_invalid_spi (struct message *msg, struct payload *p) +{ + struct sockaddr *dst; + int invspisz, off; + u_int32_t spi; + u_int16_t totsiz; + u_int8_t spisz; + + /* Any notification that make us do something should be protected */ + if(!TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_HASH])) + { + LOG_DBG ((LOG_SA, 40, + "ipsec_invalid_spi: missing HASH payload in INVALID_SPI" + " notification")); + return; + } + + /* + * get the invalid spi out of the variable sized notification data + * field, which is after the variable sized SPI field [which specifies + * the receiving entity's phase-1 SPI, not the invalid spi] + */ + totsiz = GET_ISAKMP_GEN_LENGTH (p->p); + spisz = GET_ISAKMP_NOTIFY_SPI_SZ (p->p); + off = ISAKMP_NOTIFY_SPI_OFF + spisz; + invspisz = totsiz - off; + + if (invspisz != sizeof spi) + { + LOG_DBG ((LOG_SA, 40, + "ipsec_invalid_spi: SPI size %d in INVALID_SPI " + "payload unsupported", spisz)); + return; + } + memcpy (&spi, p->p + off, sizeof spi); + + msg->transport->vtbl->get_dst (msg->transport, &dst); + + /* delete matching SPI's from this peer */ + ipsec_delete_spi_list (dst, 0, (u_int8_t *)&spi, 1, "INVALID_SPI"); +} + +static int +ipsec_responder(struct message *msg) +{ + struct exchange *exchange = msg->exchange; + int (**script)(struct message *) = 0; + struct payload *p; + u_int16_t type; + + /* Check that a new exchange is coherent with the IKE rules. */ + if (exchange->step == 0 && exchange->type != ISAKMP_EXCH_TRANSACTION + && ((exchange->phase == 1 && + exchange->type != ISAKMP_EXCH_ID_PROT && + exchange->type != ISAKMP_EXCH_AGGRESSIVE && + exchange->type != ISAKMP_EXCH_INFO) + || (exchange->phase == 2 && + exchange->type != IKE_EXCH_QUICK_MODE && + exchange->type != ISAKMP_EXCH_INFO))) { + message_drop(msg, ISAKMP_NOTIFY_UNSUPPORTED_EXCHANGE_TYPE, + 0, 1, 0); + return -1; + } + LOG_DBG((LOG_MISC, 30, "ipsec_responder: phase %d exchange %d step %d", + exchange->phase, exchange->type, exchange->step)); + switch (exchange->type) { + case ISAKMP_EXCH_ID_PROT: + script = ike_main_mode_responder; + break; +#ifdef USE_AGGRESSIVE + case ISAKMP_EXCH_AGGRESSIVE: + script = ike_aggressive_responder; + break; +#endif +#ifdef USE_ISAKMP_CFG + case ISAKMP_EXCH_TRANSACTION: + script = isakmp_cfg_responder; + break; +#endif + case ISAKMP_EXCH_INFO: + for (p = payload_first(msg, ISAKMP_PAYLOAD_NOTIFY); p; + p = TAILQ_NEXT(p, link)) { + type = GET_ISAKMP_NOTIFY_MSG_TYPE(p->p); + LOG_DBG((LOG_EXCHANGE, 10, + "ipsec_responder: got NOTIFY of type %s", + constant_name(isakmp_notify_cst, type))); + + switch (type) { + case IPSEC_NOTIFY_INITIAL_CONTACT: + /* Handled by leftover logic. */ + break; + +#if defined (USE_DPD) + case ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE: + case ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE_ACK: + dpd_handle_notify(msg, p); + break; +#endif + + default: + p->flags |= PL_MARK; + break; + } + } + + /* + * If any DELETEs are in here, let the logic of leftover + * payloads deal with them. + */ + return 0; + + case IKE_EXCH_QUICK_MODE: + script = ike_quick_mode_responder; + break; + + default: + message_drop(msg, ISAKMP_NOTIFY_UNSUPPORTED_EXCHANGE_TYPE, + 0, 1, 0); + return -1; + } + + /* 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 (payload_first(msg, ISAKMP_PAYLOAD_SA)) { + message_drop(msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 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; +} + +/* + * Find out whether the attribute of type TYPE with a LEN length value + * pointed to by VALUE is incompatible with what we can handle. + * VMSG is a pointer to the current message. + */ +int +ipsec_is_attribute_incompatible(u_int16_t type, u_int8_t *value, u_int16_t len, + void *vmsg) +{ + struct message *msg = vmsg; + u_int16_t dv = decode_16(value); + + if (msg->exchange->phase == 1) { + switch (type) { + case IKE_ATTR_ENCRYPTION_ALGORITHM: + return !crypto_get(from_ike_crypto(dv)); + case IKE_ATTR_HASH_ALGORITHM: + return !hash_get(from_ike_hash(dv)); + case IKE_ATTR_AUTHENTICATION_METHOD: + return !ike_auth_get(dv); + case IKE_ATTR_GROUP_DESCRIPTION: + return (dv < IKE_GROUP_DESC_MODP_768 + || dv > IKE_GROUP_DESC_MODP_1536) + && (dv < IKE_GROUP_DESC_MODP_2048 + || dv > IKE_GROUP_DESC_MODP_8192); + 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 dv < IKE_DURATION_SECONDS + || dv > IKE_DURATION_KILOBYTES; + case IKE_ATTR_LIFE_DURATION: + return len != 2 && len != 4; + 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 dv % 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 dv < IPSEC_DURATION_SECONDS + || dv > IPSEC_DURATION_KILOBYTES; + case IPSEC_ATTR_SA_LIFE_DURATION: + return len != 2 && len != 4; + case IPSEC_ATTR_GROUP_DESCRIPTION: + return (dv < IKE_GROUP_DESC_MODP_768 + || dv > IKE_GROUP_DESC_MODP_1536) + && (dv < IKE_GROUP_DESC_MODP_2048 + || IKE_GROUP_DESC_MODP_8192 < dv); + case IPSEC_ATTR_ENCAPSULATION_MODE: +#if defined (USE_NAT_TRAVERSAL) + return dv != IPSEC_ENCAP_TUNNEL + && dv != IPSEC_ENCAP_TRANSPORT + && dv != IPSEC_ENCAP_UDP_ENCAP_TUNNEL + && dv != IPSEC_ENCAP_UDP_ENCAP_TRANSPORT + && dv != IPSEC_ENCAP_UDP_ENCAP_TUNNEL_DRAFT + && dv != IPSEC_ENCAP_UDP_ENCAP_TRANSPORT_DRAFT; +#else + return dv < IPSEC_ENCAP_TUNNEL + || dv > IPSEC_ENCAP_TRANSPORT; +#endif /* USE_NAT_TRAVERSAL */ + case IPSEC_ATTR_AUTHENTICATION_ALGORITHM: + return dv < IPSEC_AUTH_HMAC_MD5 + || dv > IPSEC_AUTH_HMAC_RIPEMD; + case IPSEC_ATTR_KEY_LENGTH: + /* + * XXX Blowfish needs '0'. Others appear to disregard + * this attr? + */ + return 0; + case IPSEC_ATTR_KEY_ROUNDS: + return 1; + case IPSEC_ATTR_COMPRESS_DICTIONARY_SIZE: + return 1; + case IPSEC_ATTR_COMPRESS_PRIVATE_ALGORITHM: + return 1; + case IPSEC_ATTR_ECN_TUNNEL: + return 1; + } + } + /* XXX Silence gcc. */ + return 1; +} + +#ifdef USE_DEBUG +/* + * Log the attribute of TYPE with a LEN length value pointed to by VALUE + * in human-readable form. VMSG is a pointer to the current message. + */ +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) + snprintf(val, sizeof val, "%d", decode_16(value)); + else if (len == 4) + snprintf(val, sizeof val, "%d", decode_32(value)); + else + snprintf(val, sizeof val, "unrepresentable"); + + LOG_DBG((LOG_MESSAGE, 50, "Attribute %s value %s", + constant_name(msg->exchange->phase == 1 ? ike_attr_cst : + ipsec_attr_cst, type), val)); + return 0; +} +#endif + +/* + * Decode the attribute of type TYPE with a LEN length value pointed to by + * VALUE. VIDA is a pointer to a context structure where we can find the + * current message, SA and protocol. + */ +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: + isa->group_desc = 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: + log_print("ipsec_decode_attribute: " + "unreasonable lifetime"); + } + break; + case IKE_DURATION_KILOBYTES: + switch (len) { + case 2: + sa->kilobytes = decode_16(value); + break; + case 4: + sa->kilobytes = decode_32(value); + break; + default: + log_print("ipsec_decode_attribute: " + "unreasonable lifetime"); + } + break; + default: + log_print("ipsec_decode_attribute: unknown " + "lifetime type"); + } + 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: + log_print("ipsec_decode_attribute: " + "unreasonable lifetime"); + } + break; + case IPSEC_DURATION_KILOBYTES: + switch (len) { + case 2: + sa->kilobytes = decode_16(value); + break; + case 4: + sa->kilobytes = decode_32(value); + break; + default: + log_print("ipsec_decode_attribute: " + "unreasonable lifetime"); + } + break; + default: + log_print("ipsec_decode_attribute: unknown " + "lifetime type"); + } + 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; + case IPSEC_ATTR_ECN_TUNNEL: + 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_DBG((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; +} + +/* + * Delete the IPsec SA represented by the INCOMING direction in protocol PROTO + * of the IKE security association SA. + */ +static void +ipsec_delete_spi(struct sa *sa, struct proto *proto, int incoming) +{ + if (sa->phase == 1) + return; + /* XXX Error handling? Is it interesting? */ + sysdep_ipsec_delete_spi(sa, proto, incoming); +} + +/* + * Store BUF into the g^x entry of the exchange that message MSG belongs to. + * PEER is non-zero when the value is our peer's, and zero when it is ours. + */ +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) { + log_error("ipsec_g_x: malloc (%lu) failed", + (unsigned long)ie->g_x_len); + return -1; + } + memcpy(*g_x, buf, ie->g_x_len); + snprintf(header, sizeof header, "ipsec_g_x: g^x%c", + initiator ? 'i' : 'r'); + LOG_DBG_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) { + log_error("ipsec_gen_g_x: malloc (%lu) failed", + ISAKMP_KE_SZ + (unsigned long)ie->g_x_len); + return -1; + } + if (message_add_payload(msg, ISAKMP_PAYLOAD_KEY_EXCH, buf, + ISAKMP_KE_SZ + ie->g_x_len, 1)) { + free(buf); + return -1; + } + if (dh_create_exchange(ie->group, buf + ISAKMP_KE_DATA_OFF)) { + log_print("ipsec_gen_g_x: dh_create_exchange failed"); + free(buf); + return -1; + } + 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 = payload_first(msg, 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 != (size_t) dh_getlen(ie->group)) { + /* XXX Is this a good notify type? */ + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 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, *src; + 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); + /* The peer is the source. */ + transport->vtbl->get_dst(transport, &src); + return sysdep_ipsec_get_spi(sz, proto, src, dst, + msg->exchange->seq); + } +} + +/* + * We have gotten a payload PAYLOAD of type TYPE, which did not get handled + * by the logic of the exchange MSG takes part in. Now is the time to deal + * with such a payload if we know how to, if we don't, return -1, otherwise + * 0. + */ +int +ipsec_handle_leftover_payload(struct message *msg, u_int8_t type, + struct payload *payload) +{ + u_int32_t spisz, nspis; + struct sockaddr *dst; + int reenter = 0; + u_int8_t *spis, proto; + struct sa *sa; + + switch (type) { + case ISAKMP_PAYLOAD_DELETE: + proto = GET_ISAKMP_DELETE_PROTO(payload->p); + nspis = GET_ISAKMP_DELETE_NSPIS(payload->p); + spisz = GET_ISAKMP_DELETE_SPI_SZ(payload->p); + + if (nspis == 0) { + LOG_DBG((LOG_SA, 60, "ipsec_handle_leftover_payload: " + "message specified zero SPIs, ignoring")); + return -1; + } + /* verify proper SPI size */ + if ((proto == ISAKMP_PROTO_ISAKMP && spisz != + ISAKMP_HDR_COOKIES_LEN) + || (proto != ISAKMP_PROTO_ISAKMP && spisz != + sizeof(u_int32_t))) { + log_print("ipsec_handle_leftover_payload: invalid SPI " + "size %d for proto %d in DELETE payload", + spisz, proto); + return -1; + } + spis = (u_int8_t *) malloc(nspis * spisz); + if (!spis) { + log_error("ipsec_handle_leftover_payload: malloc " + "(%d) failed", nspis * spisz); + return -1; + } + /* extract SPI and get dst address */ + memcpy(spis, payload->p + ISAKMP_DELETE_SPI_OFF, nspis * spisz); + msg->transport->vtbl->get_dst(msg->transport, &dst); + + ipsec_delete_spi_list(dst, proto, spis, nspis, "DELETE"); + + free(spis); + payload->flags |= PL_MARK; + return 0; + + case ISAKMP_PAYLOAD_NOTIFY: + switch (GET_ISAKMP_NOTIFY_MSG_TYPE(payload->p)) { + case IPSEC_NOTIFY_INITIAL_CONTACT: + /* + * Permit INITIAL-CONTACT if + * - this is not an AGGRESSIVE mode exchange + * - it is protected by an ISAKMP SA + * + * XXX Instead of the first condition above, we could + * XXX permit this only for phase 2. In the last + * XXX packet of main-mode, this payload, while + * XXX encrypted, is not part of the hash digest. As + * XXX we currently send our own INITIAL-CONTACTs at + * XXX this point, this too would need to be changed. + */ + if (msg->exchange->type == ISAKMP_EXCH_AGGRESSIVE) { + log_print("ipsec_handle_leftover_payload: got " + "INITIAL-CONTACT in AGGRESSIVE mode"); + return -1; + } + if ((msg->exchange->flags & EXCHANGE_FLAG_ENCRYPT) + == 0) { + log_print("ipsec_handle_leftover_payload: got " + "INITIAL-CONTACT without ISAKMP SA"); + return -1; + } + + if ((msg->flags & MSG_AUTHENTICATED) == 0) { + log_print("ipsec_handle_leftover_payload: " + "got unauthenticated INITIAL-CONTACT"); + return -1; + } + /* + * Find out who is sending this and then delete every + * SA that is ready. Exchanges will timeout + * themselves and then the non-ready SAs will + * disappear too. + */ + msg->transport->vtbl->get_dst(msg->transport, &dst); + while ((sa = sa_lookup_by_peer(dst, + sysdep_sa_len(dst))) != 0) { + /* + * Don't delete the current SA -- we received + * the notification over it, so it's obviously + * still active. We temporarily need to remove + * the SA from the list to avoid an endless + * loop, but keep a reference so it won't + * disappear meanwhile. + */ + if (sa == msg->isakmp_sa) { + sa_reference(sa); + sa_remove(sa); + reenter = 1; + continue; + } + LOG_DBG((LOG_SA, 30, + "ipsec_handle_leftover_payload: " + "INITIAL-CONTACT made us delete SA %p", + sa)); + sa_delete(sa, 0); + } + + if (reenter) { + sa_enter(msg->isakmp_sa); + sa_release(msg->isakmp_sa); + } + payload->flags |= PL_MARK; + return 0; + } + } + return -1; +} + +/* Return the encryption keylength in octets of the ESP protocol PROTO. */ +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; + case IPSEC_ESP_CAST: + if (!iproto->keylen) + return 16; + return iproto->keylen / 8; + case IPSEC_ESP_AES: + case IPSEC_ESP_AES_128_CTR: + if (!iproto->keylen) + return 16; + /* Fallthrough */ + default: + return iproto->keylen / 8; + } +} + +/* Return the authentication keylength in octets of the ESP protocol PROTO. */ +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: + case IPSEC_AUTH_HMAC_RIPEMD: + return 20; + case IPSEC_AUTH_HMAC_SHA2_256: + return 32; + case IPSEC_AUTH_HMAC_SHA2_384: + return 48; + case IPSEC_AUTH_HMAC_SHA2_512: + return 64; + default: + return 0; + } +} + +/* Return the authentication keylength in octets of the AH protocol PROTO. */ +int +ipsec_ah_keylength(struct proto *proto) +{ + switch (proto->id) { + case IPSEC_AH_MD5: + return 16; + case IPSEC_AH_SHA: + case IPSEC_AH_RIPEMD: + return 20; + case IPSEC_AH_SHA2_256: + return 32; + case IPSEC_AH_SHA2_384: + return 48; + case IPSEC_AH_SHA2_512: + return 64; + default: + return -1; + } +} + +/* Return the total keymaterial length of the protocol PROTO. */ +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; + } +} + +/* Helper function for ipsec_get_id(). */ +static int +ipsec_get_proto_port(char *section, u_int8_t *tproto, u_int16_t *port) +{ + struct protoent *pe = NULL; + struct servent *se; + char *pstr; + + pstr = conf_get_str(section, "Protocol"); + if (!pstr) { + *tproto = 0; + return 0; + } + *tproto = (u_int8_t)atoi(pstr); + if (!*tproto) { + pe = getprotobyname(pstr); + if (pe) + *tproto = pe->p_proto; + } + if (!*tproto) { + log_print("ipsec_get_proto_port: protocol \"%s\" unknown", + pstr); + return -1; + } + + pstr = conf_get_str(section, "Port"); + if (!pstr) + return 0; + *port = (u_int16_t)atoi(pstr); + if (!*port) { + se = getservbyname(pstr, + pe ? pe->p_name : (pstr ? pstr : NULL)); + if (se) + *port = se->s_port; + } + if (!*port) { + log_print("ipsec_get_proto_port: port \"%s\" unknown", + pstr); + return -1; + } + return 0; +} + +/* + * Out of a named section SECTION in the configuration file find out + * the network address and mask as well as the ID type. Put the info + * in the areas pointed to by ADDR, MASK, TPROTO, PORT, and ID respectively. + * Return 0 on success and -1 on failure. + */ +int +ipsec_get_id(char *section, int *id, struct sockaddr **addr, + struct sockaddr **mask, u_int8_t *tproto, u_int16_t *port) +{ + char *type, *address, *netmask; + + type = conf_get_str(section, "ID-type"); + if (!type) { + log_print("ipsec_get_id: section %s has no \"ID-type\" tag", + section); + return -1; + } + *id = constant_value(ipsec_id_cst, type); + switch (*id) { + case IPSEC_ID_IPV4_ADDR: + case IPSEC_ID_IPV6_ADDR: { + int ret; + + address = conf_get_str(section, "Address"); + if (!address) { + log_print("ipsec_get_id: section %s has no " + "\"Address\" tag", section); + return -1; + } + if (text2sockaddr(address, NULL, addr)) { + log_print("ipsec_get_id: invalid address %s in " + "section %s", address, section); + return -1; + } + ret = ipsec_get_proto_port(section, tproto, port); + if (ret < 0) + free(*addr); + + return ret; + } + +#ifdef notyet + case IPSEC_ID_FQDN: + return -1; + + case IPSEC_ID_USER_FQDN: + return -1; +#endif + + case IPSEC_ID_IPV4_ADDR_SUBNET: + case IPSEC_ID_IPV6_ADDR_SUBNET: { + int ret; + + address = conf_get_str(section, "Network"); + if (!address) { + log_print("ipsec_get_id: section %s has no " + "\"Network\" tag", section); + return -1; + } + if (text2sockaddr(address, NULL, addr)) { + log_print("ipsec_get_id: invalid section %s " + "network %s", section, address); + return -1; + } + netmask = conf_get_str(section, "Netmask"); + if (!netmask) { + log_print("ipsec_get_id: section %s has no " + "\"Netmask\" tag", section); + free(*addr); + return -1; + } + if (text2sockaddr(netmask, NULL, mask)) { + log_print("ipsec_id_build: invalid section %s " + "network %s", section, netmask); + free(*addr); + return -1; + } + ret = ipsec_get_proto_port(section, tproto, port); + if (ret < 0) { + free(*mask); + free(*addr); + } + return ret; + } + +#ifdef notyet + case IPSEC_ID_IPV4_RANGE: + return -1; + + case IPSEC_ID_IPV6_RANGE: + return -1; + + case IPSEC_ID_DER_ASN1_DN: + return -1; + + case IPSEC_ID_DER_ASN1_GN: + return -1; + + case IPSEC_ID_KEY_ID: + return -1; +#endif + + default: + log_print("ipsec_get_id: unknown ID type \"%s\" in " + "section %s", type, section); + return -1; + } + + return 0; +} + +/* + * XXX I rather want this function to return a status code, and fail if + * we cannot fit the information in the supplied buffer. + */ +static void +ipsec_decode_id(char *buf, size_t size, u_int8_t *id, size_t id_len, + int isakmpform) +{ + int id_type; + char *addr = 0, *mask = 0; + u_int32_t *idp; + + if (id) { + if (!isakmpform) { + /* + * Exchanges and SAs dont carry the IDs in ISAKMP + * form. + */ + id -= ISAKMP_GEN_SZ; + id_len += ISAKMP_GEN_SZ; + } + id_type = GET_ISAKMP_ID_TYPE(id); + idp = (u_int32_t *) (id + ISAKMP_ID_DATA_OFF); + switch (id_type) { + case IPSEC_ID_IPV4_ADDR: + util_ntoa(&addr, AF_INET, id + ISAKMP_ID_DATA_OFF); + snprintf(buf, size, "%08x: %s", + decode_32(id + ISAKMP_ID_DATA_OFF), addr); + break; + + case IPSEC_ID_IPV4_ADDR_SUBNET: + util_ntoa(&addr, AF_INET, id + ISAKMP_ID_DATA_OFF); + util_ntoa(&mask, AF_INET, id + ISAKMP_ID_DATA_OFF + 4); + snprintf(buf, size, "%08x/%08x: %s/%s", + decode_32(id + ISAKMP_ID_DATA_OFF), + decode_32(id + ISAKMP_ID_DATA_OFF + 4), addr, mask); + break; + + case IPSEC_ID_IPV6_ADDR: + util_ntoa(&addr, AF_INET6, id + ISAKMP_ID_DATA_OFF); + snprintf(buf, size, "%08x%08x%08x%08x: %s", *idp, + *(idp + 1), *(idp + 2), *(idp + 3), addr); + break; + + case IPSEC_ID_IPV6_ADDR_SUBNET: + util_ntoa(&addr, AF_INET6, id + ISAKMP_ID_DATA_OFF); + util_ntoa(&mask, AF_INET6, id + ISAKMP_ID_DATA_OFF + + sizeof(struct in6_addr)); + snprintf(buf, size, + "%08x%08x%08x%08x/%08x%08x%08x%08x: %s/%s", *idp, + *(idp + 1), *(idp + 2), *(idp + 3), *(idp + 4), + *(idp + 5), *(idp + 6), *(idp + 7), addr, mask); + break; + + case IPSEC_ID_FQDN: + case IPSEC_ID_USER_FQDN: + /* String is not NUL terminated, be careful */ + id_len -= ISAKMP_ID_DATA_OFF; + id_len = MIN(id_len, size - 1); + memcpy(buf, id + ISAKMP_ID_DATA_OFF, id_len); + buf[id_len] = '\0'; + break; + +#ifdef USE_X509 + case IPSEC_ID_DER_ASN1_DN: + addr = x509_DN_string(id + ISAKMP_ID_DATA_OFF, + id_len - ISAKMP_ID_DATA_OFF); + if (!addr) { + snprintf(buf, size, "unparsable ASN1 DN ID"); + return; + } + strlcpy(buf, addr, size); + break; +#endif + + default: + snprintf(buf, size, "<id type unknown: %x>", id_type); + break; + } + } else + snprintf(buf, size, "<no ipsec id>"); + if (addr) + free(addr); + if (mask) + free(mask); +} + +char * +ipsec_decode_ids(char *fmt, u_int8_t *id1, size_t id1_len, u_int8_t *id2, + size_t id2_len, int isakmpform) +{ + static char result[1024]; + char s_id1[256], s_id2[256]; + + ipsec_decode_id(s_id1, sizeof s_id1, id1, id1_len, isakmpform); + ipsec_decode_id(s_id2, sizeof s_id2, id2, id2_len, isakmpform); + + snprintf(result, sizeof result, fmt, s_id1, s_id2); + return result; +} + +/* + * Out of a named section SECTION in the configuration file build an + * ISAKMP ID payload. Ths payload size should be stashed in SZ. + * The caller is responsible for freeing the payload. + */ +u_int8_t * +ipsec_build_id(char *section, size_t *sz) +{ + struct sockaddr *addr, *mask; + u_int8_t *p; + int id, subnet = 0; + u_int8_t tproto = 0; + u_int16_t port = 0; + + if (ipsec_get_id(section, &id, &addr, &mask, &tproto, &port)) + return 0; + + if (id == IPSEC_ID_IPV4_ADDR_SUBNET || id == IPSEC_ID_IPV6_ADDR_SUBNET) + subnet = 1; + + *sz = ISAKMP_ID_SZ + sockaddr_addrlen(addr); + if (subnet) + *sz += sockaddr_addrlen(mask); + + p = malloc(*sz); + if (!p) { + log_print("ipsec_build_id: malloc(%lu) failed", + (unsigned long)*sz); + if (subnet) + free(mask); + free(addr); + return 0; + } + SET_ISAKMP_ID_TYPE(p, id); + SET_ISAKMP_ID_DOI_DATA(p, (unsigned char *)"\000\000\000"); + + memcpy(p + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(addr), + sockaddr_addrlen(addr)); + if (subnet) + memcpy(p + ISAKMP_ID_DATA_OFF + sockaddr_addrlen(addr), + sockaddr_addrdata(mask), sockaddr_addrlen(mask)); + + SET_IPSEC_ID_PROTO(p + ISAKMP_ID_DOI_DATA_OFF, tproto); + SET_IPSEC_ID_PORT(p + ISAKMP_ID_DOI_DATA_OFF, port); + + if (subnet) + free(mask); + free(addr); + return p; +} + +/* + * copy an ISAKMPD id + */ +int +ipsec_clone_id(u_int8_t **did, size_t *did_len, u_int8_t *id, size_t id_len) +{ + if (*did) + free(*did); + + if (!id_len || !id) { + *did = 0; + *did_len = 0; + return 0; + } + *did = malloc(id_len); + if (!*did) { + *did_len = 0; + log_error("ipsec_clone_id: malloc(%lu) failed", + (unsigned long)id_len); + return -1; + } + *did_len = id_len; + memcpy(*did, id, id_len); + + return 0; +} + +/* + * IPsec-specific PROTO initializations. SECTION is only set if we are the + * initiator thus only usable there. + * XXX I want to fix this later. + */ +void +ipsec_proto_init(struct proto *proto, char *section) +{ + struct ipsec_proto *iproto = proto->data; + + if (proto->sa->phase == 2) + iproto->replay_window = section ? conf_get_num(section, + "ReplayWindow", DEFAULT_REPLAY_WINDOW) : + DEFAULT_REPLAY_WINDOW; +} + +/* + * Add a notification payload of type INITIAL CONTACT to MSG if this is + * the first contact we have made to our peer. + */ +int +ipsec_initial_contact(struct message *msg) +{ + u_int8_t *buf; + + if (ipsec_contacted(msg)) + return 0; + + buf = malloc(ISAKMP_NOTIFY_SZ + ISAKMP_HDR_COOKIES_LEN); + if (!buf) { + log_error("ike_phase_1_initial_contact: malloc (%d) failed", + ISAKMP_NOTIFY_SZ + ISAKMP_HDR_COOKIES_LEN); + return -1; + } + SET_ISAKMP_NOTIFY_DOI(buf, IPSEC_DOI_IPSEC); + SET_ISAKMP_NOTIFY_PROTO(buf, ISAKMP_PROTO_ISAKMP); + SET_ISAKMP_NOTIFY_SPI_SZ(buf, ISAKMP_HDR_COOKIES_LEN); + SET_ISAKMP_NOTIFY_MSG_TYPE(buf, IPSEC_NOTIFY_INITIAL_CONTACT); + memcpy(buf + ISAKMP_NOTIFY_SPI_OFF, msg->isakmp_sa->cookies, + ISAKMP_HDR_COOKIES_LEN); + if (message_add_payload(msg, ISAKMP_PAYLOAD_NOTIFY, buf, + ISAKMP_NOTIFY_SZ + ISAKMP_HDR_COOKIES_LEN, 1)) { + free(buf); + return -1; + } + return ipsec_add_contact(msg); +} + +/* + * Compare the two contacts pointed to by A and B. Return negative if + * *A < *B, 0 if they are equal, and positive if *A is the largest of them. + */ +static int +addr_cmp(const void *a, const void *b) +{ + const struct contact *x = a, *y = b; + int minlen = MIN(x->len, y->len); + int rv = memcmp(x->addr, y->addr, minlen); + + return rv ? rv : (x->len - y->len); +} + +/* + * Add the peer that MSG is bound to as an address we don't want to send + * INITIAL CONTACT too from now on. Do not call this function with a + * specific address duplicate times. We want fast lookup, speed of insertion + * is unimportant, if this is to scale. + */ +static int +ipsec_add_contact(struct message *msg) +{ + struct contact *new_contacts; + struct sockaddr *dst, *addr; + int cnt; + + if (contact_cnt == contact_limit) { + cnt = contact_limit ? 2 * contact_limit : 64; + new_contacts = realloc(contacts, cnt * sizeof contacts[0]); + if (!new_contacts) { + log_error("ipsec_add_contact: " + "realloc (%p, %lu) failed", contacts, + cnt * (unsigned long) sizeof contacts[0]); + return -1; + } + contact_limit = cnt; + contacts = new_contacts; + } + msg->transport->vtbl->get_dst(msg->transport, &dst); + addr = malloc(sysdep_sa_len(dst)); + if (!addr) { + log_error("ipsec_add_contact: malloc (%d) failed", + sysdep_sa_len(dst)); + return -1; + } + memcpy(addr, dst, sysdep_sa_len(dst)); + contacts[contact_cnt].addr = addr; + contacts[contact_cnt++].len = sysdep_sa_len(dst); + + /* + * XXX There are better algorithms for already mostly-sorted data like + * this, but only qsort is standard. I will someday do this inline. + */ + qsort(contacts, contact_cnt, sizeof *contacts, addr_cmp); + return 0; +} + +/* Return true if the recipient of MSG has already been contacted. */ +static int +ipsec_contacted(struct message *msg) +{ + struct contact contact; + + msg->transport->vtbl->get_dst(msg->transport, &contact.addr); + contact.len = sysdep_sa_len(contact.addr); + return contacts ? (bsearch(&contact, contacts, contact_cnt, + sizeof *contacts, addr_cmp) != 0) : 0; +} + +/* Add a HASH for to MSG. */ +u_int8_t * +ipsec_add_hash_payload(struct message *msg, size_t hashsize) +{ + u_int8_t *buf; + + buf = malloc(ISAKMP_HASH_SZ + hashsize); + if (!buf) { + log_error("ipsec_add_hash_payload: malloc (%lu) failed", + ISAKMP_HASH_SZ + (unsigned long) hashsize); + return 0; + } + if (message_add_payload(msg, ISAKMP_PAYLOAD_HASH, buf, + ISAKMP_HASH_SZ + hashsize, 1)) { + free(buf); + return 0; + } + return buf; +} + +/* Fill in the HASH payload of MSG. */ +int +ipsec_fill_in_hash(struct message *msg) +{ + struct exchange *exchange = msg->exchange; + struct sa *isakmp_sa = msg->isakmp_sa; + struct ipsec_sa *isa = isakmp_sa->data; + struct hash *hash = hash_get(isa->hash); + struct prf *prf; + struct payload *payload; + u_int8_t *buf; + u_int32_t i; + char header[80]; + + /* If no SKEYID_a, we need not do anything. */ + if (!isa->skeyid_a) + return 0; + + payload = payload_first(msg, ISAKMP_PAYLOAD_HASH); + if (!payload) { + log_print("ipsec_fill_in_hash: no HASH payload found"); + return -1; + } + buf = payload->p; + + /* Allocate the prf and start calculating our HASH(1). */ + LOG_DBG_BUF((LOG_MISC, 90, "ipsec_fill_in_hash: SKEYID_a", + isa->skeyid_a, isa->skeyid_len)); + prf = prf_alloc(isa->prf_type, hash->type, isa->skeyid_a, + isa->skeyid_len); + if (!prf) + return -1; + + prf->Init(prf->prfctx); + LOG_DBG_BUF((LOG_MISC, 90, "ipsec_fill_in_hash: 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, sizeof header, + "ipsec_fill_in_hash: payload %d after HASH(1)", i - 1); + LOG_DBG_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_DBG_BUF((LOG_MISC, 80, "ipsec_fill_in_hash: HASH(1)", buf + + ISAKMP_HASH_DATA_OFF, hash->hashsize)); + + return 0; +} + +/* Add a HASH payload to MSG, if we have an ISAKMP SA we're protected by. */ +static int +ipsec_informational_pre_hook(struct message *msg) +{ + struct sa *isakmp_sa = msg->isakmp_sa; + struct ipsec_sa *isa; + struct hash *hash; + + if (!isakmp_sa) + return 0; + isa = isakmp_sa->data; + hash = hash_get(isa->hash); + return ipsec_add_hash_payload(msg, hash->hashsize) == 0; +} + +/* + * Fill in the HASH payload in MSG, if we have an ISAKMP SA we're protected by. + */ +static int +ipsec_informational_post_hook(struct message *msg) +{ + if (!msg->isakmp_sa) + return 0; + return ipsec_fill_in_hash(msg); +} + +ssize_t +ipsec_id_size(char *section, u_int8_t *id) +{ + char *type, *data; + + type = conf_get_str(section, "ID-type"); + if (!type) { + log_print("ipsec_id_size: section %s has no \"ID-type\" tag", + section); + return -1; + } + *id = constant_value(ipsec_id_cst, type); + switch (*id) { + case IPSEC_ID_IPV4_ADDR: + return sizeof(struct in_addr); + case IPSEC_ID_IPV4_ADDR_SUBNET: + return 2 * sizeof(struct in_addr); + case IPSEC_ID_IPV6_ADDR: + return sizeof(struct in6_addr); + case IPSEC_ID_IPV6_ADDR_SUBNET: + return 2 * sizeof(struct in6_addr); + case IPSEC_ID_FQDN: + case IPSEC_ID_USER_FQDN: + case IPSEC_ID_KEY_ID: + case IPSEC_ID_DER_ASN1_DN: + case IPSEC_ID_DER_ASN1_GN: + data = conf_get_str(section, "Name"); + if (!data) { + log_print("ipsec_id_size: " + "section %s has no \"Name\" tag", section); + return -1; + } + return strlen(data); + } + log_print("ipsec_id_size: unrecognized/unsupported ID-type %d (%s)", + *id, type); + return -1; +} + +/* + * Generate a string version of the ID. + */ +char * +ipsec_id_string(u_int8_t *id, size_t id_len) +{ + char *buf = 0; + char *addrstr = 0; + size_t len, size; + + /* + * XXX Real ugly way of making the offsets correct. Be aware that id + * now will point before the actual buffer and cannot be dereferenced + * without an offset larger than or equal to ISAKM_GEN_SZ. + */ + id -= ISAKMP_GEN_SZ; + + /* This is the actual length of the ID data field. */ + id_len += ISAKMP_GEN_SZ - ISAKMP_ID_DATA_OFF; + + /* + * Conservative allocation. + * XXX I think the ASN1 DN case can be thought through to give a better + * estimate. + */ + size = MAX(sizeof "ipv6/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + sizeof "asn1_dn/" + id_len - ISAKMP_ID_DATA_OFF); + buf = malloc(size); + if (!buf) + /* XXX Log? */ + goto fail; + + switch (GET_ISAKMP_ID_TYPE(id)) { + case IPSEC_ID_IPV4_ADDR: + if (id_len < sizeof(struct in_addr)) + goto fail; + util_ntoa(&addrstr, AF_INET, id + ISAKMP_ID_DATA_OFF); + if (!addrstr) + goto fail; + snprintf(buf, size, "ipv4/%s", addrstr); + break; + + case IPSEC_ID_IPV6_ADDR: + if (id_len < sizeof(struct in6_addr)) + goto fail; + util_ntoa(&addrstr, AF_INET6, id + ISAKMP_ID_DATA_OFF); + if (!addrstr) + goto fail; + snprintf(buf, size, "ipv6/%s", addrstr); + break; + + case IPSEC_ID_FQDN: + case IPSEC_ID_USER_FQDN: + strlcpy(buf, + GET_ISAKMP_ID_TYPE(id) == IPSEC_ID_FQDN ? "fqdn/" : "ufqdn/", + size); + len = strlen(buf); + + memcpy(buf + len, id + ISAKMP_ID_DATA_OFF, id_len); + *(buf + len + id_len) = '\0'; + break; + +#ifdef USE_X509 + case IPSEC_ID_DER_ASN1_DN: + strlcpy(buf, "asn1_dn/", size); + len = strlen(buf); + addrstr = x509_DN_string(id + ISAKMP_ID_DATA_OFF, + id_len - ISAKMP_ID_DATA_OFF); + if (!addrstr) + goto fail; + if (size < len + strlen(addrstr) + 1) + goto fail; + strlcpy(buf + len, addrstr, size - len); + break; +#endif + + default: + /* Unknown type. */ + LOG_DBG((LOG_MISC, 10, + "ipsec_id_string: unknown identity type %d\n", + GET_ISAKMP_ID_TYPE(id))); + goto fail; + } + + if (addrstr) + free(addrstr); + return buf; + +fail: + if (buf) + free(buf); + if (addrstr) + free(addrstr); + return 0; +} diff --git a/keyexchange/isakmpd-20041012/ipsec.h b/keyexchange/isakmpd-20041012/ipsec.h new file mode 100644 index 0000000..1b3c996 --- /dev/null +++ b/keyexchange/isakmpd-20041012/ipsec.h @@ -0,0 +1,173 @@ +/* $OpenBSD: ipsec.h,v 1.24 2004/05/23 18:17:56 hshoexer Exp $ */ +/* $EOM: ipsec.h,v 1.42 2000/12/03 07:58:20 angelos Exp $ */ + +/* + * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 1999 Angelos D. Keromytis. All rights reserved. + * Copyright (c) 2001 Håkan Olsson. 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. + * + * 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 <sys/queue.h> +#include <sys/types.h> +#include <netinet/in.h> + +#include "ipsec_doi.h" +#ifdef USE_ISAKMP_CFG +#include "isakmp_cfg.h" +#endif + +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 several different structs, one for each kind + * of exchange, i.e. phase 1, phase 2 and ISAKMP configuration parameters + * separated. + */ +struct ipsec_exch { + u_int flags; + struct hash *hash; + struct ike_auth *ike_auth; + struct group *group; + u_int16_t prf_type; + + /* 0 if no KEY_EXCH was proposed, 1 otherwise */ + u_int8_t pfs; + + /* + * 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; + + /* Phase 2. */ + u_int8_t *id_ci; + size_t id_ci_sz; + u_int8_t *id_cr; + size_t id_cr_sz; + +#ifdef USE_ISAKMP_CFG + /* ISAKMP configuration mode parameters */ + u_int16_t cfg_id; + u_int16_t cfg_type; + LIST_HEAD(isakmp_cfg_attr_head, isakmp_cfg_attr) attrs; +#endif +}; + +#define IPSEC_EXCH_FLAG_NO_ID 1 + +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; + + /* Tunnel parameters. These are in network byte order. */ + struct sockaddr *src_net; + struct sockaddr *src_mask; + struct sockaddr *dst_net; + struct sockaddr *dst_mask; + u_int8_t tproto; + u_int16_t sport; + u_int16_t dport; +}; + +struct ipsec_proto { + /* Phase 2. */ + u_int16_t encap_mode; + u_int16_t auth; + u_int16_t keylen; + u_int16_t keyrounds; + + /* This is not negotiated, but rather configured. */ + int32_t replay_window; + + /* KEYMAT */ + u_int8_t *keymat[2]; +}; + +extern u_int8_t *ipsec_add_hash_payload(struct message *, size_t); +extern int ipsec_ah_keylength(struct proto *); +extern u_int8_t *ipsec_build_id(char *, size_t *); +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_fill_in_hash(struct message *); +extern int ipsec_gen_g_x(struct message *); +extern int ipsec_get_id(char *, int *, struct sockaddr **, + struct sockaddr **, u_int8_t *, u_int16_t *); +extern ssize_t ipsec_id_size(char *, u_int8_t *); +extern char *ipsec_id_string(u_int8_t *, size_t); +extern void ipsec_init(void); +extern int ipsec_initial_contact(struct message *); +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 *); +extern struct sa *ipsec_sa_lookup(struct sockaddr *, u_int32_t, u_int8_t); + +extern char *ipsec_decode_ids(char *, u_int8_t *, size_t, u_int8_t *, + size_t, int); +extern int ipsec_clone_id(u_int8_t **, size_t *, u_int8_t *, size_t); + +#endif /* _IPSEC_H_ */ diff --git a/keyexchange/isakmpd-20041012/ipsec_doi.h b/keyexchange/isakmpd-20041012/ipsec_doi.h new file mode 100644 index 0000000..c7000c7 --- /dev/null +++ b/keyexchange/isakmpd-20041012/ipsec_doi.h @@ -0,0 +1,44 @@ +/* $OpenBSD: ipsec_doi.h,v 1.8 2004/04/15 18:39:25 deraadt Exp $ */ +/* $EOM: ipsec_doi.h,v 1.10 1999/04/02 00:57:51 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999 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. + * + * 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 + +/* The low limit if valid SPI values. */ +#define IPSEC_SPI_LOW 0x100 + +#endif /* _IPSEC_DOI_H_ */ diff --git a/keyexchange/isakmpd-20041012/ipsec_fld.fld b/keyexchange/isakmpd-20041012/ipsec_fld.fld new file mode 100644 index 0000000..8dfd0ef --- /dev/null +++ b/keyexchange/isakmpd-20041012/ipsec_fld.fld @@ -0,0 +1,60 @@ +# $OpenBSD: ipsec_fld.fld,v 1.5 2003/06/03 14:28:16 ho Exp $ +# $EOM: ipsec_fld.fld,v 1.1 1998/08/02 20:12:02 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. +# +# 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/keyexchange/isakmpd-20041012/ipsec_num.cst b/keyexchange/isakmpd-20041012/ipsec_num.cst new file mode 100644 index 0000000..9105550 --- /dev/null +++ b/keyexchange/isakmpd-20041012/ipsec_num.cst @@ -0,0 +1,264 @@ +# $OpenBSD: ipsec_num.cst,v 1.15 2004/04/28 14:40:00 ho Exp $ +# $EOM: ipsec_num.cst,v 1.5 2000/10/13 17:56:52 angelos Exp $ + +# +# Copyright (c) 1998 Niklas Hallqvist. All rights reserved. +# Copyright (c) 2003 Håkan Olsson. 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. +# +# 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 + ECN_TUNNEL 10 +. + +# IPSEC SA duration. +IPSEC_DURATION + SECONDS 1 + KILOBYTES 2 +. + +# IPSEC encapsulation mode. +IPSEC_ENCAP + TUNNEL 1 + TRANSPORT 2 + UDP_ENCAP_TUNNEL 3 + UDP_ENCAP_TRANSPORT 4 + UDP_ENCAP_TUNNEL_DRAFT 61443 # draft-ietf-ipsec-nat-t-ike + UDP_ENCAP_TRANSPORT_DRAFT 61443 # draft-ietf-ipsec-nat-t-ike +. + +# IPSEC authentication algorithm. +IPSEC_AUTH + HMAC_MD5 1 + HMAC_SHA 2 + DES_MAC 3 + KPDK 4 + HMAC_SHA2_256 5 + HMAC_SHA2_384 6 + HMAC_SHA2_512 7 + HMAC_RIPEMD 8 +. + +# 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 ike_encrypt_cst + HASH_ALGORITHM 2 ike_hash_cst + AUTHENTICATION_METHOD 3 ike_auth_cst + GROUP_DESCRIPTION 4 ike_group_desc_cst + GROUP_TYPE 5 ike_group_cst + GROUP_PRIME 6 + GROUP_GENERATOR_1 7 + GROUP_GENERATOR_2 8 + GROUP_CURVE_A 9 + GROUP_CURVE_B 10 + LIFE_TYPE 11 ike_duration_cst + LIFE_DURATION 12 + PRF 13 ike_prf_cst + KEY_LENGTH 14 + FIELD_SIZE 15 + GROUP_ORDER 16 + BLOCK_SIZE 17 +. + +# 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 + AES_CBC 7 +. + +# IKE hash algorithm. +IKE_HASH + MD5 1 + SHA 2 + TIGER 3 + SHA2_256 4 + SHA2_384 5 + SHA2_512 6 +. + +# IKE authentication method. +IKE_AUTH + PRE_SHARED 1 + DSS 2 + RSA_SIG 3 + RSA_ENC 4 + RSA_ENC_REV 5 + EL_GAMAL_ENC 6 + EL_GAMAL_ENC_REV 7 + ECDSA_SIG 8 +. + +# IKE group description. +IKE_GROUP_DESC + MODP_768 1 + MODP_1024 2 + EC2N_155 3 + EC2N_185 4 + MODP_1536 5 + EC2N_163sect 6 + EC2N_163K 7 + EC2N_283sect 8 + EC2N_283K 9 + EC2N_409sect 10 + EC2N_409K 11 + EC2N_571sect 12 + EC2N_571K 13 + MODP_2048 14 + MODP_3072 15 + MODP_4096 16 + MODP_6144 17 + MODP_8192 18 +. + +# 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 + SHA2_256 5 + SHA2_384 6 + SHA2_512 7 + RIPEMD 8 +. + +# 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 + AES 12 + AES_128_CTR 13 + AES_MARS 249 + AES_RC6 250 + AES_RIJNDAEL 251 + AES_SERPENT 252 + AES_TWOFISH 253 +. + +# 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/keyexchange/isakmpd-20041012/isakmp.h b/keyexchange/isakmpd-20041012/isakmp.h new file mode 100644 index 0000000..4ab6869 --- /dev/null +++ b/keyexchange/isakmpd-20041012/isakmp.h @@ -0,0 +1,64 @@ +/* $OpenBSD: isakmp.h,v 1.7 2004/06/20 15:24:05 ho Exp $ */ +/* $EOM: isakmp.h,v 1.11 2000/07/05 10:48:43 ho Exp $ */ + +/* + * Copyright (c) 1998 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2004 Håkan Olsson. 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. + * + * 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 +#define UDP_DEFAULT_PORT_STR "500" + +#define ISAKMP_DEFAULT_TRANSPORT "udp" + +/* draft-ietf-ipsec-nat-t-ike-07.txt */ +#define UDP_ENCAP_DEFAULT_PORT 4500 +#define UDP_ENCAP_DEFAULT_PORT_STR "4500" + +/* 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/keyexchange/isakmpd-20041012/isakmp_cfg.c b/keyexchange/isakmpd-20041012/isakmp_cfg.c new file mode 100644 index 0000000..222d0c6 --- /dev/null +++ b/keyexchange/isakmpd-20041012/isakmp_cfg.c @@ -0,0 +1,982 @@ +/* $OpenBSD: isakmp_cfg.c,v 1.34 2004/08/08 19:11:06 deraadt Exp $ */ + +/* + * Copyright (c) 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2002 Håkan Olsson. 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. + * + * 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 Gatespace + * (http://www.gatespace.com/). + */ + +#include <sys/types.h> +#include <stdlib.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <string.h> +#include <bitstring.h> + +#include "sysdep.h" + +#include "attribute.h" +#include "conf.h" +#include "exchange.h" +#include "hash.h" +#include "ipsec.h" +#include "isakmp_fld.h" +#include "isakmp_num.h" +#include "log.h" +#include "message.h" +#include "prf.h" +#include "sa.h" +#include "transport.h" +#include "util.h" + +/* + * Validation script used to test messages for correct content of + * payloads depending on the exchange type. + */ +int16_t script_transaction[] = { + ISAKMP_PAYLOAD_ATTRIBUTE, /* Initiator -> responder. */ + EXCHANGE_SCRIPT_SWITCH, + ISAKMP_PAYLOAD_ATTRIBUTE, /* Responder -> initiator. */ + EXCHANGE_SCRIPT_END +}; + +static int cfg_decode_attribute(u_int16_t, u_int8_t *, u_int16_t, void *); +static int cfg_encode_attributes(struct isakmp_cfg_attr_head *, u_int32_t, + u_int32_t, char *, u_int8_t **, u_int16_t *); +static int cfg_initiator_send_ATTR(struct message *); +static int cfg_initiator_recv_ATTR(struct message *); +static int cfg_responder_recv_ATTR(struct message *); +static int cfg_responder_send_ATTR(struct message *); + +u_int8_t *cfg_add_hash(struct message *); +int cfg_finalize_hash(struct message *, u_int8_t *, u_int8_t *, + u_int16_t); +int cfg_verify_hash(struct message *); + +/* Server: SET/ACK Client; REQ/REPLY */ +int (*isakmp_cfg_initiator[]) (struct message *) = { + cfg_initiator_send_ATTR, + cfg_initiator_recv_ATTR +}; + +/* Server: REQ/REPLY Client: SET/ACK */ +int (*isakmp_cfg_responder[]) (struct message *) = { + cfg_responder_recv_ATTR, + cfg_responder_send_ATTR +}; + +/* + * When we are "the server", this starts SET/ACK mode + * When we are "the client", this starts REQ/REPLY mode + */ +static int +cfg_initiator_send_ATTR(struct message *msg) +{ + struct sa *isakmp_sa = msg->isakmp_sa; + struct ipsec_exch *ie = msg->exchange->data; + u_int8_t *hashp = 0, *attrp, *attr; + size_t attrlen, off; + char *id_string, *cfg_mode, *field; + struct sockaddr *sa; +#define CFG_ATTR_BIT_MAX ISAKMP_CFG_ATTR_FUTURE_MIN /* XXX */ + bitstr_t bit_decl(attrbits, CFG_ATTR_BIT_MAX); + u_int16_t bit, length; + u_int32_t life; + + if (msg->exchange->phase == 2) { + hashp = cfg_add_hash(msg); + if (!hashp) + return -1; + } + /* We initiated this exchange, check isakmp_sa for other side. */ + if (isakmp_sa->initiator) + id_string = ipsec_id_string(isakmp_sa->id_r, + isakmp_sa->id_r_len); + else + id_string = ipsec_id_string(isakmp_sa->id_i, + isakmp_sa->id_i_len); + if (!id_string) { + log_print("cfg_initiator_send_ATTR: cannot parse ID"); + goto fail; + } + /* Check for attribute list to send to the other side */ + attrlen = 0; + bit_nclear(attrbits, 0, CFG_ATTR_BIT_MAX - 1); + + cfg_mode = conf_get_str(id_string, "Mode"); + if (!cfg_mode || strcmp(cfg_mode, "SET") == 0) { + /* SET/ACK mode */ + ie->cfg_type = ISAKMP_CFG_SET; + + LOG_DBG((LOG_NEGOTIATION, 10, + "cfg_initiator_send_ATTR: SET/ACK mode")); + +#define ATTRFIND(STR,ATTR4,LEN4,ATTR6,LEN6) do \ + { \ + if ((sa = conf_get_address (id_string, STR)) != NULL) \ + switch (sa->sa_family) { \ + case AF_INET: \ + bit_set (attrbits, ATTR4); \ + attrlen += ISAKMP_ATTR_SZ + LEN4; \ + break; \ + case AF_INET6: \ + bit_set (attrbits, ATTR6); \ + attrlen += ISAKMP_ATTR_SZ + LEN6; \ + break; \ + default: \ + break; \ + } \ + free (sa); \ + } while (0) + + /* + * XXX We don't simultaneously support IPv4 and IPv6 + * addresses. + */ + ATTRFIND("Address", ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS, 4, + ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS, 16); + ATTRFIND("Netmask", ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK, 4, + ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK, 16); + ATTRFIND("Nameserver", ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS, 4, + ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS, 16); + ATTRFIND("WINS-server", ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS, 4, + ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS, 16); + ATTRFIND("DHCP-server", ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP, 4, + ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP, 16); +#ifdef notyet + ATTRFIND("Network", ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET, 8, + ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET, 17); +#endif +#undef ATTRFIND + + if (conf_get_str(id_string, "Lifetime")) { + bit_set(attrbits, + ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY); + attrlen += ISAKMP_ATTR_SZ + 4; + } + } else { + struct conf_list *alist; + struct conf_list_node *anode; + + ie->cfg_type = ISAKMP_CFG_REQUEST; + + LOG_DBG((LOG_NEGOTIATION, 10, + "cfg_initiator_send_ATTR: REQ/REPLY mode")); + + alist = conf_get_list(id_string, "Attributes"); + if (alist) { + for (anode = TAILQ_FIRST(&alist->fields); anode; + anode = TAILQ_NEXT(anode, link)) { + if (strcasecmp(anode->field, "Address") == 0) { + bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS); + bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS); + attrlen += ISAKMP_ATTR_SZ * 2; + } else if (strcasecmp(anode->field, "Netmask") + == 0) { + bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK); + bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK); + attrlen += ISAKMP_ATTR_SZ * 2; + } else if (strcasecmp(anode->field, + "Nameserver") == 0) { + bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS); + bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS); + attrlen += ISAKMP_ATTR_SZ * 2; + } else if (strcasecmp(anode->field, + "WINS-server") == 0) { + bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS); + bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS); + attrlen += ISAKMP_ATTR_SZ * 2; + } else if (strcasecmp(anode->field, + "DHCP-server") == 0) { + bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP); + bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP); + attrlen += ISAKMP_ATTR_SZ * 2; + } else if (strcasecmp(anode->field, + "Lifetime") == 0) { + bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY); + attrlen += ISAKMP_ATTR_SZ; + } else { + log_print("cfg_initiator_send_ATTR: " + "unknown attribute %.20s in " + "section [%s]", anode->field, + id_string); + } + } + + conf_free_list(alist); + } + } + + if (attrlen == 0) { + /* No data found. */ + log_print("cfg_initiator_send_ATTR: no IKECFG attributes " + "found for [%s]", id_string); + + /* + * We can continue, but this indicates a configuration error + * that the user probably will want to correct. + */ + free(id_string); + return 0; + } + attrlen += ISAKMP_ATTRIBUTE_SZ; + attrp = calloc(1, attrlen); + if (!attrp) { + log_error("cfg_initiator_send_ATTR: calloc (1, %lu) failed", + (unsigned long)attrlen); + goto fail; + } + if (message_add_payload(msg, ISAKMP_PAYLOAD_ATTRIBUTE, attrp, attrlen, + 1)) { + free(attrp); + goto fail; + } + SET_ISAKMP_ATTRIBUTE_TYPE(attrp, ie->cfg_type); + getrandom((u_int8_t *) & ie->cfg_id, sizeof ie->cfg_id); + SET_ISAKMP_ATTRIBUTE_ID(attrp, ie->cfg_id); + + off = ISAKMP_ATTRIBUTE_SZ; + + /* + * Use the bitstring built previously to collect the right + * parameters for attrp. + */ + for (bit = 0; bit < CFG_ATTR_BIT_MAX; bit++) + if (bit_test(attrbits, bit)) { + attr = attrp + off; + SET_ISAKMP_ATTR_TYPE(attr, bit); + + if (ie->cfg_type == ISAKMP_CFG_REQUEST) { + off += ISAKMP_ATTR_SZ; + continue; + } + /* All the other are similar, this is the odd one. */ + if (bit == ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY) { + life = conf_get_num(id_string, "Lifetime", + 1200); + SET_ISAKMP_ATTR_LENGTH_VALUE(attr, 4); + encode_32(attr + ISAKMP_ATTR_VALUE_OFF, life); + off += ISAKMP_ATTR_SZ + 4; + continue; + } + switch (bit) { + case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: + case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: + case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: + case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: + case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: + length = 4; + break; + + case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: + length = 16; + break; + + default: + length = 0; /* Silence gcc. */ + } + + switch (bit) { + case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: + field = "Address"; + break; + case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: + field = "Netmask"; + break; + case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: + field = "Nameserver"; + break; + case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: + field = "DHCP-server"; + break; + case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: + field = "WINS-server"; + break; + default: + field = 0; /* Silence gcc. */ + } + + sa = conf_get_address(id_string, field); + + SET_ISAKMP_ATTR_LENGTH_VALUE(attr, length); + memcpy(attr + ISAKMP_ATTR_VALUE_OFF, + sockaddr_addrdata(sa), length); + + free(sa); + + off += ISAKMP_ATTR_SZ + length; + } + if (msg->exchange->phase == 2) + if (cfg_finalize_hash(msg, hashp, attrp, attrlen)) + goto fail; + + return 0; + +fail: + if (id_string) + free(id_string); + return -1; +} + +/* + * As "the server", this ends SET/ACK. + * As "the client", this ends REQ/REPLY. + */ +static int +cfg_initiator_recv_ATTR(struct message *msg) +{ + struct payload *attrp = payload_first(msg, ISAKMP_PAYLOAD_ATTRIBUTE); + struct ipsec_exch *ie = msg->exchange->data; + struct sa *isakmp_sa = msg->isakmp_sa; + struct isakmp_cfg_attr *attr; + struct sockaddr *sa; + const char *uk_addr = "<unknown>"; + char *addr; + + if (msg->exchange->phase == 2) + if (cfg_verify_hash(msg)) + return -1; + + /* Sanity. */ + if (ie->cfg_id != GET_ISAKMP_ATTRIBUTE_ID(attrp->p)) { + log_print("cfg_initiator_recv_ATTR: " + "cfg packet ID does not match!"); + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); + return -1; + } + switch (attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF]) { + case ISAKMP_CFG_ACK: + if (ie->cfg_type != ISAKMP_CFG_SET) { + log_print("cfg_initiator_recv_ATTR: " + "bad packet type ACK"); + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, + 0, 1, 0); + return -1; + } + break; + case ISAKMP_CFG_REPLY: + if (ie->cfg_type != ISAKMP_CFG_REQUEST) { + log_print("cfg_initiator_recv_ATTR: " + "bad packet type REPLY"); + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, + 0, 1, 0); + return -1; + } + break; + + default: + log_print("cfg_initiator_recv_ATTR: unexpected configuration " + "message type %d", attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF]); + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); + return -1; + } + + attribute_map(attrp->p + ISAKMP_ATTRIBUTE_ATTRS_OFF, + GET_ISAKMP_GEN_LENGTH(attrp->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF, + cfg_decode_attribute, ie); + + switch (ie->cfg_type) { + case ISAKMP_CFG_ACK: { + /* SET/ACK -- Server side (ACK from client) */ + msg->transport->vtbl->get_src(isakmp_sa->transport, + &sa); + if (sockaddr2text(sa, &addr, 0) < 0) + addr = (char *) uk_addr; + + for (attr = LIST_FIRST(&ie->attrs); attr; + attr = LIST_NEXT(attr, link)) + LOG_DBG((LOG_NEGOTIATION, 50, + "cfg_initiator_recv_ATTR: " + "client %s ACKs attribute %s", addr, + constant_name(isakmp_cfg_attr_cst, + attr->type))); + + if (addr != uk_addr) + free(addr); + } + break; + + case ISAKMP_CFG_REPLY: { + /* + * REQ/REPLY: effect attributes we've gotten + * responses on. + */ + msg->transport->vtbl->get_src(isakmp_sa->transport, + &sa); + if (sockaddr2text(sa, &addr, 0) < 0) + addr = (char *) uk_addr; + + for (attr = LIST_FIRST(&ie->attrs); attr; + attr = LIST_NEXT(attr, link)) + LOG_DBG((LOG_NEGOTIATION, 50, + "cfg_initiator_recv_ATTR: " + "server %s replied with attribute %s", + addr, constant_name(isakmp_cfg_attr_cst, + attr->type))); + + if (addr != uk_addr) + free(addr); + } + break; + + default: + break; + } + + attrp->flags |= PL_MARK; + return 0; +} + +/* + * As "the server", this starts REQ/REPLY (initiated by the client). + * As "the client", this starts SET/ACK (initiated by the server). + */ +static int +cfg_responder_recv_ATTR(struct message *msg) +{ + struct payload *attrp = payload_first(msg, ISAKMP_PAYLOAD_ATTRIBUTE); + struct ipsec_exch *ie = msg->exchange->data; + struct sa *isakmp_sa = msg->isakmp_sa; + struct isakmp_cfg_attr *attr; + struct sockaddr *sa; + char *addr; + + if (msg->exchange->phase == 2) + if (cfg_verify_hash(msg)) + return -1; + + ie->cfg_id = GET_ISAKMP_ATTRIBUTE_ID(attrp->p); + ie->cfg_type = attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF]; + + switch (ie->cfg_type) { + case ISAKMP_CFG_REQUEST: + case ISAKMP_CFG_SET: + break; + + default: + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); + log_print("cfg_responder_recv_ATTR: " + "unexpected configuration message type %d", ie->cfg_type); + return -1; + } + + attribute_map(attrp->p + ISAKMP_ATTRIBUTE_ATTRS_OFF, + GET_ISAKMP_GEN_LENGTH(attrp->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF, + cfg_decode_attribute, ie); + + switch (ie->cfg_type) { + case ISAKMP_CFG_REQUEST: + /* We're done. */ + break; + + case ISAKMP_CFG_SET: { + /* SET/ACK -- Client side (SET from server) */ + const char *uk_addr = "<unknown>"; + + msg->transport->vtbl->get_dst(isakmp_sa->transport, + &sa); + if (sockaddr2text(sa, &addr, 0) < 0) + addr = (char *) uk_addr; + + for (attr = LIST_FIRST(&ie->attrs); attr; + attr = LIST_NEXT(attr, link)) + LOG_DBG((LOG_NEGOTIATION, 50, + "cfg_responder_recv_ATTR: " + "server %s asks us to SET attribute %s", + addr, constant_name(isakmp_cfg_attr_cst, + attr->type))); + + /* + * XXX Here's the place to add code to walk through + * XXX each attribute and send them along to dhclient + * XXX or whatever. Each attribute that we act upon + * XXX (such as setting a netmask), should be marked + * XXX like this for us to send the proper ACK + * XXX response: attr->attr_used++; + */ + + if (addr != uk_addr) + free(addr); + } + break; + + default: + break; + } + + attrp->flags |= PL_MARK; + return 0; +} + +/* + * As "the server", this ends REQ/REPLY mode. + * As "the client", this ends SET/ACK mode. + */ +static int +cfg_responder_send_ATTR(struct message *msg) +{ + struct ipsec_exch *ie = msg->exchange->data; + struct sa *isakmp_sa = msg->isakmp_sa; + u_int8_t *hashp = 0, *attrp; + u_int16_t attrlen; + char *id_string; + + if (msg->exchange->phase == 2) { + hashp = cfg_add_hash(msg); + if (!hashp) + return -1; + } + /* We are responder, check isakmp_sa for other side. */ + if (isakmp_sa->initiator ^ (ie->cfg_type == ISAKMP_CFG_REQUEST)) + id_string = ipsec_id_string(isakmp_sa->id_i, + isakmp_sa->id_i_len); + else + id_string = ipsec_id_string(isakmp_sa->id_r, + isakmp_sa->id_r_len); + if (!id_string) { + log_print("cfg_responder_send_ATTR: cannot parse client's ID"); + return -1; + } + if (cfg_encode_attributes(&ie->attrs, (ie->cfg_type == ISAKMP_CFG_SET ? + ISAKMP_CFG_ACK : ISAKMP_CFG_REPLY), ie->cfg_id, id_string, &attrp, + &attrlen)) { + free(id_string); + return -1; + } + free(id_string); + + if (message_add_payload(msg, ISAKMP_PAYLOAD_ATTRIBUTE, attrp, attrlen, + 1)) { + free(attrp); + return -1; + } + if (msg->exchange->phase == 2) + if (cfg_finalize_hash(msg, hashp, attrp, attrlen)) + return -1; + + return 0; +} + +u_int8_t * +cfg_add_hash(struct message *msg) +{ + struct ipsec_sa *isa = msg->isakmp_sa->data; + struct hash *hash = hash_get(isa->hash); + u_int8_t *hashp; + + hashp = malloc(ISAKMP_HASH_SZ + hash->hashsize); + if (!hashp) { + log_error("cfg_add_hash: malloc (%lu) failed", + ISAKMP_HASH_SZ + (unsigned long)hash->hashsize); + return 0; + } + if (message_add_payload(msg, ISAKMP_PAYLOAD_HASH, hashp, + ISAKMP_HASH_SZ + hash->hashsize, 1)) { + free(hashp); + return 0; + } + return hashp; +} + +int +cfg_finalize_hash(struct message *msg, u_int8_t *hashp, u_int8_t *data, + u_int16_t length) +{ + struct ipsec_sa *isa = msg->isakmp_sa->data; + struct prf *prf; + + prf = prf_alloc(isa->prf_type, isa->hash, isa->skeyid_a, + isa->skeyid_len); + if (!prf) + return -1; + + prf->Init(prf->prfctx); + prf->Update(prf->prfctx, msg->exchange->message_id, + ISAKMP_HDR_MESSAGE_ID_LEN); + prf->Update(prf->prfctx, data, length); + prf->Final(hashp + ISAKMP_GEN_SZ, prf->prfctx); + prf_free(prf); + return 0; +} + +int +cfg_verify_hash(struct message *msg) +{ + struct payload *hashp = payload_first(msg, ISAKMP_PAYLOAD_HASH); + struct ipsec_sa *isa = msg->isakmp_sa->data; + struct prf *prf; + u_int8_t *hash, *comp_hash; + size_t hash_len; + + if (!hashp) { + log_print("cfg_verify_hash: phase 2 message missing HASH"); + message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, + 0, 1, 0); + return -1; + } + hash = hashp->p; + hash_len = GET_ISAKMP_GEN_LENGTH(hash); + comp_hash = malloc(hash_len - ISAKMP_GEN_SZ); + if (!comp_hash) { + log_error("cfg_verify_hash: malloc (%lu) failed", + (unsigned long)hash_len - ISAKMP_GEN_SZ); + return -1; + } + /* Verify hash. */ + prf = prf_alloc(isa->prf_type, isa->hash, isa->skeyid_a, + isa->skeyid_len); + if (!prf) { + free(comp_hash); + return -1; + } + prf->Init(prf->prfctx); + prf->Update(prf->prfctx, msg->exchange->message_id, + ISAKMP_HDR_MESSAGE_ID_LEN); + prf->Update(prf->prfctx, hash + hash_len, + msg->iov[0].iov_len - ISAKMP_HDR_SZ - hash_len); + prf->Final(comp_hash, prf->prfctx); + prf_free(prf); + + if (memcmp(hash + ISAKMP_GEN_SZ, comp_hash, hash_len - ISAKMP_GEN_SZ) + != 0) { + message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, + 0, 1, 0); + free(comp_hash); + return -1; + } + free(comp_hash); + + /* Mark the HASH as handled. */ + hashp->flags |= PL_MARK; + + /* Mark message authenticated. */ + msg->flags |= MSG_AUTHENTICATED; + + return 0; +} + +/* + * Decode the attribute of type TYPE with a LEN length value pointed to by + * VALUE. VIE is a pointer to the IPsec exchange context holding the + * attributes indexed by type for easy retrieval. + */ +static int +cfg_decode_attribute(u_int16_t type, u_int8_t * value, u_int16_t len, + void *vie) +{ + struct ipsec_exch *ie = vie; + struct isakmp_cfg_attr *attr; + + if (type >= ISAKMP_CFG_ATTR_PRIVATE_MIN + && type <= ISAKMP_CFG_ATTR_PRIVATE_MAX) + return 0; + if (type == 0 || type >= ISAKMP_CFG_ATTR_FUTURE_MIN) { + LOG_DBG((LOG_NEGOTIATION, 30, + "cfg_decode_attribute: invalid attr type %u", type)); + return -1; + } + attr = calloc(1, sizeof *attr); + if (!attr) { + log_error("cfg_decode_attribute: calloc (1, %lu) failed", + (unsigned long)sizeof *attr); + return -1; + } + attr->type = type; + attr->length = len; + if (len) { + attr->value = malloc(len); + if (!attr->value) { + log_error("cfg_decode_attribute: malloc (%d) failed", + len); + free(attr); + /* Should we also deallocate all other values? */ + return -1; + } + memcpy(attr->value, value, len); + } + LIST_INSERT_HEAD(&ie->attrs, attr, link); + return 0; +} + +/* + * Encode list of attributes from ie->attrs into a attribute payload. + */ +static int +cfg_encode_attributes(struct isakmp_cfg_attr_head *attrs, u_int32_t type, + u_int32_t cfg_id, char *id_string, u_int8_t **attrp, u_int16_t *len) +{ + struct isakmp_cfg_attr *attr; + struct sockaddr *sa; + sa_family_t family; + u_int32_t value; + u_int16_t off; + char *field; + + /* Compute length */ + *len = ISAKMP_ATTRIBUTE_SZ; + for (attr = LIST_FIRST(attrs); attr; attr = LIST_NEXT(attr, link)) { + /* With ACK we only include the attrs we've actually used. */ + if (type == ISAKMP_CFG_ACK && attr->attr_used == 0) + continue; + + switch (attr->type) { + case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: + case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: + case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: + case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: + case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: + case ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY: + attr->length = 4; + break; + + case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET: + attr->length = 8; + break; + + case ISAKMP_CFG_ATTR_APPLICATION_VERSION: + /* XXX So far no version identifier of isakmpd here. */ + attr->length = 0; + break; + + case ISAKMP_CFG_ATTR_SUPPORTED_ATTRIBUTES: + attr->length = 2 * 15; + break; + + case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: + attr->length = 16; + break; + + case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET: + attr->length = 17; + break; + + default: + attr->ignore++; + /* XXX Log! */ + } + *len += ISAKMP_ATTR_SZ + attr->length; + } + + /* Allocate enough space for the payload */ + *attrp = calloc(1, *len); + if (!*attrp) { + log_error("cfg_encode_attributes: calloc (1, %lu) failed", + (unsigned long)*len); + return -1; + } + SET_ISAKMP_ATTRIBUTE_TYPE(*attrp, type); + SET_ISAKMP_ATTRIBUTE_ID(*attrp, cfg_id); + + off = ISAKMP_ATTRIBUTE_SZ; + for (attr = LIST_FIRST(attrs); attr; attr = LIST_NEXT(attr, link)) { + /* With ACK we only include the attrs we've actually used. */ + if (type == ISAKMP_CFG_ACK && attr->attr_used == 0) + continue; + + switch (attr->type) { + case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: + case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: + case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET: + case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: + case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: + case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: + family = AF_INET; + break; + + case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: + family = AF_INET6; + break; + + default: + family = 0; + break; + } + + switch (attr->type) { + case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: + field = "Address"; + break; + + case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET: + field = "Network"; /* XXX or just "Address" */ + break; + + case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: + field = "Netmask"; + break; + + case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: + field = "DHCP-server"; + break; + + case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: + field = "Nameserver"; + break; + + case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: + field = "WINS-server"; + break; + + default: + field = 0; + } + + switch (attr->type) { + case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: + case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: + case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: + case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: + case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: + case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: + sa = conf_get_address(id_string, field); + if (!sa) { + LOG_DBG((LOG_NEGOTIATION, 10, + "cfg_responder_send_ATTR: " + "attribute not found: %s", field)); + attr->length = 0; + break; + } + if (sa->sa_family != family) { + log_print("cfg_responder_send_ATTR: " + "attribute %s - expected %s got %s data", + field, + (family == AF_INET ? "IPv4" : "IPv6"), + (sa->sa_family == + AF_INET ? "IPv4" : "IPv6")); + free(sa); + attr->length = 0; + break; + } + /* Temporary limit length for the _SUBNET types. */ + if (attr->type == ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET) + attr->length = 4; + else if (attr->type == + ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET) + attr->length = 16; + + memcpy(*attrp + off + ISAKMP_ATTR_VALUE_OFF, + sockaddr_addrdata(sa), attr->length); + free(sa); + + /* _SUBNET types need some extra work. */ + if (attr->type == + ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET) { + sa = conf_get_address(id_string, "Netmask"); + if (!sa) { + LOG_DBG((LOG_NEGOTIATION, 10, + "cfg_responder_send_ATTR: " + "attribute not found: Netmask")); + attr->length = 0; + break; + } + if (sa->sa_family != AF_INET) { + log_print("cfg_responder_send_ATTR: " + "attribute Netmask - expected " + "IPv4 got IPv6 data"); + free(sa); + attr->length = 0; + break; + } + memcpy(*attrp + off + ISAKMP_ATTR_VALUE_OFF + + attr->length, sockaddr_addrdata(sa), + attr->length); + attr->length = 8; + free(sa); + } else if (attr->type == + ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET) { + int prefix = conf_get_num(id_string, "Prefix", + -1); + + if (prefix == -1) { + log_print("cfg_responder_send_ATTR: " + "attribute not found: Prefix"); + attr->length = 0; + break; + } else if (prefix < -1 || prefix > 128) { + log_print("cfg_responder_send_ATTR: " + "attribute Prefix - invalid " + "value %d", prefix); + attr->length = 0; + break; + } + *(*attrp + off + ISAKMP_ATTR_VALUE_OFF + 16) = + (u_int8_t)prefix; + attr->length = 17; + } + break; + + case ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY: + value = conf_get_num(id_string, "Lifetime", 1200); + encode_32(*attrp + off + ISAKMP_ATTR_VALUE_OFF, value); + break; + + case ISAKMP_CFG_ATTR_APPLICATION_VERSION: + /* XXX So far no version identifier of isakmpd here. */ + break; + + case ISAKMP_CFG_ATTR_SUPPORTED_ATTRIBUTES: + break; + + default: + break; + } + + SET_ISAKMP_ATTR_TYPE(*attrp + off, attr->type); + SET_ISAKMP_ATTR_LENGTH_VALUE(*attrp + off, attr->length); + off += ISAKMP_ATTR_VALUE_OFF + attr->length; + } + + return 0; +} diff --git a/keyexchange/isakmpd-20041012/isakmp_cfg.h b/keyexchange/isakmpd-20041012/isakmp_cfg.h new file mode 100644 index 0000000..169fa29 --- /dev/null +++ b/keyexchange/isakmpd-20041012/isakmp_cfg.h @@ -0,0 +1,53 @@ +/* $OpenBSD: isakmp_cfg.h,v 1.5 2004/05/23 18:17:56 hshoexer Exp $ */ + +/* + * Copyright (c) 2001 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. + * + * 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 Gatespace + * (http://www.gatespace.com/). + */ + +#ifndef _ISAKMP_CFG_H_ +#define _ISAKMP_CFG_H_ + +#include <sys/queue.h> + +struct isakmp_cfg_attr { + LIST_ENTRY(isakmp_cfg_attr) link; + u_int16_t type; + u_int8_t attr_used; + /* 8 bits just to be well-aligned. */ + u_int8_t ignore; + size_t length; + void *value; +}; + +struct message; + +extern int (*isakmp_cfg_initiator[])(struct message *); +extern int (*isakmp_cfg_responder[])(struct message *); +extern int16_t script_transaction[]; + +#endif /* _ISAKMP_CFG_H_ */ diff --git a/keyexchange/isakmpd-20041012/isakmp_doi.c b/keyexchange/isakmpd-20041012/isakmp_doi.c new file mode 100644 index 0000000..2fc8c1d --- /dev/null +++ b/keyexchange/isakmpd-20041012/isakmp_doi.c @@ -0,0 +1,264 @@ +/* $OpenBSD: isakmp_doi.c,v 1.22 2004/06/20 17:17:35 ho Exp $ */ +/* $EOM: isakmp_doi.c,v 1.42 2000/09/12 16:29:41 ho Exp $ */ + +/* + * Copyright (c) 1998, 1999, 2001 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. + * + * 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 "sysdep.h" + +#include "doi.h" +#include "exchange.h" +#include "isakmp.h" +#include "isakmp_doi.h" +#include "ipsec.h" +#include "log.h" +#include "message.h" +#include "sa.h" +#include "util.h" + +#ifdef USE_DEBUG +static int isakmp_debug_attribute(u_int16_t, u_int8_t *, u_int16_t, + void *); +#endif +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 *, 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, +#ifdef USE_DEBUG + isakmp_debug_attribute, +#endif + 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, /* handle_leftover_payload not needed. */ + 0, /* informational_post_hook not needed. */ + 0, /* informational_pre_hook not needed. */ + 0, /* XXX need maybe be filled-in. */ + 0, /* proto_init not needed. */ + 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, +#ifdef USE_DEBUG + ipsec_decode_ids +#endif +}; + +/* Requires doi_init to already have been called. */ +void +isakmp_doi_init(void) +{ + doi_register(&isakmp_doi); +} + +#ifdef USE_DEBUG +int +isakmp_debug_attribute(u_int16_t type, u_int8_t *value, u_int16_t len, + void *vmsg) +{ + /* XXX Not implemented yet. */ + return 0; +} +#endif /* USE_DEBUG */ + +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, size_t len) +{ + /* 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) +{ + if (msg->exchange->type != ISAKMP_EXCH_INFO) { + log_print("isakmp_initiator: unsupported exchange type %d " + "in phase %d", msg->exchange->type, msg->exchange->phase); + return -1; + } + return message_send_info(msg); +} + +static int +isakmp_responder(struct message *msg) +{ + struct payload *p; + + switch (msg->exchange->type) { + case ISAKMP_EXCH_INFO: + for (p = payload_first(msg, ISAKMP_PAYLOAD_NOTIFY); p; + p = TAILQ_NEXT(p, link)) { + LOG_DBG((LOG_EXCHANGE, 10, "isakmp_responder: " + "got NOTIFY of type %s, ignoring", + constant_name(isakmp_notify_cst, + GET_ISAKMP_NOTIFY_MSG_TYPE(p->p)))); + p->flags |= PL_MARK; + } + + for (p = payload_first(msg, ISAKMP_PAYLOAD_DELETE); p; + p = TAILQ_NEXT(p, link)) { + LOG_DBG((LOG_EXCHANGE, 10, + "isakmp_responder: got DELETE, ignoring")); + p->flags |= PL_MARK; + } + return 0; + +#ifdef USE_ISAKMP_CFG + case ISAKMP_EXCH_TRANSACTION: + /* return 0 isakmp_cfg_responder (msg); */ +#endif /* USE_ISAKMP_CFG */ + + default: + /* XXX So far we don't accept any proposals. */ + if (payload_first(msg, ISAKMP_PAYLOAD_SA)) { + message_drop(msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, + 0, 1, 0); + return -1; + } + } + return 0; +} diff --git a/keyexchange/isakmpd-20041012/isakmp_doi.h b/keyexchange/isakmpd-20041012/isakmp_doi.h new file mode 100644 index 0000000..13a485b --- /dev/null +++ b/keyexchange/isakmpd-20041012/isakmp_doi.h @@ -0,0 +1,37 @@ +/* $OpenBSD: isakmp_doi.h,v 1.5 2004/04/15 18:39:26 deraadt Exp $ */ +/* $EOM: isakmp_doi.h,v 1.1 1998/07/07 23:20:29 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. + * + * 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/keyexchange/isakmpd-20041012/isakmp_fld.fld b/keyexchange/isakmpd-20041012/isakmp_fld.fld new file mode 100644 index 0000000..05eeda9 --- /dev/null +++ b/keyexchange/isakmpd-20041012/isakmp_fld.fld @@ -0,0 +1,164 @@ +# $OpenBSD: isakmp_fld.fld,v 1.8 2004/06/20 15:24:05 ho Exp $ +# $EOM: isakmp_fld.fld,v 1.5 1999/04/25 13:38:22 niklas Exp $ + +# +# Copyright (c) 1998, 2001 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. +# +# 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 ike_attr_cst,ipsec_attr_cst + 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,ipsec_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 +. + +# Attribute payload. +ISAKMP_ATTRIBUTE : ISAKMP_GEN + TYPE num 1 isakmp_cfg_cst + RESERVED ign 1 + ID num 2 + ATTRS raw +. + +# NAT Discovery payload. +ISAKMP_NAT_D : ISAKMP_GEN + DATA raw +. + +# NAT Original Address payload. +ISAKMP_NAT_OA : ISAKMP_GEN + TYPE num 1 + RESERVED ign 3 + DATA raw +. diff --git a/keyexchange/isakmpd-20041012/isakmp_num.cst b/keyexchange/isakmpd-20041012/isakmp_num.cst new file mode 100644 index 0000000..d96d923 --- /dev/null +++ b/keyexchange/isakmpd-20041012/isakmp_num.cst @@ -0,0 +1,264 @@ +# $OpenBSD: isakmp_num.cst,v 1.10 2004/08/10 15:59:10 ho Exp $ +# $EOM: isakmp_num.cst,v 1.3 2000/05/17 03:09:50 angelos Exp $ + +# +# Copyright (c) 1998, 2001 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. +# +# 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 differently? Can we use +# these constants for validity 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 +# XXX the following are not quite legitimate according to the IETF process + ATTRIBUTE 14 # IKE Mode-Config attribute + SAK 15 # RFC 3547, SA KEK Payload + SAT 16 # RFC 3547, SA TEK Payload + KD 17 # RFC 3547, Key Download + SEQ 18 # RFC 3547, Sequence Number + POP 19 # RFC 3547, Proof of possession + NAT_D 20 # RFC 3947, NAT Discovery payload + NAT_OA 21 # RFC 3947, NAT Original Address payload + RESERVED_MIN 22 + RESERVED_MAX 127 + PRIVATE_MIN 128 +# XXX values from draft-ietf-ipsec-nat-t-ike-01,02,03. Later drafts specify +# XXX NAT_D as payload 15 and NAT_OA as 16, but these are allocated by RFC +# XXX 3547 as seen above. + NAT_D_DRAFT 130 # NAT Discovery payload + NAT_OA_DRAFT 131 # NAT Original Address payload + PRIVATE_MAX 255 + MAX 255 +. + +# ISAKMP exchange types. +ISAKMP_EXCH + NONE 0 + BASE 1 + ID_PROT 2 + AUTH_ONLY 3 + AGGRESSIVE 4 + INFO 5 +# XXX the following are not quite legitimate according to the IETF process + TRANSACTION 6 + FUTURE_MIN 7 + 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 + KEYNOTE 11 + HASH_URL_PKIX_CERT 12 + HASH_URL_PKIX_BUNDLE 13 + RESERVED_MIN 14 + 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 24576 + STATUS_DOI_MAX 32767 + STATUS_PRIVATE_MIN 32768 + STATUS_DPD_R_U_THERE 36136 + STATUS_DPD_R_U_THERE_ACK 36137 + STATUS_PRIVATE_MAX 40959 + STATUS_RESERVED2_MIN 40960 + STATUS_RESERVED2_MAX 65535 +. + +# ISAKMP V2 Notify payload types +ISAKMP_V2_NOTIFY + UNSUPPORTED_CRITICAL_PAYLOAD 1 + INVALID_IKE_SPI 4 + INVALID_MAJOR_VERSION 5 + INVALID_SYNTAX 7 + INVALID_MESSAGE_ID 9 + INVALID_SPI 11 + NO_PROPOSAL_CHOSEN 14 + AUTHENTICATION_FAILED 24 + SINGLE_PAIR_REQUIRED 34 + NO_ADDITIONAL_SAS 35 + INTERNAL_ADDRESS_FAILURE 36 + FAILED_CP_REQUIRED 37 + TS_UNACCEPTABLE 38 + RESERVED_MIN 39 + RESERVED_MAX 8191 + PRIVATE_MIN 8192 + PRIVATE_MAX 16383 + STATUS_RESERVED1_MIN 16384 + STATUS_RESERVED1_MAX 24577 + STATUS_INITIAL_CONTACT 24578 + STATUS_SET_WINDOW_SIZE 24579 + STATUS_ADDITIONAL_IS_POSSIBLE 24580 + STATUS_IPCOMP_SUPPORTED 24581 + STATUS_NAT_DETECTION_SOURCE_IP 24582 + STATUS_NAT_DETECTION_DESTINATION_IP 24583 + STATUS_COOKIE 24584 + STATUS_USE_TRANSPORT_MODE 24585 + STATUS_HTTP_CERT_LOOKUP_SUPPORTED 24586 + STATUS_RESERVED2_MIN 24587 + STATUS_RESERVED2_MAX 40959 + STATUS_PRIVATE_MIN 40960 + STATUS_PRIVATE_MAX 65535 +. + +# ISAKMP DOI Identifier. +ISAKMP_DOI + ISAKMP 0 +. + +# ISAKMP Protocol ID. +ISAKMP_PROTO + ISAKMP 1 +. + +# ISAKMP transaction message type. +ISAKMP_CFG + REQUEST 1 + REPLY 2 + SET 3 + ACK 4 + FUTURE_MIN 5 + FUTURE_MAX 127 + PRIVATE_MIN 128 + PRIVATE_MAX 255 +. + +# ISAKMP configuration attributes. +ISAKMP_CFG_ATTR + INTERNAL_IP4_ADDRESS 1 + INTERNAL_IP4_NETMASK 2 + INTERNAL_IP4_DNS 3 + INTERNAL_IP4_NBNS 4 + INTERNAL_ADDRESS_EXPIRY 5 + INTERNAL_IP4_DHCP 6 + APPLICATION_VERSION 7 + INTERNAL_IP6_ADDRESS 8 + INTERNAL_IP6_NETMASK 9 + INTERNAL_IP6_DNS 10 + INTERNAL_IP6_NBNS 11 + INTERNAL_IP6_DHCP 12 + INTERNAL_IP4_SUBNET 13 + SUPPORTED_ATTRIBUTES 14 + INTERNAL_IP6_SUBNET 15 + FUTURE_MIN 16 + FUTURE_MAX 16383 + PRIVATE_MIN 16384 + PRIVATE_MAX 32767 +. + +# ISAKMP EAP +ISAKMP_EAP_CODE + REQUEST 1 + RESPONSE 2 + SUCCESS 3 + FAILURE 4 +. + +# ISAKMP EAP Types (RFC2284) +ISAKMP_EAP_TYPE + IDENTITY 1 + NOTIFICATION 2 + NAK 3 # Response only + MD5_CHALLENGE 4 + OTP 5 + TOKEN 6 # Generic token card +. + diff --git a/keyexchange/isakmpd-20041012/isakmpd.8 b/keyexchange/isakmpd-20041012/isakmpd.8 new file mode 100644 index 0000000..e7f6987 --- /dev/null +++ b/keyexchange/isakmpd-20041012/isakmpd.8 @@ -0,0 +1,603 @@ +.\" $OpenBSD: isakmpd.8,v 1.65 2004/07/08 10:37:12 jmc Exp $ +.\" $EOM: isakmpd.8,v 1.23 2000/05/02 00:30:23 niklas Exp $ +.\" +.\" Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. +.\" All rights reserved. +.\" Copyright (c) 1999 Angelos D. Keromytis. All rights reserved. +.\" Copyright (c) 2001, 2002 Håkan Olsson. 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. +.\" +.\" 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 August 07, 2002 +.Dt ISAKMPD 8 +.Os +.Sh NAME +.Nm isakmpd +.Nd ISAKMP/Oakley a.k.a. IKE key management daemon +.Sh SYNOPSIS +.Nm isakmpd +.Bk -words +.Op Fl 4 +.Op Fl 6 +.Op Fl c Ar config-file +.Op Fl a +.Op Fl d +.Op Fl D Ar class=level +.Op Fl f Ar fifo +.Op Fl i Ar pid-file +.Op Fl n +.Op Fl p Ar listen-port +.Op Fl P Ar local-port +.Op Fl K +.Op Fl L +.Op Fl l Ar packetlog-file +.Op Fl r Ar seed +.Op Fl R Ar report-file +.Op Fl v +.Ek +.Sh DESCRIPTION +The +.Nm +daemon establishes security associations for encrypted +and/or authenticated network traffic. +At this moment, and probably forever, this means +.Xr ipsec 4 +traffic. +.Pp +The way +.Nm +goes about its work is by maintaining an internal configuration +as well as a policy database which describes what kinds of SAs to negotiate, +and by listening for different events that trigger these negotiations. +The events that control +.Nm +consist of negotiation initiations from a remote party, user input via +a FIFO or by signals, upcalls from the kernel via a +.Dv PF_KEY +socket, and lastly by scheduled events triggered by timers running out. +.Pp +Most uses of +.Nm +will be to implement so called "virtual private +networks" or VPNs for short. +The +.Xr vpn 8 +manual page describes how to set up +.Nm +for a simple VPN. +For other uses, some more knowledge of IKE as a protocol is required. +One source of information are the RFCs mentioned below. +.Pp +On startup +.Nm +forks into two processes for privilege separation. +The unprivileged child jails itself with +.Xr chroot 8 +to +.Pa /var/empty . +The privileged process communicates with the child, reads configuration files +and PKI information and binds to privileged ports on its behalf. +See +.Sx CAVEATS +section below. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl 4 | Fl 6 +These options control what address family +.Pf ( Dv AF_INET +and/or +.Dv AF_INET6 ) +.Nm +will use. +The default is to use both IPv4 and IPv6. +.It Fl a +If given, +.Nm +does not set up flows automatically. +This is useful when flows are configured with +.Xr ipsecadm 4 +or by other programs like +.Xr bgpd 8 . +Thus +.Nm +only takes care of the SA establishment. +.It Fl c Ar config-file +If given, the +.Fl c +option specifies an alternate configuration file instead of +.Pa /etc/isakmpd/isakmpd.conf . +As this file may contain sensitive information, it must be readable +only by the user running the daemon. +.Nm +will reread the configuration file when sent a +.Dv SIGHUP +signal. +.It Fl d +The +.Fl d +option is used to make the daemon run in the foreground, logging to stderr. +.It Xo Fl D +.Ar class Ns = Ns Ar level +.Xc +Debugging class. +It's possible to specify this argument many times. +It takes a parameter of the form +.Ar class Ns = Ns Ar level , +where both +.Ar class +and +.Ar level +are numbers. +.Ar class +denotes a debugging class, and +.Ar 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). +If +.Ar class +is set to +.Sq A , +then all debugging classes are set to the specified level. +.Pp +Valid values for +.Ar class +are as follows: +.Pp +.Bl -tag -width 2n -compact -offset indent +.It 0 +Misc +.It 1 +Transport +.It 2 +Message +.It 3 +Crypto +.It 4 +Timer +.It 5 +Sysdep +.It 6 +SA +.It 7 +Exchange +.It 8 +Negotiation +.It 9 +Policy +.It 10 +FIFO user interface +.It A +All +.El +.Pp +Currently used values for +.Ar level +are 0 to 99. +.It Fl f Ar fifo +The +.Fl f +option specifies the +.Tn FIFO +(a.k.a. named pipe) where the daemon listens for +user requests. +If the path given is a dash +.Pq Sq \&- , +.Nm +will listen to stdin instead. +.It Fl i Ar pid-file +By default the PID of the daemon process will be written to +.Pa /var/run/isakmpd.pid . +This path can be overridden by specifying another one as the argument to the +.Fl i +option. +.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 speak, in that it won't alter any +SAs in the IPsec stack. +.It Fl p Ar listen-port +The +.Fl p +option specifies the listen port the daemon will bind to. +.It Fl P Ar local-port +On the other hand, the port specified to capital +.Fl P +will be what the daemon binds its local end to when acting as +initiator. +.It Fl K +When this option is given, +.Nm +does not read the policy configuration file and no +.Xr keynote 4 +policy check is accomplished. +This option can be used when policies for flows and SA establishment are +arranged by other programs like +.Xr ipsecadm 8 +or +.Xr bgpd 8 . +.It Fl L +Enable IKE packet capture. +When this option is given, +.Nm +will capture to file an unencrypted copy of the negotiation packets it +is sending and receiving. +This file can later be read by +.Xr tcpdump 8 +and other utilities using +.Xr pcap 3 . +.It Fl l Ar packetlog-file +As option +.Fl L +above, but capture to a specified file. +.It Fl r Ar seed +If given, a deterministic random number sequence will be used internally. +This is useful for setting up regression tests. +.It Fl R Ar report-file +When you signal +.Nm +a +.Dv SIGUSR1 , +it will report its internal state to a report file, normally +.Pa /var/run/isakmpd.report , +but this can be changed by feeding +the file name as an argument to the +.Fl R +flag. +.It Fl v +Enables verbose logging. +Normally, +.Nm +is silent and outputs only messages when a warning or an error occurs. +With verbose logging +.Nm +reports successful completion of phase 1 (Main and Aggressive) and phase 2 +(Quick) exchanges (Information and Transaction exchanges do not generate any +additional status information). +.El +.Ss Setting up an IKE public key infrastructure (a.k.a. PKI) +In order to use public key based authentication, there has to be an +infrastructure managing the key signing. +Either there is an already existing PKI +.Nm +should take part in, or there will be a need to set one up. +In the former case, what is needed to be done varies depending on the +actual Certificate Authority used, and is therefore not covered here, +other than mentioning that +.Xr openssl 1 +needs to be used to create a certificate signing request that the +CA understands. +The latter case, however, is described here: +.Bl -enum +.It +Create your own CA as root. +.Bd -literal +# openssl genrsa -out /etc/ssl/private/ca.key 1024 +# openssl req -new -key /etc/ssl/private/ca.key \e + -out /etc/ssl/private/ca.csr +.Ed +.Pp +You are then asked to enter information that will be incorporated +into your certificate request. +What you are about to enter is what is called a Distinguished Name (DN). +There are quite a few fields but you can leave some blank. +For some fields there will be a default value; if you enter +.Sq \&. , +the field will be left blank. +.Bd -literal +# openssl x509 -req -days 365 -in /etc/ssl/private/ca.csr \e + -signkey /etc/ssl/private/ca.key \e + -extfile /etc/ssl/x509v3.cnf -extensions x509v3_CA \e + -out /etc/ssl/ca.crt +.Ed +.Pp +.It +Create keys and certificates for your IKE peers. +This step as well as the next one, needs to be done for every peer. +Furthermore the last step will need to be done once for each ID you +want the peer to have. +The 10.0.0.1 below symbolizes that ID, in this case an IPv4 ID, +and should be changed for each invocation. +You will be asked for a DN for each run. +Encoding the ID in the common name is recommended, as it should be unique. +.Bd -literal +# openssl genrsa -out /etc/isakmpd/private/local.key 1024 +# openssl req -new -key /etc/isakmpd/private/local.key \e + -out /etc/isakmpd/private/10.0.0.1.csr +.Ed +.Pp +Now take these certificate signing requests to your CA and process +them like below. +You have to add a subjectAltName extension field +to the certificate in order to make it usable by +.Nm isakmpd . +There are two possible ways to add the extensions to the certificate. +Either you have to run +.Xr certpatch 8 +or you have to make use of an OpenSSL configuration file, for example +.Pa /etc/ssl/x509v3.cnf . +Replace 10.0.0.1 with the IP-address which +.Nm +will use as the certificate identity. +.Pp +To use +.Xr certpatch 8 , +do the following +.Bd -literal +# openssl x509 -req -days 365 -in 10.0.0.1.csr -CA /etc/ssl/ca.crt \e + -CAkey /etc/ssl/private/ca.key -CAcreateserial \e + -out 10.0.0.1.crt +# certpatch -i 10.0.0.1 -k /etc/ssl/private/ca.key \e + 10.0.0.1.crt 10.0.0.1.crt +.Ed +.Pp +Otherwise do +.Bd -literal +# setenv CERTIP 10.0.0.1 +# openssl x509 -req -days 365 -in 10.0.0.1.csr -CA /etc/ssl/ca.crt \e + -CAkey /etc/ssl/private/ca.key -CAcreateserial \e + -extfile /etc/ssl/x509v3.cnf -extensions x509v3_IPAddr \e + -out 10.0.0.1.crt +.Ed +.Pp +For a FQDN certificate, do +.Bd -literal +# setenv CERTFQDN somehost.somedomain +# openssl x509 -req -days 365 -in somehost.somedomain.csr \e + -CA /etc/ssl/ca.crt -CAkey /etc/ssl/private/ca.key \e + -CAcreateserial \e + -extfile /etc/ssl/x509v3.cnf -extensions x509v3_FQDN \e + -out somehost.somedomain.crt +.Ed +.Pp +or with +.Xr certpatch 8 +.Bd -literal +# certpatch -t fqdn -i somehost.somedomain \e + -k /etc/ssl/private/ca.key \e + somehost.somedomain.crt somehost.somedomain.crt +.Ed +.Pp +(This assumes the previous steps were used to create a request for +somehost.somedomain instead of 10.0.0.1) +.Pp +Put the certificate (the file ending in .crt) in +.Pa /etc/isakmpd/certs/ +on your local system. +Also carry over the CA cert +.Pa /etc/ssl/ca.crt +and put it in +.Pa /etc/isakmpd/ca/ . +.El +.Pp +To revoke certificates, create a Certificate Revocation List (CRL) file +and install it in the +.Pa /etc/isakmpd/crls/ +directory. +See +.Xr openssl 1 +and the +.Sq crl +subcommand for more info. +.Pp +It is also possible to store trusted public keys to make them directly +usable by +.Nm isakmpd . +The keys should be saved in PEM format (see +.Xr openssl 1 ) +and named and stored after this easy formula: +.Bl -tag -width for_ufqdn_identities +.It For IPv4 identities +/etc/isakmpd/pubkeys/ipv4/A.B.C.D +.It For IPv6 identities +/etc/isakmpd/pubkeys/ipv6/abcd:abcd::ab:bc +.It For FQDN identities +/etc/isakmpd/pubkeys/fqdn/foo.bar.org +.It For UFQDN identities +/etc/isakmpd/pubkeys/ufqdn/user@foo.bar.org +.El +.Ss The FIFO user interface +When +.Nm +starts, it creates a FIFO (named pipe) where it listens for user +requests. +All commands start with a single letter, followed by command-specific options. +Available commands are: +.Bl -tag -width Ds -compact +.Pp +.It Ic "c <name>" +Start the named connection, if stopped or inactive. +.Pp +.It Ic "C set [section]:tag=value" +.It Ic "C set [section]:tag=value force" +.It Ic "C add [section]:tag=value" +.It Ic "C rm [section]:tag" +.It Ic "C rms [section]" +Update the running +.Nm +configuration atomically. +.Sq set +sets a configuration value consisting of a section, tag and value triplet. +.Sq set +will fail if the configuration already contains a section with the named tag; +use the +.Sq force +option to change this behaviour. +.Sq add +appends a configuration value to the named configuration list tag. +.Sq rm +removes a tag in a section. +.Sq rms +removes an entire section. +.Pp +NOTE: Sending isakmpd a SIGHUP or an "R" through the FIFO will +void any updates done to the configuration. +.Pp +.It Ic "C get [section]:tag" +Get the configuration value of the specified section and tag. +The result is stored in +.Pa /var/run/isakmpd.result . +.Pp +.It Ic "d <cookies> <msgid>" +Delete the specified SA from the system. +Specify <msgid> as "-" to match a Phase 1 SA. +.Pp +.It Ic "D <class> <level>" +.It Ic "D A <level>" +.It Ic "D T" +Set debug class <class> to level <level>. +If <class> is specified as "A", the level applies to all debug classes. +"D T" toggles all debug classes to level zero. +Another "D T" command will toggle them back to the earlier levels. +.Pp +.It Ic "p on[=<path>]" +.It Ic "p off" +Enable or disable cleartext IKE packet capture. +When enabling, optionally specify which file +.Nm +should capture the packets to. +.Pp +.It Ic "Q" +Cleanly shutdown the daemon, as when sent a +.Dv SIGTERM +signal. +.Pp +.It Ic "r" +Report +.Nm +internal state to a file. +See +.Fl R +option. +Same as when sent a +.Dv SIGUSR1 +signal. +.Pp +.It Ic "R" +Reinitialize +.Nm isakmpd , +as when sent a +.Dv SIGHUP +signal. +.Pp +.It Ic "S" +Report information on all known SAs to the +.Pa /var/run/isakmpd.result +file. +.Pp +.It Ic "t <name>" +Tear down the named connection, if active. +.Pp +.It Ic "T" +Tear down all active connections. +.El +.Sh FILES +.Bl -tag -width /etc/isakmpd/private/local. +.It Pa /etc/isakmpd/ca/ +The directory where CA certificates can be found. +.It Pa /etc/isakmpd/certs/ +The directory where IKE certificates can be found, both the local +certificate(s) and those of the peers, if a choice to have them kept +permanently has been made. +.It Pa /etc/isakmpd/crls/ +The directory where CRLs can be found. +.It Pa /etc/isakmpd/isakmpd.conf +The configuration file. +As this file can contain sensitive information +it must not be readable by anyone but the user running +.Nm isakmpd . +.It Pa /etc/isakmpd/isakmpd.policy +The keynote policy configuration file. +The same mode requirements as +.Nm isakmpd.conf . +.It Pa /etc/isakmpd/private/local.key +A local private key for certificate based authentication. +There has to be a certificate for this key in the certificate directory +mentioned above. +The same mode requirements as +.Nm isakmpd.conf . +.It Pa /etc/isakmpd/pubkeys/ +Directory in which trusted public keys can be kept. +The keys must be named in the fashion described above. +.It Pa /var/run/isakmpd.pid +The PID of the current daemon. +.It Pa /var/run/isakmpd.fifo +The FIFO used to manually control +.Nm isakmpd . +.It Pa /var/run/isakmpd.pcap +The default IKE packet capture file. +.It Pa /var/run/isakmpd.report +The report file written when +.Dv SIGUSR1 +is received. +.It Pa /var/run/isakmpd.result +The report file written when the +.Sq S +or +.Sq "C get" +command is issued in the command FIFO. +.It Pa /usr/share/ipsec/isakmpd/ +A directory containing some sample +.Nm +and keynote policy configuration files. +.El +.Sh SEE ALSO +.Xr openssl 1 , +.Xr getnameinfo 3 , +.Xr pcap 3 , +.Xr ipsec 4 , +.Xr isakmpd.conf 5 , +.Xr isakmpd.policy 5 , +.Xr ssl 8 , +.Xr tcpdump 8 , +.Xr vpn 8 +.Sh HISTORY +The ISAKMP/Oakley key management protocol is described in the RFCs +.%T RFC 2407 , +.%T RFC 2408 +and +.%T RFC 2409 . +This implementation was done 1998 by Niklas Hallqvist and Niels Provos, +sponsored by Ericsson Radio Systems. +.Sh CAVEATS +When storing a trusted public key for an IPv6 identity, the +.Em most efficient +form of address representation, i.e "::" instead of ":0:0:0:", +must be used or the matching will fail. +.Nm +uses the output from +.Xr getnameinfo 3 +for the address-to-name translation. +The privileged process only allows binding to the default port 500 or +unprivileged ports (>1024). +It is not possible to change the interfaces +.Nm +listens on without a restart. +.Sh BUGS +The +.Fl P +flag does not do what we document, rather it does nothing. diff --git a/keyexchange/isakmpd-20041012/isakmpd.c b/keyexchange/isakmpd-20041012/isakmpd.c new file mode 100644 index 0000000..8675201 --- /dev/null +++ b/keyexchange/isakmpd-20041012/isakmpd.c @@ -0,0 +1,543 @@ +/* $OpenBSD: isakmpd.c,v 1.68 2004/09/17 14:54:09 hshoexer Exp $ */ +/* $EOM: isakmpd.c,v 1.54 2000/10/05 09:28:22 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 1999, 2000 Angelos D. Keromytis. All rights reserved. + * Copyright (c) 1999, 2000, 2001 Håkan Olsson. 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. + * + * 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 <sys/param.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <netdb.h> +#include <unistd.h> +#include <fcntl.h> + +#include "sysdep.h" + +#include "app.h" +#include "conf.h" +#include "connection.h" +#include "init.h" +#include "libcrypto.h" +#include "log.h" +#include "monitor.h" +#include "sa.h" +#include "timer.h" +#include "transport.h" +#include "udp.h" +#include "ui.h" +#include "util.h" +#include "cert.h" + +#ifdef USE_POLICY +#include "policy.h" +#endif + +static void usage(void); + +/* + * Set if -d is given, currently just for running in the foreground and log + * to stderr instead of syslog. + */ +int debug = 0; + +/* Set when no policy file is found. */ +int acquire_only = 0; + +/* + * If we receive a SIGHUP signal, this flag gets set to show we need to + * reconfigure ASAP. + */ +volatile sig_atomic_t sighupped = 0; + +/* + * If we receive a USR1 signal, this flag gets set to show we need to dump + * a report over our internal state ASAP. The file to report to is settable + * via the -R parameter. + */ +volatile sig_atomic_t sigusr1ed = 0; +static char *report_file = "/var/run/isakmpd.report"; + +/* + * If we receive a USR2 signal, this flag gets set to show we need to + * rehash our SA soft expiration timers to a uniform distribution. + * XXX Perhaps this is a really bad idea? + */ +volatile sig_atomic_t sigusr2ed = 0; + +/* + * If we receive a TERM signal, perform a "clean shutdown" of the daemon. + * This includes to send DELETE notifications for all our active SAs. + * Also on recv of an INT signal (Ctrl-C out of an '-d' session, typically). + */ +volatile sig_atomic_t sigtermed = 0; +void daemon_shutdown_now(int); + +/* The default path of the PID file. */ +static char *pid_file = "/var/run/isakmpd.pid"; + +#ifdef USE_DEBUG +/* The path of the IKE packet capture log file. */ +static char *pcap_file = 0; +#endif + +static void +usage(void) +{ + fprintf(stderr, + "usage: %s [-4] [-6] [-a] [-c config-file] [-d] [-D class=level]\n" + " [-f fifo] [-i pid-file] [-K] [-n] [-p listen-port]\n" + " [-P local-port] [-L] [-l packetlog-file] [-r seed]\n" + " [-R report-file] [-v]\n", + sysdep_progname()); + exit(1); +} + +static void +parse_args(int argc, char *argv[]) +{ + int ch; + char *ep; +#ifdef USE_DEBUG + int cls, level; + int do_packetlog = 0; +#endif + + while ((ch = getopt(argc, argv, "46ac:dD:f:i:Knp:P:Ll:r:R:v")) != -1) { + switch (ch) { + case '4': + bind_family |= BIND_FAMILY_INET4; + break; + + case '6': + bind_family |= BIND_FAMILY_INET6; + break; + + case 'a': + acquire_only++; + break; + + case 'c': + conf_path = optarg; + break; + + case 'd': + debug++; + break; + +#ifdef USE_DEBUG + case 'D': + if (sscanf(optarg, "%d=%d", &cls, &level) != 2) { + if (sscanf(optarg, "A=%d", &level) == 1) { + for (cls = 0; cls < LOG_ENDCLASS; + cls++) + log_debug_cmd(cls, level); + } else + log_print("parse_args: -D argument " + "unparseable: %s", optarg); + } else + log_debug_cmd(cls, level); + break; +#endif /* USE_DEBUG */ + + case 'f': + ui_fifo = optarg; + break; + + case 'i': + pid_file = optarg; + break; + +#ifdef USE_POLICY + case 'K': + ignore_policy++; + break; +#endif + + case 'n': + app_none++; + break; + + case 'p': + udp_default_port = optarg; + break; + + case 'P': + udp_bind_port = optarg; + break; + +#ifdef USE_DEBUG + case 'l': + pcap_file = optarg; + /* Fallthrough intended. */ + + case 'L': + do_packetlog++; + break; +#endif /* USE_DEBUG */ + + case 'r': + seed = strtoul(optarg, &ep, 0); + srandom(seed); + if (*ep != '\0') + log_fatal("parse_args: invalid numeric arg " + "to -r (%s)", optarg); + regrand = 1; + break; + + case 'R': + report_file = optarg; + break; + + case 'v': + verbose_logging = 1; + break; + + case '?': + default: + usage(); + } + } + argc -= optind; + argv += optind; + +#ifdef USE_DEBUG + if (do_packetlog && !pcap_file) + pcap_file = PCAP_FILE_DEFAULT; +#endif +} + +static void +sighup(int sig) +{ + sighupped = 1; +} + +/* Report internal state on SIGUSR1. */ +static void +report(void) +{ + FILE *rfp, *old; + mode_t old_umask; + + old_umask = umask(S_IRWXG | S_IRWXO); + rfp = monitor_fopen(report_file, "w"); + umask(old_umask); + + if (!rfp) { + log_error("report: fopen (\"%s\", \"w\") failed", report_file); + return; + } + /* Divert the log channel to the report file during the report. */ + old = log_current(); + log_to(rfp); + ui_report("r"); + log_to(old); + fclose(rfp); +} + +static void +sigusr1(int sig) +{ + sigusr1ed = 1; +} + +/* Rehash soft expiration timers on SIGUSR2. */ +static void +rehash_timers(void) +{ +#if 0 + /* XXX - not yet */ + log_print("SIGUSR2 received, rehashing soft expiration timers."); + + timer_rehash_timers(); +#endif +} + +static void +sigusr2(int sig) +{ + sigusr2ed = 1; +} + +static int +phase2_sa_check(struct sa *sa, void *arg) +{ + return sa->phase == 2; +} + +static void +daemon_shutdown(void) +{ + /* Perform a (protocol-wise) clean shutdown of the daemon. */ + struct sa *sa; + + if (sigtermed == 1) { + log_print("isakmpd: shutting down..."); + + /* Delete all active phase 2 SAs. */ + while ((sa = sa_find(phase2_sa_check, NULL))) { + /* Each DELETE is another (outgoing) message. */ + sa_delete(sa, 1); + } + sigtermed++; + } + if (transport_prio_sendqs_empty()) { + /* + * When the prioritized transport sendq:s are empty, i.e all + * the DELETE notifications have been sent, we can shutdown. + */ + +#ifdef USE_DEBUG + log_packet_stop(); +#endif + /* Remove FIFO and pid files. */ + unlink(ui_fifo); + unlink(pid_file); + log_print("isakmpd: exit"); + exit(0); + } +} + +/* Called on SIGTERM, SIGINT or by ui_shutdown_daemon(). */ +void +daemon_shutdown_now(int sig) +{ + sigtermed = 1; +} + +/* Write pid file. */ +static void +write_pid_file(void) +{ + FILE *fp; + + /* Ignore errors. This will fail with USE_PRIVSEP. */ + unlink(pid_file); + + fp = monitor_fopen(pid_file, "w"); + if (fp != NULL) { + if (fprintf(fp, "%ld\n", (long) getpid()) < 0) + log_error("write_pid_file: failed to write PID to " + "\"%.100s\"", pid_file); + fclose(fp); + } else + log_fatal("write_pid_file: fopen (\"%.100s\", \"w\") failed", + pid_file); +} + +int +main(int argc, char *argv[]) +{ + fd_set *rfds, *wfds; + int n, m; + size_t mask_size; + struct timeval tv, *timeout; + +#if defined (HAVE_CLOSEFROM) && (!defined (OpenBSD) || (OpenBSD >= 200405)) + closefrom(STDERR_FILENO + 1); +#else + m = getdtablesize(); + for (n = STDERR_FILENO + 1; n < m; n++) + (void) close(n); +#endif + + /* + * Make sure init() won't alloc fd 0, 1 or 2, as daemon() will close + * them. + */ + for (n = 0; n <= 2; n++) + if (fcntl(n, F_GETFL, 0) == -1 && errno == EBADF) + (void) open("/dev/null", n ? O_WRONLY : O_RDONLY, 0); + + for (n = 1; n < _NSIG; n++) + signal(n, SIG_DFL); + + /* Log cmd line parsing and initialization errors to stderr. */ + log_to(stderr); + parse_args(argc, argv); + log_init(debug); + + /* Open protocols and services databases. */ + setprotoent(1); + setservent(1); + + /* + * Do a clean daemon shutdown on TERM/INT. These signals must be + * initialized before monitor_init(). INT is only used with '-d'. + */ + signal(SIGTERM, daemon_shutdown_now); + if (debug == 1) /* i.e '-dd' will skip this. */ + signal(SIGINT, daemon_shutdown_now); + + /* Daemonize before forking unpriv'ed child */ + if (!debug) + if (daemon(0, 0)) + log_fatal("main: daemon (0, 0) failed"); + + /* Set timezone before priv'separation */ + tzset(); + +#if defined (USE_PRIVSEP) + if (monitor_init(debug)) { + /* The parent, with privileges enters infinite monitor loop. */ + monitor_loop(debug); + exit(0); /* Never reached. */ + } + /* Child process only from this point on, no privileges left. */ +#endif + + init(); + + write_pid_file(); + + /* Reinitialize on HUP reception. */ + signal(SIGHUP, sighup); + + /* Report state on USR1 reception. */ + signal(SIGUSR1, sigusr1); + + /* Rehash soft expiration timers on USR2 reception. */ + signal(SIGUSR2, sigusr2); + +#if defined (USE_DEBUG) + /* If we wanted IKE packet capture to file, initialize it now. */ + if (pcap_file != 0) + log_packet_init(pcap_file); +#endif + + /* Allocate the file descriptor sets just big enough. */ + n = getdtablesize(); + mask_size = howmany(n, NFDBITS) * sizeof(fd_mask); + rfds = (fd_set *) malloc(mask_size); + if (!rfds) + log_fatal("main: malloc (%lu) failed", + (unsigned long)mask_size); + wfds = (fd_set *) malloc(mask_size); + if (!wfds) + log_fatal("main: malloc (%lu) failed", + (unsigned long)mask_size); + +#if defined (USE_PRIVSEP) + monitor_init_done(); +#endif + + while (1) { + /* If someone has sent SIGHUP to us, reconfigure. */ + if (sighupped) { + sighupped = 0; + log_print("SIGHUP received"); + reinit(); + } + /* and if someone sent SIGUSR1, do a state report. */ + if (sigusr1ed) { + sigusr1ed = 0; + log_print("SIGUSR1 received"); + report(); + } + /* and if someone sent SIGUSR2, do a timer rehash. */ + if (sigusr2ed) { + sigusr2ed = 0; + log_print("SIGUSR2 received"); + rehash_timers(); + } + /* + * and if someone set 'sigtermed' (SIGTERM, SIGINT or via the + * UI), this indicates we should start a controlled shutdown + * of the daemon. + * + * Note: Since _one_ message is sent per iteration of this + * enclosing while-loop, and we want to send a number of + * DELETE notifications, we must loop atleast this number of + * times. The daemon_shutdown() function starts by queueing + * the DELETEs, all other calls just increments the + * 'sigtermed' variable until it reaches a "safe" value, and + * the daemon exits. + */ + if (sigtermed) + daemon_shutdown(); + + /* Setup the descriptors to look for incoming messages at. */ + memset(rfds, 0, mask_size); + 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 && app_socket >= 0) { + FD_SET(app_socket, rfds); + if (app_socket + 1 > n) + n = app_socket + 1; + } + /* Setup the descriptors that have pending messages to send. */ + memset(wfds, 0, mask_size); + m = transport_pending_wfd_set(wfds); + if (m > n) + n = m; + + /* Find out when the next timed event is. */ + timeout = &tv; + timer_next_event(&timeout); + + n = select(n, rfds, wfds, 0, timeout); + if (n == -1) { + if (errno != EINTR) { + log_error("main: 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 && app_socket >= 0 && + FD_ISSET(app_socket, rfds)) + app_handler(); + } + timer_handle_expirations(); + } +} diff --git a/keyexchange/isakmpd-20041012/isakmpd.conf.5 b/keyexchange/isakmpd-20041012/isakmpd.conf.5 new file mode 100644 index 0000000..db3dd78 --- /dev/null +++ b/keyexchange/isakmpd-20041012/isakmpd.conf.5 @@ -0,0 +1,1126 @@ +.\" $OpenBSD: isakmpd.conf.5,v 1.94 2004/08/10 15:59:10 ho Exp $ +.\" $EOM: isakmpd.conf.5,v 1.57 2000/12/21 14:43:17 ho Exp $ +.\" +.\" Copyright (c) 1998, 1999, 2000 Niklas Hallqvist. All rights reserved. +.\" Copyright (c) 2000, 2001, 2002 Håkan Olsson. 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. +.\" +.\" 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 August 07, 2002 +.Dt ISAKMPD.CONF 5 +.Os +.Sh NAME +.Nm isakmpd.conf +.Nd configuration file for isakmpd +.Sh DESCRIPTION +.Nm +is the configuration file for the +.Nm isakmpd +daemon managing security association and key management for the +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 backslash character +immediately before the newline character. +This method can extend a value for an arbitrary number of lines. +.Pp +Comments can be put anywhere in the file by using a hash mark +.Pq Sq \&# . +The comment extends to the end of the current line. +.Pp +Often the right-hand side values consist of other section names. +This results in a tree structure. +Some values are treated as a list of several scalar values. +Such lists always use a comma character as the separator. +Some values are formatted like this: X,Y:Z, which +is an offer/accept syntax, where X is a value we offer and Y:Z is a range of +accepted values, inclusive. +.Pp +To activate changes to +.Nm +without restarting +.Nm isakmpd , +send a +.Dv SIGHUP +signal to the daemon process. +.Ss Auto-generated parts of the configuration +.Pp +Some predefined section names are recognized by the daemon, avoiding the need +to fully specify the Main Mode transforms and Quick Mode suites, protocols, +and transforms. +.Pp +For Main Mode: +.Bd -filled -compact +.Ar {DES,BLF,3DES,CAST,AES}-{MD5,SHA}[-GRP{1,2,5,14}][-{DSS,RSA_SIG}] +.Ed +.Pp +For Quick Mode: +.Bd -filled -compact +.Ar QM-{proto}[-TRP]-{cipher}[-{hash}][-PFS[-{group}]]-SUITE +.Ed +.Bd -literal + where + {proto} is either ESP or AH + {cipher} is either DES, 3DES, CAST, BLF or AES + {hash} is either MD5, SHA, RIPEMD, SHA2-{256,384,512} + {group} is either GRP1, GRP2, GRP5 or GRP14 +.Ed +.Pp +For example, 3DES-SHA means: 3DES encryption, SHA hash, and authorization by +pre-shared keys. +Similarly, QM-ESP-3DES-SHA-PFS-SUITE means: ESP protocol, 3DES encryption, +SHA hash, and use Perfect Forward Secrecy. +.Pp +Unless explicitly stated with -GRP1, 2, 5 or 14 transforms and PFS suites +use DH group 2. +There are currently no predefined ESP+AH Quick Mode suites. +.Pp +The predefinitions include some default values for the special +sections "General", "Keynote", "X509-certificates", and +"Default-phase-1-configuration". +These default values are presented in the example below. +.Pp +All autogenerated values can be overridden by manual entries by using the +same section and tag names in the configuration file. +In particular, the default phase 1 (Main or Aggressive Mode) and phase 2 +(Quick Mode) lifetimes can be overridden by these tags under the "General" +section; +.Bd -literal +[General] +Default-phase-1-lifetime= 3600,60:86400 +Default-phase-2-lifetime= 1200,60:86400 +.Ed +.Pp +The Main Mode lifetime currently defaults to one hour (minimum 60 +seconds, maximum 1 day). +The Quick Mode lifetime defaults to 20 minutes +(minimum 60 seconds, maximum 1 day). +.Pp +Also, the default phase 1 ID can be set by creating a <Phase1-ID> +section, as shown below, and adding this tag under the "General" +section; +.Bd -literal +[General] +Default-phase-1-ID= Phase1-ID-name + +[Phase1-ID-name] +ID-type= USER_FQDN +Name= foo@bar.com +.Ed +.Ss Roots +.Bl -hang -width 12n +.It Em General +Generic global configuration parameters +.Bl -tag -width 12n +.It Em Default-phase-1-ID +Optional default phase 1 ID name. +.It Em Default-phase-1-lifetime +The default lifetime for autogenerated transforms (phase 1). +If unspecified, the value 3600,60:86400 is used as the default. +.It Em Default-phase-2-lifetime +The default lifetime for autogenerated suites (phase 2). +If unspecified, the value 1200,60:86400 is used as the default. +.It Em Default-phase-2-suites +A list of phase 2 suites that will be used when establishing dynamic +SAs. +If left unspecified, QM-ESP-3DES-SHA-PFS-SUITE is used as the default. +.It Em Acquire-Only +If this tag is defined, +.Nm isakmpd +will not set up flows automatically. +This is useful when flows are configured with +.Xr ipsecadm 4 +or by other programs like +.Xr bgpd 8 . +Thus +.Nm isakmpd +only takes care of the SA establishment. +.It Em Check-interval +The interval between watchdog checks of connections we want up at all +times. +.It Em DPD-check-interval +The interval between RFC 3706 (Dead Peer Detection) messages. +The default value is 0 (zero), which means DPD is disabled. +.It Em Exchange-max-time +How many seconds should an exchange maximally take to set up before we +give up. +.It Em Listen-on +A list of IP-addresses OK to listen on. +This list is used as a filter for the set of addresses the interfaces +configured provides. +This means that we won't see if an address given here does not exist +on this host, and thus no error is given for that case. +.It Em Loglevel +A list of the form +.Ar class Ns = Ns Ar level , +where both +.Ar class +and +.Ar level +are numbers. +This is similar to the +.Fl D +command line switch of +.Em isakmpd . +See +.Xr isakmpd 8 +for details. +.It Em Logverbose +If this tag is defined, whatever the value is, verbose logging is enabled. +This is similar to the +.Fl v +command line switch of +.Em isakmpd . +See +.Xr isakmpd 8 +for details. +.It Em NAT-T-Keepalive +The number of seconds between NAT-T keepalive messages, sent by the +peer behind NAT to keep the mapping active. +Defaults to 20. +.It Em Policy-file +The name of the file that contains +.Xr keynote 4 +policies. +The default is "/etc/isakmpd/isakmpd.policy". +.It Em Pubkey-directory +The directory in which +.Nm +looks for explicitly trusted public keys. +The default is "/etc/isakmpd/pubkeys". +Read +.Xr isakmpd 8 +for the required naming convention of the files in here. +.It Em Renegotiate-on-HUP +If this tag is defined, whatever the value is, +.Nm isakmpd +will renegotiate all current phase 2 SAs when the daemon receives a +.Dv SIGHUP +signal, or an +.Sq R +is sent to the FIFO interface (see +.Xr isakmpd 8 ) . +.It Em Retransmits +How many times should a message be retransmitted before giving up. +.It Em Shared-SADB +If this tag is defined, whatever the value is, some semantics of +.Nm +are changed so that multiple instances can run on top of one SADB +and set up SAs with each other. +Specifically this means replay +protection will not be asked for, and errors that can occur when +updating an SA with its parameters a 2nd time will be ignored. +.It Em Use-Keynote +This tag controls the use of +.Xr keynote 4 +policy checking. +The default value is +.Qq yes , +which enables the policy checking. +When set to any other value, policies will not be checked. +This is useful when policies for flows and SA establishment are arranged by +other programs like +.Xr ipsecadm 8 +or +.Xr bgpd 8 . +.El +.It Em Phase 1 +ISAKMP SA negotiation parameter root +.Bl -tag -width 12n +.It Em <IP-address> +A name of the ISAKMP peer at the given IP-address. +.It Em Default +A name of the default ISAKMP peer. +Incoming phase 1 connections from other IP-addresses will use this peer name. +.It "" +This name is used as the section name for further information to be found. +Look at <ISAKMP-peer> below. +.El +.It Em Phase 2 +IPsec SA negotiation parameter root +.Bl -tag -width 12n +.It Em Connections +A list of directed IPsec "connection" names that should be brought up +automatically, either on first use if the system supports it, or at +startup of the daemon. +These names are section names where further information can be found. +Look at <IPsec-connection> below. +Normally any connections mentioned here are treated as part of the +"Passive-connection" list we present below, however there is a +flag: "Active-only" that disables this behaviour. +This too is mentioned in the <IPsec-connection> section, in the "Flags" tag. +.It Em Passive-connections +A list of IPsec "connection" names we recognize and accept initiations for. +These names are section names where further information can be found. +Look at <IPsec-connection> below. +Currently only the Local-ID and Remote-ID tags +are looked at in those sections, as they are matched against the IDs given +by the initiator. +.El +.It Em KeyNote +.Bl -tag -width 12n +.It Em Credential-directory +A directory containing directories named after IDs (IP +addresses, +.Dq user@domain , +or hostnames) that contain files named +.Dq credentials +and +.Dq private_key . +.Pp +The credentials file contains +.Xr keynote 4 +credentials that are sent to a remote IKE daemon when we use the +associated ID, or credentials that we may want to consider when doing +an exchange with a remote IKE daemon that uses that ID. +Note that, in the former case, the last credential in the file +MUST contain our public key in its Licensees field. +More than one credentials may exist in the file. +They are separated by whitelines (the format is essentially the same as +that of the policy file). +The credentials are of the same format as the policies described in +.Xr isakmpd.policy 5 . +The only difference is that the Authorizer field contains a public +key, and the assertion is signed. +Signed assertions can be generated using the +.Xr keynote 1 +utility. +.Pp +The private_key file contains the private RSA key we use for +authentication. +If the directory (and the files) exist, they take precedence over X509-based +authentication. +.El +.It Em X509-Certificates +.Bl -tag -width 12n +.It Em Accept-self-signed +If this tag is defined, whatever the value is, certificates that +do not originate from a trusted CA but are self-signed will be +accepted. +.It Em Ca-directory +A directory containing PEM certificates of certification authorities +that we trust to sign other certificates. +Note that for a CA to be really trusted, it needs to be somehow +referred to by policy, in +.Xr isakmpd.policy 5 . +The certificates in this directory are used for the actual X.509 +authentication and for cross-referencing policies that refer to +Distinguished Names (DNs). +Keeping a separate directory (as opposed to integrating policies +and X.509 CA certificates) allows for maintenance of a list of +"well known" CAs without actually having to trust all (or any) of them. +.It Em Cert-directory +A directory containing PEM certificates that we trust to be valid. +These certificates are used in preference to those passed in messages and +are required to have a subjectAltName extension containing the certificate +holder identity; usually IP address, FQDN, or User FQDN, as provided by +.Xr certpatch 8 . +.It Em Private-key +The private key matching the public key of our certificate (which should be +in the "Cert-directory", and have an appropriate subjectAltName field). +.El +.El +.Ss Referred-to sections +.Bl -hang -width 12n +.It Em <ISAKMP-peer> +Parameters for negotiation with an ISAKMP peer +.Bl -tag -width 12n +.It Em Phase +The constant +.Li 1 , +as ISAKMP-peers and IPsec-connections +really are handled by the same code inside isakmpd. +.It Em Transport +The name of the transport protocol, defaults to +.Li UDP . +.It Em Port +In case of +.Li UDP , +the +.Li UDP +port number to send to. +This is optional, the +default value is 500 which is the IANA-registered number for ISAKMP. +.It Em Local-address +The Local IP-address to use, if we are multi-homed, or have aliases. +.It Em Address +If existent, the IP-address of the peer. +.It Em Configuration +The name of the ISAKMP-configuration section to use. +Look at <ISAKMP-configuration> below. +If unspecified, defaults to "Default-phase-1-configuration". +.It Em Authentication +If existent, authentication data for this specific peer. +In the case of preshared key, this is the key value itself. +.It Em ID +If existent, the name of the section that describes the +local client ID that we should present to our peer. +If not present, it +defaults to the address of the local interface we are sending packets +over to the remote daemon. +Look at <Phase1-ID> below. +.It Em Remote-ID +If existent, the name of the section that describes the remote client +ID we expect the remote daemon to send us. +If not present, it defaults to the address of the remote daemon. +Look at <Phase1-ID> below. +.It Em Flags +A comma-separated list of flags controlling the further +handling of the ISAKMP SA. +Currently there are no specific ISAKMP SA flags defined. +.El +.It Em <Phase1-ID> +.Bl -tag -width 12n +.It Em ID-type +The ID type as given by the RFC specifications. +For phase 1 this is currently +.Li IPV4_ADDR , +.Li IPV4_ADDR_SUBNET , +.Li IPV6_ADDR , +.Li IPV6_ADDR_SUBNET , +.Li FQDN , +.Li USER_FQDN +or +.Li KEY_ID . +.It Em Address +If the ID-type is +.Li IPV4_ADDR +or +.Li IPV6_ADDR , +this tag should exist and be an IP-address. +.It Em Network +If the ID-type is +.Li IPV4_ADDR_SUBNET +or +.Li IPV6_ADDR_SUBNET +this tag should exist and +be a network address. +.It Em Netmask +If the ID-type is +.Li IPV4_ADDR_SUBNET +or +.Li IPV6_ADDR_SUBNET +this tag should exist and +be a network subnet mask. +.It Em Name +If the ID-type is +.Li FQDN , +.Li USER_FQDN +or +.Li KEY_ID , +this tag should exist and contain a domain name, user@domain, or +other identifying string respectively. +.Pp +In the case of +.Li KEY_ID , +note that the IKE protocol allows any octet sequence to be sent or +received under this payload, potentially including non-printable +ones. +.Xr isakmpd 8 +can only transmit printable +.Li KEY_ID +payloads, but can receive and process arbitrary +.Li KEY_ID +payloads. +This effectively means that non-printable +.Li KEY_ID +remote identities cannot be verified through this means, although it +is still possible to do so through +.Xr isakmpd.policy 5 . +.El +.It Em <ISAKMP-configuration> +.Bl -tag -width 12n +.It Em DOI +The domain of interpretation as given by the RFCs. +Normally +.Li IPSEC . +If unspecified, defaults to +.Li IPSEC . +.It Em EXCHANGE_TYPE +The exchange type as given by the RFCs. +For main mode this is +.Li ID_PROT +and for aggressive mode it is +.Li AGGRESSIVE . +.It Em Transforms +A list of proposed transforms to use for protecting the +ISAKMP traffic. +These are actually names for sections +further describing the transforms. +Look at <ISAKMP-transform> below. +.El +.It Em <ISAKMP-transform> +.Bl -tag -width 12n +.It Em ENCRYPTION_ALGORITHM +The encryption algorithm as the RFCs name it, or ANY to denote that any +encryption algorithm proposed will be accepted. +.It Em KEY_LENGTH +For encryption algorithms with variable key length, this is +where the offered/accepted keylengths are described. +The value is of the offer-accept kind described above. +.It Em HASH_ALGORITHM +The hash algorithm as the RFCs name it, or ANY. +.It Em AUTHENTICATION_METHOD +The authentication method as the RFCs name it, or ANY. +.It Em GROUP_DESCRIPTION +The group used for Diffie-Hellman exponentiations, or ANY. +The names are symbolic, like +.Li MODP_768 , MODP_1024 , EC_155 +and +.Li EC_185 . +.It Em PRF +The algorithm to use for the keyed pseudo-random function (used for key +derivation and authentication in phase 1), or ANY. +.It Em Life +A list of lifetime descriptions, or ANY. +In the former case, each +element is in itself a name of the section that defines the lifetime. +Look at <Lifetime> below. +If it is set to ANY, then any type of +proposed lifetime type and value will be accepted. +.El +.It Em <Lifetime> +.Bl -tag -width 12n +.It Em LIFE_TYPE +.Li SECONDS +or +.Li KILOBYTES +depending on the type of the duration. +Notice that this field may NOT be set to ANY. +.It Em LIFE_DURATION +An offer/accept kind of value, see above. +Can also be set to ANY. +.El +.It Em <IPsec-connection> +.Bl -tag -width 12n +.It Em Phase +The constant +.Li 2 , +as ISAKMP-peers and IPsec-connections +really are handled by the same code inside isakmpd. +.It Em ISAKMP-peer +The name of the ISAKMP-peer which to talk to in order to +set up this connection. +The value is the name of an <ISAKMP-peer> section. +See above. +.It Em Configuration +The name of the IPsec-configuration section to use. +Look at <IPsec-configuration> below. +.It Em Local-ID +If existent, the name of the section that describes the +optional local client ID that we should present to our peer. +It is also used when we act as responders to find out what +<IPsec-connection> we are dealing with. +Look at <IPsec-ID> below. +.It Em Remote-ID +If existent, the name of the section that describes the +optional remote client ID that we should present to our peer. +It is also used when we act as responders to find out what +<IPsec-connection> we are dealing with. +Look at <IPsec-ID> below. +.It Em Flags +A comma-separated list of flags controlling the further +handling of the IPsec SA. +Currently only one flag is defined: +.Bl -tag -width 12n +.It Em Active-only +If this flag is given and this <IPsec-connection> is part of the phase 2 +connections we automatically keep up, it will not automatically be used for +accepting connections from the peer. +.El +.El +.It Em <IPsec-configuration> +.Bl -tag -width 12n +.It Em DOI +The domain of interpretation as given by the RFCs. +Normally +.Li IPSEC . +If unspecified, defaults to +.Li IPSEC . +.It Em EXCHANGE_TYPE +The exchange type as given by the RFCs. +For quick mode this is +.Li QUICK_MODE . +.It Em Suites +A list of protection suites (bundles of protocols) usable for +protecting the IP traffic. +Each of the list elements is a name of an <IPsec-suite> section. +See below. +.El +.It Em <IPsec-suite> +.Bl -tag -width 12n +.It Em Protocols +A list of the protocols included in this protection suite. +Each of the list elements is a name of an <IPsec-protocol> +section. +See below. +.El +.It Em <IPsec-protocol> +.Bl -tag -width 12n +.It Em PROTOCOL_ID +The protocol as given by the RFCs. +Acceptable values today are +.Li IPSEC_AH +and +.Li IPSEC_ESP . +.It Em Transforms +A list of transforms usable for implementing the protocol. +Each of the list elements is a name of an <IPsec-transform> +section. +See below. +.It Em ReplayWindow +The size of the window used for replay protection. +This is normally left alone. +Look at the +.Nm ESP +and +.Nm AH +RFCs for a better description. +.El +.It Em <IPsec-transform> +.Bl -tag -width 12n +.It Em TRANSFORM_ID +The transform ID as given by the RFCs. +.It Em ENCAPSULATION_MODE +The encapsulation mode as given by the RFCs. +This means TRANSPORT or TUNNEL. +.It Em AUTHENTICATION_ALGORITHM +The optional authentication algorithm in the case of this +being an ESP transform. +.It Em GROUP_DESCRIPTION +An optional (provides PFS if present) Diffie-Hellman group +description. +The values are the same as GROUP_DESCRIPTION's +in <ISAKMP-transform> sections shown above. +.It Em Life +List of lifetimes, each element is a <Lifetime> section name. +.El +.It Em <IPsec-ID> +.Bl -tag -width 12n +.It Em ID-type +The ID type as given by the RFCs. +For IPsec this is currently +.Li IPV4_ADDR , +.Li IPV6_ADDR , +.Li IPV4_ADDR_SUBNET +or +.Li IPV6_ADDR_SUBNET . +.It Em Address +If the ID-type is +.Li IPV4_ADDR +or +.Li IPV6_ADDR +this tag should exist and be an IP-address. +.It Em Network +If the ID-type is +.Li IPV4_ADDR_SUBNET +or +.Li IPV6_ADDR_SUBNET +this tag should exist and +be a network address. +.It Em Netmask +If the ID-type is +.Li IPV4_ADDR_SUBNET +or +.Li IPV6_ADDR_SUBNET +this tag should exist and +be a network subnet mask. +.It Em Protocol +If the ID-type is +.Li IPV4_ADDR , +.Li IPV4_ADDR_SUBNET , +.Li IPV6_ADDR +or +.Li IPV6_ADDR_SUBNET +this tag indicates what transport protocol should be transmitted over +the SA. +If left unspecified, all transport protocols between the two address +(ranges) will be sent (or permitted) over that SA. +.It Em Port +If the ID-type is +.Li IPV4_ADDR , +.Li IPV4_ADDR_SUBNET , +.Li IPV6_ADDR +or +.Li IPV6_ADDR_SUBNET +this tag indicates what source or destination port is allowed to be +transported over the SA (depending on whether this is a local or +remote ID). +If left unspecified, all ports of the given transport protocol +will be transmitted (or permitted) over the SA. +The Protocol tag must be specified in conjunction with this tag. +.El +.El +.Ss Other sections +.Bl -hang -width 12n +.It Em <IKECFG-ID> +Parameters to use with IKE mode-config. +One ID per peer. +.Pp +An IKECFG-ID is written as [<ID-type>/<name>]. +The following ID types are supported: +.Bl -tag -width 12n +.It IPv4 +[ipv4/A.B.C.D] +.It IPv6 +[ipv6/abcd:abcd::ab:cd] +.It FQDN +[fqdn/foo.bar.org] +.It UFQDN +[ufqdn/user@foo.bar.org] +.It ASN1_DN +[asn1_dn//C=aa/O=cc/...] (Note the double slashes as the DN itself +starts with a +.Sq / . ) +.El +.Pp +Each section specifies what configuration values to return to the peer +requesting IKE mode-config. +Currently supported values are: +.Bl -tag -width 12n +.It Em Address +The peer's network address. +.It Em Netmask +The peer's netmask. +.It Em Nameserver +The IP address of a DNS nameserver. +.It Em WINS-server +The IP address of a WINS server. +.El +.It Em <Initiator-ID> +.Pp +During phase 1 negotiation +.Nm isakmpd +looks for a pre-shared key in the <ISAKMP-peer> section. +If no Authentication data is specified in that section, and +.Nm isakmpd +is not the initiator, it looks for Authentication data in a section named after +the initiator's phase 1 ID. +This allows mobile users with dynamic IP addresses +to have different shared secrets. +.Pp +This only works for aggressive mode because in main mode the remote +initiator ID would not yet be known. +.Pp +The name of the <Initiator-ID> section depends on the ID type sent by +the initiator. +Currently this can be: +.Bl -tag -width 12n +.It IPv4 +[A.B.C.D] +.It IPv6 +[abcd:abcd::ab:cd] +.It FQDN +[foo.bar.org] +.It UFQDN +[user@foo.bar.org] +.El +.El +.Sh FILES +.Bl -tag -width /etc/isakmpd/isakmpd.conf +.It Pa /etc/isakmpd/isakmpd.conf +The default +.Nm isakmpd +configuration file. +.It Pa /usr/share/ipsec/isakmpd/ +A directory containing some sample +.Nm isakmpd +configuration files. +.El +.Sh EXAMPLES +An example of a configuration file: +.Bd -literal +# A configuration sample for the isakmpd ISAKMP/Oakley (aka IKE) daemon. + +[General] +Listen-on= 10.1.0.2 + +# Incoming phase 1 negotiations are multiplexed on the source IP address +[Phase 1] +10.1.0.1= ISAKMP-peer-west + +# These connections are walked over after config file parsing and told +# to the application layer so that it will inform us when traffic wants to +# pass over them. +This means we can do on-demand keying. +[Phase 2] +Connections= IPsec-east-west + +# Default values are commented out. +[ISAKMP-peer-west] +Phase= 1 +#Transport= udp +Local-address= 10.1.0.2 +Address= 10.1.0.1 +#Port= isakmp +#Port= 500 +#Configuration= Default-phase-1-configuration +Authentication= mekmitasdigoat +#Flags= + +[IPsec-east-west] +Phase= 2 +ISAKMP-peer= ISAKMP-peer-west +Configuration= Default-quick-mode +Local-ID= Net-east +Remote-ID= Net-west +#Flags= + +[Net-west] +ID-type= IPV4_ADDR_SUBNET +Network= 192.168.1.0 +Netmask= 255.255.255.0 + +[Net-east] +ID-type= IPV4_ADDR_SUBNET +Network= 192.168.2.0 +Netmask= 255.255.255.0 + +# Quick mode descriptions + +[Default-quick-mode] +EXCHANGE_TYPE= QUICK_MODE +Suites= QM-ESP-3DES-SHA-PFS-SUITE,QM-ESP-AES-SHA-PFS-SUITE + +# Data for an IKE mode-config peer +[asn1_dn//C=SE/L=SomeCity/O=SomeCompany/CN=SomePeer.company.com] +Address= 192.168.1.123 +Netmask= 255.255.255.0 +Nameserver= 192.168.1.10 +WINS-server= 192.168.1.11 + +# pre-shared key based on initiator's phase 1 ID +[foo.bar.org] +Authentication= mekmitasdigoat + +# +# ##################################################################### +# All configuration data below this point is not required as the example +# uses the predefined Main Mode transform and Quick Mode suite names. +# It is included here for completeness. Note the default values for the +# [General] and [X509-certificates] sections just below. +# ##################################################################### +# + +[General] +Policy-file= /etc/isakmpd/isakmpd.policy +Retransmits= 3 +Exchange-max-time= 120 + +# KeyNote credential storage +[KeyNote] +Credential-directory= /etc/isakmpd/keynote/ + +# Certificates stored in PEM format +[X509-certificates] +CA-directory= /etc/isakmpd/ca/ +Cert-directory= /etc/isakmpd/certs/ +CRL-directory= /etc/isakmpd/crls/ +Private-key= /etc/isakmpd/private/local.key + +# Default phase 1 description (Main Mode) + +[Default-phase-1-configuration] +EXCHANGE_TYPE= ID_PROT +Transforms= 3DES-SHA + +# Main mode transforms +###################### + +# DES + +[DES-MD5] +ENCRYPTION_ALGORITHM= DES_CBC +HASH_ALGORITHM= MD5 +AUTHENTICATION_METHOD= PRE_SHARED +GROUP_DESCRIPTION= MODP_1024 +Life= Default-phase-1-lifetime + +[DES-SHA] +ENCRYPTION_ALGORITHM= DES_CBC +HASH_ALGORITHM= SHA +AUTHENTICATION_METHOD= PRE_SHARED +GROUP_DESCRIPTION= MODP_1024 +Life= Default-phase-1-lifetime + +# 3DES + +[3DES-SHA] +ENCRYPTION_ALGORITHM= 3DES_CBC +HASH_ALGORITHM= SHA +AUTHENTICATION_METHOD= PRE_SHARED +GROUP_DESCRIPTION= MODP_1024 +Life= Default-phase-1-lifetime + +# Blowfish + +[BLF-SHA] +ENCRYPTION_ALGORITHM= BLOWFISH_CBC +KEY_LENGTH= 128,96:192 +HASH_ALGORITHM= SHA +AUTHENTICATION_METHOD= PRE_SHARED +GROUP_DESCRIPTION= MODP_1024 +Life= Default-phase-1-lifetime + +# Blowfish, using DH group 4 (non-default) +[BLF-SHA-EC185] +ENCRYPTION_ALGORITHM= BLOWFISH_CBC +KEY_LENGTH= 128,96:192 +HASH_ALGORITHM= SHA +AUTHENTICATION_METHOD= PRE_SHARED +GROUP_DESCRIPTION= EC2N_185 +Life= Default-phase-1-lifetime + +# Quick mode protection suites +############################## + +# DES + +[QM-ESP-DES-SUITE] +Protocols= QM-ESP-DES + +[QM-ESP-DES-PFS-SUITE] +Protocols= QM-ESP-DES-PFS + +[QM-ESP-DES-MD5-SUITE] +Protocols= QM-ESP-DES-MD5 + +[QM-ESP-DES-MD5-PFS-SUITE] +Protocols= QM-ESP-DES-MD5-PFS + +[QM-ESP-DES-SHA-SUITE] +Protocols= QM-ESP-DES-SHA + +[QM-ESP-DES-SHA-PFS-SUITE] +Protocols= QM-ESP-DES-SHA-PFS + +# 3DES + +[QM-ESP-3DES-SHA-SUITE] +Protocols= QM-ESP-3DES-SHA + +[QM-ESP-3DES-SHA-PFS-SUITE] +Protocols= QM-ESP-3DES-SHA-PFS + +# AES + +[QM-ESP-AES-SHA-SUITE] +Protocols= QM-ESP-AES-SHA + +[QM-ESP-AES-SHA-PFS-SUITE] +Protocols= QM-ESP-AES-SHA-PFS + +# AH + +[QM-AH-MD5-SUITE] +Protocols= QM-AH-MD5 + +[QM-AH-MD5-PFS-SUITE] +Protocols= QM-AH-MD5-PFS + +# AH + ESP (non-default) + +[QM-AH-MD5-ESP-DES-SUITE] +Protocols= QM-AH-MD5,QM-ESP-DES + +[QM-AH-MD5-ESP-DES-MD5-SUITE] +Protocols= QM-AH-MD5,QM-ESP-DES-MD5 + +[QM-ESP-DES-MD5-AH-MD5-SUITE] +Protocols= QM-ESP-DES-MD5,QM-AH-MD5 + +# Quick mode protocols + +# DES + +[QM-ESP-DES] +PROTOCOL_ID= IPSEC_ESP +Transforms= QM-ESP-DES-XF + +[QM-ESP-DES-MD5] +PROTOCOL_ID= IPSEC_ESP +Transforms= QM-ESP-DES-MD5-XF + +[QM-ESP-DES-MD5-PFS] +PROTOCOL_ID= IPSEC_ESP +Transforms= QM-ESP-DES-MD5-PFS-XF + +[QM-ESP-DES-SHA] +PROTOCOL_ID= IPSEC_ESP +Transforms= QM-ESP-DES-SHA-XF + +# 3DES + +[QM-ESP-3DES-SHA] +PROTOCOL_ID= IPSEC_ESP +Transforms= QM-ESP-3DES-SHA-XF + +[QM-ESP-3DES-SHA-PFS] +PROTOCOL_ID= IPSEC_ESP +Transforms= QM-ESP-3DES-SHA-PFS-XF + +[QM-ESP-3DES-SHA-TRP] +PROTOCOL_ID= IPSEC_ESP +Transforms= QM-ESP-3DES-SHA-TRP-XF + +# AES + +[QM-ESP-AES-SHA] +PROTOCOL_ID= IPSEC_ESP +Transforms= QM-ESP-AES-SHA-XF + +[QM-ESP-AES-SHA-PFS] +PROTOCOL_ID= IPSEC_ESP +Transforms= QM-ESP-AES-SHA-PFS-XF + +[QM-ESP-AES-SHA-TRP] +PROTOCOL_ID= IPSEC_ESP +Transforms= QM-ESP-AES-SHA-TRP-XF + +# AH MD5 + +[QM-AH-MD5] +PROTOCOL_ID= IPSEC_AH +Transforms= QM-AH-MD5-XF + +[QM-AH-MD5-PFS] +PROTOCOL_ID= IPSEC_AH +Transforms= QM-AH-MD5-PFS-XF + +# Quick mode transforms + +# ESP DES+MD5 + +[QM-ESP-DES-XF] +TRANSFORM_ID= DES +ENCAPSULATION_MODE= TUNNEL +Life= Default-phase-2-lifetime + +[QM-ESP-DES-MD5-XF] +TRANSFORM_ID= DES +ENCAPSULATION_MODE= TUNNEL +AUTHENTICATION_ALGORITHM= HMAC_MD5 +Life= Default-phase-2-lifetime + +[QM-ESP-DES-MD5-PFS-XF] +TRANSFORM_ID= DES +ENCAPSULATION_MODE= TUNNEL +GROUP_DESCRIPTION= MODP_1024 +AUTHENTICATION_ALGORITHM= HMAC_MD5 +Life= Default-phase-2-lifetime + +[QM-ESP-DES-SHA-XF] +TRANSFORM_ID= DES +ENCAPSULATION_MODE= TUNNEL +AUTHENTICATION_ALGORITHM= HMAC_SHA +Life= Default-phase-2-lifetime + +# 3DES + +[QM-ESP-3DES-SHA-XF] +TRANSFORM_ID= 3DES +ENCAPSULATION_MODE= TUNNEL +AUTHENTICATION_ALGORITHM= HMAC_SHA +Life= Default-phase-2-lifetime + +[QM-ESP-3DES-SHA-PFS-XF] +TRANSFORM_ID= 3DES +ENCAPSULATION_MODE= TUNNEL +AUTHENTICATION_ALGORITHM= HMAC_SHA +GROUP_DESCRIPTION= MODP_1024 +Life= Default-phase-2-lifetime + +[QM-ESP-3DES-SHA-TRP-XF] +TRANSFORM_ID= 3DES +ENCAPSULATION_MODE= TRANSPORT +AUTHENTICATION_ALGORITHM= HMAC_SHA +Life= Default-phase-2-lifetime + +# AES + +[QM-ESP-AES-SHA-XF] +TRANSFORM_ID= AES +ENCAPSULATION_MODE= TUNNEL +AUTHENTICATION_ALGORITHM= HMAC_SHA +Life= Default-phase-2-lifetime + +[QM-ESP-AES-SHA-PFS-XF] +TRANSFORM_ID= AES +ENCAPSULATION_MODE= TUNNEL +AUTHENTICATION_ALGORITHM= HMAC_SHA +GROUP_DESCRIPTION= MODP_1024 +Life= Default-phase-2-lifetime + +[QM-ESP-AES-SHA-TRP-XF] +TRANSFORM_ID= AES +ENCAPSULATION_MODE= TRANSPORT +AUTHENTICATION_ALGORITHM= HMAC_SHA +Life= Default-phase-2-lifetime + +# AH + +[QM-AH-MD5-XF] +TRANSFORM_ID= MD5 +ENCAPSULATION_MODE= TUNNEL +AUTHENTICATION_ALGORITHM= HMAC_MD5 +Life= Default-phase-2-lifetime + +[QM-AH-MD5-PFS-XF] +TRANSFORM_ID= MD5 +ENCAPSULATION_MODE= TUNNEL +GROUP_DESCRIPTION= MODP_1024 +Life= Default-phase-2-lifetime + +[Sample-Life-Time] +LIFE_TYPE= SECONDS +LIFE_DURATION= 3600,1800:7200 + +[Sample-Life-Volume] +LIFE_TYPE= KILOBYTES +LIFE_DURATION= 1000,768:1536 +.Ed +.Sh SEE ALSO +.Xr keynote 1 , +.Xr ipsec 4 , +.Xr keynote 4 , +.Xr isakmpd.policy 5 , +.Xr isakmpd 8 +.Sh BUGS +The RFCs do not permit differing DH groups in the same proposal for +aggressive and quick mode exchanges. +Mixing both PFS and non-PFS suites in a quick mode proposal is not possible, +as PFS implies using a DH group. diff --git a/keyexchange/isakmpd-20041012/isakmpd.policy.5 b/keyexchange/isakmpd-20041012/isakmpd.policy.5 new file mode 100644 index 0000000..64800db --- /dev/null +++ b/keyexchange/isakmpd-20041012/isakmpd.policy.5 @@ -0,0 +1,638 @@ +.\" $OpenBSD: isakmpd.policy.5,v 1.35 2003/10/25 20:47:47 mcbride Exp $ +.\" $EOM: isakmpd.policy.5,v 1.24 2000/11/23 12:55:25 niklas Exp $ +.\" +.\" Copyright (c) 1999-2001, Angelos D. Keromytis. 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. +.\" +.\" 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. +.\" +.\" +.\" Manual page, using -mandoc macros +.\" +.Dd June 15, 2002 +.Dt ISAKMPD.POLICY 5 +.Os +.Sh NAME +.Nm isakmpd.policy +.Nd policy configuration file for isakmpd +.Sh DESCRIPTION +.Nm +is the policy configuration file for the +.Nm isakmpd +daemon managing security association and key management for the +.Xr ipsec 4 +layer of the kernel's networking stack. +.Pp +The +.Xr isakmpd 8 +daemon (also known as IKE, for Internet Key Exchange) is used when two +systems need to automatically set up a pair of Security Associations +(SAs) for securely communicating using IPsec. +IKE operates in two stages: +.Pp +In the first stage (Main or Identity Protection Mode), the two IKE +daemons establish a secure link between themselves, fully +authenticating each other and establishing key material for +encrypting/authenticating future communications between them. +This step is typically only performed once for every pair of IKE daemons. +.Pp +In the second stage (also called Quick Mode), the two IKE daemons +create the pair of SAs for the parties that wish to communicate using +IPsec. +These parties may be the hosts the IKE daemons run on, a host +and a network behind a firewall, or two networks behind their +respective firewalls. +At this stage, the exact parameters of the SAs +(e.g., algorithms to use, encapsulation mode, lifetime) and the +identities of the communicating parties (hosts, networks, etc.) are +specified. +The reason for the existence of Quick Mode is to allow for fast +SA setup, once the more heavy-weight Main Mode has been completed. +Generally, Quick Mode uses the key material derived from Main Mode to +provide keys to the IPsec transforms to be used. +Alternatively, a new +Diffie-Hellman computation may be performed (significantly slowing +down the exchange, but at the same time providing Perfect Forward +Secrecy (PFS)). +Briefly, this means that even should an attacker +manage to break long-term keys used in other sessions (or, +specifically, if an attacker breaks the Diffie-Hellman exchange +performed during Main Mode), they will not be able to decrypt this +traffic. +Normally, no PFS is provided (the key material used by the +IPsec SAs established as a result of this exchange will be derived +from the key material of the Main Mode exchange), allowing for a +faster Quick Mode exchange (no public key computations). +.Pp +IKE proposals are "suggestions" by the initiator of an exchange to the +responder as to what protocols and attributes should be used on a +class of packets. +For example, a given exchange may ask for ESP with +3DES and MD5 and AH with SHA1 (applied successively on the same +packet), or just ESP with Blowfish and RIPEMD-160. +The responder +examines the proposals and determines which of them are acceptable, +according to policy and any credentials. +.Pp +The following paragraphs assume some knowledge of the contents of the +.Xr keynote 4 +and +.Xr keynote 5 +man pages. +.Pp +In the KeyNote policy model for IPsec, no distinction is currently +made based on the ordering of AH and ESP in the packet. +Should this +change in the future, an appropriate attribute (see below) will be +added. +.Pp +The goal of security policy for IKE is thus to determine, based on +local policy (provided in the +.Nm isakmpd.policy +file), credentials provided during the IKE exchanges (or obtained +through other means), the SA attributes proposed during the exchange, +and perhaps other (side-channel) information, whether a pair of SAs +should be installed in the system (in fact, whether both the IPsec SAs +and the flows should be installed). +For each proposal suggested by or +to the remote IKE daemon, the KeyNote system is consulted as to +whether the proposal is acceptable based on local policy (contained in +.Nm isakmpd.policy , +in the form of policy assertions) and remote credentials (e.g., +KeyNote credentials or X509 certificates provided by the remote IKE +daemon). +.Pp +.Nm isakmpd.policy +is simply a flat +.Xr ascii 7 +file containing KeyNote policy assertions, separated by blank lines +(note that KeyNote assertions may not contain blank lines). +.Nm isakmpd.policy +is read when +.Xr isakmpd 8 +is first started, and every time it receives a +.Dv SIGHUP +signal. +The new policies read will be used for all new Phase 2 (IPsec) +SAs established from that point on (even if the associated Phase 1 SA +was already established when the new policies were loaded). +The policy change will not affect already established Phase 2 SAs. +.Pp +For more details on KeyNote assertion format, please see +.Xr keynote 5 . +Briefly, KeyNote policy assertions used in IKE have the following +characteristics: +.Bl -bullet +.It +The Authorizer field is typically "POLICY" (but see the examples +below, for use of policy delegation). +.It +The Licensees field can be an expression of passphrases used for +authentication of the Main Mode exchanges, and/or public keys +(typically, X509 certificates), and/or X509 distinguished names. +.It +The Conditions field contains an expression of attributes from the +IPsec policy action set (see below as well as the keynote syntax man +page for more details). +.It +The ordered return-values set for IPsec policy is "false, true". +.El +.Pp +For an explanation of these fields and their semantics, see +.Xr keynote 5 . +.Pp +For example, the following policy assertion: +.Bd -literal + Authorizer: "POLICY" + Licensees: "passphrase:foobar" || "x509-base64:abcd==" || + "passphrase-md5-hex:3858f62230ac3c915f300c664312c63f" || + "passphrase-sha1-hex:8843d7f92416211de9ebb963ff4ce28125932878" + Conditions: app_domain == "IPsec policy" && esp_present == "yes" + && esp_enc_alg != "null" -> "true"; +.Ed +.Pp +says that any proposal from a remote host that authenticates using the +passphrase "foobar" or the public key contained in the X509 +certificate encoded as "abcd==" will be accepted, as long as it +contains ESP with a non-null algorithm (i.e., the packet will be +encrypted). +The last two authorizers are the MD5 and SHA1 hashes respectively of +the passphrase "foobar". +This form may be used instead of the "passphrase:..." one to protect +the passphrase as included in the policy file (or as distributed in a +signed credential). +.Pp +The following policy assertion: +.Bd -literal + Authorizer: "POLICY" + Licensees: "DN:/CN=CA Certificate" + Conditions: app_domain == "IPsec policy" && esp_present == "yes" + && esp_enc_alg != "null" -> "true"; +.Ed +.Pp +is similar to the previous one, but instead of including a complete +X509 credential in the Licensees field, only the X509 certificate's +Subject Canonical Name needs to be specified (note that the "DN:" +prefix is necessary). +.Pp +KeyNote credentials have the same format as policy assertions, with +one difference: the Authorizer field always contains a public key, and +the assertion is signed (and thus its integrity can be +cryptographically verified). +Credentials are used to build chains of delegation of authority. +They can be exchanged during an IKE exchange, +or can be retrieved through some out-of-band mechanism (no such +mechanism is currently supported in this implementation however). +See +.Xr isakmpd.conf 5 +on how to specify what credentials to send in an IKE exchange. +.Pp +Passphrases that appear in the Licensees field are encoded as the +string "passphrase:", followed by the passphrase itself +(case-sensitive). +Alternatively (and preferably), they may be encoded using the +"passphrase-md5-hex:" or "passphrase-sha1-hex:" prefixes, followed +by the +.Xr md5 1 +or +.Xr sha1 1 +hash of the passphrase itself, encoded as a hexadecimal string (using +lower-case letters only). +.Pp +When X509-based authentication is performed in Main Mode, any X509 +certificates received from the remote IKE daemon are converted to very +simple KeyNote credentials. +The conversion is straightforward: the +issuer of the X509 certificate becomes the Authorizer of the KeyNote +credential, the subject becomes the only Licensees entry, while the +Conditions field simply asserts that the credential is only valid for +"IPsec policy" use (see the app_domain action attribute below). +.Pp +Similarly, any X509 CA certificates present in the directory pointed +to by the appropriate +.Xr isakmpd.conf 5 +entry, are converted to such pseudo-credentials. +This allows one to +write KeyNote policies that delegate specific authority to CAs (and +the keys those CAs certify, recursively). +.Pp +For more details on KeyNote assertion format, see +.Xr keynote 5 . +.Pp +Information about the proposals, the identity of the remote IKE +daemon, the packet classes to be protected, etc. are encoded in what +is called an action set. +The action set is composed of name-value +attributes, similar in some ways to shell environment variables. +These values are initialized by +.Nm isakmpd +before each query to the KeyNote system, and can be tested against in +the Conditions field of assertions. +See +.Xr keynote 4 +and +.Xr keynote 5 +for more details on the format and semantics of the Conditions field. +.Pp +Note that assertions and credentials can make references to +non-existent attributes without catastrophic failures (access may be +denied, depending on the overall structure, but will not be +accidentally granted). +One reason for credentials referencing +non-existent attributes is that they were defined within a specific +implementation or network only. +.Pp +In the following attribute set, IPv4 addresses are encoded as ASCII +strings in the usual dotted-quad format. +However, all quads are three digits long. +For example, the IPv4 address +.Va 10.128.1.12 +would be encoded as +.Va 010.128.001.012 . +Similarly, IPv6 addresses are encoded in the standard x:x:x:x:x:x:x:x +format, where the 'x's are the hexadecimal values of the eight 16-bit +pieces of the address. +All 'x's are four digits long. +For example, the address +.Va 1080:0:12:0:8:800:200C:417A +would be encoded as +.Va 1080:0000:0012:0000:0008:0800:200C:417A . +.Pp +The following attributes are currently defined: +.Bl -tag -width -indent +.It app_domain +Always set to +.Va IPsec policy . +.It doi +Always set to +.Va ipsec . +.It initiator +Set to +.Va yes +if the local daemon is initiating the Phase 2 SA, +.Va no +otherwise. +.It phase_1 +Set to +.Va aggressive +if aggressive mode was used to establish the Phase 1 SA, or +.Va main +if main mode was used instead. +.It pfs +Set to +.Va yes +if a Diffie-Hellman exchange will be performed during this Quick Mode, +.Va no +otherwise. +.It ah_present, esp_present, comp_present +Set to +.Va yes +if an AH, ESP, or compression proposal was received respectively, +.Va no +otherwise. +.It ah_hash_alg +One of +.Va md5 , +.Va sha , +.Va ripemd , +.Va sha2-256 , +.Va sha2-385 , +.Va sha2-512 , +or +.Va des , +based on the hash algorithm specified in the AH proposal. +This attribute describes the generic transform to be used in the AH +authentication. +.It esp_enc_alg +One of +.Va des , +.Va des-iv64 , +.Va 3des , +.Va rc4 , +.Va idea , +.Va cast , +.Va blowfish , +.Va 3idea , +.Va des-iv32 , +.Va rc4 , +.Va null , +or +.Va aes , +based on the encryption algorithm specified in the ESP proposal. +.It comp_alg +One of +.Va oui , +.Va deflate , +.Va lzs , +or +.Va v42bis , +based on the compression algorithm specified in the compression +proposal. +.It ah_auth_alg +One of +.Va hmac-md5 , +.Va hmac-sha , +.Va des-mac , +.Va kpdk , +.Va hmac-sha2-256 , +.Va hmac-sha2-385 , +.Va hmac-sha2-512 , +or +.Va hmac-ripemd . +based on the authentication method specified in the AH proposal. +.It esp_auth_alg +One of +.Va hmac-md5 , +.Va hmac-sha , +.Va des-mac , +.Va kpdk , +.Va hmac-sha2-256 , +.Va hmac-sha2-385 , +.Va hmac-sha2-512 , +or +.Va hmac-ripemd +based on the authentication method specified in the ESP proposal. +.It ah_life_seconds, esp_life_seconds, comp_life_seconds +Set to the lifetime of the AH, ESP, and compression proposal, in +seconds. +If no lifetime was proposed for the corresponding protocol +(e.g., there was no proposal for AH), the corresponding attribute will +be set to zero. +.It ah_life_kbytes, esp_life_kbytes, comp_life_kbytes +Set to the lifetime of the AH, ESP, and compression proposal, in +kbytes of traffic. +If no lifetime was proposed for the corresponding +protocol (e.g., there was no proposal for AH), the corresponding +attribute will be set to zero. +.It ah_encapsulation, esp_encapsulation, comp_encapsulation +Set to +.Va tunnel +or +.Va transport , +based on the AH, ESP, and compression proposal. +.It ah_ecn, esp_ecn, comp_ecn +Set to +.Va yes +or +.Va no , +based on whether ECN was requested for the IPsec tunnel. +.It comp_dict_size +Specifies the log2 maximum size of the dictionary, according to the +compression proposal. +.It comp_private_alg +Set to an integer specifying the private algorithm in use, according +to the compression proposal. +.It ah_key_length, esp_key_length +The number of key bits to be used by the authentication and encryption +algorithms respectively (for variable key-size algorithms). +.It ah_key_rounds, esp_key length +The number of rounds of the authentication and encryption algorithms +respectively (for variable round algorithms). +.It ah_group_desc, esp_group_desc, comp_group_desc +The Diffie-Hellman group identifier from the AH, ESP, and compression +proposal, used for PFS during Quick Mode (see the pfs attribute +above). +If more than one of these attributes are set to a value other +than zero, they should have the same value (in valid IKE proposals). +Valid values are 1 (768-bit MODP), 2 (1024-bit MODP), 3 (155-bit EC), +4 (185-bit EC), and 5 (1536-bit MODP). +.It phase1_group_desc +The Diffie-Hellman group identifier used in IKE Phase 1. +Takes the same values as +.Va ah_group_desc . +.It remote_filter_type, local_filter_type, remote_id_type +Set to +.Va IPv4 address , +.Va IPv4 range , +.Va IPv4 subnet , +.Va IPv6 address , +.Va IPv6 range , +.Va IPv6 subnet , +.Va FQDN , +.Va User FQDN , +.Va ASN1 DN , +.Va ASN1 GN , +or +.Va Key ID , +based on the Quick Mode Initiator ID, Quick Mode Responder ID, and +Main Mode peer ID respectively. +.It remote_filter_addr_upper, local_filter_addr_upper, remote_id_addr_upper +When the corresponding filter_type is +.Va IPv4 address +or +.Va IPv6 address , +these contain the respective address. +For +.Va IPv4 range +or +.Va IPv6 range , +they contain the upper end of the address range. +For +.Va IPv4 subnet +or +.Va IPv6 subnet , +they contain the highest address in the specified subnet. +.It remote_filter_addr_lower, local_filter_addr_lower, remote_id_addr_lower +When the corresponding filter_type is +.Va IPv4 address +or +.Va IPv6 address , +these contain the respective address. +For +.Va IPv4 range +or +.Va IPv6 range , +these contain the lower end of the address range. +For +.Va IPv4 subnet +or +.Va IPv6 subnet , +these contain the lowest address in the specified subnet. +.It remote_filter, local_filter, remote_id +When the corresponding filter_type specifies an address range or +subnet, these are set to the upper and lower part of the address +space separated by a dash ('-') character (if the type specifies a +single address, they are set to that address). +.Pp +For FQDN and User FQDN types, these are set to the respective string. +For Key ID, these are set to the hexadecimal representation of the +associated byte string (lower-case letters used) if the Key ID payload +contains non-printable characters. +Otherwise, they are set to the respective string. +.Pp +For ASN1 DN, these are set to the text encoding of the Distinguished +Name in the payload sent or received. +The format is the same as that used in the Licensees field. +.It remote_filter_port, local_filter_port, remote_id_port +Set to the transport protocol port. +.It remote_filter_proto, local_filter_proto, remote_id_proto +Set to +.Va etherip , +.Va tcp , +.Va udp , +or the transport protocol number, depending on the transport protocol set +in the IDci, IDcr, and Main Mode peer ID respectively. +.It remote_negotiation_address +Set to the IPv4 or IPv6 address of the remote IKE daemon. +.It local_negotiation_address +Set to the IPv4 or IPv6 address of the local interface used by the local IKE +daemon for this exchange. +.It GMTTimeOfDay +Set to the UTC date/time, in YYYYMMDDHHmmSS format. +.It LocalTimeOfDay +Set to the local date/time, in YYYYMMDDHHmmSS format. +.El +.Sh FILES +.Bl -tag -width /etc/isakmpd/isakmpd.policy +.It Pa /etc/isakmpd/isakmpd.policy +The default +.Nm isakmpd +policy configuration file. +.It Pa /usr/share/ipsec/isakmpd/policy +A sample +.Nm isakmpd +policy configuration file. +.El +.Sh EXAMPLES +.Bd -literal + Authorizer: "POLICY" + Comment: This bare-bones assertion accepts everything + + + + Authorizer: "POLICY" + Licensees: "passphrase-md5-hex:10838982612aff543e2e62a67c786550" + Comment: This policy accepts anyone using shared-secret + authentication using the password mekmitasisgoat, + and does ESP with some form of encryption (not null). + Conditions: app_domain == "IPsec policy" && + esp_present == "yes" && + esp_enc_alg != "null" -> "true"; + + + + Authorizer: "POLICY" + Licensees: "subpolicy1" || "subpolicy2" + Comment: Delegate to two other sub-policies, so we + can manage our policy better. Since these subpolicies + are not "owned" by a key (and are thus unsigned), they + have to be in isakmpd.policy. + Conditions: app_domain == "IPsec policy"; + + + + KeyNote-Version: 2 + Licensees: "passphrase-md5-hex:9c42a1346e333a770904b2a2b37fa7d3" + Conditions: esp_present == "yes" -> "true"; + Authorizer: "subpolicy1" + + + + Conditions: ah_present == "yes" -> + { + ah_auth_alg == "md5" -> "true"; + ah_auth_alg == "sha" && + esp_present == "no" -> "true"; + }; + Licensees: "passphrase:otherpassword" || + "passphrase-sha1-hex:f5ed6e4abd30c36a89409b5da7ecb542c9fbf00f" + Authorizer: "subpolicy2" + + + + keynote-version: 2 + comment: this is an example of a policy delegating to a CN. + authorizer: "POLICY" + licensees: "DN:/CN=CA Certificate/emailAddress=ca@foo.bar.com" + + + + keynote-version: 2 + comment: This is an example of a policy delegating to a key. + authorizer: "POLICY" + licensees: "x509-base64:MIICGDCCAYGgAwIBAgIBADANBgkqhkiG9w0BAQQ\\ + FADBSMQswCQYDVQQGEwJHQjEOMAwGA1UEChMFQmVuQ28xETAPBg\\ + NVBAMTCEJlbkNvIENBMSAwHgYJKoZIhvcNAQkBFhFiZW5AYWxnc\\ + m91cC5jby51azAeFw05OTEwMTEyMjQ5MzhaFw05OTExMTAyMjQ5\\ + MzhaMFIxCzAJBgNVBAYTAkdCMQ4wDAYDVQQKEwVCZW5DbzERMA8\\ + GA1UEAxMIQmVuQ28gQ0ExIDAeBgkqhkiG9w0BCQEWEWJlbkBhbG\\ + dyb3VwLmNvLnVrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBg\\ + QCxyAte2HEVouXg1Yu+vDihbnjDRn+6k00Rv6cZqbwA3BQ30mC/\\ + 3TFJ09VGXCaM0UKfpnxIpkBYLmOA3FWkKI0RvPU7E1AhKkhC1Ds\\ + PSBFjYHrB15T5lYzgfwKJCIxTDzZDx2iobUgPa0FRNGVUjpQ4/k\\ + MJ2BF4Wh7zY3X08rMzsQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBA\\ + DWJ5pbTcE7iKHWLQTMYiz8i9jGi5+Eo1yr1Bab90tgaGQV0zrRH\\ + jDHgAAy1h8WSXuyQrXfgbx2rnWFPhx9CfmuAXn7sZmQE3mnUqeP\\ + ZL2dW87jdBGqtoUdNcoz5zKBkC943yasNui/O01MiqgadTThTJH\\ + d1Pn17LbJC1ZVRNjR5" + conditions: app_domain == "IPsec policy" && doi == "ipsec" && + pfs == "yes" && esp_present == "yes" && ah_present == "no" && + (esp_enc_alg == "3des" || esp_enc_alg == "aes") -> "true"; + + + + keynote-version: 2 + comment: This is an example of a credential, the signature does + not really verify (although the keys are real). + licensees: "x509-base64:MIICGDCCAYGgAwIBAgIBADANBgkqhkiG9w0BAQQ\\ + FADBSMQswCQYDVQQGEwJHQjEOMAwGA1UEChMFQmVuQ28xETAPBg\\ + NVBAMTCEJlbkNvIENBMSAwHgYJKoZIhvcNAQkBFhFiZW5AYWxnc\\ + m91cC5jby51azAeFw05OTEwMTEyMzA2MjJaFw05OTExMTAyMzA2\\ + MjJaMFIxCzAJBgNVBAYTAkdCMQ4wDAYDVQQKEwVCZW5DbzERMA8\\ + GA1UEAxMIQmVuQ28gQ0ExIDAeBgkqhkiG9w0BCQEWEWJlbkBhbG\\ + dyb3VwLmNvLnVrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBg\\ + QDaCs+JAB6YRKAVkoi1NkOpE1V3syApjBj0Ahjq5HqYAACo1JhM\\ + +QsPwuSWCNhBT51HX6G6UzfY3mOUz/vou6MJ/wor8EdeTX4nucx\\ + NSz/r6XI262aXezAp+GdBviuJZx3Q67ON/IWYrB4QtvihI4bMn5\\ + E55nF6TKtUMJTdATvs/wIDAQABMA0GCSqGSIb3DQEBBAUAA4GBA\\ + MaQOSkaiR8id0h6Zo0VSB4HpBnjpWqz1jNG8N4RPN0W8muRA2b9\\ + 85GNP1bkC3fK1ZPpFTB0A76lLn11CfhAf/gV1iz3ELlUHo5J8nx\\ + Pu6XfsGJm3HsXJOuvOog8Aean4ODo4KInuAsnbLzpGl0d+Jqa5u\\ + TZUxsyg4QOBwYEU92H" + authorizer: "x509-base64:MIICGDCCAYGgAwIBAgIBADANBgkqhkiG9w0BAQQ\\ + FADBSMQswCQYDVQQGEwJHQjEOMAwGA1UEChMFQmVuQ28xETAPBg\\ + NVBAMTCEJlbkNvIENBMSAwHgYJKoZIhvcNAQkBFhFiZW5AYWxnc\\ + m91cC5jby51azAeFw05OTEwMTEyMjQ5MzhaFw05OTExMTAyMjQ5\\ + MzhaMFIxCzAJBgNVBAYTAkdCMQ4wDAYDVQQKEwVCZW5DbzERMA8\\ + GA1UEAxMIQmVuQ28gQ0ExIDAeBgkqhkiG9w0BCQEWEWJlbkBhbG\\ + dyb3VwLmNvLnVrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBg\\ + QCxyAte2HEVouXg1Yu+vDihbnjDRn+6k00Rv6cZqbwA3BQ30mC/\\ + 3TFJ09VGXCaM0UKfpnxIpkBYLmOA3FWkKI0RvPU7E1AhKkhC1Ds\\ + PSBFjYHrB15T5lYzgfwKJCIxTDzZDx2iobUgPa0FRNGVUjpQ4/k\\ + MJ2BF4Wh7zY3X08rMzsQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBA\\ + DWJ5pbTcE7iKHWLQTMYiz8i9jGi5+Eo1yr1Bab90tgaGQV0zrRH\\ + jDHgAAy1h8WSXuyQrXfgbx2rnWFPhx9CfmuAXn7sZmQE3mnUqeP\\ + ZL2dW87jdBGqtoUdNcoz5zKBkC943yasNui/O01MiqgadTThTJH\\ + d1Pn17LbJC1ZVRNjR5" +conditions: app_domain == "IPsec policy" && doi == "ipsec" && + pfs == "yes" && esp_present == "yes" && ah_present == "no" && + (esp_enc_alg == "3des" || esp_enc_alg == "aes") -> "true"; +Signature: "sig-x509-sha1-base64:ql+vrUxv14DcBOQHR2jsbXayq6T\\ + mmtMiUB745a8rjwSrQwh+KIVDlUrghPnqhSIkWSDi9oWWMbfg\\ + mkdudZ0wjgeTLMI2NI4GibMMsToakOKMex/0q4cpdpln3DKcQ\\ + IcjzRv4khDws69FT3QfELjcpShvbLrXmh1Z00OFmxjyqDw=" +.Ed +.Sh SEE ALSO +.Xr ipsec 4 , +.Xr keynote 4 , +.Xr keynote 5 , +.Xr isakmpd 8 +.Sh BUGS +A more sane way of expressing IPv6 address ranges is needed. diff --git a/keyexchange/isakmpd-20041012/key.c b/keyexchange/isakmpd-20041012/key.c new file mode 100644 index 0000000..bc3c9fc --- /dev/null +++ b/keyexchange/isakmpd-20041012/key.c @@ -0,0 +1,213 @@ +/* $OpenBSD: key.c,v 1.19 2004/09/17 13:53:08 ho Exp $ */ +/* + * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu) + * + * Copyright (c) 2000-2001 Angelos D. Keromytis. + * + * Permission to use, copy, and modify this software with or without fee + * is hereby granted, provided that this entire notice is included in + * all copies of any software which is or includes a copy or + * modification of this software. + * You may use this code under the GNU public license if you so wish. Please + * contribute changes back to the authors under this freer than GPL license + * so that we may further the use of strong encryption without limitations to + * all. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE + * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR + * PURPOSE. + */ + +#include <string.h> +#include <stdlib.h> + +#include "sysdep.h" + +#include "key.h" +#include "libcrypto.h" +#include "log.h" +#include "util.h" +#ifdef USE_X509 +#include "x509.h" +#endif + +void +key_free(int type, int private, void *key) +{ + switch (type) { + case ISAKMP_KEY_PASSPHRASE: + free(key); + break; + case ISAKMP_KEY_RSA: +#ifdef USE_X509 + RSA_free(key); + break; +#endif + case ISAKMP_KEY_NONE: + default: + log_error("key_free: unknown/unsupportedkey type %d", type); + break; + } +} + +/* Convert from internal form to serialized */ +void +key_serialize(int type, int private, void *key, u_int8_t **data, + size_t *datalenp) +{ +#ifdef USE_X509 + u_int8_t *p; + size_t datalen; +#endif + + switch (type) { + case ISAKMP_KEY_PASSPHRASE: + *datalenp = strlen((char *)key); + *data = (u_int8_t *)strdup((char *)key); + break; + case ISAKMP_KEY_RSA: +#ifdef USE_X509 + switch (private) { + case ISAKMP_KEYTYPE_PUBLIC: + datalen = i2d_RSAPublicKey((RSA *)key, NULL); + *data = p = malloc(datalen); + if (!p) { + log_error("key_serialize: malloc (%lu) failed", + (unsigned long)datalen); + return; + } + *datalenp = i2d_RSAPublicKey((RSA *) key, &p); + break; + + case ISAKMP_KEYTYPE_PRIVATE: + datalen = i2d_RSAPrivateKey((RSA *)key, NULL); + *data = p = malloc(datalen); + if (!p) { + log_error("key_serialize: malloc (%lu) failed", + (unsigned long)datalen); + return; + } + *datalenp = i2d_RSAPrivateKey((RSA *)key, &p); + break; + } +#endif + break; + default: + log_error("key_serialize: unknown/unsupported key type %d", + type); + break; + } +} + +/* Convert from serialized to printable */ +char * +key_printable(int type, int private, u_int8_t *data, int datalen) +{ +#ifdef USE_X509 + char *s; + int i; +#endif + + switch (type) { + case ISAKMP_KEY_PASSPHRASE: + return strdup((char *)data); + + case ISAKMP_KEY_RSA: +#ifdef USE_X509 + s = malloc(datalen * 2 + 1); + if (!s) { + log_error("key_printable: malloc (%d) failed", + datalen * 2 + 1); + return 0; + } + for (i = 0; i < datalen; i++) + snprintf(s + (2 * i), 2 * (datalen - i) + 1, "%02x", + data[i]); + return s; +#endif + + default: + log_error("key_printable: unknown/unsupported key type %d", + type); + return 0; + } +} + +/* Convert from serialized to internal. */ +void * +key_internalize(int type, int private, u_int8_t *data, int datalen) +{ + switch (type) { + case ISAKMP_KEY_PASSPHRASE: + return strdup((char *)data); + case ISAKMP_KEY_RSA: +#ifdef USE_X509 + switch (private) { +#if OPENSSL_VERSION_NUMBER >= 0x00907000L + case ISAKMP_KEYTYPE_PUBLIC: + return d2i_RSAPublicKey(NULL, + (const u_int8_t **)&data, datalen); + case ISAKMP_KEYTYPE_PRIVATE: + return d2i_RSAPrivateKey(NULL, + (const u_int8_t **)&data, datalen); +#else + case ISAKMP_KEYTYPE_PUBLIC: + return d2i_RSAPublicKey(NULL, &data, datalen); + case ISAKMP_KEYTYPE_PRIVATE: + return d2i_RSAPrivateKey(NULL, &data, datalen); +#endif + default: + log_error("key_internalize: not public or private " + "RSA key passed"); + return 0; + } + break; +#endif /* USE_X509 */ + default: + log_error("key_internalize: unknown/unsupported key type %d", + type); + break; + } + + return 0; +} + +/* Convert from printable to serialized */ +void +key_from_printable(int type, int private, char *key, u_int8_t **data, + u_int32_t *datalenp) +{ +#ifdef USE_X509 + u_int32_t datalen; +#endif + + switch (type) { + case ISAKMP_KEY_PASSPHRASE: + *datalenp = strlen(key); + *data = (u_int8_t *) strdup(key); + break; + + case ISAKMP_KEY_RSA: +#ifdef USE_X509 + datalen = (strlen(key) + 1) / 2; /* Round up, just in case */ + *data = malloc(datalen); + if (!*data) { + log_error("key_from_printable: malloc (%d) failed", + datalen); + *datalenp = 0; + return; + } + *datalenp = hex2raw(key, *data, datalen); + break; +#endif + + default: + log_error("key_from_printable: " + "unknown/unsupported key type %d", type); + *data = NULL; + *datalenp = 0; + break; + } +} diff --git a/keyexchange/isakmpd-20041012/key.h b/keyexchange/isakmpd-20041012/key.h new file mode 100644 index 0000000..81b1328 --- /dev/null +++ b/keyexchange/isakmpd-20041012/key.h @@ -0,0 +1,39 @@ +/* $OpenBSD: key.h,v 1.7 2004/04/15 18:39:26 deraadt Exp $ */ +/* + * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu) + * + * Copyright (c) 2000-2001 Angelos D. Keromytis. + * + * Permission to use, copy, and modify this software with or without fee + * is hereby granted, provided that this entire notice is included in + * all copies of any software which is or includes a copy or + * modification of this software. + * You may use this code under the GNU public license if you so wish. Please + * contribute changes back to the authors under this freer than GPL license + * so that we may further the use of strong encryption without limitations to + * all. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE + * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR + * PURPOSE. + */ + +#ifndef _KEY_H_ +#define _KEY_H_ + +#define ISAKMP_KEY_NONE 0 +#define ISAKMP_KEY_PASSPHRASE 1 +#define ISAKMP_KEY_RSA 2 +#define ISAKMP_KEY_DSA 3 + +#define ISAKMP_KEYTYPE_PUBLIC 0 +#define ISAKMP_KEYTYPE_PRIVATE 1 + +void key_free(int, int, void *); +void key_serialize(int, int, void *, u_int8_t **, size_t *); +char *key_printable(int, int, u_int8_t *, int); +void key_from_printable(int, int, char *, u_int8_t **, u_int32_t *); +void *key_internalize(int, int, u_int8_t *, int); +#endif /* _KEY_H_ */ diff --git a/keyexchange/isakmpd-20041012/libcrypto.c b/keyexchange/isakmpd-20041012/libcrypto.c new file mode 100644 index 0000000..d66c58a --- /dev/null +++ b/keyexchange/isakmpd-20041012/libcrypto.c @@ -0,0 +1,49 @@ +/* $OpenBSD: libcrypto.c,v 1.16 2004/04/15 18:39:26 deraadt Exp $ */ +/* $EOM: libcrypto.c,v 1.14 2000/09/28 12:53:27 niklas Exp $ */ + +/* + * Copyright (c) 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 1999, 2000 Angelos D. Keromytis. 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. + * + * 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 "sysdep.h" +#include "libcrypto.h" + +void +libcrypto_init(void) +{ +#if defined (USE_X509) && defined (USE_LIBCRYPTO) + + /* Add all algorithms known by SSL */ +#if OPENSSL_VERSION_NUMBER >= 0x00905100L + OpenSSL_add_all_algorithms(); +#else + SSLeay_add_all_algorithms(); +#endif + +#endif /* USE_X509 && USE_LIBCRYPTO */ +} diff --git a/keyexchange/isakmpd-20041012/libcrypto.h b/keyexchange/isakmpd-20041012/libcrypto.h new file mode 100644 index 0000000..e9581bf --- /dev/null +++ b/keyexchange/isakmpd-20041012/libcrypto.h @@ -0,0 +1,52 @@ +/* $OpenBSD: libcrypto.h,v 1.16 2004/04/15 18:39:26 deraadt Exp $ */ +/* $EOM: libcrypto.h,v 1.16 2000/09/28 12:53:27 niklas Exp $ */ + +/* + * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved. + * Copyright (c) 1999, 2000 Angelos D. Keromytis. 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. + * + * 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 _LIBCRYPTO_H_ +#define _LIBCRYPTO_H_ + +#ifdef USE_X509 + +#include <stdio.h> + +/* XXX I want #include <ssl/cryptall.h> but we appear to not install meth.h */ +#include <openssl/ssl.h> +#include <openssl/bio.h> +#include <openssl/md5.h> +#include <openssl/pem.h> +#include <openssl/x509_vfy.h> +#include <openssl/x509.h> + +#endif /* USE_X509 */ + +extern void libcrypto_init(void); + +#endif /* _LIBCRYPTO_H_ */ diff --git a/keyexchange/isakmpd-20041012/log.c b/keyexchange/isakmpd-20041012/log.c new file mode 100644 index 0000000..5d8080c --- /dev/null +++ b/keyexchange/isakmpd-20041012/log.c @@ -0,0 +1,706 @@ +/* $OpenBSD: log.c,v 1.49 2004/08/08 19:11:06 deraadt Exp $ */ +/* $EOM: log.c,v 1.30 2000/09/29 08:19:23 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 1999, 2000, 2001, 2003 Håkan Olsson. 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. + * + * 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/time.h> + +#ifdef USE_DEBUG +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/uio.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip6.h> +#include <netinet/udp.h> +#include <arpa/inet.h> + +#ifdef HAVE_PCAP +#include <pcap.h> +#else +#include "sysdep/common/pcap.h" +#endif + +#endif /* USE_DEBUG */ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <stdarg.h> +#include <unistd.h> + +#include "conf.h" +#include "isakmp_num.h" +#include "log.h" +#include "monitor.h" +#include "util.h" + +static void _log_print(int, int, const char *, va_list, int, int); + +static FILE *log_output; + +int verbose_logging = 0; +#if defined (USE_DEBUG) +static int log_level[LOG_ENDCLASS]; + +#define TCPDUMP_MAGIC 0xa1b2c3d4 +#define SNAPLEN (64 * 1024) + +struct packhdr { + struct pcap_pkthdr pcap;/* pcap file packet header */ + union { + struct ip ip4; /* IPv4 header (w/o options) */ + struct ip6_hdr ip6; /* IPv6 header */ + } ip; +}; + +struct isakmp_hdr { + u_int8_t icookie[8], rcookie[8]; + u_int8_t next, ver, type, flags; + u_int32_t msgid, len; +}; + +static char *pcaplog_file = NULL; +static FILE *packet_log; +static u_int8_t *packet_buf = NULL; + +static int udp_cksum(struct packhdr *, const struct udphdr *, + u_int16_t *, int); +static u_int16_t in_cksum(const u_int16_t *, int); +#endif /* USE_DEBUG */ + +void +log_init(int debug) +{ + if (debug) + log_output = stderr; + else + log_to(0); /* syslog */ +} + +void +log_reinit(void) +{ + struct conf_list *logging; +#ifdef USE_DEBUG + struct conf_list_node *logclass; + int class, level; +#endif /* USE_DEBUG */ + + logging = conf_get_list("General", "Logverbose"); + if (logging) { + verbose_logging = 1; + conf_free_list(logging); + } +#ifdef USE_DEBUG + logging = conf_get_list("General", "Loglevel"); + if (!logging) + return; + + for (logclass = TAILQ_FIRST(&logging->fields); logclass; + logclass = TAILQ_NEXT(logclass, link)) { + if (sscanf(logclass->field, "%d=%d", &class, &level) != 2) { + if (sscanf(logclass->field, "A=%d", &level) == 1) + for (class = 0; class < LOG_ENDCLASS; class++) + log_debug_cmd(class, level); + else { + log_print("init: invalid logging class or " + "level: %s", logclass->field); + continue; + } + } else + log_debug_cmd(class, level); + } + conf_free_list(logging); +#endif /* USE_DEBUG */ +} + +void +log_to(FILE *f) +{ + if (!log_output && f) + closelog(); + log_output = f; + if (!f) + openlog("isakmpd", LOG_PID | LOG_CONS, LOG_DAEMON); +} + +FILE * +log_current(void) +{ + return log_output; +} + +static char * +_log_get_class(int error_class) +{ + /* XXX For test purposes. To be removed later on? */ + static char *class_text[] = LOG_CLASSES_TEXT; + + if (error_class < 0) + return "Dflt"; + else if (error_class >= LOG_ENDCLASS) + return "Unkn"; + else + return class_text[error_class]; +} + +static void +_log_print(int error, int syslog_level, const char *fmt, va_list ap, + int class, int level) +{ + char buffer[LOG_SIZE], nbuf[LOG_SIZE + 32]; + static const char fallback_msg[] = + "write to log file failed (errno %d), redirecting to syslog"; + int len; + struct tm *tm; + struct timeval now; + time_t t; + + len = vsnprintf(buffer, sizeof buffer, fmt, ap); + if (len > 0 && len < (int) sizeof buffer - 1 && error) + snprintf(buffer + len, sizeof buffer - len, ": %s", + strerror(errno)); + if (log_output) { + gettimeofday(&now, 0); + t = now.tv_sec; + tm = localtime(&t); + if (class >= 0) + snprintf(nbuf, sizeof nbuf, + "%02d%02d%02d.%06ld %s %02d ", + tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec, + _log_get_class(class), level); + else /* LOG_PRINT (-1) or LOG_REPORT (-2) */ + snprintf(nbuf, sizeof nbuf, "%02d%02d%02d.%06ld %s ", + tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec, + class == LOG_PRINT ? "Default" : "Report>"); + strlcat(nbuf, buffer, sizeof nbuf); +#if defined (USE_PRIVSEP) + strlcat(nbuf, getuid() ? "" : " [priv]", LOG_SIZE + 32); +#endif + strlcat(nbuf, "\n", sizeof nbuf); + + if (fwrite(nbuf, strlen(nbuf), 1, log_output) == 0) { + /* Report fallback. */ + syslog(LOG_ALERT, fallback_msg, errno); + fprintf(log_output, fallback_msg, errno); + + /* + * Close log_output to prevent isakmpd from locking + * the file. We may need to explicitly close stdout + * to do this properly. + * XXX - Figure out how to match two FILE *'s and + * rewrite. + */ + if (fileno(log_output) != -1 && + fileno(stdout) == fileno(log_output)) + fclose(stdout); + fclose(log_output); + + /* Fallback to syslog. */ + log_to(0); + + /* (Re)send current message to syslog(). */ + syslog(class == LOG_REPORT ? LOG_ALERT : + syslog_level, "%s", buffer); + } + } else + syslog(class == LOG_REPORT ? LOG_ALERT : syslog_level, "%s", + buffer); +} + +#ifdef USE_DEBUG +void +log_debug(int cls, int level, const char *fmt, ...) +{ + va_list ap; + + /* + * If we are not debugging this class, or the level is too low, just + * return. + */ + if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls])) + return; + va_start(ap, fmt); + _log_print(0, LOG_INFO, fmt, ap, cls, level); + va_end(ap); +} + +void +log_debug_buf(int cls, int level, const char *header, const u_int8_t *buf, + size_t sz) +{ + size_t i, j; + char s[73]; + + /* + * If we are not debugging this class, or the level is too low, just + * return. + */ + if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls])) + return; + + log_debug(cls, level, "%s:", header); + for (i = j = 0; i < sz;) { + snprintf(s + j, sizeof 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 +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; + } +} + +void +log_debug_toggle(void) +{ + static int log_level_copy[LOG_ENDCLASS], toggle = 0; + + if (!toggle) { + LOG_DBG((LOG_MISC, 50, "log_debug_toggle: " + "debug levels cleared")); + memcpy(&log_level_copy, &log_level, sizeof log_level); + memset(&log_level, 0, sizeof log_level); + } else { + memcpy(&log_level, &log_level_copy, sizeof log_level); + LOG_DBG((LOG_MISC, 50, "log_debug_toggle: " + "debug levels restored")); + } + toggle = !toggle; +} +#endif /* USE_DEBUG */ + +void +log_print(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + _log_print(0, LOG_NOTICE, fmt, ap, LOG_PRINT, 0); + va_end(ap); +} + +void +log_verbose(const char *fmt, ...) +{ + va_list ap; +#ifdef USE_DEBUG + int i; +#endif /* USE_DEBUG */ + + if (verbose_logging == 0) + return; + +#ifdef USE_DEBUG + for (i = 0; i < LOG_ENDCLASS; i++) + if (log_level[i] > 0) + return; +#endif + + va_start(ap, fmt); + _log_print(0, LOG_NOTICE, fmt, ap, LOG_PRINT, 0); + va_end(ap); +} + +void +log_error(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + _log_print(1, LOG_ERR, fmt, ap, LOG_PRINT, 0); + va_end(ap); +} + +void +log_fatal(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + _log_print(1, LOG_CRIT, fmt, ap, LOG_PRINT, 0); + va_end(ap); +#ifdef USE_PRIVSEP + monitor_exit(1); +#else + exit(1); +#endif +} + +#ifdef USE_DEBUG +void +log_packet_init(char *newname) +{ + struct pcap_file_header sf_hdr; + struct stat st; + mode_t old_umask; + char *mode; + + /* Allocate packet buffer first time through. */ + if (!packet_buf) + packet_buf = malloc(SNAPLEN); + + if (!packet_buf) { + log_error("log_packet_init: malloc (%d) failed", SNAPLEN); + return; + } + if (pcaplog_file && strcmp(pcaplog_file, PCAP_FILE_DEFAULT) != 0) + free(pcaplog_file); + + pcaplog_file = strdup(newname); + if (!pcaplog_file) { + log_error("log_packet_init: strdup (\"%s\") failed", newname); + return; + } + /* Does the file already exist? XXX lstat() or stat()? */ +#if defined (USE_PRIVSEP) + /* XXX This is a fstat! */ + if (monitor_stat(pcaplog_file, &st) == 0) { +#else + if (lstat(pcaplog_file, &st) == 0) { +#endif + /* Sanity checks. */ + if ((st.st_mode & S_IFMT) != S_IFREG) { + log_print("log_packet_init: existing capture file is " + "not a regular file"); + return; + } + if ((st.st_mode & (S_IRWXG | S_IRWXO)) != 0) { + log_print("log_packet_init: existing capture " + "file has bad modes"); + return; + } + /* + * XXX It would be nice to check if it actually is a pcap + * file... + */ + + mode = "a"; + } else + mode = "w"; + + old_umask = umask(S_IRWXG | S_IRWXO); + packet_log = monitor_fopen(pcaplog_file, mode); + umask(old_umask); + + if (!packet_log) { + log_error("log_packet_init: fopen (\"%s\", \"%s\") failed", + pcaplog_file, mode); + return; + } + log_print("log_packet_init: " + "starting IKE packet capture to file \"%s\"", pcaplog_file); + + /* If this is a new file, we need to write a PCAP header to it. */ + if (*mode == 'w') { + sf_hdr.magic = TCPDUMP_MAGIC; + sf_hdr.version_major = PCAP_VERSION_MAJOR; + sf_hdr.version_minor = PCAP_VERSION_MINOR; + sf_hdr.thiszone = 0; + sf_hdr.snaplen = SNAPLEN; + sf_hdr.sigfigs = 0; + sf_hdr.linktype = DLT_LOOP; + + fwrite((char *) &sf_hdr, sizeof sf_hdr, 1, packet_log); + fflush(packet_log); + } +} + +void +log_packet_restart(char *newname) +{ + if (packet_log) { + log_print("log_packet_restart: capture already active on " + "file \"%s\"", pcaplog_file); + return; + } + if (newname) + log_packet_init(newname); + else if (!pcaplog_file) + log_packet_init(PCAP_FILE_DEFAULT); + else + log_packet_init(pcaplog_file); +} + +void +log_packet_stop(void) +{ + /* Stop capture. */ + if (packet_log) { + fclose(packet_log); + log_print("log_packet_stop: stopped capture"); + } + packet_log = 0; +} + +void +log_packet_iov(struct sockaddr *src, struct sockaddr *dst, struct iovec *iov, + int iovcnt) +{ + struct isakmp_hdr *isakmphdr; + struct packhdr hdr; + struct udphdr udp; + struct timeval tv; + int off, datalen, hdrlen, i, add_espmarker = 0; + const u_int32_t espmarker = 0; + + for (i = 0, datalen = 0; i < iovcnt; i++) + datalen += iov[i].iov_len; + + if (!packet_log || datalen > SNAPLEN) + return; + + /* copy packet into buffer */ + for (i = 0, off = 0; i < iovcnt; i++) { + memcpy(packet_buf + off, iov[i].iov_base, iov[i].iov_len); + off += iov[i].iov_len; + } + + memset(&hdr, 0, sizeof hdr); + memset(&udp, 0, sizeof udp); + + /* isakmp - turn off the encryption bit in the isakmp hdr */ + isakmphdr = (struct isakmp_hdr *) packet_buf; + isakmphdr->flags &= ~(ISAKMP_FLAGS_ENC); + + /* udp */ + udp.uh_sport = sockaddr_port(src); + udp.uh_dport = sockaddr_port(dst); + datalen += sizeof udp; +#if defined (USE_NAT_TRAVERSAL) + if (ntohs(udp.uh_sport) == 4500 || + ntohs(udp.uh_dport) == 4500) { /* XXX Quick and dirty */ + add_espmarker = 1; + datalen += sizeof espmarker; + } +#endif + udp.uh_ulen = htons(datalen); + + /* ip */ + switch (src->sa_family) { + default: + /* Assume IPv4. XXX Can 'default' ever happen here? */ + hdr.ip.ip4.ip_src.s_addr = 0x02020202; + hdr.ip.ip4.ip_dst.s_addr = 0x01010101; + /* The rest of the setup is common to AF_INET. */ + goto setup_ip4; + + case AF_INET: + hdr.ip.ip4.ip_src.s_addr = + ((struct sockaddr_in *)src)->sin_addr.s_addr; + hdr.ip.ip4.ip_dst.s_addr = + ((struct sockaddr_in *)dst)->sin_addr.s_addr; + +setup_ip4: + hdrlen = sizeof hdr.ip.ip4; + hdr.ip.ip4.ip_v = 0x4; + hdr.ip.ip4.ip_hl = 0x5; + hdr.ip.ip4.ip_p = IPPROTO_UDP; + hdr.ip.ip4.ip_len = htons(datalen + hdrlen); + /* Let's use the IP ID as a "packet counter". */ + i = ntohs(hdr.ip.ip4.ip_id) + 1; + hdr.ip.ip4.ip_id = htons(i); + /* Calculate IP header checksum. */ + hdr.ip.ip4.ip_sum = in_cksum((u_int16_t *) & hdr.ip.ip4, + hdr.ip.ip4.ip_hl << 2); + break; + + case AF_INET6: + hdrlen = sizeof(hdr.ip.ip6); + hdr.ip.ip6.ip6_vfc = IPV6_VERSION; + hdr.ip.ip6.ip6_nxt = IPPROTO_UDP; + hdr.ip.ip6.ip6_plen = udp.uh_ulen; + memcpy(&hdr.ip.ip6.ip6_src, + &((struct sockaddr_in6 *)src)->sin6_addr, + sizeof hdr.ip.ip6.ip6_src); + memcpy(&hdr.ip.ip6.ip6_dst, + &((struct sockaddr_in6 *)dst)->sin6_addr, + sizeof hdr.ip.ip6.ip6_dst); + break; + } + + /* Calculate UDP checksum. */ + udp.uh_sum = udp_cksum(&hdr, &udp, (u_int16_t *) packet_buf, src->sa_family); + /* pcap file packet header */ + gettimeofday(&tv, 0); + hdr.pcap.ts.tv_sec = tv.tv_sec; + hdr.pcap.ts.tv_usec = tv.tv_usec; + hdr.pcap.caplen = datalen + hdrlen; + hdr.pcap.len = datalen + hdrlen; + + hdrlen += sizeof(struct pcap_pkthdr); + datalen -= sizeof(struct udphdr); + + /* Write to pcap file. */ + fwrite(&hdr, hdrlen, 1, packet_log); /* pcap + IP */ + fwrite(&udp, sizeof(struct udphdr), 1, packet_log); /* UDP */ + if (add_espmarker) { + fwrite(&espmarker, sizeof espmarker, 1, packet_log); + datalen -= sizeof espmarker; + } + fwrite(packet_buf, datalen, 1, packet_log); /* IKE-data */ + fflush(packet_log); +} + +/* Copied from tcpdump/print-udp.c, mostly rewritten. */ +static int +udp_cksum(struct packhdr *hdr, const struct udphdr *u, u_int16_t *d, int af) +{ + struct ip *ip4; + struct ip6_hdr *ip6; + int i, hdrlen, tlen = ntohs(u->uh_ulen) - sizeof(struct udphdr); + + union phu { + struct ip4pseudo { + struct in_addr src; + struct in_addr dst; + u_int8_t z; + u_int8_t proto; + u_int16_t len; + } ip4p; + struct ip6pseudo { + struct in6_addr src; + struct in6_addr dst; + u_int32_t plen; + u_int16_t z0; + u_int8_t z1; + u_int8_t nxt; + } ip6p; + u_int16_t pa[20]; + } phu; + const u_int16_t *sp; + u_int32_t sum; + + /* Setup pseudoheader. */ + memset(phu.pa, 0, sizeof phu); + switch (af) { + case AF_INET: + ip4 = &hdr->ip.ip4; + memcpy(&phu.ip4p.src, &ip4->ip_src, sizeof(struct in_addr)); + memcpy(&phu.ip4p.dst, &ip4->ip_dst, sizeof(struct in_addr)); + phu.ip4p.proto = ip4->ip_p; + phu.ip4p.len = u->uh_ulen; + hdrlen = sizeof phu.ip4p; + break; + + case AF_INET6: + ip6 = &hdr->ip.ip6; + memcpy(&phu.ip6p.src, &ip6->ip6_src, sizeof(phu.ip6p.src)); + memcpy(&phu.ip6p.dst, &ip6->ip6_dst, sizeof(phu.ip6p.dst)); + phu.ip6p.plen = u->uh_ulen; + phu.ip6p.nxt = ip6->ip6_nxt; + hdrlen = sizeof phu.ip6p; + break; + + default: + return 0; + } + + /* IPv6 wants a 0xFFFF checksum "on error", not 0x0. */ + if (tlen < 0) + return (af == AF_INET ? 0 : 0xFFFF); + + sum = 0; + for (i = 0; i < hdrlen; i += 2) + sum += phu.pa[i / 2]; + + sp = (u_int16_t *) u; + for (i = 0; i < (int)sizeof(struct udphdr); i += 2) + sum += *sp++; + + sp = d; + for (i = 0; i < (tlen & ~1); i += 2) + sum += *sp++; + + if (tlen & 1) + sum += htons((*(const char *)sp) << 8); + + while (sum > 0xffff) + sum = (sum & 0xffff) + (sum >> 16); + sum = ~sum & 0xffff; + + return sum; +} + +/* Copied from tcpdump/print-ip.c, modified. */ +static u_int16_t +in_cksum(const u_int16_t *w, int len) +{ + int nleft = len, sum = 0; + u_int16_t answer; + + while (nleft > 1) { + sum += *w++; + nleft -= 2; + } + if (nleft == 1) + sum += htons(*(u_char *) w << 8); + + sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ + sum += (sum >> 16); /* add carry */ + answer = ~sum; /* truncate to 16 bits */ + return answer; +} + +#endif /* USE_DEBUG */ diff --git a/keyexchange/isakmpd-20041012/log.h b/keyexchange/isakmpd-20041012/log.h new file mode 100644 index 0000000..dc36f5d --- /dev/null +++ b/keyexchange/isakmpd-20041012/log.h @@ -0,0 +1,102 @@ +/* $OpenBSD: log.h,v 1.21 2004/05/23 18:17:56 hshoexer Exp $ */ +/* $EOM: log.h,v 1.19 2000/03/30 14:27:23 ho Exp $ */ + +/* + * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2001, 2002, 2003 Håkan Olsson. 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. + * + * 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 <sys/socket.h> +#include <sys/uio.h> +#include <stdio.h> + +extern int verbose_logging; + +/* + * 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 + +enum log_classes { + LOG_MISC, LOG_TRANSPORT, LOG_MESSAGE, LOG_CRYPTO, LOG_TIMER, LOG_SYSDEP, + LOG_SA, LOG_EXCHANGE, LOG_NEGOTIATION, LOG_POLICY, LOG_UI, LOG_ENDCLASS +}; +#define LOG_CLASSES_TEXT \ + { "Misc", "Trpt", "Mesg", "Cryp", "Timr", "Sdep", "SA ", "Exch", "Negt", \ + "Plcy", "UI " } + +/* + * "Class" LOG_REPORT will always be logged to the current log channel, + * regardless of level. + */ +#define LOG_PRINT -1 +#define LOG_REPORT -2 + +#ifdef USE_DEBUG + +#define LOG_DBG(x) log_debug x +#define LOG_DBG_BUF(x) log_debug_buf x + +extern void log_debug(int, int, const char *,...) + __attribute__((__format__(__printf__, 3, 4))); +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_debug_toggle(void); + +#define PCAP_FILE_DEFAULT "/var/run/isakmpd.pcap" +extern void log_packet_init(char *); +extern void log_packet_iov(struct sockaddr *, struct sockaddr *, + struct iovec *, int); +extern void log_packet_restart(char *); +extern void log_packet_stop(void); + +#else /* !USE_DEBUG */ + +#define LOG_DBG(x) +#define LOG_DBG_BUF(x) + +#endif /* USE_DEBUG */ + +extern FILE *log_current(void); +extern void log_error(const char *,...) + __attribute__((__format__(__printf__, 1, 2))); +extern void log_fatal(const char *,...) + __attribute__((__format__(__printf__, 1, 2))); +extern void log_print(const char *,...) + __attribute__((__format__(__printf__, 1, 2))); +extern void log_verbose(const char *,...) + __attribute__((__format__(__printf__, 1, 2))); +extern void log_to(FILE *); +extern void log_init(int); +extern void log_reinit(void); + +#endif /* _LOG_H_ */ diff --git a/keyexchange/isakmpd-20041012/math_2n.c b/keyexchange/isakmpd-20041012/math_2n.c new file mode 100644 index 0000000..f8828ef --- /dev/null +++ b/keyexchange/isakmpd-20041012/math_2n.c @@ -0,0 +1,1107 @@ +/* $OpenBSD: math_2n.c,v 1.16 2004/06/14 09:55:41 ho Exp $ */ +/* $EOM: math_2n.c,v 1.15 1999/04/20 09:23:30 niklas Exp $ */ + +/* + * Copyright (c) 1998 Niels Provos. All rights reserved. + * Copyright (c) 1999 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. + * + * 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 "sysdep.h" + +#include "math_2n.h" +#include "util.h" + +static 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 +}; + +/* Convert a hex character to its integer value. */ +static u_int8_t +hex2int(char c) +{ + if (c <= '9') + return c - '0'; + if (c <= 'f') + return 10 + c - 'a'; + + return 0; +} + +int +b2n_random(b2n_ptr n, u_int32_t bits) +{ + if (b2n_resize(n, (CHUNK_MASK + bits) >> CHUNK_SHIFTS)) + return -1; + + 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; + return 0; +} + +/* b2n management functions */ + +void +b2n_init(b2n_ptr n) +{ + n->chunks = 0; + n->limp = 0; +} + +void +b2n_clear(b2n_ptr n) +{ + if (n->limp) + free(n->limp); +} + +int +b2n_resize(b2n_ptr n, unsigned int chunks) +{ + size_t old = n->chunks; + size_t size; + CHUNK_TYPE *new; + + if (chunks == 0) + chunks = 1; + + if (chunks == old) + return 0; + + size = CHUNK_BYTES * chunks; + + new = realloc(n->limp, size); + if (!new) + return -1; + + 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); + + return 0; +} + +/* Simple assignment functions. */ + +int +b2n_set(b2n_ptr d, b2n_ptr s) +{ + if (d == s) + return 0; + + b2n_sigbit(s); + if (b2n_resize(d, (CHUNK_MASK + s->bits) >> CHUNK_SHIFTS)) + return -1; + memcpy(d->limp, s->limp, CHUNK_BYTES * d->chunks); + d->bits = s->bits; + d->dirty = s->dirty; + return 0; +} + +int +b2n_set_null(b2n_ptr n) +{ + if (b2n_resize(n, 1)) + return -1; + n->limp[0] = n->bits = n->dirty = 0; + return 0; +} + +int +b2n_set_ui(b2n_ptr n, unsigned int val) +{ +#if CHUNK_BITS < 32 + int i, chunks; + + chunks = (CHUNK_BYTES - 1 + sizeof(val)) / CHUNK_BYTES; + + if (b2n_resize(n, chunks)) + return -1; + + for (i = 0; i < chunks; i++) { + n->limp[i] = val & CHUNK_BMASK; + val >>= CHUNK_BITS; + } +#else + if (b2n_resize(n, 1)) + return -1; + n->limp[0] = val; +#endif + n->dirty = 1; + return 0; +} + +/* XXX This one only takes hex at the moment. */ +int +b2n_set_str(b2n_ptr n, char *str) +{ + int i, j, w, len, chunks; + CHUNK_TYPE tmp; + + if (strncasecmp(str, "0x", 2)) + return -1; + + /* 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; + if (b2n_resize(n, chunks)) + return -1; + 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; + return 0; +} + +/* Output function, mainly for debugging purposes. */ +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_snprint(char *buf, size_t sz, b2n_ptr n) +{ + int i, j, w, flag = 0; + size_t k; + int left; + char buffer[2 * CHUNK_BYTES]; + CHUNK_TYPE tmp; + + left = ((((7 + b2n_sigbit(n)) >> 3) - 1) % CHUNK_BYTES) + 1; + + k = strlcpy(buf, "0x", sz); + for (i = 0; i < n->chunks && k < sz - 1; 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 + && k < sz - 3; 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. */ +int +b2n_add(b2n_ptr d, b2n_ptr a, b2n_ptr b) +{ + int i; + b2n_ptr bmin, bmax; + + if (!b2n_cmp_null(a)) + return b2n_set(d, b); + + if (!b2n_cmp_null(b)) + return b2n_set(d, a); + + bmin = B2N_MIN(a, b); + bmax = B2N_MAX(a, b); + + if (b2n_resize(d, bmax->chunks)) + return -1; + + 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)) + return b2n_set_null(d); + else + d->dirty = 1; + return 0; +} + +/* 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. */ +int +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) + return b2n_set(d, n); + + maj = s >> CHUNK_SHIFTS; + min = s & CHUNK_MASK; + + add = (!(bits & CHUNK_MASK) || + ((bits & CHUNK_MASK) + min) > CHUNK_MASK) ? 1 : 0; + chunks = n->chunks; + if (b2n_resize(d, chunks + maj + add)) + return -1; + 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 0; + + op = p = &d->limp[d->chunks - 1]; + for (i = d->chunks - 2; i >= maj; i--) { + op--; + *p = (*p << min) | (*op >> (CHUNK_BITS - min)); + p--; + } + *p <<= min; + + d->dirty = 0; + d->bits = bits + (maj << CHUNK_SHIFTS) + min; + return 0; +} + +/* Right shift, needed for polynomial division. */ +int +b2n_rshift(b2n_ptr d, b2n_ptr n, unsigned int s) +{ + int maj, min, size = n->chunks, newsize; + b2n_ptr tmp; + + if (!s) + return b2n_set(d, n); + + maj = s >> CHUNK_SHIFTS; + + newsize = size - maj; + + if (size < maj) + return b2n_set_null(d); + + min = (CHUNK_BITS - (s & CHUNK_MASK)) & CHUNK_MASK; + if (min) { + if ((b2n_sigbit(n) & CHUNK_MASK) > (u_int32_t) min) + newsize++; + + if (b2n_lshift(d, n, min)) + return -1; + tmp = d; + } else + tmp = n; + + memmove(d->limp, tmp->limp + maj + (min ? 1 : 0), + CHUNK_BYTES * newsize); + if (b2n_resize(d, newsize)) + return -1; + + d->bits = tmp->bits - ((maj + (min ? 1 : 0)) << CHUNK_SHIFTS); + return 0; +} + +/* Normal polynomial multiplication. */ +int +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)) + return b2n_set_null(d); + + if (b2n_sigbit(m) == 1) + return b2n_set(d, n); + + if (b2n_sigbit(n) == 1) + return b2n_set(d, m); + + b2n_init(tmp); + b2n_init(tmp2); + + if (b2n_set(tmp, B2N_MAX(n, m))) + goto fail; + if (b2n_set(tmp2, B2N_MIN(n, m))) + goto fail; + + if (b2n_set_null(d)) + goto fail; + + 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]) + if (b2n_add(d, d, tmp)) + goto fail; + + if (b2n_lshift(tmp, tmp, 1)) + goto fail; + } + else if (b2n_lshift(tmp, tmp, CHUNK_BITS)) + goto fail; + + b2n_clear(tmp); + b2n_clear(tmp2); + return 0; + +fail: + b2n_clear(tmp); + b2n_clear(tmp2); + return -1; +} + +/* + * Squaring in this polynomial ring is more efficient than normal + * multiplication. + */ +int +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); + if (b2n_resize(t, + 2 * maj + ((CHUNK_MASK + 2 * min) >> CHUNK_SHIFTS))) { + b2n_clear(t); + return -1; + } + 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); + return 0; +} + +/* + * Normal polynomial division. + * These functions are far from optimal in speed. + */ +int +b2n_div_q(b2n_ptr d, b2n_ptr n, b2n_ptr m) +{ + b2n_t r; + int rv; + + b2n_init(r); + rv = b2n_div(d, r, n, m); + b2n_clear(r); + return rv; +} + +int +b2n_div_r(b2n_ptr r, b2n_ptr n, b2n_ptr m) +{ + b2n_t q; + int rv; + + b2n_init(q); + rv = b2n_div(q, r, n, m); + b2n_clear(q); + return rv; +} + +int +b2n_div(b2n_ptr q, b2n_ptr r, b2n_ptr n, b2n_ptr m) +{ + int i, j, len, bits; + u_int32_t sm, sn; + b2n_t nenn, div, shift, mask; + + /* If Teiler > Zaehler, the result is 0 */ + if ((sm = b2n_sigbit(m)) > (sn = b2n_sigbit(n))) { + if (b2n_set_null(q)) + return -1; + return b2n_set(r, n); + } + if (sm == 0) + /* Division by Zero */ + return -1; + else if (sm == 1) { + /* Division by the One-Element */ + if (b2n_set(q, n)) + return -1; + return b2n_set_null(r); + } + b2n_init(nenn); + b2n_init(div); + b2n_init(shift); + b2n_init(mask); + + if (b2n_set(nenn, n)) + goto fail; + if (b2n_set(div, m)) + goto fail; + if (b2n_set(shift, m)) + goto fail; + if (b2n_set_ui(mask, 1)) + goto fail; + + if (b2n_resize(q, (sn - sm + CHUNK_MASK) >> CHUNK_SHIFTS)) + goto fail; + memset(q->limp, 0, CHUNK_BYTES * q->chunks); + + if (b2n_lshift(shift, shift, sn - sm)) + goto fail; + if (b2n_lshift(mask, mask, sn - sm)) + goto fail; + + /* 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]) { + if (b2n_sub(nenn, nenn, shift)) + goto fail; + if (b2n_add(q, q, mask)) + goto fail; + } + if (b2n_rshift(shift, shift, 1)) + goto fail; + if (b2n_rshift(mask, mask, 1)) + goto fail; + } + + B2N_SWAP(r, nenn); + + b2n_clear(nenn); + b2n_clear(div); + b2n_clear(shift); + b2n_clear(mask); + return 0; + +fail: + b2n_clear(nenn); + b2n_clear(div); + b2n_clear(shift); + b2n_clear(mask); + return -1; +} + +/* Functions for Operation on GF(2**n) ~= GF(2)[x]/p(x). */ +int +b2n_mod(b2n_ptr m, b2n_ptr n, b2n_ptr p) +{ + int bits, size; + + if (b2n_div_r(m, n, p)) + return -1; + + bits = b2n_sigbit(m); + size = ((CHUNK_MASK + bits) >> CHUNK_SHIFTS); + if (size == 0) + size = 1; + if (m->chunks > size) + if (b2n_resize(m, size)) + return -1; + + m->bits = bits; + m->dirty = 0; + return 0; +} + +int +b2n_gcd(b2n_ptr e, b2n_ptr go, b2n_ptr ho) +{ + b2n_t g, h; + + b2n_init(g); + b2n_init(h); + if (b2n_set(g, go)) + goto fail; + if (b2n_set(h, ho)) + goto fail; + + while (b2n_cmp_null(h)) { + if (b2n_mod(g, g, h)) + goto fail; + B2N_SWAP(g, h); + } + + B2N_SWAP(e, g); + + b2n_clear(g); + b2n_clear(h); + return 0; + +fail: + b2n_clear(g); + b2n_clear(h); + return -1; +} + +int +b2n_mul_inv(b2n_ptr ga, b2n_ptr be, b2n_ptr p) +{ + b2n_t a; + + b2n_init(a); + if (b2n_set_ui(a, 1)) + goto fail; + + if (b2n_div_mod(ga, a, be, p)) + goto fail; + + b2n_clear(a); + return 0; + +fail: + b2n_clear(a); + return -1; +} + +int +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)) + return b2n_set_null(ga); + + b2n_init(s0); + b2n_init(s1); + b2n_init(s2); + b2n_init(r0); + b2n_init(r1); + b2n_init(q); + + if (b2n_set(r0, p)) + goto fail; + if (b2n_set(r1, be)) + goto fail; + + if (b2n_set_null(s0)) + goto fail; + if (b2n_set(s1, a)) + goto fail; + + while (b2n_cmp_null(r1)) { + if (b2n_div(q, r0, r0, r1)) + goto fail; + B2N_SWAP(r0, r1); + + if (b2n_mul(s2, q, s1)) + goto fail; + if (b2n_mod(s2, s2, p)) + goto fail; + if (b2n_sub(s2, s0, s2)) + goto fail; + + 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); + return 0; + +fail: + b2n_clear(s0); + b2n_clear(s1); + b2n_clear(s2); + b2n_clear(r0); + b2n_clear(r1); + b2n_clear(q); + return -1; +} + +/* + * 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. + */ +int +b2n_trace(b2n_ptr ho, b2n_ptr a, b2n_ptr p) +{ + int i, m = b2n_sigbit(p) - 1; + b2n_t h; + + b2n_init(h); + if (b2n_set(h, a)) + goto fail; + + for (i = 0; i < m - 1; i++) { + if (b2n_square(h, h)) + goto fail; + if (b2n_mod(h, h, p)) + goto fail; + + if (b2n_add(h, h, a)) + goto fail; + } + B2N_SWAP(ho, h); + + b2n_clear(h); + return 0; + +fail: + b2n_clear(h); + return -1; +} + +/* + * The halftrace yields the square root if the degree of the + * irreduceable polynomial is odd. + */ +int +b2n_halftrace(b2n_ptr ho, b2n_ptr a, b2n_ptr p) +{ + int i, m = b2n_sigbit(p) - 1; + b2n_t h; + + b2n_init(h); + if (b2n_set(h, a)) + goto fail; + + for (i = 0; i < (m - 1) / 2; i++) { + if (b2n_square(h, h)) + goto fail; + if (b2n_mod(h, h, p)) + goto fail; + if (b2n_square(h, h)) + goto fail; + if (b2n_mod(h, h, p)) + goto fail; + + if (b2n_add(h, h, a)) + goto fail; + } + + B2N_SWAP(ho, h); + + b2n_clear(h); + return 0; + +fail: + b2n_clear(h); + return -1; +} + +/* + * 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. + */ +int +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)) + return b2n_set_null(z); + + if (m & 1) + return b2n_halftrace(zo, b, ip); + + b2n_init(z); + b2n_init(w); + b2n_init(p); + b2n_init(temp); + + do { + if (b2n_random(p, m)) + goto fail; + if (b2n_set_null(z)) + goto fail; + if (b2n_set(w, p)) + goto fail; + + for (i = 1; i < m; i++) { + if (b2n_square(z, z)) /* z**2 */ + goto fail; + if (b2n_mod(z, z, ip)) + goto fail; + + if (b2n_square(w, w)) /* w**2 */ + goto fail; + if (b2n_mod(w, w, ip)) + goto fail; + + if (b2n_mul(temp, w, b)) /* w**2 * b */ + goto fail; + if (b2n_mod(temp, temp, ip)) + goto fail; + if (b2n_add(z, z, temp)) /* z**2 + w**2 + b */ + goto fail; + + if (b2n_add(w, w, p)) /* w**2 + p */ + goto fail; + } + } + while (!b2n_cmp_null(w)); + + B2N_SWAP(zo, z); + + b2n_clear(w); + b2n_clear(p); + b2n_clear(temp); + b2n_clear(z); + return 0; + +fail: + b2n_clear(w); + b2n_clear(p); + b2n_clear(temp); + b2n_clear(z); + return -1; +} + +/* Exponentiation modulo a polynomial. */ +int +b2n_exp_mod(b2n_ptr d, b2n_ptr b0, u_int32_t e, b2n_ptr p) +{ + b2n_t u, b; + + b2n_init(u); + b2n_init(b); + if (b2n_set_ui(u, 1)) + goto fail; + if (b2n_mod(b, b0, p)) + goto fail; + + while (e) { + if (e & 1) { + if (b2n_mul(u, u, b)) + goto fail; + if (b2n_mod(u, u, p)) + goto fail; + } + if (b2n_square(b, b)) + goto fail; + if (b2n_mod(b, b, p)) + goto fail; + e >>= 1; + } + + B2N_SWAP(d, u); + + b2n_clear(u); + b2n_clear(b); + return 0; + +fail: + b2n_clear(u); + b2n_clear(b); + return -1; +} + +/* + * 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}. */ +int +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)) + return b2n_set(d0, b0); + + if (!b2n_cmp_null(b0)) + return b2n_set(d0, a0); + + b2n_init(d); + a = B2N_MAX(a0, b0); + b = B2N_MIN(a0, b0); + + if (b2n_resize(d, a->chunks + 1)) { + b2n_clear(d); + return -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); + return 0; +} + +/* Very special sub, a > b. */ +int +b2n_nsub(b2n_ptr d0, b2n_ptr a, b2n_ptr b) +{ + int i, carry; + b2n_t d; + + if (b2n_cmp(a, b) <= 0) + return b2n_set_null(d0); + + b2n_init(d); + if (b2n_resize(d, a->chunks)) { + b2n_clear(d); + return -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); + return 0; +} + +int +b2n_3mul(b2n_ptr d0, b2n_ptr e) +{ + b2n_t d; + + b2n_init(d); + if (b2n_lshift(d, e, 1)) + goto fail; + + if (b2n_nadd(d0, d, e)) + goto fail; + + b2n_clear(d); + return 0; + +fail: + b2n_clear(d); + return -1; +} diff --git a/keyexchange/isakmpd-20041012/math_2n.h b/keyexchange/isakmpd-20041012/math_2n.h new file mode 100644 index 0000000..0515199 --- /dev/null +++ b/keyexchange/isakmpd-20041012/math_2n.h @@ -0,0 +1,132 @@ +/* $OpenBSD: math_2n.h,v 1.7 2004/04/15 18:39:26 deraadt Exp $ */ +/* $EOM: math_2n.h,v 1.9 1999/04/17 23:20:32 niklas Exp $ */ + +/* + * Copyright (c) 1998 Niels Provos. All rights reserved. + * Copyright (c) 1999 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. + * + * 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) do \ + { \ + (x)->chunks = (y)->chunks; \ + (x)->bits = (y)->bits; \ + (x)->limp = (y)->limp; \ + (x)->dirty = (y)->dirty; \ + } \ +while (0) + +#define B2N_SWAP(x,y) do \ + { \ + b2n_t _t_; \ +\ + B2N_SET (_t_, (x)); \ + B2N_SET ((x), (y)); \ + B2N_SET ((y), _t_); \ + } \ +while (0) + +#define B2N_MIN(x,y) ((x)->chunks > (y)->chunks ? (y) : (x)) +#define B2N_MAX(x,y) ((x)->chunks > (y)->chunks ? (x) : (y)) + +int b2n_3mul(b2n_ptr, b2n_ptr); +int b2n_add(b2n_ptr, b2n_ptr, b2n_ptr); +int b2n_cmp(b2n_ptr, b2n_ptr); +int b2n_cmp_null(b2n_ptr); +int b2n_div(b2n_ptr, b2n_ptr, b2n_ptr, b2n_ptr); +int b2n_div_mod(b2n_ptr, b2n_ptr, b2n_ptr, b2n_ptr); +int b2n_div_q(b2n_ptr, b2n_ptr, b2n_ptr); +int b2n_div_r(b2n_ptr, b2n_ptr, b2n_ptr); +int b2n_exp_mod(b2n_ptr, b2n_ptr, u_int32_t, b2n_ptr); +void b2n_init(b2n_ptr); +void b2n_clear(b2n_ptr); +int b2n_gcd(b2n_ptr, b2n_ptr, b2n_ptr); +int b2n_halftrace(b2n_ptr, b2n_ptr, b2n_ptr); +int b2n_lshift(b2n_ptr, b2n_ptr, unsigned int); +int b2n_mod(b2n_ptr, b2n_ptr, b2n_ptr); +int b2n_mul(b2n_ptr, b2n_ptr, b2n_ptr); +int b2n_mul_inv(b2n_ptr, b2n_ptr, b2n_ptr); +int b2n_nadd(b2n_ptr, b2n_ptr, b2n_ptr); +int b2n_nsub(b2n_ptr, b2n_ptr, b2n_ptr); +void b2n_print(b2n_ptr); +int b2n_random(b2n_ptr, u_int32_t); +int b2n_resize(b2n_ptr, unsigned int); +int b2n_rshift(b2n_ptr, b2n_ptr, unsigned int); +int b2n_set(b2n_ptr, b2n_ptr); +int b2n_set_null(b2n_ptr); +int b2n_set_str(b2n_ptr, char *); +int b2n_set_ui(b2n_ptr, unsigned int); +u_int32_t b2n_sigbit(b2n_ptr); +int b2n_snprint(char *, size_t, b2n_ptr); +int b2n_sqrt(b2n_ptr, b2n_ptr, b2n_ptr); +int b2n_square(b2n_ptr, b2n_ptr); +#define b2n_sub b2n_add +int b2n_trace(b2n_ptr, b2n_ptr, b2n_ptr); + +#endif /* _MATH_2N_H_ */ diff --git a/keyexchange/isakmpd-20041012/math_ec2n.c b/keyexchange/isakmpd-20041012/math_ec2n.c new file mode 100644 index 0000000..c06b37c --- /dev/null +++ b/keyexchange/isakmpd-20041012/math_ec2n.c @@ -0,0 +1,382 @@ +/* $OpenBSD: math_ec2n.c,v 1.11 2004/05/23 18:17:56 hshoexer Exp $ */ +/* $EOM: math_ec2n.c,v 1.9 1999/04/20 09:23:31 niklas Exp $ */ + +/* + * Copyright (c) 1998 Niels Provos. All rights reserved. + * Copyright (c) 1999 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. + * + * 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 "sysdep.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); +} + +int +ec2np_set(ec2np_ptr d, ec2np_ptr n) +{ + if (d == n) + return 0; + + d->inf = n->inf; + if (b2n_set(d->x, n->x)) + return -1; + return 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); +} + +int +ec2ng_set(ec2ng_ptr d, ec2ng_ptr n) +{ + if (b2n_set(d->a, n->a)) + return -1; + if (b2n_set(d->b, n->b)) + return -1; + return b2n_set(d->p, n->p); +} + +/* Arithmetic functions */ + +int +ec2np_right(b2n_ptr n, ec2np_ptr p, ec2ng_ptr g) +{ + b2n_t temp; + + b2n_init(temp); + + /* First calc x**3 + ax**2 + b */ + if (b2n_square(n, p->x)) + goto fail; + if (b2n_mod(n, n, g->p)) + goto fail; + + if (b2n_mul(temp, g->a, n)) /* a*x**2 */ + goto fail; + if (b2n_mod(temp, temp, g->p)) + goto fail; + + if (b2n_mul(n, n, p->x))/* x**3 */ + goto fail; + if (b2n_mod(n, n, g->p)) + goto fail; + + if (b2n_add(n, n, temp)) + goto fail; + if (b2n_add(n, n, g->b)) + goto fail; + + b2n_clear(temp); + return 0; + +fail: + b2n_clear(temp); + return -1; +} + +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 */ + if (ec2np_right(x, p, g)) + goto fail; + + /* Now calc y**2 + xy */ + if (b2n_square(y, p->y)) + goto fail; + if (b2n_mod(y, y, g->p)) + goto fail; + + if (b2n_mul(temp, p->y, p->x)) + goto fail; + if (b2n_mod(temp, temp, g->p)) + goto fail; + + if (b2n_add(y, y, temp)) + goto fail; + + res = !b2n_cmp(x, y); + + b2n_clear(x); + b2n_clear(y); + b2n_clear(temp); + return res; + +fail: + b2n_clear(x); + b2n_clear(y); + b2n_clear(temp); + return -1; +} + +int +ec2np_find_y(ec2np_ptr p, ec2ng_ptr g) +{ + b2n_t right; + + b2n_init(right); + + if (ec2np_right(right, p, g)) /* Right sight of equation */ + goto fail; + if (b2n_mul_inv(p->y, p->x, g->p)) + goto fail; + + if (b2n_square(p->y, p->y)) + goto fail; + if (b2n_mod(p->y, p->y, g->p)) + goto fail; + + if (b2n_mul(right, right, p->y)) /* x^-2 * right */ + goto fail; + if (b2n_mod(right, right, g->p)) + goto fail; + + if (b2n_sqrt(p->y, right, g->p)) /* Find root */ + goto fail; + if (b2n_mul(p->y, p->y, p->x)) + goto fail; + if (b2n_mod(p->y, p->y, g->p)) + goto fail; + + b2n_clear(right); + return 0; + +fail: + b2n_clear(right); + return -1; +} + +int +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) + return ec2np_set(d, a); + if (a->inf) + return ec2np_set(d, b); + + if (!b2n_cmp(a->x, b->x) && (b2n_cmp(a->y, b->y) || + !b2n_cmp_null(a->x))) { + d->inf = 1; + if (b2n_set_null(d->x)) + return -1; + return b2n_set_null(d->y); + } + b2n_init(lambda); + b2n_init(temp); + ec2np_init(pn); + + if (b2n_cmp(a->x, b->x)) { + if (b2n_add(temp, a->x, b->x)) + goto fail; + if (b2n_add(lambda, a->y, b->y)) + goto fail; + if (b2n_div_mod(lambda, lambda, temp, g->p)) + goto fail; + + if (b2n_square(pn->x, lambda)) + goto fail; + if (b2n_mod(pn->x, pn->x, g->p)) + goto fail; + + if (b2n_add(pn->x, pn->x, lambda)) + goto fail; + if (b2n_add(pn->x, pn->x, g->a)) + goto fail; + if (b2n_add(pn->x, pn->x, a->x)) + goto fail; + if (b2n_add(pn->x, pn->x, b->x)) + goto fail; + } else { + if (b2n_div_mod(lambda, b->y, b->x, g->p)) + goto fail; + if (b2n_add(lambda, lambda, b->x)) + goto fail; + + if (b2n_square(pn->x, lambda)) + goto fail; + if (b2n_mod(pn->x, pn->x, g->p)) + goto fail; + if (b2n_add(pn->x, pn->x, lambda)) + goto fail; + if (b2n_add(pn->x, pn->x, g->a)) + goto fail; + } + + if (b2n_add(pn->y, b->x, pn->x)) + goto fail; + + if (b2n_mul(pn->y, pn->y, lambda)) + goto fail; + if (b2n_mod(pn->y, pn->y, g->p)) + goto fail; + + if (b2n_add(pn->y, pn->y, pn->x)) + goto fail; + if (b2n_add(pn->y, pn->y, b->y)) + goto fail; + + EC2NP_SWAP(d, pn); + + ec2np_clear(pn); + b2n_clear(lambda); + b2n_clear(temp); + return 0; + +fail: + ec2np_clear(pn); + b2n_clear(lambda); + b2n_clear(temp); + return -1; +} + +int +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; + if (b2n_set_null(d->x)) + return -1; + return b2n_set_null(d->y); + } + b2n_init(h); + b2n_init(k); + ec2np_init(q); + ec2np_init(mina); + + if (ec2np_set(q, a)) + goto fail; + + /* Create the point -a. */ + if (ec2np_set(mina, a)) + goto fail; + if (b2n_add(mina->y, mina->y, mina->x)) + goto fail; + + if (b2n_set(k, e)) + goto fail; + if (b2n_3mul(h, k)) + goto fail; + if (b2n_resize(k, h->chunks)) + goto fail; + + /* + * 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) { + if (ec2np_add(q, q, q, g)) + goto fail; + if ((h->limp[i] & b2n_mask[j]) && !(k->limp[i] + & b2n_mask[j])) { + if (ec2np_add(q, q, a, g)) + goto fail; + } else if (!(h->limp[i] & b2n_mask[j]) + && (k->limp[i] & b2n_mask[j])) + if (ec2np_add(q, q, mina, g)) + goto fail; + } + EC2NP_SWAP(d, q); + + b2n_clear(k); + b2n_clear(h); + ec2np_clear(q); + ec2np_clear(mina); + return 0; + +fail: + b2n_clear(k); + b2n_clear(h); + ec2np_clear(q); + ec2np_clear(mina); + return -1; +} diff --git a/keyexchange/isakmpd-20041012/math_ec2n.h b/keyexchange/isakmpd-20041012/math_ec2n.h new file mode 100644 index 0000000..247f84a --- /dev/null +++ b/keyexchange/isakmpd-20041012/math_ec2n.h @@ -0,0 +1,94 @@ +/* $OpenBSD: math_ec2n.h,v 1.7 2004/05/23 18:17:56 hshoexer Exp $ */ +/* $EOM: math_ec2n.h,v 1.4 1999/04/17 23:20:37 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. + * + * 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) do \ + { \ + int _i_; \ +\ + _i_ = (k)->inf; \ + (k)->inf = (n)->inf; \ + (n)->inf = _i_; \ + B2N_SWAP ((k)->x, (n)->x); \ + B2N_SWAP ((k)->y, (n)->y); \ + } \ +while (0) + +void ec2np_init(ec2np_ptr); +void ec2np_clear(ec2np_ptr); +int 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); +int 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. */ + +int ec2np_add(ec2np_ptr, ec2np_ptr, ec2np_ptr, ec2ng_ptr); +int ec2np_find_y(ec2np_ptr, ec2ng_ptr); +int ec2np_ison(ec2np_ptr, ec2ng_ptr); +int ec2np_mul(ec2np_ptr, ec2np_ptr, b2n_ptr, ec2ng_ptr); +int ec2np_right(b2n_ptr n, ec2np_ptr, ec2ng_ptr); + +#endif /* _MATH_2N_H_ */ diff --git a/keyexchange/isakmpd-20041012/math_group.c b/keyexchange/isakmpd-20041012/math_group.c new file mode 100644 index 0000000..55f340f --- /dev/null +++ b/keyexchange/isakmpd-20041012/math_group.c @@ -0,0 +1,865 @@ +/* $OpenBSD: math_group.c,v 1.23 2004/06/14 09:55:41 ho Exp $ */ +/* $EOM: math_group.c,v 1.25 2000/04/07 19:53:26 niklas Exp $ */ + +/* + * Copyright (c) 1998 Niels Provos. All rights reserved. + * Copyright (c) 1999, 2000 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. + * + * 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 "sysdep.h" + +#include "gmp_util.h" +#include "log.h" +#include "math_2n.h" +#include "math_ec2n.h" +#include "math_group.h" +#include "math_mp.h" + +/* We do not want to export these definitions. */ +int modp_getlen(struct group *); +void modp_getraw(struct group *, math_mp_t, u_int8_t *); +int modp_setraw(struct group *, math_mp_t, u_int8_t *, int); +int modp_setrandom(struct group *, math_mp_t); +int modp_operation(struct group *, math_mp_t, math_mp_t, math_mp_t); + +int ec2n_getlen(struct group *); +void ec2n_getraw(struct group *, ec2np_ptr, u_int8_t *); +int ec2n_setraw(struct group *, ec2np_ptr, u_int8_t *, int); +int ec2n_setrandom(struct group *, ec2np_ptr); +int 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 { + math_mp_t gen; /* Generator */ + math_mp_t p; /* Prime */ + math_mp_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 +#define OAKLEY_GRP_5 5 +#define OAKLEY_GRP_6 6 +#define OAKLEY_GRP_7 7 +#define OAKLEY_GRP_8 8 +#define OAKLEY_GRP_9 9 +#define OAKLEY_GRP_10 10 +#define OAKLEY_GRP_11 11 +#define OAKLEY_GRP_12 12 +#define OAKLEY_GRP_13 13 +#define OAKLEY_GRP_14 14 +#define OAKLEY_GRP_15 15 +#define OAKLEY_GRP_16 16 +#define OAKLEY_GRP_17 17 +#define OAKLEY_GRP_18 18 + +/* 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" + }, + {OAKLEY_GRP_5, 102, + "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", + "0x02" + }, + {OAKLEY_GRP_14, 135, /* 2048 bit */ + "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + "15728E5A8AACAA68FFFFFFFFFFFFFFFF", + "0x02" + }, + {OAKLEY_GRP_15, 170, /* 3072 bit */ + "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" + "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF", + "0x02" + }, + {OAKLEY_GRP_16, 195, /* 4096 bit */ + "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" + "FFFFFFFFFFFFFFFF", + "0x02" + }, + {OAKLEY_GRP_17, 220, /* 6144 bit */ + "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" + "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" + "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" + "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" + "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" + "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" + "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" + "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" + "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" + "12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF", + "0x02" + }, + {OAKLEY_GRP_18, 250, /* 8192 bit */ + "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" + "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" + "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" + "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" + "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" + "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" + "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" + "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" + "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" + "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" + "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300" + "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" + "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" + "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" + "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A" + "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" + "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1" + "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" + "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47" + "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" + "60C980DD98EDD3DFFFFFFFFFFFFFFFFF", + "0x02" + }, +}; + +#ifdef USE_EC +/* 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" }, +}; +#endif /* USE_EC */ + +/* XXX I want to get rid of the casting here. */ +struct group groups[] = { + { + MODP, OAKLEY_GRP_1, 0, &oakley_modp[0], 0, 0, 0, 0, 0, + (int (*) (struct group *)) modp_getlen, + (void (*) (struct group *, void *, u_int8_t *)) modp_getraw, + (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw, + (int (*) (struct group *, void *)) modp_setrandom, + (int (*) (struct group *, void *, void *, void *)) modp_operation + }, + { + MODP, OAKLEY_GRP_2, 0, &oakley_modp[1], 0, 0, 0, 0, 0, + (int (*) (struct group *)) modp_getlen, + (void (*) (struct group *, void *, u_int8_t *)) modp_getraw, + (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw, + (int (*) (struct group *, void *)) modp_setrandom, + (int (*) (struct group *, void *, void *, void *)) modp_operation + }, +#ifdef USE_EC + { + EC2N, OAKLEY_GRP_3, 0, &oakley_ec2n[0], 0, 0, 0, 0, 0, + (int (*) (struct group *)) ec2n_getlen, + (void (*) (struct group *, void *, u_int8_t *)) ec2n_getraw, + (int (*) (struct group *, void *, u_int8_t *, int)) ec2n_setraw, + (int (*) (struct group *, void *)) ec2n_setrandom, + (int (*) (struct group *, void *, void *, void *)) ec2n_operation + }, + { + EC2N, OAKLEY_GRP_4, 0, &oakley_ec2n[1], 0, 0, 0, 0, 0, + (int (*) (struct group *)) ec2n_getlen, + (void (*) (struct group *, void *, u_int8_t *)) ec2n_getraw, + (int (*) (struct group *, void *, u_int8_t *, int)) ec2n_setraw, + (int (*) (struct group *, void *)) ec2n_setrandom, + (int (*) (struct group *, void *, void *, void *)) ec2n_operation + }, +#endif /* USE_EC */ + { + MODP, OAKLEY_GRP_5, 0, &oakley_modp[2], 0, 0, 0, 0, 0, + (int (*) (struct group *)) modp_getlen, + (void (*) (struct group *, void *, u_int8_t *)) modp_getraw, + (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw, + (int (*) (struct group *, void *)) modp_setrandom, + (int (*) (struct group *, void *, void *, void *)) modp_operation + }, +#ifdef USE_EC + /* XXX Higher EC2N group go here... */ +#endif /* USE_EC */ + /* XXX group 6 to 13 are not yet defined (draft-ike-ecc) */ + { + NOTYET, OAKLEY_GRP_6, 0, NULL, 0, 0, 0, 0, 0, + NULL, NULL, NULL, NULL, NULL + }, + { + NOTYET, OAKLEY_GRP_7, 0, NULL, 0, 0, 0, 0, 0, + NULL, NULL, NULL, NULL, NULL + }, + { + NOTYET, OAKLEY_GRP_8, 0, NULL, 0, 0, 0, 0, 0, + NULL, NULL, NULL, NULL, NULL + }, + { + NOTYET, OAKLEY_GRP_9, 0, NULL, 0, 0, 0, 0, 0, + NULL, NULL, NULL, NULL, NULL + }, + { + NOTYET, OAKLEY_GRP_10, 0, NULL, 0, 0, 0, 0, 0, + NULL, NULL, NULL, NULL, NULL + }, + { + NOTYET, OAKLEY_GRP_11, 0, NULL, 0, 0, 0, 0, 0, + NULL, NULL, NULL, NULL, NULL + }, + { + NOTYET, OAKLEY_GRP_12, 0, NULL, 0, 0, 0, 0, 0, + NULL, NULL, NULL, NULL, NULL + }, + { + NOTYET, OAKLEY_GRP_13, 0, NULL, 0, 0, 0, 0, 0, + NULL, NULL, NULL, NULL, NULL + }, + { + MODP, OAKLEY_GRP_14, 0, &oakley_modp[3], 0, 0, 0, 0, 0, + (int (*) (struct group *)) modp_getlen, + (void (*) (struct group *, void *, u_int8_t *)) modp_getraw, + (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw, + (int (*) (struct group *, void *)) modp_setrandom, + (int (*) (struct group *, void *, void *, void *)) modp_operation + }, + { + MODP, OAKLEY_GRP_15, 0, &oakley_modp[4], 0, 0, 0, 0, 0, + (int (*) (struct group *)) modp_getlen, + (void (*) (struct group *, void *, u_int8_t *)) modp_getraw, + (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw, + (int (*) (struct group *, void *)) modp_setrandom, + (int (*) (struct group *, void *, void *, void *)) modp_operation + }, + { + MODP, OAKLEY_GRP_16, 0, &oakley_modp[5], 0, 0, 0, 0, 0, + (int (*) (struct group *)) modp_getlen, + (void (*) (struct group *, void *, u_int8_t *)) modp_getraw, + (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw, + (int (*) (struct group *, void *)) modp_setrandom, + (int (*) (struct group *, void *, void *, void *)) modp_operation + }, + { + MODP, OAKLEY_GRP_17, 0, &oakley_modp[6], 0, 0, 0, 0, 0, + (int (*) (struct group *)) modp_getlen, + (void (*) (struct group *, void *, u_int8_t *)) modp_getraw, + (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw, + (int (*) (struct group *, void *)) modp_setrandom, + (int (*) (struct group *, void *, void *, void *)) modp_operation + }, + { + MODP, OAKLEY_GRP_18, 0, &oakley_modp[7], 0, 0, 0, 0, 0, + (int (*) (struct group *)) modp_getlen, + (void (*) (struct group *, void *, u_int8_t *)) modp_getraw, + (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw, + (int (*) (struct group *, void *)) modp_setrandom, + (int (*) (struct group *, void *, void *, void *)) modp_operation + }, +}; + +/* + * Initialize 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) { +#ifdef USE_EC + case EC2N: /* Initialize an Elliptic Curve over GF(2**n) */ + ec2n_init(&groups[i]); + break; +#endif + + case MODP: /* Initialize an over GF(p) */ + modp_init(&groups[i]); + break; + + case NOTYET: /* Not yet assigned, drop silently */ + break; + + default: + log_print("Unknown group type %d at index %d in " + "group_init().", groups[i].type, i); + break; + } +} + +struct group * +group_get(u_int32_t id) +{ + struct group *new, *clone; + + if (id < 1 || id > (sizeof(groups) / sizeof(groups[0]))) { + log_print("group_get: group ID (%u) out of range", id); + return 0; + } + clone = &groups[id - 1]; + + new = malloc(sizeof *new); + if (!new) { + log_error("group_get: malloc (%lu) failed", + (unsigned long)sizeof *new); + return 0; + } + switch (clone->type) { +#ifdef USE_EC + case EC2N: + new = ec2n_clone(new, clone); + break; +#endif + case MODP: + new = modp_clone(new, clone); + break; + default: + log_print("group_get: unknown group type %d", clone->type); + free(new); + return 0; + } + LOG_DBG((LOG_MISC, 70, "group_get: returning %p of group %d", new, + new->id)); + return new; +} + +void +group_free(struct group *grp) +{ + switch (grp->type) { +#ifdef USE_EC + case EC2N: + ec2n_free(grp); + break; +#endif + case MODP: + modp_free(grp); + break; + 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; + + new_grp = malloc(sizeof *new_grp); + if (!new_grp) { + log_print("modp_clone: malloc (%lu) failed", + (unsigned long)sizeof *new_grp); + free(new); + return 0; + } + memcpy(new, clone, sizeof(struct group)); + + new->group = new_grp; +#if MP_FLAVOUR == MP_FLAVOUR_GMP + 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); +#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL + new_grp->p = BN_dup(clone_grp->p); + new_grp->gen = BN_dup(clone_grp->gen); + + new_grp->a = BN_new(); + new_grp->b = BN_new(); + new_grp->c = BN_new(); +#endif + + 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; + +#if MP_FLAVOUR == MP_FLAVOUR_GMP + mpz_clear(grp->p); + mpz_clear(grp->gen); + mpz_clear(grp->a); + mpz_clear(grp->b); + mpz_clear(grp->c); +#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL + BN_clear_free(grp->p); + BN_clear_free(grp->gen); + BN_clear_free(grp->a); + BN_clear_free(grp->b); + BN_clear_free(grp->c); +#endif + + free(grp); +} + +void +modp_init(struct group *group) +{ + struct modp_dscr *dscr = (struct modp_dscr *)group->group; + struct modp_group *grp; + + grp = malloc(sizeof *grp); + if (!grp) + log_fatal("modp_init: malloc (%lu) failed", + (unsigned long)sizeof *grp); + + group->bits = dscr->bits; + +#if MP_FLAVOUR == MP_FLAVOUR_GMP + 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); +#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL + grp->p = BN_new(); + BN_hex2bn(&grp->p, dscr->prime + 2); + grp->gen = BN_new(); + BN_hex2bn(&grp->gen, dscr->gen + 2); + + grp->a = BN_new(); + grp->b = BN_new(); + grp->c = BN_new(); +#endif + + group->gen = grp->gen; + group->a = grp->a; + group->b = grp->b; + group->c = grp->c; + + group->group = grp; +} + +#ifdef USE_EC +struct group * +ec2n_clone(struct group *new, struct group *clone) +{ + struct ec2n_group *new_grp, *clone_grp = clone->group; + + new_grp = malloc(sizeof *new_grp); + if (!new_grp) { + log_error("ec2n_clone: malloc (%lu) failed", + (unsigned long)sizeof *new_grp); + free(new); + return 0; + } + memcpy(new, clone, sizeof(struct group)); + + new->group = new_grp; + ec2ng_init(new_grp->grp); + ec2np_init(new_grp->gen); + ec2np_init(new_grp->a); + ec2np_init(new_grp->b); + ec2np_init(new_grp->c); + + if (ec2ng_set(new_grp->grp, clone_grp->grp)) + goto fail; + if (ec2np_set(new_grp->gen, clone_grp->gen)) + goto fail; + + 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; + +fail: + ec2ng_clear(new_grp->grp); + ec2np_clear(new_grp->gen); + ec2np_clear(new_grp->a); + ec2np_clear(new_grp->b); + ec2np_clear(new_grp->c); + free(new_grp); + free(new); + return 0; +} + +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; + + grp = malloc(sizeof *grp); + if (!grp) + log_fatal("ec2n_init: malloc (%lu) failed", + (unsigned long)sizeof *grp); + + group->bits = dscr->bits; + + ec2ng_init(grp->grp); + ec2np_init(grp->gen); + ec2np_init(grp->a); + ec2np_init(grp->b); + ec2np_init(grp->c); + + if (ec2ng_set_p_str(grp->grp, dscr->polynomial)) + goto fail; + grp->grp->p->bits = b2n_sigbit(grp->grp->p); + if (ec2ng_set_a_str(grp->grp, dscr->a)) + goto fail; + if (ec2ng_set_b_str(grp->grp, dscr->b)) + goto fail; + + if (ec2np_set_x_str(grp->gen, dscr->gen_x)) + goto fail; + if (ec2np_find_y(grp->gen, grp->grp)) + goto fail; + + /* Sanity check */ + if (!ec2np_ison(grp->gen, grp->grp)) + log_fatal("ec2n_init: generator is not on curve"); + + 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; + return; + +fail: + log_fatal("ec2n_init: general failure"); +} +#endif /* USE_EC */ + +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, math_mp_t v, u_int8_t *d) +{ + mpz_getraw(d, v, grp->getlen(grp)); +} + +int +modp_setraw(struct group *grp, math_mp_t d, u_int8_t *s, int l) +{ + mpz_setraw(d, s, l); + return 0; +} + +int +modp_setrandom(struct group *grp, math_mp_t d) +{ + int i, l = grp->getlen(grp); + u_int32_t tmp = 0; + +#if MP_FLAVOUR == MP_FLAVOUR_GMP + mpz_set_ui(d, 0); +#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL + BN_set_word(d, 0); +#endif + + for (i = 0; i < l; i++) { + if (i % 4) + tmp = sysdep_random(); + +#if MP_FLAVOUR == MP_FLAVOUR_GMP + mpz_mul_2exp(d, d, 8); + mpz_add_ui(d, d, tmp & 0xFF); +#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL + BN_lshift(d, d, 8); + BN_add_word(d, tmp & 0xFF); +#endif + tmp >>= 8; + } + return 0; +} + +int +modp_operation(struct group *group, math_mp_t d, math_mp_t a, math_mp_t e) +{ + struct modp_group *grp = (struct modp_group *)group->group; + +#if MP_FLAVOUR == MP_FLAVOUR_GMP + mpz_powm(d, a, e, grp->p); +#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL + BN_CTX *ctx = BN_CTX_new(); + BN_mod_exp(d, a, e, grp->p, ctx); + BN_CTX_free(ctx); +#endif + return 0; +} + +#ifdef USE_EC +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); + } +} + +int +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; + if (b2n_resize(outx, len)) + return -1; + + 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; + } + return 0; +} + +int +ec2n_setrandom(struct group *group, ec2np_ptr x) +{ + b2n_ptr d = x->x; + struct ec2n_group *grp = (struct ec2n_group *) group->group; + + return b2n_random(d, b2n_sigbit(grp->grp->p) - 1); +} + +/* + * This is an attempt at operation abstraction. It can happen + * that we need to initialize 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. + */ +int +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) + if (ec2np_find_y(a, group->grp)) + return -1; + + return ec2np_mul(d, a, ex, group->grp); +} +#endif /* USE_EC */ diff --git a/keyexchange/isakmpd-20041012/math_group.h b/keyexchange/isakmpd-20041012/math_group.h new file mode 100644 index 0000000..d5a19bc --- /dev/null +++ b/keyexchange/isakmpd-20041012/math_group.h @@ -0,0 +1,94 @@ +/* $OpenBSD: math_group.h,v 1.10 2004/04/15 18:39:26 deraadt Exp $ */ +/* $EOM: math_group.h,v 1.7 1999/04/17 23:20:40 niklas Exp $ */ + +/* + * Copyright (c) 1998 Niels Provos. All rights reserved. + * Copyright (c) 1999 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. + * + * 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 */ + NOTYET /* Not yet assigned */ +}; + +/* + * 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 *); + int (*setraw) (struct group *, void *, u_int8_t *, int); + int (*setrandom) (struct group *, void *); + int (*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(u_int32_t); + +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/keyexchange/isakmpd-20041012/math_mp.h b/keyexchange/isakmpd-20041012/math_mp.h new file mode 100644 index 0000000..ed554fc --- /dev/null +++ b/keyexchange/isakmpd-20041012/math_mp.h @@ -0,0 +1,56 @@ +/* $OpenBSD: math_mp.h,v 1.6 2004/04/15 18:39:26 deraadt Exp $ */ +/* $EOM: math_mp.h,v 1.4 2000/09/16 09:41:43 ho Exp $ */ + +/* + * Copyright (c) 1999, 2000 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. + * + * 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_MP_H_ +#define _MATH_MP_H_ + +#define MP_FLAVOUR_GMP 1 +#define MP_FLAVOUR_OPENSSL 2 + +#if MP_FLAVOUR == MP_FLAVOUR_GMP + +#include <gmp.h> + +#define math_mp_t mpz_t + +#elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL + +#include <openssl/bn.h> + +typedef BIGNUM *math_mp_t; + +#else + +#error "No multiprecision math library chosen." + +#endif + +#endif /* _MATH_MP_H_ */ diff --git a/keyexchange/isakmpd-20041012/message.c b/keyexchange/isakmpd-20041012/message.c new file mode 100644 index 0000000..9259e2d --- /dev/null +++ b/keyexchange/isakmpd-20041012/message.c @@ -0,0 +1,2530 @@ +/* $OpenBSD: message.c,v 1.89 2004/09/17 13:45:02 ho Exp $ */ +/* $EOM: message.c,v 1.156 2000/10/10 12:36:39 provos Exp $ */ + +/* + * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 1999 Angelos D. Keromytis. All rights reserved. + * Copyright (c) 1999, 2000, 2001, 2004 Håkan Olsson. 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. + * + * 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 <stdlib.h> +#include <string.h> + +#include "sysdep.h" + +#include "attribute.h" +#include "cert.h" +#include "constants.h" +#include "crypto.h" +#include "doi.h" +#ifdef USE_DPD +#include "dpd.h" +#endif +#include "exchange.h" +#include "field.h" +#include "hash.h" +#include "ipsec.h" +#include "ipsec_num.h" +#include "isakmp.h" +#include "log.h" +#include "message.h" +#if defined (USE_NAT_TRAVERSAL) +#include "nat_traversal.h" +#endif +#include "prf.h" +#include "sa.h" +#include "timer.h" +#include "transport.h" +#include "util.h" +#include "virtual.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 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 u_int16_t message_payload_sz(u_int8_t); +static int message_validate_attribute(struct message *, struct payload *); +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_nat_d(struct message *, struct payload *); +static int message_validate_nat_oa(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 void message_packet_log(struct message *); + +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, message_validate_attribute, + message_validate_nat_d, message_validate_nat_oa, + message_validate_nat_d, message_validate_nat_oa +}; + +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, isakmp_attribute_fld, isakmp_nat_d_fld, + isakmp_nat_oa_fld, isakmp_nat_d_fld, isakmp_nat_oa_fld +}; + +/* + * These maps are used for indexing the payloads in msg->payloads[i]. + * payload_revmap should be updated if the payloads in isakmp_num.cst change. + * payload_map is populated during startup by message_init(). + */ +static u_int8_t payload_revmap[] = { + ISAKMP_PAYLOAD_NONE, ISAKMP_PAYLOAD_SA, ISAKMP_PAYLOAD_PROPOSAL, + ISAKMP_PAYLOAD_TRANSFORM, ISAKMP_PAYLOAD_KEY_EXCH, ISAKMP_PAYLOAD_ID, + ISAKMP_PAYLOAD_CERT, ISAKMP_PAYLOAD_CERT_REQ, ISAKMP_PAYLOAD_HASH, + ISAKMP_PAYLOAD_SIG, ISAKMP_PAYLOAD_NONCE, ISAKMP_PAYLOAD_NOTIFY, + ISAKMP_PAYLOAD_DELETE, ISAKMP_PAYLOAD_VENDOR, ISAKMP_PAYLOAD_ATTRIBUTE, +#ifdef notyet + ISAKMP_PAYLOAD_SAK, ISAKMP_PAYLOAD_SAT, ISAKMP_PAYLOAD_KD, + ISAKMP_PAYLOAD_SEQ, ISAKMP_PAYLOAD_POP +#endif + ISAKMP_PAYLOAD_NAT_D, ISAKMP_PAYLOAD_NAT_OA, + ISAKMP_PAYLOAD_NAT_D_DRAFT, ISAKMP_PAYLOAD_NAT_OA_DRAFT +}; + +static u_int8_t payload_map[256]; +u_int8_t payload_index_max; + +/* + * Fields used for checking monotonic increasing of proposal and transform + * numbers. + */ +static u_int8_t *last_sa = 0; +static u_int32_t last_prop_no; +static u_int8_t *last_prop = 0; +static u_int32_t 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 = (u_int8_t *)msg->iov[0].iov_base + + ISAKMP_HDR_NEXT_PAYLOAD_OFF; + msg->transport = t; + transport_reference(t); + msg->payload = (struct payload_head *)calloc(payload_index_max, + sizeof *msg->payload); + if (!msg->payload) { + message_free(msg); + return 0; + } + for (i = 0; i < payload_index_max; i++) + TAILQ_INIT(&msg->payload[i]); + TAILQ_INIT(&msg->post_send); + LOG_DBG((LOG_MESSAGE, 90, "message_alloc: allocated %p", msg)); + return msg; +} + +/* + * Allocate a message suitable 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; + if (msg->isakmp_sa) + sa_reference(msg->isakmp_sa); + return reply; +} + +/* Free up all resources used by the MSG message. */ +void +message_free(struct message *msg) +{ + u_int32_t i; + struct payload *payload, *next; + + LOG_DBG((LOG_MESSAGE, 20, "message_free: freeing %p", msg)); + if (!msg) + return; + if (msg->orig && msg->orig != (u_int8_t *) 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); + if (msg->payload) { + for (i = 0; i < payload_index_max; i++) + for (payload = payload_first(msg, i); payload; + payload = next) { + next = TAILQ_NEXT(payload, link); + free(payload); + } + free(msg->payload); + } + while (TAILQ_FIRST(&msg->post_send) != 0) + TAILQ_REMOVE(&msg->post_send, TAILQ_FIRST(&msg->post_send), + link); + + /* If we are on the send queue, remove us from there. */ + if (msg->flags & MSG_IN_TRANSIT) + TAILQ_REMOVE(msg->transport->vtbl->get_queue(msg), msg, link); + + if (msg->transport) + transport_release(msg->transport); + + if (msg->isakmp_sa) + sa_release(msg->isakmp_sa); + + 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_DBG((LOG_MESSAGE, 50, + "message_parse_payloads: offset %ld payload %s", + (long)(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, 1, 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 && + next <= ISAKMP_PAYLOAD_RESERVED_MAX) { + log_print("message_parse_payloads: invalid next " + "payload type %s in payload of type %d", + constant_name(isakmp_payload_cst, next), payload); + message_drop(msg, ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE, + 0, 1, 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: %x", GET_ISAKMP_GEN_RESERVED(buf)); + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, + 0, 1, 1); + return -1; + } + /* + * Decode and validate the payload length field. + */ + len = GET_ISAKMP_GEN_LENGTH(buf); + + if (message_payload_sz(payload) == 0) { + log_print("message_parse_payloads: unknown minimum " + "payload size for payload type %s", + constant_name(isakmp_payload_cst, payload)); + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, + 0, 1, 1); + return -1; + } + if (len < message_payload_sz(payload)) { + log_print("message_parse_payloads: payload too " + "short: %u", len); + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, + 0, 1, 1); + return -1; + } + if (buf + len > (u_int8_t *)msg->iov[0].iov_base + + msg->iov[0].iov_len) { + log_print("message_parse_payloads: payload too " + "long: %u", len); + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, + 0, 1, 1); + return -1; + } + /* Ignore most private payloads. */ + if (next >= ISAKMP_PAYLOAD_PRIVATE_MIN && + next != ISAKMP_PAYLOAD_NAT_D_DRAFT && + next != ISAKMP_PAYLOAD_NAT_OA_DRAFT) { + LOG_DBG((LOG_MESSAGE, 30, "message_parse_payloads: " + "private next payload type %s in payload of " + "type %d ignored", + constant_name(isakmp_payload_cst, next), payload)); + goto next_payload; + } + /* + * 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 %s " + "unexpected", constant_name(isakmp_payload_cst, + payload)); + message_drop(msg, ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE, + 0, 1, 1); + return -1; + } + /* Call the payload handler specified by the caller. */ + if (func(msg, p, payload, buf)) + return -1; + +next_payload: + /* 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(payload_revmap[ISAKMP_PAYLOAD_TRANSFORM], &payload_set); + if (message_parse_payloads(msg, + payload_last(msg, ISAKMP_PAYLOAD_PROPOSAL), + 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_DBG((LOG_MESSAGE, 50, "Transform %d's attributes", + GET_ISAKMP_TRANSFORM_NO(buf))); +#ifdef USE_DEBUG + attribute_map(buf + ISAKMP_TRANSFORM_SA_ATTRS_OFF, + GET_ISAKMP_GEN_LENGTH(buf) - ISAKMP_TRANSFORM_SA_ATTRS_OFF, + msg->exchange->doi->debug_attribute, msg); +#endif + + return 0; +} + +/* Check payloads for their required minimum size. */ +static u_int16_t +message_payload_sz(u_int8_t payload) +{ + switch (payload) { + case ISAKMP_PAYLOAD_SA: + return ISAKMP_SA_SZ; + case ISAKMP_PAYLOAD_PROPOSAL: + return ISAKMP_PROP_SZ; + case ISAKMP_PAYLOAD_TRANSFORM: + return ISAKMP_TRANSFORM_SZ; + case ISAKMP_PAYLOAD_KEY_EXCH: + return ISAKMP_KE_SZ; + case ISAKMP_PAYLOAD_ID: + return ISAKMP_ID_SZ; + case ISAKMP_PAYLOAD_CERT: + return ISAKMP_CERT_SZ; + case ISAKMP_PAYLOAD_CERT_REQ: + return ISAKMP_CERTREQ_SZ; + case ISAKMP_PAYLOAD_HASH: + return ISAKMP_HASH_SZ; + case ISAKMP_PAYLOAD_SIG: + return ISAKMP_SIG_SZ; + case ISAKMP_PAYLOAD_NONCE: + return ISAKMP_NONCE_SZ; + case ISAKMP_PAYLOAD_NOTIFY: + return ISAKMP_NOTIFY_SZ; + case ISAKMP_PAYLOAD_DELETE: + return ISAKMP_DELETE_SZ; + case ISAKMP_PAYLOAD_VENDOR: + return ISAKMP_VENDOR_SZ; + case ISAKMP_PAYLOAD_ATTRIBUTE: + return ISAKMP_ATTRIBUTE_SZ; +#if defined (USE_NAT_TRAVERSAL) + case ISAKMP_PAYLOAD_NAT_D: + case ISAKMP_PAYLOAD_NAT_D_DRAFT: + return ISAKMP_NAT_D_SZ; + case ISAKMP_PAYLOAD_NAT_OA: + case ISAKMP_PAYLOAD_NAT_OA_DRAFT: + return ISAKMP_NAT_OA_SZ; +#endif + /* Not yet supported and any other unknown payloads. */ + case ISAKMP_PAYLOAD_SAK: + case ISAKMP_PAYLOAD_SAT: + case ISAKMP_PAYLOAD_KD: + case ISAKMP_PAYLOAD_SEQ: + case ISAKMP_PAYLOAD_POP: + default: + return 0; + } +} + +/* Validate the attribute payload P in message MSG. */ +static int +message_validate_attribute(struct message *msg, struct payload *p) +{ +#ifdef USE_ISAKMP_CFG + /* If we don't have an exchange yet, create one. */ + if (!msg->exchange) { + if (zero_test((u_int8_t *) msg->iov[0].iov_base + + ISAKMP_HDR_MESSAGE_ID_OFF, ISAKMP_HDR_MESSAGE_ID_LEN)) + msg->exchange = exchange_setup_p1(msg, + IPSEC_DOI_IPSEC); + else + msg->exchange = exchange_setup_p2(msg, + IPSEC_DOI_IPSEC); + if (!msg->exchange) { + log_print("message_validate_attribute: can not " + "create exchange"); + message_free(msg); + return -1; + } + } +#endif + 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, 1, + 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, 1, + 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 + */ + cert = cert_get(GET_ISAKMP_CERTREQ_TYPE(p->p)); + if (!cert || (len && !cert->certreq_validate(p->p + + ISAKMP_CERTREQ_AUTHORITY_OFF, len))) { + message_drop(msg, ISAKMP_NOTIFY_CERT_TYPE_UNSUPPORTED, 0, 1, + 1); + return -1; + } + return 0; +} + +/* + * Validate the delete payload P in message MSG. As a side-effect, create + * an exchange if we do not have one already. + * + * Note: DELETEs are only accepted as part of an INFORMATIONAL exchange. + * exchange_validate() makes sure a HASH payload is present. Due to the order + * of message validation functions in message_validate_payload[] we can be + * sure that the HASH payload has been successfully validated at this point. + */ +static int +message_validate_delete(struct message *msg, struct payload *p) +{ + u_int8_t proto = GET_ISAKMP_DELETE_PROTO(p->p); + struct doi *doi; + struct sa *sa, *isakmp_sa; + struct sockaddr *dst, *dst_isa; + u_int32_t nspis = GET_ISAKMP_DELETE_NSPIS(p->p); + u_int8_t *spis = (u_int8_t *)p->p + ISAKMP_DELETE_SPI_OFF; + u_int32_t i; + char *addr; + + /* Only accept authenticated DELETEs. */ + if ((msg->flags & MSG_AUTHENTICATED) == 0) { + log_print("message_validate_delete: " + "got unauthenticated DELETE"); + message_free(msg); + return -1; + } + + 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 we don't have an exchange yet, create one. */ + if (!msg->exchange) { + if (zero_test((u_int8_t *) msg->iov[0].iov_base + + ISAKMP_HDR_MESSAGE_ID_OFF, ISAKMP_HDR_MESSAGE_ID_LEN)) + msg->exchange = exchange_setup_p1(msg, doi->id); + else + msg->exchange = exchange_setup_p2(msg, doi->id); + if (!msg->exchange) { + log_print("message_validate_delete: can not create " + "exchange"); + message_free(msg); + return -1; + } + } + /* Only accept DELETE as part of an INFORMATIONAL exchange. */ + if (msg->exchange->type != ISAKMP_EXCH_INFO) { + log_print("message_validate_delete: delete in exchange other " + "than INFO: %s", constant_name(isakmp_exch_cst, + msg->exchange->type)); + 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. */ + for (i = 0; i < nspis; i++) { + /* Get ISAKMP SA protecting this message. */ + isakmp_sa = msg->isakmp_sa; + if (!isakmp_sa) { + /* XXX should not happen? */ + log_print("message_validate_delete: invalid spi (no " + "valid ISAKMP SA found)"); + message_free(msg); + return -1; + } + isakmp_sa->transport->vtbl->get_dst(isakmp_sa->transport, + &dst_isa); + + /* Get SA to be deleted. */ + msg->transport->vtbl->get_dst(msg->transport, &dst); + if (proto == ISAKMP_PROTO_ISAKMP) + sa = sa_lookup_isakmp_sa(dst, spis + i + * ISAKMP_HDR_COOKIES_LEN); + else + sa = ipsec_sa_lookup(dst, ((u_int32_t *) spis)[i], + proto); + if (!sa) { + LOG_DBG((LOG_MESSAGE, 50, "message_validate_delete: " + "invalid spi (no valid SA found)")); + message_free(msg); + return -1; + } + sa->transport->vtbl->get_dst(sa->transport, &dst); + + /* Destination addresses must match. */ + if (dst->sa_family != dst_isa->sa_family || + memcmp(sockaddr_addrdata(dst_isa), sockaddr_addrdata(dst), + sockaddr_addrlen(dst))) { + sockaddr2text(dst_isa, &addr, 0); + + log_print("message_validate_delete: invalid spi " + "(illegal delete request from %s)", addr); + free(addr); + message_free(msg); + return -1; + } + } + + return 0; +} + +/* + * Validate the hash payload P in message MSG. + * XXX Currently hash payloads are processed by the particular exchanges, + * except INFORMATIONAL. This should be actually done here. + */ +static int +message_validate_hash(struct message *msg, struct payload *p) +{ + struct sa *isakmp_sa = msg->isakmp_sa; + struct ipsec_sa *isa; + struct hash *hash; + struct payload *hashp = payload_first(msg, ISAKMP_PAYLOAD_HASH); + struct prf *prf; + u_int8_t *comp_hash, *rest; + u_int8_t message_id[ISAKMP_HDR_MESSAGE_ID_LEN]; + size_t rest_len; + + /* active exchanges other than INFORMATIONAL validates hash payload. */ + if (msg->exchange && (msg->exchange->type != ISAKMP_EXCH_INFO)) + return 0; + + if (isakmp_sa == NULL) { + log_print("message_validate_hash: invalid hash information"); + message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, + 0, 1, 1); + return -1; + } + isa = isakmp_sa->data; + hash = hash_get(isa->hash); + + if (hash == NULL) { + log_print("message_validate_hash: invalid hash information"); + message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, + 0, 1, 1); + return -1; + } + /* If no SKEYID_a, we can not do anything (should not happen). */ + if (!isa->skeyid_a) { + log_print("message_validate_hash: invalid hash information"); + message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, + 0, 1, 1); + return -1; + } + /* Allocate the prf and start calculating our HASH(1). */ + LOG_DBG_BUF((LOG_MISC, 90, "message_validate_hash: SKEYID_a", + isa->skeyid_a, isa->skeyid_len)); + prf = prf_alloc(isa->prf_type, hash->type, isa->skeyid_a, + isa->skeyid_len); + if (!prf) { + message_free(msg); + return -1; + } + comp_hash = (u_int8_t *)malloc(hash->hashsize); + if (!comp_hash) { + log_error("message_validate_hash: malloc (%lu) failed", + (unsigned long)hash->hashsize); + prf_free(prf); + message_free(msg); + return -1; + } + /* This is not an active exchange. */ + GET_ISAKMP_HDR_MESSAGE_ID(msg->iov[0].iov_base, message_id); + + prf->Init(prf->prfctx); + LOG_DBG_BUF((LOG_MISC, 90, "message_validate_hash: message_id", + message_id, ISAKMP_HDR_MESSAGE_ID_LEN)); + prf->Update(prf->prfctx, message_id, ISAKMP_HDR_MESSAGE_ID_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_DBG_BUF((LOG_MISC, 90, + "message_validate_hash: payloads after HASH(1)", rest, rest_len)); + prf->Update(prf->prfctx, rest, rest_len); + prf->Final(comp_hash, prf->prfctx); + prf_free(prf); + + if (memcmp(hashp->p + ISAKMP_HASH_DATA_OFF, comp_hash, + hash->hashsize)) { + log_print("message_validate_hash: invalid hash value for %s " + "payload", payload_first(msg, ISAKMP_PAYLOAD_DELETE) ? + "DELETE" : "NOTIFY"); + message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, + 0, 1, 1); + free(comp_hash); + return -1; + } + free(comp_hash); + + /* Mark the HASH as handled. */ + hashp->flags |= PL_MARK; + + /* Mark message as authenticated. */ + msg->flags |= MSG_AUTHENTICATED; + + 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) { + /* We should have an exchange at this point. */ + log_print("message_validate_id: payload out of sequence"); + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); + return -1; + } + 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, 1, + 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) { + /* We should have an exchange at this point. */ + log_print("message_validate_key_exch: " + "payload out of sequence"); + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); + return -1; + } + 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, 1, 1); + return -1; + } + return 0; +} + +/* Validate the NAT-D payload P in message MSG. */ +static int +message_validate_nat_d(struct message *msg, struct payload *p) +{ + struct exchange *exchange = msg->exchange; + + if (!exchange) { + /* We should have an exchange at this point. */ + log_print("message_validate_nat_d: payload out of sequence"); + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); + return -1; + } + + if (exchange->phase != 1) { + log_print("message_validate_nat_d: " + "NAT-D payload must be in phase 1"); + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); + return -1; + } + + /* Mark as handled. */ + p->flags |= PL_MARK; + + return 0; +} + +/* Validate the NAT-OA payload P in message MSG. */ +static int +message_validate_nat_oa(struct message *msg, struct payload *p) +{ + struct exchange *exchange = msg->exchange; + + if (!exchange) { + /* We should have an exchange at this point. */ + log_print("message_validate_nat_d: payload out of sequence"); + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); + return -1; + } + +#ifdef notyet /* XXX Probably never, due to patent issues. */ + /* Mark as handled. */ + p->flags |= PL_MARK; +#endif + + return 0; +} + +/* Validate the nonce payload P in message MSG. */ +static int +message_validate_nonce(struct message *msg, struct payload *p) +{ + if (!msg->exchange) { + /* We should have an exchange at this point. */ + log_print("message_validate_nonce: payload out of sequence"); + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); + return -1; + } + /* Nonces require no specific validation. */ + return 0; +} + +/* + * Validate the notify payload P in message MSG. As a side-effect, create + * an exchange if we do not have one already. + */ +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 we don't have an exchange yet, create one. */ + if (!msg->exchange) { + if (zero_test((u_int8_t *) msg->iov[0].iov_base + + ISAKMP_HDR_MESSAGE_ID_OFF, ISAKMP_HDR_MESSAGE_ID_LEN)) + msg->exchange = exchange_setup_p1(msg, doi->id); + else + msg->exchange = exchange_setup_p2(msg, doi->id); + if (!msg->exchange) { + log_print("message_validate_notify: can not create " + "exchange"); + 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; + } + + /* Validate the SPI. XXX Just ISAKMP for now. */ + if (proto == ISAKMP_PROTO_ISAKMP && + GET_ISAKMP_NOTIFY_SPI_SZ(p->p) == ISAKMP_HDR_COOKIES_LEN && + msg->isakmp_sa && + memcmp(p->p + ISAKMP_NOTIFY_SPI_OFF, msg->isakmp_sa->cookies, + ISAKMP_HDR_COOKIES_LEN) != 0) { + log_print("message_validate_notify: bad cookies"); + message_drop(msg, ISAKMP_NOTIFY_INVALID_SPI, 0, 1, 0); + return -1; + } + + 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 (!msg->exchange) { + /* We should have an exchange at this point. */ + log_print("message_validate_proposal: " + "payload out of sequence"); + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); + return -1; + } + if (proto != ISAKMP_PROTO_ISAKMP + && msg->exchange->doi->validate_proto(proto)) { + message_drop(msg, ISAKMP_NOTIFY_INVALID_PROTOCOL_ID, 0, 1, 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, 1, 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. + * XXX Make sure the above comment is relevant, isn't SA always checked + * first due to the IANA assigned payload number? + */ +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, 1, 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, and the phase 1 SA is ready, setup a phase 2 SA. + */ + if (!exchange) { + if (zero_test(pkt + ISAKMP_HDR_RCOOKIE_OFF, + ISAKMP_HDR_RCOOKIE_LEN)) + exchange = exchange_setup_p1(msg, doi_id); + else if (msg->isakmp_sa->flags & SA_FLAG_READY) + exchange = exchange_setup_p2(msg, doi_id); + else { + /* XXX What to do here? */ + message_free(msg); + return -1; + } + if (!exchange) { + /* XXX Log? */ + message_free(msg); + return -1; + } + } + msg->exchange = exchange; + + /* + * Create a struct sa for each SA payload handed to us unless we are + * the initiator 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); + if (msg->isakmp_sa) + sa_reference(msg->isakmp_sa); + } + /* + * 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, + GET_ISAKMP_GEN_LENGTH(p->p) - ISAKMP_SA_SIT_OFF)) { + log_print("message_validate_sa: situation not supported"); + message_drop(msg, ISAKMP_NOTIFY_SITUATION_NOT_SUPPORTED, + 0, 1, 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(payload_revmap[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) +{ + if (!msg->exchange) { + /* We should have an exchange at this point. */ + log_print("message_validate_sig: payload out of sequence"); + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); + return -1; + } + /* 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) { + /* We should have an exchange at this point. */ + log_print("message_validate_transform: " + "payload out of sequence"); + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); + return -1; + } + if (msg->exchange->doi + ->validate_transform_id(proto, GET_ISAKMP_TRANSFORM_ID(p->p))) { + message_drop(msg, ISAKMP_NOTIFY_INVALID_TRANSFORM_ID, 0, 1, 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, 1, 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, 1, 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, 1, 1); + return -1; + } + return 0; +} + +/* Validate the vendor payload P in message MSG. */ +static int +message_validate_vendor(struct message *msg, struct payload *p) +{ + if (!msg->exchange) { + /* We should have an exchange at this point. */ + log_print("message_validate_vendor: payload out of sequence"); + message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); + return -1; + } + /* Vendor IDs are only allowed in phase 1. */ + if (msg->exchange->phase != 1) { + message_drop(msg, ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE, 0, 1, 1); + return -1; + } +#if defined (USE_DPD) + dpd_check_vendor_payload(msg, p); +#endif +#if defined (USE_NAT_TRAVERSAL) + nat_t_check_vendor_payload(msg, p); +#endif + if (!(p->flags & PL_MARK)) + LOG_DBG((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_map[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 < payload_index_max; i++) + if (i != ISAKMP_PAYLOAD_PROPOSAL && i != + ISAKMP_PAYLOAD_TRANSFORM) + SET(payload_revmap[i], &payload_set); + sz = message_parse_payloads(msg, 0, next, + (u_int8_t *)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 < payload_index_max; i++) + for (p = payload_first(msg, i); p; p = TAILQ_NEXT(p, link)) { + LOG_DBG((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; + struct proto tmp_proto; + struct sa tmp_sa; + + /* 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, 1, 1); + return -1; + } +#ifdef USE_DEBUG + /* Possibly dump a raw hex image of the message to the log channel. */ + message_dump_raw("message_recv", msg, LOG_MESSAGE); +#endif + + /* + * 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)) { + /* + * XXX Later we should differentiate between + * retransmissions and potential replay attacks. + */ + LOG_DBG((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 (msg->isakmp_sa) + sa_reference(msg->isakmp_sa); + + /* + * 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 && msg->exchange->phase == 1 + && zero_test(msg->exchange->cookies + + ISAKMP_HDR_RCOOKIE_OFF, ISAKMP_HDR_RCOOKIE_LEN)) + exchange_upgrade_p1(msg); + else { + log_print("message_recv: invalid cookie(s) " + "%08x%08x %08x%08x", + decode_32(buf + ISAKMP_HDR_ICOOKIE_OFF), + decode_32(buf + ISAKMP_HDR_ICOOKIE_OFF + 4), + decode_32(buf + ISAKMP_HDR_RCOOKIE_OFF), + decode_32(buf + ISAKMP_HDR_RCOOKIE_OFF + 4)); + tmp_proto.sa = &tmp_sa; + tmp_sa.doi = doi_lookup(ISAKMP_DOI_ISAKMP); + tmp_proto.proto = ISAKMP_PROTO_ISAKMP; + tmp_proto.spi_sz[1] = ISAKMP_HDR_COOKIES_LEN; + tmp_proto.spi[1] = + buf + ISAKMP_HDR_COOKIES_OFF; + message_drop(msg, ISAKMP_NOTIFY_INVALID_COOKIE, + &tmp_proto, 1, 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 (check passphrases, if applicable and in Phase 1)", + GET_ISAKMP_HDR_NEXT_PAYLOAD(buf)); + message_drop(msg, ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE, 0, 1, 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, 1, + 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, 1, + 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, 1, + 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, 1, 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, 1, 1); + return -1; + } + if (!setup_isakmp_sa && msgid_is_zero) { + /* + * XXX Very likely redundant, look at the else clause of the + * if (setup_isakmp_sa) statement above. + */ + msg->exchange = exchange_lookup(buf, 0); + if (!msg->exchange) { + log_print("message_recv: phase 1 message after " + "ISAKMP SA is ready"); + message_free(msg); + return -1; + } else if (msg->exchange->last_sent) { + LOG_DBG((LOG_MESSAGE, 80, "message_recv: resending " + "last message from phase 1")); + message_send(msg->exchange->last_sent); + } + } + if (flags & ISAKMP_FLAGS_ENC) { + if (!msg->isakmp_sa) { + LOG_DBG((LOG_MISC, 10, "message_recv: no isakmp_sa " + "for encrypted message")); + message_free(msg); + return -1; + } + /* 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); + free(ks); + 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; + + /* IKE packet capture */ + message_packet_log(msg); + + /* + * 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))) { + if (ks) + free(ks); + 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)) { + if (ks) + free(ks); + 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, 1, 1); + if (ks) + free(ks); + 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->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, 1, + 1); + if (ks) + free(ks); + return -1; + } + /* Make sure the IV we used gets saved in the proper SA. */ + if (ks) { + if (!msg->exchange->keystate) { + msg->exchange->keystate = ks; + msg->exchange->crypto = ks->xf; + } else + free(ks); + } + /* 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; + + /* + * Except for the 3rd Aggressive Mode message, require encryption + * as soon as we have the keystate for it. + */ + if ((flags & ISAKMP_FLAGS_ENC) == 0 && + (msg->exchange->phase == 2 || + (msg->exchange->keystate && + msg->exchange->type != ISAKMP_EXCH_AGGRESSIVE))) { + log_print("message_recv: cleartext phase %d message", + msg->exchange->phase); + message_drop(msg, ISAKMP_NOTIFY_INVALID_FLAGS, 0, 1, 1); + return -1; + } + + /* OK let the exchange logic do the rest. */ + exchange_run(msg); + + return 0; +} + +void +message_send_expire(struct message *msg) +{ + msg->retrans = 0; + + message_send(msg); +} + +/* Queue up message MSG for transmittal. */ +void +message_send(struct message *msg) +{ + struct exchange *exchange = msg->exchange; + struct message *m; + struct msg_head *q; + + /* Remove retransmissions on this message */ + if (msg->retrans) { + timer_remove_event(msg->retrans); + msg->retrans = 0; + } + /* IKE packet capture */ + message_packet_log(msg); + + /* + * 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); + if (!exchange->keystate) + return; + exchange->crypto = exchange->keystate->xf; + exchange->flags |= EXCHANGE_FLAG_ENCRYPT; + } + if (message_encrypt(msg)) { + /* XXX Log. */ + return; + } + } + /* Keep the COMMIT bit on. */ + if (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); + +#ifdef USE_DEBUG + message_dump_raw("message_send", msg, LOG_MESSAGE); +#endif + msg->flags |= MSG_IN_TRANSIT; + exchange->in_transit = msg; + + /* + * If we get a retransmission of a message before our response + * has left the queue, don't queue it again, as it will result + * in a circular list. + */ + q = msg->transport->vtbl->get_queue(msg); + for (m = TAILQ_FIRST(q); m; m = TAILQ_NEXT(m, link)) + if (m == msg) { + LOG_DBG((LOG_MESSAGE, 60, + "message_send: msg %p already on sendq %p", m, q)); + return; + } + TAILQ_INSERT_TAIL(q, 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 = calloc(1, sizeof *payload_node); + if (!payload_node) { + log_error("message_add_payload: calloc (1, %lu) failed", + (unsigned long)sizeof *payload_node); + return -1; + } + new_iov = (struct iovec *) realloc(msg->iov, (msg->iovlen + 1) * + sizeof *msg->iov); + if (!new_iov) { + log_error("message_add_payload: realloc (%p, %lu) failed", + msg->iov, (msg->iovlen + 1) * + (unsigned long)sizeof *msg->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_map[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 *spis; + } d; +#if defined (USE_DPD) + struct { + u_int16_t msg_type; + u_int8_t *spi; + u_int32_t seq; + } dpd; +#endif + } 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. INCOMING is true if the SPI field should be + * filled with the incoming SPI and false if it is to be filled with the + * outgoing one. + * + * 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 incoming) +{ + struct info_args args; + struct sa *doi_sa = proto ? proto->sa : isakmp_sa; + + args.discr = 'N'; + args.doi = doi_sa ? doi_sa->doi->id : ISAKMP_DOI_ISAKMP; + args.proto = proto ? proto->proto : ISAKMP_PROTO_ISAKMP; + args.spi_sz = proto ? proto->spi_sz[incoming] : 0; + args.u.n.msg_type = notify; + args.u.n.spi = proto ? proto->spi[incoming] : 0; + if (isakmp_sa && (isakmp_sa->flags & SA_FLAG_READY)) + exchange_establish_p2(isakmp_sa, ISAKMP_EXCH_INFO, 0, &args, + 0, 0); + else + exchange_establish_p1(msg->transport, ISAKMP_EXCH_INFO, + msg->exchange ? msg->exchange->doi->id : ISAKMP_DOI_ISAKMP, + 0, &args, 0, 0); +} + +/* Send a DELETE inside an informational exchange for each protocol in SA. */ +void +message_send_delete(struct sa *sa) +{ + struct info_args args; + struct proto *proto; + struct sa *isakmp_sa; + struct sockaddr *dst; + + sa->transport->vtbl->get_dst(sa->transport, &dst); + isakmp_sa = sa_isakmp_lookup_by_peer(dst, sysdep_sa_len(dst)); + if (!isakmp_sa) { + /* + * XXX We ought to setup an ISAKMP SA with our peer here and + * send the DELETE over that one. + */ + return; + } + args.discr = 'D'; + args.doi = sa->doi->id; + args.u.d.nspis = 1; + for (proto = TAILQ_FIRST(&sa->protos); proto; + proto = TAILQ_NEXT(proto, link)) { + args.proto = proto->proto; + args.spi_sz = proto->spi_sz[1]; + args.u.d.spis = proto->spi[1]; + exchange_establish_p2(isakmp_sa, ISAKMP_EXCH_INFO, 0, &args, + 0, 0); + } +} + +#if defined (USE_DPD) +void +message_send_dpd_notify(struct sa* isakmp_sa, u_int16_t notify, u_int32_t seq) +{ + struct info_args args; + + args.discr = 'P'; + args.doi = IPSEC_DOI_IPSEC; + args.proto = ISAKMP_PROTO_ISAKMP; + args.spi_sz = ISAKMP_HDR_COOKIES_LEN; + args.u.dpd.msg_type = notify; + args.u.dpd.spi = isakmp_sa->cookies; + args.u.dpd.seq = htonl(seq); + + exchange_establish_p2(isakmp_sa, ISAKMP_EXCH_INFO, 0, &args, 0, 0); +} +#endif + +/* Build the informational message into MSG. */ +int +message_send_info(struct message *msg) +{ + u_int8_t *buf; + size_t sz = 0; + struct info_args *args = msg->extra; + u_int8_t payload; + + /* Let the DOI get the first hand on the message. */ + if (msg->exchange->doi->informational_pre_hook) + if (msg->exchange->doi->informational_pre_hook(msg)) + return -1; + + switch (args->discr) { +#if defined (USE_DPD) + case 'P': + sz = sizeof args->u.dpd.seq; + /* FALLTHROUGH */ +#endif + case 'N': + sz += ISAKMP_NOTIFY_SPI_OFF + args->spi_sz; + break; + case 'D': + default: /* Silence gcc */ + sz = ISAKMP_DELETE_SPI_OFF + args->u.d.nspis * args->spi_sz; + break; + } + + buf = calloc(1, sz); + if (!buf) { + log_error("message_send_info: calloc (1, %lu) failed", + (unsigned long)sz); + message_free(msg); + return -1; + } + switch (args->discr) { +#if defined (USE_DPD) + case 'P': + memcpy(buf + ISAKMP_NOTIFY_SPI_OFF + args->spi_sz, + &args->u.dpd.seq, sizeof args->u.dpd.seq); + /* FALLTHROUGH */ +#endif + 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.spis, + args->u.d.nspis * args->spi_sz); + msg->flags |= MSG_PRIORITIZED; + break; + } + + if (message_add_payload(msg, payload, buf, sz, 1)) { + free(buf); + message_free(msg); + return -1; + } + /* Let the DOI get the last hand on the message. */ + if (msg->exchange->doi->informational_post_hook) + if (msg->exchange->doi->informational_post_hook(msg)) { + message_free(msg); + return -1; + } + return 0; +} + +/* + * Drop the MSG message due to reason given in NOTIFY. If NOTIFY is set + * send out a notification to the originator. Fill this notification with + * values from PROTO. INCOMING decides which SPI to include. If CLEAN is + * set, free the message when ready with it. + */ +void +message_drop(struct message *msg, int notify, struct proto *proto, + int incoming, int clean) +{ + struct transport *t = msg->transport; + struct sockaddr *dst; + char *address; + short port = 0; + + t->vtbl->get_dst(t, &dst); + if (sockaddr2text(dst, &address, 0)) { + log_error("message_drop: sockaddr2text () failed"); + address = 0; + } + switch (dst->sa_family) { + case AF_INET: + port = ((struct sockaddr_in *)dst)->sin_port; + break; + case AF_INET6: + port = ((struct sockaddr_in6 *)dst)->sin6_port; + break; + default: + log_print("message_drop: unknown protocol family %d", + dst->sa_family); + } + + log_print("dropped message from %s port %d due to notification type " + "%s", address ? address : "<unknown>", htons(port), + constant_name(isakmp_notify_cst, notify)); + + if (address) + free(address); + + /* If specified, return a notification. */ + if (notify) + message_send_notification(msg, msg->isakmp_sa, notify, proto, + incoming); + 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. + */ +void +message_dump_raw(char *header, struct message *msg, int class) +{ + u_int32_t i, j, k = 0; + char buf[80], *p = buf; + + LOG_DBG((class, 70, "%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++) { + snprintf(p, sizeof buf - (int) (p - buf), "%02x", + ((u_int8_t *) msg->iov[i].iov_base)[j]); + p += 2; + if (++k % 32 == 0) { + *p = '\0'; + LOG_DBG((class, 70, "%s: %s", header, buf)); + p = buf; + } else if (k % 4 == 0) + *p++ = ' '; + } + *p = '\0'; + if (p != buf) + LOG_DBG((class, 70, "%s: %s", header, buf)); +} + +static void +message_packet_log(struct message *msg) +{ +#if defined (USE_DEBUG) + struct sockaddr *src, *dst; + struct transport *t = msg->transport; + + /* Don't log retransmissions. Redundant for incoming packets... */ + if (msg->xmits > 0) + return; + +#if defined (USE_NAT_TRAVERSAL) + if (msg->exchange && msg->exchange->flags & EXCHANGE_FLAG_NAT_T_ENABLE) + t = ((struct virtual_transport *)msg->transport)->encap; +#endif + + /* Figure out direction. */ + if (msg->exchange && + msg->exchange->initiator ^ (msg->exchange->step % 2)) { + t->vtbl->get_src(t, &src); + t->vtbl->get_dst(t, &dst); + } else { + t->vtbl->get_src(t, &dst); + t->vtbl->get_dst(t, &src); + } + + log_packet_iov(src, dst, msg->iov, msg->iovlen); +#endif /* USE_DEBUG */ +} + +/* + * 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 i, sz = 0; + u_int8_t *buf; + + /* 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) { + log_error("message_encrypt: realloc (%p, %lu) failed", + msg->iov[1].iov_base, (unsigned long) sz); + 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_DBG((LOG_MESSAGE, 90, "message_check_duplicate: last_received %p", + exchange->last_received)); + if (exchange->last_received) { + LOG_DBG_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_DBG((LOG_MESSAGE, 80, + "message_check_duplicate: dropping dup")); + + /* + * Retransmit if the previos sent message was the last + * of an exchange, otherwise just wait for the + * ordinary retransmission. + */ + if (exchange->last_sent && (exchange->last_sent->flags + & MSG_LAST)) + message_send(exchange->last_sent); + 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) { + if (exchange->last_sent == exchange->in_transit) { + struct message *m = exchange->in_transit; + TAILQ_REMOVE(m->transport->vtbl->get_queue(m), m, + link); + exchange->in_transit = 0; + } + 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, int (*validate)(struct exchange *, + struct sa *, struct sa *)) +{ + struct payload *tp, *propp, *sap, *next_tp = 0, *next_propp, *next_sap; + struct payload *saved_tp = 0, *saved_propp = 0, *saved_sap = 0; + struct sa *sa; + struct proto *proto; + int suite_ok_so_far = 0; + struct exchange *exchange = msg->exchange; + + /* + * 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 = payload_first(msg, 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_DBG((LOG_NEGOTIATION, 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; + + saved_tp = next_tp; + saved_propp = next_propp; + saved_sap = next_sap; + /* Skip to last transform of this protocol proposal. */ + while ((next_tp = step_transform(tp, &next_propp, + &next_sap)) && next_propp == propp) + tp = next_tp; + } +retry_transform: + /* + * 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_DBG((LOG_NEGOTIATION, 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 check it against the accepted ones. + */ + if (suite_ok_so_far) { + if (!validate || validate(exchange, sa, + msg->isakmp_sa)) { + LOG_DBG((LOG_NEGOTIATION, 30, + "message_negotiate_sa: proposal " + "%d succeeded", + GET_ISAKMP_PROP_NO(propp->p))); + + /* + * Skip to the last transform of this + * SA. + */ + while ((next_tp = step_transform(tp, + &next_propp, &next_sap)) + && next_sap == sap) + tp = next_tp; + } else { + /* Backtrack. */ + LOG_DBG((LOG_NEGOTIATION, 30, + "message_negotiate_sa: proposal " + "%d failed", + GET_ISAKMP_PROP_NO(propp->p))); + next_tp = saved_tp; + next_propp = saved_propp; + next_sap = saved_sap; + suite_ok_so_far = 0; + + /* + * Remove potentially succeeded + * choices from the SA. + */ + while (TAILQ_FIRST(&sa->protos)) + TAILQ_REMOVE(&sa->protos, + TAILQ_FIRST(&sa->protos), + link); + goto retry_transform; + } + } + } + /* 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. + */ + log_print("message_negotiate_sa: no " + "compatible proposal found"); + message_drop(msg, + ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0); + } + sa = TAILQ_NEXT(sa, next); + } + } + return 0; + +cleanup: + /* + * Remove potentially succeeded choices from the SA. + * XXX Do we leak struct protos and related data here? + */ + while (TAILQ_FIRST(&sa->protos)) + TAILQ_REMOVE(&sa->protos, TAILQ_FIRST(&sa->protos), link); + return -1; +} + +/* + * Add SA, proposal and transform payload(s) to MSG out of information + * found in the exchange MSG is part of.. + */ +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) { + log_error("message_add_sa_payload: " + "malloc (%lu) failed", (unsigned long)sa_len); + 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) { + log_error("message_add_sa_payload: calloc (%d, %lu) " + "failed", nprotos, + (unsigned long)sizeof *transforms); + goto cleanup; + } + transform_lens = calloc(nprotos, sizeof *transform_lens); + if (!transform_lens) { + log_error("message_add_sa_payload: calloc (%d, %lu) " + "failed", nprotos, + (unsigned long) sizeof *transform_lens); + goto cleanup; + } + proposals = calloc(nprotos, sizeof *proposals); + if (!proposals) { + log_error("message_add_sa_payload: calloc (%d, %lu) " + "failed", nprotos, + (unsigned long)sizeof *proposals); + goto cleanup; + } + proposal_lens = calloc(nprotos, sizeof *proposal_lens); + if (!proposal_lens) { + log_error("message_add_sa_payload: calloc (%d, %lu) " + "failed", nprotos, + (unsigned long)sizeof *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]) { + log_error("message_add_sa_payload: malloc " + "(%lu) failed", + (unsigned long)transform_lens[i]); + goto cleanup; + } + /* Get incoming 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[1] = spi; + proto->spi_sz[1] = spi_sz; + } else + spi_sz = 0; + + proposal_lens[i] = ISAKMP_PROP_SPI_OFF + spi_sz; + proposals[i] = malloc(proposal_lens[i]); + if (!proposals[i]) { + log_error("message_add_sa_payload: malloc " + "(%lu) failed", + (unsigned long)proposal_lens[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); + 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 (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 skip = 0; + size_t i, 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, (u_int8_t *) 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); + } +} + +/* Initialize and populate payload_map[]. */ +void +message_init(void) +{ + u_int8_t i; + + memset(&payload_map, 0, sizeof payload_map); + + payload_index_max = sizeof payload_revmap / sizeof payload_revmap[0]; + for (i = 0; i < payload_index_max; i++) { + payload_map[payload_revmap[i]] = i; + LOG_DBG((LOG_MESSAGE, 95, "message_init: payload_map[%d] = %d", + payload_revmap[i], i)); + } +} + +struct payload * +payload_first(struct message *msg, u_int8_t payload) +{ + if (payload_map[payload]) + return TAILQ_FIRST(&msg->payload[payload_map[payload]]); + else + return 0; +} + +struct payload * +payload_last(struct message *msg, u_int8_t payload) +{ + if (payload_map[payload]) + return TAILQ_LAST(&msg->payload[payload_map[payload]], + payload_head); + else + return 0; +} diff --git a/keyexchange/isakmpd-20041012/message.h b/keyexchange/isakmpd-20041012/message.h new file mode 100644 index 0000000..14b1d9a --- /dev/null +++ b/keyexchange/isakmpd-20041012/message.h @@ -0,0 +1,205 @@ +/* $OpenBSD: message.h,v 1.22 2004/08/10 15:59:10 ho Exp $ */ +/* $EOM: message.h,v 1.51 2000/10/10 12:36:39 provos Exp $ */ + +/* + * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved. + * Copyright (c) 1999 Angelos D. Keromytis. All rights reserved. + * Copyright (c) 2001, 2004 Håkan Olsson. 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. + * + * 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 + * unencrypted 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; + + /* 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. */ + +/* + * This is the last message of an exchange, meaning it should not be + * retransmitted other than if we see duplicates from our peer's last + * message. + */ +#define MSG_LAST 0x01 + +/* The message has already been encrypted. */ +#define MSG_ENCRYPTED 0x02 + +/* The message is on the send queue. */ +#define MSG_IN_TRANSIT 0x04 + +/* This message should be kept on the prioritized sendq. */ +#define MSG_PRIORITIZED 0x08 + +/* This message has successfully been authenticated. */ +#define MSG_AUTHENTICATED 0x10 + +TAILQ_HEAD(msg_head, message); + +/* The number of different ISAKMP payloads supported. */ +extern u_int8_t payload_index_max; + +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_dump_raw(char *, struct message *, int); +extern void message_free(struct message *); +extern void message_init(void); +extern int message_negotiate_sa(struct message *, + int (*)(struct exchange *, struct sa *, struct sa *)); +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_expire(struct message *); +extern void message_send_delete(struct sa *); +extern int 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 *); +struct payload *payload_first(struct message *, u_int8_t); +struct payload *payload_last(struct message *, u_int8_t); + +#if defined (USE_DPD) +extern void message_send_dpd_notify(struct sa*, u_int16_t, u_int32_t); +#endif + +#endif /* _MESSAGE_H_ */ diff --git a/keyexchange/isakmpd-20041012/monitor.c b/keyexchange/isakmpd-20041012/monitor.c new file mode 100644 index 0000000..bd14005 --- /dev/null +++ b/keyexchange/isakmpd-20041012/monitor.c @@ -0,0 +1,1174 @@ +/* $OpenBSD: monitor.c,v 1.29 2004/08/12 11:21:07 hshoexer Exp $ */ + +/* + * Copyright (c) 2003 Håkan Olsson. 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. + * + * 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. + */ + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <netinet/in.h> +#include <errno.h> +#include <fcntl.h> +#include <pwd.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#if defined (USE_POLICY) +#include <regex.h> +#include <keynote.h> +#endif + +#include "sysdep.h" + +#include "conf.h" +#include "log.h" +#include "monitor.h" +#include "policy.h" +#include "ui.h" +#include "util.h" +#include "pf_key_v2.h" + +struct monitor_state { + pid_t pid; + int s; + char root[MAXPATHLEN]; +} m_state; + +volatile sig_atomic_t sigchlded = 0; +extern volatile sig_atomic_t sigtermed; +static volatile sig_atomic_t cur_state = STATE_INIT; + +/* Private functions. */ +int m_write_int32(int, int32_t); +int m_write_raw(int, char *, size_t); +int m_read_int32(int, int32_t *); +int m_read_raw(int, char *, size_t); +void m_flush(int); + +static void m_priv_getfd(int); +static void m_priv_getsocket(int); +static void m_priv_setsockopt(int); +static void m_priv_bind(int); +static int m_priv_local_sanitize_path(char *, size_t, int); +static int m_priv_check_sockopt(int, int); +static int m_priv_check_bind(const struct sockaddr *, socklen_t); +static void m_priv_increase_state(int); +static void m_priv_test_state(int); + +static void m_priv_ui_init(int); +static void m_priv_pfkey_open(int); + +/* + * Public functions, unprivileged. + */ + +/* Setup monitor context, fork, drop child privs. */ +pid_t +monitor_init(int debug) +{ + struct passwd *pw; + int p[2]; + + memset(&m_state, 0, sizeof m_state); + + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, p) != 0) + log_fatal("monitor_init: socketpair() failed"); + + pw = getpwnam(ISAKMPD_PRIVSEP_USER); + if (pw == NULL) + log_fatal("monitor_init: getpwnam(\"%s\") failed", + ISAKMPD_PRIVSEP_USER); + + m_state.pid = fork(); + m_state.s = p[m_state.pid ? 1 : 0]; + strlcpy(m_state.root, pw->pw_dir, sizeof m_state.root); + + LOG_DBG((LOG_SYSDEP, 30, "monitor_init: pid %d my fd %d", m_state.pid, + m_state.s)); + + /* The child process should drop privileges now. */ + if (!m_state.pid) { + if (chroot(pw->pw_dir) != 0 || chdir("/") != 0) + log_fatal("monitor_init: chroot failed"); + + if (setgid(pw->pw_gid) != 0) + log_fatal("monitor_init: setgid(%d) failed", + pw->pw_gid); + + if (setuid(pw->pw_uid) != 0) + log_fatal("monitor_init: setuid(%d) failed", + pw->pw_uid); + + LOG_DBG((LOG_MISC, 10, + "monitor_init: privileges dropped for child process")); + } else { + setproctitle("monitor [priv]"); + } + + + /* With "-dd", stop and wait here. For gdb "attach" etc. */ + if (debug > 1) { + log_print("monitor_init: stopped %s PID %d fd %d%s", + m_state.pid ? "priv" : "child", getpid(), m_state.s, + m_state.pid ? ", waiting for SIGCONT" : ""); + kill(getpid(), SIGSTOP); /* Wait here for SIGCONT. */ + if (m_state.pid) + kill(m_state.pid, SIGCONT); /* Continue child. */ + } + + return m_state.pid; +} + +void +monitor_exit(int code) +{ + if (m_state.pid != 0) + kill(m_state.pid, SIGKILL); + + exit(code); +} + +void +monitor_ui_init(void) +{ + int32_t err; + + if (m_write_int32(m_state.s, MONITOR_UI_INIT)) + goto errout; + + if (m_read_int32(m_state.s, &err)) + goto errout; + + if (err != 0) { + log_fatal("monitor_ui_init: parent could not create FIFO " + "\"%s\"", ui_fifo); + exit(1); + } + + ui_socket = mm_receive_fd(m_state.s); + if (ui_socket < 0) + log_fatal("monitor_ui_init: parent could not create FIFO " + "\"%s\"", ui_fifo); + + return; + +errout: + log_error("monitor_ui_init: problem talking to privileged process"); + return; +} + +int +monitor_pf_key_v2_open(void) +{ + int32_t err; + + if (m_write_int32(m_state.s, MONITOR_PFKEY_OPEN)) + goto errout; + + if (m_read_int32(m_state.s, &err)) + goto errout; + + if (err < 0) { + log_error("monitor_pf_key_v2_open: parent could not create " + "PF_KEY socket"); + return -1; + } + + pf_key_v2_socket = mm_receive_fd(m_state.s); + if (pf_key_v2_socket < 0) { + log_error("monitor_pf_key_v2_open: mm_receive_fd() failed: %s", + strerror(errno)); + return -1; + } + return pf_key_v2_socket; + +errout: + log_error("monitor_pf_key_v2_open: problem talking to privileged " + "process"); + return -1; +} + +int +monitor_open(const char *path, int flags, mode_t mode) +{ + int fd, mode32 = (int32_t) mode; + int32_t err; + char realpath[MAXPATHLEN]; + + if (path[0] == '/') + strlcpy(realpath, path, sizeof realpath); + else + snprintf(realpath, sizeof realpath, "%s/%s", m_state.root, + path); + + /* Write data to priv process. */ + if (m_write_int32(m_state.s, MONITOR_GET_FD)) + goto errout; + + if (m_write_raw(m_state.s, realpath, strlen(realpath) + 1)) + goto errout; + + if (m_write_int32(m_state.s, flags)) + goto errout; + + if (m_write_int32(m_state.s, mode32)) + goto errout; + + if (m_read_int32(m_state.s, &err)) + goto errout; + + if (err != 0) { + errno = (int) err; + return -1; + } + /* Wait for response. */ + fd = mm_receive_fd(m_state.s); + if (fd < 0) { + log_error("monitor_open: mm_receive_fd () failed: %s", + strerror(errno)); + return -1; + } + return fd; + +errout: + log_error("monitor_open: problem talking to privileged process"); + return -1; +} + +FILE * +monitor_fopen(const char *path, const char *mode) +{ + FILE *fp; + int fd, flags = 0, saved_errno; + mode_t mask, cur_umask; + + /* Only the child process is supposed to run this. */ + if (m_state.pid) + log_fatal("[priv] bad call to monitor_fopen"); + + switch (mode[0]) { + case 'r': + flags = (mode[1] == '+' ? O_RDWR : O_RDONLY); + break; + case 'w': + flags = (mode[1] == '+' ? O_RDWR : O_WRONLY) | O_CREAT | + O_TRUNC; + break; + case 'a': + flags = (mode[1] == '+' ? O_RDWR : O_WRONLY) | O_CREAT | + O_APPEND; + break; + default: + log_fatal("monitor_fopen: bad call"); + } + + cur_umask = umask(0); + (void)umask(cur_umask); + mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + mask &= ~cur_umask; + + fd = monitor_open(path, flags, mask); + if (fd < 0) + return NULL; + + /* Got the fd, attach a FILE * to it. */ + fp = fdopen(fd, mode); + if (!fp) { + log_error("monitor_fopen: fdopen() failed"); + saved_errno = errno; + close(fd); + errno = saved_errno; + return NULL; + } + return fp; +} + +int +monitor_stat(const char *path, struct stat *sb) +{ + int fd, r, saved_errno; + + /* O_NONBLOCK is needed for stat'ing fifos. */ + fd = monitor_open(path, O_RDONLY | O_NONBLOCK, 0); + if (fd < 0) + return -1; + + r = fstat(fd, sb); + saved_errno = errno; + close(fd); + errno = saved_errno; + return r; +} + +int +monitor_socket(int domain, int type, int protocol) +{ + int s; + int32_t err; + + if (m_write_int32(m_state.s, MONITOR_GET_SOCKET)) + goto errout; + + if (m_write_int32(m_state.s, (int32_t)domain)) + goto errout; + + if (m_write_int32(m_state.s, (int32_t)type)) + goto errout; + + if (m_write_int32(m_state.s, (int32_t)protocol)) + goto errout; + + if (m_read_int32(m_state.s, &err)) + goto errout; + + if (err != 0) { + errno = (int)err; + return -1; + } + /* Read result. */ + s = mm_receive_fd(m_state.s); + if (s < 0) { + log_error("monitor_socket: mm_receive_fd () failed: %s", + strerror(errno)); + return -1; + } + return s; + +errout: + log_error("monitor_socket: problem talking to privileged process"); + return -1; +} + +int +monitor_setsockopt(int s, int level, int optname, const void *optval, + socklen_t optlen) +{ + int32_t ret, err; + + if (m_write_int32(m_state.s, MONITOR_SETSOCKOPT)) + goto errout; + if (mm_send_fd(m_state.s, s)) + goto errout; + + if (m_write_int32(m_state.s, (int32_t)level)) + goto errout; + if (m_write_int32(m_state.s, (int32_t)optname)) + goto errout; + if (m_write_int32(m_state.s, (int32_t)optlen)) + goto errout; + if (m_write_raw(m_state.s, (char *)optval, (size_t)optlen)) + goto errout; + + if (m_read_int32(m_state.s, &err)) + goto errout; + + if (err != 0) + errno = (int)err; + + if (m_read_int32(m_state.s, &ret)) + goto errout; + + return (int)ret; + +errout: + log_print("monitor_setsockopt: read/write error"); + return -1; +} + +int +monitor_bind(int s, const struct sockaddr *name, socklen_t namelen) +{ + int32_t ret, err; + + if (m_write_int32(m_state.s, MONITOR_BIND)) + goto errout; + if (mm_send_fd(m_state.s, s)) + goto errout; + + if (m_write_int32(m_state.s, (int32_t)namelen)) + goto errout; + if (m_write_raw(m_state.s, (char *)name, (size_t)namelen)) + goto errout; + + if (m_read_int32(m_state.s, &err)) + goto errout; + + if (err != 0) + errno = (int)err; + + if (m_read_int32(m_state.s, &ret)) + goto errout; + + return (int)ret; + +errout: + log_print("monitor_bind: read/write error"); + return -1; +} + +struct monitor_dirents * +monitor_opendir(const char *path) +{ + char *buf, *cp; + size_t bufsize; + int fd, nbytes, entries; + long base; + struct stat sb; + struct dirent *dp; + struct monitor_dirents *direntries; + + fd = monitor_open(path, 0, O_RDONLY); + if (fd < 0) { + log_error("monitor_opendir: opendir(\"%s\") failed", path); + return NULL; + } + /* Now build a list with all dirents from fd. */ + if (fstat(fd, &sb) < 0) { + (void)close(fd); + return NULL; + } + if (!S_ISDIR(sb.st_mode)) { + (void)close(fd); + errno = EACCES; + return NULL; + } + bufsize = sb.st_size; + if (bufsize < sb.st_blksize) + bufsize = sb.st_blksize; + + buf = calloc(bufsize, sizeof(char)); + if (buf == NULL) { + (void)close(fd); + errno = EACCES; + return NULL; + } + nbytes = getdirentries(fd, buf, bufsize, &base); + if (nbytes <= 0) { + (void)close(fd); + free(buf); + errno = EACCES; + return NULL; + } + (void)close(fd); + + for (entries = 0, cp = buf; cp < buf + nbytes;) { + dp = (struct dirent *)cp; + cp += dp->d_reclen; + entries++; + } + + direntries = calloc(1, sizeof(struct monitor_dirents)); + if (direntries == NULL) { + free(buf); + errno = EACCES; + return NULL; + } + direntries->dirents = calloc(entries + 1, sizeof(struct dirent *)); + if (direntries->dirents == NULL) { + free(buf); + free(direntries); + errno = EACCES; + return NULL; + } + direntries->current = 0; + + for (entries = 0, cp = buf; cp < buf + nbytes;) { + dp = (struct dirent *)cp; + direntries->dirents[entries++] = dp; + cp += dp->d_reclen; + } + direntries->dirents[entries] = NULL; + + return direntries; +} + +struct dirent * +monitor_readdir(struct monitor_dirents *direntries) +{ + if (direntries->dirents[direntries->current] != NULL) + return direntries->dirents[direntries->current++]; + + return NULL; +} + +int +monitor_closedir(struct monitor_dirents *direntries) +{ + free(direntries->dirents); + free(direntries); + + return 0; +} + +void +monitor_init_done(void) +{ + if (m_write_int32(m_state.s, MONITOR_INIT_DONE)) + log_print("monitor_init_done: read/write error"); + + return; +} + +/* + * Start of code running with privileges (the monitor process). + */ + +/* Help functions for monitor_loop(). */ +static void +monitor_got_sigchld(int sig) +{ + sigchlded = 1; +} + +static void +sig_pass_to_chld(int sig) +{ + int oerrno = errno; + + if (m_state.pid != -1) + kill(m_state.pid, sig); + errno = oerrno; +} + +/* This function is where the privileged process waits(loops) indefinitely. */ +void +monitor_loop(int debug) +{ + pid_t pid; + fd_set *fds; + size_t fdsn; + int status, n, maxfd; + + if (!debug) + log_to(0); + + maxfd = m_state.s + 1; + + fdsn = howmany(maxfd, NFDBITS) * sizeof(fd_mask); + fds = (fd_set *)malloc(fdsn); + if (!fds) { + kill(m_state.pid, SIGTERM); + log_fatal("monitor_loop: malloc (%lu) failed", + (unsigned long)fdsn); + return; + } + /* If the child dies, we should shutdown also. */ + signal(SIGCHLD, monitor_got_sigchld); + + /* SIGHUP, SIGUSR1 and SIGUSR2 will be forwarded to child. */ + signal(SIGHUP, sig_pass_to_chld); + signal(SIGUSR1, sig_pass_to_chld); + signal(SIGUSR2, sig_pass_to_chld); + + while (cur_state < STATE_QUIT) { + /* + * Currently, there is no need for us to hang around if the + * child is in the process of shutting down. + */ + if (sigtermed) { + m_priv_increase_state(STATE_QUIT); + kill(m_state.pid, SIGTERM); + break; + } + + if (sigchlded) { + do { + pid = waitpid(m_state.pid, &status, WNOHANG); + } while (pid == -1 && errno == EINTR); + + if (pid == m_state.pid && (WIFEXITED(status) || + WIFSIGNALED(status))) { + m_priv_increase_state(STATE_QUIT); + break; + } + } + + memset(fds, 0, fdsn); + FD_SET(m_state.s, fds); + + n = select(maxfd, fds, NULL, NULL, NULL); + if (n == -1) { + if (errno != EINTR) { + log_error("select"); + sleep(1); + } + } else if (n) + if (FD_ISSET(m_state.s, fds)) { + int32_t msgcode; + if (m_read_int32(m_state.s, &msgcode)) + m_flush(m_state.s); + else + switch (msgcode) { + case MONITOR_GET_FD: + m_priv_getfd(m_state.s); + break; + + case MONITOR_UI_INIT: + LOG_DBG((LOG_MISC, 80, + "%s: MONITOR_UI_INIT", + __func__)); + m_priv_test_state(STATE_INIT); + m_priv_ui_init(m_state.s); + break; + + case MONITOR_PFKEY_OPEN: + LOG_DBG((LOG_MISC, 80, + "%s: MONITOR_PFKEY_OPEN", + __func__)); + m_priv_test_state(STATE_INIT); + m_priv_pfkey_open(m_state.s); + break; + + case MONITOR_GET_SOCKET: + LOG_DBG((LOG_MISC, 80, + "%s: MONITOR_GET_SOCKET", + __func__)); + m_priv_test_state(STATE_INIT); + m_priv_getsocket(m_state.s); + break; + + case MONITOR_SETSOCKOPT: + LOG_DBG((LOG_MISC, 80, + "%s: MONITOR_SETSOCKOPT", + __func__)); + m_priv_test_state(STATE_INIT); + m_priv_setsockopt(m_state.s); + break; + + case MONITOR_BIND: + LOG_DBG((LOG_MISC, 80, + "%s: MONITOR_BIND", + __func__)); + m_priv_test_state(STATE_INIT); + m_priv_bind(m_state.s); + break; + + case MONITOR_INIT_DONE: + LOG_DBG((LOG_MISC, 80, + "%s: MONITOR_INIT_DONE", + __func__)); + m_priv_test_state(STATE_INIT); + m_priv_increase_state( + STATE_RUNNING); + break; + + case MONITOR_SHUTDOWN: + LOG_DBG((LOG_MISC, 80, + "%s: MONITOR_SHUTDOWN", + __func__)); + m_priv_increase_state( + STATE_QUIT); + break; + + default: + log_print("monitor_loop: " + "got unknown code %d", + msgcode); + } + } + } + + free(fds); + exit(0); +} + + +/* Privileged: called by monitor_loop. */ +static void +m_priv_ui_init(int s) +{ + int32_t err; + + ui_init(); + + if (ui_socket >= 0) + err = 0; + else + err = -1; + + if (m_write_int32(s, err)) + goto errout; + + if (ui_socket >= 0 && mm_send_fd(s, ui_socket)) { + close(ui_socket); + goto errout; + } + + /* In case of stdin, we do not close the socket. */ + if (ui_socket > 0) + close(ui_socket); + return; + +errout: + log_error("m_priv_ui_init: read/write operation failed"); + return; +} + +/* Privileged: called by monitor_loop. */ +static void +m_priv_pfkey_open(int s) +{ + int fd; + int32_t err; + + fd = pf_key_v2_open(); + + if (fd < 0) + err = -1; + else + err = 0; + + if (m_write_int32(s, err)) + goto errout; + + if (fd > 0 && mm_send_fd(s, fd)) { + close(fd); + goto errout; + } + close(fd); + + return; + +errout: + log_error("m_priv_pfkey_open: read/write operation failed"); + return; +} + +/* Privileged: called by monitor_loop. */ +static void +m_priv_getfd(int s) +{ + char path[MAXPATHLEN]; + int32_t v, err; + int flags; + mode_t mode; + + /* + * We expect the following data on the socket: + * u_int32_t pathlen + * <variable> path + * u_int32_t flags + * u_int32_t mode + */ + + if (m_read_raw(s, path, MAXPATHLEN)) + goto errout; + + if (m_read_int32(s, &v)) + goto errout; + flags = (int)v; + + if (m_read_int32(s, &v)) + goto errout; + mode = (mode_t) v; + + if (m_priv_local_sanitize_path(path, sizeof path, flags) != 0) { + err = EACCES; + v = -1; + } else { + err = 0; + v = (int32_t)open(path, flags, mode); + if (v < 0) + err = (int32_t)errno; + } + + if (m_write_int32(s, err)) + goto errout; + + if (v > 0 && mm_send_fd(s, v)) { + close(v); + goto errout; + } + close(v); + return; + +errout: + log_error("m_priv_getfd: read/write operation failed"); + return; +} + +/* Privileged: called by monitor_loop. */ +static void +m_priv_getsocket(int s) +{ + int domain, type, protocol; + int32_t v, err; + + if (m_read_int32(s, &v)) + goto errout; + domain = (int)v; + + if (m_read_int32(s, &v)) + goto errout; + type = (int)v; + + if (m_read_int32(s, &v)) + goto errout; + protocol = (int)v; + + err = 0; + v = (int32_t)socket(domain, type, protocol); + if (v < 0) + err = (int32_t)errno; + + if (m_write_int32(s, err)) + goto errout; + + if (v > 0 && mm_send_fd(s, v)) { + close(v); + goto errout; + } + close(v); + return; + +errout: + log_error("m_priv_getsocket: read/write operation failed"); + return; +} + +/* Privileged: called by monitor_loop. */ +static void +m_priv_setsockopt(int s) +{ + int sock, level, optname; + char *optval = 0; + socklen_t optlen; + int32_t v, err; + + sock = mm_receive_fd(s); + if (sock < 0) + goto errout; + + if (m_read_int32(s, &level)) + goto errout; + + if (m_read_int32(s, &optname)) + goto errout; + + if (m_read_int32(s, &optlen)) + goto errout; + + optval = (char *)malloc(optlen); + if (!optval) + goto errout; + + if (m_read_raw(s, optval, optlen)) + goto errout; + + if (m_priv_check_sockopt(level, optname) != 0) { + err = EACCES; + v = -1; + } else { + err = 0; + v = (int32_t)setsockopt(sock, level, optname, optval, optlen); + if (v < 0) + err = (int32_t)errno; + } + + close(sock); + sock = -1; + + if (m_write_int32(s, err)) + goto errout; + + if (m_write_int32(s, v)) + goto errout; + + free(optval); + return; + +errout: + log_print("m_priv_setsockopt: read/write error"); + if (optval) + free(optval); + if (sock >= 0) + close(sock); + return; +} + +/* Privileged: called by monitor_loop. */ +static void +m_priv_bind(int s) +{ + int sock; + struct sockaddr *name = 0; + socklen_t namelen; + int32_t v, err; + + sock = mm_receive_fd(s); + if (sock < 0) + goto errout; + + if (m_read_int32(s, &v)) + goto errout; + namelen = (socklen_t) v; + + name = (struct sockaddr *)malloc(namelen); + if (!name) + goto errout; + + if (m_read_raw(s, (char *)name, (size_t)namelen)) + goto errout; + + if (m_priv_check_bind(name, namelen) != 0) { + err = EACCES; + v = -1; + } else { + err = 0; + v = (int32_t)bind(sock, name, namelen); + if (v < 0) { + log_error("m_priv_bind: bind(%d,%p,%d) returned %d", + sock, name, namelen, v); + err = (int32_t)errno; + } + } + + close(sock); + sock = -1; + + if (m_write_int32(s, err)) + goto errout; + + if (m_write_int32(s, v)) + goto errout; + + free(name); + return; + +errout: + log_print("m_priv_bind: read/write error"); + if (name) + free(name); + if (sock >= 0) + close(sock); + return; +} + +/* + * Help functions, used by both privileged and unprivileged code + */ + +/* Write a 32-bit value to a socket. */ +int +m_write_int32(int s, int32_t value) +{ + u_int32_t v; + + memcpy(&v, &value, sizeof v); + return (write(s, &v, sizeof v) == -1); +} + +/* Write a number of bytes of data to a socket. */ +int +m_write_raw(int s, char *data, size_t dlen) +{ + if (m_write_int32(s, (int32_t) dlen)) + return 1; + return (write(s, data, dlen) == -1); +} + +int +m_read_int32(int s, int32_t *value) +{ + u_int32_t v; + + if (read(s, &v, sizeof v) != sizeof v) + return 1; + memcpy(value, &v, sizeof v); + return 0; +} + +int +m_read_raw(int s, char *data, size_t maxlen) +{ + u_int32_t v; + int r; + + if (m_read_int32(s, &v)) + return 1; + if (v > maxlen) + return 1; + r = read(s, data, v); + return (r == -1); +} + +/* Drain all available input on a socket. */ +void +m_flush(int s) +{ + u_int8_t tmp; + int one = 1; + + ioctl(s, FIONBIO, &one);/* Non-blocking */ + while (read(s, &tmp, 1) > 0); + ioctl(s, FIONBIO, 0); /* Blocking */ +} + +/* Check that path/mode is permitted. */ +static int +m_priv_local_sanitize_path(char *path, size_t pmax, int flags) +{ + char *p; + + /* + * We only permit paths starting with + * /etc/isakmpd/ (read only) + * /var/run/ (rw) + */ + + if (strlen(path) < strlen("/var/run/")) + goto bad_path; + + /* Any path containing '..' is invalid. */ + for (p = path; *p && (p - path) < (int)pmax; p++) + if (*p == '.' && *(p + 1) == '.') + goto bad_path; + + /* For any write-mode, only a few paths are permitted. */ + if ((flags & O_ACCMODE) != O_RDONLY) { + if (strncmp("/var/run/", path, strlen("/var/run/")) == 0) + return 0; + goto bad_path; + } + /* Any other path is read-only. */ + if (strncmp(ISAKMPD_ROOT, path, strlen(ISAKMPD_ROOT)) == 0 || + strncmp("/var/run/", path, strlen("/var/run/")) == 0) + return 0; + +bad_path: + log_print("m_priv_local_sanitize_path: illegal path \"%.1023s\", " + "replaced with \"/dev/null\"", path); + strlcpy(path, "/dev/null", pmax); + return 1; +} + +/* Check setsockopt */ +static int +m_priv_check_sockopt(int level, int name) +{ + switch (level) { + /* These are allowed */ + case SOL_SOCKET: + case IPPROTO_IP: + case IPPROTO_IPV6: + break; + + default: + log_print("m_priv_check_sockopt: Illegal level %d", level); + return 1; + } + + switch (name) { + /* These are allowed */ + case SO_REUSEPORT: + case SO_REUSEADDR: + case IP_AUTH_LEVEL: + case IP_ESP_TRANS_LEVEL: + case IP_ESP_NETWORK_LEVEL: + case IP_IPCOMP_LEVEL: + case IPV6_AUTH_LEVEL: + case IPV6_ESP_TRANS_LEVEL: + case IPV6_ESP_NETWORK_LEVEL: + case IPV6_IPCOMP_LEVEL: + break; + + default: + log_print("m_priv_check_sockopt: Illegal option name %d", + name); + return 1; + } + + return 0; +} + +/* Check bind */ +static int +m_priv_check_bind(const struct sockaddr *sa, socklen_t salen) +{ + in_port_t port; + + if (sa == NULL) { + log_print("NULL address"); + return 1; + } + if (sysdep_sa_len((struct sockaddr *)sa) != salen) { + log_print("Length mismatch: %d %d", + (int)sysdep_sa_len((struct sockaddr *)sa), (int)salen); + return 1; + } + switch (sa->sa_family) { + case AF_INET: + if (salen != sizeof(struct sockaddr_in)) { + log_print("Invalid inet address length"); + return 1; + } + port = ((const struct sockaddr_in *)sa)->sin_port; + break; + case AF_INET6: + if (salen != sizeof(struct sockaddr_in6)) { + log_print("Invalid inet6 address length"); + return 1; + } + port = ((const struct sockaddr_in6 *)sa)->sin6_port; + break; + default: + log_print("Unknown address family"); + return 1; + } + + port = ntohs(port); + + if (port != ISAKMP_PORT_DEFAULT && port < 1024) { + log_print("Disallowed port %u", port); + return 1; + } + return 0; +} + +/* Increase state into less permissive mode */ +static void +m_priv_increase_state(int state) +{ + if (state <= cur_state) + log_print("m_priv_increase_state: attempt to decrase state " + "or match current state"); + if (state < STATE_INIT || state > STATE_QUIT) + log_print("m_priv_increase_state: attempt to switch to " + "invalid state"); + cur_state = state; +} + +static void +m_priv_test_state(int state) +{ + if (cur_state != state) + log_print("m_priv_test_state: Illegal state: %d != %d", + (int)cur_state, state); + return; +} diff --git a/keyexchange/isakmpd-20041012/monitor.h b/keyexchange/isakmpd-20041012/monitor.h new file mode 100644 index 0000000..caea4ff --- /dev/null +++ b/keyexchange/isakmpd-20041012/monitor.h @@ -0,0 +1,104 @@ +/* $OpenBSD: monitor.h,v 1.11 2004/06/26 06:07:03 hshoexer Exp $ */ + +/* + * Copyright (c) 2003 Håkan Olsson. 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. + * + * 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. + */ + +#ifndef _MONITOR_H_ +#define _MONITOR_H_ + +#if defined (USE_PRIVSEP) +#include <sys/types.h> +#include <sys/stat.h> + +#include <dirent.h> +#include <stdio.h> + +#define ISAKMPD_PRIVSEP_USER "_isakmpd" + +#define ISAKMP_PORT_DEFAULT 500 + +enum monitor_reqtypes { + MONITOR_UI_INIT, + MONITOR_PFKEY_OPEN, + MONITOR_GET_FD, + MONITOR_GET_SOCKET, + MONITOR_SETSOCKOPT, + MONITOR_BIND, + MONITOR_MKFIFO, + MONITOR_INIT_DONE, + MONITOR_SHUTDOWN +}; + +enum priv_state { + STATE_INIT, /* just started */ + STATE_RUNNING, /* running */ + STATE_QUIT /* shutting down */ +}; + +struct monitor_dirents { + int current; + struct dirent **dirents; +}; + +pid_t monitor_init(int); +void monitor_loop(int); + +int mm_send_fd(int, int); +int mm_receive_fd(int); + +FILE *monitor_fopen(const char *, const char *); +int monitor_open(const char *, int, mode_t); +int monitor_stat(const char *, struct stat *); +int monitor_socket(int, int, int); +int monitor_setsockopt(int, int, int, const void *, socklen_t); +int monitor_bind(int, const struct sockaddr *, socklen_t); +int monitor_mkfifo(const char *, mode_t); +struct monitor_dirents *monitor_opendir(const char *); +struct dirent *monitor_readdir(struct monitor_dirents *); +int monitor_closedir(struct monitor_dirents *); +void monitor_init_done(void); + +void monitor_ui_init(void); +int monitor_pf_key_v2_open(void); +void monitor_exit(int); + +#else /* !USE_PRIVSEP */ + +#define monitor_fopen fopen +#define monitor_open open +#define monitor_stat stat +#define monitor_socket socket +#define monitor_setsockopt setsockopt +#define monitor_bind bind +#define monitor_mkfifo mkfifo +#define monitor_opendir opendir +#define monitor_readdir readdir +#define monitor_closedir closedir + +#define monitor_ui_init ui_init +#define monitor_exit exit +#define monitor_pf_key_v2_open pf_key_v2_open + +#endif /* USE_PRIVSEP */ +#endif /* _MONITOR_H_ */ diff --git a/keyexchange/isakmpd-20041012/monitor_fdpass.c b/keyexchange/isakmpd-20041012/monitor_fdpass.c new file mode 100644 index 0000000..0159653 --- /dev/null +++ b/keyexchange/isakmpd-20041012/monitor_fdpass.c @@ -0,0 +1,112 @@ +/* $OpenBSD: monitor_fdpass.c,v 1.11 2004/10/01 04:08:45 jsg Exp $ */ + +/* + * Copyright 2001 Niels Provos <provos@citi.umich.edu> + * 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. + * + * 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. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/uio.h> + +#include <errno.h> +#include <string.h> + +#include "log.h" +#include "monitor.h" + +int +mm_send_fd(int socket, int fd) +{ + struct msghdr msg; + char tmp[CMSG_SPACE(sizeof(int))], ch = '\0'; + struct cmsghdr *cmsg; + struct iovec vec; + ssize_t n; + + memset(&msg, 0, sizeof msg); + msg.msg_control = (caddr_t) tmp; + msg.msg_controllen = CMSG_LEN(sizeof(int)); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + *(int *)CMSG_DATA(cmsg) = fd; + + vec.iov_base = &ch; + vec.iov_len = 1; + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + + if ((n = sendmsg(socket, &msg, 0)) == -1) { + log_error("mm_send_fd: sendmsg(%d)", fd); + return -1; + } + if (n != 1) { + log_error("mm_send_fd: sendmsg: expected sent 1 got %ld", + (long)n); + return -1; + } + return 0; +} + +int +mm_receive_fd(int socket) +{ + struct msghdr msg; + char tmp[CMSG_SPACE(sizeof(int))], ch; + struct cmsghdr *cmsg; + struct iovec vec; + ssize_t n; + int fd; + + memset(&msg, 0, sizeof msg); + vec.iov_base = &ch; + vec.iov_len = 1; + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + msg.msg_control = tmp; + msg.msg_controllen = sizeof tmp; + + if ((n = recvmsg(socket, &msg, 0)) == -1) { + log_error("mm_receive_fd: recvmsg"); + return -1; + } + if (n != 1) { + log_error("mm_receive_fd: recvmsg: expected received 1 got %ld", + (long)n); + return -1; + } + cmsg = CMSG_FIRSTHDR(&msg); + if (cmsg == NULL) { + log_error("mm_receive_fd: no message header"); + return -1; + } + if (cmsg->cmsg_type != SCM_RIGHTS) { + log_error("mm_receive_fd: expected type %d got %d", SCM_RIGHTS, + cmsg->cmsg_type); + return -1; + } + fd = (*(int *)CMSG_DATA(cmsg)); + return fd; +} diff --git a/keyexchange/isakmpd-20041012/nat_traversal.c b/keyexchange/isakmpd-20041012/nat_traversal.c new file mode 100644 index 0000000..86d2d57 --- /dev/null +++ b/keyexchange/isakmpd-20041012/nat_traversal.c @@ -0,0 +1,439 @@ +/* $OpenBSD: nat_traversal.c,v 1.17 2006/06/14 14:03:33 hshoexer Exp $ */ + +/* + * Copyright (c) 2004 Håkan Olsson. 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. + * + * 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. + */ + +#include <sys/types.h> +#include <stdlib.h> +#include <string.h> + +#include "sysdep.h" + +#include "conf.h" +#include "exchange.h" +#include "hash.h" +#include "ipsec.h" +#include "isakmp_fld.h" +#include "isakmp_num.h" +#include "ipsec_num.h" +#include "hash.h" +#include "log.h" +#include "message.h" +#include "nat_traversal.h" +#include "prf.h" +#include "sa.h" +#include "timer.h" +#include "transport.h" +#include "util.h" +#include "virtual.h" + +int disable_nat_t = 0; + +/* + * NAT-T capability of the other peer is determined by a particular vendor + * ID sent in the first message. This vendor ID string is supposed to be a + * MD5 hash of "RFC 3947". + * + * These seem to be the "well" known variants of this string in use by + * products today. + */ + +static struct nat_t_cap isakmp_nat_t_cap[] = { + { VID_DRAFT_V2_N, EXCHANGE_FLAG_NAT_T_DRAFT, + "draft-ietf-ipsec-nat-t-ike-02\n", NULL, 0 }, + { VID_DRAFT_V3, EXCHANGE_FLAG_NAT_T_DRAFT, + "draft-ietf-ipsec-nat-t-ike-03", NULL, 0 }, + { VID_RFC3947, EXCHANGE_FLAG_NAT_T_RFC, + "RFC 3947", NULL, 0 }, +}; + +#define NUMNATTCAP (sizeof isakmp_nat_t_cap / sizeof isakmp_nat_t_cap[0]) + +/* In seconds. Recommended in draft-ietf-ipsec-udp-encaps-09. */ +#define NAT_T_KEEPALIVE_INTERVAL 20 + +static int nat_t_setup_hashes(void); +static int nat_t_add_vendor_payload(struct message *, struct nat_t_cap *); +static int nat_t_add_nat_d(struct message *, struct sockaddr *); +static int nat_t_match_nat_d_payload(struct message *, struct sockaddr *); + +void +nat_t_init(void) +{ + nat_t_setup_hashes(); +} + +/* Generate the NAT-T capability marker hashes. Executed only once. */ +static int +nat_t_setup_hashes(void) +{ + struct hash *hash; + int n = NUMNATTCAP; + int i; + + /* The draft says to use MD5. */ + hash = hash_get(HASH_MD5); + if (!hash) { + /* Should never happen. */ + log_print("nat_t_setup_hashes: " + "could not find MD5 hash structure!"); + return -1; + } + + /* Populate isakmp_nat_t_cap with hashes. */ + for (i = 0; i < n; i++) { + isakmp_nat_t_cap[i].hashsize = hash->hashsize; + isakmp_nat_t_cap[i].hash = (char *)malloc(hash->hashsize); + if (!isakmp_nat_t_cap[i].hash) { + log_error("nat_t_setup_hashes: malloc (%lu) failed", + (unsigned long)hash->hashsize); + goto errout; + } + + hash->Init(hash->ctx); + hash->Update(hash->ctx, + (unsigned char *)isakmp_nat_t_cap[i].text, + strlen(isakmp_nat_t_cap[i].text)); + hash->Final(isakmp_nat_t_cap[i].hash, hash->ctx); + + LOG_DBG((LOG_EXCHANGE, 50, "nat_t_setup_hashes: " + "MD5(\"%s\") (%lu bytes)", isakmp_nat_t_cap[i].text, + (unsigned long)hash->hashsize)); + LOG_DBG_BUF((LOG_EXCHANGE, 50, "nat_t_setup_hashes", + isakmp_nat_t_cap[i].hash, hash->hashsize)); + } + + return 0; + +errout: + for (i = 0; i < n; i++) + if (isakmp_nat_t_cap[i].hash) + free(isakmp_nat_t_cap[i].hash); + return -1; +} + +/* Add one NAT-T VENDOR payload. */ +static int +nat_t_add_vendor_payload(struct message *msg, struct nat_t_cap *cap) +{ + size_t buflen = cap->hashsize + ISAKMP_GEN_SZ; + u_int8_t *buf; + + if (disable_nat_t) + return 0; + + buf = malloc(buflen); + if (!buf) { + log_error("nat_t_add_vendor_payload: malloc (%lu) failed", + (unsigned long)buflen); + return -1; + } + + SET_ISAKMP_GEN_LENGTH(buf, buflen); + memcpy(buf + ISAKMP_VENDOR_ID_OFF, cap->hash, cap->hashsize); + if (message_add_payload(msg, ISAKMP_PAYLOAD_VENDOR, buf, buflen, 1)) { + free(buf); + return -1; + } + return 0; +} + +/* Add the NAT-T capability markers (VENDOR payloads). */ +int +nat_t_add_vendor_payloads(struct message *msg) +{ + int i; + + if (disable_nat_t) + return 0; + + for (i = 0; i < NUMNATTCAP; i++) + if (nat_t_add_vendor_payload(msg, &isakmp_nat_t_cap[i])) + return -1; + return 0; +} + +/* + * Check an incoming message for NAT-T capability markers. + */ +void +nat_t_check_vendor_payload(struct message *msg, struct payload *p) +{ + u_int8_t *pbuf = p->p; + size_t vlen; + int i; + + if (disable_nat_t) + return; + + vlen = GET_ISAKMP_GEN_LENGTH(pbuf) - ISAKMP_GEN_SZ; + + for (i = 0; i < NUMNATTCAP; i++) { + if (vlen != isakmp_nat_t_cap[i].hashsize) { + LOG_DBG((LOG_EXCHANGE, 50, "nat_t_check_vendor_payload: " + "bad size %lu != %lu", (unsigned long)vlen, + (unsigned long)isakmp_nat_t_cap[i].hashsize)); + continue; + } + if (memcmp(isakmp_nat_t_cap[i].hash, pbuf + ISAKMP_GEN_SZ, + vlen) == 0) { + /* This peer is NAT-T capable. */ + msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_CAP_PEER; + msg->exchange->flags |= isakmp_nat_t_cap[i].flags; + LOG_DBG((LOG_EXCHANGE, 10, + "nat_t_check_vendor_payload: " + "NAT-T capable peer detected")); + p->flags |= PL_MARK; + } + } + + return; +} + +/* Generate the NAT-D payload hash : HASH(CKY-I | CKY-R | IP | Port). */ +static u_int8_t * +nat_t_generate_nat_d_hash(struct message *msg, struct sockaddr *sa, + size_t *hashlen) +{ + struct ipsec_exch *ie = (struct ipsec_exch *)msg->exchange->data; + struct hash *hash; + u_int8_t *res; + in_port_t port; + + hash = hash_get(ie->hash->type); + if (hash == NULL) { + log_print ("nat_t_generate_nat_d_hash: no hash"); + return NULL; + } + + *hashlen = hash->hashsize; + + res = (u_int8_t *)malloc((unsigned long)*hashlen); + if (!res) { + log_print("nat_t_generate_nat_d_hash: malloc (%lu) failed", + (unsigned long)*hashlen); + *hashlen = 0; + return NULL; + } + + port = sockaddr_port(sa); + bzero(res, *hashlen); + + hash->Init(hash->ctx); + hash->Update(hash->ctx, msg->exchange->cookies, + sizeof msg->exchange->cookies); + hash->Update(hash->ctx, sockaddr_addrdata(sa), sockaddr_addrlen(sa)); + hash->Update(hash->ctx, (unsigned char *)&port, sizeof port); + hash->Final(res, hash->ctx); + return res; +} + +/* Add a NAT-D payload to our message. */ +static int +nat_t_add_nat_d(struct message *msg, struct sockaddr *sa) +{ + int ret; + u_int8_t *hbuf, *buf; + size_t hbuflen, buflen; + + hbuf = nat_t_generate_nat_d_hash(msg, sa, &hbuflen); + if (!hbuf) { + log_print("nat_t_add_nat_d: NAT-D hash gen failed"); + return -1; + } + + buflen = ISAKMP_NAT_D_DATA_OFF + hbuflen; + buf = malloc(buflen); + if (!buf) { + log_error("nat_t_add_nat_d: malloc (%lu) failed", + (unsigned long)buflen); + free(hbuf); + return -1; + } + + SET_ISAKMP_GEN_LENGTH(buf, buflen); + memcpy(buf + ISAKMP_NAT_D_DATA_OFF, hbuf, hbuflen); + free(hbuf); + + if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_RFC) + ret = message_add_payload(msg, ISAKMP_PAYLOAD_NAT_D, buf, + buflen, 1); + else if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_DRAFT) + ret = message_add_payload(msg, ISAKMP_PAYLOAD_NAT_D_DRAFT, + buf, buflen, 1); + else + ret = -1; + + if (ret) { + free(buf); + return -1; + } + return 0; +} + +/* We add two NAT-D payloads, one each for src and dst. */ +int +nat_t_exchange_add_nat_d(struct message *msg) +{ + struct sockaddr *sa; + + /* Remote address first. */ + msg->transport->vtbl->get_dst(msg->transport, &sa); + if (nat_t_add_nat_d(msg, sa)) + return -1; + + msg->transport->vtbl->get_src(msg->transport, &sa); + if (nat_t_add_nat_d(msg, sa)) + return -1; + return 0; +} + +/* Generate and match a NAT-D hash against the NAT-D payload (pl.) data. */ +static int +nat_t_match_nat_d_payload(struct message *msg, struct sockaddr *sa) +{ + struct payload *p; + u_int8_t *hbuf; + size_t hbuflen; + int found = 0; + + /* + * If there are no NAT-D payloads in the message, return "found" + * as this will avoid NAT-T (see nat_t_exchange_check_nat_d()). + */ + if ((p = payload_first(msg, ISAKMP_PAYLOAD_NAT_D_DRAFT)) == NULL && + (p = payload_first(msg, ISAKMP_PAYLOAD_NAT_D)) == NULL) + return 1; + + hbuf = nat_t_generate_nat_d_hash(msg, sa, &hbuflen); + if (!hbuf) + return 0; + + while (p) { + if (GET_ISAKMP_GEN_LENGTH (p->p) != + hbuflen + ISAKMP_NAT_D_DATA_OFF) + continue; + + if (memcmp(p->p + ISAKMP_NAT_D_DATA_OFF, hbuf, hbuflen) == 0) { + found++; + break; + } + p = TAILQ_NEXT(p, link); + } + free(hbuf); + return found; +} + +/* + * Check if we need to activate NAT-T, and if we need to send keepalive + * messages to the other side, i.e if we are a nat:ed peer. + */ +int +nat_t_exchange_check_nat_d(struct message *msg) +{ + struct sockaddr *sa; + int outgoing_path_is_clear, incoming_path_is_clear; + + /* Assume trouble, i.e NAT-boxes in our path. */ + outgoing_path_is_clear = incoming_path_is_clear = 0; + + msg->transport->vtbl->get_src(msg->transport, &sa); + if (nat_t_match_nat_d_payload(msg, sa)) + outgoing_path_is_clear = 1; + + msg->transport->vtbl->get_dst(msg->transport, &sa); + if (nat_t_match_nat_d_payload(msg, sa)) + incoming_path_is_clear = 1; + + if (outgoing_path_is_clear && incoming_path_is_clear) { + LOG_DBG((LOG_EXCHANGE, 40, "nat_t_exchange_check_nat_d: " + "no NAT")); + return 0; /* No NAT-T required. */ + } + + /* NAT-T handling required. */ + msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_ENABLE; + + if (!outgoing_path_is_clear) { + msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_KEEPALIVE; + LOG_DBG((LOG_EXCHANGE, 10, "nat_t_exchange_check_nat_d: " + "NAT detected, we're behind it")); + } else + LOG_DBG ((LOG_EXCHANGE, 10, + "nat_t_exchange_check_nat_d: NAT detected")); + return 1; +} + +static void +nat_t_send_keepalive(void *v_arg) +{ + struct sa *sa = (struct sa *)v_arg; + struct transport *t; + struct timeval now; + int interval; + + /* Send the keepalive message. */ + t = ((struct virtual_transport *)sa->transport)->encap; + t->vtbl->send_message(NULL, t); + + /* Set new timer. */ + interval = conf_get_num("General", "NAT-T-Keepalive", 0); + if (interval < 1) + interval = NAT_T_KEEPALIVE_INTERVAL; + gettimeofday(&now, 0); + now.tv_sec += interval; + + sa->nat_t_keepalive = timer_add_event("nat_t_send_keepalive", + nat_t_send_keepalive, v_arg, &now); + if (!sa->nat_t_keepalive) + log_print("nat_t_send_keepalive: " + "timer_add_event() failed, will send no more keepalives"); +} + +void +nat_t_setup_keepalive(struct sa *sa) +{ + struct sockaddr *src; + struct timeval now; + + if (sa->initiator) + sa->transport->vtbl->get_src(sa->transport, &src); + else + sa->transport->vtbl->get_dst(sa->transport, &src); + + if (!virtual_listen_lookup(src)) + return; + + gettimeofday(&now, 0); + now.tv_sec += NAT_T_KEEPALIVE_INTERVAL; + + sa->nat_t_keepalive = timer_add_event("nat_t_send_keepalive", + nat_t_send_keepalive, sa, &now); + if (!sa->nat_t_keepalive) + log_print("nat_t_setup_keepalive: " + "timer_add_event() failed, will not send keepalives"); + + LOG_DBG((LOG_TRANSPORT, 50, "nat_t_setup_keepalive: " + "added event for phase 1 SA %p", sa)); +} diff --git a/keyexchange/isakmpd-20041012/nat_traversal.h b/keyexchange/isakmpd-20041012/nat_traversal.h new file mode 100644 index 0000000..843d43b --- /dev/null +++ b/keyexchange/isakmpd-20041012/nat_traversal.h @@ -0,0 +1,55 @@ +/* $OpenBSD: nat_traversal.h,v 1.4 2005/07/25 15:03:47 hshoexer Exp $ */ + +/* + * Copyright (c) 2004 Håkan Olsson. 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. + * + * 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. + */ + +#ifndef _NAT_TRAVERSAL_H_ +#define _NAT_TRAVERSAL_H_ + +#define VID_DRAFT_V2 0 +#define VID_DRAFT_V2_N 1 +#define VID_DRAFT_V3 2 +#define VID_RFC3947 3 + +struct nat_t_cap { + int id; + u_int32_t flags; + const char *text; + char *hash; + size_t hashsize; +}; + +/* + * Set if -T is given on the command line to disable NAT-T support. + */ +extern int disable_nat_t; + +void nat_t_init(void); +int nat_t_add_vendor_payloads(struct message *); +void nat_t_check_vendor_payload(struct message *, struct payload *); +int nat_t_exchange_add_nat_d(struct message *); +int nat_t_exchange_check_nat_d(struct message *); +void nat_t_setup_keepalive(struct sa *); + +#endif /* _NAT_TRAVERSAL_H_ */ diff --git a/keyexchange/isakmpd-20041012/pf_key_v2.c b/keyexchange/isakmpd-20041012/pf_key_v2.c new file mode 100644 index 0000000..d8cbc35 --- /dev/null +++ b/keyexchange/isakmpd-20041012/pf_key_v2.c @@ -0,0 +1,4442 @@ +/* $OpenBSD: pf_key_v2.c,v 1.150 2004/09/17 13:53:08 ho Exp $ */ +/* $EOM: pf_key_v2.c,v 1.79 2000/12/12 00:33:19 niklas Exp $ */ + +/* + * Copyright (c) 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 1999, 2000, 2001 Angelos D. Keromytis. All rights reserved. + * Copyright (c) 2001 Håkan Olsson. 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. + * + * 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/ioctl.h> +#include <sys/queue.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/uio.h> + +#include "sysdep.h" + +#if !defined (LINUX_IPSEC) +#include <net/pfkeyv2.h> +#endif +#include <netinet/in.h> +#ifdef SADB_X_EXT_FLOW_TYPE +#include <sys/mbuf.h> +#include <netinet/ip_ipsp.h> +#endif +#include <arpa/inet.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <pwd.h> +#include <errno.h> +#include <bitstring.h> + +#include "cert.h" +#include "conf.h" +#include "exchange.h" +#include "ipsec.h" +#include "ipsec_num.h" +#include "key.h" +#include "log.h" +#include "pf_key_v2.h" +#include "sa.h" +#include "timer.h" +#include "transport.h" +#include "util.h" + +#if defined (USE_KEYNOTE) +#include "policy.h" +#endif + +#if defined (USE_NAT_TRAVERSAL) +#include "udp_encap.h" +#endif + +#define IN6_IS_ADDR_FULL(a) \ + ((*(u_int32_t *)(void *)(&(a)->s6_addr[0]) == 0xffff) && \ + (*(u_int32_t *)(void *)(&(a)->s6_addr[4]) == 0xffff) && \ + (*(u_int32_t *)(void *)(&(a)->s6_addr[8]) == 0xffff) && \ + (*(u_int32_t *)(void *)(&(a)->s6_addr[12]) == 0xffff)) + +#define ADDRESS_MAX sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255" + +/* + * PF_KEY v2 always work with 64-bit entities and aligns on 64-bit boundaries. + */ +#define PF_KEY_V2_CHUNK 8 +#define PF_KEY_V2_ROUND(x) \ + (((x) + PF_KEY_V2_CHUNK - 1) & ~(PF_KEY_V2_CHUNK - 1)) + +/* How many microseconds we will wait for a reply from the PF_KEY socket. */ +#define PF_KEY_REPLY_TIMEOUT 1000 + +struct pf_key_v2_node { + TAILQ_ENTRY(pf_key_v2_node) link; + void *seg; + size_t sz; + int cnt; + u_int16_t type; + u_int8_t flags; +}; + +TAILQ_HEAD(pf_key_v2_msg, pf_key_v2_node); + +#define PF_KEY_V2_NODE_MALLOCED 1 +#define PF_KEY_V2_NODE_MARK 2 + +/* Used to derive "unique" connection identifiers. */ +int connection_seq = 0; + +#ifdef KAME +/* + * KAME requires the sadb_msg_seq of an UPDATE be the same of that of the + * GETSPI creating the larval SA. + */ +struct pf_key_v2_sa_seq { + TAILQ_ENTRY(pf_key_v2_sa_seq) link; + u_int8_t *spi; + size_t sz; + u_int8_t proto; + struct sockaddr *dst; + int dstlen; + u_int32_t seq; +}; + +TAILQ_HEAD(, pf_key_v2_sa_seq) pf_key_v2_sa_seq_map; +#endif + +#ifndef KAME +static u_int8_t *pf_key_v2_convert_id(u_int8_t *, int, size_t *, int *); +#endif +static struct pf_key_v2_msg *pf_key_v2_call(struct pf_key_v2_msg *); +static struct pf_key_v2_node *pf_key_v2_find_ext(struct pf_key_v2_msg *, + u_int16_t); +static void pf_key_v2_notify(struct pf_key_v2_msg *); +static struct pf_key_v2_msg *pf_key_v2_read(u_int32_t); +static u_int32_t pf_key_v2_seq(void); +static u_int32_t pf_key_v2_write(struct pf_key_v2_msg *); +static int pf_key_v2_remove_conf(char *); +static int pf_key_v2_conf_refhandle(int, char *); + +#ifdef SADB_X_ASKPOLICY +static int pf_key_v2_conf_refinc(int, char *); +#endif + +/* The socket to use for PF_KEY interactions. */ +int pf_key_v2_socket; + +#ifdef KAME +static int +pf_key_v2_register_sa_seq(u_int8_t *spi, size_t sz, u_int8_t proto, + struct sockaddr *dst, int dstlen, u_int32_t seq) +{ + struct pf_key_v2_sa_seq *node = 0; + + node = malloc(sizeof *node); + if (!node) + goto cleanup; + memset(node, '0', sizeof *node); + node->spi = malloc(sz); + if (!node->spi) + goto cleanup; + node->dst = malloc(sysdep_sa_len(dst)); + if (!node->dst) + goto cleanup; + memcpy(node->dst, dst, sysdep_sa_len(dst)); + node->dstlen = sysdep_sa_len(dst); + memcpy(node->spi, spi, sz); + node->sz = sz; + node->proto = proto; + node->seq = seq; + TAILQ_INSERT_TAIL(&pf_key_v2_sa_seq_map, node, link); + return 1; + +cleanup: + if (node->dst) + free(node->dst); + if (node) + free(node); + return 0; +} + +static u_int32_t +pf_key_v2_seq_by_sa(u_int8_t *spi, size_t sz, u_int8_t proto, + struct sockaddr *dst, int dstlen) +{ + struct pf_key_v2_sa_seq *node; + + for (node = TAILQ_FIRST(&pf_key_v2_sa_seq_map); node; + node = TAILQ_NEXT(node, link)) + if (node->proto == proto && + node->sz == sz && memcmp(node->spi, spi, sz) == 0 && + node->dstlen == sysdep_sa_len(dst) && + memcmp(node->dst, dst, sysdep_sa_len(dst)) == 0) + return node->seq; + return 0; +} +#endif + +static struct pf_key_v2_msg * +pf_key_v2_msg_new(struct sadb_msg *msg, int flags) +{ + struct pf_key_v2_node *node = 0; + struct pf_key_v2_msg *ret; + + node = malloc(sizeof *node); + if (!node) + goto cleanup; + ret = malloc(sizeof *ret); + if (!ret) + goto cleanup; + TAILQ_INIT(ret); + node->seg = msg; + node->sz = sizeof *msg; + node->type = 0; + node->cnt = 1; + node->flags = flags; + TAILQ_INSERT_HEAD(ret, node, link); + return ret; + +cleanup: + if (node) + free(node); + return 0; +} + +/* Add a SZ sized segment SEG to the PF_KEY message MSG. */ +static int +pf_key_v2_msg_add(struct pf_key_v2_msg *msg, struct sadb_ext *ext, int flags) +{ + struct pf_key_v2_node *node; + + node = malloc(sizeof *node); + if (!node) + return -1; + node->seg = ext; + node->sz = ext->sadb_ext_len * PF_KEY_V2_CHUNK; + node->type = ext->sadb_ext_type; + node->flags = flags; + TAILQ_FIRST(msg)->cnt++; + TAILQ_INSERT_TAIL(msg, node, link); + return 0; +} + +/* Deallocate the PF_KEY message MSG. */ +static void +pf_key_v2_msg_free(struct pf_key_v2_msg *msg) +{ + struct pf_key_v2_node *np; + + np = TAILQ_FIRST(msg); + while (np) { + TAILQ_REMOVE(msg, np, link); + if (np->flags & PF_KEY_V2_NODE_MALLOCED) + free(np->seg); + free(np); + np = TAILQ_FIRST(msg); + } + free(msg); +} + +/* Just return a new sequence number. */ +static u_int32_t +pf_key_v2_seq(void) +{ + static u_int32_t seq = 0; + + return ++seq; +} + +/* + * Read a PF_KEY packet with SEQ as the sequence number, looping if necessary. + * If SEQ is zero just read the first message we see, otherwise we queue + * messages up until both the PID and the sequence number match. + */ +static struct pf_key_v2_msg * +pf_key_v2_read(u_int32_t seq) +{ + ssize_t n; + u_int8_t *buf = 0; + struct pf_key_v2_msg *ret = 0; + struct sadb_msg *msg; + struct sadb_msg hdr; + struct sadb_ext *ext; + struct timeval tv; + fd_set *fds; + + while (1) { + /* + * If this is a read of a reply we should actually expect the + * reply to get lost as PF_KEY is an unreliable service per + * the specs. Currently we do this by setting a short timeout, + * and if it is not readable in that time, we fail the read. + */ + if (seq) { + fds = calloc(howmany(pf_key_v2_socket + 1, NFDBITS), + sizeof(fd_mask)); + if (!fds) { + log_error("pf_key_v2_read: " + "calloc (%lu, %lu) failed", + (unsigned long) howmany(pf_key_v2_socket + 1, + NFDBITS), + (unsigned long) sizeof(fd_mask)); + goto cleanup; + } + FD_SET(pf_key_v2_socket, fds); + tv.tv_sec = 0; + tv.tv_usec = PF_KEY_REPLY_TIMEOUT; + n = select(pf_key_v2_socket + 1, fds, 0, 0, &tv); + free(fds); + if (n == -1) { + log_error("pf_key_v2_read: " + "select (%d, fds, 0, 0, &tv) failed", + pf_key_v2_socket + 1); + goto cleanup; + } + if (!n) { + log_print("pf_key_v2_read: " + "no reply from PF_KEY"); + goto cleanup; + } + } + n = recv(pf_key_v2_socket, &hdr, sizeof hdr, MSG_PEEK); + if (n == -1) { + log_error("pf_key_v2_read: recv (%d, ...) failed", + pf_key_v2_socket); + goto cleanup; + } + if (n != sizeof hdr) { + log_error("pf_key_v2_read: recv (%d, ...) " + "returned short packet (%lu bytes)", + pf_key_v2_socket, (unsigned long) n); + goto cleanup; + } + n = hdr.sadb_msg_len * PF_KEY_V2_CHUNK; + buf = malloc(n); + if (!buf) { + log_error("pf_key_v2_read: malloc (%lu) failed", + (unsigned long) n); + goto cleanup; + } + n = read(pf_key_v2_socket, buf, n); + if (n == -1) { + log_error("pf_key_v2_read: read (%d, ...) failed", + pf_key_v2_socket); + goto cleanup; + } + if (n != hdr.sadb_msg_len * PF_KEY_V2_CHUNK) { + log_print("pf_key_v2_read: read (%d, ...) " + "returned short packet (%lu bytes)", + pf_key_v2_socket, (unsigned long) n); + goto cleanup; + } + LOG_DBG_BUF((LOG_SYSDEP, 80, "pf_key_v2_read: msg", buf, n)); + + /* We drop all messages that is not what we expect. */ + msg = (struct sadb_msg *) buf; + if (msg->sadb_msg_version != PF_KEY_V2 || + (msg->sadb_msg_pid != 0 && + msg->sadb_msg_pid != (u_int32_t) getpid())) { + if (seq) { + free(buf); + buf = 0; + continue; + } else { + LOG_DBG((LOG_SYSDEP, 90, "pf_key_v2_read:" + "bad version (%d) or PID (%d, mine is " + "%ld), ignored", msg->sadb_msg_version, + msg->sadb_msg_pid, (long) getpid())); + goto cleanup; + } + } + /* Parse the message. */ + ret = pf_key_v2_msg_new(msg, PF_KEY_V2_NODE_MALLOCED); + if (!ret) + goto cleanup; + buf = 0; + for (ext = (struct sadb_ext *) (msg + 1); + (u_int8_t *) ext - (u_int8_t *) msg < + msg->sadb_msg_len * PF_KEY_V2_CHUNK; + ext = (struct sadb_ext *) ((u_int8_t *) ext + + ext->sadb_ext_len * PF_KEY_V2_CHUNK)) + pf_key_v2_msg_add(ret, ext, 0); + + /* + * If the message is not the one we are waiting for, queue it + * up. + */ + if (seq && (msg->sadb_msg_pid != (u_int32_t) getpid() || + msg->sadb_msg_seq != seq)) { + gettimeofday(&tv, 0); + timer_add_event("pf_key_v2_notify", + (void (*) (void *)) pf_key_v2_notify, ret, &tv); + ret = 0; + continue; + } + return ret; + } + +cleanup: + if (buf) + free(buf); + if (ret) + pf_key_v2_msg_free(ret); + return 0; +} + +/* Write the message in PMSG to the PF_KEY socket. */ +u_int32_t +pf_key_v2_write(struct pf_key_v2_msg *pmsg) +{ + struct iovec *iov = 0; + ssize_t n; + size_t len; + int i, cnt = TAILQ_FIRST(pmsg)->cnt; + char header[80]; + struct sadb_msg *msg = TAILQ_FIRST(pmsg)->seg; + struct pf_key_v2_node *np = TAILQ_FIRST(pmsg); + + iov = (struct iovec *) malloc(cnt * sizeof *iov); + if (!iov) { + log_error("pf_key_v2_write: malloc (%lu) failed", + cnt * (unsigned long) sizeof *iov); + return 0; + } + msg->sadb_msg_version = PF_KEY_V2; + msg->sadb_msg_errno = 0; + msg->sadb_msg_reserved = 0; + msg->sadb_msg_pid = getpid(); + if (!msg->sadb_msg_seq) + msg->sadb_msg_seq = pf_key_v2_seq(); + + /* Compute the iovec segments as well as the message length. */ + len = 0; + for (i = 0; i < cnt; i++) { + iov[i].iov_base = np->seg; + len += iov[i].iov_len = np->sz; + + /* + * XXX One can envision setting specific extension fields, like + * *_reserved ones here. For now we require them to be set by the + * caller. + */ + + np = TAILQ_NEXT(np, link); + } + msg->sadb_msg_len = len / PF_KEY_V2_CHUNK; + + for (i = 0; i < cnt; i++) { + snprintf(header, sizeof header, "pf_key_v2_write: iov[%d]", i); + LOG_DBG_BUF((LOG_SYSDEP, 80, header, + (u_int8_t *) iov[i].iov_base, iov[i].iov_len)); + } + + n = writev(pf_key_v2_socket, iov, cnt); + if (n == -1) { + log_error("pf_key_v2_write: writev (%d, %p, %d) failed", + pf_key_v2_socket, iov, cnt); + goto cleanup; + } + if ((size_t) n != len) { + log_error("pf_key_v2_write: " + "writev (%d, ...) returned prematurely (%lu)", + pf_key_v2_socket, (unsigned long) n); + goto cleanup; + } + free(iov); + return msg->sadb_msg_seq; + +cleanup: + if (iov) + free(iov); + return 0; +} + +/* + * Do a PF_KEY "call", i.e. write a message MSG, read the reply and return + * it to the caller. + */ +static struct pf_key_v2_msg * +pf_key_v2_call(struct pf_key_v2_msg *msg) +{ + u_int32_t seq; + + seq = pf_key_v2_write(msg); + if (!seq) + return 0; + return pf_key_v2_read(seq); +} + +/* Find the TYPE extension in MSG. Return zero if none found. */ +static struct pf_key_v2_node * +pf_key_v2_find_ext(struct pf_key_v2_msg *msg, u_int16_t type) +{ + struct pf_key_v2_node *ext; + + for (ext = TAILQ_NEXT(TAILQ_FIRST(msg), link); ext; + ext = TAILQ_NEXT(ext, link)) + if (ext->type == type) + return ext; + return 0; +} + +/* + * Open the PF_KEYv2 sockets and return the descriptor used for notifies. + * Return -1 for failure and -2 if no notifies will show up. + */ +int +pf_key_v2_open(void) +{ + int fd = -1, err; + struct sadb_msg msg; + struct pf_key_v2_msg *regmsg = 0, *ret = 0; + + /* Open the socket we use to speak to IPsec. */ + pf_key_v2_socket = -1; + fd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2); + if (fd == -1) { + log_error("pf_key_v2_open: " + "socket (PF_KEY, SOCK_RAW, PF_KEY_V2) failed"); + goto cleanup; + } + pf_key_v2_socket = fd; + + /* Register it to get ESP and AH acquires from the kernel. */ + msg.sadb_msg_seq = 0; + msg.sadb_msg_type = SADB_REGISTER; + msg.sadb_msg_satype = SADB_SATYPE_ESP; + regmsg = pf_key_v2_msg_new(&msg, 0); + if (!regmsg) + goto cleanup; + ret = pf_key_v2_call(regmsg); + pf_key_v2_msg_free(regmsg); + if (!ret) + goto cleanup; + err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; + if (err) { + log_print("pf_key_v2_open: REGISTER: %s", strerror(err)); + goto cleanup; + } + /* XXX Register the accepted transforms. */ + + pf_key_v2_msg_free(ret); + ret = 0; + + msg.sadb_msg_seq = 0; + msg.sadb_msg_type = SADB_REGISTER; + msg.sadb_msg_satype = SADB_SATYPE_AH; + regmsg = pf_key_v2_msg_new(&msg, 0); + if (!regmsg) + goto cleanup; + ret = pf_key_v2_call(regmsg); + pf_key_v2_msg_free(regmsg); + if (!ret) + goto cleanup; + err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; + if (err) { + log_print("pf_key_v2_open: REGISTER: %s", strerror(err)); + goto cleanup; + } + /* XXX Register the accepted transforms. */ + + pf_key_v2_msg_free(ret); + ret = 0; + +#ifdef SADB_X_SATYPE_IPCOMP + msg.sadb_msg_seq = 0; + msg.sadb_msg_type = SADB_REGISTER; + msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP; + regmsg = pf_key_v2_msg_new(&msg, 0); + if (!regmsg) + goto cleanup; + ret = pf_key_v2_call(regmsg); + pf_key_v2_msg_free(regmsg); + if (!ret) + goto cleanup; + err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; + if (err) { + log_print("pf_key_v2_open: REGISTER: %s", strerror(err)); + goto cleanup; + } + /* XXX Register the accepted transforms. */ + + pf_key_v2_msg_free(ret); +#endif /* SADB_X_SATYPE_IPCOMP */ + +#ifdef KAME + TAILQ_INIT(&pf_key_v2_sa_seq_map); +#endif + + return fd; + +cleanup: + if (pf_key_v2_socket != -1) { + close(pf_key_v2_socket); + pf_key_v2_socket = -1; + } + if (ret) + pf_key_v2_msg_free(ret); + return -1; +} + +/* + * Generate a SPI for protocol PROTO and the source/destination pair given by + * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ. + */ +u_int8_t * +pf_key_v2_get_spi(size_t *sz, u_int8_t proto, struct sockaddr *src, + struct sockaddr *dst, u_int32_t seq) +{ + struct sadb_msg msg; + struct sadb_sa *sa; + struct sadb_address *addr = 0; + struct sadb_spirange spirange; + struct pf_key_v2_msg *getspi = 0, *ret = 0; + struct pf_key_v2_node *ext; + u_int8_t *spi = 0; + int len, err; +#ifdef KAME + struct sadb_x_sa2 ssa2; +#endif + + msg.sadb_msg_type = SADB_GETSPI; + switch (proto) { + case IPSEC_PROTO_IPSEC_ESP: + msg.sadb_msg_satype = SADB_SATYPE_ESP; + break; + case IPSEC_PROTO_IPSEC_AH: + msg.sadb_msg_satype = SADB_SATYPE_AH; + break; +#ifdef SADB_X_SATYPE_IPCOMP + case IPSEC_PROTO_IPCOMP: + msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP; + break; +#endif + default: + log_print("pf_key_v2_get_spi: invalid proto %d", proto); + goto cleanup; + } + + /* Set the sequence number from the ACQUIRE message. */ + msg.sadb_msg_seq = seq; + getspi = pf_key_v2_msg_new(&msg, 0); + if (!getspi) + goto cleanup; + +#ifdef KAME + memset(&ssa2, 0, sizeof ssa2); + ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; + ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK; + ssa2.sadb_x_sa2_mode = 0; + if (pf_key_v2_msg_add(getspi, (struct sadb_ext *)&ssa2, 0) == -1) + goto cleanup; +#endif + + /* Setup the ADDRESS extensions. */ + len = + sizeof(struct sadb_address) + PF_KEY_V2_ROUND(sysdep_sa_len(src)); + addr = calloc(1, len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#ifndef __OpenBSD__ + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memcpy(addr + 1, src, sysdep_sa_len(src)); + switch (((struct sockaddr *) (addr + 1))->sa_family) { + case AF_INET: + ((struct sockaddr_in *) (addr + 1))->sin_port = 0; + break; + case AF_INET6: + ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; + break; + } + if (pf_key_v2_msg_add(getspi, (struct sadb_ext *) addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + + len = + sizeof(struct sadb_address) + PF_KEY_V2_ROUND(sysdep_sa_len(dst)); + addr = calloc(1, len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#ifndef __OpenBSD__ + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memcpy(addr + 1, dst, sysdep_sa_len(dst)); + switch (((struct sockaddr *) (addr + 1))->sa_family) { + case AF_INET: + ((struct sockaddr_in *) (addr + 1))->sin_port = 0; + break; + case AF_INET6: + ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; + break; + } + if (pf_key_v2_msg_add(getspi, (struct sadb_ext *) addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + + /* Setup the SPIRANGE extension. */ + spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE; + spirange.sadb_spirange_len = sizeof spirange / PF_KEY_V2_CHUNK; + if (proto == IPSEC_PROTO_IPCOMP) { + spirange.sadb_spirange_min = CPI_RESERVED_MAX + 1; + spirange.sadb_spirange_max = CPI_PRIVATE_MIN - 1; + } else { + spirange.sadb_spirange_min = IPSEC_SPI_LOW; + spirange.sadb_spirange_max = 0xffffffff; + } + spirange.sadb_spirange_reserved = 0; + if (pf_key_v2_msg_add(getspi, (struct sadb_ext *)&spirange, 0) == -1) + goto cleanup; + + ret = pf_key_v2_call(getspi); + pf_key_v2_msg_free(getspi); + getspi = 0; + if (!ret) + goto cleanup; + err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; + if (err) { + log_print("pf_key_v2_get_spi: GETSPI: %s", strerror(err)); + goto cleanup; + } + ext = pf_key_v2_find_ext(ret, SADB_EXT_SA); + if (!ext) { + log_print("pf_key_v2_get_spi: no SA extension found"); + goto cleanup; + } + sa = ext->seg; + + /* IPCOMP CPIs are only 16 bits long. */ + *sz = (proto == IPSEC_PROTO_IPCOMP) ? sizeof(u_int16_t) + : sizeof sa->sadb_sa_spi; + spi = malloc(*sz); + if (!spi) + goto cleanup; + /* XXX This is ugly. */ + if (proto == IPSEC_PROTO_IPCOMP) { + u_int32_t tspi = ntohl(sa->sadb_sa_spi); + *(u_int16_t *) spi = htons((u_int16_t) tspi); + } else + memcpy(spi, &sa->sadb_sa_spi, *sz); + +#ifdef KAME + if (!pf_key_v2_register_sa_seq(spi, *sz, proto, dst, + sysdep_sa_len(dst), + ((struct sadb_msg *) (TAILQ_FIRST(ret)->seg))->sadb_msg_seq)) + goto cleanup; +#endif + pf_key_v2_msg_free(ret); + + LOG_DBG_BUF((LOG_SYSDEP, 50, "pf_key_v2_get_spi: spi", spi, *sz)); + return spi; + +cleanup: + if (spi) + free(spi); + if (addr) + free(addr); + if (getspi) + pf_key_v2_msg_free(getspi); + if (ret) + pf_key_v2_msg_free(ret); + return 0; +} + +/* Fetch SA information from the kernel. XXX OpenBSD only? */ +struct sa_kinfo * +pf_key_v2_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto, + struct sockaddr *dst) +{ + struct sadb_msg msg; + struct sadb_sa *ssa; + struct sadb_address *addr = 0; + struct sockaddr *sa; + struct sadb_lifetime *life; + struct pf_key_v2_msg *gettdb = 0, *ret = 0; + struct pf_key_v2_node *ext; + static struct sa_kinfo ksa; +#if defined (SADB_X_EXT_UDPENCAP) + struct sadb_x_udpencap *udpencap; +#endif + int len, err; + + if (spi_sz != sizeof (ssa->sadb_sa_spi)) + return 0; + + msg.sadb_msg_type = SADB_GET; + switch (proto) { + case IPSEC_PROTO_IPSEC_ESP: + msg.sadb_msg_satype = SADB_SATYPE_ESP; + break; + case IPSEC_PROTO_IPSEC_AH: + msg.sadb_msg_satype = SADB_SATYPE_AH; + break; +#ifdef SADB_X_SATYPE_IPCOMP + case IPSEC_PROTO_IPCOMP: + msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP; + break; +#endif + default: + log_print("pf_key_v2_get_kernel_sa: invalid proto %d", proto); + goto cleanup; + } + + gettdb = pf_key_v2_msg_new(&msg, 0); + if (!gettdb) + goto cleanup; + + /* SPI */ + ssa = (struct sadb_sa *)calloc(1, sizeof *ssa); + if (!ssa) { + log_print("pf_key_v2_get_kernel_sa: calloc(1, %lu) failed", + (unsigned long)sizeof *ssa); + goto cleanup; + } + + ssa->sadb_sa_exttype = SADB_EXT_SA; + ssa->sadb_sa_len = sizeof *ssa / PF_KEY_V2_CHUNK; + memcpy(&ssa->sadb_sa_spi, spi, sizeof ssa->sadb_sa_spi); + ssa->sadb_sa_state = SADB_SASTATE_MATURE; + if (pf_key_v2_msg_add(gettdb, (struct sadb_ext *)ssa, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + ssa = 0; + + /* XXX KAME SADB_X_EXT_xyz here? */ + + /* Address */ + len = + sizeof(struct sadb_address) + PF_KEY_V2_ROUND(sysdep_sa_len(dst)); + addr = calloc(1, len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#ifndef __OpenBSD__ + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memcpy(addr + 1, dst, sysdep_sa_len(dst)); + switch (((struct sockaddr *) (addr + 1))->sa_family) { + case AF_INET: + ((struct sockaddr_in *) (addr + 1))->sin_port = 0; + break; + case AF_INET6: + ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; + break; + } + if (pf_key_v2_msg_add(gettdb, (struct sadb_ext *)addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + + ret = pf_key_v2_call(gettdb); + pf_key_v2_msg_free(gettdb); + gettdb = 0; + if (!ret) + goto cleanup; + err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; + if (err) { + log_print("pf_key_v2_get_kernel_sa: SADB_GET: %s", + strerror(err)); + goto cleanup; + } + + /* Extract the data. */ + memset(&ksa, 0, sizeof ksa); + + ext = pf_key_v2_find_ext(ret, SADB_EXT_SA); + if (!ext) + goto cleanup; + + ssa = (struct sadb_sa *)ext; + ksa.spi = ssa->sadb_sa_spi; + ksa.wnd = ssa->sadb_sa_replay; + ksa.flags = ssa->sadb_sa_flags; + + ext = pf_key_v2_find_ext(ret, SADB_EXT_LIFETIME_CURRENT); + if (ext) { + life = (struct sadb_lifetime *)ext->seg; + ksa.cur_allocations = life->sadb_lifetime_allocations; + ksa.cur_bytes = life->sadb_lifetime_bytes; + ksa.first_use = life->sadb_lifetime_usetime; + ksa.established = life->sadb_lifetime_addtime; + } + + ext = pf_key_v2_find_ext(ret, SADB_EXT_LIFETIME_SOFT); + if (ext) { + life = (struct sadb_lifetime *)ext->seg; + ksa.soft_allocations = life->sadb_lifetime_allocations; + ksa.soft_bytes = life->sadb_lifetime_bytes; + ksa.soft_timeout = life->sadb_lifetime_addtime; + ksa.soft_first_use = life->sadb_lifetime_usetime; + } + + ext = pf_key_v2_find_ext(ret, SADB_EXT_LIFETIME_HARD); + if (ext) { + life = (struct sadb_lifetime *)ext->seg; + ksa.exp_allocations = life->sadb_lifetime_allocations; + ksa.exp_bytes = life->sadb_lifetime_bytes; + ksa.exp_timeout = life->sadb_lifetime_addtime; + ksa.exp_first_use = life->sadb_lifetime_usetime; + } + +#if defined (SADB_X_EXT_LIFETIME_LASTUSE) + ext = pf_key_v2_find_ext(ret, SADB_X_EXT_LIFETIME_LASTUSE); + if (ext) { + life = (struct sadb_lifetime *)ext->seg; + ksa.last_used = life->sadb_lifetime_usetime; + } +#endif + + ext = pf_key_v2_find_ext(ret, SADB_EXT_ADDRESS_SRC); + if (ext) { + sa = (struct sockaddr *)ext->seg; + memcpy(&ksa.src, sa, + sa->sa_family == AF_INET ? sizeof(struct sockaddr_in) : + sizeof(struct sockaddr_in6)); + } + + ext = pf_key_v2_find_ext(ret, SADB_EXT_ADDRESS_DST); + if (ext) { + sa = (struct sockaddr *)ext->seg; + memcpy(&ksa.dst, sa, + sa->sa_family == AF_INET ? sizeof(struct sockaddr_in) : + sizeof(struct sockaddr_in6)); + } + + ext = pf_key_v2_find_ext(ret, SADB_EXT_ADDRESS_PROXY); + if (ext) { + sa = (struct sockaddr *)ext->seg; + memcpy(sa, &ksa.proxy, + sa->sa_family == AF_INET ? sizeof(struct sockaddr_in) : + sizeof(struct sockaddr_in6)); + } + +#if defined (SADB_X_EXT_UDPENCAP) + ext = pf_key_v2_find_ext(ret, SADB_X_EXT_UDPENCAP); + if (ext) { + udpencap = (struct sadb_x_udpencap *)ext->seg; + ksa.udpencap_port = udpencap->sadb_x_udpencap_port; + } +#endif + + pf_key_v2_msg_free(ret); + + LOG_DBG_BUF((LOG_SYSDEP, 50, "pf_key_v2_get_kernel_sa: spi", spi, + spi_sz)); + + return &ksa; + + cleanup: + if (addr) + free (addr); + if (gettdb) + pf_key_v2_msg_free(gettdb); + if (ret) + pf_key_v2_msg_free(ret); + return 0; +} + +static void +pf_key_v2_setup_sockaddr(void *res, struct sockaddr *src, + struct sockaddr *dst, in_port_t port, int ingress) +{ + struct sockaddr_in *ip4_sa; + struct sockaddr_in6 *ip6_sa; + u_int8_t *p; + + switch (src->sa_family) { + case AF_INET: + ip4_sa = (struct sockaddr_in *) res; + ip4_sa->sin_family = AF_INET; +#ifndef USE_OLD_SOCKADDR + ip4_sa->sin_len = sizeof *ip4_sa; +#endif + ip4_sa->sin_port = port; + if (dst) + p = (u_int8_t *) (ingress ? + &((struct sockaddr_in *)src)->sin_addr.s_addr : + &((struct sockaddr_in *)dst)->sin_addr.s_addr); + else + p = (u_int8_t *)&((struct sockaddr_in *)src)->sin_addr.s_addr; + ip4_sa->sin_addr.s_addr = *((in_addr_t *) p); + break; + + case AF_INET6: + ip6_sa = (struct sockaddr_in6 *) res; + ip6_sa->sin6_family = AF_INET6; +#ifndef USE_OLD_SOCKADDR + ip6_sa->sin6_len = sizeof *ip6_sa; +#endif + ip6_sa->sin6_port = port; + if (dst) + p = (u_int8_t *) (ingress ? + &((struct sockaddr_in6 *)src)->sin6_addr.s6_addr : + &((struct sockaddr_in6 *)dst)->sin6_addr.s6_addr); + else + p = (u_int8_t *)&((struct sockaddr_in6 *)src)->sin6_addr.s6_addr; + memcpy(ip6_sa->sin6_addr.s6_addr, p, sizeof(struct in6_addr)); + break; + + default: + log_print("pf_key_v2_setup_sockaddr: unknown family %d\n", + src->sa_family); + break; + } +} + +/* + * Store/update a PF_KEY_V2 security association with full information from the + * IKE SA and PROTO into the kernel. INCOMING is set if we are setting the + * parameters for the incoming SA, and cleared otherwise. + */ +int +pf_key_v2_set_spi(struct sa *sa, struct proto *proto, int incoming, + struct sa *isakmp_sa) +{ + struct sadb_msg msg; + struct sadb_sa ssa; + struct sadb_lifetime *life = 0; + struct sadb_address *addr = 0; + struct sadb_key *key = 0; + struct sadb_ident *sid = 0; + struct sockaddr *src, *dst; + struct pf_key_v2_msg *update = 0, *ret = 0; + struct ipsec_proto *iproto = proto->data; + size_t len; + int keylen, hashlen, err; +#ifndef KAME + u_int8_t *pp; + int idtype; +#else /* KAME */ + struct sadb_x_sa2 ssa2; +#endif +#if defined (SADB_X_CREDTYPE_NONE) || defined (SADB_X_AUTHTYPE_NONE) + struct ipsec_sa *isa = sa->data; + struct sadb_x_cred *cred; + struct sadb_protocol flowtype, tprotocol; +#endif +#if defined (USE_NAT_TRAVERSAL) && defined (SADB_X_EXT_UDPENCAP) + struct sadb_x_udpencap udpencap; +#elif defined (USE_NAT_TRAVERSAL) && defined (SADB_X_EXT_NAT_T_TYPE) + struct sadb_x_nat_t_type nat_t_type; + struct sadb_x_nat_t_port nat_t_sport; + struct sadb_x_nat_t_port nat_t_dport; +#endif +#ifdef USE_DEBUG + char *addr_str; +#endif + + msg.sadb_msg_type = incoming ? SADB_UPDATE : SADB_ADD; + switch (proto->proto) { + case IPSEC_PROTO_IPSEC_ESP: + msg.sadb_msg_satype = SADB_SATYPE_ESP; + keylen = ipsec_esp_enckeylength(proto); + hashlen = ipsec_esp_authkeylength(proto); + + switch (proto->id) { + case IPSEC_ESP_DES: + case IPSEC_ESP_DES_IV32: + case IPSEC_ESP_DES_IV64: + ssa.sadb_sa_encrypt = SADB_EALG_DESCBC; + break; + + case IPSEC_ESP_3DES: + ssa.sadb_sa_encrypt = SADB_EALG_3DESCBC; + break; + +#ifdef SADB_X_EALG_AES + case IPSEC_ESP_AES: + /* case IPSEC_ESP_AES_128_CTR: */ + ssa.sadb_sa_encrypt = SADB_X_EALG_AES; + break; +#endif + +#ifdef SADB_X_EALG_CAST + case IPSEC_ESP_CAST: + ssa.sadb_sa_encrypt = SADB_X_EALG_CAST; + break; +#endif + +#ifdef SADB_X_EALG_BLF + case IPSEC_ESP_BLOWFISH: + ssa.sadb_sa_encrypt = SADB_X_EALG_BLF; + break; +#endif + + default: + LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_set_spi: " + "unknown encryption algorithm %d", proto->id)); + return -1; + } + + switch (iproto->auth) { + case IPSEC_AUTH_HMAC_MD5: +#ifdef SADB_AALG_MD5HMAC96 + ssa.sadb_sa_auth = SADB_AALG_MD5HMAC96; +#else + ssa.sadb_sa_auth = SADB_AALG_MD5HMAC; +#endif + break; + + case IPSEC_AUTH_HMAC_SHA: +#ifdef SADB_AALG_SHA1HMAC96 + ssa.sadb_sa_auth = SADB_AALG_SHA1HMAC96; +#else + ssa.sadb_sa_auth = SADB_AALG_SHA1HMAC; +#endif + break; + +#ifndef KAME + case IPSEC_AUTH_HMAC_RIPEMD: +#ifdef SADB_X_AALG_RIPEMD160HMAC96 + ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC96; +#elif defined (SADB_X_AALG_RIPEMD160HMAC) + ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC; +#elif defined (SADB_X_AALG_RIPEMD160) + ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160; +#else + ssa.sadb_sa_auth = SADB_AALG_RIPEMD160HMAC; +#endif + break; +#endif + +#ifdef SADB_X_AALG_SHA2_256 + case IPSEC_AUTH_HMAC_SHA2_256: + ssa.sadb_sa_auth = SADB_X_AALG_SHA2_256; + break; +#endif + +#ifdef SADB_X_AALG_SHA2_384 + case IPSEC_AUTH_HMAC_SHA2_384: + ssa.sadb_sa_auth = SADB_X_AALG_SHA2_384; + break; +#endif + +#ifdef SADB_X_AALG_SHA2_512 + case IPSEC_AUTH_HMAC_SHA2_512: + ssa.sadb_sa_auth = SADB_X_AALG_SHA2_512; + break; +#endif + + case IPSEC_AUTH_DES_MAC: + case IPSEC_AUTH_KPDK: + /* XXX We should be supporting KPDK */ + LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_set_spi: " + "unknown authentication algorithm %d", + iproto->auth)); + return -1; + + default: + ssa.sadb_sa_auth = SADB_AALG_NONE; + } + break; + + case IPSEC_PROTO_IPSEC_AH: + msg.sadb_msg_satype = SADB_SATYPE_AH; + hashlen = ipsec_ah_keylength(proto); + keylen = 0; + + ssa.sadb_sa_encrypt = SADB_EALG_NONE; + switch (proto->id) { + case IPSEC_AH_MD5: +#ifdef SADB_AALG_MD5HMAC96 + ssa.sadb_sa_auth = SADB_AALG_MD5HMAC96; +#else + ssa.sadb_sa_auth = SADB_AALG_MD5HMAC; +#endif + break; + + case IPSEC_AH_SHA: +#ifdef SADB_AALG_SHA1HMAC96 + ssa.sadb_sa_auth = SADB_AALG_SHA1HMAC96; +#else + ssa.sadb_sa_auth = SADB_AALG_SHA1HMAC; +#endif + break; + +#ifndef KAME + case IPSEC_AH_RIPEMD: +#ifdef SADB_X_AALG_RIPEMD160HMAC96 + ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC96; +#elif defined (SADB_X_AALG_RIPEMD160HMAC) + ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC; +#elif defined (SADB_X_AALG_RIPEMD160) + ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160; +#else + ssa.sadb_sa_auth = SADB_AALG_RIPEMD160HMAC; +#endif + break; +#endif + +#ifdef SADB_X_AALG_SHA2_256 + case IPSEC_AH_SHA2_256: + ssa.sadb_sa_auth = SADB_X_AALG_SHA2_256; + break; +#endif + +#ifdef SADB_X_AALG_SHA2_384 + case IPSEC_AH_SHA2_384: + ssa.sadb_sa_auth = SADB_X_AALG_SHA2_384; + break; +#endif + +#ifdef SADB_X_AALG_SHA2_512 + case IPSEC_AH_SHA2_512: + ssa.sadb_sa_auth = SADB_X_AALG_SHA2_512; + break; +#endif + + default: + LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_set_spi: " + "unknown authentication algorithm %d", proto->id)); + goto cleanup; + } + break; + +#ifdef SADB_X_SATYPE_IPCOMP + case IPSEC_PROTO_IPCOMP: + msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP; + ssa.sadb_sa_auth = SADB_AALG_NONE; + keylen = 0; + hashlen = 0; + + /* + * Put compression algorithm type in the sadb_sa_encrypt + * field. + */ + switch (proto->id) { +#ifdef SADB_X_CALG_OUI + case IPSEC_IPCOMP_OUI: + ssa.sadb_sa_encrypt = SADB_X_CALG_OUI; + break; +#endif + +#ifdef SADB_X_CALG_DEFLATE + case IPSEC_IPCOMP_DEFLATE: + ssa.sadb_sa_encrypt = SADB_X_CALG_DEFLATE; + break; +#endif + +#ifdef SADB_X_CALG_LZS + case IPSEC_IPCOMP_LZS: + ssa.sadb_sa_encrypt = SADB_X_CALG_LZS; + break; +#endif + +#ifdef SADB_X_CALG_V42BIS + case IPSEC_IPCOMP_V42BIS: + ssa.sadb_sa_encrypt = SADB_X_CALG_V42BIS; + break; +#endif + + default: + break; + } + break; +#endif /* SADB_X_SATYPE_IPCOMP */ + + default: + log_print("pf_key_v2_set_spi: invalid proto %d", proto->proto); + goto cleanup; + } + if (incoming) { + sa->transport->vtbl->get_src(sa->transport, &dst); + sa->transport->vtbl->get_dst(sa->transport, &src); + } + else { + sa->transport->vtbl->get_dst(sa->transport, &dst); + sa->transport->vtbl->get_src(sa->transport, &src); + } + +#ifdef KAME + msg.sadb_msg_seq = (incoming ? + pf_key_v2_seq_by_sa(proto->spi[incoming], sizeof ssa.sadb_sa_spi, + proto->proto, dst, sysdep_sa_len(dst)) : 0); +#else + msg.sadb_msg_seq = sa->seq; +#endif + update = pf_key_v2_msg_new(&msg, 0); + if (!update) + goto cleanup; + +#ifdef KAME + memset(&ssa2, 0, sizeof ssa2); + ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; + ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK; +#if defined (LINUX_IPSEC) + if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL) + ssa2.sadb_x_sa2_mode = IPSEC_MODE_TUNNEL; + else + ssa2.sadb_x_sa2_mode = IPSEC_MODE_TRANSPORT; +#else + ssa2.sadb_x_sa2_mode = 0; +#endif + if (pf_key_v2_msg_add(update, (struct sadb_ext *)&ssa2, 0) == -1) + goto cleanup; +#endif + + /* Setup the rest of the SA extension. */ + ssa.sadb_sa_exttype = SADB_EXT_SA; + ssa.sadb_sa_len = sizeof ssa / PF_KEY_V2_CHUNK; + if (proto->spi_sz[incoming] == 2) /* IPCOMP uses 16bit CPIs. */ + ssa.sadb_sa_spi = htonl(proto->spi[incoming][0] << 8 | + proto->spi[incoming][1]); + else + memcpy(&ssa.sadb_sa_spi, proto->spi[incoming], + sizeof ssa.sadb_sa_spi); + ssa.sadb_sa_replay = conf_get_str("General", "Shared-SADB") ? 0 : + iproto->replay_window; + ssa.sadb_sa_state = SADB_SASTATE_MATURE; + ssa.sadb_sa_flags = 0; +#ifdef SADB_X_SAFLAGS_TUNNEL + if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL || + iproto->encap_mode == IPSEC_ENCAP_UDP_ENCAP_TUNNEL || + iproto->encap_mode == IPSEC_ENCAP_UDP_ENCAP_TUNNEL_DRAFT) + ssa.sadb_sa_flags = SADB_X_SAFLAGS_TUNNEL; +#endif + + if (isakmp_sa->flags & SA_FLAG_NAT_T_ENABLE) { +#if defined (USE_NAT_TRAVERSAL) && defined (SADB_X_EXT_UDPENCAP) + memset(&udpencap, 0, sizeof udpencap); + ssa.sadb_sa_flags |= SADB_X_SAFLAGS_UDPENCAP; + udpencap.sadb_x_udpencap_exttype = SADB_X_EXT_UDPENCAP; + udpencap.sadb_x_udpencap_len = + sizeof udpencap / PF_KEY_V2_CHUNK; + udpencap.sadb_x_udpencap_port = sockaddr_port(dst); + if (pf_key_v2_msg_add(update, (struct sadb_ext *)&udpencap, 0) + == -1) + goto cleanup; +#elif defined (USE_NAT_TRAVERSAL) && defined (SADB_X_EXT_NAT_T_TYPE) +#ifndef UDP_ENCAP_ESPINUDP +#define UDP_ENCAP_ESPINUDP 2 +#endif + memset(&nat_t_type, 0, sizeof nat_t_type); + memset(&nat_t_sport, 0, sizeof nat_t_sport); + memset(&nat_t_dport, 0, sizeof nat_t_dport); + + /* type = draft-udp-encap-06 */ + nat_t_type.sadb_x_nat_t_type_len = sizeof nat_t_type / PF_KEY_V2_CHUNK; + nat_t_type.sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE; + nat_t_type.sadb_x_nat_t_type_type = UDP_ENCAP_ESPINUDP; + if(pf_key_v2_msg_add(update, (struct sadb_ext *)&nat_t_type, 0) == -1) + goto cleanup; + + /* source port */ + nat_t_sport.sadb_x_nat_t_port_len = sizeof nat_t_sport / + PF_KEY_V2_CHUNK; + nat_t_sport.sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_SPORT; + nat_t_sport.sadb_x_nat_t_port_port = sockaddr_port(src); + if(pf_key_v2_msg_add(update, (struct sadb_ext *)&nat_t_sport, 0) == -1) + goto cleanup; + + /* destination port */ + nat_t_dport.sadb_x_nat_t_port_len = sizeof nat_t_dport / + PF_KEY_V2_CHUNK; + nat_t_dport.sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_DPORT; + nat_t_dport.sadb_x_nat_t_port_port = sockaddr_port(dst); + if(pf_key_v2_msg_add(update, (struct sadb_ext *)&nat_t_dport, 0) == -1) + goto cleanup; + + /* original address (transport mode checksum missing info) goes here */ +#endif + } + + if (pf_key_v2_msg_add(update, (struct sadb_ext *)&ssa, 0) == -1) + goto cleanup; + + if (sa->seconds || sa->kilobytes) { + /* Setup the hard limits. */ + life = malloc(sizeof *life); + if (!life) + goto cleanup; + life->sadb_lifetime_len = sizeof *life / PF_KEY_V2_CHUNK; + life->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; + life->sadb_lifetime_allocations = 0; + life->sadb_lifetime_bytes = sa->kilobytes * 1024; + /* + * XXX I am not sure which one is best in security respect. + * Maybe the RFCs actually mandate what a lifetime really is. + */ +#if 0 + life->sadb_lifetime_addtime = 0; + life->sadb_lifetime_usetime = sa->seconds; +#else + life->sadb_lifetime_addtime = sa->seconds; + life->sadb_lifetime_usetime = 0; +#endif + if (pf_key_v2_msg_add(update, (struct sadb_ext *) life, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + life = 0; + + /* + * Setup the soft limits, we use 90 % of the hard ones. + * XXX A configurable ratio would be better. + */ + life = malloc(sizeof *life); + if (!life) + goto cleanup; + life->sadb_lifetime_len = sizeof *life / PF_KEY_V2_CHUNK; + life->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; + life->sadb_lifetime_allocations = 0; + life->sadb_lifetime_bytes = sa->kilobytes * 1024 * 9 / 10; + /* + * XXX I am not sure which one is best in security respect. + * Maybe the RFCs actually mandate what a lifetime really is. + */ +#if 0 + life->sadb_lifetime_addtime = 0; + life->sadb_lifetime_usetime = sa->seconds * 9 / 10; +#else + life->sadb_lifetime_addtime = sa->seconds * 9 / 10; + life->sadb_lifetime_usetime = 0; +#endif + if (pf_key_v2_msg_add(update, (struct sadb_ext *) life, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + life = 0; + } + /* + * Setup the ADDRESS extensions. + */ + len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(src)); + addr = calloc(1, len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#ifndef __OpenBSD__ + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memcpy(addr + 1, src, sysdep_sa_len(src)); + switch (((struct sockaddr *) (addr + 1))->sa_family) { + case AF_INET: + ((struct sockaddr_in *) (addr + 1))->sin_port = 0; + break; + case AF_INET6: + ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; + break; + } + if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + + len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(dst)); + addr = calloc(1, len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#ifndef __OpenBSD__ + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memcpy(addr + 1, dst, sysdep_sa_len(dst)); + switch (((struct sockaddr *) (addr + 1))->sa_family) { + case AF_INET: + ((struct sockaddr_in *) (addr + 1))->sin_port = 0; + break; + case AF_INET6: + ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; + break; + } + if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + +#if 0 + /* XXX I am not sure about what to do here just yet. */ + if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL) { + len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(dst)); + addr = calloc(1, len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#ifndef __OpenBSD__ + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memcpy(addr + 1, dst, sysdep_sa_len(dst)); + switch (((struct sockaddr *) (addr + 1))->sa_family) { + case AF_INET: + ((struct sockaddr_in *) (addr + 1))->sin_port = 0; + break; + case AF_INET6: + ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; + break; + } + if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; +#if 0 + msg->em_odst = msg->em_dst; + msg->em_osrc = msg->em_src; +#endif + } +#endif + + if (proto->proto != IPSEC_PROTO_IPCOMP) { + /* Setup the KEY extensions. */ + if (hashlen) { + len = sizeof *key + PF_KEY_V2_ROUND(hashlen); + key = malloc(len); + if (!key) + goto cleanup; + key->sadb_key_exttype = SADB_EXT_KEY_AUTH; + key->sadb_key_len = len / PF_KEY_V2_CHUNK; + key->sadb_key_bits = hashlen * 8; + key->sadb_key_reserved = 0; + memcpy(key + 1, + iproto->keymat[incoming] + + (proto->proto == + IPSEC_PROTO_IPSEC_ESP ? keylen : 0), + hashlen); + if (pf_key_v2_msg_add(update, (struct sadb_ext *) key, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + key = 0; + } + if (keylen) { + len = sizeof *key + PF_KEY_V2_ROUND(keylen); + key = malloc(len); + if (!key) + goto cleanup; + key->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; + key->sadb_key_len = len / PF_KEY_V2_CHUNK; + key->sadb_key_bits = keylen * 8; + key->sadb_key_reserved = 0; + memcpy(key + 1, iproto->keymat[incoming], keylen); + if (pf_key_v2_msg_add(update, (struct sadb_ext *) key, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + key = 0; + } + } +#ifndef KAME + /* Setup identity extensions. */ + if (isakmp_sa->id_i) { + pp = pf_key_v2_convert_id(isakmp_sa->id_i, isakmp_sa->id_i_len, + &len, &idtype); + if (!pp) + goto nosid; + + sid = calloc(PF_KEY_V2_ROUND(len + 1) + sizeof *sid, + sizeof(u_int8_t)); + if (!sid) { + free(pp); + goto cleanup; + } + sid->sadb_ident_type = idtype; + sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK) + + PF_KEY_V2_ROUND(len + 1) / PF_KEY_V2_CHUNK; + if ((isakmp_sa->initiator && !incoming) || + (!isakmp_sa->initiator && incoming)) + sid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC; + else + sid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST; + + memcpy(sid + 1, pp, len); + free(pp); + + if (pf_key_v2_msg_add(update, (struct sadb_ext *) sid, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + sid = 0; + +nosid: + if (sid) + free(sid); + sid = 0; + } + if (isakmp_sa->id_r) { + pp = pf_key_v2_convert_id(isakmp_sa->id_r, isakmp_sa->id_r_len, + &len, &idtype); + if (!pp) + goto nodid; + + sid = calloc(PF_KEY_V2_ROUND(len + 1) + sizeof *sid, + sizeof(u_int8_t)); + if (!sid) { + free(pp); + goto cleanup; + } + sid->sadb_ident_type = idtype; + sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK) + + PF_KEY_V2_ROUND(len + 1) / PF_KEY_V2_CHUNK; + if ((isakmp_sa->initiator && !incoming) || + (!isakmp_sa->initiator && incoming)) + sid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST; + else + sid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC; + + memcpy(sid + 1, pp, len); + free(pp); + + if (pf_key_v2_msg_add(update, (struct sadb_ext *) sid, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + sid = 0; + +nodid: + if (sid) + free(sid); + sid = 0; + } +#endif /* KAME */ + +#ifdef SADB_X_CREDTYPE_NONE + /* + * Send received credentials to the kernel. We don't bother with + * our credentials, since the process either knows them (if it + * specified them with setsockopt()), or has no business looking at + * them (e.g., system wide certs). + */ + if (isakmp_sa->recv_cert) { + switch (isakmp_sa->recv_certtype) { + case ISAKMP_CERTENC_NONE: + /* Nothing to be done here. */ + break; + +#if defined (USE_KEYNOTE) && defined (SADB_X_EXT_REMOTE_CREDENTIALS) + case ISAKMP_CERTENC_KEYNOTE: + len = strlen(isakmp_sa->recv_cert); + cred = calloc(PF_KEY_V2_ROUND(len) + sizeof *cred, + sizeof(u_int8_t)); + if (!cred) + goto cleanup; + + cred->sadb_x_cred_len = + ((sizeof *cred) / PF_KEY_V2_CHUNK) + + PF_KEY_V2_ROUND(len) / PF_KEY_V2_CHUNK; + cred->sadb_x_cred_exttype = + SADB_X_EXT_REMOTE_CREDENTIALS; + cred->sadb_x_cred_type = SADB_X_CREDTYPE_KEYNOTE; + memcpy(cred + 1, isakmp_sa->recv_cert, len); + + if (pf_key_v2_msg_add(update, (struct sadb_ext *) cred, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + break; +#endif /* USE_KEYNOTE */ + +#if defined (USE_X509) && defined (SADB_X_EXT_REMOTE_CREDENTIALS) + case ISAKMP_CERTENC_X509_SIG: + { + u_int8_t *data; + u_int32_t datalen; + struct cert_handler *handler; + + /* We do it this way to avoid weird includes.*/ + handler = cert_get(ISAKMP_CERTENC_X509_SIG); + if (!handler) + break; + handler->cert_serialize(isakmp_sa->recv_cert, + &data, &datalen); + if (!data) + break; + + len = datalen; + cred = + calloc(PF_KEY_V2_ROUND(len) + sizeof *cred, + sizeof(u_int8_t)); + if (!cred) { + free(data); + goto cleanup; + } + cred->sadb_x_cred_len = + ((sizeof *cred) / PF_KEY_V2_CHUNK) + + PF_KEY_V2_ROUND(len) / PF_KEY_V2_CHUNK; + cred->sadb_x_cred_exttype = + SADB_X_EXT_REMOTE_CREDENTIALS; + cred->sadb_x_cred_type = SADB_X_CREDTYPE_X509; + memcpy(cred + 1, data, len); + free(data); + + if (pf_key_v2_msg_add(update, + (struct sadb_ext *) cred, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + } + break; +#endif /* USE_X509 */ + } + } +#endif /* SADB_X_CREDTYPE_NONE */ + +#ifdef SADB_X_AUTHTYPE_NONE + /* + * Tell the kernel what the peer used to authenticate, unless it was a + * passphrase. + */ + if (isakmp_sa->recv_key) { + u_int8_t *data; + + /* + * If it's a private key, we shouldn't pass it to the kernel + * for processes to see; successful authentication of Phase 1 + * implies that the process already knew the passphrase. On + * the other hand, we don't want to reveal to processes any + * system-wide passphrases used for authentication with remote + * systems. Same reason we don't send up the key (private or + * passphrase) we used to authenticate with the peer. + */ + if (isakmp_sa->recv_keytype == ISAKMP_KEY_PASSPHRASE) + goto doneauth; + + key_serialize(isakmp_sa->recv_keytype, ISAKMP_KEYTYPE_PUBLIC, + isakmp_sa->recv_key, &data, &len); + if (!data) + goto cleanup; + + cred = calloc(PF_KEY_V2_ROUND(len) + sizeof *cred, + sizeof(u_int8_t)); + if (!cred) { + free(data); + goto cleanup; + } + cred->sadb_x_cred_len = ((sizeof *cred) / PF_KEY_V2_CHUNK) + + PF_KEY_V2_ROUND(len) / PF_KEY_V2_CHUNK; + cred->sadb_x_cred_exttype = SADB_X_EXT_REMOTE_AUTH; + memcpy(cred + 1, data, len); + free(data); + + switch (isakmp_sa->recv_keytype) { + case ISAKMP_KEY_RSA: + cred->sadb_x_cred_type = SADB_X_AUTHTYPE_RSA; + break; + + default: + log_print("pf_key_v2_set_spi: " + "unknown received key type %d", + isakmp_sa->recv_keytype); + free(cred); + goto cleanup; + } + + if (pf_key_v2_msg_add(update, (struct sadb_ext *) cred, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + } +doneauth: +#endif /* SADB_X_AUTHTYPE_NONE */ + +#ifdef SADB_X_EXT_FLOW_TYPE + /* Setup the flow type extension. */ + bzero(&flowtype, sizeof flowtype); + flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE; + flowtype.sadb_protocol_len = sizeof flowtype / PF_KEY_V2_CHUNK; + flowtype.sadb_protocol_direction = incoming ? + IPSP_DIRECTION_IN : IPSP_DIRECTION_OUT; + + if (pf_key_v2_msg_add(update, (struct sadb_ext *)&flowtype, 0) == -1) + goto cleanup; + + bzero(&tprotocol, sizeof tprotocol); + tprotocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL; + tprotocol.sadb_protocol_len = sizeof tprotocol / PF_KEY_V2_CHUNK; + tprotocol.sadb_protocol_proto = isa->tproto; + + if (pf_key_v2_msg_add(update, (struct sadb_ext *)&tprotocol, + 0) == -1) + goto cleanup; + + len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(isa->src_net)); + addr = calloc(1, len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = incoming ? + SADB_X_EXT_DST_FLOW : SADB_X_EXT_SRC_FLOW; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; + addr->sadb_address_reserved = 0; + pf_key_v2_setup_sockaddr(addr + 1, isa->src_net, 0, isa->sport, 0); + if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + + addr = calloc(1, len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = + incoming ? SADB_X_EXT_DST_MASK : SADB_X_EXT_SRC_MASK; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; + addr->sadb_address_reserved = 0; + pf_key_v2_setup_sockaddr(addr + 1, isa->src_mask, 0, + isa->sport ? 0xffff : 0, 0); + if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + + addr = calloc(1, len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = incoming ? + SADB_X_EXT_SRC_FLOW : SADB_X_EXT_DST_FLOW; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; + addr->sadb_address_reserved = 0; + pf_key_v2_setup_sockaddr(addr + 1, isa->dst_net, 0, isa->dport, 0); + if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + + addr = calloc(1, len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = + incoming ? SADB_X_EXT_SRC_MASK : SADB_X_EXT_DST_MASK; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; + addr->sadb_address_reserved = 0; + pf_key_v2_setup_sockaddr(addr + 1, isa->dst_mask, 0, + isa->dport ? 0xffff : 0, 0); + if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; +#endif /* SADB_X_EXT_FLOW_TYPE */ + + /* XXX Here can sensitivity extensions be setup. */ + +#ifdef USE_DEBUG + if (sockaddr2text(dst, &addr_str, 0)) + addr_str = 0; + + LOG_DBG((LOG_SYSDEP, 10, "pf_key_v2_set_spi: " + "satype %d dst %s SPI 0x%x", msg.sadb_msg_satype, + addr_str ? addr_str : "unknown", ntohl(ssa.sadb_sa_spi))); + + if (addr_str) + free(addr_str); +#endif /* USE_DEBUG */ + + /* + * Although PF_KEY knows about expirations, it is unreliable per the + * specs thus we need to do them inside isakmpd as well. + */ + if (sa->seconds) + if (sa_setup_expirations(sa)) + goto cleanup; + + ret = pf_key_v2_call(update); + pf_key_v2_msg_free(update); + update = 0; + if (!ret) + goto cleanup; + err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; + pf_key_v2_msg_free(ret); + ret = 0; + + /* + * If we are doing an addition into an SADB shared with our peer, + * errors here are to be expected as the peer will already have + * created the SA, and can thus be ignored. + */ + if (err && !(msg.sadb_msg_type == SADB_ADD && + conf_get_str("General", "Shared-SADB"))) { + log_print("pf_key_v2_set_spi: %s: %s", + msg.sadb_msg_type == SADB_ADD ? "ADD" : "UPDATE", + strerror(err)); + goto cleanup; + } + LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_set_spi: done")); + + return 0; + +cleanup: + if (sid) + free(sid); + if (addr) + free(addr); + if (life) + free(life); + if (key) + free(key); + if (update) + pf_key_v2_msg_free(update); + if (ret) + pf_key_v2_msg_free(ret); + return -1; +} + +static __inline__ int +pf_key_v2_mask_to_bits(u_int32_t mask) +{ + u_int32_t hmask = ntohl(mask); + + return (33 - ffs(~hmask + 1)) % 33; +} + +static int +pf_key_v2_mask6_to_bits(u_int8_t * mask) +{ + int n; + + bit_ffc(mask, 128, &n); + return n == -1 ? 128 : n; +} + +/* + * Enable/disable a flow. + * XXX Assumes OpenBSD {ADD,DEL}FLOW extensions. + * Should probably be moved to sysdep.c + */ +static int +pf_key_v2_flow(struct sockaddr *laddr, struct sockaddr *lmask, + struct sockaddr *raddr, struct sockaddr *rmask, + u_int8_t tproto, u_int16_t sport, u_int16_t dport, + u_int8_t *spi, u_int8_t proto, struct sockaddr *dst, + struct sockaddr *src, int delete, int ingress, + u_int8_t srcid_type, u_int8_t *srcid, int srcid_len, + u_int8_t dstid_type, u_int8_t *dstid, int dstid_len, + struct ipsec_proto *iproto) +{ +#ifdef USE_DEBUG + char *laddr_str, *lmask_str, *raddr_str, *rmask_str; +#endif + +#if defined (SADB_X_ADDFLOW) && defined (SADB_X_DELFLOW) + struct sadb_msg msg; +#if defined (SADB_X_EXT_FLOW_TYPE) + struct sadb_protocol flowtype; + struct sadb_ident *sid = 0; +#else + struct sadb_sa ssa; +#endif + struct sadb_address *addr = 0; + struct sadb_protocol tprotocol; + struct pf_key_v2_msg *flow = 0, *ret = 0; + size_t len; + int err; + +#if !defined (SADB_X_SAFLAGS_INGRESS_FLOW) && !defined (SADB_X_EXT_FLOW_TYPE) + if (ingress) + return 0; +#endif + + msg.sadb_msg_type = delete ? SADB_X_DELFLOW : SADB_X_ADDFLOW; + switch (proto) { + case IPSEC_PROTO_IPSEC_ESP: + msg.sadb_msg_satype = SADB_SATYPE_ESP; + break; + case IPSEC_PROTO_IPSEC_AH: + msg.sadb_msg_satype = SADB_SATYPE_AH; + break; + case IPSEC_PROTO_IPCOMP: + msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP; + break; + default: + log_print("pf_key_v2_flow: invalid proto %d", proto); + goto cleanup; + } + msg.sadb_msg_seq = 0; + flow = pf_key_v2_msg_new(&msg, 0); + if (!flow) + goto cleanup; + +#if defined (SADB_X_EXT_FLOW_TYPE) + if (!delete) { + /* Setup the source ID, if provided. */ + if (srcid) { + sid = calloc( + PF_KEY_V2_ROUND(srcid_len + 1) + sizeof *sid, + sizeof(u_int8_t)); + if (!sid) + goto cleanup; + + sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK) + + PF_KEY_V2_ROUND(srcid_len + 1) / PF_KEY_V2_CHUNK; + sid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC; + sid->sadb_ident_type = srcid_type; + + memcpy(sid + 1, srcid, srcid_len); + + if (pf_key_v2_msg_add(flow, (struct sadb_ext *) sid, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + + sid = 0; + } + /* Setup the destination ID, if provided. */ + if (dstid) { + sid = calloc( + PF_KEY_V2_ROUND(dstid_len + 1) + sizeof *sid, + sizeof(u_int8_t)); + if (!sid) + goto cleanup; + + sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK) + + PF_KEY_V2_ROUND(dstid_len + 1) / PF_KEY_V2_CHUNK; + sid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST; + sid->sadb_ident_type = dstid_type; + + memcpy(sid + 1, dstid, dstid_len); + + if (pf_key_v2_msg_add(flow, (struct sadb_ext *) sid, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + + sid = 0; + } + } + /* Setup the flow type extension. */ + bzero(&flowtype, sizeof flowtype); + flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE; + flowtype.sadb_protocol_len = sizeof flowtype / PF_KEY_V2_CHUNK; + flowtype.sadb_protocol_direction = + ingress ? IPSP_DIRECTION_IN : IPSP_DIRECTION_OUT; + flowtype.sadb_protocol_proto = + ingress ? SADB_X_FLOW_TYPE_USE : SADB_X_FLOW_TYPE_REQUIRE; + + if (pf_key_v2_msg_add(flow, (struct sadb_ext *)&flowtype, 0) == -1) + goto cleanup; +#else /* SADB_X_EXT_FLOW_TYPE */ + /* Setup the SA extension. */ + ssa.sadb_sa_exttype = SADB_EXT_SA; + ssa.sadb_sa_len = sizeof ssa / PF_KEY_V2_CHUNK; + memcpy(&ssa.sadb_sa_spi, spi, sizeof ssa.sadb_sa_spi); + ssa.sadb_sa_replay = 0; + ssa.sadb_sa_state = 0; + ssa.sadb_sa_auth = 0; + ssa.sadb_sa_encrypt = 0; + ssa.sadb_sa_flags = 0; +#if defined (SADB_X_SAFLAGS_INGRESS_FLOW) + if (ingress) + ssa.sadb_sa_flags |= SADB_X_SAFLAGS_INGRESS_FLOW; +#endif +#if defined (SADB_X_SAFLAGS_REPLACEFLOW) + if (!delete && !ingress) + ssa.sadb_sa_flags |= SADB_X_SAFLAGS_REPLACEFLOW; +#endif + + if (pf_key_v2_msg_add(flow, (struct sadb_ext *)&ssa, 0) == -1) + goto cleanup; +#endif /* SADB_X_EXT_FLOW_TYPE */ + + /* + * Setup the ADDRESS extensions. + */ + len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(src)); +#if !defined (SADB_X_EXT_FLOW_TYPE) + if (!delete || ingress) +#else + if (!delete) +#endif /* SADB_X_EXT_FLOW_TYPE */ + { + addr = calloc(1, len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; + addr->sadb_address_reserved = 0; +#if defined (SADB_X_EXT_FLOW_TYPE) + pf_key_v2_setup_sockaddr(addr + 1, src, dst, 0, ingress); +#else + pf_key_v2_setup_sockaddr(addr + 1, dst, 0, 0, 0); +#endif + if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + } + len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(laddr)); + addr = calloc(1, len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_X_EXT_SRC_FLOW; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; + addr->sadb_address_reserved = 0; + pf_key_v2_setup_sockaddr(addr + 1, laddr, 0, sport, 0); + if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + + addr = calloc(1, len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_X_EXT_SRC_MASK; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; + addr->sadb_address_reserved = 0; + pf_key_v2_setup_sockaddr(addr + 1, lmask, 0, sport ? 0xffff : 0, 0); + if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + + addr = calloc(1, len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_X_EXT_DST_FLOW; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; + addr->sadb_address_reserved = 0; + pf_key_v2_setup_sockaddr(addr + 1, raddr, 0, dport, 0); + if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + + addr = calloc(1, len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_X_EXT_DST_MASK; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; + addr->sadb_address_reserved = 0; + pf_key_v2_setup_sockaddr(addr + 1, rmask, 0, dport ? 0xffff : 0, 0); + if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + + /* Setup the protocol extension. */ + bzero(&tprotocol, sizeof tprotocol); + tprotocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL; + tprotocol.sadb_protocol_len = sizeof tprotocol / PF_KEY_V2_CHUNK; + tprotocol.sadb_protocol_proto = tproto; + + if (pf_key_v2_msg_add(flow, (struct sadb_ext *)&tprotocol, 0) == -1) + goto cleanup; + +#ifdef USE_DEBUG + if (sockaddr2text(laddr, &laddr_str, 0)) + laddr_str = 0; + if (sockaddr2text(lmask, &lmask_str, 0)) + lmask_str = 0; + if (sockaddr2text(raddr, &raddr_str, 0)) + raddr_str = 0; + if (sockaddr2text(rmask, &rmask_str, 0)) + rmask_str = 0; + + LOG_DBG((LOG_SYSDEP, 50, + "pf_key_v2_flow: src %s %s dst %s %s proto %u sport %u dport %u", + laddr_str ? laddr_str : "<??\?>", lmask_str ? lmask_str : "<??\?>", + raddr_str ? raddr_str : "<??\?>", rmask_str ? rmask_str : "<??\?>", + tproto, ntohs(sport), ntohs(dport))); + + if (laddr_str) + free(laddr_str); + if (lmask_str) + free(lmask_str); + if (raddr_str) + free(raddr_str); + if (rmask_str) + free(rmask_str); +#endif /* USE_DEBUG */ + + ret = pf_key_v2_call(flow); + pf_key_v2_msg_free(flow); + flow = 0; + if (!ret) + goto cleanup; + err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; + if (err) { + if (err == ESRCH) /* These are common and usually + * harmless. */ + LOG_DBG((LOG_SYSDEP, 10, "pf_key_v2_flow: %sFLOW: %s", + delete ? "DEL" : "ADD", strerror(err))); + else + log_print("pf_key_v2_flow: %sFLOW: %s", + delete ? "DEL" : "ADD", strerror(err)); + goto cleanup; + } + pf_key_v2_msg_free(ret); + + LOG_DBG((LOG_MISC, 50, "pf_key_v2_flow: %sFLOW: done", + delete ? "DEL" : "ADD")); + + return 0; + +cleanup: +#if defined (SADB_X_EXT_FLOW_TYPE) + if (sid) + free(sid); +#endif /* SADB_X_EXT_FLOW_TYPE */ + if (addr) + free(addr); + if (flow) + pf_key_v2_msg_free(flow); + if (ret) + pf_key_v2_msg_free(ret); + return -1; + +#elif defined (SADB_X_SPDUPDATE) && defined (SADB_X_SPDDELETE) + struct sadb_msg msg; + struct sadb_x_policy *policy = 0; + struct sadb_x_ipsecrequest *ipsecrequest; + struct sadb_x_sa2 ssa2; + struct sadb_address *addr = 0; + struct sockaddr *saddr; + struct pf_key_v2_msg *flow = 0, *ret = 0; + u_int8_t *policy_buf; + size_t len; + int err; + struct sockaddr_in *ip4_sa; + struct sockaddr_in6 *ip6_sa; + + msg.sadb_msg_type = delete ? SADB_X_SPDDELETE : SADB_X_SPDUPDATE; + msg.sadb_msg_satype = SADB_SATYPE_UNSPEC; + msg.sadb_msg_seq = 0; + flow = pf_key_v2_msg_new(&msg, 0); + if (!flow) + goto cleanup; + + memset(&ssa2, 0, sizeof ssa2); + ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; + ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK; + ssa2.sadb_x_sa2_mode = 0; + if (pf_key_v2_msg_add(flow, (struct sadb_ext *)&ssa2, 0) == -1) + goto cleanup; + + /* + * Setup the ADDRESS extensions. + */ + len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(src)); + addr = calloc(1, len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#ifdef LINUX_IPSEC + addr->sadb_address_proto = tproto; +#else + addr->sadb_address_proto = IPSEC_ULPROTO_ANY; +#endif + addr->sadb_address_reserved = 0; +#ifdef LINUX_IPSEC + pf_key_v2_setup_sockaddr(addr + 1, laddr, 0, sport, 0); +#else + pf_key_v2_setup_sockaddr(addr + 1, laddr, 0, IPSEC_PORT_ANY, 0); +#endif + switch (laddr->sa_family) { + case AF_INET: + ip4_sa = (struct sockaddr_in *) lmask; + addr->sadb_address_prefixlen + = pf_key_v2_mask_to_bits(ip4_sa->sin_addr.s_addr); + break; + case AF_INET6: + ip6_sa = (struct sockaddr_in6 *) lmask; + addr->sadb_address_prefixlen = + pf_key_v2_mask6_to_bits(&ip6_sa->sin6_addr.s6_addr[0]); + break; + } + if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + + len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(raddr)); + addr = calloc(1, len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#ifdef LINUX_IPSEC + addr->sadb_address_proto = tproto; +#else + addr->sadb_address_proto = IPSEC_ULPROTO_ANY; +#endif + addr->sadb_address_reserved = 0; +#ifdef LINUX_IPSEC + pf_key_v2_setup_sockaddr(addr + 1, raddr, 0, dport, 0); +#else + pf_key_v2_setup_sockaddr(addr + 1, raddr, 0, IPSEC_PORT_ANY, 0); +#endif + switch (raddr->sa_family) { + case AF_INET: + ip4_sa = (struct sockaddr_in *) rmask; + addr->sadb_address_prefixlen + = pf_key_v2_mask_to_bits(ip4_sa->sin_addr.s_addr); + break; + case AF_INET6: + ip6_sa = (struct sockaddr_in6 *) rmask; + addr->sadb_address_prefixlen = + pf_key_v2_mask6_to_bits(&ip6_sa->sin6_addr.s6_addr[0]); + break; + } + if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + + /* Setup the POLICY extension. */ + len = sizeof *policy + sizeof *ipsecrequest + + 2 * PF_KEY_V2_ROUND(sysdep_sa_len(src)); + policy_buf = (u_int8_t *) calloc(1, len); + if (!policy_buf) { + log_error("pf_key_v2_flow: calloc %lu failed", + (unsigned long) len); + goto cleanup; + } + policy = (struct sadb_x_policy *) policy_buf; + policy->sadb_x_policy_exttype = SADB_X_EXT_POLICY; + policy->sadb_x_policy_len = len / PF_KEY_V2_CHUNK; + policy->sadb_x_policy_type = IPSEC_POLICY_IPSEC; + if (ingress) + policy->sadb_x_policy_dir = IPSEC_DIR_INBOUND; + else + policy->sadb_x_policy_dir = IPSEC_DIR_OUTBOUND; + policy->sadb_x_policy_reserved = 0; + + /* Setup the IPSECREQUEST extension part. */ + ipsecrequest = (struct sadb_x_ipsecrequest *) (policy + 1); + ipsecrequest->sadb_x_ipsecrequest_len = len - sizeof *policy; + switch (proto) { + case IPSEC_PROTO_IPSEC_ESP: + ipsecrequest->sadb_x_ipsecrequest_proto = IPPROTO_ESP; + break; + case IPSEC_PROTO_IPSEC_AH: + ipsecrequest->sadb_x_ipsecrequest_proto = IPPROTO_AH; + break; + default: + log_print("pf_key_v2_flow: invalid proto %d", proto); + goto cleanup; + } +#if defined (LINUX_IPSEC) + if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL) + ipsecrequest->sadb_x_ipsecrequest_mode = IPSEC_MODE_TUNNEL; + else + ipsecrequest->sadb_x_ipsecrequest_mode = IPSEC_MODE_TRANSPORT; +#else + ipsecrequest->sadb_x_ipsecrequest_mode = IPSEC_MODE_TUNNEL; /* XXX */ +#endif + ipsecrequest->sadb_x_ipsecrequest_level + = ingress ? IPSEC_LEVEL_USE : IPSEC_LEVEL_REQUIRE; + ipsecrequest->sadb_x_ipsecrequest_reqid = 0; /* XXX */ + + /* Add source and destination addresses. */ + saddr = (struct sockaddr *)(ipsecrequest + 1); + pf_key_v2_setup_sockaddr(saddr, src, 0, 0, 0); + switch (src->sa_family) { + case AF_INET: + saddr = (struct sockaddr *)((struct sockaddr_in *)saddr + 1); + break; + case AF_INET6: + saddr = (struct sockaddr *)((struct sockaddr_in6 *)saddr + 1); + break; + } + pf_key_v2_setup_sockaddr(saddr, dst, 0, 0, 0); + if (pf_key_v2_msg_add(flow, (struct sadb_ext *)policy, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + policy = 0; + +#ifdef USE_DEBUG + if (sockaddr2text(laddr, &laddr_str, 0)) + laddr_str = 0; + if (sockaddr2text(lmask, &lmask_str, 0)) + lmask_str = 0; + if (sockaddr2text(raddr, &raddr_str, 0)) + raddr_str = 0; + if (sockaddr2text(rmask, &rmask_str, 0)) + rmask_str = 0; + + LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_flow: src %s %s dst %s %s", + laddr_str ? laddr_str : "<??\?>", lmask_str ? lmask_str : "<??\?>", + raddr_str ? raddr_str : "<??\?>", + rmask_str ? rmask_str : "<??\?>")); + + if (laddr_str) + free(laddr_str); + if (lmask_str) + free(lmask_str); + if (raddr_str) + free(raddr_str); + if (rmask_str) + free(rmask_str); +#endif + + ret = pf_key_v2_call(flow); + pf_key_v2_msg_free(flow); + flow = 0; + if (!ret) + goto cleanup; + err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; + if (!delete && err == EEXIST) { + LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_flow: " + "SPDADD returns EEXIST")); + } else if (err) { + log_print("pf_key_v2_flow: SPD%s: %s", + delete ? "DELETE" : "ADD", strerror(err)); + goto cleanup; + } + pf_key_v2_msg_free(ret); + + LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_flow: SPD%s: done", + delete ? "DELETE" : "ADD")); + + return 0; + +cleanup: + if (addr) + free(addr); + if (policy) + free(policy); + if (flow) + pf_key_v2_msg_free(flow); + if (ret) + pf_key_v2_msg_free(ret); + return -1; + +#else + log_print("pf_key_v2_flow: not supported in pure PF_KEYv2"); + return -1; +#endif +} + +#ifndef KAME +static u_int8_t * +pf_key_v2_convert_id(u_int8_t * id, int idlen, size_t * reslen, int *idtype) +{ + u_int8_t *addr, *res = 0; + char addrbuf[ADDRESS_MAX + 5]; + + switch (id[0]) { + case IPSEC_ID_FQDN: + res = calloc(idlen - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ, + sizeof(u_int8_t)); + if (!res) + return 0; + + *reslen = idlen - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ; + memcpy(res, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, *reslen); + *idtype = SADB_IDENTTYPE_FQDN; + LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: FQDN %.*s", + (int) *reslen, res)); + return res; + + case IPSEC_ID_USER_FQDN: + res = calloc(idlen - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ, + sizeof(u_int8_t)); + if (!res) + return 0; + + *reslen = idlen - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ; + memcpy(res, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, *reslen); + *idtype = SADB_IDENTTYPE_USERFQDN; + LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: UFQDN %.*s", + (int) *reslen, res)); + return res; + + case IPSEC_ID_IPV4_ADDR: /* XXX CONNECTION ? */ + if (inet_ntop(AF_INET, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, + addrbuf, ADDRESS_MAX) == NULL) + return 0; + *reslen = strlen(addrbuf) + 3; + strlcat(addrbuf, "/32", ADDRESS_MAX + 5); + res = (u_int8_t *) strdup(addrbuf); + if (!res) + return 0; + *idtype = SADB_IDENTTYPE_PREFIX; + LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: " + "IPv4 address %s", res)); + return res; + + case IPSEC_ID_IPV6_ADDR: /* XXX CONNECTION ? */ + if (inet_ntop(AF_INET6, + id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, + addrbuf, ADDRESS_MAX) == NULL) + return 0; + *reslen = strlen(addrbuf) + 4; + strlcat(addrbuf, "/128", ADDRESS_MAX + 5); + res = (u_int8_t *) strdup(addrbuf); + if (!res) + return 0; + LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: " + "IPv6 address %s", res)); + *idtype = SADB_IDENTTYPE_PREFIX; + return res; + + case IPSEC_ID_IPV4_ADDR_SUBNET: /* XXX PREFIX */ + addr = id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ; + if (inet_ntop(AF_INET, addr, addrbuf, ADDRESS_MAX) == NULL) + return 0; + snprintf(addrbuf + strlen(addrbuf), + ADDRESS_MAX - strlen(addrbuf), "/%d", + pf_key_v2_mask_to_bits(*(u_int32_t *)(addr + + sizeof(struct in_addr)))); + *reslen = strlen(addrbuf); + res = (u_int8_t *) strdup(addrbuf); + if (!res) + return 0; + *idtype = SADB_IDENTTYPE_PREFIX; + LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: " + "IPv4 subnet %s", res)); + return res; + + case IPSEC_ID_IPV6_ADDR_SUBNET: /* XXX PREFIX */ + addr = id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ; + if (inet_ntop(AF_INET6, addr, addrbuf, ADDRESS_MAX) == NULL) + return 0; + snprintf(addrbuf + strlen(addrbuf), + ADDRESS_MAX - strlen(addrbuf), "/%d", + pf_key_v2_mask6_to_bits(addr + + sizeof(struct in6_addr))); + *reslen = strlen(addrbuf); + res = (u_int8_t *) strdup(addrbuf); + if (!res) + return 0; + LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: " + "IPv6 subnet %s", res)); + *idtype = SADB_IDENTTYPE_PREFIX; + return res; + + case IPSEC_ID_IPV4_RANGE: + case IPSEC_ID_IPV6_RANGE: + case IPSEC_ID_DER_ASN1_DN: + case IPSEC_ID_DER_ASN1_GN: + case IPSEC_ID_KEY_ID: + /* XXX Not implemented yet. */ + return 0; + } + + return 0; +} +#endif + +/* Enable a flow given an SA. */ +int +pf_key_v2_enable_sa(struct sa *sa, struct sa *isakmp_sa) +{ + struct ipsec_sa *isa = sa->data; + struct sockaddr *dst, *src; + int error; + struct proto *proto = TAILQ_FIRST(&sa->protos); + int sidtype = 0, didtype = 0; + size_t sidlen = 0, didlen = 0; + u_int8_t *sid = 0, *did = 0; +#if !defined (SADB_X_EXT_FLOW_TYPE) + struct sockaddr_storage hostmask_storage; + struct sockaddr *hostmask = (struct sockaddr *)&hostmask_storage; +#endif /* SADB_X_EXT_FLOW_TYPE */ + + sa->transport->vtbl->get_dst(sa->transport, &dst); + sa->transport->vtbl->get_src(sa->transport, &src); + +#if defined (SADB_X_EXT_FLOW_TYPE) + if (isakmp_sa->id_i) { + if (isakmp_sa->initiator) + sid = pf_key_v2_convert_id(isakmp_sa->id_i, + isakmp_sa->id_i_len, &sidlen, &sidtype); + else + did = pf_key_v2_convert_id(isakmp_sa->id_i, + isakmp_sa->id_i_len, &didlen, &didtype); + } + if (isakmp_sa->id_r) { + if (isakmp_sa->initiator) + did = pf_key_v2_convert_id(isakmp_sa->id_r, + isakmp_sa->id_r_len, &didlen, &didtype); + else + sid = pf_key_v2_convert_id(isakmp_sa->id_r, + isakmp_sa->id_r_len, &sidlen, &sidtype); + } +#endif /* SADB_X_EXT_FLOW_TYPE */ + + error = pf_key_v2_flow(isa->src_net, isa->src_mask, isa->dst_net, + isa->dst_mask, isa->tproto, isa->sport, isa->dport, + proto->spi[0], proto->proto, dst, src, 0, 0, + sidtype, sid, sidlen, didtype, did, didlen, + proto->data); + if (error) + goto cleanup; + +#if !defined (SADB_X_EXT_FLOW_TYPE) + /* Set hostmask to '-1'. */ + switch (dst->sa_family) { + case AF_INET: + ((struct sockaddr_in *) hostmask)->sin_family = AF_INET; +#ifndef USE_OLD_SOCKADDR + ((struct sockaddr_in *) hostmask)->sin_len = + sizeof(struct in_addr); +#endif + memset(&((struct sockaddr_in *) hostmask)->sin_addr.s_addr, + 0xff, sizeof(struct in_addr)); + break; + case AF_INET6: + ((struct sockaddr_in6 *) hostmask)->sin6_family = AF_INET6; +#ifndef USE_OLD_SOCKADDR + ((struct sockaddr_in6 *) hostmask)->sin6_len = + sizeof(struct in6_addr); +#endif + memset(&((struct sockaddr_in6 *) hostmask)->sin6_addr.s6_addr, + 0xff, sizeof(struct in6_addr)); + break; + } + + /* Ingress flows, handling SA bundles. */ + while (TAILQ_NEXT(proto, link)) { + error = pf_key_v2_flow(dst, hostmask, src, hostmask, 0, 0, 0, + proto->spi[1], proto->proto, src, dst, + 0, 1, 0, 0, 0, 0, 0, 0, proto->data); + if (error) + goto cleanup; + proto = TAILQ_NEXT(proto, link); + } +#endif /* SADB_X_EXT_FLOW_TYPE */ + + error = pf_key_v2_flow(isa->dst_net, isa->dst_mask, isa->src_net, + isa->src_mask, isa->tproto, isa->dport, isa->sport, + proto->spi[1], proto->proto, src, dst, 0, 1, + sidtype, sid, sidlen, didtype, did, didlen, + proto->data); + +cleanup: +#if defined (SADB_X_EXT_FLOW_TYPE) + if (sid) + free(sid); + if (did) + free(did); +#endif /* SADB_X_EXT_FLOW_TYPE */ + + return error; +} + +#if defined (SADB_X_ASKPOLICY) +/* Increase reference count of refcounted sections. */ +static int +pf_key_v2_conf_refinc(int af, char *section) +{ + char conn[22]; + int num; + + if (!section) + return 0; + + num = conf_get_num(section, "Refcount", 0); + if (num == 0) + return 0; + + snprintf(conn, sizeof conn, "%d", num + 1); + conf_set(af, section, "Refcount", conn, 1, 0); + return 0; +} +#endif + +/* + * Return 0 if the section didn't exist or was removed, non-zero otherwise. + * Don't touch non-refcounted (statically defined) sections. + */ +static int +pf_key_v2_conf_refhandle(int af, char *section) +{ + char conn[22]; + int num; + + if (!section) + return 0; + + num = conf_get_num(section, "Refcount", 0); + if (num == 1) { + conf_remove_section(af, section); + num--; + } else if (num != 0) { + snprintf(conn, sizeof conn, "%d", num - 1); + conf_set(af, section, "Refcount", conn, 1, 0); + } + return num; +} + +/* Remove all dynamically-established configuration entries. */ +static int +pf_key_v2_remove_conf(char *section) +{ + char *ikepeer, *localid, *remoteid, *configname; + struct conf_list_node *attr; + struct conf_list *attrs; + int af; + + if (!section) + return 0; + + if (!conf_get_str(section, "Phase")) + return 0; + + /* Only remove dynamically-established entries. */ + attrs = conf_get_list(section, "Flags"); + if (attrs) { + for (attr = TAILQ_FIRST(&attrs->fields); attr; + attr = TAILQ_NEXT(attr, link)) + if (!strcasecmp(attr->field, "__ondemand")) + goto passed; + + conf_free_list(attrs); + } + return 0; + +passed: + conf_free_list(attrs); + + af = conf_begin(); + + configname = conf_get_str(section, "Configuration"); + conf_remove_section(af, configname); + + /* These are the Phase 2 Local/Remote IDs. */ + localid = conf_get_str(section, "Local-ID"); + pf_key_v2_conf_refhandle(af, localid); + + remoteid = conf_get_str(section, "Remote-ID"); + pf_key_v2_conf_refhandle(af, remoteid); + + ikepeer = conf_get_str(section, "ISAKMP-peer"); + + pf_key_v2_conf_refhandle(af, section); + + if (ikepeer) { + remoteid = conf_get_str(ikepeer, "Remote-ID"); + localid = conf_get_str(ikepeer, "ID"); + configname = conf_get_str(ikepeer, "Configuration"); + + pf_key_v2_conf_refhandle(af, ikepeer); + pf_key_v2_conf_refhandle(af, configname); + + /* Phase 1 IDs */ + pf_key_v2_conf_refhandle(af, localid); + pf_key_v2_conf_refhandle(af, remoteid); + } + conf_end(af, 1); + return 0; +} + +/* Disable a flow given a SA. */ +static int +pf_key_v2_disable_sa(struct sa *sa, int incoming) +{ + struct ipsec_sa *isa = sa->data; + struct sockaddr *dst, *src; + struct proto *proto = TAILQ_FIRST(&sa->protos); +#if !defined (SADB_X_EXT_FLOW_TYPE) + struct sockaddr_storage hostmask_storage; + struct sockaddr *hostmask = (struct sockaddr *)&hostmask_storage; + int error; +#endif /* SADB_X_EXT_FLOW_TYPE */ + + sa->transport->vtbl->get_dst(sa->transport, &dst); + sa->transport->vtbl->get_src(sa->transport, &src); + + if (!incoming) + return pf_key_v2_flow(isa->src_net, isa->src_mask, + isa->dst_net, isa->dst_mask, isa->tproto, isa->sport, + isa->dport, proto->spi[0], proto->proto, src, dst, 1, 0, + 0, 0, 0, 0, 0, 0, proto->data); + else { +#if !defined (SADB_X_EXT_FLOW_TYPE) + /* Set hostmask to '-1'. */ + switch (dst->sa_family) { + case AF_INET: + ((struct sockaddr_in *) hostmask)->sin_family = + AF_INET; +#ifndef USE_OLD_SOCKADDR + ((struct sockaddr_in *) hostmask)->sin_len = + sizeof(struct in_addr); +#endif + memset(&((struct sockaddr_in *) hostmask)->sin_addr.s_addr, + 0xff, sizeof(struct in_addr)); + break; + case AF_INET6: + ((struct sockaddr_in6 *) hostmask)->sin6_family = + AF_INET6; +#ifndef USE_OLD_SOCKADDR + ((struct sockaddr_in6 *) hostmask)->sin6_len = + sizeof(struct in6_addr); +#endif + memset(&((struct sockaddr_in6 *) hostmask)->sin6_addr.s6_addr, + 0xff, sizeof(struct in6_addr)); + break; + } + + /* Ingress flow --- SA bundles */ + while (TAILQ_NEXT(proto, link)) { + error = pf_key_v2_flow(dst, hostmask, src, hostmask, + 0, 0, 0, proto->spi[1], proto->proto, src, dst, + 1, 1, 0, 0, 0, 0, 0, 0, proto->data); + if (error) + return error; + proto = TAILQ_NEXT(proto, link); + } +#endif /* SADB_X_EXT_FLOW_TYPE */ + + return pf_key_v2_flow(isa->dst_net, isa->dst_mask, + isa->src_net, isa->src_mask, isa->tproto, isa->dport, + isa->sport, proto->spi[1], proto->proto, src, dst, 1, 1, + 0, 0, 0, 0, 0, 0, proto->data); + } +} + +/* + * Delete the IPsec SA represented by the INCOMING direction in protocol PROTO + * of the IKE security association SA. Also delete potential flows tied to it. + */ +int +pf_key_v2_delete_spi(struct sa *sa, struct proto *proto, int incoming) +{ + struct sadb_msg msg; + struct sadb_sa ssa; + struct sadb_address *addr = 0; + struct sockaddr *saddr; + int len, err; + struct pf_key_v2_msg *delete = 0, *ret = 0; +#ifdef KAME + struct sadb_x_sa2 ssa2; +#endif + + /* If it's not an established SA, don't proceed. */ + if (!(sa->flags & SA_FLAG_READY)) + return 0; + + /* + * If the SA was not replaced and was not one acquired through the + * kernel (ACQUIRE message), remove the flow associated with it. + * We ignore any errors from the disabling of the flow. + */ + if (!(sa->flags & SA_FLAG_REPLACED) + && !(sa->flags & SA_FLAG_ONDEMAND)) + pf_key_v2_disable_sa(sa, incoming); + + if (sa->name && !(sa->flags & SA_FLAG_REPLACED)) { + LOG_DBG((LOG_SYSDEP, 50, + "pf_key_v2_delete_spi: removing configuration %s", + sa->name)); + pf_key_v2_remove_conf(sa->name); + } + msg.sadb_msg_type = SADB_DELETE; + switch (proto->proto) { + case IPSEC_PROTO_IPSEC_ESP: + msg.sadb_msg_satype = SADB_SATYPE_ESP; + break; + case IPSEC_PROTO_IPSEC_AH: + msg.sadb_msg_satype = SADB_SATYPE_AH; + break; +#if defined (SADB_X_SATYPE_IPCOMP) + case IPSEC_PROTO_IPCOMP: + msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP; + break; +#endif + default: + log_print("pf_key_v2_delete_spi: invalid proto %d", + proto->proto); + goto cleanup; + } + msg.sadb_msg_seq = 0; + delete = pf_key_v2_msg_new(&msg, 0); + if (!delete) + goto cleanup; + + /* Setup the SA extension. */ + ssa.sadb_sa_exttype = SADB_EXT_SA; + ssa.sadb_sa_len = sizeof ssa / PF_KEY_V2_CHUNK; + memcpy(&ssa.sadb_sa_spi, proto->spi[incoming], sizeof ssa.sadb_sa_spi); + ssa.sadb_sa_replay = 0; + ssa.sadb_sa_state = 0; + ssa.sadb_sa_auth = 0; + ssa.sadb_sa_encrypt = 0; + ssa.sadb_sa_flags = 0; + if (pf_key_v2_msg_add(delete, (struct sadb_ext *)&ssa, 0) == -1) + goto cleanup; + +#ifdef KAME + memset(&ssa2, 0, sizeof ssa2); + ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; + ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK; + ssa2.sadb_x_sa2_mode = 0; + if (pf_key_v2_msg_add(delete, (struct sadb_ext *)&ssa2, 0) == -1) + goto cleanup; +#endif + + /* + * Setup the ADDRESS extensions. + */ + if (incoming) + sa->transport->vtbl->get_dst(sa->transport, &saddr); + else + sa->transport->vtbl->get_src(sa->transport, &saddr); + len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(saddr)); + addr = calloc(1, len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#ifndef __OpenBSD__ + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memcpy(addr + 1, saddr, sysdep_sa_len(saddr)); + switch (saddr->sa_family) { + case AF_INET: + ((struct sockaddr_in *) (addr + 1))->sin_port = 0; + break; + case AF_INET6: + ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; + break; + } + if (pf_key_v2_msg_add(delete, (struct sadb_ext *) addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + + if (incoming) + sa->transport->vtbl->get_src(sa->transport, &saddr); + else + sa->transport->vtbl->get_dst(sa->transport, &saddr); + len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(saddr)); + addr = calloc(1, len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#ifndef __OpenBSD__ + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memcpy(addr + 1, saddr, sysdep_sa_len(saddr)); + switch (saddr->sa_family) { + case AF_INET: + ((struct sockaddr_in *) (addr + 1))->sin_port = 0; + break; + case AF_INET6: + ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; + break; + } + if (pf_key_v2_msg_add(delete, (struct sadb_ext *) addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + + ret = pf_key_v2_call(delete); + pf_key_v2_msg_free(delete); + delete = 0; + if (!ret) + goto cleanup; + err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; + if (err) { + LOG_DBG((LOG_SYSDEP, 10, "pf_key_v2_delete_spi: DELETE: %s", + strerror(err))); + goto cleanup; + } + pf_key_v2_msg_free(ret); + + LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_delete_spi: done")); + + return 0; + +cleanup: + if (addr) + free(addr); + if (delete) + pf_key_v2_msg_free(delete); + if (ret) + pf_key_v2_msg_free(ret); + return -1; +} + +static void +pf_key_v2_stayalive(struct exchange *exchange, void *vconn, int fail) +{ + char *conn = vconn; + struct sa *sa; + + /* XXX What if it is phase 1 ? */ + sa = sa_lookup_by_name(conn, 2); + if (sa) + sa->flags |= SA_FLAG_STAYALIVE; + + /* + * Remove failed configuration entry -- call twice because it is + * created with a Refcount of 2. + */ + if (fail && (!exchange || exchange->name)) { + pf_key_v2_remove_conf(conn); + pf_key_v2_remove_conf(conn); + } +} + +/* Check if a connection CONN exists, otherwise establish it. */ +void +pf_key_v2_connection_check(char *conn) +{ + if (!sa_lookup_by_name(conn, 2)) { + LOG_DBG((LOG_SYSDEP, 70, + "pf_key_v2_connection_check: SA for %s missing", conn)); + exchange_establish(conn, pf_key_v2_stayalive, conn); + } else + LOG_DBG((LOG_SYSDEP, 70, "pf_key_v2_connection_check: " + "SA for %s exists", conn)); +} + +/* Handle a PF_KEY lifetime expiration message PMSG. */ +static void +pf_key_v2_expire(struct pf_key_v2_msg *pmsg) +{ + struct sadb_msg *msg; + struct sadb_sa *ssa; + struct sadb_address *dst; + struct sockaddr *dstaddr; + struct sadb_lifetime *life, *lifecurrent; + struct sa *sa; + struct pf_key_v2_node *lifenode, *ext; +#ifdef USE_DEBUG + char *dst_str; +#endif + + msg = (struct sadb_msg *)TAILQ_FIRST(pmsg)->seg; + ext = pf_key_v2_find_ext(pmsg, SADB_EXT_SA); + if (!ext) { + log_print("pf_key_v2_expire: no SA extension found"); + return; + } + ssa = ext->seg; + ext = pf_key_v2_find_ext(pmsg, SADB_EXT_ADDRESS_DST); + if (!ext) { + log_print("pf_key_v2_expire: " + "no destination address extension found"); + return; + } + dst = ext->seg; + dstaddr = (struct sockaddr *) (dst + 1); + lifenode = pf_key_v2_find_ext(pmsg, SADB_EXT_LIFETIME_HARD); + if (!lifenode) + lifenode = pf_key_v2_find_ext(pmsg, SADB_EXT_LIFETIME_SOFT); + if (!lifenode) { + log_print("pf_key_v2_expire: no lifetime extension found"); + return; + } + life = lifenode->seg; + + lifenode = pf_key_v2_find_ext(pmsg, SADB_EXT_LIFETIME_CURRENT); + if (!lifenode) { + log_print("pf_key_v2_expire: " + "no current lifetime extension found"); + return; + } + lifecurrent = lifenode->seg; + +#ifdef USE_DEBUG + + if (sockaddr2text(dstaddr, &dst_str, 0)) + dst_str = 0; + + LOG_DBG((LOG_SYSDEP, 20, "pf_key_v2_expire: " + "%s dst %s SPI %x sproto %d", + life->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT ? "SOFT" + : "HARD", dst_str ? dst_str : "<unknown>", + ntohl(ssa->sadb_sa_spi), msg->sadb_msg_satype)); + + if (dst_str) + free(dst_str); + +#endif /* USE_DEBUG */ + + /* + * Find the IPsec SA. The IPsec stack has two SAs for every IKE SA, + * one outgoing and one incoming, we regard expirations for any of + * them as an expiration of the full IKE SA. Likewise, in + * protection suites consisting of more than one protocol, any + * expired individual IPsec stack SA will be seen as an expiration + * of the full suite. + */ + switch (msg->sadb_msg_satype) { + case SADB_SATYPE_ESP: + sa = ipsec_sa_lookup(dstaddr, ssa->sadb_sa_spi, + IPSEC_PROTO_IPSEC_ESP); + break; + + case SADB_SATYPE_AH: + sa = ipsec_sa_lookup(dstaddr, ssa->sadb_sa_spi, + IPSEC_PROTO_IPSEC_AH); + break; + +#ifdef SADB_X_SATYPE_IPCOMP + case SADB_X_SATYPE_IPCOMP: + sa = ipsec_sa_lookup(dstaddr, ssa->sadb_sa_spi, + IPSEC_PROTO_IPCOMP); + break; +#endif + + default: + /* XXX Log? */ + sa = 0; + break; + } + + /* If the SA is already gone, don't do anything. */ + if (!sa) + return; + + /* + * If we got a notification, try to renegotiate the SA -- unless of + * course it has already been replaced by another. + * Also, ignore SAs that were not dynamically established, or that + * did not see any use. + */ + if (!(sa->flags & SA_FLAG_REPLACED) && + (sa->flags & SA_FLAG_ONDEMAND) && + lifecurrent->sadb_lifetime_bytes) + exchange_establish(sa->name, 0, 0); + + if (life->sadb_lifetime_exttype == SADB_EXT_LIFETIME_HARD) { + /* Remove the old SA, it isn't useful anymore. */ + sa_free(sa); + } +} + +/* Handle a PF_KEY SA ACQUIRE message PMSG. */ +static void +pf_key_v2_acquire(struct pf_key_v2_msg *pmsg) +{ +#if defined (SADB_X_ASKPOLICY) + struct sadb_msg *msg, askpolicy_msg; + struct pf_key_v2_msg *askpolicy = 0, *ret = 0; + struct sadb_x_policy policy; + struct sadb_address *dst = 0, *src = 0; + struct sockaddr *dstaddr, *srcaddr = 0; + struct sadb_comb *scmb = 0; + struct sadb_prop *sprp = 0; + struct sadb_ident *srcident = 0, *dstident = 0; + char dstbuf[ADDRESS_MAX], srcbuf[ADDRESS_MAX], *peer = 0, + *conn = 0; + char confname[120]; + char *srcid = 0, *dstid = 0, *prefstring = 0; + int slen, af, afamily, masklen, buflen; + struct sockaddr *smask, *sflow, *dmask, *dflow; + struct sadb_protocol *sproto; + char ssflow[ADDRESS_MAX], sdflow[ADDRESS_MAX]; + char sdmask[ADDRESS_MAX], ssmask[ADDRESS_MAX]; + char *sidtype = 0, *didtype = 0; + char lname[100], dname[100], configname[30]; + int shostflag = 0, dhostflag = 0; + struct pf_key_v2_node *ext; + struct passwd *pwd = 0; + u_int16_t sport = 0, dport = 0; + u_int8_t tproto = 0; + char tmbuf[sizeof sport * 3 + 1], *xform; + int connlen; +#if defined (SADB_X_CREDTYPE_NONE) + struct sadb_x_cred *cred = 0, *sauth = 0; +#endif + + /* This needs to be dynamically allocated. */ + connlen = 22; + conn = malloc(connlen); + if (!conn) { + log_error("pf_key_v2_acquire: malloc (%d) failed", connlen); + return; + } + msg = (struct sadb_msg *)TAILQ_FIRST(pmsg)->seg; + + ext = pf_key_v2_find_ext(pmsg, SADB_EXT_ADDRESS_DST); + if (!ext) { + log_print("pf_key_v2_acquire: " + "no destination address specified"); + return; + } + dst = ext->seg; + + ext = pf_key_v2_find_ext(pmsg, SADB_EXT_ADDRESS_SRC); + if (ext) + src = ext->seg; + + ext = pf_key_v2_find_ext(pmsg, SADB_EXT_PROPOSAL); + if (ext) { + sprp = ext->seg; + scmb = (struct sadb_comb *) (sprp + 1); + } + ext = pf_key_v2_find_ext(pmsg, SADB_EXT_IDENTITY_SRC); + if (ext) + srcident = ext->seg; + + ext = pf_key_v2_find_ext(pmsg, SADB_EXT_IDENTITY_DST); + if (ext) + dstident = ext->seg; + + /* Ask the kernel for the matching policy. */ + bzero(&askpolicy_msg, sizeof askpolicy_msg); + askpolicy_msg.sadb_msg_type = SADB_X_ASKPOLICY; + askpolicy = pf_key_v2_msg_new(&askpolicy_msg, 0); + if (!askpolicy) + goto fail; + + policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY; + policy.sadb_x_policy_len = sizeof policy / PF_KEY_V2_CHUNK; + policy.sadb_x_policy_seq = msg->sadb_msg_seq; + if (pf_key_v2_msg_add(askpolicy, (struct sadb_ext *)&policy, 0) == -1) + goto fail; + + ret = pf_key_v2_call(askpolicy); + if (!ret) + goto fail; + + /* Now we have all the information needed. */ + + ext = pf_key_v2_find_ext(ret, SADB_X_EXT_SRC_FLOW); + if (!ext) { + log_print("pf_key_v2_acquire: no source flow extension found"); + goto fail; + } + sflow = (struct sockaddr *) (((struct sadb_address *) ext->seg) + 1); + + ext = pf_key_v2_find_ext(ret, SADB_X_EXT_DST_FLOW); + if (!ext) { + log_print("pf_key_v2_acquire: " + "no destination flow extension found"); + goto fail; + } + dflow = (struct sockaddr *) (((struct sadb_address *) ext->seg) + 1); + ext = pf_key_v2_find_ext(ret, SADB_X_EXT_SRC_MASK); + if (!ext) { + log_print("pf_key_v2_acquire: no source mask extension found"); + goto fail; + } + smask = (struct sockaddr *) (((struct sadb_address *) ext->seg) + 1); + + ext = pf_key_v2_find_ext(ret, SADB_X_EXT_DST_MASK); + if (!ext) { + log_print("pf_key_v2_acquire: " + "no destination mask extension found"); + goto fail; + } + dmask = (struct sockaddr *) (((struct sadb_address *) ext->seg) + 1); + + ext = pf_key_v2_find_ext(ret, SADB_X_EXT_FLOW_TYPE); + if (!ext) { + log_print("pf_key_v2_acquire: no flow type extension found"); + goto fail; + } + sproto = ext->seg; + tproto = sproto->sadb_protocol_proto; + +#if defined (SADB_X_EXT_LOCAL_CREDENTIALS) + ext = pf_key_v2_find_ext(pmsg, SADB_X_EXT_LOCAL_CREDENTIALS); + if (ext) + cred = (struct sadb_x_cred *) ext->seg; + else + cred = 0; +#endif + +#if defined (SADB_X_EXT_LOCAL_AUTH) + ext = pf_key_v2_find_ext(pmsg, SADB_X_EXT_LOCAL_AUTH); + if (ext) + sauth = (struct sadb_x_cred *) ext->seg; + else + sauth = 0; +#endif + + bzero(ssflow, sizeof ssflow); + bzero(sdflow, sizeof sdflow); + bzero(ssmask, sizeof ssmask); + bzero(sdmask, sizeof sdmask); + + sidtype = didtype = "IPV4_ADDR_SUBNET"; /* default */ + + switch (sflow->sa_family) { + case AF_INET: + if (inet_ntop(AF_INET, + &((struct sockaddr_in *) sflow)->sin_addr, ssflow, + ADDRESS_MAX) == NULL) { + log_print("pf_key_v2_acquire: inet_ntop failed"); + goto fail; + } + sport = ((struct sockaddr_in *) sflow)->sin_port; + if (inet_ntop(AF_INET, + &((struct sockaddr_in *) dflow)->sin_addr, sdflow, + ADDRESS_MAX) == NULL) { + log_print("pf_key_v2_acquire: inet_ntop failed"); + goto fail; + } + dport = ((struct sockaddr_in *) dflow)->sin_port; + if (inet_ntop(AF_INET, + &((struct sockaddr_in *) smask)->sin_addr, ssmask, + ADDRESS_MAX) == NULL) { + log_print("pf_key_v2_acquire: inet_ntop failed"); + goto fail; + } + if (inet_ntop(AF_INET, + &((struct sockaddr_in *) dmask)->sin_addr, sdmask, + ADDRESS_MAX) == NULL) { + log_print("pf_key_v2_acquire: inet_ntop failed"); + goto fail; + } + if (((struct sockaddr_in *) smask)->sin_addr.s_addr == + INADDR_BROADCAST) { + shostflag = 1; + sidtype = "IPV4_ADDR"; + } + if (((struct sockaddr_in *) dmask)->sin_addr.s_addr == + INADDR_BROADCAST) { + dhostflag = 1; + didtype = "IPV4_ADDR"; + } + break; + + case AF_INET6: + if (inet_ntop(AF_INET6, + &((struct sockaddr_in6 *) sflow)->sin6_addr, + ssflow, ADDRESS_MAX) == NULL) { + log_print("pf_key_v2_acquire: inet_ntop failed"); + goto fail; + } + sport = ((struct sockaddr_in6 *) sflow)->sin6_port; + if (inet_ntop(AF_INET6, + &((struct sockaddr_in6 *) dflow)->sin6_addr, + sdflow, ADDRESS_MAX) == NULL) { + log_print("pf_key_v2_acquire: inet_ntop failed"); + goto fail; + } + dport = ((struct sockaddr_in6 *) dflow)->sin6_port; + if (inet_ntop(AF_INET6, + &((struct sockaddr_in6 *) smask)->sin6_addr, + ssmask, ADDRESS_MAX) == NULL) { + log_print("pf_key_v2_acquire: inet_ntop failed"); + goto fail; + } + if (inet_ntop(AF_INET6, + &((struct sockaddr_in6 *) dmask)->sin6_addr, + sdmask, ADDRESS_MAX) == NULL) { + log_print("pf_key_v2_acquire: inet_ntop failed"); + goto fail; + } + sidtype = didtype = "IPV6_ADDR_SUBNET"; + if (IN6_IS_ADDR_FULL(&((struct sockaddr_in6 *)smask)->sin6_addr)) { + shostflag = 1; + sidtype = "IPV6_ADDR"; + } + if (IN6_IS_ADDR_FULL(&((struct sockaddr_in6 *)dmask)->sin6_addr)) { + dhostflag = 1; + didtype = "IPV6_ADDR"; + } + break; + } + + dstaddr = (struct sockaddr *)(dst + 1); + bzero(dstbuf, sizeof dstbuf); + bzero(srcbuf, sizeof srcbuf); + + if (dstaddr->sa_family == 0) { + /* + * Destination was not specified in the flow -- can we derive + * it? + */ + if (dhostflag == 0) { + log_print("pf_key_v2_acquire: " + "Cannot determine precise destination"); + goto fail; + } + dstaddr = dflow; + } + switch (dstaddr->sa_family) { + case AF_INET: + if (inet_ntop(AF_INET, + &((struct sockaddr_in *) dstaddr)->sin_addr, + dstbuf, ADDRESS_MAX) == NULL) { + log_print("pf_key_v2_acquire: inet_ntop failed"); + goto fail; + } + LOG_DBG((LOG_SYSDEP, 20, + "pf_key_v2_acquire: dst=%s sproto %d", dstbuf, + msg->sadb_msg_satype)); + break; + + case AF_INET6: + if (inet_ntop(AF_INET6, + &((struct sockaddr_in6 *) dstaddr)->sin6_addr, + dstbuf, ADDRESS_MAX) == NULL) { + log_print("pf_key_v2_acquire: inet_ntop failed"); + goto fail; + } + LOG_DBG((LOG_SYSDEP, 20, + "pf_key_v2_acquire: dst=%s sproto %d", dstbuf, + msg->sadb_msg_satype)); + break; + } + + if (src) { + srcaddr = (struct sockaddr *) (src + 1); + + switch (srcaddr->sa_family) { + case AF_INET: + if (inet_ntop(AF_INET, + &((struct sockaddr_in *) srcaddr)->sin_addr, + srcbuf, ADDRESS_MAX) == NULL) { + log_print("pf_key_v2_acquire: " + "inet_ntop failed"); + goto fail; + } + break; + + case AF_INET6: + if (inet_ntop(AF_INET6, + &((struct sockaddr_in6 *)srcaddr)->sin6_addr, + srcbuf, ADDRESS_MAX) == NULL) { + log_print("pf_key_v2_acquire: " + "inet_ntop failed"); + goto fail; + } + break; + + default: + /* + * The kernel will pass an all '0' EXT_ADDRESS_SRC if + * it wasn't specified for the flow. In that case, do + * NOT specify the srcaddr in the Peer-name below + */ + srcbuf[0] = 0; + srcaddr = NULL; + break; + } + } + /* Insert source ID. */ + if (srcident) { + slen = (srcident->sadb_ident_len * sizeof(u_int64_t)) + - sizeof(struct sadb_ident); + if (((unsigned char *) (srcident + 1))[slen - 1] != '\0') { + log_print("pf_key_v2_acquire: " + "source identity not NUL-terminated"); + goto fail; + } + /* Check for valid type. */ + switch (srcident->sadb_ident_type) { +#if defined (SADB_X_IDENTTYPE_CONNECTION) + case SADB_X_IDENTTYPE_CONNECTION: + /* XXX */ + break; +#endif + + case SADB_IDENTTYPE_PREFIX: + /* Determine what the address family is. */ + srcid = memchr(srcident + 1, ':', slen); + if (srcid) + afamily = AF_INET6; + else + afamily = AF_INET; + + srcid = memchr(srcident + 1, '/', slen); + if (!srcid) { + log_print("pf_key_v2_acquire: " + "badly formatted PREFIX identity"); + goto fail; + } + masklen = atoi(srcid + 1); + + /* XXX We only support host addresses. */ + if ((afamily == AF_INET6 && masklen != 128) + || (afamily == AF_INET && masklen != 32)) { + log_print("pf_key_v2_acquire: " + "non-host address specified in source " + "identity (mask length %d), ignoring " + "request", masklen); + goto fail; + } + /* + * NUL-terminate the PREFIX string at the separator, + * then dup. + */ + *srcid = '\0'; + slen = strlen((char *) (srcident + 1)) + + sizeof "ID:Address/"; + srcid = malloc(slen); + if (!srcid) { + log_error("pf_key_v2_acquire: " + "malloc (%d) failed", slen); + goto fail; + } + snprintf(srcid, slen, "ID:Address/%s", + (char *) (srcident + 1)); + + /* Set the section if it doesn't already exist. */ + af = conf_begin(); + if (!conf_get_str(srcid, "ID-type")) { + if (conf_set(af, srcid, "ID-type", + afamily == AF_INET ? "IPV4_ADDR" : + "IPV6_ADDR", 1, 0) + || conf_set(af, srcid, "Refcount", "1", 1, + 0) + || conf_set(af, srcid, "Address", + (char *) (srcident + 1), 1, 0)) { + conf_end(af, 0); + goto fail; + } + } else + pf_key_v2_conf_refinc(af, srcid); + conf_end(af, 1); + break; + + case SADB_IDENTTYPE_FQDN: + prefstring = "FQDN"; + /* Fall through */ + case SADB_IDENTTYPE_USERFQDN: + if (!prefstring) { + prefstring = "USER_FQDN"; + + /* + * Check whether there is a string following + * the header; if no, that there is a user ID + * (and acquire the login name). If there is + * both a string and a user ID, check that + * they match. + */ + if ((slen == 0) && + (srcident->sadb_ident_id == 0)) { + log_print("pf_key_v2_acquire: " + "no user FQDN or ID provided"); + goto fail; + } + if (srcident->sadb_ident_id) { + pwd = + getpwuid(srcident->sadb_ident_id); + if (!pwd) { + log_error("pf_key_v2_acquire: " + "could not acquire " + "username from provided " + "ID %llu", + srcident->sadb_ident_id); + goto fail; + } + if (slen != 0) + if (strcmp(pwd->pw_name, + (char *) (srcident + 1)) + != 0) { + log_print("pf_key_v2_acquire: " + "provided user " + "name and ID do " + "not match (%s != " + "%s)", + (char *) (srcident + 1), + pwd->pw_name); + /* + * String has + * precedence, per + * RFC 2367. + */ + } + } + } + buflen = (slen ? slen : strlen(pwd->pw_name)) + + strlen(prefstring) + sizeof "ID:/"; + srcid = malloc(buflen); + if (!srcid) { + log_error("pf_key_v2_acquire: " + "malloc (%d) failed", buflen); + goto fail; + } + snprintf(srcid, buflen, "ID:%s/", prefstring); + if (slen != 0) + strlcat(srcid, + (char *) (srcident + 1), buflen); + else + strlcat(srcid, pwd->pw_name, buflen); + pwd = 0; + + /* Set the section if it doesn't already exist. */ + af = conf_begin(); + if (!conf_get_str(srcid, "ID-type")) { + if (conf_set(af, srcid, "ID-type", prefstring, + 1, 0) + || conf_set(af, srcid, "Refcount", "1", 1, + 0) + || conf_set(af, srcid, "Name", + srcid + sizeof "ID:/" - 1 + + strlen(prefstring), 1, 0)) { + conf_end(af, 0); + goto fail; + } + } else + pf_key_v2_conf_refinc(af, srcid); + conf_end(af, 1); + break; + + default: + LOG_DBG((LOG_SYSDEP, 20, + "pf_key_v2_acquire: invalid source ID type %d", + srcident->sadb_ident_type)); + goto fail; + } + + LOG_DBG((LOG_SYSDEP, 50, + "pf_key_v2_acquire: constructed source ID \"%s\"", srcid)); + prefstring = 0; + } + /* Insert destination ID. */ + if (dstident) { + slen = (dstident->sadb_ident_len * sizeof(u_int64_t)) + - sizeof(struct sadb_ident); + + /* Check for valid type. */ + switch (dstident->sadb_ident_type) { +#if defined (SADB_X_IDENTTYPE_CONNECTION) + case SADB_X_IDENTTYPE_CONNECTION: + /* XXX */ + break; +#endif + + case SADB_IDENTTYPE_PREFIX: + /* Determine what the address family is. */ + dstid = memchr(dstident + 1, ':', slen); + if (dstid) + afamily = AF_INET6; + else + afamily = AF_INET; + + dstid = memchr(dstident + 1, '/', slen); + if (!dstid) { + log_print("pf_key_v2_acquire: " + "badly formatted PREFIX identity"); + goto fail; + } + masklen = atoi(dstid + 1); + + /* XXX We only support host addresses. */ + if ((afamily == AF_INET6 && masklen != 128) + || (afamily == AF_INET && masklen != 32)) { + log_print("pf_key_v2_acquire: " + "non-host address specified in " + "destination identity (mask length %d), " + "ignoring request", masklen); + goto fail; + } + /* + * NUL-terminate the PREFIX string at the separator, + * then dup. + */ + *dstid = '\0'; + slen = strlen((char *) (dstident + 1)) + + sizeof "ID:Address/"; + dstid = malloc(slen); + if (!dstid) { + log_error("pf_key_v2_acquire: " + "malloc (%d) failed", slen); + goto fail; + } + snprintf(dstid, slen, "ID:Address/%s", + (char *) (dstident + 1)); + + /* Set the section if it doesn't already exist. */ + af = conf_begin(); + if (!conf_get_str(dstid, "ID-type")) { + if (conf_set(af, dstid, "ID-type", + afamily == AF_INET ? "IPV4_ADDR" : + "IPV6_ADDR", 1, 0) + || conf_set(af, dstid, "Refcount", "1", 1, + 0) + || conf_set(af, dstid, "Address", + (char *) (dstident + 1), 1, 0)) { + conf_end(af, 0); + goto fail; + } + } else + pf_key_v2_conf_refinc(af, dstid); + conf_end(af, 1); + break; + + case SADB_IDENTTYPE_FQDN: + prefstring = "FQDN"; + /* Fall through */ + + case SADB_IDENTTYPE_USERFQDN: + if (!prefstring) { + prefstring = "USER_FQDN"; + + /* + * Check whether there is a string following + * the header; if no, that there is a user ID + * (and acquire the login name). If there is + * both a string and a user ID, check that + * they match. + */ + if (slen == 0 && + dstident->sadb_ident_id == 0) { + log_print("pf_key_v2_acquire: " + "no user FQDN or ID provided"); + goto fail; + } + if (dstident->sadb_ident_id) { + pwd = getpwuid(dstident->sadb_ident_id); + if (!pwd) { + log_error("pf_key_v2_acquire: " + "could not acquire " + "username from provided " + "ID %llu", + dstident->sadb_ident_id); + goto fail; + } + if (slen != 0) + if (strcmp(pwd->pw_name, + (char *) (dstident + 1)) + != 0) { + log_print("pf_key_v2_acquire: " + "provided user " + "name and ID do " + "not match (%s != " + "%s)", + (char *) (dstident + 1), + pwd->pw_name); + /* + * String has + * precedence, per RF + * 2367. + */ + } + } + } + buflen = (slen ? slen : strlen(pwd->pw_name)) + + strlen(prefstring) + sizeof "ID:/"; + dstid = malloc(buflen); + if (!dstid) { + log_error("pf_key_v2_acquire: " + "malloc (%d) failed", buflen); + goto fail; + } + snprintf(dstid, buflen, "ID:%s/", prefstring); + if (slen != 0) + strlcat(dstid, (char *) (dstident + 1), + buflen); + else + strlcat(dstid, pwd->pw_name, buflen); + pwd = 0; + + /* Set the section if it doesn't already exist. */ + af = conf_begin(); + if (!conf_get_str(dstid, "ID-type")) { + if (conf_set(af, dstid, "ID-type", prefstring, + 1, 0) + || conf_set(af, dstid, "Refcount", "1", 1, + 0) + || conf_set(af, dstid, "Name", + dstid + sizeof "ID:/" - 1 + + strlen(prefstring), 1, 0)) { + conf_end(af, 0); + goto fail; + } + } else + pf_key_v2_conf_refinc(af, dstid); + conf_end(af, 1); + break; + + default: + LOG_DBG((LOG_SYSDEP, 20, "pf_key_v2_acquire: " + "invalid destination ID type %d", + dstident->sadb_ident_type)); + goto fail; + } + + LOG_DBG((LOG_SYSDEP, 50, + "pf_key_v2_acquire: constructed destination ID \"%s\"", + dstid)); + } + /* Now we've placed the necessary IDs in the configuration space. */ + + /* Get a new connection sequence number. */ + for (;; connection_seq++) { + snprintf(conn, connlen, "Connection-%u", connection_seq); + snprintf(configname, sizeof configname, "Config-Phase2-%u", + connection_seq); + + /* Does it exist ? */ + if (!conf_get_str(conn, "Phase") + && !conf_get_str(configname, "Suites")) + break; + } + + /* + * Set the IPsec connection entry. In particular, the following fields: + * - Phase + * - ISAKMP-peer + * - Local-ID/Remote-ID (if provided) + * - Acquire-ID (sequence number of kernel message, e.g., PF_KEYv2) + * - Configuration + * + * Also set the following section: + * [Peer-dstaddr(/srcaddr)(-srcid)(/dstid)] + * with these fields: + * - Phase + * - ID (if provided) + * - Remote-ID (if provided) + * - Local-address (if provided) + * - Address + * - Configuration (if an entry ISAKMP-configuration-dstaddr(/srcaddr) + * exists -- otherwise use the defaults) + */ + + slen = strlen(dstbuf) + strlen(srcbuf) + (srcid ? strlen(srcid) : 0) + + (dstid ? strlen(dstid) : 0) + sizeof "Peer-/-/"; + peer = malloc(slen); + if (!peer) + goto fail; + + /* + * The various cases: + * - Peer-dstaddr + * - Peer-dstaddr/srcaddr + * - Peer-dstaddr/srcaddr-srcid + * - Peer-dstaddr/srcaddr-srcid/dstid + * - Peer-dstaddr/srcaddr-/dstid + * - Peer-dstaddr-srcid/dstid + * - Peer-dstaddr-/dstid + * - Peer-dstaddr-srcid + */ + snprintf(peer, slen, "Peer-%s%s%s%s%s%s%s", dstbuf, srcaddr ? "/" : "", + srcaddr ? srcbuf : "", srcid ? "-" : "", srcid ? srcid : "", + dstid ? (srcid ? "/" : "-/") : "", dstid ? dstid : ""); + + /* + * Set the IPsec connection section. Refcount is set to 2, because + * it will be linked both to the incoming and the outgoing SA. + */ + af = conf_begin(); + if (conf_set(af, conn, "Phase", "2", 0, 0) + || conf_set(af, conn, "Flags", "__ondemand", 0, 0) + || conf_set(af, conn, "Refcount", "2", 0, 0) + || conf_set(af, conn, "ISAKMP-peer", peer, 0, 0)) { + conf_end(af, 0); + goto fail; + } + /* Set the sequence number. */ + snprintf(lname, sizeof lname, "%u", msg->sadb_msg_seq); + if (conf_set(af, conn, "Acquire-ID", lname, 0, 0)) { + conf_end(af, 0); + goto fail; + } + /* Set Phase 2 IDs -- this is the Local-ID section. */ + snprintf(lname, sizeof lname, "Phase2-ID:%s/%s/%u/%u", ssflow, ssmask, + tproto, sport); + if (conf_set(af, conn, "Local-ID", lname, 0, 0)) { + conf_end(af, 0); + goto fail; + } + if (!conf_get_str(lname, "ID-type")) { + if (conf_set(af, lname, "Refcount", "1", 0, 0)) { + conf_end(af, 0); + goto fail; + } + if (shostflag) { + if (conf_set(af, lname, "ID-type", sidtype, 0, 0) + || conf_set(af, lname, "Address", ssflow, 0, 0)) { + conf_end(af, 0); + goto fail; + } + } else { + if (conf_set(af, lname, "ID-type", sidtype, 0, 0) + || conf_set(af, lname, "Network", ssflow, 0, 0) + || conf_set(af, lname, "Netmask", ssmask, 0, 0)) { + conf_end(af, 0); + goto fail; + } + } + if (tproto) { + snprintf(tmbuf, sizeof sport * 3 + 1, "%u", tproto); + if (conf_set(af, lname, "Protocol", tmbuf, 0, 0)) { + conf_end(af, 0); + goto fail; + } + if (sport) { + snprintf(tmbuf, sizeof sport * 3 + 1, "%u", + ntohs(sport)); + if (conf_set(af, lname, "Port", tmbuf, 0, 0)) { + conf_end(af, 0); + goto fail; + } + } + } + } else + pf_key_v2_conf_refinc(af, lname); + + /* Set Remote-ID section. */ + snprintf(dname, sizeof dname, "Phase2-ID:%s/%s/%u/%u", sdflow, sdmask, + tproto, dport); + if (conf_set(af, conn, "Remote-ID", dname, 0, 0)) { + conf_end(af, 0); + goto fail; + } + if (!conf_get_str(dname, "ID-type")) { + if (conf_set(af, dname, "Refcount", "1", 0, 0)) { + conf_end(af, 0); + goto fail; + } + if (dhostflag) { + if (conf_set(af, dname, "ID-type", didtype, 0, 0) + || conf_set(af, dname, "Address", sdflow, 0, 0)) { + conf_end(af, 0); + goto fail; + } + } else { + if (conf_set(af, dname, "ID-type", didtype, 0, 0) + || conf_set(af, dname, "Network", sdflow, 0, 0) + || conf_set(af, dname, "Netmask", sdmask, 0, 0)) { + conf_end(af, 0); + goto fail; + } + } + + if (tproto) { + snprintf(tmbuf, sizeof dport * 3 + 1, "%u", tproto); + if (conf_set(af, dname, "Protocol", tmbuf, 0, 0)) { + conf_end(af, 0); + goto fail; + } + if (dport) { + snprintf(tmbuf, sizeof dport * 3 + 1, "%u", + ntohs(dport)); + if (conf_set(af, dname, "Port", tmbuf, 0, 0)) { + conf_end(af, 0); + goto fail; + } + } + } + } else + pf_key_v2_conf_refinc(af, dname); + + /* + * XXX + * We should be using information from the proposal to set this up. + * At least, we should make this selectable. + */ + + /* Phase 2 configuration. */ + if (conf_set(af, conn, "Configuration", configname, 0, 0)) { + conf_end(af, 0); + goto fail; + } + if (conf_set(af, configname, "Exchange_type", "Quick_mode", 0, 0) + || conf_set(af, configname, "DOI", "IPSEC", 0, 0)) { + conf_end(af, 0); + goto fail; + } + if (conf_get_str("General", "Default-phase-2-suites")) { + if (conf_set(af, configname, "Suites", + conf_get_str("General", "Default-phase-2-suites"), 0, 0)) { + conf_end(af, 0); + goto fail; + } + } else { + if (conf_set(af, configname, "Suites", + "QM-ESP-3DES-SHA-PFS-SUITE", 0, 0)) { + conf_end(af, 0); + goto fail; + } + } + + /* Set the ISAKMP-peer section. */ + if (!conf_get_str(peer, "Phase")) { + if (conf_set(af, peer, "Phase", "1", 0, 0) + || conf_set(af, peer, "Refcount", "1", 0, 0) + || conf_set(af, peer, "Address", dstbuf, 0, 0)) { + conf_end(af, 0); + goto fail; + } + if (srcaddr && conf_set(af, peer, "Local-address", srcbuf, 0, + 0)) { + conf_end(af, 0); + goto fail; + } + snprintf(confname, sizeof confname, "ISAKMP-Configuration-%s", + peer); + if (conf_set(af, peer, "Configuration", confname, 0, 0)) { + conf_end(af, 0); + goto fail; + } +#if defined (SADB_X_CREDTYPE_NONE) + /* Store any credentials passed to us. */ + if (cred) { + struct cert_handler *handler = 0; + void *cert; + char num[12], *certprint; + + /* Convert to bytes in-place. */ + cred->sadb_x_cred_len *= PF_KEY_V2_CHUNK; + + if (cred->sadb_x_cred_len <= sizeof *cred) { + log_print("pf_key_v2_acquire: " + "zero-length credentials, aborting SA " + "acquisition"); + conf_end(af, 0); + goto fail; + } + switch (cred->sadb_x_cred_type) { + case SADB_X_CREDTYPE_X509: + snprintf(num, sizeof num, "%d", + ISAKMP_CERTENC_X509_SIG); + handler = cert_get(ISAKMP_CERTENC_X509_SIG); + break; + case SADB_X_CREDTYPE_KEYNOTE: + snprintf(num, sizeof num, "%d", + ISAKMP_CERTENC_KEYNOTE); + handler = cert_get(ISAKMP_CERTENC_KEYNOTE); + break; + default: + log_print("pf_key_v2_acquire: " + "unknown credential type %d", + cred->sadb_x_cred_type); + conf_end(af, 0); + goto fail; + } + + if (!handler) { + log_print("pf_key_v2_acquire: " + "cert_get (%s) failed", num); + conf_end(af, 0); + goto fail; + } + /* Set the credential type as a number. */ + if (conf_set(af, peer, "Credential_type", num, 0, 0)) { + conf_end(af, 0); + goto fail; + } + /* Get the certificate. */ + cert = handler->cert_get((u_int8_t *) (cred + 1), + cred->sadb_x_cred_len - sizeof *cred); + + /* Now convert to printable format. */ + certprint = handler->cert_printable(cert); + handler->cert_free(cert); + if (!certprint + || conf_set(af, peer, "Credentials", certprint, 0, + 0)) { + if (certprint) + free(certprint); + conf_end(af, 0); + goto fail; + } + free(certprint); + } +#endif /* SADB_X_CREDTYPE_NONE */ + + /* Phase 1 configuration. */ + if (!conf_get_str(confname, "exchange_type")) { +#if defined (SADB_X_EXT_LOCAL_AUTH) + /* + * We may have been provided with authentication + * material. + */ + if (sauth) { + char *authm; + + /* Convert to bytes in-place. */ + sauth->sadb_x_cred_len *= PF_KEY_V2_CHUNK; + + switch (sauth->sadb_x_cred_type) { + case SADB_X_AUTHTYPE_PASSPHRASE: + if (conf_set(af, confname, + "Transforms", "3DES-SHA", 0, 0)) { + conf_end(af, 0); + goto fail; + } + if (sauth->sadb_x_cred_len <= + sizeof *sauth) { + log_print("pf_key_v2_acquire: " + "zero-length passphrase, " + "aborting SA acquisition"); + conf_end(af, 0); + goto fail; + } + authm = malloc(sauth->sadb_x_cred_len - + sizeof *sauth + 1); + if (!authm) { + log_error("pf_key_v2_acquire: " + "malloc (%lu) failed", + sauth->sadb_x_cred_len - + (unsigned long) sizeof *sauth + 1); + conf_end(af, 0); + goto fail; + } + memcpy(authm, sauth + 1, + sauth->sadb_x_cred_len - + sizeof *sauth + 1); + + /* Set the passphrase in the peer. */ + if (conf_set(af, peer, + "Authentication", authm, 0, 0)) { + free(authm); + conf_end(af, 0); + goto fail; + } + free(authm); + break; + + case SADB_X_AUTHTYPE_RSA: + if (conf_set(af, confname, + "Transforms", "3DES-SHA-RSA_SIG", + 0, 0)) { + conf_end(af, 0); + goto fail; + } + if (sauth->sadb_x_cred_len <= + sizeof *sauth) { + log_print("pf_key_v2_acquire: " + "zero-length RSA key, " + "aborting SA acquisition"); + conf_end(af, 0); + goto fail; + } + authm = key_printable(ISAKMP_KEY_RSA, + ISAKMP_KEYTYPE_PRIVATE, + (u_int8_t *) sauth + 1, + sauth->sadb_x_cred_len - + sizeof *sauth); + if (!authm) { + log_print("pf_key_v2_acquire: " + "failed to convert " + "private key to printable " + "format (size %lu)", + sauth->sadb_x_cred_len - + (unsigned long) sizeof *sauth); + conf_end(af, 0); + goto fail; + } + /* + * Set the key in the peer. We don't + * use "Authentication" to avoid + * potential conflicts with file-based + * configurations that use public key + * authentication but still specify + * an "Authentication" tag (typically + * as a remnant of passphrase-based + * testing). + */ + if (conf_set(af, peer, + "PKAuthentication", authm, 0, 0)) { + free(authm); + conf_end(af, 0); + goto fail; + } + free(authm); + break; + + default: + log_print("pf_key_v2_acquire: " + "unknown authentication " + "material type %d received from " + "kernel", sauth->sadb_x_cred_type); + conf_end(af, 0); + goto fail; + } + } else /* Fall through */ +#endif /* SADB_X_EXT_LOCAL_AUTH */ + { + xform = conf_get_str( + "Default-phase-1-configuration", + "Transforms"); + if (conf_set(af, confname, "Transforms", + xform ? xform : "3DES-SHA-RSA_SIG", 0, + 0)) { + conf_end(af, 0); + goto fail; + } + } + + if (conf_set(af, confname, "Exchange_Type", "ID_PROT", + 0, 0) + || conf_set(af, confname, "DOI", "IPSEC", 0, 0) + || conf_set(af, confname, "Refcount", "1", 0, 0)) { + conf_end(af, 0); + goto fail; + } + } else + pf_key_v2_conf_refinc(af, confname); + + /* The ID we should use in Phase 1. */ + if (srcid && conf_set(af, peer, "ID", srcid, 0, 0)) { + conf_end(af, 0); + goto fail; + } + /* The ID the other side should use in Phase 1. */ + if (dstid && conf_set(af, peer, "Remote-ID", dstid, 0, 0)) { + conf_end(af, 0); + goto fail; + } + } else + pf_key_v2_conf_refinc(af, peer); + + /* All done. */ + conf_end(af, 1); + + /* Let's rock 'n roll. */ + pf_key_v2_connection_check(conn); + conn = 0; + + /* Fall-through to cleanup. */ +fail: + if (ret) + pf_key_v2_msg_free(ret); + if (askpolicy) + pf_key_v2_msg_free(askpolicy); + if (srcid) + free(srcid); + if (dstid) + free(dstid); + if (peer) + free(peer); + if (conn) + free(conn); + return; +#else + /* acquire not supported */ + return; +#endif /* SADB_X_ASKPOLICY */ +} + +static void +pf_key_v2_notify(struct pf_key_v2_msg *msg) +{ + switch (((struct sadb_msg *)TAILQ_FIRST(msg)->seg)->sadb_msg_type) { + case SADB_EXPIRE: + pf_key_v2_expire(msg); + break; + + case SADB_ACQUIRE: + pf_key_v2_acquire(msg); + break; + + default: + log_print("pf_key_v2_notify: unexpected message type (%d)", + ((struct sadb_msg *)TAILQ_FIRST(msg)->seg)->sadb_msg_type); + } + pf_key_v2_msg_free(msg); +} + +void +pf_key_v2_handler(int fd) +{ + struct pf_key_v2_msg *msg; +#if !defined (LINUX_IPSEC) + int n; + + /* + * As synchronous read/writes to the socket can have taken place + * between the select(2) call of the main loop and this handler, we + * need to recheck the readability. + */ + if (ioctl(pf_key_v2_socket, FIONREAD, &n) == -1) { + log_error("pf_key_v2_handler: ioctl (%d, FIONREAD, &n) failed", + pf_key_v2_socket); + return; + } + if (!n) + return; +#endif /* LINUX_IPSEC */ + + msg = pf_key_v2_read(0); + if (msg) + pf_key_v2_notify(msg); +} + +/* + * Group 2 IPsec SAs given by the PROTO1 and PROTO2 protocols of the SA IKE + * security association in a chain. + * XXX Assumes OpenBSD GRPSPIS extension. Should probably be moved to sysdep.c + */ +int +pf_key_v2_group_spis(struct sa *sa, struct proto *proto1, + struct proto *proto2, int incoming) +{ +#if defined (SADB_X_GRPSPIS) + struct sadb_msg msg; + struct sadb_sa sa1, sa2; + struct sadb_address *addr = 0; + struct sadb_protocol protocol; + struct pf_key_v2_msg *grpspis = 0, *ret = 0; + struct sockaddr *saddr; + int err; + size_t len; +#ifdef KAME + struct sadb_x_sa2 kamesa2; +#endif + + msg.sadb_msg_type = SADB_X_GRPSPIS; + switch (proto1->proto) { + case IPSEC_PROTO_IPSEC_ESP: + msg.sadb_msg_satype = SADB_SATYPE_ESP; + break; + case IPSEC_PROTO_IPSEC_AH: + msg.sadb_msg_satype = SADB_SATYPE_AH; + break; +#if defined (SADB_X_SATYPE_IPCOMP) + case IPSEC_PROTO_IPCOMP: + msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP; + break; +#endif + default: + log_print("pf_key_v2_group_spis: invalid proto %d", + proto1->proto); + goto cleanup; + } + msg.sadb_msg_seq = 0; + grpspis = pf_key_v2_msg_new(&msg, 0); + if (!grpspis) + goto cleanup; + + /* Setup the SA extensions. */ + sa1.sadb_sa_exttype = SADB_EXT_SA; + sa1.sadb_sa_len = sizeof sa1 / PF_KEY_V2_CHUNK; + memcpy(&sa1.sadb_sa_spi, proto1->spi[incoming], + sizeof sa1.sadb_sa_spi); + sa1.sadb_sa_replay = 0; + sa1.sadb_sa_state = 0; + sa1.sadb_sa_auth = 0; + sa1.sadb_sa_encrypt = 0; + sa1.sadb_sa_flags = 0; + if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *)&sa1, 0) == -1) + goto cleanup; + +#ifndef KAME + sa2.sadb_sa_exttype = SADB_X_EXT_SA2; + sa2.sadb_sa_len = sizeof sa2 / PF_KEY_V2_CHUNK; + memcpy(&sa2.sadb_sa_spi, proto2->spi[incoming], + sizeof sa2.sadb_sa_spi); + sa2.sadb_sa_replay = 0; + sa2.sadb_sa_state = 0; + sa2.sadb_sa_auth = 0; + sa2.sadb_sa_encrypt = 0; + sa2.sadb_sa_flags = 0; + if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *)&sa2, 0) == -1) + goto cleanup; +#else + memset(&kamesa2, 0, sizeof kamesa2); + kamesa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; + kamesa2.sadb_x_sa2_len = sizeof kamesa2 / PF_KEY_V2_CHUNK; + kamesa2.sadb_x_sa2_mode = 0; + if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *)&kamesa2, 0) == -1) + goto cleanup; +#endif + + /* + * Setup the ADDRESS extensions. + */ + if (incoming) + sa->transport->vtbl->get_src(sa->transport, &saddr); + else + sa->transport->vtbl->get_dst(sa->transport, &saddr); + len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(saddr)); + addr = calloc(1, len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#ifndef __OpenBSD__ + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memcpy(addr + 1, saddr, sysdep_sa_len(saddr)); + ((struct sockaddr_in *) (addr + 1))->sin_port = 0; + if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *) addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + + addr = calloc(1, len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_X_EXT_DST2; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#ifndef __OpenBSD__ + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memcpy(addr + 1, saddr, sysdep_sa_len(saddr)); + ((struct sockaddr_in *) (addr + 1))->sin_port = 0; + if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *) addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + + /* Setup the PROTOCOL extension. */ + protocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL; + protocol.sadb_protocol_len = sizeof protocol / PF_KEY_V2_CHUNK; + switch (proto2->proto) { + case IPSEC_PROTO_IPSEC_ESP: + protocol.sadb_protocol_proto = SADB_SATYPE_ESP; + break; + case IPSEC_PROTO_IPSEC_AH: + protocol.sadb_protocol_proto = SADB_SATYPE_AH; + break; +#if defined (SADB_X_SATYPE_IPCOMP) + case IPSEC_PROTO_IPCOMP: + protocol.sadb_protocol_proto = SADB_X_SATYPE_IPCOMP; + break; +#endif + default: + log_print("pf_key_v2_group_spis: invalid proto %d", + proto2->proto); + goto cleanup; + } + protocol.sadb_protocol_reserved2 = 0; + if (pf_key_v2_msg_add(grpspis, + (struct sadb_ext *)&protocol, 0) == -1) + goto cleanup; + + ret = pf_key_v2_call(grpspis); + pf_key_v2_msg_free(grpspis); + grpspis = 0; + if (!ret) + goto cleanup; + err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; + if (err) { + log_print("pf_key_v2_group_spis: GRPSPIS: %s", strerror(err)); + goto cleanup; + } + pf_key_v2_msg_free(ret); + + LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_group_spis: done")); + + return 0; + +cleanup: + if (addr) + free(addr); + if (grpspis) + pf_key_v2_msg_free(grpspis); + if (ret) + pf_key_v2_msg_free(ret); + return -1; + +#else /* SADB_X_GRPSPIS */ + log_print("pf_key_v2_group_spis: not supported in pure PF_KEYv2"); + return -1; +#endif +} diff --git a/keyexchange/isakmpd-20041012/pf_key_v2.h b/keyexchange/isakmpd-20041012/pf_key_v2.h new file mode 100644 index 0000000..8eaed1a --- /dev/null +++ b/keyexchange/isakmpd-20041012/pf_key_v2.h @@ -0,0 +1,61 @@ +/* $OpenBSD: pf_key_v2.h,v 1.12 2004/08/10 15:59:10 ho Exp $ */ +/* $EOM: pf_key_v2.h,v 1.4 2000/12/04 04:46:35 angelos Exp $ */ + +/* + * Copyright (c) 1999 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. + * + * 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_KEY_V2_H_ +#define _PF_KEY_V2_H_ + +#include <sys/types.h> +#include <sys/queue.h> + +struct proto; +struct sa; +struct sockaddr; +struct kernel_sa; + +extern int pf_key_v2_socket; + +extern void pf_key_v2_connection_check(char *); +extern int pf_key_v2_delete_spi(struct sa *, struct proto *, int); +extern int pf_key_v2_enable_sa(struct sa *, struct sa *); +extern int pf_key_v2_enable_spi(in_addr_t, in_addr_t, in_addr_t, + in_addr_t, u_int8_t *, u_int8_t, in_addr_t); +extern struct sa_kinfo *pf_key_v2_get_kernel_sa(u_int8_t *, size_t, u_int8_t, + struct sockaddr *); +extern u_int8_t *pf_key_v2_get_spi(size_t *, u_int8_t, struct sockaddr *, + struct sockaddr *, u_int32_t); +extern int pf_key_v2_group_spis(struct sa *, struct proto *, + struct proto *, int); +extern void pf_key_v2_handler(int); +extern int pf_key_v2_open(void); +extern int pf_key_v2_set_spi(struct sa *, struct proto *, int, + struct sa *); + +#endif /* _PF_KEY_V2_H_ */ diff --git a/keyexchange/isakmpd-20041012/policy.c b/keyexchange/isakmpd-20041012/policy.c new file mode 100644 index 0000000..279b3a1 --- /dev/null +++ b/keyexchange/isakmpd-20041012/policy.c @@ -0,0 +1,2318 @@ +/* $OpenBSD: policy.c,v 1.78 2004/08/08 19:11:06 deraadt Exp $ */ +/* $EOM: policy.c,v 1.49 2000/10/24 13:33:39 niklas Exp $ */ + +/* + * Copyright (c) 1999, 2000, 2001 Angelos D. Keromytis. All rights reserved. + * Copyright (c) 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2001 Håkan Olsson. 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. + * + * 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/param.h> +#include <sys/mman.h> +#include <sys/queue.h> +#include <sys/stat.h> +#include <regex.h> +#include <ctype.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <keynote.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <errno.h> +#include <openssl/ssl.h> +#include <netdb.h> + +#include "sysdep.h" + +#include "conf.h" +#include "exchange.h" +#include "ipsec.h" +#include "isakmp_doi.h" +#include "sa.h" +#include "transport.h" +#include "log.h" +#include "message.h" +#include "monitor.h" +#include "util.h" +#include "policy.h" +#include "x509.h" + +char **policy_asserts = NULL; +int ignore_policy = 0; +int policy_asserts_num = 0; +struct exchange *policy_exchange = 0; +struct sa *policy_sa = 0; +struct sa *policy_isakmp_sa = 0; + +static const char hextab[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' +}; + +/* + * Adaptation of Vixie's inet_ntop4 () + */ +static const char * +my_inet_ntop4(const in_addr_t *src, char *dst, size_t size, int normalize) +{ + static const char fmt[] = "%03u.%03u.%03u.%03u"; + char tmp[sizeof "255.255.255.255"]; + in_addr_t src2; + + if (normalize) + src2 = ntohl(*src); + else + src2 = *src; + + if (snprintf(tmp, sizeof tmp, fmt, ((u_int8_t *)&src2)[0], + ((u_int8_t *)&src2)[1], ((u_int8_t *)&src2)[2], + ((u_int8_t *)&src2)[3]) > (int)size) { + errno = ENOSPC; + return 0; + } + strlcpy(dst, tmp, size); + return dst; +} + +static const char * +my_inet_ntop6(const unsigned char *src, char *dst, size_t size) +{ + static const char fmt[] = + "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x"; + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"]; + + if (snprintf(tmp, sizeof tmp, fmt, src[0], src[1], src[2], src[3], + src[4], src[5], src[6], src[7], src[8], src[9], src[10], src[11], + src[12], src[13], src[14], src[15]) > (int)size) { + errno = ENOSPC; + return 0; + } + strlcpy(dst, tmp, size); + return dst; +} + +char * +policy_callback(char *name) +{ + struct proto *proto; + + u_int8_t *attr, *value, *id, *idlocal, *idremote; + size_t id_sz, idlocalsz, idremotesz; + struct sockaddr *sin; + struct ipsec_exch *ie; + struct ipsec_sa *is; + size_t i; + int fmt, lifetype = 0; + in_addr_t net, subnet; + u_int16_t len, type; + time_t tt; + char *addr; + static char mytimeofday[15]; + + /* We use all these as a cache. */ +#define PMAX 32 + static char *esp_present, *ah_present, *comp_present; + static char *ah_hash_alg, *ah_auth_alg, *esp_auth_alg, *esp_enc_alg; + static char *comp_alg, ah_life_kbytes[PMAX], ah_life_seconds[PMAX]; + static char esp_life_kbytes[PMAX], esp_life_seconds[PMAX]; + static char comp_life_kbytes[PMAX]; + static char *ah_ecn, *esp_ecn, *comp_ecn; + static char comp_life_seconds[PMAX], *ah_encapsulation; + static char *esp_encapsulation, *comp_encapsulation; + static char ah_key_length[PMAX], esp_key_length[PMAX]; + static char ah_key_rounds[PMAX], esp_key_rounds[PMAX]; + static char comp_dict_size[PMAX], comp_private_alg[PMAX]; + static char *remote_filter_type, *local_filter_type; + static char remote_filter_addr_upper[NI_MAXHOST]; + static char remote_filter_addr_lower[NI_MAXHOST]; + static char local_filter_addr_upper[NI_MAXHOST]; + static char local_filter_addr_lower[NI_MAXHOST]; + static char ah_group_desc[PMAX], esp_group_desc[PMAX]; + static char comp_group_desc[PMAX], remote_ike_address[NI_MAXHOST]; + static char local_ike_address[NI_MAXHOST]; + static char *remote_id_type, remote_id_addr_upper[NI_MAXHOST]; + static char *phase_1, remote_id_addr_lower[NI_MAXHOST]; + static char *remote_id_proto, remote_id_port[PMAX]; + static char remote_filter_port[PMAX], local_filter_port[PMAX]; + static char *remote_filter_proto, *local_filter_proto, *pfs; + static char *initiator, remote_filter_proto_num[3]; + static char local_filter_proto_num[3], remote_id_proto_num[3]; + static char phase1_group[PMAX]; + + /* Allocated. */ + static char *remote_filter = 0, *local_filter = 0, *remote_id = 0; + + static int dirty = 1; + + /* We only need to set dirty at initialization time really. */ + if (strcmp(name, KEYNOTE_CALLBACK_CLEANUP) == 0 + || strcmp(name, KEYNOTE_CALLBACK_INITIALIZE) == 0) { + esp_present = ah_present = comp_present = pfs = "no"; + ah_hash_alg = ah_auth_alg = phase_1 = ""; + esp_auth_alg = esp_enc_alg = comp_alg = ah_encapsulation = ""; + ah_ecn = esp_ecn = comp_ecn = "no"; + esp_encapsulation = comp_encapsulation = ""; + remote_filter_type = ""; + local_filter_type = remote_id_type = initiator = ""; + remote_filter_proto = local_filter_proto = ""; + remote_id_proto = ""; + + if (remote_filter != 0) { + free(remote_filter); + remote_filter = 0; + } + if (local_filter != 0) { + free(local_filter); + local_filter = 0; + } + if (remote_id != 0) { + free(remote_id); + remote_id = 0; + } + memset(remote_ike_address, 0, sizeof remote_ike_address); + memset(local_ike_address, 0, sizeof local_ike_address); + memset(ah_life_kbytes, 0, sizeof ah_life_kbytes); + memset(ah_life_seconds, 0, sizeof ah_life_seconds); + memset(esp_life_kbytes, 0, sizeof esp_life_kbytes); + memset(esp_life_seconds, 0, sizeof esp_life_seconds); + memset(comp_life_kbytes, 0, sizeof comp_life_kbytes); + memset(comp_life_seconds, 0, sizeof comp_life_seconds); + memset(ah_key_length, 0, sizeof ah_key_length); + memset(ah_key_rounds, 0, sizeof ah_key_rounds); + memset(esp_key_length, 0, sizeof esp_key_length); + memset(esp_key_rounds, 0, sizeof esp_key_rounds); + memset(comp_dict_size, 0, sizeof comp_dict_size); + memset(comp_private_alg, 0, sizeof comp_private_alg); + memset(remote_filter_addr_upper, 0, + sizeof remote_filter_addr_upper); + memset(remote_filter_addr_lower, 0, + sizeof remote_filter_addr_lower); + memset(local_filter_addr_upper, 0, + sizeof local_filter_addr_upper); + memset(local_filter_addr_lower, 0, + sizeof local_filter_addr_lower); + memset(remote_id_addr_upper, 0, sizeof remote_id_addr_upper); + memset(remote_id_addr_lower, 0, sizeof remote_id_addr_lower); + memset(ah_group_desc, 0, sizeof ah_group_desc); + memset(esp_group_desc, 0, sizeof esp_group_desc); + memset(remote_id_port, 0, sizeof remote_id_port); + memset(remote_filter_port, 0, sizeof remote_filter_port); + memset(local_filter_port, 0, sizeof local_filter_port); + memset(phase1_group, 0, sizeof phase1_group); + + dirty = 1; + return ""; + } + /* + * If dirty is set, this is the first request for an attribute, so + * populate our value cache. + */ + if (dirty) { + ie = policy_exchange->data; + + if (ie->pfs) + pfs = "yes"; + + is = policy_isakmp_sa->data; + snprintf(phase1_group, sizeof phase1_group, "%u", + is->group_desc); + + for (proto = TAILQ_FIRST(&policy_sa->protos); proto; + proto = TAILQ_NEXT(proto, link)) { + switch (proto->proto) { + case IPSEC_PROTO_IPSEC_AH: + ah_present = "yes"; + switch (proto->id) { + case IPSEC_AH_MD5: + ah_hash_alg = "md5"; + break; + + case IPSEC_AH_SHA: + ah_hash_alg = "sha"; + break; + + case IPSEC_AH_RIPEMD: + ah_hash_alg = "ripemd"; + break; + + case IPSEC_AH_SHA2_256: + ah_auth_alg = "sha2-256"; + break; + + case IPSEC_AH_SHA2_384: + ah_auth_alg = "sha2-384"; + break; + + case IPSEC_AH_SHA2_512: + ah_auth_alg = "sha2-512"; + break; + + case IPSEC_AH_DES: + ah_hash_alg = "des"; + break; + } + + break; + + case IPSEC_PROTO_IPSEC_ESP: + esp_present = "yes"; + switch (proto->id) { + case IPSEC_ESP_DES_IV64: + esp_enc_alg = "des-iv64"; + break; + + case IPSEC_ESP_DES: + esp_enc_alg = "des"; + break; + + case IPSEC_ESP_3DES: + esp_enc_alg = "3des"; + break; + + case IPSEC_ESP_AES: + case IPSEC_ESP_AES_128_CTR: + esp_enc_alg = "aes"; + break; + + case IPSEC_ESP_RC5: + esp_enc_alg = "rc5"; + break; + + case IPSEC_ESP_IDEA: + esp_enc_alg = "idea"; + break; + + case IPSEC_ESP_CAST: + esp_enc_alg = "cast"; + break; + + case IPSEC_ESP_BLOWFISH: + esp_enc_alg = "blowfish"; + break; + + case IPSEC_ESP_3IDEA: + esp_enc_alg = "3idea"; + break; + + case IPSEC_ESP_DES_IV32: + esp_enc_alg = "des-iv32"; + break; + + case IPSEC_ESP_RC4: + esp_enc_alg = "rc4"; + break; + + case IPSEC_ESP_NULL: + esp_enc_alg = "null"; + break; + } + + break; + + case IPSEC_PROTO_IPCOMP: + comp_present = "yes"; + switch (proto->id) { + case IPSEC_IPCOMP_OUI: + comp_alg = "oui"; + break; + + case IPSEC_IPCOMP_DEFLATE: + comp_alg = "deflate"; + break; + + case IPSEC_IPCOMP_LZS: + comp_alg = "lzs"; + break; + + case IPSEC_IPCOMP_V42BIS: + comp_alg = "v42bis"; + break; + } + + break; + } + + for (attr = proto->chosen->p + + ISAKMP_TRANSFORM_SA_ATTRS_OFF; + attr < proto->chosen->p + + GET_ISAKMP_GEN_LENGTH(proto->chosen->p); + attr = value + len) { + if (attr + ISAKMP_ATTR_VALUE_OFF > + (proto->chosen->p + + GET_ISAKMP_GEN_LENGTH(proto->chosen->p))) + return ""; + + 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 > proto->chosen->p + + GET_ISAKMP_GEN_LENGTH(proto->chosen->p)) + return ""; + + switch (type) { + case IPSEC_ATTR_SA_LIFE_TYPE: + lifetype = decode_16(value); + break; + + case IPSEC_ATTR_SA_LIFE_DURATION: + switch (proto->proto) { + case IPSEC_PROTO_IPSEC_AH: + if (lifetype == IPSEC_DURATION_SECONDS) { + if (len == 2) + snprintf(ah_life_seconds, sizeof ah_life_seconds, + "%u", decode_16(value)); + else + snprintf(ah_life_seconds, sizeof ah_life_seconds, + "%u", decode_32(value)); + } else { + if (len == 2) + snprintf(ah_life_kbytes, sizeof ah_life_kbytes, + "%u", decode_16(value)); + else + snprintf(ah_life_kbytes, sizeof ah_life_kbytes, + "%u", decode_32(value)); + } + + break; + + case IPSEC_PROTO_IPSEC_ESP: + if (lifetype == IPSEC_DURATION_SECONDS) { + if (len == 2) + snprintf(esp_life_seconds, + sizeof esp_life_seconds, "%u", + decode_16(value)); + else + snprintf(esp_life_seconds, + sizeof esp_life_seconds, "%u", + decode_32(value)); + } else { + if (len == 2) + snprintf(esp_life_kbytes, + sizeof esp_life_kbytes, "%u", + decode_16(value)); + else + snprintf(esp_life_kbytes, + sizeof esp_life_kbytes, "%u", + decode_32(value)); + } + + break; + + case IPSEC_PROTO_IPCOMP: + if (lifetype == IPSEC_DURATION_SECONDS) { + if (len == 2) + snprintf(comp_life_seconds, + sizeof comp_life_seconds, "%u", + decode_16(value)); + else + snprintf(comp_life_seconds, + sizeof comp_life_seconds, "%u", + decode_32(value)); + } else { + if (len == 2) + snprintf(comp_life_kbytes, + sizeof comp_life_kbytes, "%u", + decode_16(value)); + else + snprintf(comp_life_kbytes, + sizeof comp_life_kbytes, "%u", + decode_32(value)); + } + break; + } + break; + + case IPSEC_ATTR_GROUP_DESCRIPTION: + switch (proto->proto) { + case IPSEC_PROTO_IPSEC_AH: + snprintf(ah_group_desc, + sizeof ah_group_desc, "%u", + decode_16(value)); + break; + + case IPSEC_PROTO_IPSEC_ESP: + snprintf(esp_group_desc, + sizeof esp_group_desc, "%u", + decode_16(value)); + break; + + case IPSEC_PROTO_IPCOMP: + snprintf(comp_group_desc, + sizeof comp_group_desc, "%u", + decode_16(value)); + break; + } + break; + + case IPSEC_ATTR_ECN_TUNNEL: + if (decode_16(value)) + switch (proto->proto) { + case IPSEC_PROTO_IPSEC_AH: + ah_ecn = "yes"; + break; + + case IPSEC_PROTO_IPSEC_ESP: + esp_ecn = "yes"; + break; + + case IPSEC_PROTO_IPCOMP: + comp_ecn = "yes"; + break; + } + + case IPSEC_ATTR_ENCAPSULATION_MODE: + if (decode_16(value) == IPSEC_ENCAP_TUNNEL) + switch (proto->proto) { + case IPSEC_PROTO_IPSEC_AH: + ah_encapsulation = "tunnel"; + break; + + case IPSEC_PROTO_IPSEC_ESP: + esp_encapsulation = "tunnel"; + break; + + case IPSEC_PROTO_IPCOMP: + comp_encapsulation = "tunnel"; + break; + } +#if defined (USE_NAT_TRAVERSAL) + else if (decode_16(value) == + IPSEC_ENCAP_UDP_ENCAP_TUNNEL || + decode_16(value) == + IPSEC_ENCAP_UDP_ENCAP_TUNNEL_DRAFT) + switch (proto->proto) { + case IPSEC_PROTO_IPSEC_AH: + ah_encapsulation = "udp-encap-tunnel"; + break; + + case IPSEC_PROTO_IPSEC_ESP: + esp_encapsulation = "udp-encap-tunnel"; + break; + + case IPSEC_PROTO_IPCOMP: + comp_encapsulation = "udp-encap-tunnel"; + break; + } + /* XXX IPSEC_ENCAP_UDP_ENCAP_TRANSPORT */ +#endif + else + switch (proto->proto) { + case IPSEC_PROTO_IPSEC_AH: + ah_encapsulation = "transport"; + break; + + case IPSEC_PROTO_IPSEC_ESP: + esp_encapsulation = "transport"; + break; + + case IPSEC_PROTO_IPCOMP: + comp_encapsulation = "transport"; + break; + } + break; + + case IPSEC_ATTR_AUTHENTICATION_ALGORITHM: + switch (proto->proto) { + case IPSEC_PROTO_IPSEC_AH: + switch (decode_16(value)) { + case IPSEC_AUTH_HMAC_MD5: + ah_auth_alg = "hmac-md5"; + break; + + case IPSEC_AUTH_HMAC_SHA: + ah_auth_alg = "hmac-sha"; + break; + + case IPSEC_AUTH_HMAC_RIPEMD: + ah_auth_alg = "hmac-ripemd"; + break; + + case IPSEC_AUTH_HMAC_SHA2_256: + ah_auth_alg = "hmac-sha2-256"; + break; + + case IPSEC_AUTH_HMAC_SHA2_384: + ah_auth_alg = "hmac-sha2-384"; + break; + + case IPSEC_AUTH_HMAC_SHA2_512: + ah_auth_alg = "hmac-sha2-512"; + break; + + case IPSEC_AUTH_DES_MAC: + ah_auth_alg = "des-mac"; + break; + + case IPSEC_AUTH_KPDK: + ah_auth_alg = "kpdk"; + break; + } + break; + + case IPSEC_PROTO_IPSEC_ESP: + switch (decode_16(value)) { + case IPSEC_AUTH_HMAC_MD5: + esp_auth_alg = "hmac-md5"; + break; + + case IPSEC_AUTH_HMAC_SHA: + esp_auth_alg = "hmac-sha"; + break; + + case IPSEC_AUTH_HMAC_RIPEMD: + esp_auth_alg = "hmac-ripemd"; + break; + + case IPSEC_AUTH_HMAC_SHA2_256: + esp_auth_alg = "hmac-sha2-256"; + break; + + case IPSEC_AUTH_HMAC_SHA2_384: + esp_auth_alg = "hmac-sha2-384"; + break; + + case IPSEC_AUTH_HMAC_SHA2_512: + esp_auth_alg = "hmac-sha2-512"; + break; + + case IPSEC_AUTH_DES_MAC: + esp_auth_alg = "des-mac"; + break; + + case IPSEC_AUTH_KPDK: + esp_auth_alg = "kpdk"; + break; + } + break; + } + break; + + case IPSEC_ATTR_KEY_LENGTH: + switch (proto->proto) { + case IPSEC_PROTO_IPSEC_AH: + snprintf(ah_key_length, + sizeof ah_key_length, "%u", + decode_16(value)); + break; + + case IPSEC_PROTO_IPSEC_ESP: + snprintf(esp_key_length, + sizeof esp_key_length, "%u", + decode_16(value)); + break; + } + break; + + case IPSEC_ATTR_KEY_ROUNDS: + switch (proto->proto) { + case IPSEC_PROTO_IPSEC_AH: + snprintf(ah_key_rounds, + sizeof ah_key_rounds, "%u", + decode_16(value)); + break; + + case IPSEC_PROTO_IPSEC_ESP: + snprintf(esp_key_rounds, + sizeof esp_key_rounds, "%u", + decode_16(value)); + break; + } + break; + + case IPSEC_ATTR_COMPRESS_DICTIONARY_SIZE: + snprintf(comp_dict_size, + sizeof comp_dict_size, "%u", + decode_16(value)); + break; + + case IPSEC_ATTR_COMPRESS_PRIVATE_ALGORITHM: + snprintf(comp_private_alg, + sizeof comp_private_alg, "%u", + decode_16(value)); + break; + } + } + } + + policy_sa->transport->vtbl->get_src(policy_sa->transport, + &sin); + if (sockaddr2text(sin, &addr, 1)) { + log_error("policy_callback: sockaddr2text failed"); + goto bad; + } + strlcpy(local_ike_address, addr, sizeof local_ike_address); + free(addr); + + policy_sa->transport->vtbl->get_dst(policy_sa->transport, + &sin); + if (sockaddr2text(sin, &addr, 1)) { + log_error("policy_callback: sockaddr2text failed"); + goto bad; + } + strlcpy(remote_ike_address, addr, sizeof remote_ike_address); + free(addr); + + switch (policy_isakmp_sa->exch_type) { + case ISAKMP_EXCH_AGGRESSIVE: + phase_1 = "aggressive"; + break; + + case ISAKMP_EXCH_ID_PROT: + phase_1 = "main"; + break; + } + + if (policy_isakmp_sa->initiator) { + id = policy_isakmp_sa->id_r; + id_sz = policy_isakmp_sa->id_r_len; + } else { + id = policy_isakmp_sa->id_i; + id_sz = policy_isakmp_sa->id_i_len; + } + + switch (id[0]) { + case IPSEC_ID_IPV4_ADDR: + remote_id_type = "IPv4 address"; + + net = decode_32(id + ISAKMP_ID_DATA_OFF - + ISAKMP_GEN_SZ); + my_inet_ntop4(&net, remote_id_addr_upper, + sizeof remote_id_addr_upper - 1, 1); + my_inet_ntop4(&net, remote_id_addr_lower, + sizeof remote_id_addr_lower - 1, 1); + remote_id = strdup(remote_id_addr_upper); + if (!remote_id) { + log_error("policy_callback: " + "strdup (\"%s\") failed", + remote_id_addr_upper); + goto bad; + } + break; + + case IPSEC_ID_IPV4_RANGE: + remote_id_type = "IPv4 range"; + + net = decode_32(id + ISAKMP_ID_DATA_OFF - + ISAKMP_GEN_SZ); + my_inet_ntop4(&net, remote_id_addr_lower, + sizeof remote_id_addr_lower - 1, 1); + net = decode_32(id + ISAKMP_ID_DATA_OFF - + ISAKMP_GEN_SZ + 4); + my_inet_ntop4(&net, remote_id_addr_upper, + sizeof remote_id_addr_upper - 1, 1); + len = strlen(remote_id_addr_upper) + + strlen(remote_id_addr_lower) + 2; + remote_id = calloc(len, sizeof(char)); + if (!remote_id) { + log_error("policy_callback: " + "calloc (%d, %lu) failed", len, + (unsigned long)sizeof(char)); + goto bad; + } + strlcpy(remote_id, remote_id_addr_lower, len); + strlcat(remote_id, "-", len); + strlcat(remote_id, remote_id_addr_upper, len); + break; + + case IPSEC_ID_IPV4_ADDR_SUBNET: + remote_id_type = "IPv4 subnet"; + + net = decode_32(id + ISAKMP_ID_DATA_OFF - + ISAKMP_GEN_SZ); + subnet = decode_32(id + ISAKMP_ID_DATA_OFF - + ISAKMP_GEN_SZ + 4); + net &= subnet; + my_inet_ntop4(&net, remote_id_addr_lower, + sizeof remote_id_addr_lower - 1, 1); + net |= ~subnet; + my_inet_ntop4(&net, remote_id_addr_upper, + sizeof remote_id_addr_upper - 1, 1); + len = strlen(remote_id_addr_upper) + + strlen(remote_id_addr_lower) + 2; + remote_id = calloc(len, sizeof(char)); + if (!remote_id) { + log_error("policy_callback: " + "calloc (%d, %lu) failed", len, + (unsigned long)sizeof(char)); + goto bad; + } + strlcpy(remote_id, remote_id_addr_lower, len); + strlcat(remote_id, "-", len); + strlcat(remote_id, remote_id_addr_upper, len); + break; + + case IPSEC_ID_IPV6_ADDR: + remote_id_type = "IPv6 address"; + my_inet_ntop6(id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, + remote_id_addr_upper, sizeof remote_id_addr_upper); + strlcpy(remote_id_addr_lower, remote_id_addr_upper, + sizeof remote_id_addr_lower); + remote_id = strdup(remote_id_addr_upper); + if (!remote_id) { + log_error("policy_callback: " + "strdup (\"%s\") failed", + remote_id_addr_upper); + goto bad; + } + break; + + case IPSEC_ID_IPV6_RANGE: + remote_id_type = "IPv6 range"; + + my_inet_ntop6(id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, + remote_id_addr_lower, + sizeof remote_id_addr_lower - 1); + + my_inet_ntop6(id + ISAKMP_ID_DATA_OFF - + ISAKMP_GEN_SZ + 16, remote_id_addr_upper, + sizeof remote_id_addr_upper - 1); + + len = strlen(remote_id_addr_upper) + + strlen(remote_id_addr_lower) + 2; + remote_id = calloc(len, sizeof(char)); + if (!remote_id) { + log_error("policy_callback: " + "calloc (%d, %lu) failed", len, + (unsigned long)sizeof(char)); + goto bad; + } + strlcpy(remote_id, remote_id_addr_lower, len); + strlcat(remote_id, "-", len); + strlcat(remote_id, remote_id_addr_upper, len); + break; + + case IPSEC_ID_IPV6_ADDR_SUBNET: + { + struct in6_addr net, mask; + + remote_id_type = "IPv6 subnet"; + + bcopy(id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, &net, + sizeof(net)); + bcopy(id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ + 16, + &mask, sizeof(mask)); + + for (i = 0; i < 16; i++) + net.s6_addr[i] &= mask.s6_addr[i]; + + my_inet_ntop6((unsigned char *)&net, + remote_id_addr_lower, + sizeof remote_id_addr_lower - 1); + + for (i = 0; i < 16; i++) + net.s6_addr[i] |= ~mask.s6_addr[i]; + + my_inet_ntop6((unsigned char *)&net, + remote_id_addr_upper, + sizeof remote_id_addr_upper - 1); + + len = strlen(remote_id_addr_upper) + + strlen(remote_id_addr_lower) + 2; + remote_id = calloc(len, sizeof(char)); + if (!remote_id) { + log_error("policy_callback: " + "calloc (%d, %lu) failed", len, + (unsigned long)sizeof(char)); + goto bad; + } + strlcpy(remote_id, remote_id_addr_lower, len); + strlcat(remote_id, "-", len); + strlcat(remote_id, remote_id_addr_upper, len); + break; + } + + case IPSEC_ID_FQDN: + remote_id_type = "FQDN"; + remote_id = calloc(id_sz - ISAKMP_ID_DATA_OFF + + ISAKMP_GEN_SZ + 1, sizeof(char)); + if (!remote_id) { + log_error("policy_callback: " + "calloc (%lu, %lu) failed", + (unsigned long)id_sz - ISAKMP_ID_DATA_OFF + + ISAKMP_GEN_SZ + 1, + (unsigned long)sizeof(char)); + goto bad; + } + memcpy(remote_id, + id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, + id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ); + break; + + case IPSEC_ID_USER_FQDN: + remote_id_type = "User FQDN"; + remote_id = calloc(id_sz - ISAKMP_ID_DATA_OFF + + ISAKMP_GEN_SZ + 1, sizeof(char)); + if (!remote_id) { + log_error("policy_callback: " + "calloc (%lu, %lu) failed", + (unsigned long)id_sz - ISAKMP_ID_DATA_OFF + + ISAKMP_GEN_SZ + 1, + (unsigned long)sizeof(char)); + goto bad; + } + memcpy(remote_id, + id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, + id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ); + break; + + case IPSEC_ID_DER_ASN1_DN: + remote_id_type = "ASN1 DN"; + + remote_id = x509_DN_string(id + ISAKMP_ID_DATA_OFF - + ISAKMP_GEN_SZ, + id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ); + if (!remote_id) { + LOG_DBG((LOG_POLICY, 50, + "policy_callback: failed to decode name")); + goto bad; + } + break; + + case IPSEC_ID_DER_ASN1_GN: /* XXX */ + remote_id_type = "ASN1 GN"; + break; + + case IPSEC_ID_KEY_ID: + remote_id_type = "Key ID"; + remote_id = calloc(2 * (id_sz - ISAKMP_ID_DATA_OFF + + ISAKMP_GEN_SZ) + 1, sizeof(char)); + if (!remote_id) { + log_error("policy_callback: " + "calloc (%lu, %lu) failed", + 2 * ((unsigned long)id_sz - + ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ) + 1, + (unsigned long)sizeof(char)); + goto bad; + } + /* Does it contain any non-printable characters ? */ + for (i = 0; + i < id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ; + i++) + if (!isprint(*(id + ISAKMP_ID_DATA_OFF - + ISAKMP_GEN_SZ + i))) + break; + if (i >= id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ) { + memcpy(remote_id, id + ISAKMP_ID_DATA_OFF - + ISAKMP_GEN_SZ, + id_sz - ISAKMP_ID_DATA_OFF + + ISAKMP_GEN_SZ); + break; + } + /* Non-printable characters, convert to hex */ + for (i = 0; + i < id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ; + i++) { + remote_id[2 * i] = hextab[*(id + + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ) >> 4]; + remote_id[2 * i + 1] = hextab[*(id + + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ) & 0xF]; + } + break; + + default: + log_print("policy_callback: " + "unknown remote ID type %u", id[0]); + goto bad; + } + + switch (id[1]) { + case IPPROTO_TCP: + remote_id_proto = "tcp"; + break; + + case IPPROTO_UDP: + remote_id_proto = "udp"; + break; + +#ifdef IPPROTO_ETHERIP + case IPPROTO_ETHERIP: + remote_id_proto = "etherip"; + break; +#endif + + default: + snprintf(remote_id_proto_num, + sizeof remote_id_proto_num, "%d", + id[1]); + remote_id_proto = remote_id_proto_num; + break; + } + + snprintf(remote_id_port, sizeof remote_id_port, "%u", + decode_16(id + 2)); + + if (policy_exchange->initiator) { + initiator = "yes"; + idlocal = ie->id_ci; + idremote = ie->id_cr; + idlocalsz = ie->id_ci_sz; + idremotesz = ie->id_cr_sz; + } else { + initiator = "no"; + idlocal = ie->id_cr; + idremote = ie->id_ci; + idlocalsz = ie->id_cr_sz; + idremotesz = ie->id_ci_sz; + } + + /* Initialize the ID variables. */ + if (idremote) { + switch (GET_ISAKMP_ID_TYPE(idremote)) { + case IPSEC_ID_IPV4_ADDR: + remote_filter_type = "IPv4 address"; + + net = decode_32(idremote + ISAKMP_ID_DATA_OFF); + my_inet_ntop4(&net, remote_filter_addr_upper, + sizeof remote_filter_addr_upper - 1, 1); + my_inet_ntop4(&net, remote_filter_addr_lower, + sizeof remote_filter_addr_lower - 1, 1); + remote_filter = + strdup(remote_filter_addr_upper); + if (!remote_filter) { + log_error("policy_callback: strdup " + "(\"%s\") failed", + remote_filter_addr_upper); + goto bad; + } + break; + + case IPSEC_ID_IPV4_RANGE: + remote_filter_type = "IPv4 range"; + + net = decode_32(idremote + ISAKMP_ID_DATA_OFF); + my_inet_ntop4(&net, remote_filter_addr_lower, + sizeof remote_filter_addr_lower - 1, 1); + net = decode_32(idremote + ISAKMP_ID_DATA_OFF + + 4); + my_inet_ntop4(&net, remote_filter_addr_upper, + sizeof remote_filter_addr_upper - 1, 1); + len = strlen(remote_filter_addr_upper) + + strlen(remote_filter_addr_lower) + 2; + remote_filter = calloc(len, sizeof(char)); + if (!remote_filter) { + log_error("policy_callback: calloc " + "(%d, %lu) failed", len, + (unsigned long)sizeof(char)); + goto bad; + } + strlcpy(remote_filter, + remote_filter_addr_lower, len); + strlcat(remote_filter, "-", len); + strlcat(remote_filter, + remote_filter_addr_upper, len); + break; + + case IPSEC_ID_IPV4_ADDR_SUBNET: + remote_filter_type = "IPv4 subnet"; + + net = decode_32(idremote + ISAKMP_ID_DATA_OFF); + subnet = decode_32(idremote + + ISAKMP_ID_DATA_OFF + 4); + net &= subnet; + my_inet_ntop4(&net, remote_filter_addr_lower, + sizeof remote_filter_addr_lower - 1, 1); + net |= ~subnet; + my_inet_ntop4(&net, remote_filter_addr_upper, + sizeof remote_filter_addr_upper - 1, 1); + len = strlen(remote_filter_addr_upper) + + strlen(remote_filter_addr_lower) + 2; + remote_filter = calloc(len, sizeof(char)); + if (!remote_filter) { + log_error("policy_callback: calloc " + "(%d, %lu) failed", len, + (unsigned long)sizeof(char)); + goto bad; + } + strlcpy(remote_filter, + remote_filter_addr_lower, len); + strlcat(remote_filter, "-", len); + strlcat(remote_filter, + remote_filter_addr_upper, len); + break; + + case IPSEC_ID_IPV6_ADDR: + remote_filter_type = "IPv6 address"; + my_inet_ntop6(idremote + ISAKMP_ID_DATA_OFF, + remote_filter_addr_upper, + sizeof remote_filter_addr_upper - 1); + strlcpy(remote_filter_addr_lower, + remote_filter_addr_upper, + sizeof remote_filter_addr_lower); + remote_filter = + strdup(remote_filter_addr_upper); + if (!remote_filter) { + log_error("policy_callback: strdup " + "(\"%s\") failed", + remote_filter_addr_upper); + goto bad; + } + break; + + case IPSEC_ID_IPV6_RANGE: + remote_filter_type = "IPv6 range"; + + my_inet_ntop6(idremote + ISAKMP_ID_DATA_OFF, + remote_filter_addr_lower, + sizeof remote_filter_addr_lower - 1); + + my_inet_ntop6(idremote + ISAKMP_ID_DATA_OFF + + 16, remote_filter_addr_upper, + sizeof remote_filter_addr_upper - 1); + + len = strlen(remote_filter_addr_upper) + + strlen(remote_filter_addr_lower) + 2; + remote_filter = calloc(len, sizeof(char)); + if (!remote_filter) { + log_error("policy_callback: calloc " + "(%d, %lu) failed", len, + (unsigned long)sizeof(char)); + goto bad; + } + strlcpy(remote_filter, + remote_filter_addr_lower, len); + strlcat(remote_filter, "-", len); + strlcat(remote_filter, + remote_filter_addr_upper, len); + break; + + case IPSEC_ID_IPV6_ADDR_SUBNET: + { + struct in6_addr net, mask; + + remote_filter_type = "IPv6 subnet"; + + bcopy(idremote + ISAKMP_ID_DATA_OFF, + &net, sizeof(net)); + bcopy(idremote + ISAKMP_ID_DATA_OFF + + 16, &mask, sizeof(mask)); + + for (i = 0; i < 16; i++) + net.s6_addr[i] &= + mask.s6_addr[i]; + + my_inet_ntop6((unsigned char *)&net, + remote_filter_addr_lower, + sizeof remote_filter_addr_lower - 1); + + for (i = 0; i < 16; i++) + net.s6_addr[i] |= + ~mask.s6_addr[i]; + + my_inet_ntop6((unsigned char *)&net, + remote_filter_addr_upper, + sizeof remote_filter_addr_upper - 1); + + len = strlen(remote_filter_addr_upper) + + strlen(remote_filter_addr_lower) + 2; + remote_filter = calloc(len, + sizeof(char)); + if (!remote_filter) { + log_error("policy_callback: " + "calloc (%d, %lu) failed", + len, + (unsigned long)sizeof(char)); + goto bad; + } + strlcpy(remote_filter, + remote_filter_addr_lower, len); + strlcat(remote_filter, "-", len); + strlcat(remote_filter, + remote_filter_addr_upper, len); + break; + } + + case IPSEC_ID_FQDN: + remote_filter_type = "FQDN"; + remote_filter = malloc(idremotesz - + ISAKMP_ID_DATA_OFF + 1); + if (!remote_filter) { + log_error("policy_callback: " + "malloc (%lu) failed", + (unsigned long)idremotesz - + ISAKMP_ID_DATA_OFF + 1); + goto bad; + } + memcpy(remote_filter, + idremote + ISAKMP_ID_DATA_OFF, + idremotesz - ISAKMP_ID_DATA_OFF); + remote_filter[idremotesz - ISAKMP_ID_DATA_OFF] + = '\0'; + break; + + case IPSEC_ID_USER_FQDN: + remote_filter_type = "User FQDN"; + remote_filter = malloc(idremotesz - + ISAKMP_ID_DATA_OFF + 1); + if (!remote_filter) { + log_error("policy_callback: " + "malloc (%lu) failed", + (unsigned long)idremotesz - + ISAKMP_ID_DATA_OFF + 1); + goto bad; + } + memcpy(remote_filter, + idremote + ISAKMP_ID_DATA_OFF, + idremotesz - ISAKMP_ID_DATA_OFF); + remote_filter[idremotesz - ISAKMP_ID_DATA_OFF] + = '\0'; + break; + + case IPSEC_ID_DER_ASN1_DN: + remote_filter_type = "ASN1 DN"; + + remote_filter = x509_DN_string(idremote + + ISAKMP_ID_DATA_OFF, + idremotesz - ISAKMP_ID_DATA_OFF); + if (!remote_filter) { + LOG_DBG((LOG_POLICY, 50, + "policy_callback: " + "failed to decode name")); + goto bad; + } + break; + + case IPSEC_ID_DER_ASN1_GN: /* XXX -- not sure + * what's in this. */ + remote_filter_type = "ASN1 GN"; + break; + + case IPSEC_ID_KEY_ID: + remote_filter_type = "Key ID"; + remote_filter + = calloc(2 * (idremotesz - + ISAKMP_ID_DATA_OFF) + 1, + sizeof(char)); + if (!remote_filter) { + log_error("policy_callback: " + "calloc (%lu, %lu) failed", + 2 * ((unsigned long)idremotesz - + ISAKMP_ID_DATA_OFF) + 1, + (unsigned long)sizeof(char)); + goto bad; + } + /* + * Does it contain any non-printable + * characters ? + */ + for (i = 0; + i < idremotesz - ISAKMP_ID_DATA_OFF; i++) + if (!isprint(*(idremote + + ISAKMP_ID_DATA_OFF + i))) + break; + if (i >= idremotesz - ISAKMP_ID_DATA_OFF) { + memcpy(remote_filter, + idremote + ISAKMP_ID_DATA_OFF, + idremotesz - ISAKMP_ID_DATA_OFF); + break; + } + /* Non-printable characters, convert to hex */ + for (i = 0; + i < idremotesz - ISAKMP_ID_DATA_OFF; + i++) { + remote_filter[2 * i] + = hextab[*(idremote + + ISAKMP_ID_DATA_OFF) >> 4]; + remote_filter[2 * i + 1] + = hextab[*(idremote + + ISAKMP_ID_DATA_OFF) & 0xF]; + } + break; + + default: + log_print("policy_callback: " + "unknown Remote ID type %u", + GET_ISAKMP_ID_TYPE(idremote)); + goto bad; + } + + switch (idremote[ISAKMP_GEN_SZ + 1]) { + case IPPROTO_TCP: + remote_filter_proto = "tcp"; + break; + + case IPPROTO_UDP: + remote_filter_proto = "udp"; + break; + +#ifdef IPPROTO_ETHERIP + case IPPROTO_ETHERIP: + remote_filter_proto = "etherip"; + break; +#endif + + default: + snprintf(remote_filter_proto_num, + sizeof remote_filter_proto_num, "%d", + idremote[ISAKMP_GEN_SZ + 1]); + remote_filter_proto = remote_filter_proto_num; + break; + } + + snprintf(remote_filter_port, sizeof remote_filter_port, + "%u", decode_16(idremote + ISAKMP_GEN_SZ + 2)); + } else { + policy_sa->transport->vtbl->get_dst(policy_sa->transport, &sin); + switch (sin->sa_family) { + case AF_INET: + remote_filter_type = "IPv4 address"; + break; + case AF_INET6: + remote_filter_type = "IPv6 address"; + break; + default: + log_print("policy_callback: " + "unsupported protocol family %d", + sin->sa_family); + goto bad; + } + if (sockaddr2text(sin, &addr, 1)) { + log_error("policy_callback: " + "sockaddr2text failed"); + goto bad; + } + memcpy(remote_filter_addr_upper, addr, + sizeof remote_filter_addr_upper); + memcpy(remote_filter_addr_lower, addr, + sizeof remote_filter_addr_lower); + free(addr); + remote_filter = strdup(remote_filter_addr_upper); + if (!remote_filter) { + log_error("policy_callback: " + "strdup (\"%s\") failed", + remote_filter_addr_upper); + goto bad; + } + } + + if (idlocal) { + switch (GET_ISAKMP_ID_TYPE(idlocal)) { + case IPSEC_ID_IPV4_ADDR: + local_filter_type = "IPv4 address"; + + net = decode_32(idlocal + ISAKMP_ID_DATA_OFF); + my_inet_ntop4(&net, local_filter_addr_upper, + sizeof local_filter_addr_upper - 1, 1); + my_inet_ntop4(&net, local_filter_addr_lower, + sizeof local_filter_addr_upper - 1, 1); + local_filter = strdup(local_filter_addr_upper); + if (!local_filter) { + log_error("policy_callback: " + "strdup (\"%s\") failed", + local_filter_addr_upper); + goto bad; + } + break; + + case IPSEC_ID_IPV4_RANGE: + local_filter_type = "IPv4 range"; + + net = decode_32(idlocal + ISAKMP_ID_DATA_OFF); + my_inet_ntop4(&net, local_filter_addr_lower, + sizeof local_filter_addr_lower - 1, 1); + net = decode_32(idlocal + ISAKMP_ID_DATA_OFF + + 4); + my_inet_ntop4(&net, local_filter_addr_upper, + sizeof local_filter_addr_upper - 1, 1); + len = strlen(local_filter_addr_upper) + + strlen(local_filter_addr_lower) + 2; + local_filter = calloc(len, sizeof(char)); + if (!local_filter) { + log_error("policy_callback: " + "calloc (%d, %lu) failed", len, + (unsigned long)sizeof(char)); + goto bad; + } + strlcpy(local_filter, local_filter_addr_lower, + len); + strlcat(local_filter, "-", len); + strlcat(local_filter, local_filter_addr_upper, + len); + break; + + case IPSEC_ID_IPV4_ADDR_SUBNET: + local_filter_type = "IPv4 subnet"; + + net = decode_32(idlocal + ISAKMP_ID_DATA_OFF); + subnet = decode_32(idlocal + + ISAKMP_ID_DATA_OFF + 4); + net &= subnet; + my_inet_ntop4(&net, local_filter_addr_lower, + sizeof local_filter_addr_lower - 1, 1); + net |= ~subnet; + my_inet_ntop4(&net, local_filter_addr_upper, + sizeof local_filter_addr_upper - 1, 1); + len = strlen(local_filter_addr_upper) + + strlen(local_filter_addr_lower) + 2; + local_filter = calloc(len, sizeof(char)); + if (!local_filter) { + log_error("policy_callback: " + "calloc (%d, %lu) failed", len, + (unsigned long)sizeof(char)); + goto bad; + } + strlcpy(local_filter, local_filter_addr_lower, + len); + strlcat(local_filter, "-", len); + strlcat(local_filter, local_filter_addr_upper, + len); + break; + + case IPSEC_ID_IPV6_ADDR: + local_filter_type = "IPv6 address"; + my_inet_ntop6(idlocal + ISAKMP_ID_DATA_OFF, + local_filter_addr_upper, + sizeof local_filter_addr_upper - 1); + strlcpy(local_filter_addr_lower, + local_filter_addr_upper, + sizeof local_filter_addr_lower); + local_filter = strdup(local_filter_addr_upper); + if (!local_filter) { + log_error("policy_callback: " + "strdup (\"%s\") failed", + local_filter_addr_upper); + goto bad; + } + break; + + case IPSEC_ID_IPV6_RANGE: + local_filter_type = "IPv6 range"; + + my_inet_ntop6(idlocal + ISAKMP_ID_DATA_OFF, + local_filter_addr_lower, + sizeof local_filter_addr_lower - 1); + + my_inet_ntop6(idlocal + ISAKMP_ID_DATA_OFF + + 16, local_filter_addr_upper, + sizeof local_filter_addr_upper - 1); + + len = strlen(local_filter_addr_upper) + + strlen(local_filter_addr_lower) + 2; + local_filter = calloc(len, sizeof(char)); + if (!local_filter) { + log_error("policy_callback: " + "calloc (%d, %lu) failed", len, + (unsigned long)sizeof(char)); + goto bad; + } + strlcpy(local_filter, local_filter_addr_lower, + len); + strlcat(local_filter, "-", len); + strlcat(local_filter, local_filter_addr_upper, + len); + break; + + case IPSEC_ID_IPV6_ADDR_SUBNET: + { + struct in6_addr net, mask; + + local_filter_type = "IPv6 subnet"; + + bcopy(idlocal + ISAKMP_ID_DATA_OFF, + &net, sizeof(net)); + bcopy(idlocal + ISAKMP_ID_DATA_OFF + + 16, &mask, sizeof(mask)); + + for (i = 0; i < 16; i++) + net.s6_addr[i] &= + mask.s6_addr[i]; + + my_inet_ntop6((unsigned char *)&net, + local_filter_addr_lower, + sizeof local_filter_addr_lower - 1); + + for (i = 0; i < 16; i++) + net.s6_addr[i] |= + ~mask.s6_addr[i]; + + my_inet_ntop6((unsigned char *)&net, + local_filter_addr_upper, + sizeof local_filter_addr_upper - + 1); + + len = strlen(local_filter_addr_upper) + + strlen(local_filter_addr_lower) + + 2; + local_filter = calloc(len, + sizeof(char)); + if (!local_filter) { + log_error("policy_callback: " + "calloc (%d, %lu) failed", + len, + (unsigned long)sizeof(char)); + goto bad; + } + strlcpy(local_filter, + local_filter_addr_lower, len); + strlcat(local_filter, "-", len); + strlcat(local_filter, + local_filter_addr_upper, len); + break; + } + + case IPSEC_ID_FQDN: + local_filter_type = "FQDN"; + local_filter = malloc(idlocalsz - + ISAKMP_ID_DATA_OFF + 1); + if (!local_filter) { + log_error("policy_callback: " + "malloc (%lu) failed", + (unsigned long)idlocalsz - + ISAKMP_ID_DATA_OFF + 1); + goto bad; + } + memcpy(local_filter, + idlocal + ISAKMP_ID_DATA_OFF, + idlocalsz - ISAKMP_ID_DATA_OFF); + local_filter[idlocalsz - ISAKMP_ID_DATA_OFF] + = '\0'; + break; + + case IPSEC_ID_USER_FQDN: + local_filter_type = "User FQDN"; + local_filter = malloc(idlocalsz - + ISAKMP_ID_DATA_OFF + 1); + if (!local_filter) { + log_error("policy_callback: " + "malloc (%lu) failed", + (unsigned long)idlocalsz - + ISAKMP_ID_DATA_OFF + 1); + goto bad; + } + memcpy(local_filter, + idlocal + ISAKMP_ID_DATA_OFF, + idlocalsz - ISAKMP_ID_DATA_OFF); + local_filter[idlocalsz - ISAKMP_ID_DATA_OFF] + = '\0'; + break; + + case IPSEC_ID_DER_ASN1_DN: + local_filter_type = "ASN1 DN"; + + local_filter = x509_DN_string(idlocal + + ISAKMP_ID_DATA_OFF, + idlocalsz - ISAKMP_ID_DATA_OFF); + if (!local_filter) { + LOG_DBG((LOG_POLICY, 50, + "policy_callback: failed to decode" + " name")); + goto bad; + } + break; + + case IPSEC_ID_DER_ASN1_GN: + /* XXX -- not sure what's in this. */ + local_filter_type = "ASN1 GN"; + break; + + case IPSEC_ID_KEY_ID: + local_filter_type = "Key ID"; + local_filter = calloc(2 * (idlocalsz - + ISAKMP_ID_DATA_OFF) + 1, + sizeof(char)); + if (!local_filter) { + log_error("policy_callback: " + "calloc (%lu, %lu) failed", + 2 * ((unsigned long)idlocalsz - + ISAKMP_ID_DATA_OFF) + 1, + (unsigned long)sizeof(char)); + goto bad; + } + /* + * Does it contain any non-printable + * characters ? + */ + for (i = 0; + i < idlocalsz - ISAKMP_ID_DATA_OFF; i++) + if (!isprint(*(idlocal + + ISAKMP_ID_DATA_OFF + i))) + break; + if (i >= idlocalsz - ISAKMP_ID_DATA_OFF) { + memcpy(local_filter, idlocal + + ISAKMP_ID_DATA_OFF, + idlocalsz - ISAKMP_ID_DATA_OFF); + break; + } + /* Non-printable characters, convert to hex */ + for (i = 0; + i < idlocalsz - ISAKMP_ID_DATA_OFF; i++) { + local_filter[2 * i] + = hextab[*(idlocal + + ISAKMP_ID_DATA_OFF) >> 4]; + local_filter[2 * i + 1] + = hextab[*(idlocal + + ISAKMP_ID_DATA_OFF) & 0xF]; + } + break; + + default: + log_print("policy_callback: " + "unknown Local ID type %u", + GET_ISAKMP_ID_TYPE(idlocal)); + goto bad; + } + + switch (idlocal[ISAKMP_GEN_SZ + 1]) { + case IPPROTO_TCP: + local_filter_proto = "tcp"; + break; + + case IPPROTO_UDP: + local_filter_proto = "udp"; + break; + +#ifdef IPPROTO_ETHERIP + case IPPROTO_ETHERIP: + local_filter_proto = "etherip"; + break; +#endif + + default: + snprintf(local_filter_proto_num, + sizeof local_filter_proto_num, + "%d", idlocal[ISAKMP_GEN_SZ + 1]); + local_filter_proto = local_filter_proto_num; + break; + } + + snprintf(local_filter_port, sizeof local_filter_port, + "%u", decode_16(idlocal + ISAKMP_GEN_SZ + 2)); + } else { + policy_sa->transport->vtbl->get_src(policy_sa->transport, + (struct sockaddr **)&sin); + switch (sin->sa_family) { + case AF_INET: + local_filter_type = "IPv4 address"; + break; + case AF_INET6: + local_filter_type = "IPv6 address"; + break; + default: + log_print("policy_callback: " + "unsupported protocol family %d", + sin->sa_family); + goto bad; + } + + if (sockaddr2text(sin, &addr, 1)) { + log_error("policy_callback: " + "sockaddr2text failed"); + goto bad; + } + memcpy(local_filter_addr_upper, addr, + sizeof local_filter_addr_upper); + memcpy(local_filter_addr_lower, addr, + sizeof local_filter_addr_lower); + free(addr); + local_filter = strdup(local_filter_addr_upper); + if (!local_filter) { + log_error("policy_callback: " + "strdup (\"%s\") failed", + local_filter_addr_upper); + goto bad; + } + } + + LOG_DBG((LOG_POLICY, 80, + "Policy context (action attributes):")); + LOG_DBG((LOG_POLICY, 80, "esp_present == %s", esp_present)); + LOG_DBG((LOG_POLICY, 80, "ah_present == %s", ah_present)); + LOG_DBG((LOG_POLICY, 80, "comp_present == %s", comp_present)); + LOG_DBG((LOG_POLICY, 80, "ah_hash_alg == %s", ah_hash_alg)); + LOG_DBG((LOG_POLICY, 80, "esp_enc_alg == %s", esp_enc_alg)); + LOG_DBG((LOG_POLICY, 80, "comp_alg == %s", comp_alg)); + LOG_DBG((LOG_POLICY, 80, "ah_auth_alg == %s", ah_auth_alg)); + LOG_DBG((LOG_POLICY, 80, "esp_auth_alg == %s", esp_auth_alg)); + LOG_DBG((LOG_POLICY, 80, "ah_life_seconds == %s", + ah_life_seconds)); + LOG_DBG((LOG_POLICY, 80, "ah_life_kbytes == %s", + ah_life_kbytes)); + LOG_DBG((LOG_POLICY, 80, "esp_life_seconds == %s", + esp_life_seconds)); + LOG_DBG((LOG_POLICY, 80, "esp_life_kbytes == %s", + esp_life_kbytes)); + LOG_DBG((LOG_POLICY, 80, "comp_life_seconds == %s", + comp_life_seconds)); + LOG_DBG((LOG_POLICY, 80, "comp_life_kbytes == %s", + comp_life_kbytes)); + LOG_DBG((LOG_POLICY, 80, "ah_encapsulation == %s", + ah_encapsulation)); + LOG_DBG((LOG_POLICY, 80, "esp_encapsulation == %s", + esp_encapsulation)); + LOG_DBG((LOG_POLICY, 80, "comp_encapsulation == %s", + comp_encapsulation)); + LOG_DBG((LOG_POLICY, 80, "comp_dict_size == %s", + comp_dict_size)); + LOG_DBG((LOG_POLICY, 80, "comp_private_alg == %s", + comp_private_alg)); + LOG_DBG((LOG_POLICY, 80, "ah_key_length == %s", + ah_key_length)); + LOG_DBG((LOG_POLICY, 80, "ah_key_rounds == %s", + ah_key_rounds)); + LOG_DBG((LOG_POLICY, 80, "esp_key_length == %s", + esp_key_length)); + LOG_DBG((LOG_POLICY, 80, "esp_key_rounds == %s", + esp_key_rounds)); + LOG_DBG((LOG_POLICY, 80, "ah_group_desc == %s", + ah_group_desc)); + LOG_DBG((LOG_POLICY, 80, "esp_group_desc == %s", + esp_group_desc)); + LOG_DBG((LOG_POLICY, 80, "comp_group_desc == %s", + comp_group_desc)); + LOG_DBG((LOG_POLICY, 80, "ah_ecn == %s", ah_ecn)); + LOG_DBG((LOG_POLICY, 80, "esp_ecn == %s", esp_ecn)); + LOG_DBG((LOG_POLICY, 80, "comp_ecn == %s", comp_ecn)); + LOG_DBG((LOG_POLICY, 80, "remote_filter_type == %s", + remote_filter_type)); + LOG_DBG((LOG_POLICY, 80, "remote_filter_addr_upper == %s", + remote_filter_addr_upper)); + LOG_DBG((LOG_POLICY, 80, "remote_filter_addr_lower == %s", + remote_filter_addr_lower)); + LOG_DBG((LOG_POLICY, 80, "remote_filter == %s", + (remote_filter ? remote_filter : ""))); + LOG_DBG((LOG_POLICY, 80, "remote_filter_port == %s", + remote_filter_port)); + LOG_DBG((LOG_POLICY, 80, "remote_filter_proto == %s", + remote_filter_proto)); + LOG_DBG((LOG_POLICY, 80, "local_filter_type == %s", + local_filter_type)); + LOG_DBG((LOG_POLICY, 80, "local_filter_addr_upper == %s", + local_filter_addr_upper)); + LOG_DBG((LOG_POLICY, 80, "local_filter_addr_lower == %s", + local_filter_addr_lower)); + LOG_DBG((LOG_POLICY, 80, "local_filter == %s", + (local_filter ? local_filter : ""))); + LOG_DBG((LOG_POLICY, 80, "local_filter_port == %s", + local_filter_port)); + LOG_DBG((LOG_POLICY, 80, "local_filter_proto == %s", + local_filter_proto)); + LOG_DBG((LOG_POLICY, 80, "remote_id_type == %s", + remote_id_type)); + LOG_DBG((LOG_POLICY, 80, "remote_id_addr_upper == %s", + remote_id_addr_upper)); + LOG_DBG((LOG_POLICY, 80, "remote_id_addr_lower == %s", + remote_id_addr_lower)); + LOG_DBG((LOG_POLICY, 80, "remote_id == %s", + (remote_id ? remote_id : ""))); + LOG_DBG((LOG_POLICY, 80, "remote_id_port == %s", + remote_id_port)); + LOG_DBG((LOG_POLICY, 80, "remote_id_proto == %s", + remote_id_proto)); + LOG_DBG((LOG_POLICY, 80, "remote_negotiation_address == %s", + remote_ike_address)); + LOG_DBG((LOG_POLICY, 80, "local_negotiation_address == %s", + local_ike_address)); + LOG_DBG((LOG_POLICY, 80, "pfs == %s", pfs)); + LOG_DBG((LOG_POLICY, 80, "initiator == %s", initiator)); + LOG_DBG((LOG_POLICY, 80, "phase1_group_desc == %s", + phase1_group)); + + /* Unset dirty now. */ + dirty = 0; + } + if (strcmp(name, "phase_1") == 0) + return phase_1; + + if (strcmp(name, "GMTTimeOfDay") == 0) { + tt = time((time_t)NULL); + strftime(mytimeofday, 14, "%Y%m%d%H%M%S", gmtime(&tt)); + return mytimeofday; + } + if (strcmp(name, "LocalTimeOfDay") == 0) { + tt = time((time_t)NULL); + strftime(mytimeofday, 14, "%Y%m%d%H%M%S", localtime(&tt)); + return mytimeofday; + } + if (strcmp(name, "initiator") == 0) + return initiator; + + if (strcmp(name, "pfs") == 0) + return pfs; + + if (strcmp(name, "app_domain") == 0) + return "IPsec policy"; + + if (strcmp(name, "doi") == 0) + return "ipsec"; + + if (strcmp(name, "esp_present") == 0) + return esp_present; + + if (strcmp(name, "ah_present") == 0) + return ah_present; + + if (strcmp(name, "comp_present") == 0) + return comp_present; + + if (strcmp(name, "ah_hash_alg") == 0) + return ah_hash_alg; + + if (strcmp(name, "ah_auth_alg") == 0) + return ah_auth_alg; + + if (strcmp(name, "esp_auth_alg") == 0) + return esp_auth_alg; + + if (strcmp(name, "esp_enc_alg") == 0) + return esp_enc_alg; + + if (strcmp(name, "comp_alg") == 0) + return comp_alg; + + if (strcmp(name, "ah_life_kbytes") == 0) + return ah_life_kbytes; + + if (strcmp(name, "ah_life_seconds") == 0) + return ah_life_seconds; + + if (strcmp(name, "esp_life_kbytes") == 0) + return esp_life_kbytes; + + if (strcmp(name, "esp_life_seconds") == 0) + return esp_life_seconds; + + if (strcmp(name, "comp_life_kbytes") == 0) + return comp_life_kbytes; + + if (strcmp(name, "comp_life_seconds") == 0) + return comp_life_seconds; + + if (strcmp(name, "ah_encapsulation") == 0) + return ah_encapsulation; + + if (strcmp(name, "esp_encapsulation") == 0) + return esp_encapsulation; + + if (strcmp(name, "comp_encapsulation") == 0) + return comp_encapsulation; + + if (strcmp(name, "ah_key_length") == 0) + return ah_key_length; + + if (strcmp(name, "ah_key_rounds") == 0) + return ah_key_rounds; + + if (strcmp(name, "esp_key_length") == 0) + return esp_key_length; + + if (strcmp(name, "esp_key_rounds") == 0) + return esp_key_rounds; + + if (strcmp(name, "comp_dict_size") == 0) + return comp_dict_size; + + if (strcmp(name, "comp_private_alg") == 0) + return comp_private_alg; + + if (strcmp(name, "remote_filter_type") == 0) + return remote_filter_type; + + if (strcmp(name, "remote_filter") == 0) + return (remote_filter ? remote_filter : ""); + + if (strcmp(name, "remote_filter_addr_upper") == 0) + return remote_filter_addr_upper; + + if (strcmp(name, "remote_filter_addr_lower") == 0) + return remote_filter_addr_lower; + + if (strcmp(name, "remote_filter_port") == 0) + return remote_filter_port; + + if (strcmp(name, "remote_filter_proto") == 0) + return remote_filter_proto; + + if (strcmp(name, "local_filter_type") == 0) + return local_filter_type; + + if (strcmp(name, "local_filter") == 0) + return (local_filter ? local_filter : ""); + + if (strcmp(name, "local_filter_addr_upper") == 0) + return local_filter_addr_upper; + + if (strcmp(name, "local_filter_addr_lower") == 0) + return local_filter_addr_lower; + + if (strcmp(name, "local_filter_port") == 0) + return local_filter_port; + + if (strcmp(name, "local_filter_proto") == 0) + return local_filter_proto; + + if (strcmp(name, "remote_ike_address") == 0) + return remote_ike_address; + + if (strcmp(name, "remote_negotiation_address") == 0) + return remote_ike_address; + + if (strcmp(name, "local_ike_address") == 0) + return local_ike_address; + + if (strcmp(name, "local_negotiation_address") == 0) + return local_ike_address; + + if (strcmp(name, "remote_id_type") == 0) + return remote_id_type; + + if (strcmp(name, "remote_id") == 0) + return (remote_id ? remote_id : ""); + + if (strcmp(name, "remote_id_addr_upper") == 0) + return remote_id_addr_upper; + + if (strcmp(name, "remote_id_addr_lower") == 0) + return remote_id_addr_lower; + + if (strcmp(name, "remote_id_port") == 0) + return remote_id_port; + + if (strcmp(name, "remote_id_proto") == 0) + return remote_id_proto; + + if (strcmp(name, "phase1_group_desc") == 0) + return phase1_group; + + if (strcmp(name, "esp_group_desc") == 0) + return esp_group_desc; + + if (strcmp(name, "ah_group_desc") == 0) + return ah_group_desc; + + if (strcmp(name, "comp_group_desc") == 0) + return comp_group_desc; + + if (strcmp(name, "comp_ecn") == 0) + return comp_ecn; + + if (strcmp(name, "ah_ecn") == 0) + return ah_ecn; + + if (strcmp(name, "esp_ecn") == 0) + return esp_ecn; + + return ""; + +bad: + policy_callback(KEYNOTE_CALLBACK_INITIALIZE); + return ""; +} + +void +policy_init(void) +{ + char *ptr, *policy_file, *use_keynote; + char **asserts; + size_t sz, len; + int fd, i; + + LOG_DBG((LOG_POLICY, 30, "policy_init: initializing")); + + /* Do we want to use the policy modules? */ + use_keynote = conf_get_str("General", "Use-Keynote"); + if (ignore_policy || + (use_keynote && strncmp("yes", use_keynote, 3))) + return; + + /* Get policy file from configuration. */ + policy_file = conf_get_str("General", "Policy-file"); + if (!policy_file) + policy_file = CONF_DFLT_POLICY_FILE; + + /* Open policy file. */ + fd = monitor_open(policy_file, O_RDONLY, 0); + if (fd == -1) + log_fatal("policy_init: open (\"%s\", O_RDONLY) failed", + policy_file); + + /* Check file modes and collect file size */ + if (check_file_secrecy_fd(fd, policy_file, &sz)) { + close(fd); + log_fatal("policy_init: cannot read %s", policy_file); + } + + /* Allocate memory to keep policies. */ + ptr = calloc(sz + 1, sizeof(char)); + if (!ptr) + log_fatal("policy_init: calloc (%lu, %lu) failed", + (unsigned long)sz + 1, (unsigned long)sizeof(char)); + + /* Just in case there are short reads... */ + for (len = 0; len < sz; len += i) { + i = read(fd, ptr + len, sz - len); + if (i == -1) + log_fatal("policy_init: read (%d, %p, %lu) failed", fd, + ptr + len, (unsigned long)(sz - len)); + } + + /* We're done with this. */ + close(fd); + + /* Parse buffer, break up into individual policies. */ + asserts = kn_read_asserts(ptr, sz, &i); + + /* Begone! */ + free(ptr); + + if (asserts == (char **)NULL) + log_print("policy_init: all policies flushed"); + + /* Cleanup */ + if (policy_asserts) { + for (fd = 0; fd < policy_asserts_num; fd++) + if (policy_asserts && policy_asserts[fd]) + free(policy_asserts[fd]); + + free(policy_asserts); + } + policy_asserts = asserts; + policy_asserts_num = i; +} + +/* Nothing needed for initialization */ +int +keynote_cert_init(void) +{ + return 1; +} + +/* Just copy and return. */ +void * +keynote_cert_get(u_int8_t *data, u_int32_t len) +{ + char *foo = malloc(len + 1); + + if (foo == NULL) + return NULL; + + memcpy(foo, data, len); + foo[len] = '\0'; + return foo; +} + +/* + * We just verify the signature on the credentials. + * On signature failure, just drop the whole payload. + */ +int +keynote_cert_validate(void *scert) +{ + char **foo; + int num, i; + + if (scert == NULL) + return 0; + + foo = kn_read_asserts((char *)scert, strlen((char *)scert), &num); + if (foo == NULL) + return 0; + + for (i = 0; i < num; i++) { + if (kn_verify_assertion(scert, strlen((char *)scert)) + != SIGRESULT_TRUE) { + for (; i < num; i++) + free(foo[i]); + free(foo); + return 0; + } + free(foo[i]); + } + + free(foo); + return 1; +} + +/* Add received credentials. */ +int +keynote_cert_insert(int sid, void *scert) +{ + char **foo; + int num; + + if (scert == NULL) + return 0; + + foo = kn_read_asserts((char *)scert, strlen((char *)scert), &num); + if (foo == NULL) + return 0; + + while (num--) + kn_add_assertion(sid, foo[num], strlen(foo[num]), 0); + + return 1; +} + +/* Just regular memory free. */ +void +keynote_cert_free(void *cert) +{ + free(cert); +} + +/* Verify that the key given to us is valid. */ +int +keynote_certreq_validate(u_int8_t *data, u_int32_t len) +{ + struct keynote_deckey dc; + int err = 1; + char *dat; + + dat = calloc(len + 1, sizeof(char)); + if (!dat) { + log_error("keynote_certreq_validate: calloc (%d, %lu) failed", + len + 1, (unsigned long)sizeof(char)); + return 0; + } + memcpy(dat, data, len); + + if (kn_decode_key(&dc, dat, KEYNOTE_PUBLIC_KEY) != 0) + err = 0; + else + kn_free_key(&dc); + + free(dat); + + return err; +} + +/* Beats me what we should be doing with this. */ +void * +keynote_certreq_decode(u_int8_t *data, u_int32_t len) +{ + /* XXX */ + return NULL; +} + +void +keynote_free_aca(void *blob) +{ + /* XXX */ +} + +int +keynote_cert_obtain(u_int8_t *id, size_t id_len, void *data, u_int8_t **cert, + u_int32_t *certlen) +{ + char *dirname, *file, *addr_str; + struct stat sb; + size_t size; + int idtype, fd, len; + + if (!id) { + log_print("keynote_cert_obtain: ID is missing"); + return 0; + } + /* Get type of ID. */ + idtype = id[0]; + id += ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ; + id_len -= ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ; + + dirname = conf_get_str("KeyNote", "Credential-directory"); + if (!dirname) { + LOG_DBG((LOG_POLICY, 30, + "keynote_cert_obtain: no Credential-directory")); + return 0; + } + len = strlen(dirname) + strlen(CREDENTIAL_FILE) + 3; + + switch (idtype) { + case IPSEC_ID_IPV4_ADDR: + case IPSEC_ID_IPV6_ADDR: + util_ntoa(&addr_str, idtype == IPSEC_ID_IPV4_ADDR ? + AF_INET : AF_INET6, id); + if (addr_str == 0) + return 0; + + file = calloc(len + strlen(addr_str), sizeof(char)); + if (file == NULL) { + log_error("keynote_cert_obtain: failed to allocate " + "%lu bytes", (unsigned long)len + + strlen(addr_str)); + free(addr_str); + return 0; + } + snprintf(file, len + strlen(addr_str), "%s/%s/%s", dirname, + addr_str, CREDENTIAL_FILE); + free(addr_str); + break; + + case IPSEC_ID_FQDN: + case IPSEC_ID_USER_FQDN: { + file = calloc(len + id_len, sizeof(char)); + if (file == NULL) { + log_error("keynote_cert_obtain: " + "failed to allocate %lu bytes", + (unsigned long)len + id_len); + return 0; + } + snprintf(file, len + id_len, "%s/", dirname); + memcpy(file + strlen(dirname) + 1, id, id_len); + snprintf(file + strlen(dirname) + 1 + id_len, + len - strlen(dirname) - 1, "/%s", CREDENTIAL_FILE); + break; + } + + default: + return 0; + } + + fd = monitor_open(file, O_RDONLY, 0); + if (fd < 0) { + LOG_DBG((LOG_POLICY, 30, "keynote_cert_obtain: " + "failed to open \"%s\"", file)); + free(file); + return 0; + } + + if (fstat(fd, &sb) < 0) { + LOG_DBG((LOG_POLICY, 30, "keynote_cert_obtain: " + "failed to stat \"%s\"", file)); + free(file); + close(fd); + return 0; + } + size = (size_t)sb.st_size; + + *cert = calloc(size + 1, sizeof(char)); + if (*cert == NULL) { + log_error("keynote_cert_obtain: failed to allocate %lu bytes", + (unsigned long)size); + free(file); + return 0; + } + + if (read(fd, *cert, size) != (int)size) { + LOG_DBG((LOG_POLICY, 30, "keynote_cert_obtain: " + "failed to read %lu bytes from \"%s\"", + (unsigned long)size, file)); + free(file); + close(fd); + return 0; + } + close(fd); + free(file); + *certlen = size; + return 1; +} + +/* This should never be called. */ +int +keynote_cert_get_subjects(void *scert, int *n, u_int8_t ***id, + u_int32_t **id_len) +{ + return 0; +} + +/* Get the authorizer key. */ +int +keynote_cert_get_key(void *scert, void *keyp) +{ + struct keynote_keylist *kl; + int sid, kid, num; + char **foo; + + foo = kn_read_asserts((char *)scert, strlen((char *)scert), &num); + if (foo == NULL || num == 0) { + log_print("keynote_cert_get_key: " + "failed to decompose credentials"); + return 0; + } + kid = kn_init(); + if (kid == -1) { + log_print("keynote_cert_get_key: " + "failed to initialize new policy session"); + while (num--) + free(foo[num]); + free(foo); + return 0; + } + sid = kn_add_assertion(kid, foo[num - 1], strlen(foo[num - 1]), 0); + while (num--) + free(foo[num]); + free(foo); + + if (sid == -1) { + log_print("keynote_cert_get_key: failed to add assertion"); + kn_close(kid); + return 0; + } + *(RSA **)keyp = NULL; + + kl = kn_get_licensees(kid, sid); + while (kl) { + if (kl->key_alg == KEYNOTE_ALGORITHM_RSA || + kl->key_alg == KEYNOTE_ALGORITHM_X509) { + *(RSA **)keyp = RSAPublicKey_dup(kl->key_key); + break; + } + kl = kl->key_next; + } + + kn_remove_assertion(kid, sid); + kn_close(kid); + return *(RSA **)keyp == NULL ? 0 : 1; +} + +void * +keynote_cert_dup(void *cert) +{ + return strdup((char *)cert); +} + +void +keynote_serialize(void *cert, u_int8_t **data, u_int32_t *datalen) +{ + *datalen = strlen((char *)cert) + 1; + *data = (u_int8_t *)strdup(cert); /* i.e an extra character at + * the end... */ + if (*data == NULL) + log_error("keynote_serialize: malloc (%d) failed", *datalen); +} + +/* From cert to printable */ +char * +keynote_printable(void *cert) +{ + return strdup((char *)cert); +} + +/* From printable to cert */ +void * +keynote_from_printable(char *cert) +{ + return strdup(cert); +} diff --git a/keyexchange/isakmpd-20041012/policy.h b/keyexchange/isakmpd-20041012/policy.h new file mode 100644 index 0000000..e4b5e9a --- /dev/null +++ b/keyexchange/isakmpd-20041012/policy.h @@ -0,0 +1,70 @@ +/* $OpenBSD: policy.h,v 1.15 2004/06/25 20:25:34 hshoexer Exp $ */ +/* $EOM: policy.h,v 1.12 2000/09/28 12:53:27 niklas Exp $ */ + +/* + * Copyright (c) 1999, 2000 Angelos D. Keromytis. All rights reserved. + * Copyright (c) 2000 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. + * + * 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 _POLICY_H_ +#define _POLICY_H_ + +#if defined (USE_KEYNOTE) +#define CREDENTIAL_FILE "credentials" +#define PRIVATE_KEY_FILE "private_key" +#endif + +extern int ignore_policy; +extern int policy_asserts_num; +extern int x509_policy_asserts_num; +extern int x509_policy_asserts_num_alloc; +extern char **policy_asserts; +extern char **x509_policy_asserts; +extern struct exchange *policy_exchange; +extern struct sa *policy_sa; +extern struct sa *policy_isakmp_sa; + +extern void policy_init(void); +extern char *policy_callback(char *); +extern int keynote_cert_init(void); +extern void *keynote_cert_get(u_int8_t *, u_int32_t); +extern int keynote_cert_validate(void *); +extern int keynote_cert_insert(int, void *); +extern void keynote_cert_free(void *); +extern int keynote_certreq_validate(u_int8_t *, u_int32_t); +extern void *keynote_certreq_decode(u_int8_t *, u_int32_t); +extern void keynote_free_aca(void *); +extern int keynote_cert_obtain(u_int8_t *, size_t, void *, + u_int8_t **, u_int32_t *); +extern int keynote_cert_get_subjects(void *, int *, u_int8_t ***, + u_int32_t **); +extern int keynote_cert_get_key(void *, void *); +extern void *keynote_cert_dup(void *); +extern void keynote_serialize(void *, u_int8_t **, u_int32_t *); +extern char *keynote_printable(void *); +extern void *keynote_from_printable(char *); +#endif /* _POLICY_H_ */ diff --git a/keyexchange/isakmpd-20041012/prf.c b/keyexchange/isakmpd-20041012/prf.c new file mode 100644 index 0000000..fdb91fe --- /dev/null +++ b/keyexchange/isakmpd-20041012/prf.c @@ -0,0 +1,161 @@ +/* $OpenBSD: prf.c,v 1.14 2004/05/23 18:17:56 hshoexer Exp $ */ +/* $EOM: prf.c,v 1.7 1999/05/02 12:50:29 niklas Exp $ */ + +/* + * Copyright (c) 1998 Niels Provos. All rights reserved. + * Copyright (c) 1999 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. + * + * 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 "sysdep.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, unsigned char *shared, + unsigned int sharedsize) +{ + struct hash *hash; + struct prf *prf; + struct prf_hash_ctx *prfctx; + + switch (type) { + case PRF_HMAC: + hash = hash_get(subtype); + if (!hash) { + log_print("prf_alloc: unknown hash type %d", subtype); + return 0; + } + break; + default: + log_print("prf_alloc: unknown PRF type %d", type); + return 0; + } + + prf = malloc(sizeof *prf); + if (!prf) { + log_error("prf_alloc: malloc (%lu) failed", + (unsigned long)sizeof *prf); + return 0; + } + if (type == PRF_HMAC) { + /* Obtain needed memory. */ + prfctx = malloc(sizeof *prfctx); + if (!prfctx) { + log_error("prf_alloc: malloc (%lu) failed", + (unsigned long)sizeof *prfctx); + goto cleanprf; + } + prf->prfctx = prfctx; + + prfctx->ctx = malloc(hash->ctxsize); + if (!prfctx->ctx) { + log_error("prf_alloc: malloc (%d) failed", + hash->ctxsize); + goto cleanprfctx; + } + prfctx->ctx2 = malloc(hash->ctxsize); + if (!prfctx->ctx2) { + log_error("prf_alloc: malloc (%d) failed", + hash->ctxsize); + 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 0; +} + +/* Deallocate the PRF pointed to by PRF. */ +void +prf_free(struct prf *prf) +{ + struct prf_hash_ctx *prfctx = prf->prfctx; + + if (prf->type == PRF_HMAC) { + free(prfctx->ctx2); + free(prfctx->ctx); + } + free(prf->prfctx); + free(prf); +} diff --git a/keyexchange/isakmpd-20041012/prf.h b/keyexchange/isakmpd-20041012/prf.h new file mode 100644 index 0000000..08a6fb3 --- /dev/null +++ b/keyexchange/isakmpd-20041012/prf.h @@ -0,0 +1,58 @@ +/* $OpenBSD: prf.h,v 1.10 2004/04/15 18:39:26 deraadt Exp $ */ +/* $EOM: prf.h,v 1.1 1998/07/11 20:06:22 provos Exp $ */ + +/* + * Copyright (c) 1998 Niels Provos. All rights reserved. + * Copyright (c) 2001 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. + * + * 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, unsigned char *, unsigned int); +void prf_free(struct prf *); + +#endif /* _PRF_H_ */ diff --git a/keyexchange/isakmpd-20041012/regress/Makefile b/keyexchange/isakmpd-20041012/regress/Makefile new file mode 100644 index 0000000..bcbf7e5 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/Makefile @@ -0,0 +1,34 @@ +# $OpenBSD: Makefile,v 1.9 2003/06/03 14:39:50 ho Exp $ +# $EOM: Makefile,v 1.8 1999/07/17 20:44:13 niklas Exp $ + +# +# Copyright (c) 1998, 1999 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. +# +# 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= b2n crypto dh ec2n exchange group hmac prf rsakeygen util x509 + +.include <bsd.subdir.mk> diff --git a/keyexchange/isakmpd-20041012/regress/b2n/.cvsignore b/keyexchange/isakmpd-20041012/regress/b2n/.cvsignore new file mode 100644 index 0000000..ed605b2 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/b2n/.cvsignore @@ -0,0 +1,2 @@ +b2ntest +obj diff --git a/keyexchange/isakmpd-20041012/regress/b2n/Makefile b/keyexchange/isakmpd-20041012/regress/b2n/Makefile new file mode 100644 index 0000000..57ffb1f --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/b2n/Makefile @@ -0,0 +1,16 @@ +# $OpenBSD: Makefile,v 1.7 2004/02/25 16:01:29 hshoexer Exp $ +# $EOM: Makefile,v 1.12 2000/10/13 13:04:17 ho Exp $ + +# Test some math + +PROG= b2ntest +SRCS= b2ntest.c conf.c log.c math_2n.c sysdep.c util.c +NOMAN= +TOPSRC= ${.CURDIR}/../.. +TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- +OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile +.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} +CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall +DEBUG= -g + +.include <bsd.prog.mk> diff --git a/keyexchange/isakmpd-20041012/regress/b2n/b2ntest.c b/keyexchange/isakmpd-20041012/regress/b2n/b2ntest.c new file mode 100644 index 0000000..97284db --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/b2n/b2ntest.c @@ -0,0 +1,368 @@ +/* $OpenBSD: b2ntest.c,v 1.8 2003/06/03 14:39:50 ho Exp $ */ +/* $EOM: b2ntest.c,v 1.4 1998/07/16 19:31:55 provos Exp $ */ + +/* + * Copyright (c) 1998 Niels Provos. All rights reserved. + * Copyright (c) 2001 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. + * + * 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 BUFSIZE 200 + +#define CMP_FAIL(n,x) b2n_snprint (buf, BUFSIZE, 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[BUFSIZE]; + + 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_snprint (buf, BUFSIZE, 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/keyexchange/isakmpd-20041012/regress/check.sh b/keyexchange/isakmpd-20041012/regress/check.sh new file mode 100644 index 0000000..ea726c5 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/check.sh @@ -0,0 +1,88 @@ +#!/bin/sh +# $OpenBSD: check.sh,v 1.4 2003/06/03 14:39:50 ho Exp $ +# $EOM: check.sh,v 1.4 1998/07/17 21:33:13 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. +# +# 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/keyexchange/isakmpd-20041012/regress/crypto/.cvsignore b/keyexchange/isakmpd-20041012/regress/crypto/.cvsignore new file mode 100644 index 0000000..7b3c6ec --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/crypto/.cvsignore @@ -0,0 +1,2 @@ +cryptotest +obj diff --git a/keyexchange/isakmpd-20041012/regress/crypto/Makefile b/keyexchange/isakmpd-20041012/regress/crypto/Makefile new file mode 100644 index 0000000..b2a0ef9 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/crypto/Makefile @@ -0,0 +1,20 @@ +# $OpenBSD: Makefile,v 1.11 2004/02/25 16:01:29 hshoexer Exp $ +# $EOM: Makefile,v 1.7 2000/03/28 21:22:06 ho Exp $ + +# Test Crypto: + +PROG= cryptotest +SRCS= crypto.c cryptotest.c conf.c log.c sysdep.c util.c +TOPSRC= ${.CURDIR}/../.. +TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- +OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile +.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} +CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall \ + -DUSE_TRIPLEDES -DUSE_CAST -DUSE_BLOWFISH -DUSE_DES \ + -DUSE_AES +LDADD+= -lcrypto -ldes +DPADD+= ${LIBCRYPTO} ${LIBDES} +NOMAN= +DEBUG= -g + +.include <bsd.prog.mk> diff --git a/keyexchange/isakmpd-20041012/regress/crypto/cryptotest.c b/keyexchange/isakmpd-20041012/regress/crypto/cryptotest.c new file mode 100644 index 0000000..d860ddd --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/crypto/cryptotest.c @@ -0,0 +1,178 @@ +/* $OpenBSD: cryptotest.c,v 1.13 2004/04/07 22:45:50 ho Exp $ */ +/* $EOM: cryptotest.c,v 1.5 1998/10/07 16:40:49 niklas Exp $ */ + +/* + * Copyright (c) 1998 Niels Provos. All rights reserved. + * Copyright (c) 2001 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. + * + * 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) {size_t 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))) + +static 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); + + test_crypto (AES_CBC); + + special_test_blf (); + + return 1; +} + +void +dump_buf (u_int8_t *buf, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) + printf ("%02x ", buf[i]); + printf ("\n"); +} + +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)); + dump_buf (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/keyexchange/isakmpd-20041012/regress/dh/.cvsignore b/keyexchange/isakmpd-20041012/regress/dh/.cvsignore new file mode 100644 index 0000000..d47de54 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/dh/.cvsignore @@ -0,0 +1,2 @@ +dhtest +obj diff --git a/keyexchange/isakmpd-20041012/regress/dh/Makefile b/keyexchange/isakmpd-20041012/regress/dh/Makefile new file mode 100644 index 0000000..e7f8d79 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/dh/Makefile @@ -0,0 +1,29 @@ +# $OpenBSD: Makefile,v 1.8 2004/02/25 16:01:29 hshoexer Exp $ +# $EOM: Makefile,v 1.10 2000/04/07 20:19:43 niklas Exp $ + +# Test DH: + +PROG= dhtest +SRCS= math_2n.c math_ec2n.c math_group.c dh.c dhtest.c log.c util.c \ + sysdep.c gmp_util.c conf.c +TOPSRC= ${.CURDIR}/../.. +TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- +OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile +FEATURES!= awk '/^FEATURES=/ { print $$0 }' ${.CURDIR}/../../Makefile | sed 's/FEATURES=.//' +.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} +CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall \ + -DUSE_EC +NOMAN= +LDADD+= -lcrypto +DPADD+= ${LIBCRYPTO} +DEBUG= -g + +.if ${FEATURES:Mgmp} == "gmp" +CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_GMP +LDADD+= -lgmp +DPADD+= ${LIBGMP} +.else +CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL +.endif + +.include <bsd.prog.mk> diff --git a/keyexchange/isakmpd-20041012/regress/dh/dhtest.c b/keyexchange/isakmpd-20041012/regress/dh/dhtest.c new file mode 100644 index 0000000..ef23caf --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/dh/dhtest.c @@ -0,0 +1,102 @@ +/* $OpenBSD: dhtest.c,v 1.5 2003/06/03 14:39:50 ho Exp $ */ +/* $EOM: dhtest.c,v 1.1 1998/07/18 21:14:20 provos 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. + * + * 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/keyexchange/isakmpd-20041012/regress/ec2n/.cvsignore b/keyexchange/isakmpd-20041012/regress/ec2n/.cvsignore new file mode 100644 index 0000000..6f2d7c6 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/ec2n/.cvsignore @@ -0,0 +1,2 @@ +ec2ntest +obj diff --git a/keyexchange/isakmpd-20041012/regress/ec2n/Makefile b/keyexchange/isakmpd-20041012/regress/ec2n/Makefile new file mode 100644 index 0000000..827ecbe --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/ec2n/Makefile @@ -0,0 +1,16 @@ +# $OpenBSD: Makefile,v 1.7 2004/02/25 16:01:29 hshoexer Exp $ +# $EOM: Makefile,v 1.9 2000/10/13 13:04:17 ho Exp $ + +# Test EC2N: + +PROG= ec2ntest +SRCS= math_2n.c math_ec2n.c ec2ntest.c log.c sysdep.c util.c conf.c +TOPSRC= ${.CURDIR}/../.. +TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- +OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile +.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} +CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall +NOMAN= +DEBUG= -g + +.include <bsd.prog.mk> diff --git a/keyexchange/isakmpd-20041012/regress/ec2n/ec2ntest.c b/keyexchange/isakmpd-20041012/regress/ec2n/ec2ntest.c new file mode 100644 index 0000000..0535e8c --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/ec2n/ec2ntest.c @@ -0,0 +1,144 @@ +/* $OpenBSD: ec2ntest.c,v 1.5 2003/06/04 07:31:17 ho Exp $ */ +/* $EOM: ec2ntest.c,v 1.3 1998/07/16 09:21:59 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. + * + * 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 BUFSIZE 200 + +#define CMP_FAIL(n,x) b2n_snprint (buf, BUFSIZE, 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[BUFSIZE]; + + 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/keyexchange/isakmpd-20041012/regress/exchange/.cvsignore b/keyexchange/isakmpd-20041012/regress/exchange/.cvsignore new file mode 100644 index 0000000..b672fde --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/exchange/.cvsignore @@ -0,0 +1 @@ +obj diff --git a/keyexchange/isakmpd-20041012/regress/exchange/Makefile b/keyexchange/isakmpd-20041012/regress/exchange/Makefile new file mode 100644 index 0000000..ac22db8 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/exchange/Makefile @@ -0,0 +1,58 @@ +# $OpenBSD: Makefile,v 1.7 2003/06/03 14:39:50 ho Exp $ +# $EOM: Makefile,v 1.8 2000/03/28 21:22:07 ho Exp $ + +# +# Copyright (c) 1998, 1999 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. +# +# 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. +# + +TOPSRC= ${.CURDIR}/../.. +TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- +OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile +.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} +CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall +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/keyexchange/isakmpd-20041012/regress/exchange/README b/keyexchange/isakmpd-20041012/regress/exchange/README new file mode 100644 index 0000000..cd1555b --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/exchange/README @@ -0,0 +1,78 @@ +$OpenBSD: README,v 1.1 1999/08/05 22:41:39 niklas Exp $ +$EOM: README,v 1.1 1999/08/05 15:07:37 niklas Exp $ + +XXX The old run.sh test-framework is obsoleted, it will go away anyday. + +We wanted to do a regression test environment which was flexible +enough to be able to easily reproduce anomalies in isakmpd. It +turns out this is not easy to do, as many problems are timing related. + +Currently ticks are milliseconds. An idea is to try to measure +isakmpd's response time somehow, and use that time as some kind of +basis for a tick. + +Our test environment should be able to parse scripts like this: + +#Tick Action Format Data +0 send H* ffffffff +0 recv H* 00000000 +1000 send H* deadbeef + +Ticks are not absolute but relative to the last event. the format is +Perl's pack/unpack template formats. Data is in the given format with +one exception, spaces are ignored, newlines are end-of-data unless +preceeded by a backslash. + +Comments are lines with a numbersign as the first non-whitespace +character. Empty lines are ignored, unless inside a multi-line data +in which it will be part of the data buffer. + +Here is a real world example: + +# $RCSId$ + +# Initiate a MM +0 send H* ad9de636 f12460bb 00000000 00000000 01100200 00000000 \ + 00000050 00000034 00000001 00000001 00000028 01010001 \ + 00000020 00010000 80010005 80020002 80030001 80040002 \ + 800b0001 800c0258 + +400 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 01100200 00000000 \ + 00000050 00000034 00000001 00000001 00000028 01010001 \ + 00000020 00010000 80010005 80020002 80030001 80040002 \ + 800b0001 800c0258 + +110 send H* ad9de636 f12460bb 2aa5a583 ab2f3980 04100200 00000000 \ + 000000b4 0a000084 60a8c102 ce97687e 45e3fdd9 6fd586b4 \ + f3a91167 559dd214 a78d678e 2772b7b2 83267487 15ec02a9 \ + 419b77ee 0f2add09 e9e09b7d ad40c883 ef2039c9 c59b67ff \ + 56e4d6f8 c99d47cb d4a565bc 8d192f76 f695d243 09121df5 \ + 524884a7 3f702630 7f4fad44 e222c4b1 242fd1cd ca3a161d \ + bcdf6706 025cc90d c4b00ef9 bee5ada2 00000014 ff7c493c \ + 88e68a10 4ab19a6a 7e75c771 + +800 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 04100200 00000000 \ + 000000b4 0a000084 681b9859 7680a3ff 894bb982 ef924bc8 \ + 4d9c7ebf 3a92db7b bcfe68f7 6e1de327 a975293f f5c550b1 \ + 9c69d6ed 64f201ec 514f4f44 0e6242b9 df4917e6 4418212d \ + 66a66eb1 f3b70c2d 4e14e382 d42ebe04 1027957c 5dadcaf1 \ + a531c085 6cee739f 433c185c 12a8a946 88622f66 f211783c \ + 277e134d 22d8e809 f1d38bab 6ca2a35f 00000014 6a917048 \ + a406fd47 b3d16554 cd6f0967 + +140 send H* ad9de636 f12460bb 2aa5a583 ab2f3980 05100201 00000000 \ + 0000005c d6571dec a8b55acb 1069210c 7d195417 1c2738e9 \ + 42f1d9a3 8561d0ec 0697cd06 ac1beb19 1dc8acf5 904ec1d5 \ + 5b2b154e 38b0de90 4f2e1f71 083047ca 10cab3d5 + +900 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 05100201 00000000 \ + 00000044 b46b1db4 9ecfbfa6 a5e9baa2 8eb3cb68 be3a857c \ + b039fa72 d595e69f 03669dbd 350781e2 56c36dce + +run with: + +perl run.pl filename + +You need to have an isakmpd listening on the address which is given in +run.pl. Of course you need to run it in deterministic mode (-r). +There will be a better explanation soon. diff --git a/keyexchange/isakmpd-20041012/regress/exchange/def-i.1 b/keyexchange/isakmpd-20041012/regress/exchange/def-i.1 Binary files differnew file mode 100644 index 0000000..1712249 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/exchange/def-i.1 diff --git a/keyexchange/isakmpd-20041012/regress/exchange/def-r.1 b/keyexchange/isakmpd-20041012/regress/exchange/def-r.1 Binary files differnew file mode 100644 index 0000000..56f5e62 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/exchange/def-r.1 diff --git a/keyexchange/isakmpd-20041012/regress/exchange/mm-1-setup.sh b/keyexchange/isakmpd-20041012/regress/exchange/mm-1-setup.sh new file mode 100644 index 0000000..0efd7c9 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/exchange/mm-1-setup.sh @@ -0,0 +1,12 @@ +# $OpenBSD: mm-1-setup.sh,v 1.2 2000/01/26 15:23:52 niklas Exp $ +# $EOM: mm-1-setup.sh,v 1.2 1999/10/05 12:54:27 niklas Exp $ + +# XXX Need to start isakmpd here in a nice way. + +echo "C set [Phase 1]:127.0.0.1=localhost 1">/tmp/fifo +echo "C set [localhost]:phase=1 1">/tmp/fifo +echo "C set [localhost]:transport=udp 1">/tmp/fifo +echo "C set [localhost]:address=127.0.0.1 1">/tmp/fifo +echo "C set [localhost]:port=1501 1">/tmp/fifo +echo "C set [localhost]:configuration=default-main-mode 1">/tmp/fifo +echo "C set [localhost]:authentication=mekmitasdigoat 1">/tmp/fifo diff --git a/keyexchange/isakmpd-20041012/regress/exchange/mm-i-1.t b/keyexchange/isakmpd-20041012/regress/exchange/mm-i-1.t new file mode 100644 index 0000000..9f9b1be --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/exchange/mm-i-1.t @@ -0,0 +1,43 @@ +# $OpenBSD: mm-i-1.t,v 1.1 1999/08/05 22:41:39 niklas Exp $ +# $EOM: mm-i-1.t,v 1.1 1999/08/05 15:07:38 niklas Exp $ + +# The seed to isakmpd was 19990805 + +# Initiate a MM +0 send H* ad9de636 f12460bb 00000000 00000000 01100200 00000000 \ + 00000050 00000034 00000001 00000001 00000028 01010001 \ + 00000020 00010000 80010005 80020002 80030001 80040002 \ + 800b0001 800c0258 + +400 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 01100200 00000000 \ + 00000050 00000034 00000001 00000001 00000028 01010001 \ + 00000020 00010000 80010005 80020002 80030001 80040002 \ + 800b0001 800c0258 + +110 send H* ad9de636 f12460bb 2aa5a583 ab2f3980 04100200 00000000 \ + 000000b4 0a000084 60a8c102 ce97687e 45e3fdd9 6fd586b4 \ + f3a91167 559dd214 a78d678e 2772b7b2 83267487 15ec02a9 \ + 419b77ee 0f2add09 e9e09b7d ad40c883 ef2039c9 c59b67ff \ + 56e4d6f8 c99d47cb d4a565bc 8d192f76 f695d243 09121df5 \ + 524884a7 3f702630 7f4fad44 e222c4b1 242fd1cd ca3a161d \ + bcdf6706 025cc90d c4b00ef9 bee5ada2 00000014 ff7c493c \ + 88e68a10 4ab19a6a 7e75c771 + +800 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 04100200 00000000 \ + 000000b4 0a000084 681b9859 7680a3ff 894bb982 ef924bc8 \ + 4d9c7ebf 3a92db7b bcfe68f7 6e1de327 a975293f f5c550b1 \ + 9c69d6ed 64f201ec 514f4f44 0e6242b9 df4917e6 4418212d \ + 66a66eb1 f3b70c2d 4e14e382 d42ebe04 1027957c 5dadcaf1 \ + a531c085 6cee739f 433c185c 12a8a946 88622f66 f211783c \ + 277e134d 22d8e809 f1d38bab 6ca2a35f 00000014 6a917048 \ + a406fd47 b3d16554 cd6f0967 + +140 send H* ad9de636 f12460bb 2aa5a583 ab2f3980 05100201 00000000 \ + 0000005c d6571dec a8b55acb 1069210c 7d195417 1c2738e9 \ + 42f1d9a3 8561d0ec 0697cd06 ac1beb19 1dc8acf5 904ec1d5 \ + 5b2b154e 38b0de90 4f2e1f71 083047ca 10cab3d5 + +900 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 05100201 00000000 \ + 00000044 b46b1db4 9ecfbfa6 a5e9baa2 8eb3cb68 be3a857c \ + b039fa72 d595e69f 03669dbd 350781e2 56c36dce + diff --git a/keyexchange/isakmpd-20041012/regress/exchange/mm-r-1.t b/keyexchange/isakmpd-20041012/regress/exchange/mm-r-1.t new file mode 100644 index 0000000..0c48224 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/exchange/mm-r-1.t @@ -0,0 +1,42 @@ +# $OpenBSD: mm-r-1.t,v 1.1 1999/08/05 22:41:39 niklas Exp $ +# $EOM: mm-r-1.t,v 1.1 1999/08/05 15:07:38 niklas Exp $ + +# The seed to isakmpd was 19990805 + +# Respond to this MM +999999 recv H* ad9de636 f12460bb 00000000 00000000 01100200 00000000 \ + 00000050 00000034 00000001 00000001 00000028 01010001 \ + 00000020 00010000 80010005 80020002 80030001 80040002 \ + 800b0001 800c0258 + +40 send H* ad9de636 f12460bb 2aa5a583 ab2f3980 01100200 00000000 \ + 00000050 00000034 00000001 00000001 00000028 01010001 \ + 00000020 00010000 80010005 80020002 80030001 80040002 \ + 800b0001 800c0258 + +1100 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 04100200 00000000 \ + 000000b4 0a000084 60a8c102 ce97687e 45e3fdd9 6fd586b4 \ + f3a91167 559dd214 a78d678e 2772b7b2 83267487 15ec02a9 \ + 419b77ee 0f2add09 e9e09b7d ad40c883 ef2039c9 c59b67ff \ + 56e4d6f8 c99d47cb d4a565bc 8d192f76 f695d243 09121df5 \ + 524884a7 3f702630 7f4fad44 e222c4b1 242fd1cd ca3a161d \ + bcdf6706 025cc90d c4b00ef9 bee5ada2 00000014 ff7c493c \ + 88e68a10 4ab19a6a 7e75c771 + +80 send H* ad9de636 f12460bb 2aa5a583 ab2f3980 04100200 00000000 \ + 000000b4 0a000084 681b9859 7680a3ff 894bb982 ef924bc8 \ + 4d9c7ebf 3a92db7b bcfe68f7 6e1de327 a975293f f5c550b1 \ + 9c69d6ed 64f201ec 514f4f44 0e6242b9 df4917e6 4418212d \ + 66a66eb1 f3b70c2d 4e14e382 d42ebe04 1027957c 5dadcaf1 \ + a531c085 6cee739f 433c185c 12a8a946 88622f66 f211783c \ + 277e134d 22d8e809 f1d38bab 6ca2a35f 00000014 6a917048 \ + a406fd47 b3d16554 cd6f0967 + +1400 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 05100201 00000000 \ + 0000005c d6571dec a8b55acb 1069210c 7d195417 1c2738e9 \ + 42f1d9a3 8561d0ec 0697cd06 ac1beb19 1dc8acf5 904ec1d5 \ + 5b2b154e 38b0de90 4f2e1f71 083047ca 10cab3d5 + +90 send H* ad9de636 f12460bb 2aa5a583 ab2f3980 05100201 00000000 \ + 00000044 b46b1db4 9ecfbfa6 a5e9baa2 8eb3cb68 be3a857c \ + b039fa72 d595e69f 03669dbd 350781e2 56c36dce diff --git a/keyexchange/isakmpd-20041012/regress/exchange/run.pl b/keyexchange/isakmpd-20041012/regress/exchange/run.pl new file mode 100644 index 0000000..d9fce2d --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/exchange/run.pl @@ -0,0 +1,105 @@ +#!/usr/bin/perl +# $OpenBSD: run.pl,v 1.2 2004/01/26 14:56:03 niklas Exp $ +# $EOM: run.pl,v 1.2 1999/08/05 22:42:42 niklas Exp $ + +# +# Copyright (c) 2004 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. +# +# 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. +# + +use strict; +require 5.002; +require 'sys/syscall.ph'; +use Socket; +use Sys::Hostname; + +my ($rfd, $tickfac, $myaddr, $myport, $hisaddr, $hisport, $proto, $bindaddr, + $conaddr, $sec, $tick, $action, $template, $data, $next, + $nfd, $pkt, $verbose); + +$| = 1; + +$verbose = 1; +$tickfac = 0.001; +$myaddr = gethostbyname ('127.0.0.1'); +$myport = 1501; + $hisaddr = inet_aton ('127.0.0.1'); +$hisport = 1500; + +$proto = getprotobyname ('udp'); +$bindaddr = sockaddr_in ($myport, $myaddr); +socket (SOCKET, PF_INET, SOCK_DGRAM, $proto) || die "socket: $!"; +bind (SOCKET, $bindaddr); +vec ($rfd, fileno SOCKET, 1) = 1; + +$conaddr = sockaddr_in ($hisport, $hisaddr); + +sub getsec +{ + my ($tv) = pack ("ll", 0, 0); + my ($tz) = pack ("ii", 0, 0); + syscall (&SYS_gettimeofday, $tv, $tz) && return undef; + my ($sec, $usec) = unpack ("ll", $tv); + $sec % 86400 + $usec / 1000000; +} + +$sec = &getsec; +while (<>) { + next if /^\s*#/o || /^\s*$/o; + chop; + ($tick, $action, $template, $data) = split ' ', $_, 4; + while ($data =~ /\\$/o) { + chop $data; + $_ = <>; + next if /^\s*#/o; + chop; + $data .= $_; + } + $data =~ s/\s//go; + $data = pack $template, $data; + $next = $sec + $tick * $tickfac; + if ($action eq "send") { + # Wait for the moment to come. + print STDERR "waiting ", $next - $sec, " secs\n"; + select undef, undef, undef, $next - $sec + while ($sec = &getsec) < $next; +# print $data; + send SOCKET, $data, 0, $conaddr; + print STDERR "sent ", unpack ("H*", $data), "\n" if $verbose; + } elsif ($action eq "recv") { + $sec = &getsec; + printf (STDERR "waiting for data or the %.3f sec timeout\n", + $next - $sec); + $nfd = select $rfd, undef, undef, $next - $sec; + if ($nfd) { + printf STDERR "got back after %.3f secs\n", &getsec - $sec + if $verbose; +# sysread (STDIN, $pkt, 65536) if $nfd; + sysread (SOCKET, $pkt, 65536) if $nfd; + print STDERR "read ", unpack ("H*", $pkt), "\n" if $verbose; + print STDERR "cmp ", unpack ("H*", $data), "\n" if $verbose; + } else { + print STDERR "timed out\n" if $verbose; + } + die "mismatch\n" if $pkt ne $data; + } +} diff --git a/keyexchange/isakmpd-20041012/regress/exchange/run.sh b/keyexchange/isakmpd-20041012/regress/exchange/run.sh new file mode 100644 index 0000000..587c2c1 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/exchange/run.sh @@ -0,0 +1,137 @@ +#!/bin/sh +# $OpenBSD: run.sh,v 1.8 2004/01/09 10:03:04 hshoexer Exp $ +# $EOM: run.sh,v 1.6 1999/08/05 15:02:33 niklas Exp $ + +# +# Copyright (c) 1998, 1999 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. +# +# 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. +# + +# Defaults +SRCPORT=1500 +DSTPORT=1501 +FIFO=test.fifo +TIMEOUT=2 + +NC=${NC:-/usr/bin/nc} +ISAKMPD=${ISAKMPD:-/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} 127.0.0.1 ${DSTPORT} </dev/null >packet & +# ${NC} -nu -w${TIMEOUT} -p${SRCPORT} 127.0.0.1 ${DSTPORT} </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${SRCPORT} 127.0.0.1 ${DSTPORT} \ + >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/keyexchange/isakmpd-20041012/regress/group/.cvsignore b/keyexchange/isakmpd-20041012/regress/group/.cvsignore new file mode 100644 index 0000000..2326f3a --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/group/.cvsignore @@ -0,0 +1,2 @@ +grouptest +obj diff --git a/keyexchange/isakmpd-20041012/regress/group/Makefile b/keyexchange/isakmpd-20041012/regress/group/Makefile new file mode 100644 index 0000000..9dc9982 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/group/Makefile @@ -0,0 +1,29 @@ +# $OpenBSD: Makefile,v 1.8 2004/02/25 16:01:29 hshoexer Exp $ +# $EOM: Makefile,v 1.12 2000/04/07 20:19:43 niklas Exp $ + +# Test Group: + +PROG= grouptest +SRCS= math_2n.c math_ec2n.c math_group.c grouptest.c log.c util.c \ + sysdep.c gmp_util.c conf.c +TOPSRC= ${.CURDIR}/../.. +TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- +OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile +FEATURES!= awk '/^FEATURES=/ { print $$0 }' ${.CURDIR}/../../Makefile | sed 's/FEATURES=.//' +.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} +CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall \ + -DUSE_EC +NOMAN= +LDADD+= -lcrypto +DPADD+= ${LIBCRYPTO} +DEBUG= -g + +.if ${FEATURES:Mgmp} == "gmp" +CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_GMP +LDADD+= -lgmp +DPADD+= ${LIBGMP} +.else +CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL +.endif + +.include <bsd.prog.mk> diff --git a/keyexchange/isakmpd-20041012/regress/group/grouptest.c b/keyexchange/isakmpd-20041012/regress/group/grouptest.c new file mode 100644 index 0000000..ba03283 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/group/grouptest.c @@ -0,0 +1,121 @@ +/* $OpenBSD: grouptest.c,v 1.4 2003/06/03 14:39:51 ho Exp $ */ +/* $EOM: grouptest.c,v 1.2 1998/07/18 21:15:55 provos 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. + * + * 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/keyexchange/isakmpd-20041012/regress/hmac/.cvsignore b/keyexchange/isakmpd-20041012/regress/hmac/.cvsignore new file mode 100644 index 0000000..5fc5f86 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/hmac/.cvsignore @@ -0,0 +1,2 @@ +hmactest +obj diff --git a/keyexchange/isakmpd-20041012/regress/hmac/Makefile b/keyexchange/isakmpd-20041012/regress/hmac/Makefile new file mode 100644 index 0000000..39bb2c7 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/hmac/Makefile @@ -0,0 +1,16 @@ +# $OpenBSD: Makefile,v 1.4 1999/02/26 03:28:31 niklas Exp $ +# $EOM: Makefile,v 1.3 1999/02/25 15:14:24 niklas Exp $ + +# Test HMAC: + +PROG= hmactest +SRCS= hash.c hmactest.c +TOPSRC= ${.CURDIR}/../.. +TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- +OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile +.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} +CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall +NOMAN= +DEBUG= -g + +.include <bsd.prog.mk> diff --git a/keyexchange/isakmpd-20041012/regress/hmac/hmactest.c b/keyexchange/isakmpd-20041012/regress/hmac/hmactest.c new file mode 100644 index 0000000..3b86f06 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/hmac/hmactest.c @@ -0,0 +1,93 @@ +/* $OpenBSD: hmactest.c,v 1.5 2003/06/04 07:31:17 ho Exp $ */ +/* $EOM: hmactest.c,v 1.3 1998/08/09 19:16:24 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. + * + * 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/keyexchange/isakmpd-20041012/regress/prf/.cvsignore b/keyexchange/isakmpd-20041012/regress/prf/.cvsignore new file mode 100644 index 0000000..023b310 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/prf/.cvsignore @@ -0,0 +1,2 @@ +prftest +obj diff --git a/keyexchange/isakmpd-20041012/regress/prf/Makefile b/keyexchange/isakmpd-20041012/regress/prf/Makefile new file mode 100644 index 0000000..5d9b1fa --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/prf/Makefile @@ -0,0 +1,16 @@ +# $OpenBSD: Makefile,v 1.7 2004/02/25 16:01:29 hshoexer Exp $ +# $EOM: Makefile,v 1.6 2000/03/28 21:22:07 ho Exp $ + +# Test PRF: + +PROG= prftest +SRCS= prf.c hash.c log.c prftest.c conf.c sysdep.c util.c +TOPSRC= ${.CURDIR}/../.. +TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- +OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile +.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} +CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall +NOMAN= +DEBUG= -g + +.include <bsd.prog.mk> diff --git a/keyexchange/isakmpd-20041012/regress/prf/prftest.c b/keyexchange/isakmpd-20041012/regress/prf/prftest.c new file mode 100644 index 0000000..15d7578 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/prf/prftest.c @@ -0,0 +1,116 @@ +/* $OpenBSD: prftest.c,v 1.7 2003/06/03 14:39:51 ho Exp $ */ +/* $EOM: prftest.c,v 1.2 1998/10/07 16:40: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. + * + * 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"); + test_prf ("PRF SHA1 Test Case 3", HASH_SHA1, + "Bloody long key, this one, eben longer than the blocksize " + "of ordinary keyed HMAC functions", 90, + "what do ya want for nothing?", 28, + "52ca5fbcd7d4821bc6bf8b6e95e131109dff901b"); + + return 0; +} + +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) + { + printf("prf_alloc () failed\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) == 0) + { + printf ("OKAY\n"); + return 1; + } + + printf ("%s <-> %s\n", output, cmp); + return 0; +} diff --git a/keyexchange/isakmpd-20041012/regress/rsakeygen/.cvsignore b/keyexchange/isakmpd-20041012/regress/rsakeygen/.cvsignore new file mode 100644 index 0000000..0ecb82e --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/rsakeygen/.cvsignore @@ -0,0 +1,4 @@ +isakmpd_key +isakmpd_key.pub +rsakeygen +obj diff --git a/keyexchange/isakmpd-20041012/regress/rsakeygen/Makefile b/keyexchange/isakmpd-20041012/regress/rsakeygen/Makefile new file mode 100644 index 0000000..578a7b5 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/rsakeygen/Makefile @@ -0,0 +1,83 @@ +# $OpenBSD: Makefile,v 1.15 2004/02/25 16:01:29 hshoexer Exp $ +# $EOM: Makefile,v 1.10 2000/03/28 21:23:24 ho Exp $ + +# +# Copyright (c) 1999 Niels Provos. All rights reserved. +# Copyright (c) 1999, 2001 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. +# +# 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. +# + +# RSA Key Generation + +PROG= rsakeygen +SRCS= libcrypto.c log.c rsakeygen.c sysdep.c util.c conf.c +TOPSRC= ${.CURDIR}/../.. +TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- +OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile +FEATURES!= awk '/^FEATURES=/ { print $$0 }' ${.CURDIR}/../../Makefile | sed 's/FEATURES=.//' +.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} +CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall \ + -DUSE_DEBUG +NOMAN= +DEBUG= -g + +.if ${FEATURES:Mgmp} == "gmp" +CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_GMP +LDADD+= -lgmp +DPADD+= ${LIBGMP} +.else +CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL +.endif + +.include "${TOPSRC}/sysdep/${OS}/Makefile.sysdep" + +.ifdef HAVE_DLOPEN +CFLAGS+= -DHAVE_DLOPEN +SRCS+= dyn.c +.endif + +.ifdef USE_LIBCRYPTO +CFLAGS+= -DUSE_LIBCRYPTO +LDADD+= -lcrypto +DPADD+= ${LIBCRYPTO} +.endif + +.if !defined (HAVE_DLOPEN) && !defined (USE_LIBCRYPTO) +.BEGIN: + @echo RSA cannot be used in this environmet, skipping... + +PROG= +.else +# USE_X509 is required for libcrypto.h to include the correct headers, +# but it is not set by ${OS}/Makefile.sysdep - setting it manually here +# should be safe enough. +CFLAGS+= -DUSE_X509 +.endif + +LDADD+= ${DESLIB} +DPADD+= ${DESLIBDEP} + +.include <bsd.prog.mk> diff --git a/keyexchange/isakmpd-20041012/regress/rsakeygen/rsakeygen.c b/keyexchange/isakmpd-20041012/regress/rsakeygen/rsakeygen.c new file mode 100644 index 0000000..08548a0 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/rsakeygen/rsakeygen.c @@ -0,0 +1,128 @@ +/* $OpenBSD: rsakeygen.c,v 1.19 2004/02/26 15:27:05 hshoexer Exp $ */ +/* $EOM: rsakeygen.c,v 1.10 2000/12/21 15:18:53 ho Exp $ */ + +/* + * Copyright (c) 1998, 1999 Niels Provos. All rights reserved. + * Copyright (c) 1999, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2001 Håkan Olsson. 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. + * + * 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 "libcrypto.h" +#include "log.h" +#include "math_mp.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))) + +#define TEST_STRING "!Dies ist ein Test" + +int +main (void) +{ + u_int8_t enc[256], dec[256], *asn, *foo; + int len; + FILE *fd; + int erg = 0; + RSA *key; + + libcrypto_init (); + + log_debug_cmd (LOG_CRYPTO, 99); + memset (dec, '\0', sizeof dec); + strlcpy (dec, TEST_STRING, 256); + + key = RSA_generate_key (1024, RSA_F4, NULL, NULL); + if (key == NULL) + { + printf("Failed to generate key\n"); + return 0; + } + + printf ("n: 0x"); + BN_print_fp (stdout, key->n); + printf ("\ne: 0x"); + BN_print_fp (stdout, key->e); + printf ("\n"); + + printf ("n: 0x"); + BN_print_fp (stdout, key->n); + printf ("\ne: 0x"); + BN_print_fp (stdout, key->e); + printf ("\nd: 0x"); + BN_print_fp (stdout, key->d); + printf ("\np: 0x"); + BN_print_fp (stdout, key->p); + printf ("\nq: 0x"); + BN_print_fp (stdout, key->q); + printf ("\n"); + + printf ("Testing Signing/Verifying: "); + /* Sign with Private Key */ + len = RSA_private_encrypt (strlen (dec) + 1, dec, enc, key, + RSA_PKCS1_PADDING); + if (len == -1) + printf ("SIGN FAILED "); + else + { + /* Decrypt/Verify with Public Key */ + erg = RSA_public_decrypt (len, enc, dec, key, RSA_PKCS1_PADDING); + + if (erg == -1 || strcmp (dec, TEST_STRING)) + printf ("VERIFY FAILED"); + else + printf ("OKAY"); + } + + printf ("\n"); + + len = i2d_RSAPublicKey (key, NULL); + foo = asn = malloc (len); + len = i2d_RSAPublicKey (key, &foo); + fd = fopen ("isakmpd_key.pub", "w"); + fwrite (asn, len, 1, fd); + fclose (fd); + free (asn); + + len = i2d_RSAPrivateKey (key, NULL); + foo = asn = malloc (len); + len = i2d_RSAPrivateKey (key, &foo); + fd = fopen ("isakmpd_key", "w"); + fwrite (asn, len, 1, fd); + fclose (fd); + free (asn); + + RSA_free (key); + + return 1; +} diff --git a/keyexchange/isakmpd-20041012/regress/util/Makefile b/keyexchange/isakmpd-20041012/regress/util/Makefile new file mode 100644 index 0000000..88c0785 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/util/Makefile @@ -0,0 +1,15 @@ +# $OpenBSD: Makefile,v 1.2 2004/02/25 16:01:29 hshoexer Exp $ + +# Test some utility functions + +PROG= utiltest +SRCS= log.c sysdep.c util.c utiltest.c conf.c +TOPSRC= ${.CURDIR}/../.. +TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- +OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile +.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} +CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall +NOMAN= +DEBUG= -g + +.include <bsd.prog.mk> diff --git a/keyexchange/isakmpd-20041012/regress/util/utiltest.c b/keyexchange/isakmpd-20041012/regress/util/utiltest.c new file mode 100644 index 0000000..89d8615 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/util/utiltest.c @@ -0,0 +1,85 @@ +/* $OpenBSD: utiltest.c,v 1.3 2003/06/03 14:39:51 ho Exp $ */ + +/* + * Copyright (c) 2001 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. + * + * 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. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <stdio.h> + +#include "sysdep.h" + +#include "util.h" + +int test_1 (char *, char *, int); + +int +main (int argc, char *argv[]) +{ + test_1 ("10.0.0.1", "10", 0); + test_1 ("10.0.0.1", "isakmp", 0); + test_1 ("10::1", "10", 0); + test_1 ("10::1", "isakmp", 0); + test_1 ("10.0x0.1", "10", -1); + test_1 ("10.0.0.1", "telnet", -1); + test_1 ("10::x:1", "10", -1); + test_1 ("10::1", "telnet", -1); + return 0; +} + +int test_1 (char *address, char *port, int ok) +{ + struct sockaddr *sa; +#ifdef DEBUG + struct sockaddr_in *sai; + struct sockaddr_in6 *sai6; + int i; +#endif + int rv; + + printf ("test_1 (\"%s\", \"%s\") ", address, port); + rv = text2sockaddr (address, port, &sa) == ok; + printf (rv ? "OK" : "FAIL"); + printf ("\n"); + +#ifdef DEBUG + printf ("af %d len %d ", sa->sa_family, sa->sa_len); + if (sa->sa_family == AF_INET) + { + sai = (struct sockaddr_in *)sa; + printf ("addr %08x port %d\n", ntohl (sai->sin_addr.s_addr), + ntohs (sai->sin_port)); + } + else + { + sai6 = (struct sockaddr_in6 *)sa; + printf ("addr "); + for (i = 0; i < sizeof sai6->sin6_addr; i++) + printf ("%02x", sai6->sin6_addr.s6_addr[i]); + printf (" port %d\n", ntohs (sai6->sin6_port)); + } +#endif + return rv; +} diff --git a/keyexchange/isakmpd-20041012/regress/x509/.cvsignore b/keyexchange/isakmpd-20041012/regress/x509/.cvsignore new file mode 100644 index 0000000..9863c98 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/x509/.cvsignore @@ -0,0 +1,2 @@ +x509test +obj diff --git a/keyexchange/isakmpd-20041012/regress/x509/Makefile b/keyexchange/isakmpd-20041012/regress/x509/Makefile new file mode 100644 index 0000000..2ce1e95 --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/x509/Makefile @@ -0,0 +1,95 @@ +# $OpenBSD: Makefile,v 1.14 2003/06/03 14:39:51 ho Exp $ +# $EOM: Makefile,v 1.16 2000/09/28 12:53:27 niklas Exp $ + +# +# Copyright (c) 1999 Niels Provos. All rights reserved. +# Copyright (c) 1999, 2001 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. +# +# 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. +# + +# Test X509 + +# Enable this if you have a DNSSEC enabled OpenSSL +#LIBLWRES= /usr/local/lib/liblwres.a + +PROG= x509test +SRCS= x509test.c conf.c log.c libcrypto.c sysdep.c field.c util.c \ + isakmp_fld.c ipsec_fld.c ipsec_num.c isakmp_num.c constants.c \ + cert.c +TOPSRC= ${.CURDIR}/../.. +TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- +OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile +FEATURES!= awk '/^FEATURES=/ { print $$0 }' ${.CURDIR}/../../Makefile | sed 's/FEATURES=.//' +.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} +CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall \ + -DUSE_X509 +NOMAN= +DEBUG= -g + +.if ${FEATURES:Mgmp} == "gmp" +CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_GMP +LDADD+= -lgmp +DPADD+= ${LIBGMP} +.else +CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL +.endif + +.include "${TOPSRC}/sysdep/${OS}/Makefile.sysdep" + +.ifdef HAVE_DLOPEN +X509= x509.c +POLICY= policy.c +CFLAGS+= -DHAVE_DLOPEN +SRCS+= dyn.c +.endif + +.ifdef USE_KEYNOTE +USE_LIBCRYPTO= yes +POLICY= policy.c +LDADD+= -lkeynote -lm +DPADD+= ${LIBKEYNOTE} ${LIBM} +CFLAGS+= -DUSE_KEYNOTE +.endif + +.ifdef USE_LIBCRYPTO +X509= x509.c +CFLAGS+= -DUSE_LIBCRYPTO +LDADD+= -lcrypto ${LIBLWRES} +DPADD+= ${LIBCRYPTO} +.endif + +.if !defined (HAVE_DLOPEN) && !defined (USE_LIBCRYPTO) || !defined (USE_KEYNOTE) +.BEGIN: + +PROG= +.endif + +SRCS+= ${X509} ${POLICY} + +LDADD+= ${DESLIB} +DPADD+= ${DESLIBDEP} + +.include <bsd.prog.mk> diff --git a/keyexchange/isakmpd-20041012/regress/x509/x509test.c b/keyexchange/isakmpd-20041012/regress/x509/x509test.c new file mode 100644 index 0000000..25b8bab --- /dev/null +++ b/keyexchange/isakmpd-20041012/regress/x509/x509test.c @@ -0,0 +1,291 @@ +/* $OpenBSD: x509test.c,v 1.22 2003/06/03 14:39:51 ho Exp $ */ +/* $EOM: x509test.c,v 1.9 2000/12/21 15:24:25 ho Exp $ */ + +/* + * Copyright (c) 1998, 1999 Niels Provos. All rights reserved. + * Copyright (c) 1999, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2001 Håkan Olsson. 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. + * + * 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 program takes a certificate generated by ssleay and a key pair + * from rsakeygen. It reads the IP address from certificate.txt and + * includes this as subject alt name extension into the certifcate. + * The result gets written as new certificate that can be used by + * isakmpd. + */ + +#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 <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include "conf.h" +#include "ipsec_num.h" +#include "isakmp_fld.h" +#include "libcrypto.h" +#include "log.h" +#include "math_mp.h" +#include "x509.h" + +static int x509_check_subjectaltname (u_char *, u_int, X509 *); + +u_int32_t file_sz; + +#if 0 +/* XXX Currently unused. */ +static 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 == MAP_FAILED) + log_fatal ("mmap (0, %d, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE," + "%d, 0)", file_sz, fd); + close (fd); + + return addr; +} +#endif + +/* + * Check that a certificate has a subjectAltName and that it matches our ID. + */ +static int +x509_check_subjectaltname (u_char *id, u_int id_len, X509 *scert) +{ + u_int8_t *altname; + u_int32_t altlen; + int type, idtype, ret; + + type = x509_cert_subjectaltname (scert, &altname, &altlen); + if (!type) + { + log_print ("x509_check_subjectaltname: can't access subjectAltName"); + return 0; + } + + /* + * Now that we have the X509 certicate in native form, get the + * subjectAltName extension and verify that it matches our ID. + */ + + /* XXX Get type of ID. */ + idtype = id[0]; + id += ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ; + id_len -= ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ; + + ret = 0; + switch (idtype) + { + case IPSEC_ID_IPV4_ADDR: + if (type == X509v3_IP_ADDR) + ret = 1; + break; + case IPSEC_ID_FQDN: + if (type == X509v3_DNS_NAME) + ret = 1; + break; + case IPSEC_ID_USER_FQDN: + if (type == X509v3_RFC_NAME) + ret = 1; + break; + default: + ret = 0; + break; + } + + if (!ret) + { + LOG_DBG ((LOG_CRYPTO, 50, + "x509_check_subjectaltname: " + "our ID type (%d) does not match X509 cert ID type (%d)", + idtype, type)); + return 0; + } + + if (altlen != id_len || memcmp (altname, id, id_len) != 0) + { + LOG_DBG ((LOG_CRYPTO, 50, + "x509_check_subjectaltname: " + "our ID does not match X509 cert ID")); + return 0; + } + + return 1; +} + +int +main (int argc, char *argv[]) +{ + RSA *pub_key, *priv_key; + X509 *cert; + BIO *certfile, *keyfile; + EVP_PKEY *pkey_pub; + u_char ipaddr[6]; + struct in_addr saddr; + char enc[256], dec[256]; + u_int8_t idpayload[8]; + int err, len; + + if (argc < 3 || argc > 4) + { + fprintf (stderr, "usage: x509test private-key certificate ip-address\n"); + exit (1); + } + + /* + * X509_verify will fail, as will all other functions that call + * EVP_get_digest_byname. + */ + + libcrypto_init (); + + printf ("Reading private key %s\n", argv[1]); + keyfile = BIO_new (BIO_s_file ()); + if (BIO_read_filename (keyfile, argv[1]) == -1) + { + perror ("read"); + exit (1); + } +#if SSLEAY_VERSION_NUMBER >= 0x00904100L + priv_key = PEM_read_bio_RSAPrivateKey (keyfile, NULL, NULL, NULL); +#else + priv_key = PEM_read_bio_RSAPrivateKey (keyfile, NULL, NULL); +#endif + BIO_free (keyfile); + if (priv_key == NULL) + { + printf("PEM_read_bio_RSAPrivateKey () failed\n"); + exit (1); + } + + /* Use a certificate created by ssleay. */ + printf ("Reading ssleay created certificate %s\n", argv[2]); + certfile = BIO_new (BIO_s_file ()); + if (BIO_read_filename (certfile, argv[2]) == -1) + { + perror ("read"); + exit (1); + } +#if SSLEAY_VERSION_NUMBER >= 0x00904100L + cert = PEM_read_bio_X509 (certfile, NULL, NULL, NULL); +#else + cert = PEM_read_bio_X509 (certfile, NULL, NULL); +#endif + BIO_free (certfile); + if (cert == NULL) + { + printf("PEM_read_bio_X509 () failed\n"); + exit (1); + } + + pkey_pub = X509_get_pubkey (cert); + /* XXX Violation of the interface? */ + pub_key = pkey_pub->pkey.rsa; + if (pub_key == NULL) + { + exit (1); + } + + printf ("Testing RSA keys: "); + + err = 0; + strlcpy (dec, "Eine kleine Testmeldung", 256); + if ((len = RSA_private_encrypt (strlen (dec), dec, enc, priv_key, + RSA_PKCS1_PADDING)) == -1) + + printf ("SIGN FAILED "); + else + err = RSA_public_decrypt (len, enc, dec, pub_key, RSA_PKCS1_PADDING); + + if (err == -1 || strcmp (dec, "Eine kleine Testmeldung")) + printf ("SIGN/VERIFY FAILED"); + else + printf ("OKAY"); + printf ("\n"); + + + printf ("Validate SIGNED: "); + err = X509_verify (cert, pkey_pub); + printf ("X509 verify: %d ", err); + if (err == -1) + printf ("FAILED "); + else + printf ("OKAY "); + printf ("\n"); + + if (argc == 4) + { + printf ("Verifying extension: "); + if (inet_aton (argv[3], &saddr) == 0) + { + printf ("inet_aton () failed\n"); + exit (1); + } + + saddr.s_addr = htonl (saddr.s_addr); + ipaddr[0] = 0x87; + ipaddr[1] = 0x04; + ipaddr[2] = saddr.s_addr >> 24; + ipaddr[3] = (saddr.s_addr >> 16) & 0xff; + ipaddr[4] = (saddr.s_addr >> 8) & 0xff; + ipaddr[5] = saddr.s_addr & 0xff; + bzero (idpayload, sizeof idpayload); + idpayload[0] = IPSEC_ID_IPV4_ADDR; + bcopy (ipaddr + 2, idpayload + 4, 4); + + if (!x509_check_subjectaltname (idpayload, sizeof idpayload, cert)) + printf("FAILED "); + else + printf("OKAY "); + printf ("\n"); + } + + return 1; +} diff --git a/keyexchange/isakmpd-20041012/sa.c b/keyexchange/isakmpd-20041012/sa.c new file mode 100644 index 0000000..14c7857 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sa.c @@ -0,0 +1,1247 @@ +/* $OpenBSD: sa.c,v 1.86 2004/08/10 15:59:10 ho Exp $ */ +/* $EOM: sa.c,v 1.112 2000/12/12 00:22:52 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 1999, 2001 Angelos D. Keromytis. All rights reserved. + * Copyright (c) 2003, 2004 Håkan Olsson. 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. + * + * 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> + +#if defined (USE_KEYNOTE) || defined (USE_POLICY) +#include <regex.h> +#include <keynote.h> +#endif /* USE_KEYNOTE || USE_POLICY */ + +#include "sysdep.h" + +#include "attribute.h" +#include "conf.h" +#include "connection.h" +#include "cookie.h" +#include "doi.h" +#include "exchange.h" +#include "isakmp.h" +#include "log.h" +#include "message.h" +#include "monitor.h" +#include "sa.h" +#include "timer.h" +#include "transport.h" +#include "util.h" +#include "cert.h" +#include "policy.h" +#include "key.h" +#include "ipsec.h" +#include "ipsec_num.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 + +#if 0 +static void sa_resize(void); +#endif +static void sa_soft_expire(void *); +static void sa_hard_expire(void *); + +static LIST_HEAD(sa_list, sa) *sa_tab; + +/* Works both as a maximum index and a mask. */ +static int bucket_mask; + +void +sa_init(void) +{ + int i; + + bucket_mask = (1 << INITIAL_BUCKET_BITS) - 1; + sa_tab = malloc((bucket_mask + 1) * sizeof(struct sa_list)); + if (!sa_tab) + log_fatal("sa_init: malloc (%lu) failed", + (bucket_mask + 1) * (unsigned long)sizeof(struct sa_list)); + for (i = 0; i <= bucket_mask; i++) + LIST_INIT(&sa_tab[i]); +} + +#if 0 +/* XXX We don't yet resize. */ +static void +sa_resize(void) +{ + 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. */ +} +#endif + +/* Lookup an SA with the help from a user-supplied checking function. */ +struct sa * +sa_find(int (*check) (struct sa*, void *), void *arg) +{ + 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 (check(sa, arg)) { + LOG_DBG((LOG_SA, 90, "sa_find: return SA %p", + sa)); + return sa; + } + LOG_DBG((LOG_SA, 90, "sa_find: no SA matched query")); + return 0; +} + +/* Check if SA is an ISAKMP SA with an initiator cookie equal to ICOOKIE. */ +static int +sa_check_icookie(struct sa *sa, void *icookie) +{ + return sa->phase == 1 && + memcmp(sa->cookies, icookie, ISAKMP_HDR_ICOOKIE_LEN) == 0; +} + +/* Lookup an ISAKMP SA out of just the initiator cookie. */ +struct sa * +sa_lookup_from_icookie(u_int8_t *cookie) +{ + return sa_find(sa_check_icookie, cookie); +} + +struct name_phase_arg { + char *name; + u_int8_t phase; +}; + +/* Check if SA has the name and phase given by V_ARG. */ +static int +sa_check_name_phase(struct sa *sa, void *v_arg) +{ + struct name_phase_arg *arg = v_arg; + + return sa->name && strcasecmp(sa->name, arg->name) == 0 && + sa->phase == arg->phase && !(sa->flags & SA_FLAG_REPLACED); +} + +/* Lookup an SA by name, case-independent, and phase. */ +struct sa * +sa_lookup_by_name(char *name, int phase) +{ + struct name_phase_arg arg; + + arg.name = name; + arg.phase = phase; + return sa_find(sa_check_name_phase, &arg); +} + +struct addr_arg { + struct sockaddr *addr; + socklen_t len; + int phase; + int flags; +}; + +/* + * Check if SA is ready and has a peer with an address equal the one given + * by V_ADDR. Furthermore if we are searching for a specific phase, check + * that too. + */ +static int +sa_check_peer(struct sa *sa, void *v_addr) +{ + struct addr_arg *addr = v_addr; + struct sockaddr *dst; + + if (!sa->transport || (sa->flags & SA_FLAG_READY) == 0 || + (addr->phase && addr->phase != sa->phase)) + return 0; + + sa->transport->vtbl->get_dst(sa->transport, &dst); + return sysdep_sa_len(dst) == addr->len && + memcmp(dst, addr->addr, sysdep_sa_len(dst)) == 0; +} + +struct dst_isakmpspi_arg { + struct sockaddr *dst; + u_int8_t *spi; /* must be ISAKMP_SPI_SIZE octets */ +}; + +/* + * Check if SA matches what we are asking for through V_ARG. It has to + * be a finished phaes 1 (ISAKMP) SA. + */ +static int +isakmp_sa_check(struct sa *sa, void *v_arg) +{ + struct dst_isakmpspi_arg *arg = v_arg; + struct sockaddr *dst, *src; + + if (sa->phase != 1 || !(sa->flags & SA_FLAG_READY)) + return 0; + + /* verify address is either src or dst for this sa */ + sa->transport->vtbl->get_dst(sa->transport, &dst); + sa->transport->vtbl->get_src(sa->transport, &src); + if (memcmp(src, arg->dst, sysdep_sa_len(src)) && + memcmp(dst, arg->dst, sysdep_sa_len(dst))) + return 0; + + /* match icookie+rcookie against spi */ + if (memcmp(sa->cookies, arg->spi, ISAKMP_HDR_COOKIES_LEN) == 0) + return 1; + + return 0; +} + +/* + * Find an ISAKMP SA with a "name" of DST & SPI. + */ +struct sa * +sa_lookup_isakmp_sa(struct sockaddr *dst, u_int8_t *spi) +{ + struct dst_isakmpspi_arg arg; + + arg.dst = dst; + arg.spi = spi; + + return sa_find(isakmp_sa_check, &arg); +} + +/* Lookup a ready SA by the peer's address. */ +struct sa * +sa_lookup_by_peer(struct sockaddr *dst, socklen_t dstlen) +{ + struct addr_arg arg; + + arg.addr = dst; + arg.len = dstlen; + arg.phase = 0; + + return sa_find(sa_check_peer, &arg); +} + +/* Lookup a ready ISAKMP SA given its peer address. */ +struct sa * +sa_isakmp_lookup_by_peer(struct sockaddr *dst, socklen_t dstlen) +{ + struct addr_arg arg; + + arg.addr = dst; + arg.len = dstlen; + arg.phase = 1; + + return sa_find(sa_check_peer, &arg); +} + +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); + sa_reference(sa); + LOG_DBG((LOG_SA, 70, "sa_enter: SA %p added to SA list", sa)); + 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 + * a null pointer, 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) + || (!message_id && !zero_test(sa->message_id, + ISAKMP_HDR_MESSAGE_ID_LEN))); + sa = LIST_NEXT(sa, link)) + ; + + return sa; +} + +/* Create an 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) { + log_error("sa_create: calloc (1, %lu) failed", + (unsigned long)sizeof *sa); + return -1; + } + sa->transport = t; + if (t) + transport_reference(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; + sa->policy_id = -1; + + if (sa->doi->sa_size) { + /* + * Allocate the DOI-specific structure and initialize it to + * zeroes. + */ + sa->data = calloc(1, sa->doi->sa_size); + if (!sa->data) { + log_error("sa_create: calloc (1, %lu) failed", + (unsigned long)sa->doi->sa_size); + free(sa); + return -1; + } + } + TAILQ_INIT(&sa->protos); + + sa_enter(sa); + TAILQ_INSERT_TAIL(&exchange->sa_list, sa, next); + sa_reference(sa); + + LOG_DBG((LOG_SA, 60, + "sa_create: sa %p phase %d added to exchange %p (%s)", sa, + sa->phase, exchange, + exchange->name ? exchange->name : "<unnamed>")); + return 0; +} + +/* + * Dump the internal state of SA to the report channel, with HEADER + * prepended to each line. + */ +void +sa_dump(int cls, int level, char *header, struct sa *sa) +{ + struct proto *proto; + char spi_header[80]; + int i; + + LOG_DBG((cls, level, "%s: %p %s phase %d doi %d flags 0x%x", header, + sa, sa->name ? sa->name : "<unnamed>", sa->phase, sa->doi->id, + sa->flags)); + LOG_DBG((cls, level, "%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))); + LOG_DBG((cls, level, "%s: msgid %08x refcnt %d", header, + decode_32(sa->message_id), sa->refcnt)); + LOG_DBG((cls, level, "%s: life secs %llu kb %llu", header, sa->seconds, + sa->kilobytes)); + for (proto = TAILQ_FIRST(&sa->protos); proto; + proto = TAILQ_NEXT(proto, link)) { + LOG_DBG((cls, level, "%s: suite %d proto %d", header, + proto->no, proto->proto)); + LOG_DBG((cls, level, + "%s: spi_sz[0] %d spi[0] %p spi_sz[1] %d spi[1] %p", + header, proto->spi_sz[0], proto->spi[0], proto->spi_sz[1], + proto->spi[1])); + LOG_DBG((cls, level, "%s: %s, %s", header, + !sa->doi ? "<nodoi>" : + sa->doi->decode_ids("initiator id: %s, responder id: %s", + sa->id_i, sa->id_i_len, + sa->id_r, sa->id_r_len, 0), + !sa->transport ? "<no transport>" : + sa->transport->vtbl->decode_ids(sa->transport))); + for (i = 0; i < 2; i++) + if (proto->spi[i]) { + snprintf(spi_header, sizeof spi_header, + "%s: spi[%d]", header, i); + LOG_DBG_BUF((cls, level, spi_header, + proto->spi[i], proto->spi_sz[i])); + } + } +} + +/* + * Display the SA's two SPI values. + */ +static void +report_spi(FILE *fd, const u_int8_t *buf, size_t sz, int spi) +{ +#define SBUFSZ (2 * 32 + 9) + char s[SBUFSZ]; + size_t i, j; + + for (i = j = 0; i < sz;) { + snprintf(s + j, sizeof s - j, "%02x", buf[i++]); + j += 2; + if (i % 4 == 0) { + if (i % 32 == 0) { + s[j] = '\0'; + fprintf(fd, "%s", s); + j = 0; + } else + s[j++] = ' '; + } + } + + if (j) { + s[j] = '\0'; + fprintf(fd, "SPI %d: %s\n", spi, s); + } +} + +/* + * Display the transform names to file. + * Structure is taken from pf_key_v2.c, pf_key_v2_set_spi. + * Transform names are taken from /usr/src/sys/crypto/xform.c. + */ +static void +report_proto(FILE *fd, struct proto *proto) +{ + struct ipsec_proto *iproto = proto->data; + int keylen, hashlen; + + switch (proto->proto) { + case IPSEC_PROTO_IPSEC_ESP: + keylen = ipsec_esp_enckeylength(proto); + hashlen = ipsec_esp_authkeylength(proto); + fprintf(fd, "Transform: IPsec ESP\n"); + fprintf(fd, "Encryption key length: %d\n", keylen); + fprintf(fd, "Authentication key length: %d\n", hashlen); + + fprintf(fd, "Encryption algorithm: "); + switch (proto->id) { + case IPSEC_ESP_DES: + case IPSEC_ESP_DES_IV32: + case IPSEC_ESP_DES_IV64: + fprintf(fd, "DES\n"); + break; + + case IPSEC_ESP_3DES: + fprintf(fd, "3DES\n"); + break; + + case IPSEC_ESP_AES: + fprintf(fd, "AES-128 (CBC)\n"); + break; + + case IPSEC_ESP_AES_128_CTR: + fprintf(fd, "AES-128 (CTR)\n"); + break; + + case IPSEC_ESP_CAST: + fprintf(fd, "Cast-128\n"); + break; + + case IPSEC_ESP_BLOWFISH: + fprintf(fd, "Blowfish\n"); + break; + + default: + fprintf(fd, "unknown (%d)\n", proto->id); + } + + fprintf(fd, "Authentication algorithm: "); + switch (iproto->auth) { + case IPSEC_AUTH_HMAC_MD5: + fprintf(fd, "HMAC-MD5\n"); + break; + + case IPSEC_AUTH_HMAC_SHA: + fprintf(fd, "HMAC-SHA1\n"); + break; + + case IPSEC_AUTH_HMAC_RIPEMD: + fprintf(fd, "HMAC-RIPEMD-160\n"); + break; + + case IPSEC_AUTH_HMAC_SHA2_256: + fprintf(fd, "HMAC-SHA2-256\n"); + break; + + case IPSEC_AUTH_HMAC_SHA2_384: + fprintf(fd, "HMAC-SHA2-384\n"); + break; + + case IPSEC_AUTH_HMAC_SHA2_512: + fprintf(fd, "HMAC-SHA2-512\n"); + break; + + case IPSEC_AUTH_DES_MAC: + case IPSEC_AUTH_KPDK: + /* XXX We should be supporting KPDK */ + fprintf(fd, "unknown (%d)", iproto->auth); + break; + + default: + fprintf(fd, "none\n"); + } + break; + + case IPSEC_PROTO_IPSEC_AH: + hashlen = ipsec_ah_keylength(proto); + fprintf(fd, "Transform: IPsec AH\n"); + fprintf(fd, "Encryption not used.\n"); + fprintf(fd, "Authentication key length: %d\n", hashlen); + + fprintf(fd, "Authentication algorithm: "); + switch (proto->id) { + case IPSEC_AH_MD5: + fprintf(fd, "HMAC-MD5\n"); + break; + + case IPSEC_AH_SHA: + fprintf(fd, "HMAC-SHA1\n"); + break; + + case IPSEC_AH_RIPEMD: + fprintf(fd, "HMAC-RIPEMD-160\n"); + break; + + case IPSEC_AH_SHA2_256: + fprintf(fd, "HMAC-SHA2-256\n"); + break; + + case IPSEC_AH_SHA2_384: + fprintf(fd, "HMAC-SHA2-384\n"); + break; + + case IPSEC_AH_SHA2_512: + fprintf(fd, "HMAC-SHA2-512\n"); + break; + + default: + fprintf(fd, "unknown (%d)", proto->id); + } + break; + + default: + fprintf(fd, "report_proto: invalid proto %d\n", proto->proto); + } +} + +/* Report all the SAs to the report channel. */ +void +sa_report(void) +{ + struct sa *sa; + int i; + + for (i = 0; i <= bucket_mask; i++) + for (sa = LIST_FIRST(&sa_tab[i]); sa; sa = LIST_NEXT(sa, link)) + sa_dump(LOG_REPORT, 0, "sa_report", sa); +} + + +/* + * Print an SA's connection details to file SA_FILE. + */ +static void +sa_dump_all(FILE *fd, struct sa *sa) +{ + struct proto *proto; + int i; + + /* SA name and phase. */ + fprintf(fd, "SA name: %s", sa->name ? sa->name : "<unnamed>"); + fprintf(fd, " (Phase %d)\n", sa->phase); + + /* Source and destination IPs. */ + fprintf(fd, sa->transport == NULL ? "<no transport>" : + sa->transport->vtbl->decode_ids(sa->transport)); + fprintf(fd, "\n"); + + /* Transform information. */ + for (proto = TAILQ_FIRST(&sa->protos); proto; + proto = TAILQ_NEXT(proto, link)) { + /* SPI values. */ + for (i = 0; i < 2; i++) + if (proto->spi[i]) + report_spi(fd, proto->spi[i], proto->spi_sz[i], + i); + else + fprintf(fd, "SPI %d not defined.", i); + + /* Proto values. */ + report_proto(fd, proto); + + /* SA separator. */ + fprintf(fd, "\n"); + } +} + +/* Report info of all SAs to file 'fd'. */ +void +sa_report_all(FILE *fd) +{ + struct sa *sa; + int i; + + for (i = 0; i <= bucket_mask; i++) + for (sa = LIST_FIRST(&sa_tab[i]); sa; sa = LIST_NEXT(sa, link)) + if (sa->phase == 1) + fprintf(fd, "SA name: none (phase 1)\n\n"); + else + sa_dump_all(fd, sa); +} + +/* Free the protocol structure pointed to by PROTO. */ +void +proto_free(struct proto *proto) +{ + struct proto_attr *pa; + struct sa *sa = proto->sa; + int i; + + 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); + } + if (proto->xf_cnt) + while ((pa = TAILQ_FIRST(&proto->xfs)) != NULL) { + if (pa->attrs) + free(pa->attrs); + TAILQ_REMOVE(&proto->xfs, pa, next); + free(pa); + } + + LOG_DBG((LOG_SA, 90, "proto_free: freeing %p", proto)); + free(proto); +} + +/* Release all resources this SA is using. */ +void +sa_free(struct sa *sa) +{ + if (sa->death) { + timer_remove_event(sa->death); + sa->death = 0; + sa->refcnt--; + } + if (sa->soft_death) { + timer_remove_event(sa->soft_death); + sa->soft_death = 0; + sa->refcnt--; + } + sa_remove(sa); +} + +/* Remove the SA from the hash table of live SAs. */ +void +sa_remove(struct sa *sa) +{ + LIST_REMOVE(sa, link); + LOG_DBG((LOG_SA, 70, "sa_remove: SA %p removed from SA list", sa)); + sa_release(sa); +} + +/* Raise the reference count of SA. */ +void +sa_reference(struct sa *sa) +{ + sa->refcnt++; + LOG_DBG((LOG_SA, 80, "sa_reference: SA %p now has %d references", + sa, sa->refcnt)); +} + +/* Release a reference to SA. */ +void +sa_release(struct sa *sa) +{ + struct cert_handler *handler; + struct proto *proto; + + LOG_DBG((LOG_SA, 80, "sa_release: SA %p had %d references", + sa, sa->refcnt)); + + if (--sa->refcnt) + return; + + LOG_DBG((LOG_SA, 60, "sa_release: freeing SA %p", sa)); + + while ((proto = TAILQ_FIRST(&sa->protos)) != 0) + proto_free(proto); + if (sa->data) { + if (sa->doi && sa->doi->free_sa_data) + sa->doi->free_sa_data(sa->data); + free(sa->data); + } + if (sa->id_i) + free(sa->id_i); + if (sa->id_r) + free(sa->id_r); + if (sa->recv_cert) { + handler = cert_get(sa->recv_certtype); + if (handler) + handler->cert_free(sa->recv_cert); + } + if (sa->sent_cert) { + handler = cert_get(sa->sent_certtype); + if (handler) + handler->cert_free(sa->sent_cert); + } + if (sa->recv_key) + key_free(sa->recv_keytype, ISAKMP_KEYTYPE_PUBLIC, + sa->recv_key); + if (sa->keynote_key) + free(sa->keynote_key); /* This is just a string */ +#if defined (USE_POLICY) || defined (USE_KEYNOTE) + if (sa->policy_id != -1) + kn_close(sa->policy_id); +#endif + if (sa->name) + free(sa->name); + if (sa->keystate) + free(sa->keystate); +#if defined (USE_NAT_TRAVERSAL) + if (sa->nat_t_keepalive) + timer_remove_event(sa->nat_t_keepalive); +#endif +#if defined (USE_DPD) + if (sa->dpd_event) + timer_remove_event(sa->dpd_event); +#endif + if (sa->transport) + transport_release(sa->transport); + 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); + + sa_remove(sa); + 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; + transport_reference(sa->transport); + sa_enter(sa); +} + +#define ATTRS_SIZE (IKE_ATTR_BLOCK_SIZE + 1) /* XXX Should be dynamic. */ + +struct attr_validation_state { + u_int8_t *attrp[ATTRS_SIZE]; + u_int8_t checked[ATTRS_SIZE]; + int phase; /* IKE (1) or IPSEC (2) attrs? */ + int mode; /* 0 = 'load', 1 = check */ +}; + +/* Validate an attribute. Return 0 on match. */ +static int +sa_validate_xf_attrs(u_int16_t type, u_int8_t *value, u_int16_t len, + void *arg) +{ + struct attr_validation_state *avs = + (struct attr_validation_state *)arg; + + LOG_DBG((LOG_SA, 95, "sa_validate_xf_attrs: phase %d mode %d type %d " + "len %d", avs->phase, avs->mode, type, len)); + + /* Make sure the phase and type are valid. */ + if (avs->phase == 1) { + if (type < IKE_ATTR_ENCRYPTION_ALGORITHM || + type > IKE_ATTR_BLOCK_SIZE) + return 1; + } else if (avs->phase == 2) { + if (type < IPSEC_ATTR_SA_LIFE_TYPE || + type > IPSEC_ATTR_ECN_TUNNEL) + return 1; + } else + return 1; + + if (avs->mode == 0) { /* Load attrs. */ + avs->attrp[type] = value; + return 0; + } + /* Checking for a missing attribute is an immediate failure. */ + if (!avs->attrp[type]) + return 1; + + /* Match the loaded attribute against this one, mark it as checked. */ + avs->checked[type]++; + return memcmp(avs->attrp[type], value, len); +} + +/* + * This function is used to validate the returned proposal (protection suite) + * we get from the responder against a proposal we sent. Only run as initiator. + * We return 0 if a match is found (in any transform of this proposal), 1 + * otherwise. Also see note in sa_add_transform() below. + */ +static int +sa_validate_proto_xf(struct proto *match, struct payload *xf, int phase) +{ + struct attr_validation_state *avs; + struct proto_attr *pa; + int found = 0; + size_t i; + u_int8_t xf_id; + + if (!match->xf_cnt) + return 0; + + if (match->proto != GET_ISAKMP_PROP_PROTO(xf->context->p)) { + LOG_DBG((LOG_SA, 70, "sa_validate_proto_xf: proto %p (#%d) " + "protocol mismatch", match, match->no)); + return 1; + } + avs = (struct attr_validation_state *)calloc(1, sizeof *avs); + if (!avs) { + log_error("sa_validate_proto_xf: calloc (1, %lu)", + (unsigned long)sizeof *avs); + return 1; + } + avs->phase = phase; + + /* Load the "proposal candidate" attribute set. */ + (void) attribute_map(xf->p + ISAKMP_TRANSFORM_SA_ATTRS_OFF, + GET_ISAKMP_GEN_LENGTH(xf->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF, + sa_validate_xf_attrs, avs); + xf_id = GET_ISAKMP_TRANSFORM_ID(xf->p); + + /* Check against the transforms we suggested. */ + avs->mode++; + for (pa = TAILQ_FIRST(&match->xfs); pa && !found; + pa = TAILQ_NEXT(pa, next)) { + if (xf_id != GET_ISAKMP_TRANSFORM_ID(pa->attrs)) + continue; + + memset(avs->checked, 0, sizeof avs->checked); + if (attribute_map(pa->attrs + ISAKMP_TRANSFORM_SA_ATTRS_OFF, + pa->len - ISAKMP_TRANSFORM_SA_ATTRS_OFF, + sa_validate_xf_attrs, avs) == 0) + found++; + + LOG_DBG((LOG_SA, 80, "sa_validate_proto_xf: attr_map " + "xf %p proto %p pa %p found %d", xf, match, pa, found)); + + if (!found) + continue; + + /* + * Require all attributes present and checked. XXX perhaps + * not? + */ + for (i = 0; i < sizeof avs->checked; i++) + if (avs->attrp[i] && !avs->checked[i]) + found = 0; + + LOG_DBG((LOG_SA, 80, "sa_validate_proto_xf: req_attr " + "xf %p proto %p pa %p found %d", xf, match, pa, found)); + } + free(avs); + return found ? 0 : 1; +} + +/* + * Register the chosen transform XF into SA. As a side effect set PROTOP + * to point at the corresponding proto structure. INITIATOR is true if we + * are the initiator. + */ +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); + if (!proto) + log_error("sa_add_transform: calloc (1, %lu) failed", + (unsigned long)sizeof *proto); + } else { + /* + * RFC 2408, section 4.2 states the responder SHOULD use the + * proposal number from the initiator (i.e us), in it's + * selected proposal to make this lookup easier. Most vendors + * follow this. One noted exception is the CiscoPIX (and + * perhaps other Cisco products). + * + * We start by matching on the proposal number, as before. + */ + for (proto = TAILQ_FIRST(&sa->protos); + proto && proto->no != GET_ISAKMP_PROP_NO(prop->p); + proto = TAILQ_NEXT(proto, link)) + ; + /* + * If we did not find a match, search through all proposals + * and xforms. + */ + if (!proto || sa_validate_proto_xf(proto, xf, sa->phase) != 0) + for (proto = TAILQ_FIRST(&sa->protos); + proto && sa_validate_proto_xf(proto, xf, + sa->phase) != 0; + 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) { + log_error("sa_add_transform: calloc (1, %lu) failed", + (unsigned long)sa->doi->proto_size); + goto cleanup; + } + } + proto->no = GET_ISAKMP_PROP_NO(prop->p); + proto->proto = GET_ISAKMP_PROP_PROTO(prop->p); + proto->spi_sz[0] = GET_ISAKMP_PROP_SPI_SZ(prop->p); + if (proto->spi_sz[0]) { + proto->spi[0] = malloc(proto->spi_sz[0]); + if (!proto->spi[0]) + goto cleanup; + memcpy(proto->spi[0], prop->p + ISAKMP_PROP_SPI_OFF, + proto->spi_sz[0]); + } + proto->chosen = xf; + proto->sa = sa; + proto->id = GET_ISAKMP_TRANSFORM_ID(xf->p); + if (!initiator) + TAILQ_INSERT_TAIL(&sa->protos, proto, link); + + /* Let the DOI get at proto for initializing its own data. */ + if (sa->doi->proto_init) + sa->doi->proto_init(proto, 0); + + LOG_DBG((LOG_SA, 80, + "sa_add_transform: " + "proto %p no %d proto %d chosen %p sa %p id %d", + proto, proto->no, proto->proto, proto->chosen, proto->sa, + proto->id)); + + return 0; + +cleanup: + if (!initiator) { + if (proto->data) + free(proto->data); + free(proto); + } + *protop = 0; + return -1; +} + +/* Delete an SA. Tell the peer if NOTIFY is set. */ +void +sa_delete(struct sa *sa, int notify) +{ + /* Don't bother notifying of Phase 1 SA deletes. */ + if (sa->phase != 1 && notify) + message_send_delete(sa); + sa_free(sa); +} + + +/* Teardown all SAs. */ +void +sa_teardown_all(void) +{ + int i; + struct sa *sa, *next = 0; + + LOG_DBG((LOG_SA, 70, "sa_teardown_all:")); + /* Get Phase 2 SAs. */ + for (i = 0; i <= bucket_mask; i++) + for (sa = LIST_FIRST(&sa_tab[i]); sa; sa = next) { + next = LIST_NEXT(sa, link); + if (sa->phase == 2) { + /* + * Teardown the phase 2 SAs by name, similar + * to ui_teardown. + */ + LOG_DBG((LOG_SA, 70, + "sa_teardown_all: tearing down SA %s", + sa->name)); + connection_teardown(sa->name); + sa_delete(sa, 1); + } + } +} + +/* + * This function will get called when we are closing in on the death time of SA + */ +static void +sa_soft_expire(void *v_sa) +{ + struct sa *sa = v_sa; + + sa->soft_death = 0; + sa_release(sa); + + if ((sa->flags & (SA_FLAG_STAYALIVE | SA_FLAG_REPLACED)) == + SA_FLAG_STAYALIVE) + exchange_establish(sa->name, 0, 0); + else + /* + * Start to watch the use of this SA, so a renegotiation can + * happen as soon as it is shown to be alive. + */ + sa->flags |= SA_FLAG_FADING; +} + +/* SA has passed its best before date. */ +static void +sa_hard_expire(void *v_sa) +{ + struct sa *sa = v_sa; + + sa->death = 0; + sa_release(sa); + + if ((sa->flags & (SA_FLAG_STAYALIVE | SA_FLAG_REPLACED)) == + SA_FLAG_STAYALIVE) + exchange_establish(sa->name, 0, 0); + + sa_delete(sa, 1); +} + +void +sa_reinit(void) +{ + struct sa *sa; + char *tag; + int i; + + /* For now; only do this if we have the proper tag configured. */ + tag = conf_get_str("General", "Renegotiate-on-HUP"); + if (!tag) + return; + + LOG_DBG((LOG_SA, 30, "sa_reinit: renegotiating active connections")); + + /* + * Get phase 2 SAs. Soft expire those without active exchanges. Do + * not touch a phase 2 SA where the soft expiration is not set, ie. + * the SA is not yet established. + */ + for (i = 0; i <= bucket_mask; i++) + for (sa = LIST_FIRST(&sa_tab[i]); sa; sa = LIST_NEXT(sa, link)) + if (sa->phase == 2) + if (exchange_lookup_by_name(sa->name, + sa->phase) == 0 && sa->soft_death) { + timer_remove_event(sa->soft_death); + sa_soft_expire(sa); + } +} + +/* + * Get an SA attribute's flag value out of textual description. + */ +int +sa_flag(char *attr) +{ + static struct sa_flag_map { + char *name; + int flag; + } sa_flag_map[] = { + { + "active-only", SA_FLAG_ACTIVE_ONLY + }, + + /* + * Below this point are flags that are internal to the + * implementation. + */ + { + "__ondemand", SA_FLAG_ONDEMAND + }, + { + "ikecfg", SA_FLAG_IKECFG + }, + }; + size_t i; + + for (i = 0; i < sizeof sa_flag_map / sizeof sa_flag_map[0]; i++) + if (strcasecmp(attr, sa_flag_map[i].name) == 0) + return sa_flag_map[i].flag; + log_print("sa_flag: attribute \"%s\" unknown", attr); + return 0; +} + +/* Mark SA as replaced. */ +void +sa_mark_replaced(struct sa *sa) +{ + LOG_DBG((LOG_SA, 60, "sa_mark_replaced: SA %p (%s) marked as replaced", + sa, sa->name ? sa->name : "unnamed")); + sa->flags |= SA_FLAG_REPLACED; +} + +/* + * Setup expiration timers for SA. This is used for ISAKMP SAs, but also + * possible to use for application SAs if the application does not deal + * with expirations itself. An example is the Linux FreeS/WAN KLIPS IPsec + * stack. + */ +int +sa_setup_expirations(struct sa *sa) +{ + struct timeval expiration; + u_int64_t seconds = sa->seconds; + + /* + * Set the soft timeout to a random percentage between 85 & 95 of + * the negotiated lifetime to break strictly synchronized + * renegotiations. This works better when the randomization is on the + * order of processing plus network-roundtrip times, or larger. + * I.e. it depends on configuration and negotiated lifetimes. + * It is not good to do the decrease on the hard timeout, because then + * we may drop our SA before our peer. + * XXX Better scheme to come? + */ + if (!sa->soft_death) { + gettimeofday(&expiration, 0); + /* + * XXX This should probably be configuration controlled + * somehow. + */ + seconds = sa->seconds * (850 + sysdep_random() % 100) / 1000; + LOG_DBG((LOG_TIMER, 95, + "sa_setup_expirations: SA %p soft timeout in %llu seconds", + sa, seconds)); + expiration.tv_sec += seconds; + sa->soft_death = timer_add_event("sa_soft_expire", + sa_soft_expire, sa, &expiration); + if (!sa->soft_death) { + /* If we don't give up we might start leaking... */ + sa_delete(sa, 1); + return -1; + } + sa_reference(sa); + } + if (!sa->death) { + gettimeofday(&expiration, 0); + LOG_DBG((LOG_TIMER, 95, + "sa_setup_expirations: SA %p hard timeout in %llu seconds", + sa, sa->seconds)); + expiration.tv_sec += sa->seconds; + sa->death = timer_add_event("sa_hard_expire", sa_hard_expire, + sa, &expiration); + if (!sa->death) { + /* If we don't give up we might start leaking... */ + sa_delete(sa, 1); + return -1; + } + sa_reference(sa); + } + return 0; +} diff --git a/keyexchange/isakmpd-20041012/sa.h b/keyexchange/isakmpd-20041012/sa.h new file mode 100644 index 0000000..4f6100f --- /dev/null +++ b/keyexchange/isakmpd-20041012/sa.h @@ -0,0 +1,318 @@ +/* $OpenBSD: sa.h,v 1.41 2004/08/10 15:59:10 ho Exp $ */ +/* $EOM: sa.h,v 1.58 2000/10/10 12:39:01 provos Exp $ */ + +/* + * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 1999, 2001 Angelos D. Keromytis. All rights reserved. + * Copyright (c) 2004 Håkan Olsson. 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. + * + * 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 proto_attr; +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 - outgoing, 1 - + * incoming. + */ + 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; + + /* Proposal transforms data, for validating the responders selection. */ + TAILQ_HEAD(proto_attr_head, proto_attr) xfs; + size_t xf_cnt; +}; + +struct proto_attr { + /* Link to next transform. */ + TAILQ_ENTRY(proto_attr) next; + + /* Transform attribute data and size, suitable for attribute_map(). */ + u_int8_t *attrs; + size_t len; +}; + +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; + + /* + * A name of the major policy deciding offers and acceptable + * proposals. + */ + char *name; + + /* The transport this SA got negotiated over. */ + 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; + + /* A reference counter for this structure. */ + u_int16_t refcnt; + + /* 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; + + /* IDs from Phase 1 */ + u_int8_t *id_i; + size_t id_i_len; + u_int8_t *id_r; + size_t id_r_len; + + /* Set if we were the initiator of the SA/exchange in Phase 1 */ + int initiator; + + /* Policy session ID, where applicable, copied over from the exchange */ + int policy_id; + + /* + * The key used to authenticate phase 1, in printable format, used + * only by KeyNote. + */ + char *keynote_key; + + /* + * Certificates or other information from Phase 1; these are copied + * from the exchange, so look at exchange.h for an explanation of + * their use. + */ + int recv_certtype, recv_keytype; + /* Certificate received from peer, native format. */ + void *recv_cert; + /* Key peer used to authenticate, native format. */ + void *recv_key; + + /* + * Certificates or other information we used to authenticate to the + * peer, Phase 1. + */ + int sent_certtype; + /* Certificate (to be) sent to peer, native format. */ + void *sent_cert; + + /* DOI-specific opaque data. */ + void *data; + + /* Lifetime data. */ + u_int64_t seconds; + u_int64_t kilobytes; + + /* ACQUIRE sequence number */ + u_int32_t seq; + + /* The events that will occur when an SA has timed out. */ + struct event *soft_death; + struct event *death; + +#if defined (USE_NAT_TRAVERSAL) + struct event *nat_t_keepalive; +#endif + +#if defined (USE_DPD) + /* IKE DPD (RFC3706) message sequence number. */ + u_int32_t dpd_seq; /* sent */ + u_int32_t dpd_rseq; /* recieved */ + u_int32_t dpd_failcount; /* # of subsequent failures */ + struct event *dpd_event; /* time of next event */ +#endif +}; + +/* This SA is alive. */ +#define SA_FLAG_READY 0x01 + +/* Renegotiate the SA at each expiry. */ +#define SA_FLAG_STAYALIVE 0x02 + +/* Establish the SA when it is needed. */ +#define SA_FLAG_ONDEMAND 0x04 + +/* This SA has been replaced by another newer one. */ +#define SA_FLAG_REPLACED 0x08 + +/* This SA has seen a soft timeout and wants to be renegotiated on use. */ +#define SA_FLAG_FADING 0x10 + +/* This SA should always be actively renegotiated (with us as initiator). */ +#define SA_FLAG_ACTIVE_ONLY 0x20 + +/* This SA flag is a placeholder for a TRANSACTION exchange "SA flag". */ +#define SA_FLAG_IKECFG 0x40 + +/* This SA flag indicates if we should do DPD with the phase 1 SA peer. */ +#define SA_FLAG_DPD 0x80 + +/* NAT-T encapsulation state. Kept in isakmp_sa for the new p2 exchange. */ +#define SA_FLAG_NAT_T_ENABLE 0x100 +#define SA_FLAG_NAT_T_KEEPALIVE 0x200 + +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 int sa_enter(struct sa *); +extern void sa_delete(struct sa *, int); +extern void sa_teardown_all(void); +extern struct sa *sa_find(int (*) (struct sa *, void *), void *); +extern int sa_flag(char *); +extern void sa_free(struct sa *); +extern void sa_init(void); +extern void sa_reinit(void); +extern struct sa *sa_isakmp_lookup_by_peer(struct sockaddr *, socklen_t); +extern void sa_isakmp_upgrade(struct message *); +extern struct sa *sa_lookup(u_int8_t *, u_int8_t *); +extern struct sa *sa_lookup_by_peer(struct sockaddr *, socklen_t); +extern struct sa *sa_lookup_by_header(u_int8_t *, int); +extern struct sa *sa_lookup_by_name(char *, int); +extern struct sa *sa_lookup_from_icookie(u_int8_t *); +extern struct sa *sa_lookup_isakmp_sa(struct sockaddr *, u_int8_t *); +extern void sa_mark_replaced(struct sa *); +extern void sa_reference(struct sa *); +extern void sa_release(struct sa *); +extern void sa_remove(struct sa *); +extern void sa_report(void); +extern void sa_dump(int, int, char *, struct sa *); +extern void sa_report_all(FILE *); +extern int sa_setup_expirations(struct sa *); + +/* + * This structure contains most of the data of the in-kernel SA. + * Currently only used to collect the tdb_last_used time for DPD. + */ +struct sa_kinfo { + u_int32_t flags; /* /usr/include/netinet/ip_ipsp.h */ + + u_int32_t exp_allocations; + u_int32_t soft_allocations; + u_int32_t cur_allocations; + + u_int64_t exp_bytes; + u_int64_t soft_bytes; + u_int64_t cur_bytes; + + u_int64_t exp_timeout; + u_int64_t soft_timeout; + + u_int64_t first_use; + u_int64_t established; + u_int64_t soft_first_use; + u_int64_t exp_first_use; + + u_int64_t last_used; + u_int64_t last_marked; + + struct sockaddr_storage dst; + struct sockaddr_storage src; + struct sockaddr_storage proxy; + + u_int32_t spi; + u_int32_t rpl; + u_int16_t udpencap_port; + u_int16_t amxkeylen; + u_int16_t emxkeylen; + u_int16_t ivlen; + u_int8_t sproto; + u_int8_t wnd; + u_int8_t satype; +}; + +#endif /* _SA_H_ */ diff --git a/keyexchange/isakmpd-20041012/samples/Makefile b/keyexchange/isakmpd-20041012/samples/Makefile new file mode 100644 index 0000000..558bd23 --- /dev/null +++ b/keyexchange/isakmpd-20041012/samples/Makefile @@ -0,0 +1,34 @@ +# $OpenBSD: Makefile,v 1.2 2003/06/03 14:39:50 ho Exp $ +# $EOM: Makefile,v 1.1 2000/05/01 20:04:53 niklas Exp $ + +# +# Copyright (c) 2000 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. +# +# 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. +# + +FILES= VPN-* policy singlehost-* +TARGETDIR= /usr/share/ipsec/isakmpd + +# The mkdir below is for installation on OpenBSD pre 2.7 +install: + @-mkdir -p ${DESTDIR}${TARGETDIR} + $(INSTALL) -c -m 0444 ${FILES} ${DESTDIR}${TARGETDIR} diff --git a/keyexchange/isakmpd-20041012/samples/VPN-3way-template.conf b/keyexchange/isakmpd-20041012/samples/VPN-3way-template.conf new file mode 100644 index 0000000..b64c801 --- /dev/null +++ b/keyexchange/isakmpd-20041012/samples/VPN-3way-template.conf @@ -0,0 +1,116 @@ +# $OpenBSD: VPN-3way-template.conf,v 1.11 2004/02/11 08:55:22 jmc Exp $ +# $EOM: VPN-3way-template.conf,v 1.8 2000/10/09 22:08:30 angelos Exp $ +# +# A configuration sample for the isakmpd ISAKMP/Oakley (aka IKE) daemon. +# +# This is a template file of a VPN setup between three nodes in +# a fully meshed 'three-way' configuration. Suggested use is to copy +# this file to all three nodes and then edit them accordingly. +# +# These nodes are initially called XXX, YYY and ZZZ. +# +# In pseudographics: XXX --- YYY +# \ / +# ZZZ +# +# In cases where IP/network addresses should be defined values like +# 192.168.XXX.nnn have been used. +# + +# Incoming phase 1 negotiations are multiplexed on the source IP +# address. In the three-way VPN, we have two possible peers. + +[Phase 1] +192.168.YYY.nnn= ISAKMP-peer-node-YYY +192.168.ZZZ.nnn= ISAKMP-peer-node-ZZZ + +# These connections are walked over after config file parsing and +# told to the application layer so that it will inform us when +# traffic wants to pass over them. This means we can do on-demand +# keying. In the three-way VPN, each node knows two connections. + +[Phase 2] +Connections= IPsec-Conn-XXX-YYY,IPsec-Conn-XXX-ZZZ + +# ISAKMP Phase 1 peer sections +############################## + +[ISAKMP-peer-node-YYY] +Phase= 1 +Transport= udp +Address= 192.168.YYY.nnn +Configuration= Default-main-mode +Authentication= yoursharedsecretwithYYY + +[ISAKMP-peer-node-ZZZ] +Phase= 1 +Transport= udp +Address= 192.168.ZZZ.nnn +Configuration= Default-main-mode +Authentication= yoursharedsecretwithZZZ + +# IPsec Phase 2 sections +######################## + +[IPsec-Conn-XXX-YYY] +Phase= 2 +ISAKMP-peer= ISAKMP-peer-node-YYY +Configuration= Default-quick-mode +Local-ID= MyNet-XXX +Remote-ID= OtherNet-YYY + +[IPsec-Conn-XXX-ZZZ] +Phase= 2 +ISAKMP-peer= ISAKMP-peer-node-ZZZ +Configuration= Default-quick-mode +Local-ID= MyNet-XXX +Remote-ID= OtherNet-ZZZ + +# Client ID sections +#################### + +[MyNet-XXX] +ID-type= IPV4_ADDR_SUBNET +Network= 192.168.XXX.0 +Netmask= 255.255.255.0 + +[OtherNet-YYY] +ID-type= IPV4_ADDR_SUBNET +Network= 192.168.YYY.0 +Netmask= 255.255.255.0 + +[OtherNet-ZZZ] +ID-type= IPV4_ADDR_SUBNET +Network= 192.168.ZZZ.0 +Netmask= 255.255.255.0 + +# +# There is no more node-specific configuration below this point. +# + +# Main mode descriptions + +[Default-main-mode] +DOI= IPSEC +EXCHANGE_TYPE= ID_PROT +Transforms= 3DES-SHA,3DES-MD5 + +[Blowfish-main-mode] +DOI= IPSEC +EXCHANGE_TYPE= ID_PROT +Transforms= BLF-SHA-M1024 + +# Quick mode description +######################## + +[Default-quick-mode] +DOI= IPSEC +EXCHANGE_TYPE= QUICK_MODE +Suites= QM-ESP-AES-SHA-PFS-SUITE + +[Blowfish-quick-mode] +DOI= IPSEC +EXCHANGE_TYPE= QUICK_MODE +Suites= QM-ESP-BLF-SHA-PFS-SUITE +#Suites= QM-ESP-BLF-SHA-SUITE + diff --git a/keyexchange/isakmpd-20041012/samples/VPN-east.conf b/keyexchange/isakmpd-20041012/samples/VPN-east.conf new file mode 100644 index 0000000..04d0bb9 --- /dev/null +++ b/keyexchange/isakmpd-20041012/samples/VPN-east.conf @@ -0,0 +1,50 @@ +# $OpenBSD: VPN-east.conf,v 1.13 2003/03/16 08:13:02 matthieu Exp $ +# $EOM: VPN-east.conf,v 1.12 2000/10/09 22:08:30 angelos Exp $ + +# A configuration sample for the isakmpd ISAKMP/Oakley (aka IKE) daemon. +# +# The network topology of the example net is like this: +# +# 192.168.11.0/24 - west [.11] - 10.1.0.0/24 - [.12] east - 192.168.12.0/24 +# +# "west" and "east" are the respective security gateways (aka VPN-nodes). + +[Phase 1] +10.1.0.11= ISAKMP-peer-west + +[Phase 2] +Connections= IPsec-east-west + +[ISAKMP-peer-west] +Phase= 1 +Transport= udp +Address= 10.1.0.11 +Configuration= Default-main-mode +Authentication= mekmitasdigoat + +[IPsec-east-west] +Phase= 2 +ISAKMP-peer= ISAKMP-peer-west +Configuration= Default-quick-mode +Local-ID= Net-east +Remote-ID= Net-west + +[Net-west] +ID-type= IPV4_ADDR_SUBNET +Network= 192.168.11.0 +Netmask= 255.255.255.0 + +[Net-east] +ID-type= IPV4_ADDR_SUBNET +Network= 192.168.12.0 +Netmask= 255.255.255.0 + +[Default-main-mode] +DOI= IPSEC +EXCHANGE_TYPE= ID_PROT +Transforms= 3DES-SHA + +[Default-quick-mode] +DOI= IPSEC +EXCHANGE_TYPE= QUICK_MODE +Suites= QM-ESP-AES-SHA-PFS-SUITE diff --git a/keyexchange/isakmpd-20041012/samples/VPN-west.conf b/keyexchange/isakmpd-20041012/samples/VPN-west.conf new file mode 100644 index 0000000..5b3a8f6 --- /dev/null +++ b/keyexchange/isakmpd-20041012/samples/VPN-west.conf @@ -0,0 +1,50 @@ +# $OpenBSD: VPN-west.conf,v 1.14 2003/03/16 08:13:02 matthieu Exp $ +# $EOM: VPN-west.conf,v 1.13 2000/10/09 22:08:30 angelos Exp $ + +# A configuration sample for the isakmpd ISAKMP/Oakley (aka IKE) daemon. +# +# The network topology of the example net is like this: +# +# 192.168.11.0/24 - west [.11] - 10.1.0.0/24 - [.12] east - 192.168.12.0/24 +# +# "west" and "east" are the respective security gateways (aka VPN-nodes). + +[Phase 1] +10.1.0.12= ISAKMP-peer-east + +[Phase 2] +Connections= IPsec-west-east + +[ISAKMP-peer-east] +Phase= 1 +Transport= udp +Address= 10.1.0.12 +Configuration= Default-main-mode +Authentication= mekmitasdigoat + +[IPsec-west-east] +Phase= 2 +ISAKMP-peer= ISAKMP-peer-east +Configuration= Default-quick-mode +Local-ID= Net-west +Remote-ID= Net-east + +[Net-west] +ID-type= IPV4_ADDR_SUBNET +Network= 192.168.11.0 +Netmask= 255.255.255.0 + +[Net-east] +ID-type= IPV4_ADDR_SUBNET +Network= 192.168.12.0 +Netmask= 255.255.255.0 + +[Default-main-mode] +DOI= IPSEC +EXCHANGE_TYPE= ID_PROT +Transforms= 3DES-SHA + +[Default-quick-mode] +DOI= IPSEC +EXCHANGE_TYPE= QUICK_MODE +Suites= QM-ESP-AES-SHA-PFS-SUITE diff --git a/keyexchange/isakmpd-20041012/samples/policy b/keyexchange/isakmpd-20041012/samples/policy new file mode 100644 index 0000000..0e194aa --- /dev/null +++ b/keyexchange/isakmpd-20041012/samples/policy @@ -0,0 +1,10 @@ +KeyNote-Version: 2 +Comment: This policy accepts ESP SAs from a remote that uses the right password + $OpenBSD: policy,v 1.6 2001/06/20 16:36:19 angelos Exp $ + $EOM: policy,v 1.6 2000/10/09 22:08:30 angelos Exp $ +Authorizer: "POLICY" +Licensees: "passphrase:mekmitasdigoat" +Conditions: app_domain == "IPsec policy" && + esp_present == "yes" && + esp_enc_alg == "aes" && + esp_auth_alg == "hmac-sha" -> "true"; diff --git a/keyexchange/isakmpd-20041012/samples/singlehost-east.conf b/keyexchange/isakmpd-20041012/samples/singlehost-east.conf new file mode 100644 index 0000000..f0afc46 --- /dev/null +++ b/keyexchange/isakmpd-20041012/samples/singlehost-east.conf @@ -0,0 +1,64 @@ +# $OpenBSD: singlehost-east.conf,v 1.10 2000/11/23 12:56:25 niklas Exp $ +# $EOM: singlehost-east.conf,v 1.10 2000/11/23 12:24:43 niklas Exp $ + +# A configuration sample for the isakmpd ISAKMP/Oakley (aka IKE) daemon. + +[General] +Listen-on= 10.1.0.12 +Shared-SADB= Defined +Policy-File= policy + +[Phase 1] +10.1.0.11= ISAKMP-peer-west +Default= ISAKMP-peer-west-aggressive + +[Phase 2] +Connections= IPsec-east-west + +[ISAKMP-peer-west] +Phase= 1 +Transport= udp +Local-address= 10.1.0.12 +Address= 10.1.0.11 +Configuration= Default-main-mode +Authentication= mekmitasdigoat + +[ISAKMP-peer-west-aggressive] +Phase= 1 +Transport= udp +Local-address= 10.1.0.12 +Address= 10.1.0.11 +Configuration= Default-aggressive-mode +Authentication= mekmitasdigoat + +[IPsec-east-west] +Phase= 2 +ISAKMP-peer= ISAKMP-peer-west +Configuration= Default-quick-mode +Local-ID= Net-east +Remote-ID= Net-west + +[Net-west] +ID-type= IPV4_ADDR_SUBNET +Network= 192.168.11.0 +Netmask= 255.255.255.0 + +[Net-east] +ID-type= IPV4_ADDR_SUBNET +Network= 192.168.12.0 +Netmask= 255.255.255.0 + +[Default-main-mode] +DOI= IPSEC +EXCHANGE_TYPE= ID_PROT +Transforms= 3DES-SHA + +[Default-aggressive-mode] +DOI= IPSEC +EXCHANGE_TYPE= AGGRESSIVE +Transforms= 3DES-SHA-RSA + +[Default-quick-mode] +DOI= IPSEC +EXCHANGE_TYPE= QUICK_MODE +Suites= QM-ESP-AES-SHA-PFS-SUITE diff --git a/keyexchange/isakmpd-20041012/samples/singlehost-east.gdb b/keyexchange/isakmpd-20041012/samples/singlehost-east.gdb new file mode 100644 index 0000000..a41df0d --- /dev/null +++ b/keyexchange/isakmpd-20041012/samples/singlehost-east.gdb @@ -0,0 +1 @@ +r -d -D0=99 -D1=99 -D2=99 -D3=99 -D4=99 -D5=99 -feast.fifo -c../samples/singlehost-east.conf diff --git a/keyexchange/isakmpd-20041012/samples/singlehost-setup.sh b/keyexchange/isakmpd-20041012/samples/singlehost-setup.sh new file mode 100644 index 0000000..818ce2d --- /dev/null +++ b/keyexchange/isakmpd-20041012/samples/singlehost-setup.sh @@ -0,0 +1,84 @@ +#!/bin/sh +# $OpenBSD: singlehost-setup.sh,v 1.5 2003/08/18 09:41:40 markus Exp $ +# $EOM: singlehost-setup.sh,v 1.3 2000/11/23 12:24:43 niklas Exp $ + +# A script to test single-host VPNs + +# For the 'pf' variable +. /etc/rc.conf + +# Default paths +PFCTL=/sbin/pfctl +ISAKMPD=/sbin/isakmpd + +do_routes() +{ + /sbin/route $1 -net 192.168.11.0/24 192.168.11.1 -iface >/dev/null + /sbin/route $1 -net 192.168.12.0/24 192.168.12.1 -iface >/dev/null + /sbin/route $1 -net 10.1.0.0/16 10.1.0.11 -iface >/dev/null +} + +# Called on script exit +cleanup () { + if [ "x${pf}" = "xYES" -a -f ${pf_rules} ]; then + ${PFCTL} -R -f ${pf_rules} + else + ${PFCTL} -qd + fi + + USER=`id -p | grep ^login | cut -f2` + chown $USER singlehost-east.conf singlehost-west.conf policy + chmod 644 singlehost-east.conf singlehost-west.conf policy + + [ -p east.fifo ] && echo "Q" >> east.fifo + [ -p west.fifo ] && echo "Q" >> west.fifo + rm -f east.fifo west.fifo + + do_routes delete +} + +# Start by initializing interfaces +/sbin/ifconfig lo2 192.168.11.1 netmask 0xffffff00 up +/sbin/ifconfig lo3 192.168.12.1 netmask 0xffffff00 up +/sbin/ifconfig lo4 10.1.0.11 netmask 0xffff0000 up +/sbin/ifconfig lo5 10.1.0.12 netmask 0xffff0000 up +# ... and by adding the required routes +do_routes add + +# Add rules +( + cat <<EOF +pass out quick on lo2 proto 50 all +pass out quick on lo2 from 192.168.11.0/24 to any +pass out quick on lo3 proto 50 all +pass out quick on lo3 from 192.168.12.0/24 to any +block out on lo2 all +block out on lo3 all +EOF + if [ "x${pf}" = "xYES" -a -f ${pf_rules} ]; then + cat ${pf_rules} | egrep -v '^(scrub|rdr|binat|nat)' + else + pfctl -qe >/dev/null + fi +) | pfctl -R -f - + +trap cleanup 1 2 3 15 + +# The configuration files needs proper owners and modes +USER=`id -p | grep ^uid | cut -f2` +chown $USER singlehost-east.conf singlehost-west.conf policy +chmod 600 singlehost-east.conf singlehost-west.conf policy + +# Start the daemons +rm -f east.fifo west.fifo +${ISAKMPD} -c singlehost-east.conf -f east.fifo "$@" +${ISAKMPD} -c singlehost-west.conf -f west.fifo "$@" + +# Give them some time to negotiate their stuff... +SECS=3 +echo "Waiting $SECS seconds..." +sleep $SECS +echo "Running 'ping', using the tunnel..." +ping -I 192.168.11.1 -c 5 192.168.12.1 + +cleanup diff --git a/keyexchange/isakmpd-20041012/samples/singlehost-west.conf b/keyexchange/isakmpd-20041012/samples/singlehost-west.conf new file mode 100644 index 0000000..40538a3 --- /dev/null +++ b/keyexchange/isakmpd-20041012/samples/singlehost-west.conf @@ -0,0 +1,64 @@ +# $OpenBSD: singlehost-west.conf,v 1.11 2003/08/20 14:43:36 ho Exp $ +# $EOM: singlehost-west.conf,v 1.10 2000/11/23 12:24:43 niklas Exp $ + +# A configuration sample for the isakmpd ISAKMP/Oakley (aka IKE) daemon. + +[General] +Listen-on= 10.1.0.11 +Shared-SADB= Defined +Policy-File= policy + +[Phase 1] +10.1.0.12= ISAKMP-peer-east +Default= ISAKMP-peer-east-aggressive + +[Phase 2] +Connections= IPsec-west-east + +[ISAKMP-peer-east] +Phase= 1 +Transport= udp +Local-address= 10.1.0.11 +Address= 10.1.0.12 +Configuration= Default-main-mode +Authentication= mekmitasdigoat + +[ISAKMP-peer-east-aggressive] +Phase= 1 +Transport= udp +Local-address= 10.1.0.11 +Address= 10.1.0.12 +Configuration= Default-aggressive-mode +Authentication= mekmitasdigoat + +[IPsec-west-east] +Phase= 2 +ISAKMP-peer= ISAKMP-peer-east +Configuration= Default-quick-mode +Local-ID= Net-west +Remote-ID= Net-east + +[Net-west] +ID-type= IPV4_ADDR_SUBNET +Network= 192.168.11.0 +Netmask= 255.255.255.0 + +[Net-east] +ID-type= IPV4_ADDR_SUBNET +Network= 192.168.12.0 +Netmask= 255.255.255.0 + +[Default-main-mode] +DOI= IPSEC +EXCHANGE_TYPE= ID_PROT +Transforms= 3DES-SHA + +[Default-aggressive-mode] +DOI= IPSEC +EXCHANGE_TYPE= AGGRESSIVE +Transforms= 3DES-SHA-RSA + +[Default-quick-mode] +DOI= IPSEC +EXCHANGE_TYPE= QUICK_MODE +Suites= QM-ESP-AES-SHA-PFS-SUITE diff --git a/keyexchange/isakmpd-20041012/samples/singlehost-west.gdb b/keyexchange/isakmpd-20041012/samples/singlehost-west.gdb new file mode 100644 index 0000000..5315e46 --- /dev/null +++ b/keyexchange/isakmpd-20041012/samples/singlehost-west.gdb @@ -0,0 +1 @@ +r -d -D0=99 -D1=99 -D2=99 -D3=99 -D4=99 -D5=99 -fwest.fifo -c../samples/singlehost-west.conf diff --git a/keyexchange/isakmpd-20041012/sysdep.h b/keyexchange/isakmpd-20041012/sysdep.h new file mode 100644 index 0000000..50de819 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep.h @@ -0,0 +1,84 @@ +/* $OpenBSD: sysdep.h,v 1.19 2004/08/10 15:59:10 ho Exp $ */ +/* $EOM: sysdep.h,v 1.17 2000/12/04 04:46:35 angelos Exp $ */ + +/* + * Copyright (c) 1998, 1999 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. + * + * 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> +#if defined (USE_BOEHM_GC) +#include <stdlib.h> +#include <string.h> +#endif + +#include "sysdep-os.h" + +struct proto; +struct sa; +struct sockaddr; + +extern void sysdep_app_handler(int); +extern int sysdep_app_open(void); +extern int sysdep_cleartext(int, int); +extern void sysdep_connection_check(char *); +extern int sysdep_ipsec_delete_spi(struct sa *, struct proto *, int); +extern int sysdep_ipsec_enable_sa(struct sa *, struct sa *); +extern u_int8_t *sysdep_ipsec_get_spi(size_t *, u_int8_t, struct sockaddr *, + struct sockaddr *, u_int32_t); +extern struct sa_kinfo *sysdep_ipsec_get_kernel_sa(u_int8_t *, size_t, + u_int8_t, struct sockaddr *); +extern int sysdep_ipsec_group_spis(struct sa *, struct proto *, + struct proto *, int); +extern int sysdep_ipsec_set_spi(struct sa *, struct proto *, int, + struct sa *); +extern char *sysdep_progname(void); +extern u_int32_t sysdep_random(void); +extern u_int8_t sysdep_sa_len(struct sockaddr *); + +#if defined (USE_BOEHM_GC) +/* + * Use Boehm's garbage collector as a means to find leaks. + * XXX The defines below are GCC-specific. I think it is OK to require + * XXX GCC if you are debugging isakmpd in this way. + */ +void *GC_debug_malloc(size_t, char *, int); +void *GC_debug_realloc(void *, size_t, char *, int); +void GC_debug_free(void *); +char *gc_strdup(const char *); + +#define malloc(x) GC_debug_malloc ((x), __FILE__, __LINE__) +#define realloc(x,y) GC_debug_realloc ((x), (y), __FILE__, __LINE__) +#define free(x) GC_debug_free (x) +#define calloc(x,y) malloc((x) * (y)) +#define strdup(x) gc_strdup((x)) + +#endif /* WITH_BOEHM_GC */ + +#endif /* _SYSDEP_H_ */ diff --git a/keyexchange/isakmpd-20041012/sysdep/bsdi/GNUmakefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/bsdi/GNUmakefile.sysdep new file mode 100644 index 0000000..cc7b8cc --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/bsdi/GNUmakefile.sysdep @@ -0,0 +1,64 @@ +# $OpenBSD: GNUmakefile.sysdep,v 1.3 2003/06/03 14:53:11 ho Exp $ +# +# XXX UNTESTED + +# +# Copyright (c) 1999 Niklas Hallqvist. All rights reserved. +# Copyright (c) 2000 Håkan Olsson. 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. +# +# 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. +# + +LIBGMP:= +LIBCRYPTO:= /usr/contrib/lib/libcrypto.a + +LIBSYSDEPDIR:= ${.CURDIR}/sysdep/common/libsysdep +LIBSYSDEP:= ${LIBSYSDEPDIR}/libsysdep.a + +LDADD+= ${LIBGMP} ${LIBSYSDEP} +DPADD+= ${LIBGMP} ${LIBSYSDEP} + +FEATURES= debug tripledes blowfish cast ec aggressive +# Not yet +#FEATURES+= policy x509 + +CFLAGS+= -DNO_RSA -DNO_RC5 -DNO_IDEA \ + -I${.CURDIR}/sysdep/common -I/usr/contrib/include \ + +IPSEC_SRCS= pf_key_v2.c +IPSEC_CFLAGS= -DUSE_PF_KEY_V2 + +USE_LIBCRYPTO= defined + +# +# hack libsysdep.a dependency +# +${LIBSYSDEPDIR}/.depend ${LIBSYSDEP}: + @cd ${LIBSYSDEPDIR} && \ + ${MAKE} --no-print-directory ${MAKEFLAGS} \ + CFLAGS="${CFLAGS}" MKDEP="${MKDEP}" ${MAKECMDGOALS} + +depend: ${LIBSYSDEPDIR}/.depend + +ifeq ($(findstring clean, $(MAKECMDGOALS)), clean) +SUBDIR+= sysdep/common/libsysdep +MAKEFLAGS+= --no-print-directory +endif diff --git a/keyexchange/isakmpd-20041012/sysdep/bsdi/Makefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/bsdi/Makefile.sysdep new file mode 100644 index 0000000..3840fec --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/bsdi/Makefile.sysdep @@ -0,0 +1,79 @@ +# $OpenBSD: Makefile.sysdep,v 1.6 2004/06/26 03:40:57 mcbride Exp $ + +# +# Copyright (c) 1999 Niklas Hallqvist. All rights reserved. +# Copyright (c) 2000 H\xe5kan Olsson. All rights reserved. +# Copyright (c) 2001 Markus Friedl. 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. +# +# 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 INN 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. +# + +# Override default features +FEATURES= tripledes des blowfish cast ec aggressive debug x509 +FEATURES+= rawkey +# Not yet +#FEATURES+= policy isakmp_cfg + +LIBCRYPTO= /usr/contrib/lib/libcrypto.a +LIBSYSDEPDIR= ${.CURDIR}/sysdep/common/libsysdep + +CFLAGS+= -DHAVE_PCAP + +LDADD+= ${LIBGMP} ${LIBSYSDEPDIR}/libsysdep.a -lipsec +DPADD+= ${LIBGMP} ${LIBSYSDEPDIR}/libsysdep.a ${LIBIPSEC} + +SYSSRC=/usr/build/kame/bsdi4/sys + +.if exists(${SYSSRC}/net/pfkeyv2.h) +CFLAGS+= -I${SYSSRC} +.endif + +.if exists(/usr/build/keynote/keynote.h) +CFLAGS+= -I/usr/build/keynote +LDFLAGS+= -L/usr/build/keynote +.endif + +CFLAGS+= -DNO_IDEA -DNO_RC5 -DHAVE_GETIFADDRS \ + -I${.CURDIR}/sysdep/common +CFLAGS+= -I/usr/include -I/usr/contrib/include + +LDADD+= -L/usr/contrib/lib + +IPSEC_SRCS= pf_key_v2.c +IPSEC_CFLAGS= -DUSE_PF_KEY_V2 + +USE_LIBCRYPTO= defined +USE_GMP= defined +USE_KEYNOTE= defined + +# This is a hack in order to make sure libsysdep is built before the +# linkstage of isakmpd. As a side effect the link is always done even if +# not necessary. Well, I just don't care. +GENERATED+= sysdep-target +sysdep-target: + cd ${.CURDIR}/sysdep/common/libsysdep; ${MAKE} ${.MAKEFLAGS} + +.if make(clean) || make(cleandir) +SUBDIR+= sysdep/common/libsysdep +.endif + +# Kludge around bug in /usr/share/mk/bsd.subdir.mk +NO_REGRESS= defined diff --git a/keyexchange/isakmpd-20041012/sysdep/bsdi/sysdep-os.h b/keyexchange/isakmpd-20041012/sysdep/bsdi/sysdep-os.h new file mode 100644 index 0000000..710ab82 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/bsdi/sysdep-os.h @@ -0,0 +1,66 @@ +/* $OpenBSD: sysdep-os.h,v 1.5 2003/08/06 11:20:00 markus Exp $ */ + +/* + * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2000 H\xe5kan Olsson. All rights reserved. + * Copyright (c) 2001 Markus Friedl. 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. + * + * 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. + */ + +#ifndef _SYSDEP_OS_H_ + +#define _SYSDEP_OS_H_ + +#define KAME + +#include <netinet6/ipsec.h> + +/* in_port_t */ +#include <netinet/in.h> + +#define timersub(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ + if ((vvp)->tv_usec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_usec += 1000000; \ + } \ + } while (0) + +#ifndef CPI_RESERVED_MIN +/* Reserved CPI numbers */ +#define CPI_RESERVED_MIN 1 +#define CPI_RESERVED_MAX 255 +#define CPI_PRIVATE_MIN 61440 +#define CPI_PRIVATE_MAX 65535 +#endif + +#if !defined(SADB_X_EALG_CAST) && defined(SADB_X_EALG_CAST128CBC) +#define SADB_X_EALG_CAST SADB_X_EALG_CAST128CBC +#endif + +#if !defined(SADB_X_EALG_BLF) && defined(SADB_X_EALG_BLOWFISHCBC) +#define SADB_X_EALG_BLF SADB_X_EALG_BLOWFISHCBC +#endif + +#endif /* _SYSDEP_OS_H_ */ diff --git a/keyexchange/isakmpd-20041012/sysdep/bsdi/sysdep.c b/keyexchange/isakmpd-20041012/sysdep/bsdi/sysdep.c new file mode 100644 index 0000000..99715d5 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/bsdi/sysdep.c @@ -0,0 +1,225 @@ +/* $OpenBSD: sysdep.c,v 1.12 2004/08/10 15:59:10 ho Exp $ */ + +/* + * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2000 H\xe5kan Olsson. 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. + * + * 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. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdlib.h> +#include <string.h> + +#include "sysdep.h" + +#include "util.h" + +#ifdef NEED_SYSDEP_APP +#include "app.h" +#include "conf.h" +#include "ipsec.h" + +#ifdef USE_PF_KEY_V2 +#include "pf_key_v2.h" +#define KEY_API(x) pf_key_v2_##x +#endif + +#endif /* NEED_SYSDEP_APP */ +#include "log.h" + +extern char *__progname; + +/* + * An as strong as possible random number generator, reverting to a + * deterministic pseudo-random one if regrand is set. + */ +u_int32_t +sysdep_random () +{ + return random(); +} + +/* Return the basename of the command used to invoke us. */ +char * +sysdep_progname () +{ + return __progname; +} + +/* Return the length of the sockaddr struct. */ +u_int8_t +sysdep_sa_len (struct sockaddr *sa) +{ + return sa->sa_len; +} + +/* As regress/ use this file I protect the sysdep_app_* stuff like this. */ +#ifdef NEED_SYSDEP_APP +/* + * Prepare the application we negotiate SAs for (i.e. the IPsec stack) + * for communication. We return a file descriptor useable to select(2) on. + */ +int +sysdep_app_open () +{ + return KEY_API(open) (); +} + +/* + * When select(2) has noticed our application needs attendance, this is what + * gets called. FD is the file descriptor causing the alarm. + */ +void +sysdep_app_handler (int fd) +{ + KEY_API (handler) (fd); +} + +/* Check that the connection named NAME is active, or else make it active. */ +void +sysdep_connection_check (char *name) +{ + KEY_API (connection_check) (name); +} + +/* + * Generate a SPI for protocol PROTO and the source/destination pair given by + * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ. + */ +u_int8_t * +sysdep_ipsec_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src, + struct sockaddr *dst, u_int32_t seq) +{ + if (app_none) + { + *sz = IPSEC_SPI_SIZE; + /* XXX should be random instead I think. */ + return strdup ("\x12\x34\x56\x78"); + } + return KEY_API (get_spi) (sz, proto, src, dst, seq); +} + +struct sa_kinfo * +sysdep_ipsec_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto, + struct sockaddr *dst) +{ + if (app_none) + return 0; + /* XXX return KEY_API(get_kernel_sa)(spi, spi_sz, proto, dst); */ + return 0; +} + +/* Force communication on socket FD to go in the clear. */ +int +sysdep_cleartext (int fd, int af) +{ + char *buf; + char *policy[] = { "in bypass", "out bypass", NULL }; + char **p; + int ipp; + int opt; + char *msgstr; + + if (app_none) + return 0; + + switch (af) + { + case AF_INET: + ipp = IPPROTO_IP; + opt = IP_IPSEC_POLICY; + msgstr = ""; + break; + case AF_INET6: + ipp = IPPROTO_IPV6; + opt = IPV6_IPSEC_POLICY; + msgstr = "V6"; + break; + default: + log_print ("sysdep_cleartext: unsupported protocol family %d", af); + return -1; + } + + /* + * Need to bypass system security policy, so I can send and + * receive key management datagrams in the clear. + */ + + for (p = policy; p && *p; p++) + { + buf = ipsec_set_policy (*p, strlen(*p)); + if (buf == NULL) + { + log_error ("sysdep_cleartext: %s: %s", *p, ipsec_strerror()); + return -1; + } + + if (setsockopt(fd, ipp, opt, buf, ipsec_get_policylen(buf)) < 0) + { + log_error ("sysdep_cleartext: " + "setsockopt (%d, IPPROTO_IP%s, IP%s_IPSEC_POLICY, ...) " + "failed", fd, msgstr, msgstr); + return -1; + } + free(buf); + } + + return 0; +} + +int +sysdep_ipsec_delete_spi (struct sa *sa, struct proto *proto, int incoming) +{ + if (app_none) + return 0; + return KEY_API (delete_spi) (sa, proto, incoming); +} + +int +sysdep_ipsec_enable_sa (struct sa *sa, struct sa *isakmp_sa) +{ + if (app_none) + return 0; + return KEY_API (enable_sa) (sa, isakmp_sa); +} + +int +sysdep_ipsec_group_spis (struct sa *sa, struct proto *proto1, + struct proto *proto2, int incoming) +{ + if (app_none) + return 0; + return KEY_API (group_spis) (sa, proto1, proto2, incoming); +} + +int +sysdep_ipsec_set_spi (struct sa *sa, struct proto *proto, int incoming, + struct sa *isakmp_sa) +{ + if (app_none) + return 0; + return KEY_API (set_spi) (sa, proto, incoming, isakmp_sa); +} +#endif diff --git a/keyexchange/isakmpd-20041012/sysdep/common/blf.h b/keyexchange/isakmpd-20041012/sysdep/common/blf.h new file mode 100644 index 0000000..97eec89 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/common/blf.h @@ -0,0 +1,70 @@ +/* $OpenBSD: blf.h,v 1.5 2003/06/03 14:52:06 ho Exp $ */ +/* + * Blowfish - a fast block cipher designed by Bruce Schneier + * + * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de> + * 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. + * + * 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. + */ + +#ifndef _BLF_H_ +#define _BLF_H_ + +/* Schneier states the maximum key length to be 56 bytes. + * The way how the subkeys are initialized by the key up + * to (N+2)*4 i.e. 72 bytes are utilized. + * Warning: For normal blowfish encryption only 56 bytes + * of the key affect all cipherbits. + */ + +#define BLF_N 16 /* Number of Subkeys */ +#define BLF_MAXKEYLEN ((BLF_N-2)*4) /* 448 bits */ + +/* Blowfish context */ +typedef struct BlowfishContext { + u_int32_t S[4][256]; /* S-Boxes */ + u_int32_t P[BLF_N + 2]; /* Subkeys */ +} blf_ctx; + +/* Raw access to customized Blowfish + * blf_key is just: + * Blowfish_initstate( state ) + * Blowfish_expand0state( state, key, keylen ) + */ + +void Blowfish_encipher(blf_ctx *, u_int32_t *, u_int32_t *); +void Blowfish_decipher(blf_ctx *, u_int32_t *, u_int32_t *); +void Blowfish_initstate(blf_ctx *); +void Blowfish_expand0state(blf_ctx *, const u_int8_t *, u_int16_t); +void Blowfish_expandstate +(blf_ctx *, const u_int8_t *, u_int16_t, const u_int8_t *, u_int16_t); + +/* Standard Blowfish */ + +void blf_key(blf_ctx *, const u_int8_t *, u_int16_t); +void blf_enc(blf_ctx *, u_int32_t *, u_int16_t); +void blf_dec(blf_ctx *, u_int32_t *, u_int16_t); + +/* Converts u_int8_t to u_int32_t */ +u_int32_t Blowfish_stream2word(const u_int8_t *, u_int16_t , u_int16_t *); + +#endif diff --git a/keyexchange/isakmpd-20041012/sysdep/common/cast.h b/keyexchange/isakmpd-20041012/sysdep/common/cast.h new file mode 100644 index 0000000..c130986 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/common/cast.h @@ -0,0 +1,22 @@ +/* $OpenBSD: cast.h,v 1.1 2001/01/26 11:34:00 niklas Exp $ */ +/* + * CAST-128 in C + * Written by Steve Reid <sreid@sea-to-sky.net> + * 100% Public Domain - no warranty + * Released 1997.10.11 + */ + +#ifndef _CAST_H_ +#define _CAST_H_ + +typedef struct { + u_int32_t xkey[32]; /* Key, after expansion */ + int rounds; /* Number of rounds to use, 12 or 16 */ +} cast_key; + +void cast_setkey(cast_key* key, u_int8_t* rawkey, int keybytes); +void cast_encrypt(cast_key* key, u_int8_t* inblock, u_int8_t* outblock); +void cast_decrypt(cast_key* key, u_int8_t* inblock, u_int8_t* outblock); + +#endif /* ifndef _CAST_H_ */ + diff --git a/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/GNUmakefile b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/GNUmakefile new file mode 100644 index 0000000..3b62328 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/GNUmakefile @@ -0,0 +1,57 @@ +# $OpenBSD: GNUmakefile,v 1.4 2003/06/03 14:52:06 ho Exp $ + +# +# Copyright (c) 1999 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. +# +# 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. +# + +.CURDIR:= $(shell pwd) + +LIB= sysdep +SRCS= arc4random.c blowfish.c cast.c md5.c sha1.c strlcat.c strlcpy.c +NOMAN= +CFLAGS+= -I${.CURDIR}/.. -I/usr/include/machine + +lib${LIB}.a: ${SRCS:%.c=%.o} + ar cq $@ ${SRCS:%.c=%.o} + +clean: + rm -f lib${LIB}.a ${SRCS:%.c=%.o} + +cleandir: clean cleandepend + +depend: .depend + +.depend: ${SRCS} + @rm -f .depend + ${MKDEP} ${CFLAGS} ${SRCS} > .depend + +cleandepend: + rm -f .depend + +ifneq ($(findstring clean,$(MAKECMDGOALS)),clean) +-include .depend +endif diff --git a/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/Makefile b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/Makefile new file mode 100644 index 0000000..fce68d3 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/Makefile @@ -0,0 +1,43 @@ +# $OpenBSD: Makefile,v 1.4 2003/06/03 14:52:06 ho Exp $ + +# +# Copyright (c) 1999 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. +# +# 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. +# +OPSYS!= uname -s + +LIB= sysdep +SRCS= arc4random.c blowfish.c cast.c md5.c sha1.c strlcat.c strlcpy.c +NOPROFILE= +NOPIC= +NOMAN= +.if ${OPSYS} == "NetBSD" +CPPFLAGS+= -I${.CURDIR}/.. -I/usr/include/machine +.else +CFLAGS+= -I${.CURDIR}/.. -I/usr/include/machine +.endif + +.include <bsd.lib.mk> diff --git a/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/arc4random.c b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/arc4random.c new file mode 100644 index 0000000..afd5bb6 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/arc4random.c @@ -0,0 +1,178 @@ +/* $OpenBSD: arc4random.c,v 1.6 2004/10/08 15:18:26 hshoexer Exp $ */ + +/* + * Arc4 random number generator for OpenBSD. + * Copyright 1996 David Mazieres <dm@lcs.mit.edu>. + * + * Modification and redistribution in source and binary forms is + * permitted provided that due credit is given to the author and the + * OpenBSD project by leaving this copyright notice intact. + */ + +/* + * This code is derived from section 17.1 of Applied Cryptography, + * second edition, which describes a stream cipher allegedly + * compatible with RSA Labs "RC4" cipher (the actual description of + * which is a trade secret). The same algorithm is used as a stream + * cipher called "arcfour" in Tatu Ylonen's ssh package. + * + * Here the stream cipher has been modified always to include the time + * when initializing the state. That makes it impossible to + * regenerate the same random sequence twice, so this can't be used + * for encryption, but will generate good random numbers. + * + * RC4 is a registered trademark of RSA Laboratories. + */ + +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/time.h> + +#ifdef __GNUC__ +#define inline __inline +#else /* !__GNUC__ */ +#define inline +#endif /* !__GNUC__ */ + +struct arc4_stream { + u_int8_t i; + u_int8_t j; + u_int8_t s[256]; +}; + +int rs_initialized; +static struct arc4_stream rs; + +static inline u_int8_t arc4_getbyte(struct arc4_stream *); + +static inline void +arc4_init(struct arc4_stream *as) +{ + int n; + + for (n = 0; n < 256; n++) + as->s[n] = n; + as->i = 0; + as->j = 0; +} + +static inline void +arc4_addrandom(struct arc4_stream *as, u_char *dat, int datlen) +{ + int n; + u_int8_t si; + + as->i--; + for (n = 0; n < 256; n++) { + as->i = (as->i + 1); + si = as->s[as->i]; + as->j = (as->j + si + dat[n % datlen]); + as->s[as->i] = as->s[as->j]; + as->s[as->j] = si; + } + as->j = as->i; +} + +static void +arc4_stir(struct arc4_stream *as) +{ + int fd, i; + struct { + struct timeval tv; + u_int8_t rnd[128 - sizeof(struct timeval)]; + } rdat; + + gettimeofday(&rdat.tv, NULL); + fd = open("/dev/arandom", O_RDONLY); + if (fd < 0) + fd = open("/dev/random", O_RDONLY); + if (fd >= 0) { + read(fd, rdat.rnd, sizeof(rdat.rnd)); + close(fd); + } + /* fd < 0? Ah, what the heck. We'll just take whatever was on the + * stack... */ + + arc4_addrandom(as, (void *)&rdat, sizeof(rdat)); + + /* + * Discard early keystream, as per recommendations in: + * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps + */ + for (i = 0; i < 256; i++) + (void)arc4_getbyte(as); +} + +static inline u_int8_t +arc4_getbyte(struct arc4_stream *as) +{ + u_int8_t si, sj; + + as->i = (as->i + 1); + si = as->s[as->i]; + as->j = (as->j + si); + sj = as->s[as->j]; + as->s[as->i] = sj; + as->s[as->j] = si; + return (as->s[(si + sj) & 0xff]); +} + +static inline u_int32_t +arc4_getword(struct arc4_stream *as) +{ + u_int32_t val; + val = arc4_getbyte(as) << 24; + val |= arc4_getbyte(as) << 16; + val |= arc4_getbyte(as) << 8; + val |= arc4_getbyte(as); + return val; +} + +void +arc4random_stir(void) +{ + if (!rs_initialized) { + arc4_init(&rs); + rs_initialized = 1; + } + arc4_stir(&rs); +} + +void +arc4random_addrandom(u_char *dat, int datlen) +{ + if (!rs_initialized) + arc4random_stir(); + arc4_addrandom(&rs, dat, datlen); +} + +u_int32_t +arc4random(void) +{ + if (!rs_initialized) + arc4random_stir(); + return arc4_getword(&rs); +} + +#if 0 +/*-------- Test code for i386 --------*/ +#include <stdio.h> +#include <machine/pctr.h> +int +main(int argc, char **argv) +{ + const int iter = 1000000; + int i; + pctrval v; + + v = rdtsc(); + for (i = 0; i < iter; i++) + arc4random(); + v = rdtsc() - v; + v /= iter; + + printf("%qd cycles\n", v); +} +#endif diff --git a/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/blowfish.c b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/blowfish.c new file mode 100644 index 0000000..5c59f4b --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/blowfish.c @@ -0,0 +1,685 @@ +/* $OpenBSD: blowfish.c,v 1.4 2003/06/03 14:52:06 ho Exp $ */ +/* + * Blowfish block cipher for OpenBSD + * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de> + * All rights reserved. + * + * Implementation advice by David Mazieres <dm@lcs.mit.edu>. + * + * 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. + * + * 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 is derived from section 14.3 and the given source + * in section V of Applied Cryptography, second edition. + * Blowfish is an unpatented fast block cipher designed by + * Bruce Schneier. + */ + +#if 0 +#include <stdio.h> /* used for debugging */ +#include <string.h> +#endif + +#include <sys/types.h> +#include <blf.h> + +#undef inline +#ifdef __GNUC__ +#define inline __inline +#else /* !__GNUC__ */ +#define inline +#endif /* !__GNUC__ */ + +/* Function for Feistel Networks */ + +#define F(bc, x) ((((bc)->S[0][((x) & 0xFF000000) >> 24] \ + + (bc)->S[1][((x) &0xFF0000 ) >> 16]) \ + ^ (bc)->S[2][((x) & 0xFF00) >> 8]) \ + + (bc)->S[3][(x) & 0x00FF]) + +#define BLFRND(bc,i,j,n) (i ^= F(bc,j) ^ (bc)->P[n]) + +void +Blowfish_encipher(c, xl, xr) + blf_ctx *c; + u_int32_t *xl; + u_int32_t *xr; +{ + u_int32_t Xl; + u_int32_t Xr; + + Xl = *xl; + Xr = *xr; + + Xl ^= c->P[0]; + BLFRND(c, Xr, Xl, 1); BLFRND(c, Xl, Xr, 2); + BLFRND(c, Xr, Xl, 3); BLFRND(c, Xl, Xr, 4); + BLFRND(c, Xr, Xl, 5); BLFRND(c, Xl, Xr, 6); + BLFRND(c, Xr, Xl, 7); BLFRND(c, Xl, Xr, 8); + BLFRND(c, Xr, Xl, 9); BLFRND(c, Xl, Xr, 10); + BLFRND(c, Xr, Xl, 11); BLFRND(c, Xl, Xr, 12); + BLFRND(c, Xr, Xl, 13); BLFRND(c, Xl, Xr, 14); + BLFRND(c, Xr, Xl, 15); BLFRND(c, Xl, Xr, 16); + + *xl = Xr ^ c->P[17]; + *xr = Xl; +} + +void +Blowfish_decipher(c, xl, xr) + blf_ctx *c; + u_int32_t *xl; + u_int32_t *xr; +{ + u_int32_t Xl; + u_int32_t Xr; + + Xl = *xl; + Xr = *xr; + + Xl ^= c->P[17]; + BLFRND(c, Xr, Xl, 16); BLFRND(c, Xl, Xr, 15); + BLFRND(c, Xr, Xl, 14); BLFRND(c, Xl, Xr, 13); + BLFRND(c, Xr, Xl, 12); BLFRND(c, Xl, Xr, 11); + BLFRND(c, Xr, Xl, 10); BLFRND(c, Xl, Xr, 9); + BLFRND(c, Xr, Xl, 8); BLFRND(c, Xl, Xr, 7); + BLFRND(c, Xr, Xl, 6); BLFRND(c, Xl, Xr, 5); + BLFRND(c, Xr, Xl, 4); BLFRND(c, Xl, Xr, 3); + BLFRND(c, Xr, Xl, 2); BLFRND(c, Xl, Xr, 1); + + *xl = Xr ^ c->P[0]; + *xr = Xl; +} + +void +Blowfish_initstate(c) + blf_ctx *c; +{ + +/* P-box and S-box tables initialized with digits of Pi */ + + const blf_ctx initstate = + + { { + { + 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, + 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, + 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, + 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, + 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, + 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, + 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, + 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, + 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, + 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, + 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, + 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, + 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, + 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, + 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, + 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, + 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, + 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, + 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, + 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, + 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, + 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, + 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, + 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, + 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, + 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, + 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, + 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, + 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, + 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, + 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, + 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, + 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, + 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, + 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, + 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, + 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, + 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, + 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, + 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, + 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, + 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, + 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, + 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, + 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, + 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, + 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, + 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, + 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, + 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, + 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, + 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, + 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, + 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a}, + { + 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, + 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, + 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, + 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, + 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, + 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, + 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, + 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, + 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, + 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, + 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, + 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, + 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, + 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, + 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, + 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, + 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, + 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, + 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, + 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, + 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, + 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, + 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, + 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, + 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, + 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, + 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, + 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, + 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, + 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, + 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, + 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, + 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, + 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, + 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, + 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, + 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, + 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, + 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, + 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, + 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, + 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, + 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, + 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, + 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, + 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, + 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, + 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, + 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, + 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, + 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, + 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, + 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, + 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7}, + { + 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, + 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, + 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, + 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, + 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, + 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, + 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, + 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, + 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, + 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, + 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, + 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, + 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, + 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, + 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, + 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, + 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, + 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, + 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, + 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, + 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, + 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, + 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, + 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, + 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, + 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, + 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, + 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, + 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, + 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, + 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, + 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, + 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, + 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, + 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, + 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, + 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, + 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, + 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, + 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, + 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, + 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, + 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, + 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, + 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, + 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, + 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, + 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, + 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, + 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, + 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, + 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, + 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, + 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0}, + { + 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, + 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, + 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, + 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, + 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, + 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, + 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, + 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, + 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, + 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, + 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, + 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, + 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, + 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, + 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, + 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, + 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, + 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, + 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, + 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, + 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, + 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, + 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, + 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, + 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, + 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, + 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, + 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, + 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, + 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, + 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, + 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, + 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, + 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, + 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, + 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, + 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, + 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, + 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, + 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, + 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, + 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, + 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, + 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, + 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, + 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, + 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, + 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, + 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, + 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, + 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, + 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, + 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, + 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6} + }, + { + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, + 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, + 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, + 0x9216d5d9, 0x8979fb1b + } }; + + *c = initstate; + +} + +u_int32_t +Blowfish_stream2word(const u_int8_t *data, u_int16_t databytes, u_int16_t *current) +{ + u_int8_t i; + u_int16_t j; + u_int32_t temp; + + temp = 0x00000000; + j = *current; + + for (i = 0; i < 4; i++, j++) { + if (j >= databytes) + j = 0; + temp = (temp << 8) | data[j]; + } + + *current = j; + return temp; +} + +void +Blowfish_expand0state(blf_ctx *c, const u_int8_t *key, u_int16_t keybytes) +{ + u_int16_t i; + u_int16_t j; + u_int16_t k; + u_int32_t temp; + u_int32_t datal; + u_int32_t datar; + + j = 0; + for (i = 0; i < BLF_N + 2; i++) { + /* Extract 4 int8 to 1 int32 from keystream */ + temp = Blowfish_stream2word(key, keybytes, &j); + c->P[i] = c->P[i] ^ temp; + } + + j = 0; + datal = 0x00000000; + datar = 0x00000000; + for (i = 0; i < BLF_N + 2; i += 2) { + Blowfish_encipher(c, &datal, &datar); + + c->P[i] = datal; + c->P[i + 1] = datar; + } + + for (i = 0; i < 4; i++) { + for (k = 0; k < 256; k += 2) { + Blowfish_encipher(c, &datal, &datar); + + c->S[i][k] = datal; + c->S[i][k + 1] = datar; + } + } +} + + +void +Blowfish_expandstate(blf_ctx *c, const u_int8_t *data, u_int16_t databytes, + const u_int8_t *key, u_int16_t keybytes) +{ + u_int16_t i; + u_int16_t j; + u_int16_t k; + u_int32_t temp; + u_int32_t datal; + u_int32_t datar; + + j = 0; + for (i = 0; i < BLF_N + 2; i++) { + /* Extract 4 int8 to 1 int32 from keystream */ + temp = Blowfish_stream2word(key, keybytes, &j); + c->P[i] = c->P[i] ^ temp; + } + + j = 0; + datal = 0x00000000; + datar = 0x00000000; + for (i = 0; i < BLF_N + 2; i += 2) { + datal ^= Blowfish_stream2word(data, databytes, &j); + datar ^= Blowfish_stream2word(data, databytes, &j); + Blowfish_encipher(c, &datal, &datar); + + c->P[i] = datal; + c->P[i + 1] = datar; + } + + for (i = 0; i < 4; i++) { + for (k = 0; k < 256; k += 2) { + datal ^= Blowfish_stream2word(data, databytes, &j); + datar ^= Blowfish_stream2word(data, databytes, &j); + Blowfish_encipher(c, &datal, &datar); + + c->S[i][k] = datal; + c->S[i][k + 1] = datar; + } + } + +} + +void +blf_key(blf_ctx *c, const u_int8_t *k, u_int16_t len) +{ + /* Initialize S-boxes and subkeys with Pi */ + Blowfish_initstate(c); + + /* Transform S-boxes and subkeys with key */ + Blowfish_expand0state(c, k, len); +} + +void +blf_enc(blf_ctx *c, u_int32_t *data, u_int16_t blocks) +{ + u_int32_t *d; + u_int16_t i; + + d = data; + for (i = 0; i < blocks; i++) { + Blowfish_encipher(c, d, d + 1); + d += 2; + } +} + +void +blf_dec(blf_ctx *c, u_int32_t *data, u_int16_t blocks) +{ + u_int32_t *d; + u_int16_t i; + + d = data; + for (i = 0; i < blocks; i++) { + Blowfish_decipher(c, d, d + 1); + d += 2; + } +} + +void +blf_ecb_encrypt(blf_ctx *c, u_int8_t *data, u_int32_t len) +{ + u_int32_t l, r; + u_int32_t i; + + for (i = 0; i < len; i += 8) { + l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; + r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; + Blowfish_encipher(c, &l, &r); + data[0] = l >> 24 & 0xff; + data[1] = l >> 16 & 0xff; + data[2] = l >> 8 & 0xff; + data[3] = l & 0xff; + data[4] = r >> 24 & 0xff; + data[5] = r >> 16 & 0xff; + data[6] = r >> 8 & 0xff; + data[7] = r & 0xff; + data += 8; + } +} + +void +blf_ecb_decrypt(blf_ctx *c, u_int8_t *data, u_int32_t len) +{ + u_int32_t l, r; + u_int32_t i; + + for (i = 0; i < len; i += 8) { + l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; + r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; + Blowfish_decipher(c, &l, &r); + data[0] = l >> 24 & 0xff; + data[1] = l >> 16 & 0xff; + data[2] = l >> 8 & 0xff; + data[3] = l & 0xff; + data[4] = r >> 24 & 0xff; + data[5] = r >> 16 & 0xff; + data[6] = r >> 8 & 0xff; + data[7] = r & 0xff; + data += 8; + } +} + +void +blf_cbc_encrypt(blf_ctx *c, u_int8_t *iv, u_int8_t *data, u_int32_t len) +{ + u_int32_t l, r; + u_int32_t i, j; + + for (i = 0; i < len; i += 8) { + for (j = 0; j < 8; j++) + data[j] ^= iv[j]; + l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; + r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; + Blowfish_encipher(c, &l, &r); + data[0] = l >> 24 & 0xff; + data[1] = l >> 16 & 0xff; + data[2] = l >> 8 & 0xff; + data[3] = l & 0xff; + data[4] = r >> 24 & 0xff; + data[5] = r >> 16 & 0xff; + data[6] = r >> 8 & 0xff; + data[7] = r & 0xff; + iv = data; + data += 8; + } +} + +void +blf_cbc_decrypt(blf_ctx *c, u_int8_t *iva, u_int8_t *data, u_int32_t len) +{ + u_int32_t l, r; + u_int8_t *iv; + u_int32_t i, j; + + iv = data + len - 16; + data = data + len - 8; + for (i = len - 8; i >= 8; i -= 8) { + l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; + r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; + Blowfish_decipher(c, &l, &r); + data[0] = l >> 24 & 0xff; + data[1] = l >> 16 & 0xff; + data[2] = l >> 8 & 0xff; + data[3] = l & 0xff; + data[4] = r >> 24 & 0xff; + data[5] = r >> 16 & 0xff; + data[6] = r >> 8 & 0xff; + data[7] = r & 0xff; + for (j = 0; j < 8; j++) + data[j] ^= iv[j]; + iv -= 8; + data -= 8; + } + l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; + r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; + Blowfish_decipher(c, &l, &r); + data[0] = l >> 24 & 0xff; + data[1] = l >> 16 & 0xff; + data[2] = l >> 8 & 0xff; + data[3] = l & 0xff; + data[4] = r >> 24 & 0xff; + data[5] = r >> 16 & 0xff; + data[6] = r >> 8 & 0xff; + data[7] = r & 0xff; + for (j = 0; j < 8; j++) + data[j] ^= iva[j]; +} + +#if 0 +void +report(u_int32_t data[], u_int16_t len) +{ + u_int16_t i; + for (i = 0; i < len; i += 2) + printf("Block %0hd: %08lx %08lx.\n", + i / 2, data[i], data[i + 1]); +} +void +main(void) +{ + + blf_ctx c; + char key[] = "AAAAA"; + char key2[] = "abcdefghijklmnopqrstuvwxyz"; + + u_int32_t data[10]; + u_int32_t data2[] = + {0x424c4f57l, 0x46495348l}; + + u_int16_t i; + + /* First test */ + for (i = 0; i < 10; i++) + data[i] = i; + + blf_key(&c, (u_int8_t *) key, 5); + blf_enc(&c, data, 5); + blf_dec(&c, data, 1); + blf_dec(&c, data + 2, 4); + printf("Should read as 0 - 9.\n"); + report(data, 10); + + /* Second test */ + blf_key(&c, (u_int8_t *) key2, strlen(key2)); + blf_enc(&c, data2, 1); + printf("\nShould read as: 0x324ed0fe 0xf413a203.\n"); + report(data2, 2); + blf_dec(&c, data2, 1); + report(data2, 2); +} +#endif diff --git a/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/cast.c b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/cast.c new file mode 100644 index 0000000..dc21610 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/cast.c @@ -0,0 +1,778 @@ +/* $OpenBSD: cast.c,v 1.3 2001/06/05 00:12:51 niklas Exp $ */ +/* + * CAST-128 in C + * Written by Steve Reid <sreid@sea-to-sky.net> + * 100% Public Domain - no warranty + * Released 1997.10.11 + */ + +#include <sys/types.h> + +#include <cast.h> + +/* CAST S-Boxes */ + +static const u_int32_t cast_sbox1[256] = { + 0x30FB40D4, 0x9FA0FF0B, 0x6BECCD2F, 0x3F258C7A, + 0x1E213F2F, 0x9C004DD3, 0x6003E540, 0xCF9FC949, + 0xBFD4AF27, 0x88BBBDB5, 0xE2034090, 0x98D09675, + 0x6E63A0E0, 0x15C361D2, 0xC2E7661D, 0x22D4FF8E, + 0x28683B6F, 0xC07FD059, 0xFF2379C8, 0x775F50E2, + 0x43C340D3, 0xDF2F8656, 0x887CA41A, 0xA2D2BD2D, + 0xA1C9E0D6, 0x346C4819, 0x61B76D87, 0x22540F2F, + 0x2ABE32E1, 0xAA54166B, 0x22568E3A, 0xA2D341D0, + 0x66DB40C8, 0xA784392F, 0x004DFF2F, 0x2DB9D2DE, + 0x97943FAC, 0x4A97C1D8, 0x527644B7, 0xB5F437A7, + 0xB82CBAEF, 0xD751D159, 0x6FF7F0ED, 0x5A097A1F, + 0x827B68D0, 0x90ECF52E, 0x22B0C054, 0xBC8E5935, + 0x4B6D2F7F, 0x50BB64A2, 0xD2664910, 0xBEE5812D, + 0xB7332290, 0xE93B159F, 0xB48EE411, 0x4BFF345D, + 0xFD45C240, 0xAD31973F, 0xC4F6D02E, 0x55FC8165, + 0xD5B1CAAD, 0xA1AC2DAE, 0xA2D4B76D, 0xC19B0C50, + 0x882240F2, 0x0C6E4F38, 0xA4E4BFD7, 0x4F5BA272, + 0x564C1D2F, 0xC59C5319, 0xB949E354, 0xB04669FE, + 0xB1B6AB8A, 0xC71358DD, 0x6385C545, 0x110F935D, + 0x57538AD5, 0x6A390493, 0xE63D37E0, 0x2A54F6B3, + 0x3A787D5F, 0x6276A0B5, 0x19A6FCDF, 0x7A42206A, + 0x29F9D4D5, 0xF61B1891, 0xBB72275E, 0xAA508167, + 0x38901091, 0xC6B505EB, 0x84C7CB8C, 0x2AD75A0F, + 0x874A1427, 0xA2D1936B, 0x2AD286AF, 0xAA56D291, + 0xD7894360, 0x425C750D, 0x93B39E26, 0x187184C9, + 0x6C00B32D, 0x73E2BB14, 0xA0BEBC3C, 0x54623779, + 0x64459EAB, 0x3F328B82, 0x7718CF82, 0x59A2CEA6, + 0x04EE002E, 0x89FE78E6, 0x3FAB0950, 0x325FF6C2, + 0x81383F05, 0x6963C5C8, 0x76CB5AD6, 0xD49974C9, + 0xCA180DCF, 0x380782D5, 0xC7FA5CF6, 0x8AC31511, + 0x35E79E13, 0x47DA91D0, 0xF40F9086, 0xA7E2419E, + 0x31366241, 0x051EF495, 0xAA573B04, 0x4A805D8D, + 0x548300D0, 0x00322A3C, 0xBF64CDDF, 0xBA57A68E, + 0x75C6372B, 0x50AFD341, 0xA7C13275, 0x915A0BF5, + 0x6B54BFAB, 0x2B0B1426, 0xAB4CC9D7, 0x449CCD82, + 0xF7FBF265, 0xAB85C5F3, 0x1B55DB94, 0xAAD4E324, + 0xCFA4BD3F, 0x2DEAA3E2, 0x9E204D02, 0xC8BD25AC, + 0xEADF55B3, 0xD5BD9E98, 0xE31231B2, 0x2AD5AD6C, + 0x954329DE, 0xADBE4528, 0xD8710F69, 0xAA51C90F, + 0xAA786BF6, 0x22513F1E, 0xAA51A79B, 0x2AD344CC, + 0x7B5A41F0, 0xD37CFBAD, 0x1B069505, 0x41ECE491, + 0xB4C332E6, 0x032268D4, 0xC9600ACC, 0xCE387E6D, + 0xBF6BB16C, 0x6A70FB78, 0x0D03D9C9, 0xD4DF39DE, + 0xE01063DA, 0x4736F464, 0x5AD328D8, 0xB347CC96, + 0x75BB0FC3, 0x98511BFB, 0x4FFBCC35, 0xB58BCF6A, + 0xE11F0ABC, 0xBFC5FE4A, 0xA70AEC10, 0xAC39570A, + 0x3F04442F, 0x6188B153, 0xE0397A2E, 0x5727CB79, + 0x9CEB418F, 0x1CACD68D, 0x2AD37C96, 0x0175CB9D, + 0xC69DFF09, 0xC75B65F0, 0xD9DB40D8, 0xEC0E7779, + 0x4744EAD4, 0xB11C3274, 0xDD24CB9E, 0x7E1C54BD, + 0xF01144F9, 0xD2240EB1, 0x9675B3FD, 0xA3AC3755, + 0xD47C27AF, 0x51C85F4D, 0x56907596, 0xA5BB15E6, + 0x580304F0, 0xCA042CF1, 0x011A37EA, 0x8DBFAADB, + 0x35BA3E4A, 0x3526FFA0, 0xC37B4D09, 0xBC306ED9, + 0x98A52666, 0x5648F725, 0xFF5E569D, 0x0CED63D0, + 0x7C63B2CF, 0x700B45E1, 0xD5EA50F1, 0x85A92872, + 0xAF1FBDA7, 0xD4234870, 0xA7870BF3, 0x2D3B4D79, + 0x42E04198, 0x0CD0EDE7, 0x26470DB8, 0xF881814C, + 0x474D6AD7, 0x7C0C5E5C, 0xD1231959, 0x381B7298, + 0xF5D2F4DB, 0xAB838653, 0x6E2F1E23, 0x83719C9E, + 0xBD91E046, 0x9A56456E, 0xDC39200C, 0x20C8C571, + 0x962BDA1C, 0xE1E696FF, 0xB141AB08, 0x7CCA89B9, + 0x1A69E783, 0x02CC4843, 0xA2F7C579, 0x429EF47D, + 0x427B169C, 0x5AC9F049, 0xDD8F0F00, 0x5C8165BF +}; + +static const u_int32_t cast_sbox2[256] = { + 0x1F201094, 0xEF0BA75B, 0x69E3CF7E, 0x393F4380, + 0xFE61CF7A, 0xEEC5207A, 0x55889C94, 0x72FC0651, + 0xADA7EF79, 0x4E1D7235, 0xD55A63CE, 0xDE0436BA, + 0x99C430EF, 0x5F0C0794, 0x18DCDB7D, 0xA1D6EFF3, + 0xA0B52F7B, 0x59E83605, 0xEE15B094, 0xE9FFD909, + 0xDC440086, 0xEF944459, 0xBA83CCB3, 0xE0C3CDFB, + 0xD1DA4181, 0x3B092AB1, 0xF997F1C1, 0xA5E6CF7B, + 0x01420DDB, 0xE4E7EF5B, 0x25A1FF41, 0xE180F806, + 0x1FC41080, 0x179BEE7A, 0xD37AC6A9, 0xFE5830A4, + 0x98DE8B7F, 0x77E83F4E, 0x79929269, 0x24FA9F7B, + 0xE113C85B, 0xACC40083, 0xD7503525, 0xF7EA615F, + 0x62143154, 0x0D554B63, 0x5D681121, 0xC866C359, + 0x3D63CF73, 0xCEE234C0, 0xD4D87E87, 0x5C672B21, + 0x071F6181, 0x39F7627F, 0x361E3084, 0xE4EB573B, + 0x602F64A4, 0xD63ACD9C, 0x1BBC4635, 0x9E81032D, + 0x2701F50C, 0x99847AB4, 0xA0E3DF79, 0xBA6CF38C, + 0x10843094, 0x2537A95E, 0xF46F6FFE, 0xA1FF3B1F, + 0x208CFB6A, 0x8F458C74, 0xD9E0A227, 0x4EC73A34, + 0xFC884F69, 0x3E4DE8DF, 0xEF0E0088, 0x3559648D, + 0x8A45388C, 0x1D804366, 0x721D9BFD, 0xA58684BB, + 0xE8256333, 0x844E8212, 0x128D8098, 0xFED33FB4, + 0xCE280AE1, 0x27E19BA5, 0xD5A6C252, 0xE49754BD, + 0xC5D655DD, 0xEB667064, 0x77840B4D, 0xA1B6A801, + 0x84DB26A9, 0xE0B56714, 0x21F043B7, 0xE5D05860, + 0x54F03084, 0x066FF472, 0xA31AA153, 0xDADC4755, + 0xB5625DBF, 0x68561BE6, 0x83CA6B94, 0x2D6ED23B, + 0xECCF01DB, 0xA6D3D0BA, 0xB6803D5C, 0xAF77A709, + 0x33B4A34C, 0x397BC8D6, 0x5EE22B95, 0x5F0E5304, + 0x81ED6F61, 0x20E74364, 0xB45E1378, 0xDE18639B, + 0x881CA122, 0xB96726D1, 0x8049A7E8, 0x22B7DA7B, + 0x5E552D25, 0x5272D237, 0x79D2951C, 0xC60D894C, + 0x488CB402, 0x1BA4FE5B, 0xA4B09F6B, 0x1CA815CF, + 0xA20C3005, 0x8871DF63, 0xB9DE2FCB, 0x0CC6C9E9, + 0x0BEEFF53, 0xE3214517, 0xB4542835, 0x9F63293C, + 0xEE41E729, 0x6E1D2D7C, 0x50045286, 0x1E6685F3, + 0xF33401C6, 0x30A22C95, 0x31A70850, 0x60930F13, + 0x73F98417, 0xA1269859, 0xEC645C44, 0x52C877A9, + 0xCDFF33A6, 0xA02B1741, 0x7CBAD9A2, 0x2180036F, + 0x50D99C08, 0xCB3F4861, 0xC26BD765, 0x64A3F6AB, + 0x80342676, 0x25A75E7B, 0xE4E6D1FC, 0x20C710E6, + 0xCDF0B680, 0x17844D3B, 0x31EEF84D, 0x7E0824E4, + 0x2CCB49EB, 0x846A3BAE, 0x8FF77888, 0xEE5D60F6, + 0x7AF75673, 0x2FDD5CDB, 0xA11631C1, 0x30F66F43, + 0xB3FAEC54, 0x157FD7FA, 0xEF8579CC, 0xD152DE58, + 0xDB2FFD5E, 0x8F32CE19, 0x306AF97A, 0x02F03EF8, + 0x99319AD5, 0xC242FA0F, 0xA7E3EBB0, 0xC68E4906, + 0xB8DA230C, 0x80823028, 0xDCDEF3C8, 0xD35FB171, + 0x088A1BC8, 0xBEC0C560, 0x61A3C9E8, 0xBCA8F54D, + 0xC72FEFFA, 0x22822E99, 0x82C570B4, 0xD8D94E89, + 0x8B1C34BC, 0x301E16E6, 0x273BE979, 0xB0FFEAA6, + 0x61D9B8C6, 0x00B24869, 0xB7FFCE3F, 0x08DC283B, + 0x43DAF65A, 0xF7E19798, 0x7619B72F, 0x8F1C9BA4, + 0xDC8637A0, 0x16A7D3B1, 0x9FC393B7, 0xA7136EEB, + 0xC6BCC63E, 0x1A513742, 0xEF6828BC, 0x520365D6, + 0x2D6A77AB, 0x3527ED4B, 0x821FD216, 0x095C6E2E, + 0xDB92F2FB, 0x5EEA29CB, 0x145892F5, 0x91584F7F, + 0x5483697B, 0x2667A8CC, 0x85196048, 0x8C4BACEA, + 0x833860D4, 0x0D23E0F9, 0x6C387E8A, 0x0AE6D249, + 0xB284600C, 0xD835731D, 0xDCB1C647, 0xAC4C56EA, + 0x3EBD81B3, 0x230EABB0, 0x6438BC87, 0xF0B5B1FA, + 0x8F5EA2B3, 0xFC184642, 0x0A036B7A, 0x4FB089BD, + 0x649DA589, 0xA345415E, 0x5C038323, 0x3E5D3BB9, + 0x43D79572, 0x7E6DD07C, 0x06DFDF1E, 0x6C6CC4EF, + 0x7160A539, 0x73BFBE70, 0x83877605, 0x4523ECF1 +}; + +static const u_int32_t cast_sbox3[256] = { + 0x8DEFC240, 0x25FA5D9F, 0xEB903DBF, 0xE810C907, + 0x47607FFF, 0x369FE44B, 0x8C1FC644, 0xAECECA90, + 0xBEB1F9BF, 0xEEFBCAEA, 0xE8CF1950, 0x51DF07AE, + 0x920E8806, 0xF0AD0548, 0xE13C8D83, 0x927010D5, + 0x11107D9F, 0x07647DB9, 0xB2E3E4D4, 0x3D4F285E, + 0xB9AFA820, 0xFADE82E0, 0xA067268B, 0x8272792E, + 0x553FB2C0, 0x489AE22B, 0xD4EF9794, 0x125E3FBC, + 0x21FFFCEE, 0x825B1BFD, 0x9255C5ED, 0x1257A240, + 0x4E1A8302, 0xBAE07FFF, 0x528246E7, 0x8E57140E, + 0x3373F7BF, 0x8C9F8188, 0xA6FC4EE8, 0xC982B5A5, + 0xA8C01DB7, 0x579FC264, 0x67094F31, 0xF2BD3F5F, + 0x40FFF7C1, 0x1FB78DFC, 0x8E6BD2C1, 0x437BE59B, + 0x99B03DBF, 0xB5DBC64B, 0x638DC0E6, 0x55819D99, + 0xA197C81C, 0x4A012D6E, 0xC5884A28, 0xCCC36F71, + 0xB843C213, 0x6C0743F1, 0x8309893C, 0x0FEDDD5F, + 0x2F7FE850, 0xD7C07F7E, 0x02507FBF, 0x5AFB9A04, + 0xA747D2D0, 0x1651192E, 0xAF70BF3E, 0x58C31380, + 0x5F98302E, 0x727CC3C4, 0x0A0FB402, 0x0F7FEF82, + 0x8C96FDAD, 0x5D2C2AAE, 0x8EE99A49, 0x50DA88B8, + 0x8427F4A0, 0x1EAC5790, 0x796FB449, 0x8252DC15, + 0xEFBD7D9B, 0xA672597D, 0xADA840D8, 0x45F54504, + 0xFA5D7403, 0xE83EC305, 0x4F91751A, 0x925669C2, + 0x23EFE941, 0xA903F12E, 0x60270DF2, 0x0276E4B6, + 0x94FD6574, 0x927985B2, 0x8276DBCB, 0x02778176, + 0xF8AF918D, 0x4E48F79E, 0x8F616DDF, 0xE29D840E, + 0x842F7D83, 0x340CE5C8, 0x96BBB682, 0x93B4B148, + 0xEF303CAB, 0x984FAF28, 0x779FAF9B, 0x92DC560D, + 0x224D1E20, 0x8437AA88, 0x7D29DC96, 0x2756D3DC, + 0x8B907CEE, 0xB51FD240, 0xE7C07CE3, 0xE566B4A1, + 0xC3E9615E, 0x3CF8209D, 0x6094D1E3, 0xCD9CA341, + 0x5C76460E, 0x00EA983B, 0xD4D67881, 0xFD47572C, + 0xF76CEDD9, 0xBDA8229C, 0x127DADAA, 0x438A074E, + 0x1F97C090, 0x081BDB8A, 0x93A07EBE, 0xB938CA15, + 0x97B03CFF, 0x3DC2C0F8, 0x8D1AB2EC, 0x64380E51, + 0x68CC7BFB, 0xD90F2788, 0x12490181, 0x5DE5FFD4, + 0xDD7EF86A, 0x76A2E214, 0xB9A40368, 0x925D958F, + 0x4B39FFFA, 0xBA39AEE9, 0xA4FFD30B, 0xFAF7933B, + 0x6D498623, 0x193CBCFA, 0x27627545, 0x825CF47A, + 0x61BD8BA0, 0xD11E42D1, 0xCEAD04F4, 0x127EA392, + 0x10428DB7, 0x8272A972, 0x9270C4A8, 0x127DE50B, + 0x285BA1C8, 0x3C62F44F, 0x35C0EAA5, 0xE805D231, + 0x428929FB, 0xB4FCDF82, 0x4FB66A53, 0x0E7DC15B, + 0x1F081FAB, 0x108618AE, 0xFCFD086D, 0xF9FF2889, + 0x694BCC11, 0x236A5CAE, 0x12DECA4D, 0x2C3F8CC5, + 0xD2D02DFE, 0xF8EF5896, 0xE4CF52DA, 0x95155B67, + 0x494A488C, 0xB9B6A80C, 0x5C8F82BC, 0x89D36B45, + 0x3A609437, 0xEC00C9A9, 0x44715253, 0x0A874B49, + 0xD773BC40, 0x7C34671C, 0x02717EF6, 0x4FEB5536, + 0xA2D02FFF, 0xD2BF60C4, 0xD43F03C0, 0x50B4EF6D, + 0x07478CD1, 0x006E1888, 0xA2E53F55, 0xB9E6D4BC, + 0xA2048016, 0x97573833, 0xD7207D67, 0xDE0F8F3D, + 0x72F87B33, 0xABCC4F33, 0x7688C55D, 0x7B00A6B0, + 0x947B0001, 0x570075D2, 0xF9BB88F8, 0x8942019E, + 0x4264A5FF, 0x856302E0, 0x72DBD92B, 0xEE971B69, + 0x6EA22FDE, 0x5F08AE2B, 0xAF7A616D, 0xE5C98767, + 0xCF1FEBD2, 0x61EFC8C2, 0xF1AC2571, 0xCC8239C2, + 0x67214CB8, 0xB1E583D1, 0xB7DC3E62, 0x7F10BDCE, + 0xF90A5C38, 0x0FF0443D, 0x606E6DC6, 0x60543A49, + 0x5727C148, 0x2BE98A1D, 0x8AB41738, 0x20E1BE24, + 0xAF96DA0F, 0x68458425, 0x99833BE5, 0x600D457D, + 0x282F9350, 0x8334B362, 0xD91D1120, 0x2B6D8DA0, + 0x642B1E31, 0x9C305A00, 0x52BCE688, 0x1B03588A, + 0xF7BAEFD5, 0x4142ED9C, 0xA4315C11, 0x83323EC5, + 0xDFEF4636, 0xA133C501, 0xE9D3531C, 0xEE353783 +}; + +static const u_int32_t cast_sbox4[256] = { + 0x9DB30420, 0x1FB6E9DE, 0xA7BE7BEF, 0xD273A298, + 0x4A4F7BDB, 0x64AD8C57, 0x85510443, 0xFA020ED1, + 0x7E287AFF, 0xE60FB663, 0x095F35A1, 0x79EBF120, + 0xFD059D43, 0x6497B7B1, 0xF3641F63, 0x241E4ADF, + 0x28147F5F, 0x4FA2B8CD, 0xC9430040, 0x0CC32220, + 0xFDD30B30, 0xC0A5374F, 0x1D2D00D9, 0x24147B15, + 0xEE4D111A, 0x0FCA5167, 0x71FF904C, 0x2D195FFE, + 0x1A05645F, 0x0C13FEFE, 0x081B08CA, 0x05170121, + 0x80530100, 0xE83E5EFE, 0xAC9AF4F8, 0x7FE72701, + 0xD2B8EE5F, 0x06DF4261, 0xBB9E9B8A, 0x7293EA25, + 0xCE84FFDF, 0xF5718801, 0x3DD64B04, 0xA26F263B, + 0x7ED48400, 0x547EEBE6, 0x446D4CA0, 0x6CF3D6F5, + 0x2649ABDF, 0xAEA0C7F5, 0x36338CC1, 0x503F7E93, + 0xD3772061, 0x11B638E1, 0x72500E03, 0xF80EB2BB, + 0xABE0502E, 0xEC8D77DE, 0x57971E81, 0xE14F6746, + 0xC9335400, 0x6920318F, 0x081DBB99, 0xFFC304A5, + 0x4D351805, 0x7F3D5CE3, 0xA6C866C6, 0x5D5BCCA9, + 0xDAEC6FEA, 0x9F926F91, 0x9F46222F, 0x3991467D, + 0xA5BF6D8E, 0x1143C44F, 0x43958302, 0xD0214EEB, + 0x022083B8, 0x3FB6180C, 0x18F8931E, 0x281658E6, + 0x26486E3E, 0x8BD78A70, 0x7477E4C1, 0xB506E07C, + 0xF32D0A25, 0x79098B02, 0xE4EABB81, 0x28123B23, + 0x69DEAD38, 0x1574CA16, 0xDF871B62, 0x211C40B7, + 0xA51A9EF9, 0x0014377B, 0x041E8AC8, 0x09114003, + 0xBD59E4D2, 0xE3D156D5, 0x4FE876D5, 0x2F91A340, + 0x557BE8DE, 0x00EAE4A7, 0x0CE5C2EC, 0x4DB4BBA6, + 0xE756BDFF, 0xDD3369AC, 0xEC17B035, 0x06572327, + 0x99AFC8B0, 0x56C8C391, 0x6B65811C, 0x5E146119, + 0x6E85CB75, 0xBE07C002, 0xC2325577, 0x893FF4EC, + 0x5BBFC92D, 0xD0EC3B25, 0xB7801AB7, 0x8D6D3B24, + 0x20C763EF, 0xC366A5FC, 0x9C382880, 0x0ACE3205, + 0xAAC9548A, 0xECA1D7C7, 0x041AFA32, 0x1D16625A, + 0x6701902C, 0x9B757A54, 0x31D477F7, 0x9126B031, + 0x36CC6FDB, 0xC70B8B46, 0xD9E66A48, 0x56E55A79, + 0x026A4CEB, 0x52437EFF, 0x2F8F76B4, 0x0DF980A5, + 0x8674CDE3, 0xEDDA04EB, 0x17A9BE04, 0x2C18F4DF, + 0xB7747F9D, 0xAB2AF7B4, 0xEFC34D20, 0x2E096B7C, + 0x1741A254, 0xE5B6A035, 0x213D42F6, 0x2C1C7C26, + 0x61C2F50F, 0x6552DAF9, 0xD2C231F8, 0x25130F69, + 0xD8167FA2, 0x0418F2C8, 0x001A96A6, 0x0D1526AB, + 0x63315C21, 0x5E0A72EC, 0x49BAFEFD, 0x187908D9, + 0x8D0DBD86, 0x311170A7, 0x3E9B640C, 0xCC3E10D7, + 0xD5CAD3B6, 0x0CAEC388, 0xF73001E1, 0x6C728AFF, + 0x71EAE2A1, 0x1F9AF36E, 0xCFCBD12F, 0xC1DE8417, + 0xAC07BE6B, 0xCB44A1D8, 0x8B9B0F56, 0x013988C3, + 0xB1C52FCA, 0xB4BE31CD, 0xD8782806, 0x12A3A4E2, + 0x6F7DE532, 0x58FD7EB6, 0xD01EE900, 0x24ADFFC2, + 0xF4990FC5, 0x9711AAC5, 0x001D7B95, 0x82E5E7D2, + 0x109873F6, 0x00613096, 0xC32D9521, 0xADA121FF, + 0x29908415, 0x7FBB977F, 0xAF9EB3DB, 0x29C9ED2A, + 0x5CE2A465, 0xA730F32C, 0xD0AA3FE8, 0x8A5CC091, + 0xD49E2CE7, 0x0CE454A9, 0xD60ACD86, 0x015F1919, + 0x77079103, 0xDEA03AF6, 0x78A8565E, 0xDEE356DF, + 0x21F05CBE, 0x8B75E387, 0xB3C50651, 0xB8A5C3EF, + 0xD8EEB6D2, 0xE523BE77, 0xC2154529, 0x2F69EFDF, + 0xAFE67AFB, 0xF470C4B2, 0xF3E0EB5B, 0xD6CC9876, + 0x39E4460C, 0x1FDA8538, 0x1987832F, 0xCA007367, + 0xA99144F8, 0x296B299E, 0x492FC295, 0x9266BEAB, + 0xB5676E69, 0x9BD3DDDA, 0xDF7E052F, 0xDB25701C, + 0x1B5E51EE, 0xF65324E6, 0x6AFCE36C, 0x0316CC04, + 0x8644213E, 0xB7DC59D0, 0x7965291F, 0xCCD6FD43, + 0x41823979, 0x932BCDF6, 0xB657C34D, 0x4EDFD282, + 0x7AE5290C, 0x3CB9536B, 0x851E20FE, 0x9833557E, + 0x13ECF0B0, 0xD3FFB372, 0x3F85C5C1, 0x0AEF7ED2 +}; + +static const u_int32_t cast_sbox5[256] = { + 0x7EC90C04, 0x2C6E74B9, 0x9B0E66DF, 0xA6337911, + 0xB86A7FFF, 0x1DD358F5, 0x44DD9D44, 0x1731167F, + 0x08FBF1FA, 0xE7F511CC, 0xD2051B00, 0x735ABA00, + 0x2AB722D8, 0x386381CB, 0xACF6243A, 0x69BEFD7A, + 0xE6A2E77F, 0xF0C720CD, 0xC4494816, 0xCCF5C180, + 0x38851640, 0x15B0A848, 0xE68B18CB, 0x4CAADEFF, + 0x5F480A01, 0x0412B2AA, 0x259814FC, 0x41D0EFE2, + 0x4E40B48D, 0x248EB6FB, 0x8DBA1CFE, 0x41A99B02, + 0x1A550A04, 0xBA8F65CB, 0x7251F4E7, 0x95A51725, + 0xC106ECD7, 0x97A5980A, 0xC539B9AA, 0x4D79FE6A, + 0xF2F3F763, 0x68AF8040, 0xED0C9E56, 0x11B4958B, + 0xE1EB5A88, 0x8709E6B0, 0xD7E07156, 0x4E29FEA7, + 0x6366E52D, 0x02D1C000, 0xC4AC8E05, 0x9377F571, + 0x0C05372A, 0x578535F2, 0x2261BE02, 0xD642A0C9, + 0xDF13A280, 0x74B55BD2, 0x682199C0, 0xD421E5EC, + 0x53FB3CE8, 0xC8ADEDB3, 0x28A87FC9, 0x3D959981, + 0x5C1FF900, 0xFE38D399, 0x0C4EFF0B, 0x062407EA, + 0xAA2F4FB1, 0x4FB96976, 0x90C79505, 0xB0A8A774, + 0xEF55A1FF, 0xE59CA2C2, 0xA6B62D27, 0xE66A4263, + 0xDF65001F, 0x0EC50966, 0xDFDD55BC, 0x29DE0655, + 0x911E739A, 0x17AF8975, 0x32C7911C, 0x89F89468, + 0x0D01E980, 0x524755F4, 0x03B63CC9, 0x0CC844B2, + 0xBCF3F0AA, 0x87AC36E9, 0xE53A7426, 0x01B3D82B, + 0x1A9E7449, 0x64EE2D7E, 0xCDDBB1DA, 0x01C94910, + 0xB868BF80, 0x0D26F3FD, 0x9342EDE7, 0x04A5C284, + 0x636737B6, 0x50F5B616, 0xF24766E3, 0x8ECA36C1, + 0x136E05DB, 0xFEF18391, 0xFB887A37, 0xD6E7F7D4, + 0xC7FB7DC9, 0x3063FCDF, 0xB6F589DE, 0xEC2941DA, + 0x26E46695, 0xB7566419, 0xF654EFC5, 0xD08D58B7, + 0x48925401, 0xC1BACB7F, 0xE5FF550F, 0xB6083049, + 0x5BB5D0E8, 0x87D72E5A, 0xAB6A6EE1, 0x223A66CE, + 0xC62BF3CD, 0x9E0885F9, 0x68CB3E47, 0x086C010F, + 0xA21DE820, 0xD18B69DE, 0xF3F65777, 0xFA02C3F6, + 0x407EDAC3, 0xCBB3D550, 0x1793084D, 0xB0D70EBA, + 0x0AB378D5, 0xD951FB0C, 0xDED7DA56, 0x4124BBE4, + 0x94CA0B56, 0x0F5755D1, 0xE0E1E56E, 0x6184B5BE, + 0x580A249F, 0x94F74BC0, 0xE327888E, 0x9F7B5561, + 0xC3DC0280, 0x05687715, 0x646C6BD7, 0x44904DB3, + 0x66B4F0A3, 0xC0F1648A, 0x697ED5AF, 0x49E92FF6, + 0x309E374F, 0x2CB6356A, 0x85808573, 0x4991F840, + 0x76F0AE02, 0x083BE84D, 0x28421C9A, 0x44489406, + 0x736E4CB8, 0xC1092910, 0x8BC95FC6, 0x7D869CF4, + 0x134F616F, 0x2E77118D, 0xB31B2BE1, 0xAA90B472, + 0x3CA5D717, 0x7D161BBA, 0x9CAD9010, 0xAF462BA2, + 0x9FE459D2, 0x45D34559, 0xD9F2DA13, 0xDBC65487, + 0xF3E4F94E, 0x176D486F, 0x097C13EA, 0x631DA5C7, + 0x445F7382, 0x175683F4, 0xCDC66A97, 0x70BE0288, + 0xB3CDCF72, 0x6E5DD2F3, 0x20936079, 0x459B80A5, + 0xBE60E2DB, 0xA9C23101, 0xEBA5315C, 0x224E42F2, + 0x1C5C1572, 0xF6721B2C, 0x1AD2FFF3, 0x8C25404E, + 0x324ED72F, 0x4067B7FD, 0x0523138E, 0x5CA3BC78, + 0xDC0FD66E, 0x75922283, 0x784D6B17, 0x58EBB16E, + 0x44094F85, 0x3F481D87, 0xFCFEAE7B, 0x77B5FF76, + 0x8C2302BF, 0xAAF47556, 0x5F46B02A, 0x2B092801, + 0x3D38F5F7, 0x0CA81F36, 0x52AF4A8A, 0x66D5E7C0, + 0xDF3B0874, 0x95055110, 0x1B5AD7A8, 0xF61ED5AD, + 0x6CF6E479, 0x20758184, 0xD0CEFA65, 0x88F7BE58, + 0x4A046826, 0x0FF6F8F3, 0xA09C7F70, 0x5346ABA0, + 0x5CE96C28, 0xE176EDA3, 0x6BAC307F, 0x376829D2, + 0x85360FA9, 0x17E3FE2A, 0x24B79767, 0xF5A96B20, + 0xD6CD2595, 0x68FF1EBF, 0x7555442C, 0xF19F06BE, + 0xF9E0659A, 0xEEB9491D, 0x34010718, 0xBB30CAB8, + 0xE822FE15, 0x88570983, 0x750E6249, 0xDA627E55, + 0x5E76FFA8, 0xB1534546, 0x6D47DE08, 0xEFE9E7D4 +}; + +static const u_int32_t cast_sbox6[256] = { + 0xF6FA8F9D, 0x2CAC6CE1, 0x4CA34867, 0xE2337F7C, + 0x95DB08E7, 0x016843B4, 0xECED5CBC, 0x325553AC, + 0xBF9F0960, 0xDFA1E2ED, 0x83F0579D, 0x63ED86B9, + 0x1AB6A6B8, 0xDE5EBE39, 0xF38FF732, 0x8989B138, + 0x33F14961, 0xC01937BD, 0xF506C6DA, 0xE4625E7E, + 0xA308EA99, 0x4E23E33C, 0x79CBD7CC, 0x48A14367, + 0xA3149619, 0xFEC94BD5, 0xA114174A, 0xEAA01866, + 0xA084DB2D, 0x09A8486F, 0xA888614A, 0x2900AF98, + 0x01665991, 0xE1992863, 0xC8F30C60, 0x2E78EF3C, + 0xD0D51932, 0xCF0FEC14, 0xF7CA07D2, 0xD0A82072, + 0xFD41197E, 0x9305A6B0, 0xE86BE3DA, 0x74BED3CD, + 0x372DA53C, 0x4C7F4448, 0xDAB5D440, 0x6DBA0EC3, + 0x083919A7, 0x9FBAEED9, 0x49DBCFB0, 0x4E670C53, + 0x5C3D9C01, 0x64BDB941, 0x2C0E636A, 0xBA7DD9CD, + 0xEA6F7388, 0xE70BC762, 0x35F29ADB, 0x5C4CDD8D, + 0xF0D48D8C, 0xB88153E2, 0x08A19866, 0x1AE2EAC8, + 0x284CAF89, 0xAA928223, 0x9334BE53, 0x3B3A21BF, + 0x16434BE3, 0x9AEA3906, 0xEFE8C36E, 0xF890CDD9, + 0x80226DAE, 0xC340A4A3, 0xDF7E9C09, 0xA694A807, + 0x5B7C5ECC, 0x221DB3A6, 0x9A69A02F, 0x68818A54, + 0xCEB2296F, 0x53C0843A, 0xFE893655, 0x25BFE68A, + 0xB4628ABC, 0xCF222EBF, 0x25AC6F48, 0xA9A99387, + 0x53BDDB65, 0xE76FFBE7, 0xE967FD78, 0x0BA93563, + 0x8E342BC1, 0xE8A11BE9, 0x4980740D, 0xC8087DFC, + 0x8DE4BF99, 0xA11101A0, 0x7FD37975, 0xDA5A26C0, + 0xE81F994F, 0x9528CD89, 0xFD339FED, 0xB87834BF, + 0x5F04456D, 0x22258698, 0xC9C4C83B, 0x2DC156BE, + 0x4F628DAA, 0x57F55EC5, 0xE2220ABE, 0xD2916EBF, + 0x4EC75B95, 0x24F2C3C0, 0x42D15D99, 0xCD0D7FA0, + 0x7B6E27FF, 0xA8DC8AF0, 0x7345C106, 0xF41E232F, + 0x35162386, 0xE6EA8926, 0x3333B094, 0x157EC6F2, + 0x372B74AF, 0x692573E4, 0xE9A9D848, 0xF3160289, + 0x3A62EF1D, 0xA787E238, 0xF3A5F676, 0x74364853, + 0x20951063, 0x4576698D, 0xB6FAD407, 0x592AF950, + 0x36F73523, 0x4CFB6E87, 0x7DA4CEC0, 0x6C152DAA, + 0xCB0396A8, 0xC50DFE5D, 0xFCD707AB, 0x0921C42F, + 0x89DFF0BB, 0x5FE2BE78, 0x448F4F33, 0x754613C9, + 0x2B05D08D, 0x48B9D585, 0xDC049441, 0xC8098F9B, + 0x7DEDE786, 0xC39A3373, 0x42410005, 0x6A091751, + 0x0EF3C8A6, 0x890072D6, 0x28207682, 0xA9A9F7BE, + 0xBF32679D, 0xD45B5B75, 0xB353FD00, 0xCBB0E358, + 0x830F220A, 0x1F8FB214, 0xD372CF08, 0xCC3C4A13, + 0x8CF63166, 0x061C87BE, 0x88C98F88, 0x6062E397, + 0x47CF8E7A, 0xB6C85283, 0x3CC2ACFB, 0x3FC06976, + 0x4E8F0252, 0x64D8314D, 0xDA3870E3, 0x1E665459, + 0xC10908F0, 0x513021A5, 0x6C5B68B7, 0x822F8AA0, + 0x3007CD3E, 0x74719EEF, 0xDC872681, 0x073340D4, + 0x7E432FD9, 0x0C5EC241, 0x8809286C, 0xF592D891, + 0x08A930F6, 0x957EF305, 0xB7FBFFBD, 0xC266E96F, + 0x6FE4AC98, 0xB173ECC0, 0xBC60B42A, 0x953498DA, + 0xFBA1AE12, 0x2D4BD736, 0x0F25FAAB, 0xA4F3FCEB, + 0xE2969123, 0x257F0C3D, 0x9348AF49, 0x361400BC, + 0xE8816F4A, 0x3814F200, 0xA3F94043, 0x9C7A54C2, + 0xBC704F57, 0xDA41E7F9, 0xC25AD33A, 0x54F4A084, + 0xB17F5505, 0x59357CBE, 0xEDBD15C8, 0x7F97C5AB, + 0xBA5AC7B5, 0xB6F6DEAF, 0x3A479C3A, 0x5302DA25, + 0x653D7E6A, 0x54268D49, 0x51A477EA, 0x5017D55B, + 0xD7D25D88, 0x44136C76, 0x0404A8C8, 0xB8E5A121, + 0xB81A928A, 0x60ED5869, 0x97C55B96, 0xEAEC991B, + 0x29935913, 0x01FDB7F1, 0x088E8DFA, 0x9AB6F6F5, + 0x3B4CBF9F, 0x4A5DE3AB, 0xE6051D35, 0xA0E1D855, + 0xD36B4CF1, 0xF544EDEB, 0xB0E93524, 0xBEBB8FBD, + 0xA2D762CF, 0x49C92F54, 0x38B5F331, 0x7128A454, + 0x48392905, 0xA65B1DB8, 0x851C97BD, 0xD675CF2F +}; + +static const u_int32_t cast_sbox7[256] = { + 0x85E04019, 0x332BF567, 0x662DBFFF, 0xCFC65693, + 0x2A8D7F6F, 0xAB9BC912, 0xDE6008A1, 0x2028DA1F, + 0x0227BCE7, 0x4D642916, 0x18FAC300, 0x50F18B82, + 0x2CB2CB11, 0xB232E75C, 0x4B3695F2, 0xB28707DE, + 0xA05FBCF6, 0xCD4181E9, 0xE150210C, 0xE24EF1BD, + 0xB168C381, 0xFDE4E789, 0x5C79B0D8, 0x1E8BFD43, + 0x4D495001, 0x38BE4341, 0x913CEE1D, 0x92A79C3F, + 0x089766BE, 0xBAEEADF4, 0x1286BECF, 0xB6EACB19, + 0x2660C200, 0x7565BDE4, 0x64241F7A, 0x8248DCA9, + 0xC3B3AD66, 0x28136086, 0x0BD8DFA8, 0x356D1CF2, + 0x107789BE, 0xB3B2E9CE, 0x0502AA8F, 0x0BC0351E, + 0x166BF52A, 0xEB12FF82, 0xE3486911, 0xD34D7516, + 0x4E7B3AFF, 0x5F43671B, 0x9CF6E037, 0x4981AC83, + 0x334266CE, 0x8C9341B7, 0xD0D854C0, 0xCB3A6C88, + 0x47BC2829, 0x4725BA37, 0xA66AD22B, 0x7AD61F1E, + 0x0C5CBAFA, 0x4437F107, 0xB6E79962, 0x42D2D816, + 0x0A961288, 0xE1A5C06E, 0x13749E67, 0x72FC081A, + 0xB1D139F7, 0xF9583745, 0xCF19DF58, 0xBEC3F756, + 0xC06EBA30, 0x07211B24, 0x45C28829, 0xC95E317F, + 0xBC8EC511, 0x38BC46E9, 0xC6E6FA14, 0xBAE8584A, + 0xAD4EBC46, 0x468F508B, 0x7829435F, 0xF124183B, + 0x821DBA9F, 0xAFF60FF4, 0xEA2C4E6D, 0x16E39264, + 0x92544A8B, 0x009B4FC3, 0xABA68CED, 0x9AC96F78, + 0x06A5B79A, 0xB2856E6E, 0x1AEC3CA9, 0xBE838688, + 0x0E0804E9, 0x55F1BE56, 0xE7E5363B, 0xB3A1F25D, + 0xF7DEBB85, 0x61FE033C, 0x16746233, 0x3C034C28, + 0xDA6D0C74, 0x79AAC56C, 0x3CE4E1AD, 0x51F0C802, + 0x98F8F35A, 0x1626A49F, 0xEED82B29, 0x1D382FE3, + 0x0C4FB99A, 0xBB325778, 0x3EC6D97B, 0x6E77A6A9, + 0xCB658B5C, 0xD45230C7, 0x2BD1408B, 0x60C03EB7, + 0xB9068D78, 0xA33754F4, 0xF430C87D, 0xC8A71302, + 0xB96D8C32, 0xEBD4E7BE, 0xBE8B9D2D, 0x7979FB06, + 0xE7225308, 0x8B75CF77, 0x11EF8DA4, 0xE083C858, + 0x8D6B786F, 0x5A6317A6, 0xFA5CF7A0, 0x5DDA0033, + 0xF28EBFB0, 0xF5B9C310, 0xA0EAC280, 0x08B9767A, + 0xA3D9D2B0, 0x79D34217, 0x021A718D, 0x9AC6336A, + 0x2711FD60, 0x438050E3, 0x069908A8, 0x3D7FEDC4, + 0x826D2BEF, 0x4EEB8476, 0x488DCF25, 0x36C9D566, + 0x28E74E41, 0xC2610ACA, 0x3D49A9CF, 0xBAE3B9DF, + 0xB65F8DE6, 0x92AEAF64, 0x3AC7D5E6, 0x9EA80509, + 0xF22B017D, 0xA4173F70, 0xDD1E16C3, 0x15E0D7F9, + 0x50B1B887, 0x2B9F4FD5, 0x625ABA82, 0x6A017962, + 0x2EC01B9C, 0x15488AA9, 0xD716E740, 0x40055A2C, + 0x93D29A22, 0xE32DBF9A, 0x058745B9, 0x3453DC1E, + 0xD699296E, 0x496CFF6F, 0x1C9F4986, 0xDFE2ED07, + 0xB87242D1, 0x19DE7EAE, 0x053E561A, 0x15AD6F8C, + 0x66626C1C, 0x7154C24C, 0xEA082B2A, 0x93EB2939, + 0x17DCB0F0, 0x58D4F2AE, 0x9EA294FB, 0x52CF564C, + 0x9883FE66, 0x2EC40581, 0x763953C3, 0x01D6692E, + 0xD3A0C108, 0xA1E7160E, 0xE4F2DFA6, 0x693ED285, + 0x74904698, 0x4C2B0EDD, 0x4F757656, 0x5D393378, + 0xA132234F, 0x3D321C5D, 0xC3F5E194, 0x4B269301, + 0xC79F022F, 0x3C997E7E, 0x5E4F9504, 0x3FFAFBBD, + 0x76F7AD0E, 0x296693F4, 0x3D1FCE6F, 0xC61E45BE, + 0xD3B5AB34, 0xF72BF9B7, 0x1B0434C0, 0x4E72B567, + 0x5592A33D, 0xB5229301, 0xCFD2A87F, 0x60AEB767, + 0x1814386B, 0x30BCC33D, 0x38A0C07D, 0xFD1606F2, + 0xC363519B, 0x589DD390, 0x5479F8E6, 0x1CB8D647, + 0x97FD61A9, 0xEA7759F4, 0x2D57539D, 0x569A58CF, + 0xE84E63AD, 0x462E1B78, 0x6580F87E, 0xF3817914, + 0x91DA55F4, 0x40A230F3, 0xD1988F35, 0xB6E318D2, + 0x3FFA50BC, 0x3D40F021, 0xC3C0BDAE, 0x4958C24C, + 0x518F36B2, 0x84B1D370, 0x0FEDCE83, 0x878DDADA, + 0xF2A279C7, 0x94E01BE8, 0x90716F4B, 0x954B8AA3 +}; + +static const u_int32_t cast_sbox8[256] = { + 0xE216300D, 0xBBDDFFFC, 0xA7EBDABD, 0x35648095, + 0x7789F8B7, 0xE6C1121B, 0x0E241600, 0x052CE8B5, + 0x11A9CFB0, 0xE5952F11, 0xECE7990A, 0x9386D174, + 0x2A42931C, 0x76E38111, 0xB12DEF3A, 0x37DDDDFC, + 0xDE9ADEB1, 0x0A0CC32C, 0xBE197029, 0x84A00940, + 0xBB243A0F, 0xB4D137CF, 0xB44E79F0, 0x049EEDFD, + 0x0B15A15D, 0x480D3168, 0x8BBBDE5A, 0x669DED42, + 0xC7ECE831, 0x3F8F95E7, 0x72DF191B, 0x7580330D, + 0x94074251, 0x5C7DCDFA, 0xABBE6D63, 0xAA402164, + 0xB301D40A, 0x02E7D1CA, 0x53571DAE, 0x7A3182A2, + 0x12A8DDEC, 0xFDAA335D, 0x176F43E8, 0x71FB46D4, + 0x38129022, 0xCE949AD4, 0xB84769AD, 0x965BD862, + 0x82F3D055, 0x66FB9767, 0x15B80B4E, 0x1D5B47A0, + 0x4CFDE06F, 0xC28EC4B8, 0x57E8726E, 0x647A78FC, + 0x99865D44, 0x608BD593, 0x6C200E03, 0x39DC5FF6, + 0x5D0B00A3, 0xAE63AFF2, 0x7E8BD632, 0x70108C0C, + 0xBBD35049, 0x2998DF04, 0x980CF42A, 0x9B6DF491, + 0x9E7EDD53, 0x06918548, 0x58CB7E07, 0x3B74EF2E, + 0x522FFFB1, 0xD24708CC, 0x1C7E27CD, 0xA4EB215B, + 0x3CF1D2E2, 0x19B47A38, 0x424F7618, 0x35856039, + 0x9D17DEE7, 0x27EB35E6, 0xC9AFF67B, 0x36BAF5B8, + 0x09C467CD, 0xC18910B1, 0xE11DBF7B, 0x06CD1AF8, + 0x7170C608, 0x2D5E3354, 0xD4DE495A, 0x64C6D006, + 0xBCC0C62C, 0x3DD00DB3, 0x708F8F34, 0x77D51B42, + 0x264F620F, 0x24B8D2BF, 0x15C1B79E, 0x46A52564, + 0xF8D7E54E, 0x3E378160, 0x7895CDA5, 0x859C15A5, + 0xE6459788, 0xC37BC75F, 0xDB07BA0C, 0x0676A3AB, + 0x7F229B1E, 0x31842E7B, 0x24259FD7, 0xF8BEF472, + 0x835FFCB8, 0x6DF4C1F2, 0x96F5B195, 0xFD0AF0FC, + 0xB0FE134C, 0xE2506D3D, 0x4F9B12EA, 0xF215F225, + 0xA223736F, 0x9FB4C428, 0x25D04979, 0x34C713F8, + 0xC4618187, 0xEA7A6E98, 0x7CD16EFC, 0x1436876C, + 0xF1544107, 0xBEDEEE14, 0x56E9AF27, 0xA04AA441, + 0x3CF7C899, 0x92ECBAE6, 0xDD67016D, 0x151682EB, + 0xA842EEDF, 0xFDBA60B4, 0xF1907B75, 0x20E3030F, + 0x24D8C29E, 0xE139673B, 0xEFA63FB8, 0x71873054, + 0xB6F2CF3B, 0x9F326442, 0xCB15A4CC, 0xB01A4504, + 0xF1E47D8D, 0x844A1BE5, 0xBAE7DFDC, 0x42CBDA70, + 0xCD7DAE0A, 0x57E85B7A, 0xD53F5AF6, 0x20CF4D8C, + 0xCEA4D428, 0x79D130A4, 0x3486EBFB, 0x33D3CDDC, + 0x77853B53, 0x37EFFCB5, 0xC5068778, 0xE580B3E6, + 0x4E68B8F4, 0xC5C8B37E, 0x0D809EA2, 0x398FEB7C, + 0x132A4F94, 0x43B7950E, 0x2FEE7D1C, 0x223613BD, + 0xDD06CAA2, 0x37DF932B, 0xC4248289, 0xACF3EBC3, + 0x5715F6B7, 0xEF3478DD, 0xF267616F, 0xC148CBE4, + 0x9052815E, 0x5E410FAB, 0xB48A2465, 0x2EDA7FA4, + 0xE87B40E4, 0xE98EA084, 0x5889E9E1, 0xEFD390FC, + 0xDD07D35B, 0xDB485694, 0x38D7E5B2, 0x57720101, + 0x730EDEBC, 0x5B643113, 0x94917E4F, 0x503C2FBA, + 0x646F1282, 0x7523D24A, 0xE0779695, 0xF9C17A8F, + 0x7A5B2121, 0xD187B896, 0x29263A4D, 0xBA510CDF, + 0x81F47C9F, 0xAD1163ED, 0xEA7B5965, 0x1A00726E, + 0x11403092, 0x00DA6D77, 0x4A0CDD61, 0xAD1F4603, + 0x605BDFB0, 0x9EEDC364, 0x22EBE6A8, 0xCEE7D28A, + 0xA0E736A0, 0x5564A6B9, 0x10853209, 0xC7EB8F37, + 0x2DE705CA, 0x8951570F, 0xDF09822B, 0xBD691A6C, + 0xAA12E4F2, 0x87451C0F, 0xE0F6A27A, 0x3ADA4819, + 0x4CF1764F, 0x0D771C2B, 0x67CDB156, 0x350D8384, + 0x5938FA0F, 0x42399EF3, 0x36997B07, 0x0E84093D, + 0x4AA93E61, 0x8360D87B, 0x1FA98B0C, 0x1149382C, + 0xE97625A5, 0x0614D1B7, 0x0E25244B, 0x0C768347, + 0x589E8D82, 0x0D2059D1, 0xA466BB1E, 0xF8DA0A82, + 0x04F19130, 0xBA6E4EC0, 0x99265164, 0x1EE7230D, + 0x50B2AD80, 0xEAEE6801, 0x8DB2A283, 0xEA8BF59E +}; + +/* Macros to access 8-bit bytes out of a 32-bit word */ +#define U8a(x) ( (u_int8_t) (x>>24) ) +#define U8b(x) ( (u_int8_t) ((x>>16)&255) ) +#define U8c(x) ( (u_int8_t) ((x>>8)&255) ) +#define U8d(x) ( (u_int8_t) ((x)&255) ) + +/* Circular left shift */ +#define ROL(x, n) ( ((x)<<(n)) | ((x)>>(32-(n))) ) + +/* CAST-128 uses three different round functions */ +#define F1(l, r, i) \ + t = ROL(key->xkey[i] + r, key->xkey[i+16]); \ + l ^= ((cast_sbox1[U8a(t)] ^ cast_sbox2[U8b(t)]) - \ + cast_sbox3[U8c(t)]) + cast_sbox4[U8d(t)]; +#define F2(l, r, i) \ + t = ROL(key->xkey[i] ^ r, key->xkey[i+16]); \ + l ^= ((cast_sbox1[U8a(t)] - cast_sbox2[U8b(t)]) + \ + cast_sbox3[U8c(t)]) ^ cast_sbox4[U8d(t)]; +#define F3(l, r, i) \ + t = ROL(key->xkey[i] - r, key->xkey[i+16]); \ + l ^= ((cast_sbox1[U8a(t)] + cast_sbox2[U8b(t)]) ^ \ + cast_sbox3[U8c(t)]) - cast_sbox4[U8d(t)]; + + +/***** Encryption Function *****/ + +void cast_encrypt(cast_key* key, u_int8_t* inblock, u_int8_t* outblock) +{ +u_int32_t t, l, r; + + /* Get inblock into l,r */ + l = ((u_int32_t)inblock[0] << 24) | ((u_int32_t)inblock[1] << 16) | + ((u_int32_t)inblock[2] << 8) | (u_int32_t)inblock[3]; + r = ((u_int32_t)inblock[4] << 24) | ((u_int32_t)inblock[5] << 16) | + ((u_int32_t)inblock[6] << 8) | (u_int32_t)inblock[7]; + /* Do the work */ + F1(l, r, 0); + F2(r, l, 1); + F3(l, r, 2); + F1(r, l, 3); + F2(l, r, 4); + F3(r, l, 5); + F1(l, r, 6); + F2(r, l, 7); + F3(l, r, 8); + F1(r, l, 9); + F2(l, r, 10); + F3(r, l, 11); + /* Only do full 16 rounds if key length > 80 bits */ + if (key->rounds > 12) { + F1(l, r, 12); + F2(r, l, 13); + F3(l, r, 14); + F1(r, l, 15); + } + /* Put l,r into outblock */ + outblock[0] = U8a(r); + outblock[1] = U8b(r); + outblock[2] = U8c(r); + outblock[3] = U8d(r); + outblock[4] = U8a(l); + outblock[5] = U8b(l); + outblock[6] = U8c(l); + outblock[7] = U8d(l); + /* Wipe clean */ + t = l = r = 0; +} + + +/***** Decryption Function *****/ + +void cast_decrypt(cast_key* key, u_int8_t* inblock, u_int8_t* outblock) +{ +u_int32_t t, l, r; + + /* Get inblock into l,r */ + r = ((u_int32_t)inblock[0] << 24) | ((u_int32_t)inblock[1] << 16) | + ((u_int32_t)inblock[2] << 8) | (u_int32_t)inblock[3]; + l = ((u_int32_t)inblock[4] << 24) | ((u_int32_t)inblock[5] << 16) | + ((u_int32_t)inblock[6] << 8) | (u_int32_t)inblock[7]; + /* Do the work */ + /* Only do full 16 rounds if key length > 80 bits */ + if (key->rounds > 12) { + F1(r, l, 15); + F3(l, r, 14); + F2(r, l, 13); + F1(l, r, 12); + } + F3(r, l, 11); + F2(l, r, 10); + F1(r, l, 9); + F3(l, r, 8); + F2(r, l, 7); + F1(l, r, 6); + F3(r, l, 5); + F2(l, r, 4); + F1(r, l, 3); + F3(l, r, 2); + F2(r, l, 1); + F1(l, r, 0); + /* Put l,r into outblock */ + outblock[0] = U8a(l); + outblock[1] = U8b(l); + outblock[2] = U8c(l); + outblock[3] = U8d(l); + outblock[4] = U8a(r); + outblock[5] = U8b(r); + outblock[6] = U8c(r); + outblock[7] = U8d(r); + /* Wipe clean */ + t = l = r = 0; +} + + +/***** Key Schedual *****/ + +void cast_setkey(cast_key* key, u_int8_t* rawkey, int keybytes) +{ +u_int32_t t[4], z[4], x[4]; +int i; + + /* Set number of rounds to 12 or 16, depending on key length */ + key->rounds = (keybytes <= 10 ? 12 : 16); + + /* Copy key to workspace x */ + for (i = 0; i < 4; i++) { + x[i] = 0; + if ((i*4+0) < keybytes) x[i] = (u_int32_t)rawkey[i*4+0] << 24; + if ((i*4+1) < keybytes) x[i] |= (u_int32_t)rawkey[i*4+1] << 16; + if ((i*4+2) < keybytes) x[i] |= (u_int32_t)rawkey[i*4+2] << 8; + if ((i*4+3) < keybytes) x[i] |= (u_int32_t)rawkey[i*4+3]; + } + /* Generate 32 subkeys, four at a time */ + for (i = 0; i < 32; i+=4) { + switch (i & 4) { + case 0: + t[0] = z[0] = x[0] ^ cast_sbox5[U8b(x[3])] ^ + cast_sbox6[U8d(x[3])] ^ cast_sbox7[U8a(x[3])] ^ + cast_sbox8[U8c(x[3])] ^ cast_sbox7[U8a(x[2])]; + t[1] = z[1] = x[2] ^ cast_sbox5[U8a(z[0])] ^ + cast_sbox6[U8c(z[0])] ^ cast_sbox7[U8b(z[0])] ^ + cast_sbox8[U8d(z[0])] ^ cast_sbox8[U8c(x[2])]; + t[2] = z[2] = x[3] ^ cast_sbox5[U8d(z[1])] ^ + cast_sbox6[U8c(z[1])] ^ cast_sbox7[U8b(z[1])] ^ + cast_sbox8[U8a(z[1])] ^ cast_sbox5[U8b(x[2])]; + t[3] = z[3] = x[1] ^ cast_sbox5[U8c(z[2])] ^ + cast_sbox6[U8b(z[2])] ^ cast_sbox7[U8d(z[2])] ^ + cast_sbox8[U8a(z[2])] ^ cast_sbox6[U8d(x[2])]; + break; + case 4: + t[0] = x[0] = z[2] ^ cast_sbox5[U8b(z[1])] ^ + cast_sbox6[U8d(z[1])] ^ cast_sbox7[U8a(z[1])] ^ + cast_sbox8[U8c(z[1])] ^ cast_sbox7[U8a(z[0])]; + t[1] = x[1] = z[0] ^ cast_sbox5[U8a(x[0])] ^ + cast_sbox6[U8c(x[0])] ^ cast_sbox7[U8b(x[0])] ^ + cast_sbox8[U8d(x[0])] ^ cast_sbox8[U8c(z[0])]; + t[2] = x[2] = z[1] ^ cast_sbox5[U8d(x[1])] ^ + cast_sbox6[U8c(x[1])] ^ cast_sbox7[U8b(x[1])] ^ + cast_sbox8[U8a(x[1])] ^ cast_sbox5[U8b(z[0])]; + t[3] = x[3] = z[3] ^ cast_sbox5[U8c(x[2])] ^ + cast_sbox6[U8b(x[2])] ^ cast_sbox7[U8d(x[2])] ^ + cast_sbox8[U8a(x[2])] ^ cast_sbox6[U8d(z[0])]; + break; + } + switch (i & 12) { + case 0: + case 12: + key->xkey[i+0] = cast_sbox5[U8a(t[2])] ^ cast_sbox6[U8b(t[2])] ^ + cast_sbox7[U8d(t[1])] ^ cast_sbox8[U8c(t[1])]; + key->xkey[i+1] = cast_sbox5[U8c(t[2])] ^ cast_sbox6[U8d(t[2])] ^ + cast_sbox7[U8b(t[1])] ^ cast_sbox8[U8a(t[1])]; + key->xkey[i+2] = cast_sbox5[U8a(t[3])] ^ cast_sbox6[U8b(t[3])] ^ + cast_sbox7[U8d(t[0])] ^ cast_sbox8[U8c(t[0])]; + key->xkey[i+3] = cast_sbox5[U8c(t[3])] ^ cast_sbox6[U8d(t[3])] ^ + cast_sbox7[U8b(t[0])] ^ cast_sbox8[U8a(t[0])]; + break; + case 4: + case 8: + key->xkey[i+0] = cast_sbox5[U8d(t[0])] ^ cast_sbox6[U8c(t[0])] ^ + cast_sbox7[U8a(t[3])] ^ cast_sbox8[U8b(t[3])]; + key->xkey[i+1] = cast_sbox5[U8b(t[0])] ^ cast_sbox6[U8a(t[0])] ^ + cast_sbox7[U8c(t[3])] ^ cast_sbox8[U8d(t[3])]; + key->xkey[i+2] = cast_sbox5[U8d(t[1])] ^ cast_sbox6[U8c(t[1])] ^ + cast_sbox7[U8a(t[2])] ^ cast_sbox8[U8b(t[2])]; + key->xkey[i+3] = cast_sbox5[U8b(t[1])] ^ cast_sbox6[U8a(t[1])] ^ + cast_sbox7[U8c(t[2])] ^ cast_sbox8[U8d(t[2])]; + break; + } + switch (i & 12) { + case 0: + key->xkey[i+0] ^= cast_sbox5[U8c(z[0])]; + key->xkey[i+1] ^= cast_sbox6[U8c(z[1])]; + key->xkey[i+2] ^= cast_sbox7[U8b(z[2])]; + key->xkey[i+3] ^= cast_sbox8[U8a(z[3])]; + break; + case 4: + key->xkey[i+0] ^= cast_sbox5[U8a(x[2])]; + key->xkey[i+1] ^= cast_sbox6[U8b(x[3])]; + key->xkey[i+2] ^= cast_sbox7[U8d(x[0])]; + key->xkey[i+3] ^= cast_sbox8[U8d(x[1])]; + break; + case 8: + key->xkey[i+0] ^= cast_sbox5[U8b(z[2])]; + key->xkey[i+1] ^= cast_sbox6[U8a(z[3])]; + key->xkey[i+2] ^= cast_sbox7[U8c(z[0])]; + key->xkey[i+3] ^= cast_sbox8[U8c(z[1])]; + break; + case 12: + key->xkey[i+0] ^= cast_sbox5[U8d(x[0])]; + key->xkey[i+1] ^= cast_sbox6[U8d(x[1])]; + key->xkey[i+2] ^= cast_sbox7[U8a(x[2])]; + key->xkey[i+3] ^= cast_sbox8[U8b(x[3])]; + break; + } + if (i >= 16) { + key->xkey[i+0] &= 31; + key->xkey[i+1] &= 31; + key->xkey[i+2] &= 31; + key->xkey[i+3] &= 31; + } + } + /* Wipe clean */ + for (i = 0; i < 4; i++) { + t[i] = x[i] = z[i] = 0; + } +} + +/* Made in Canada */ diff --git a/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/md5.c b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/md5.c new file mode 100644 index 0000000..8a7a483 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/md5.c @@ -0,0 +1,392 @@ +/* $OpenBSD: md5.c,v 1.3 2002/06/14 21:34:58 todd Exp $ */ + +/* + * The rest of the code is derived from MD5C.C by RSADSI. Minor cosmetic + * changes to accommodate it in the kernel by ji. + */ + +/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +/* + * Additions by JI + * + * HAVEMEMCOPY is defined if mem* routines are available + * + * HAVEHTON is defined if htons() and htonl() can be used + * for big/little endian conversions + * + */ + +#include <stddef.h> +#include <string.h> + +#include "md5.h" + +#ifndef WIN32 +#include "endian.h" /* sets BYTE_ORDER, LITTLE_ENDIAN, and BIG_ENDIAN */ +#endif + +#define HAVEMEMCOPY 1 /* use ISO C's memcpy and memset */ + +/* Constants for MD5Transform routine. + */ + +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +#define MD5Transform _MD5Transform + +static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64])); + +#if BYTE_ORDER == LITTLE_ENDIAN +#define Encode MD5_memcpy +#define Decode MD5_memcpy +#else +static void Encode PROTO_LIST + ((unsigned char *, UINT4 *, unsigned int)); +static void Decode PROTO_LIST + ((UINT4 *, unsigned char *, unsigned int)); +#endif + +#ifdef HAVEMEMCOPY +#include <memory.h> +#define MD5_memcpy memcpy +#define MD5_memset memset +#else +#ifdef HAVEBCOPY +#define MD5_memcpy(_a,_b,_c) memcpy((_a), (_b),(_c)) +#define MD5_memset(_a,_b,_c) memset((_a), '\0',(_c)) +#else +static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int)); +static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int)); +#endif +#endif +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/* MD5 initialization. Begins an MD5 operation, writing a new context. + */ +void MD5Init (context) +MD5_CTX *context; /* context */ +{ + context->count[0] = context->count[1] = 0; + /* Load magic initialization constants. +*/ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the + context. + */ +void MD5Update (context, input, inputLen) +MD5_CTX *context; /* context */ +unsigned char *input; /* input block */ +unsigned int inputLen; /* length of input block */ +{ + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((UINT4)inputLen << 3)) + < ((UINT4)inputLen << 3)) + context->count[1]++; + context->count[1] += ((UINT4)inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible. +*/ + if (inputLen >= partLen) { + MD5_memcpy + ((POINTER)&context->buffer[index], (POINTER)input, partLen); + MD5Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform (context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + MD5_memcpy + ((POINTER)&context->buffer[index], (POINTER)&input[i], + inputLen-i); +} + +/* MD5 finalization. Ends an MD5 message-digest operation, writing the + the message digest and zeroizing the context. + */ +void MD5Final (digest, context) +unsigned char digest[16]; /* message digest */ +MD5_CTX *context; /* context */ +{ + unsigned char bits[8]; + unsigned int index, padLen; + + /* Save number of bits */ + Encode (bits, context->count, 8); + + /* Pad out to 56 mod 64. +*/ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update (context, PADDING, padLen); + + /* Append length (before padding) */ + MD5Update (context, bits, 8); + + if (digest != NULL) /* Bill Simpson's padding */ + { + /* store state in digest */ + Encode (digest, context->state, 16); + + /* Zeroize sensitive information. + */ + MD5_memset ((POINTER)context, 0, sizeof (*context)); + } +} + +/* MD5 basic transformation. Transforms state based on block. + */ +static void MD5Transform (state, block) +UINT4 state[4]; +unsigned char block[64]; +{ + UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. +*/ + MD5_memset ((POINTER)x, 0, sizeof (x)); +} + +#if BYTE_ORDER != LITTLE_ENDIAN + +/* Encodes input (UINT4) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void Encode (output, input, len) +unsigned char *output; +UINT4 *input; +unsigned int len; +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +/* Decodes input (unsigned char) into output (UINT4). Assumes len is + a multiple of 4. + */ +static void Decode (output, input, len) +UINT4 *output; +unsigned char *input; +unsigned int len; +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | + (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); +} + +#endif + +#ifndef HAVEMEMCOPY +#ifndef HAVEBCOPY +/* Note: Replace "for loop" with standard memcpy if possible. + */ + +static void MD5_memcpy (output, input, len) +POINTER output; +POINTER input; +unsigned int len; +{ + unsigned int i; + + for (i = 0; i < len; i++) + + output[i] = input[i]; +} + +/* Note: Replace "for loop" with standard memset if possible. + */ +static void MD5_memset (output, value, len) +POINTER output; +int value; +unsigned int len; +{ + unsigned int i; + + for (i = 0; i < len; i++) + ((char *)output)[i] = (char)value; +} +#endif +#endif + diff --git a/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/sha1.c b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/sha1.c new file mode 100644 index 0000000..da63563 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/sha1.c @@ -0,0 +1,173 @@ +/* $OpenBSD: sha1.c,v 1.2 2001/01/28 22:38:48 niklas Exp $ */ + +/* +SHA-1 in C +By Steve Reid <steve@edmweb.com> +100% Public Domain + +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */ +/* #define SHA1HANDSOFF * Copies data before messing with it. */ + +#define SHA1HANDSOFF + +#include <string.h> + +#include "sha1.h" +#ifndef WIN32 + #include "endian.h" /* sets BYTE_ORDER, LITTLE_ENDIAN, and BIG_ENDIAN */ +#endif + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#if BYTE_ORDER == LITTLE_ENDIAN +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) +#elif BYTE_ORDER == BIG_ENDIAN +#define blk0(i) block->l[i] +#else +#error "Endianness not defined!" +#endif +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +void SHA1Transform(unsigned long state[5], unsigned char buffer[64]) +{ +unsigned long a, b, c, d, e; +typedef union { + unsigned char c[64]; + unsigned long l[16]; +} CHAR64LONG16; +CHAR64LONG16* block; +#ifdef SHA1HANDSOFF +static CHAR64LONG16 workspace; + block = &workspace; + memcpy(block, buffer, 64); +#else + block = (CHAR64LONG16*)buffer; +#endif + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; +} + + +/* SHA1Init - Initialize new context */ + +void SHA1Init(SHA1_CTX* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ + +void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len) +{ +unsigned int i; +unsigned long j; + + j = context->count[0]; + if ((context->count[0] += len << 3) < j) context->count[1] += (len>>29)+1; + j = (j >> 3) & 63; + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + SHA1Transform(context->state, &data[i]); + } + j = 0; + } + else i = 0; + memcpy(&context->buffer[j], &data[i], len - i); +} + + +/* Add padding and return the message digest. */ + +void SHA1Final(unsigned char digest[20], SHA1_CTX* context) +{ +unsigned long i, j; +unsigned char finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + SHA1Update(context, (unsigned char *)"\200", 1); + while ((context->count[0] & 504) != 448) { + SHA1Update(context, (unsigned char *)"\0", 1); + } + SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ + for (i = 0; i < 20; i++) { + digest[i] = (unsigned char) + ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } + /* Wipe variables */ + i = j = 0; + memset(context->buffer, '\0', 64); + memset(context->state, '\0', 20); + memset(context->count, '\0', 8); + memset(&finalcount, '\0', 8); +#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ + SHA1Transform(context->state, context->buffer); +#endif +} diff --git a/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/strlcat.c b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/strlcat.c new file mode 100644 index 0000000..3b55428 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/strlcat.c @@ -0,0 +1,62 @@ +/* $OpenBSD: strlcat.c,v 1.3 2003/06/17 21:56:24 millert Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: strlcat.c,v 1.3 2003/06/17 21:56:24 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <string.h> + +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(src) + MIN(siz, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +size_t +strlcat(dst, src, siz) + char *dst; + const char *src; + size_t siz; +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} diff --git a/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/strlcpy.c b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/strlcpy.c new file mode 100644 index 0000000..ef7db13 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/common/libsysdep/strlcpy.c @@ -0,0 +1,58 @@ +/* $OpenBSD: strlcpy.c,v 1.3 2003/06/17 21:56:24 millert Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: strlcpy.c,v 1.3 2003/06/17 21:56:24 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <string.h> + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +strlcpy(dst, src, siz) + char *dst; + const char *src; + size_t siz; +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} diff --git a/keyexchange/isakmpd-20041012/sysdep/common/md5.h b/keyexchange/isakmpd-20041012/sysdep/common/md5.h new file mode 100644 index 0000000..ea703c3 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/common/md5.h @@ -0,0 +1,73 @@ +/* $OpenBSD: md5.h,v 1.2 2001/01/28 22:38:47 niklas Exp $ */ + +/* GLOBAL.H - RSAREF types and constants + */ + +/* PROTOTYPES should be set to one if and only if the compiler supports + function argument prototyping. + The following makes PROTOTYPES default to 0 if it has not already + been defined with C compiler flags. + */ +#ifndef PROTOTYPES +#define PROTOTYPES 1 +#endif + +/* POINTER defines a generic pointer type */ +typedef unsigned char *POINTER; + +/* UINT2 defines a two byte word */ +typedef unsigned short int UINT2; + +/* UINT4 defines a four byte word */ +typedef unsigned long int UINT4; + +/* PROTO_LIST is defined depending on how PROTOTYPES is defined above. + If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it + returns an empty list. + */ + +#if PROTOTYPES +#define PROTO_LIST(list) list +#else +#define PROTO_LIST(list) () +#endif + + +/* MD5.H - header file for MD5C.C + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +/* MD5 context. */ +typedef struct { + UINT4 state[4]; /* state (ABCD) */ + UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} MD5_CTX; + +void MD5Init PROTO_LIST ((MD5_CTX *)); +void MD5Update PROTO_LIST + ((MD5_CTX *, unsigned char *, unsigned int)); +void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *)); + +#define _MD5_H_ diff --git a/keyexchange/isakmpd-20041012/sysdep/common/pcap.h b/keyexchange/isakmpd-20041012/sysdep/common/pcap.h new file mode 100644 index 0000000..21117d8 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/common/pcap.h @@ -0,0 +1,69 @@ +/* $OpenBSD: pcap.h,v 1.2 2002/05/10 15:09:00 ho Exp $ */ + +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. 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 the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + * + * @(#) $Header: /cvs/src/sbin/isakmpd/sysdep/common/pcap.h,v 1.2 2002/05/10 15:09:00 ho Exp $ (LBL) + */ + +#ifndef lib_pcap_h +#define lib_pcap_h + +#include <sys/types.h> +#include <sys/time.h> + +#define PCAP_VERSION_MAJOR 2 +#define PCAP_VERSION_MINOR 4 +#define DLT_LOOP 12 /* from /usr/include/net/bpf.h */ + +struct pcap_file_header { + u_int32_t magic; + u_int16_t version_major; + u_int16_t version_minor; + int32_t thiszone; /* gmt to local correction */ + u_int32_t sigfigs; /* accuracy of timestamps */ + u_int32_t snaplen; /* max length saved portion of each pkt */ + u_int32_t linktype; /* data link type (DLT_*) */ +}; + +struct pcap_timeval { + int32_t tv_sec; /* seconds */ + int32_t tv_usec; /* microseconds */ +}; + +struct pcap_pkthdr { + struct pcap_timeval ts; /* time stamp */ + u_int32_t caplen; /* length of portion present */ + u_int32_t len; /* length this packet (off wire) */ +}; + +#endif /* lib_pcap_h */ diff --git a/keyexchange/isakmpd-20041012/sysdep/common/sha1.h b/keyexchange/isakmpd-20041012/sysdep/common/sha1.h new file mode 100644 index 0000000..c706c6e --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/common/sha1.h @@ -0,0 +1,18 @@ +/* $OpenBSD: sha1.h,v 1.2 2001/01/28 22:38:47 niklas Exp $ */ + +/* +SHA-1 in C +By Steve Reid <steve@edmweb.com> +100% Public Domain +*/ + +typedef struct { + unsigned long state[5]; + unsigned long count[2]; + unsigned char buffer[64]; +} SHA1_CTX; + +void SHA1Transform(unsigned long state[5], unsigned char buffer[64]); +void SHA1Init(SHA1_CTX* context); +void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len); +void SHA1Final(unsigned char digest[20], SHA1_CTX* context); diff --git a/keyexchange/isakmpd-20041012/sysdep/darwin/GNUmakefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/darwin/GNUmakefile.sysdep new file mode 100644 index 0000000..09f888d --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/darwin/GNUmakefile.sysdep @@ -0,0 +1,48 @@ +# $OpenBSD: GNUmakefile.sysdep,v 1.3 2004/06/26 03:40:57 mcbride Exp $ + +# +# Copyright (c) 1999,2002 Håkan Olsson. All rights reserved. +# Copyright (c) 1999 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. +# +# 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. +# + +LDADD+= -lipsec + +# gcc under MacOS X does not seem to like building things -static +LDSTATIC= + +CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL +CFLAGS+= -DHAVE_GETIFADDRS + +FEATURES= debug tripledes des blowdish cast ec aggressive x509 +FEATURES+= rawkey isakmp_cfg +# Not yet +#FEATURES+= policy + +IPSEC_SRCS= pf_key_v2.c +IPSEC_CFLAGS= -DUSE_PF_KEY_V2 + +USE_LIBCRYPTO= defined diff --git a/keyexchange/isakmpd-20041012/sysdep/darwin/Makefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/darwin/Makefile.sysdep new file mode 100644 index 0000000..834347d --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/darwin/Makefile.sysdep @@ -0,0 +1,45 @@ +# $OpenBSD: Makefile.sysdep,v 1.3 2004/06/26 03:40:57 mcbride Exp $ + +# +# Copyright (c) 1999 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. +# +# 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 INN 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. +# + +# Override default features +FEATURES= tripledes des blowfish cast x509 ec aggressive debug +FEATURES+= rawkey isakmp_cfg + +LDADD+= -lipsec + +CFLAGS+= -DHAVE_GETIFADDRS -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL + +IPSEC_SRCS= pf_key_v2.c +IPSEC_CFLAGS= -DUSE_PF_KEY_V2 + +USE_LIBCRYPTO= defined + +obj: + mkdir obj diff --git a/keyexchange/isakmpd-20041012/sysdep/darwin/sysdep-os.h b/keyexchange/isakmpd-20041012/sysdep/darwin/sysdep-os.h new file mode 100644 index 0000000..28755bc --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/darwin/sysdep-os.h @@ -0,0 +1,81 @@ +/* $OpenBSD: sysdep-os.h,v 1.3 2003/08/06 11:23:11 markus Exp $ */ + +/* + * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2002 Håkan Olsson. 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. + * + * 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_OS_H_ + +#define _SYSDEP_OS_H_ + +#define KAME + +#include <netinet6/ipsec.h> + +typedef u_int32_t socklen_t; + +#ifndef CPI_RESERVED_MAX +#define CPI_RESERVED_MIN 1 +#define CPI_RESERVED_MAX 255 +#define CPI_PRIVATE_MIN 61440 +#define CPI_PRIVATE_MAX 65536 +#endif + +#if !defined(SADB_X_EALG_CAST) && defined(SADB_X_EALG_CAST128CBC) +#define SADB_X_EALG_CAST SADB_X_EALG_CAST128CBC +#endif + +#if !defined(SADB_X_EALG_BLF) && defined(SADB_X_EALG_BLOWFISHCBC) +#define SADB_X_EALG_BLF SADB_X_EALG_BLOWFISHCBC +#endif + +#if 1 +/* OpenSSL differs from OpenBSD very slightly... */ + +#define MD5Init MD5_Init +#define MD5Update MD5_Update +#define MD5Final MD5_Final + +#define SHA1Init SHA1_Init +#define SHA1Update SHA1_Update +#define SHA1Final SHA1_Final +#define SHA1_CTX SHA_CTX + +#define cast_key CAST_KEY +#define cast_setkey(k, d, l) CAST_set_key ((k), (l), (d)) +#define cast_encrypt(k, i, o) do { \ + memcpy ((o), (i), BLOCKSIZE); \ + CAST_encrypt ((CAST_LONG *)(o), (k)); \ +} while (0) +#define cast_decrypt(k, i, o) do { \ + memcpy ((o), (i), BLOCKSIZE); \ + CAST_decrypt ((CAST_LONG *)(o), (k)); \ +} while (0) +#endif + +#endif /* _SYSDEP_OS_H_ */ diff --git a/keyexchange/isakmpd-20041012/sysdep/darwin/sysdep.c b/keyexchange/isakmpd-20041012/sysdep/darwin/sysdep.c new file mode 100644 index 0000000..cd61d5a --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/darwin/sysdep.c @@ -0,0 +1,223 @@ +/* $OpenBSD: sysdep.c,v 1.3 2004/08/10 15:59:10 ho Exp $ */ + +/* + * Copyright (c) 1998, 1999 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. + * + * 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 <stdlib.h> +#include <string.h> + +#include "sysdep.h" + +#include "util.h" + +#ifdef NEED_SYSDEP_APP +#include "app.h" +#include "conf.h" +#include "ipsec.h" + +#ifdef USE_PF_KEY_V2 +#include "pf_key_v2.h" +#define KEY_API(x) pf_key_v2_##x +#endif + +#endif /* NEED_SYSDEP_APP */ +#include "log.h" + +extern char *__progname; + +/* + * An as strong as possible random number generator, reverting to a + * deterministic pseudo-random one if regrand is set. + */ +u_int32_t +sysdep_random () +{ + return random(); +} + +/* Return the basename of the command used to invoke us. */ +char * +sysdep_progname () +{ + return __progname; +} + +/* Return the length of the sockaddr struct. */ +u_int8_t +sysdep_sa_len (struct sockaddr *sa) +{ + return sa->sa_len; +} + +/* As regress/ use this file I protect the sysdep_app_* stuff like this. */ +#ifdef NEED_SYSDEP_APP +/* + * Prepare the application we negotiate SAs for (i.e. the IPsec stack) + * for communication. We return a file descriptor useable to select(2) on. + */ +int +sysdep_app_open () +{ + return KEY_API(open) (); +} + +/* + * When select(2) has noticed our application needs attendance, this is what + * gets called. FD is the file descriptor causing the alarm. + */ +void +sysdep_app_handler (int fd) +{ + KEY_API (handler) (fd); +} + +/* Check that the connection named NAME is active, or else make it active. */ +void +sysdep_connection_check (char *name) +{ + KEY_API (connection_check) (name); +} + +/* + * Generate a SPI for protocol PROTO and the source/destination pair given by + * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ. + */ +u_int8_t * +sysdep_ipsec_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src, + struct sockaddr *dst, u_int32_t seq) +{ + if (app_none) + { + *sz = IPSEC_SPI_SIZE; + /* XXX should be random instead I think. */ + return strdup ("\x12\x34\x56\x78"); + } + return KEY_API (get_spi) (sz, proto, src, dst, seq); +} + +struct sa_kinfo * +sysdep_ipsec_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto, + struct sockaddr *dst) +{ + if (app_none) + return 0; + /* XXX return KEY_API(get_kernel_sa)(spi, spi_sz, proto, dst); */ + return 0; +} + +/* Force communication on socket FD to go in the clear. */ +int +sysdep_cleartext (int fd, int af) +{ + char *buf; + char *policy[] = { "in bypass", "out bypass", NULL }; + char **p; + int ipp; + + if (app_none) + return 0; + + switch (af) + { + case AF_INET: + ipp = IPPROTO_IP; + break; + case AF_INET6: + ipp = IPPROTO_IPV6; + break; + default: + log_print ("sysdep_cleartext: unsupported protocol family %d", af); + return -1; + } + + /* + * Need to bypass system security policy, so I can send and + * receive key management datagrams in the clear. + */ + + for (p = policy; p && *p; p++) + { + buf = ipsec_set_policy (*p, strlen(*p)); + if (buf == NULL) + { + log_error ("sysdep_cleartext: %s: %s", *p, ipsec_strerror()); + return -1; + } + + if (setsockopt(fd, ipp, IP_IPSEC_POLICY, buf, + ipsec_get_policylen(buf)) < 0) + { + log_error ("sysdep_cleartext: " + "setsockopt (%d, IPPROTO_IP, IP_IPSEC_POLICY, ...) failed", + fd); + return -1; + } + free(buf); + } + + return 0; +} + +int +sysdep_ipsec_delete_spi (struct sa *sa, struct proto *proto, int incoming) +{ + if (app_none) + return 0; + return KEY_API (delete_spi) (sa, proto, incoming); +} + +int +sysdep_ipsec_enable_sa (struct sa *sa, struct sa *isakmp_sa) +{ + if (app_none) + return 0; + return KEY_API (enable_sa) (sa, isakmp_sa); +} + +int +sysdep_ipsec_group_spis (struct sa *sa, struct proto *proto1, + struct proto *proto2, int incoming) +{ + if (app_none) + return 0; + return KEY_API (group_spis) (sa, proto1, proto2, incoming); +} + +int +sysdep_ipsec_set_spi (struct sa *sa, struct proto *proto, int incoming, + struct sa *isakmp_sa) +{ + if (app_none) + return 0; + return KEY_API (set_spi) (sa, proto, incoming, isakmp_sa); +} +#endif diff --git a/keyexchange/isakmpd-20041012/sysdep/freebsd/GNUmakefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/freebsd/GNUmakefile.sysdep new file mode 100644 index 0000000..618ef5f --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/freebsd/GNUmakefile.sysdep @@ -0,0 +1,61 @@ +# $OpenBSD: GNUmakefile.sysdep,v 1.6 2004/06/26 03:40:57 mcbride Exp $ + +# +# Copyright (c) 1999 Håkan Olsson. All rights reserved. +# Copyright (c) 1999 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. +# +# 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. +# + +LIBGMP:= /usr/lib/libgmp.a +LIBCRYPTO:= /usr/lib/libcrypto.a +LIBSYSDEPDIR:= ${.CURDIR}/sysdep/common/libsysdep +LIBSYSDEP:= ${LIBSYSDEPDIR}/libsysdep.a + +LDADD+= -lgmp ${LIBSYSDEP} +DPADD+= ${LIBGMP} ${LIBSYSDEP} + +FEATURES= debug tripledes des blowdish cast ec aggressive +# Not yet +#FEATURES+= policy x509 + +IPSEC_SRCS= pf_key_v2.c +IPSEC_CFLAGS= -DUSE_PF_KEY_V2 + +USE_LIBCRYPTO= defined + +# hack libsysdep.a dependency +${LIBSYSDEPDIR}/.depend ${LIBSYSDEP}: + cd ${LIBSYSDEPDIR} && + ${MAKE} --no-print-directory ${MAKEFLAGS} \ + CFLAGS="${CFLAGS}" MKDEP="${MKDEP}" ${MAKECMDGOALS} + +depend: ${LIBSYSDEPDIR}/.depend + +ifeq ($(findstring clean, $(MAKECMDGOALS)), clean) +SUBDIR+= sysdep/common/libsysdep +MAKEFLAGS+= --no-print-directory +endif + diff --git a/keyexchange/isakmpd-20041012/sysdep/freebsd/Makefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/freebsd/Makefile.sysdep new file mode 100644 index 0000000..03dae50 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/freebsd/Makefile.sysdep @@ -0,0 +1,77 @@ +# $OpenBSD: Makefile.sysdep,v 1.10 2004/06/26 03:40:57 mcbride Exp $ + +# +# Copyright (c) 1999 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. +# +# 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 INN 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. +# + +# Override default features +FEATURES= tripledes des blowfish cast x509 ec aggressive debug +FEATURES+= rawkey +# Not yet +#FEATURES+= policy isakmp_cfg + +.if defined(TOPDIR) +LIBSYSDEPDIR= ${TOPDIR}/sysdep/common/libsysdep +.else +LIBSYSDEPDIR= ${.CURDIR}/sysdep/common/libsysdep +.endif + +LDADD+= -lgmp ${LIBSYSDEPDIR}/libsysdep.a -lipsec -L/usr/local/lib +DPADD+= ${LIBGMP} ${LIBSYSDEPDIR}/libsysdep.a + +CFLAGS+= -DHAVE_GETIFADDRS \ + -I${.CURDIR}/sysdep/common -I/usr/include \ + -I/usr/local/include -I/usr/local/include/openssl + +IPSEC_SRCS= pf_key_v2.c +IPSEC_CFLAGS= -DUSE_PF_KEY_V2 + +USE_LIBCRYPTO= defined + +# This is a hack in order to make sure libsysdep is built before the +# linkstage of isakmpd. As a side effect the link is always done even if +# not necessary. Well, I just don't care. +GENERATED+= sysdep-target +sysdep-target: + cd ${.CURDIR}/sysdep/common/libsysdep; ${MAKE} ${.MAKEFLAGS} + +# Kludge around much strange behaviour in /usr/share/mk/bsd.*/mk, don't build certpatch +SUBDIR= + +.if make(clean) +SUBDIR+= sysdep/common/libsysdep +.endif + +# Kludge around bug in /usr/share/mk/bsd.subdir.mk +NO_REGRESS= defined + +# Kludge around bug/feature in /usr/share/mk/bsd.man.mk +MAN8= isakmpd.8 +MAN5= isakmpd.conf.5 isakmpd.policy.5 + +obj: + mkdir obj diff --git a/keyexchange/isakmpd-20041012/sysdep/freebsd/sysdep-os.h b/keyexchange/isakmpd-20041012/sysdep/freebsd/sysdep-os.h new file mode 100644 index 0000000..cecc2c2 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/freebsd/sysdep-os.h @@ -0,0 +1,79 @@ +/* $OpenBSD: sysdep-os.h,v 1.5 2003/06/03 14:53:11 ho Exp $ */ + +/* + * Copyright (c) 1998, 1999 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. + * + * 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_OS_H_ + +#define _SYSDEP_OS_H_ + +#define KAME + +#include <netinet6/ipsec.h> + +#if ( __FreeBSD_cc_version < 440000 ) +/* We need in_addr_t & in_port_t */ +typedef u_int32_t in_addr_t; +typedef u_int16_t in_port_t; +#endif +#if ( __FreeBSD__ < 4 ) +/* We need socklen_t too. */ +typedef u_int32_t socklen_t; +#endif + +/* Map extensions to values from /usr/include/net/pfkeyv2.h */ +#if ( SADB_EALG_MAX == 7 ) +/* FreeBSD 4.2 */ +#define SADB_X_EALG_BLF SADB_EALG_BLOWFISHCBC +#define SADB_X_EALG_CAST SADB_EALG_CAST128CBC +#else if ( SADB_EALG_MAX == 12 ) +/* FreeBSD 4.4 */ +#define SADB_X_EALG_BLF SADB_X_EALG_BLOWFISHCBC +#define SADB_X_EALG_CAST SADB_X_EALG_CAST128CBC +#endif + +#if 0 +/* OpenSSL differs from OpenBSD very slightly... */ + +#define SHA1Init SHA1_Init +#define SHA1Update SHA1_Update +#define SHA1Final SHA1_Final + +#define cast_key CAST_KEY +#define cast_setkey(k, d, l) CAST_set_key ((k), (l), (d)) +#define cast_encrypt(k, i, o) do { \ + memcpy ((o), (i), BLOCKSIZE); \ + CAST_encrypt ((CAST_LONG *)(o), (k)); \ +} +#define cast_decrypt(k, i, o) do { \ + memcpy ((o), (i), BLOCKSIZE); \ + CAST_decrypt ((CAST_LONG *)(o), (k)); \ +} +#endif + +#endif /* _SYSDEP_OS_H_ */ diff --git a/keyexchange/isakmpd-20041012/sysdep/freebsd/sysdep.c b/keyexchange/isakmpd-20041012/sysdep/freebsd/sysdep.c new file mode 100644 index 0000000..2679fc8 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/freebsd/sysdep.c @@ -0,0 +1,228 @@ +/* $OpenBSD: sysdep.c,v 1.13 2004/08/10 15:59:10 ho Exp $ */ + +/* + * Copyright (c) 1998, 1999 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. + * + * 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 <stdlib.h> +#include <string.h> + +#include "sysdep.h" + +#include "util.h" + +#ifdef NEED_SYSDEP_APP +#include "app.h" +#include "conf.h" +#include "ipsec.h" + +#ifdef USE_PF_KEY_V2 +#include "pf_key_v2.h" +#define KEY_API(x) pf_key_v2_##x +#endif + +#endif /* NEED_SYSDEP_APP */ +#include "log.h" + +extern char *__progname; + +/* + * An as strong as possible random number generator, reverting to a + * deterministic pseudo-random one if regrand is set. + */ +u_int32_t +sysdep_random () +{ + return random(); +} + +/* Return the basename of the command used to invoke us. */ +char * +sysdep_progname () +{ + return __progname; +} + +/* Return the length of the sockaddr struct. */ +u_int8_t +sysdep_sa_len (struct sockaddr *sa) +{ + return sa->sa_len; +} + +/* As regress/ use this file I protect the sysdep_app_* stuff like this. */ +#ifdef NEED_SYSDEP_APP +/* + * Prepare the application we negotiate SAs for (i.e. the IPsec stack) + * for communication. We return a file descriptor useable to select(2) on. + */ +int +sysdep_app_open () +{ + return KEY_API(open) (); +} + +/* + * When select(2) has noticed our application needs attendance, this is what + * gets called. FD is the file descriptor causing the alarm. + */ +void +sysdep_app_handler (int fd) +{ + KEY_API (handler) (fd); +} + +/* Check that the connection named NAME is active, or else make it active. */ +void +sysdep_connection_check (char *name) +{ + KEY_API (connection_check) (name); +} + +/* + * Generate a SPI for protocol PROTO and the source/destination pair given by + * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ. + */ +u_int8_t * +sysdep_ipsec_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src, + struct sockaddr *dst, u_int32_t seq) +{ + if (app_none) + { + *sz = IPSEC_SPI_SIZE; + /* XXX should be random instead I think. */ + return strdup ("\x12\x34\x56\x78"); + } + return KEY_API (get_spi) (sz, proto, src, dst, seq); +} + +struct sa_kinfo * +sysdep_ipsec_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto, + struct sockaddr *dst) +{ + if (app_none) + return 0; + /* XXX return KEY_API(get_kernel_sa)(spi, spi_sz, proto, dst); */ + return 0; +} + +/* Force communication on socket FD to go in the clear. */ +int +sysdep_cleartext (int fd, int af) +{ + char *buf; + char *policy[] = { "in bypass", "out bypass", NULL }; + char **p; + int ipp; + int opt; + char *msgstr; + + if (app_none) + return 0; + + switch (af) + { + case AF_INET: + ipp = IPPROTO_IP; + opt = IP_IPSEC_POLICY; + msgstr = ""; + break; + case AF_INET6: + ipp = IPPROTO_IPV6; + opt = IPV6_IPSEC_POLICY; + msgstr = "V6"; + break; + default: + log_print ("sysdep_cleartext: unsupported protocol family %d", af); + return -1; + } + + /* + * Need to bypass system security policy, so I can send and + * receive key management datagrams in the clear. + */ + + for (p = policy; p && *p; p++) + { + buf = ipsec_set_policy (*p, strlen(*p)); + if (buf == NULL) + { + log_error ("sysdep_cleartext: %s: %s", *p, ipsec_strerror()); + return -1; + } + + if (setsockopt(fd, ipp, opt, buf, ipsec_get_policylen(buf)) < 0) + { + log_error ("sysdep_cleartext: " + "setsockopt (%d, IPPROTO_IP%s, IP%s_IPSEC_POLICY, ...) " + "failed", fd, msgstr, msgstr); + return -1; + } + free(buf); + } + + return 0; +} + +int +sysdep_ipsec_delete_spi (struct sa *sa, struct proto *proto, int incoming) +{ + if (app_none) + return 0; + return KEY_API (delete_spi) (sa, proto, incoming); +} + +int +sysdep_ipsec_enable_sa (struct sa *sa, struct sa *isakmp_sa) +{ + if (app_none) + return 0; + return KEY_API (enable_sa) (sa, isakmp_sa); +} + +int +sysdep_ipsec_group_spis (struct sa *sa, struct proto *proto1, + struct proto *proto2, int incoming) +{ + if (app_none) + return 0; + return KEY_API (group_spis) (sa, proto1, proto2, incoming); +} + +int +sysdep_ipsec_set_spi (struct sa *sa, struct proto *proto, int incoming, + struct sa *isakmp_sa) +{ + if (app_none) + return 0; + return KEY_API (set_spi) (sa, proto, incoming, isakmp_sa); +} +#endif diff --git a/keyexchange/isakmpd-20041012/sysdep/freeswan/GNUmakefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/freeswan/GNUmakefile.sysdep new file mode 100644 index 0000000..9b9bd18 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/freeswan/GNUmakefile.sysdep @@ -0,0 +1,72 @@ +# $OpenBSD: GNUmakefile.sysdep,v 1.2 2003/06/03 14:53:11 ho Exp $ + +# +# Copyright (c) 1999 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. +# +# 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. +# + +# In order for this to work, invocations need to set FREESWAN to the +# directory where FreeS/WAN is installed. + +ifndef FREESWAN +FREESWAN= /usr/src/freeswan +endif + +BINDIR= /usr/local/sbin +# Partly good for RedHat 5.2, but man(1) does not find them so I have it +# disabled for now. +#MANDIR= /var/catman/cat +#MAN5= isakmpd.conf.0 +#MAN8= isakmpd.0 +NOMAN= + +LIBGMP= -lgmp +LIBDES= ${FREESWAN}/libdes/libdes.a +LIBSYSDEPDIR= ${.CURDIR}/sysdep/common/libsysdep +LIBSYSDEP= ${LIBSYSDEPDIR}/libsysdep.a + +FEATURES= tripledes blowfish cast ec aggressive debug + +SRCS+= klips.c + +LDADD+= ${LIBSYSDEP} ${LIBGMP} ${LIBDES} -ldl +DPADD+= ${LIBSYSDEP} ${LIBGMP} ${LIBDES} + +CFLAGS+= -I${FREESWAN}/gmp -I${FREESWAN}/libdes \ + -I${FREESWAN}/klips -I${FREESWAN}/lib -DUSE_OLD_SOCKADDR \ + -I${.CURDIR}/sysdep/common -DSYMBOL_PREFIX='"_"' +CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_GMP +CFLAGS+= -D'SALEN(x)=8' + +${LIBSYSDEP}: + cd ${LIBSYSDEPDIR}; \ + ${MAKE} --no-print-directory ${MAKEFLAGS} CFLAGS="${CFLAGS}" MKDEP="${MKDEP}" + +ifneq ($(findstring install,$(MAKECMDGOALS)),install) +SUBDIR+= sysdep/common/libsysdep +# The regress/ subdir is completely broken in the linux environment +SUBDIR:= $(filter-out regress,${SUBDIR}) +endif diff --git a/keyexchange/isakmpd-20041012/sysdep/freeswan/Makefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/freeswan/Makefile.sysdep new file mode 100644 index 0000000..56bc6df --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/freeswan/Makefile.sysdep @@ -0,0 +1,75 @@ +# $OpenBSD: Makefile.sysdep,v 1.2 2003/06/03 14:53:11 ho Exp $ + +# +# Copyright (c) 1999 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. +# +# 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. +# + +# In order for this to work, invocations need to set FREESWAN to the +# directory where FreeS/WAN is installed. + +BINDIR= /usr/local/sbin +# Partly good for RedHat 5.2, but man(1) does not find them so I have it +# disabled for now. +#MANDIR= /var/catman/cat +#MAN5= isakmpd.conf.0 +#MAN8= isakmpd.0 +NOMAN= + +IPSEC_SRCS= klips.c + +LDADD+= ${.CURDIR}/sysdep/common/libsysdep/libsysdep.a \ + ${FREESWAN}/gmp/libgmp.a +DPADD+= ${.CURDIR}/sysdep/common/libsysdep/libsysdep.a \ + ${FREESWAN}/gmp/libgmp.a + +CFLAGS+= ${DEBUG} -I${FREESWAN}/gmp -I${FREESWAN}/libdes \ + -I${FREESWAN}/klips -I${FREESWAN}/lib -DUSE_OLD_SOCKADDR \ + -I${.CURDIR}/sysdep/common + +#USE_LIBCRYPTO= defined +#USE_KEYNOTE= defined + +.ifndef USE_LIBCRYPTO +DESLIB= ${FREESWAN}/libdes/libdes.a +DESLIBDEP= ${FREESWAN}/libdes/libdes.a +.endif + +# This is a hack in order to make sure libsysdep is built before the +# linkstage of isakmpd. As a side effect the link is always done even if +# not necessary. Well, I just don't care. +GENERATED+= sysdep-target +sysdep-target: + cd ${.CURDIR}/sysdep/common/libsysdep; ${MAKE} ${.MAKEFLAGS} + +.if make(clean) +SUBDIR+= sysdep/common/libsysdep +.endif + +# The regress/ subdir is completely broken in the linux environment +.if !make(install) +SUBDIR:= ${SUBDIR:Nregress} +.endif diff --git a/keyexchange/isakmpd-20041012/sysdep/freeswan/README b/keyexchange/isakmpd-20041012/sysdep/freeswan/README new file mode 100644 index 0000000..3990ab3 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/freeswan/README @@ -0,0 +1,16 @@ +$OpenBSD: README,v 1.1 2003/05/14 20:49:37 ho Exp $ + +Currently, you have to manually configure any IPsec interfaces and do the +association betweent these and the physical ones. This is done like +this in FreeS/WAN: + +ipsec tncfg --attach --virtual ipsec0 --physical eth0 +ifconfig ipsec0 A.B.C.D netmask E.F.G.H + +Then there is one special configuration option in the IPsec-connection +sections for Phase 2 of the configuration file, named Next-hop, which +should be set to the next hop's IP address along the way to the peer: + +Next-hop= I.J.K.L + +This is specific to the way FreeS/WAN works. diff --git a/keyexchange/isakmpd-20041012/sysdep/freeswan/klips.c b/keyexchange/isakmpd-20041012/sysdep/freeswan/klips.c new file mode 100644 index 0000000..d362333 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/freeswan/klips.c @@ -0,0 +1,662 @@ +/* $OpenBSD: klips.c,v 1.3 2003/09/26 15:59:34 aaron Exp $ */ + +/* + * Copyright (c) 1999 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. + * + * 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 <asm/types.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <linux/sockios.h> +#include <net/route.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> + +#include <freeswan.h> +#include <net/ipsec/radij.h> +#include <net/ipsec/ipsec_encap.h> +#include <net/ipsec/ipsec_netlink.h> +#include <net/ipsec/ipsec_xform.h> +#include <net/ipsec/ipsec_ipe4.h> +#include <net/ipsec/ipsec_ah.h> +#include <net/ipsec/ipsec_esp.h> + +#include "sysdep.h" + +#include "conf.h" +#include "exchange.h" +#include "hash.h" +#include "ipsec.h" +#include "ipsec_doi.h" +#include "ipsec_num.h" +#include "isakmp.h" +#include "log.h" +#include "klips.h" +#include "sa.h" +#include "timer.h" +#include "transport.h" + +#define KLIPS_DEVICE "/dev/ipsec" + +#define PROC_ROUTE_FILE "/proc/net/route" +#define PROC_ROUTE_FMT "%15s %127s %127s %X %d %d %d %127s %d %d %d\n" + +/* XXX Maybe these are available through some system-supplied define? */ +#define AH_NEW_XENCAP_LEN (3 * sizeof(u_short) + 2 * sizeof(u_char)) +#define ESP_NEW_XENCAP_LEN sizeof (struct espblkrply_edata) +#define EMT_GRPSPIS_COMPLEN (sizeof (((struct encap_msghdr *)0)->em_rel[0])) + +/* How often should we check that connections we require to be up, are up? */ +#define KLIPS_CHECK_FREQ 60 + +static int klips_socket; + +/* Open the KLIPS device. */ +int +klips_open () +{ + int fd; + + fd = open (KLIPS_DEVICE, O_RDWR); + if (fd == -1) + { + log_error ("klips_open: open (\"%s\", O_RDWR) failed", KLIPS_DEVICE); + return -1; + } + klips_socket = fd; + return fd; +} + +/* Write a KLIPS request down to the kernel. */ +static int +klips_write (struct encap_msghdr *em) +{ + ssize_t n; + + em->em_magic = EM_MAGIC; + em->em_version = 0; + + LOG_DBG_BUF ((LOG_SYSDEP, 30, "klips_write: em", (u_int8_t *)em, + em->em_msglen)); + n = write (klips_socket, em, em->em_msglen); + if (n == -1) + { + log_error ("write (%d, ...) failed", klips_socket); + return -1; + } + if ((size_t)n != em->em_msglen) + { + log_error ("write (%d, ...) returned prematurely", klips_socket); + return -1; + } + return 0; +} + +/* + * Generate a SPI for protocol PROTO and the source/destination pair given by + * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ. + */ +u_int8_t * +klips_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src, + struct sockaddr *dst, u_int32_t seq) +{ + u_int8_t *spi; + u_int32_t spinum; + + *sz = IPSEC_SPI_SIZE; + spi = malloc (*sz); + if (!spi) + return 0; + do + spinum = sysdep_random (); + while (spinum < IPSEC_SPI_LOW); + spinum = htonl (spinum); + memcpy (spi, &spinum, *sz); + + LOG_DBG_BUF ((LOG_SYSDEP, 50, "klips_get_spi: spi", spi, *sz)); + + return spi; +} + +/* Group 2 SPIs in a chain. XXX Not fully implemented yet. */ +int +klips_group_spis (struct sa *sa, struct proto *proto1, struct proto *proto2, + int incoming) +{ + struct encap_msghdr *emsg = 0; + struct sockaddr *dst; + + emsg = calloc (1, EMT_GRPSPIS_FLEN + 2 * EMT_GRPSPIS_COMPLEN); + if (!emsg) + return -1; + + emsg->em_msglen = EMT_GRPSPIS_FLEN + 2 * EMT_GRPSPIS_COMPLEN; + emsg->em_type = EMT_GRPSPIS; + + /* + * XXX The code below is wrong if we are in tunnel mode. + * The fix is to reorder stuff so the IP-in-IP SA will always come + * upfront, and if there are two such, one is dropped. + */ + memcpy (&emsg->em_rel[0].emr_spi, proto1->spi[incoming], + sizeof emsg->em_rel[0].emr_spi); + memcpy (&emsg->em_rel[1].emr_spi, proto2->spi[incoming], + sizeof emsg->em_rel[1].emr_spi); + if (incoming) + sa->transport->vtbl->get_src (sa->transport, &dst); + else + sa->transport->vtbl->get_dst (sa->transport, &dst); + emsg->em_rel[0].emr_dst + = emsg->em_rel[1].emr_dst = ((struct sockaddr_in *)dst)->sin_addr; + /* XXX What if IPCOMP etc. comes along? */ + emsg->em_rel[0].emr_proto + = proto1->proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH; + emsg->em_rel[1].emr_proto + = proto2->proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH; + + if (klips_write (emsg)) + goto cleanup; + free (emsg); + + LOG_DBG ((LOG_SYSDEP, 50, "klips_group_spis: done")); + + return 0; + + cleanup: + if (emsg) + free (emsg); + return -1; +} + +/* Store/update a SPI with full information into the kernel. */ +int +klips_set_spi (struct sa *sa, struct proto *proto, int incoming, + struct sa *isakmp_sa) +{ + struct encap_msghdr *emsg = 0; + struct ipsec_proto *iproto = proto->data; + struct sockaddr *dst, *src; + int keylen, hashlen; + size_t len; + struct ipe4_xdata *ip4x; + + /* Actually works for all. */ + struct espblkrply_edata *edx; + + /* Actually works for all. */ + struct ahhmacmd5_edata *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; + emsg = calloc (1, len); + if (!emsg) + return -1; + + emsg->em_proto = IPPROTO_ESP; + + edx = (struct espblkrply_edata *)emsg->em_dat; + + /* Funny expression due to I just want one switch. */ + switch (proto->id | (iproto->auth << 8)) + { + case IPSEC_ESP_3DES: + emsg->em_alg = XF_ESP3DES; + break; + + case IPSEC_ESP_3DES | (IPSEC_AUTH_HMAC_MD5 << 8): + emsg->em_alg = XF_ESP3DESMD596; + break; + + case IPSEC_ESP_3DES | (IPSEC_AUTH_HMAC_SHA << 8): + emsg->em_alg = XF_ESP3DESSHA196; + break; + + default: + LOG_DBG ((LOG_SYSDEP, 10, + "klips_set_spi: Unsupported enc/auth alg negotiated")); + return -1; + } + + /* XXX What if we have a protocol requiring IV? */ + edx->eme_ivlen = EMT_ESPDES_IV_SZ; + edx->eme_klen = keylen; + edx->ame_klen = hashlen; +#if 0 + /* I have reason to believe Shared-SADB won't work at all in KLIPS. */ + edx->eme_ooowin + = conf_get_str ("General", "Shared-SADB") ? 0 : iproto->replay_window; +#else + edx->eme_ooowin = iproto->replay_window; +#endif + /* + * XXX Pluto sets the unused by KLIPS flag EME_INITIATOR in + * edx->eme_flags, if the party is the initiator. Should we too? + */ + edx->eme_flags = 0; + memcpy (edx->eme_key, iproto->keymat[incoming], keylen); + if (iproto->auth) + memcpy (edx->ame_key, iproto->keymat[incoming] + 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; + + emsg->em_proto = IPPROTO_AH; + + amx = (struct ahhmacmd5_edata *)emsg->em_dat; + + switch (proto->id) + { + case IPSEC_AH_MD5: + emsg->em_alg = XF_AHHMACMD5; + break; + + case IPSEC_AH_SHA: + emsg->em_alg = XF_AHHMACSHA1; + break; + + default: + /* XXX Log? */ + goto cleanup; + } + + /* XXX Should we be able to send in different lengths here? */ + amx->ame_alen = amx->ame_klen = hashlen; +#if 0 + /* I have reason to believe Shared-SADB won't work at all in KLIPS. */ + amx->ame_ooowin + = conf_get_str ("General", "Shared-SADB") ? 0 : iproto->replay_window; +#else + amx->ame_ooowin = iproto->replay_window; +#endif + amx->ame_replayp = amx->ame_ooowin > 0; + memcpy (amx->ame_key, iproto->keymat[incoming], hashlen); + break; + + default: + /* XXX Log? */ + goto cleanup; + } + + emsg->em_msglen = len; + emsg->em_type = EMT_SETSPI; + memcpy (&emsg->em_spi, proto->spi[incoming], sizeof emsg->em_spi); + emsg->em_flags = incoming ? EMT_INBOUND : 0; + + /* + * XXX Addresses has to be thought through. Assumes IPv4. + */ + sa->transport->vtbl->get_dst (sa->transport, &dst); + sa->transport->vtbl->get_src (sa->transport, &src); + emsg->em_dst + = ((struct sockaddr_in *)(incoming ? src : dst))->sin_addr; + + /* + * Klips does not know about expirations, thus we need to do them inside + * isakmpd. + */ + if (sa->seconds) + if (sa_setup_expirations (sa)) + goto cleanup; + + LOG_DBG ((LOG_SYSDEP, 10, "klips_set_spi: proto %d dst %s SPI 0x%x", + emsg->em_proto, inet_ntoa (emsg->em_dst), htonl (emsg->em_spi))); + if (klips_write (emsg)) + goto cleanup; + free (emsg); + + /* If we are tunneling we have to setup an IP in IP tunnel too. */ + if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL) + { + len = EMT_SETSPI_FLEN + EMT_IPE4_ULEN; + emsg = calloc (1, len); + if (!emsg) + goto cleanup; + + emsg->em_proto = IPPROTO_IPIP; + emsg->em_msglen = len; + emsg->em_type = EMT_SETSPI; + /* + * XXX Code in Pluto suggests this is not possible, but that we have + * to have a unique SPI for the IP4 SA. + */ + memcpy (&emsg->em_spi, proto->spi[incoming], sizeof emsg->em_spi); + emsg->em_flags = 0; + emsg->em_alg = XF_IP4; + + ip4x = (struct ipe4_xdata *)emsg->em_dat; + ip4x->i4_dst = emsg->em_dst + = ((struct sockaddr_in *)(incoming ? src : dst))->sin_addr; + ip4x->i4_src + = ((struct sockaddr_in *)(incoming ? dst : src))->sin_addr; + + LOG_DBG ((LOG_SYSDEP, 10, "klips_set_spi: proto %d dst %s SPI 0x%x", + emsg->em_proto, inet_ntoa (emsg->em_dst), + htonl (emsg->em_spi))); + if (klips_write (emsg)) + goto cleanup; + free (emsg); + + /* + * Grouping the IP-in-IP SA with the IPsec one means we must be careful + * in klips_group_spis so that we'll remove duplicate IP-in-IP SAs + * and get everything grouped in the right order. + * + * XXX Could we not share code with klips_group_spis here? + */ + emsg = calloc (1, EMT_GRPSPIS_FLEN + 2 * EMT_GRPSPIS_COMPLEN); + if (!emsg) + goto cleanup; + + emsg->em_msglen = EMT_GRPSPIS_FLEN + 2 * EMT_GRPSPIS_COMPLEN; + emsg->em_type = EMT_GRPSPIS; + + memcpy (&emsg->em_rel[0].emr_spi, proto->spi[incoming], + sizeof emsg->em_rel[0].emr_spi); + memcpy (&emsg->em_rel[1].emr_spi, proto->spi[incoming], + sizeof emsg->em_rel[1].emr_spi); + emsg->em_rel[0].emr_dst = emsg->em_rel[1].emr_dst + = ((struct sockaddr_in *)(incoming ? src : dst))->sin_addr; + + emsg->em_rel[0].emr_proto = IPPROTO_IPIP; + /* XXX What if IPCOMP etc. comes along? */ + emsg->em_rel[1].emr_proto + = proto->proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH; + + if (klips_write (emsg)) + goto cleanup; + free (emsg); + } + + LOG_DBG ((LOG_SYSDEP, 50, "klips_set_spi: done")); + + return 0; + + cleanup: + /* XXX Cleanup the potential SAs we have setup. */ + if (emsg) + free (emsg); + return -1; +} + +/* + * Delete the IPsec SA represented by the INCOMING direction in protocol PROTO + * of the IKE security association SA. + */ +int +klips_delete_spi (struct sa *sa, struct proto *proto, int incoming) +{ + struct encap_msghdr *emsg = 0; + struct sockaddr *dst; + struct ipsec_proto *iproto = proto->data; + + emsg = calloc (1, EMT_SETSPI_FLEN); + if (!emsg) + return -1; + + emsg->em_msglen = EMT_SETSPI_FLEN; + emsg->em_type = EMT_DELSPI; + + memcpy (&emsg->em_spi, proto->spi[incoming], sizeof emsg->em_spi); + if (incoming) + sa->transport->vtbl->get_src (sa->transport, &dst); + else + sa->transport->vtbl->get_dst (sa->transport, &dst); + emsg->em_dst = ((struct sockaddr_in *)dst)->sin_addr; + /* XXX What if IPCOMP etc. comes along? */ + emsg->em_proto + = (iproto->encap_mode == IPSEC_ENCAP_TUNNEL ? IPPROTO_IPIP + : proto->proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH); + + if (klips_write (emsg)) + goto cleanup; + free (emsg); + + LOG_DBG ((LOG_SYSDEP, 50, "klips_delete_spi: done")); + + return 0; + + cleanup: + if (emsg) + free (emsg); + return -1; +} + +int +klips_hex_decode (char *src, u_char *dst, int dstsize) +{ + char *p, *pe; + u_char *q, *qe, ch, cl; + + pe = src + strlen (src); + qe = dst + dstsize; + + for (p = src, q = dst; p < pe && q < qe && isxdigit ((int)*p); p += 2) + { + ch = tolower (p[0]); + cl = tolower (p[1]); + + if ((ch >= '0') && (ch <= '9')) + ch -= '0'; + else if ((ch >= 'a') && (ch <= 'f')) + ch -= 'a' - 10; + else + return -1; + + if ((cl >= '0') && (cl <= '9')) + cl -= '0'; + else if ((cl >= 'a') && (cl <= 'f')) + cl -= 'a' - 10; + else + return -1; + + *q++ = (ch << 4) | cl; + } + + return (int)(q - dst); +} + +/* Consult kernel routing table for next-hop lookup. From dugsong@monkey.org */ +u_long +klips_route_get (u_long dst) +{ + FILE *f; + char buf[BUFSIZ]; + char ifbuf[16], netbuf[128], gatebuf[128], maskbuf[128]; + int i, iflags, refcnt, use, metric, mss, win, irtt; + u_long ret, gate, net, mask; + + if ((f = fopen (PROC_ROUTE_FILE, "r")) == NULL) + return dst; + + ret = dst; + + while (fgets (buf, sizeof buf, f) != NULL) + { + i = sscanf (buf, PROC_ROUTE_FMT, ifbuf, netbuf, gatebuf, &iflags, + &refcnt, &use, &metric, maskbuf, &mss, &win, &irtt); + if (i < 10 || !(iflags & RTF_UP)) + continue; + + klips_hex_decode (netbuf, (u_char *)&net, sizeof net); + klips_hex_decode (gatebuf, (u_char *)&gate, sizeof gate); + klips_hex_decode (maskbuf, (u_char *)&mask, sizeof mask); + + net = htonl (net); + gate = htonl (gate); + mask = htonl (mask); + + if ((dst & mask) == net) + { + if (gate != INADDR_ANY) + ret = gate; + break; + } + } + + fclose (f); + return ret; +} + +/* Enable a flow given a SA. */ +int +klips_enable_sa (struct sa *sa, struct sa *isakmp_sa) +{ + struct ipsec_sa *isa = sa->data; + struct sockaddr *dst; + struct proto *proto = TAILQ_FIRST (&sa->protos); + struct ipsec_proto *iproto = proto->data; + struct encap_msghdr emsg; + int s = -1; + struct rtentry rt; + + sa->transport->vtbl->get_dst (sa->transport, &dst); + + /* XXX Is this needed? */ + memset (&emsg, '\0', sizeof emsg); + + emsg.em_msglen = sizeof emsg; + emsg.em_type = EMT_RPLACEROUTE; + + memcpy (&emsg.em_erspi, proto->spi[0], sizeof emsg.em_erspi); + emsg.em_erdst = ((struct sockaddr_in *)dst)->sin_addr; + + LOG_DBG ((LOG_SYSDEP, 50, "klips_enable_sa: src %x %x dst %x %x", + ntohl (isa->src_net), ntohl (isa->src_mask), ntohl (isa->dst_net), + ntohl (isa->dst_mask))); + + /* XXX Magic constant from Pluto (26 = AF_ISDN in BSD). */ + emsg.em_eaddr.sen_family = emsg.em_emask.sen_family = 26; + emsg.em_eaddr.sen_type = SENT_IP4; + /* XXX Magic constant from Pluto. */ + emsg.em_emask.sen_type = 255; + emsg.em_eaddr.sen_len = emsg.em_emask.sen_len + = sizeof (struct sockaddr_encap); + + emsg.em_eaddr.sen_ip_src.s_addr = isa->src_net; + emsg.em_emask.sen_ip_src.s_addr = isa->src_mask; + emsg.em_eaddr.sen_ip_dst.s_addr = isa->dst_net; + emsg.em_emask.sen_ip_dst.s_addr = isa->dst_mask; + + /* XXX What if IPCOMP etc. comes along? */ + emsg.em_erproto + = (iproto->encap_mode == IPSEC_ENCAP_TUNNEL ? IPPROTO_IPIP + : proto->proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH); + + if (klips_write (&emsg)) + { + emsg.em_type = EMT_SETEROUTE; + if (klips_write (&emsg)) + goto cleanup; + } + + s = socket (PF_INET, SOCK_DGRAM, AF_UNSPEC); + if (s == -1) + { + log_error ("klips_enable_sa: " + "socket(PF_INET, SOCK_DGRAM, AF_UNSPEC) failed"); + goto cleanup; + } + + memset (&rt, '\0', sizeof rt); + rt.rt_dst.sa_family = AF_INET; + ((struct sockaddr_in *)&rt.rt_dst)->sin_addr.s_addr = isa->dst_net; + rt.rt_genmask.sa_family = AF_INET; + ((struct sockaddr_in *)&rt.rt_genmask)->sin_addr.s_addr = isa->dst_mask; + rt.rt_gateway.sa_family = AF_INET; + + ((struct sockaddr_in *)&rt.rt_gateway)->sin_addr.s_addr + = klips_route_get (emsg.em_erdst.s_addr); + + rt.rt_flags = RTF_UP | RTF_GATEWAY; + /* XXX What if we have multiple interfaces? */ + rt.rt_dev = "ipsec0"; + + if (ioctl (s, SIOCDELRT, &rt) == -1 && errno != ESRCH) + { + log_error ("klips_enable_sa: ioctl (%d, SIOCDELRT, %p) failed", s, &rt); + goto cleanup; + } + + if (ioctl (s, SIOCADDRT, &rt) == -1) + { + log_error ("klips_enable_sa: ioctl (%d, SIOCADDRT, %p) failed", s, &rt); + goto cleanup; + } + + close (s); + return 0; + + cleanup: + if (s != -1) + close (s); + return -1; +} + +static void +klips_stayalive (struct exchange *exchange, void *vconn, int fail) +{ + char *conn = vconn; + struct sa *sa; + + /* XXX What if it is phase 1? */ + sa = sa_lookup_by_name (conn, 2); + if (sa) + sa->flags |= SA_FLAG_STAYALIVE; +} + +/* Establish the connection in VCONN and set the stayalive flag for it. */ +void +klips_connection_check (char *conn) +{ + if (!sa_lookup_by_name (conn, 2)) + { + LOG_DBG ((LOG_SYSDEP, 70, "klips_connection_check: SA for %s missing", + conn)); + exchange_establish (conn, klips_stayalive, conn); + } + else + LOG_DBG ((LOG_SYSDEP, 70, "klips_connection_check: SA for %s exists", + conn)); +} diff --git a/keyexchange/isakmpd-20041012/sysdep/freeswan/klips.h b/keyexchange/isakmpd-20041012/sysdep/freeswan/klips.h new file mode 100644 index 0000000..a786dcb --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/freeswan/klips.h @@ -0,0 +1,51 @@ +/* $OpenBSD: klips.h,v 1.2 2003/06/03 14:53:11 ho Exp $ */ + +/* + * Copyright (c) 1999 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. + * + * 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 _KLIPS_H_ +#define _KLIPS_H_ + +#include <sys/types.h> +#include <sys/queue.h> + +struct proto; +struct sa; +struct sockaddr; + +extern void klips_connection_check (char *); +extern int klips_delete_spi (struct sa *, struct proto *, int); +extern int klips_enable_sa (struct sa *, struct sa *); +extern u_int8_t *klips_get_spi (size_t *, u_int8_t, struct sockaddr *, int, + struct sockaddr *, int, u_int32_t); +extern int klips_group_spis (struct sa *, struct proto *, struct proto *, + int); +extern int klips_open (void); +extern int klips_set_spi (struct sa *, struct proto *, int); + +#endif /* _KLIPS_H_ */ diff --git a/keyexchange/isakmpd-20041012/sysdep/freeswan/sys/queue.h b/keyexchange/isakmpd-20041012/sysdep/freeswan/sys/queue.h new file mode 100644 index 0000000..ae555ee --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/freeswan/sys/queue.h @@ -0,0 +1,333 @@ +/* $OpenBSD: queue.h,v 1.2 2003/06/02 20:06:15 millert Exp $ */ +/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +#ifndef NULL +#define NULL ((void *)0) +#endif + +/* + * This file defines four types of data structures: lists, simple queues, + * tail queues, and circular queues. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so only elements can only be removed from the + * head of the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) +#define LIST_END(head) NULL + +/* + * List functions. + */ +#define LIST_INIT(head) do { \ + (head)->lh_first = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ +} while (0) + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (0) + +#define SIMPLEQ_REMOVE_HEAD(head, elm, field) do { \ + if (((head)->sqh_first = (elm)->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +/* + * Tail queue definitions. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + + +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_END(head) NULL +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ +} while (0) + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_END(head) ((void *)(head)) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = (void *)(head); \ + (head)->cqh_last = (void *)(head); \ +} while (0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = (void *)(head); \ + if ((head)->cqh_last == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = (void *)(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ +} while (0) +#endif /* !_SYS_QUEUE_H_ */ diff --git a/keyexchange/isakmpd-20041012/sysdep/freeswan/sysdep-os.h b/keyexchange/isakmpd-20041012/sysdep/freeswan/sysdep-os.h new file mode 100644 index 0000000..72e9d08 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/freeswan/sysdep-os.h @@ -0,0 +1,46 @@ +/* $OpenBSD: sysdep-os.h,v 1.2 2003/06/03 14:53:11 ho Exp $ */ + +/* + * Copyright (c) 1998, 1999 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. + * + * 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_OS_H_ +#define _SYSDEP_OS_H_ + +typedef u_int16_t in_port_t; +typedef u_int32_t in_addr_t; + +#if 0 +/* + * Why -D__USE_GNU does not work in order to get this from stdio.h beats me. + */ +extern int asprintf(char **, const char *, ...); +#endif + +#define DL_LAZY RTLD_LAZY + +#endif /* _SYSDEP_OS_H_ */ diff --git a/keyexchange/isakmpd-20041012/sysdep/freeswan/sysdep.c b/keyexchange/isakmpd-20041012/sysdep/freeswan/sysdep.c new file mode 100644 index 0000000..9e99d7e --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/freeswan/sysdep.c @@ -0,0 +1,186 @@ +/* $OpenBSD: sysdep.c,v 1.3 2004/08/10 15:59:10 ho Exp $ */ + +/* + * Copyright (c) 1998, 1999 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. + * + * 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 <sys/time.h> +#include <netinet/in.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <md5.h> +#include <unistd.h> + +#include "sysdep.h" + +#ifdef NEED_SYSDEP_APP +#include "app.h" +#include "conf.h" +#include "ipsec.h" +#include "klips.h" +#endif /* NEED_SYSDEP_APP */ +#include "log.h" +#include "sysdep.h" + +extern char *__progname; + +u_int32_t +sysdep_random () +{ + u_int32_t rndval; + u_char sig[16]; + MD5_CTX ctx; + int fd, i; + struct { + struct timeval tv; + u_int rnd[(128 - sizeof (struct timeval)) / sizeof (u_int)]; + } rdat; + + fd = open ("/dev/urandom", O_RDONLY); + if (fd != -1) + { + read (fd, rdat.rnd, sizeof(rdat.rnd)); + close (fd); + } + MD5Init (&ctx); + MD5Update (&ctx, (char *)&rdat, sizeof(rdat)); + MD5Final (sig, &ctx); + + rndval = 0; + for (i = 0; i < 4; i++) + { + u_int32_t *tmp = (u_int32_t *)&sig[i * 4]; + rndval ^= *tmp; + } + + return rndval; +} + +char * +sysdep_progname () +{ + return __progname; +} + +/* Return the length of the sockaddr struct. */ +u_int8_t +sysdep_sa_len (struct sockaddr *sa) +{ + switch (sa->sa_family) + { + case AF_INET: + return sizeof (struct sockaddr_in); + case AF_INET6: + return sizeof (struct sockaddr_in6); + } + log_print ("sysdep_sa_len: unknown sa family %d", sa->sa_family); + return sizeof (struct sockaddr_in); +} + +/* As regress/ use this file I protect the sysdep_app_* stuff like this. */ +#ifdef NEED_SYSDEP_APP +int +sysdep_app_open () +{ + return klips_open (); +} + +void +sysdep_app_handler (int fd) +{ +} + +/* Check that the connection named NAME is active, or else make it active. */ +void +sysdep_connection_check (char *name) +{ + klips_connection_check (name); +} + +/* + * Generate a SPI for protocol PROTO and the source/destination pair given by + * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ. + */ +u_int8_t * +sysdep_ipsec_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src, + struct sockaddr *dst, u_int32_t seq) +{ + if (app_none) + { + *sz = IPSEC_SPI_SIZE; + /* XXX should be random instead I think. */ + return strdup ("\x12\x34\x56\x78"); + } + + return klips_get_spi (sz, proto, src, dst, seq); +} + +struct sa_kinfo * +sysdep_ipsec_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto, + struct sockaddr *dst) +{ + if (app_none) + return 0; + /* XXX return KEY_API(get_kernel_sa)(spi, spi_sz, proto, dst); */ + return 0; +} + +int +sysdep_cleartext (int fd, int af) +{ + return 0; +} + +int +sysdep_ipsec_delete_spi (struct sa *sa, struct proto *proto, int incoming) +{ + return klips_delete_spi (sa, proto, incoming); +} + +int +sysdep_ipsec_enable_sa (struct sa *sa, struct sa *isakmp_sa) +{ + return klips_enable_sa (sa, isakmp_sa); +} + +int +sysdep_ipsec_group_spis (struct sa *sa, struct proto *proto1, + struct proto *proto2, int incoming) +{ + return klips_group_spis (sa, proto1, proto2, incoming); +} + +int +sysdep_ipsec_set_spi (struct sa *sa, struct proto *proto, int incoming, + struct sa *isakmp_sa) +{ + return klips_set_spi (sa, proto, incoming, isakmp_sa); +} +#endif diff --git a/keyexchange/isakmpd-20041012/sysdep/linux/GNUmakefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/linux/GNUmakefile.sysdep new file mode 100644 index 0000000..6c0fa10 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/linux/GNUmakefile.sysdep @@ -0,0 +1,60 @@ +# $OpenBSD: GNUmakefile.sysdep,v 1.9 2004/08/10 09:49:51 ho Exp $ + +# +# Copyright (c) 1999 Niklas Hallqvist. All rights reserved. +# Copyright (c) 2003 Thomas Walpuski. 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. +# +# 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. +# + +LIBGMP:= /usr/lib/libgmp.a +LIBCRYPTO:= /usr/lib/libcrypto.a +LIBSYSDEPDIR:= ${.CURDIR}/sysdep/common/libsysdep +LIBSYSDEP:= ${LIBSYSDEPDIR}/libsysdep.a + +LDADD+= -lgmp ${LIBSYSDEP} ${LIBCRYPTO} +DPADD+= ${LIBGMP} ${LIBSYSDEP} + +CFLAGS+= -DHAVE_GETNAMEINFO -DUSE_OLD_SOCKADDR -DHAVE_PCAP \ + -DNEED_SYSDEP_APP -DMP_FLAVOUR=MP_FLAVOUR_GMP -DUSE_AES \ + -I${.CURDIR}/sysdep/linux/include -I${.CURDIR}/sysdep/common \ + -I/usr/include/openssl + +FEATURES= debug tripledes blowfish cast ec aggressive x509 policy +FEATURES+= dpd nat_traversal isakmp_cfg des aes + +IPSEC_SRCS= pf_key_v2.c +IPSEC_CFLAGS= -DUSE_PF_KEY_V2 + +USE_LIBCRYPO= defined +HAVE_DLOPEN= defined +USE_KEYNOTE= defined + +# hack libsysdep.a dependenc +${LIBSYSDEPDIR}/.depend ${LIBSYSDEP}: + cd ${LIBSYSDEPDIR} && \ + ${MAKE} --no-print-directory \ + CFLAGS="${CFLAGS}" MKDEP="${MKDEP}" ${MAKECMDGOALS} + +ifeq ($(findstring clean,$(MAKECMDGOALS)),clean) +SUBDIR+= sysdep/common/libsysdep +MAKEFLAGS+= --no-print-directory +endif diff --git a/keyexchange/isakmpd-20041012/sysdep/linux/bitstring.h b/keyexchange/isakmpd-20041012/sysdep/linux/bitstring.h new file mode 100644 index 0000000..ce20dd9 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/linux/bitstring.h @@ -0,0 +1,128 @@ +/* $OpenBSD: bitstring.h,v 1.1 2003/09/02 18:11:15 ho Exp $ */ +/* $NetBSD: bitstring.h,v 1.5 1997/05/14 15:49:55 pk Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Paul Vixie. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + * + * @(#)bitstring.h 8.1 (Berkeley) 7/19/93 + */ + +#ifndef _BITSTRING_H_ +#define _BITSTRING_H_ + +/* modified for SV/AT and bitstring bugfix by M.R.Murphy, 11oct91 + * bitstr_size changed gratuitously, but shorter + * bit_alloc spelling error fixed + * the following were efficient, but didn't work, they've been made to + * work, but are no longer as efficient :-) + * bit_nclear, bit_nset, bit_ffc, bit_ffs + */ +typedef unsigned char bitstr_t; + +/* internal macros */ + /* byte of the bitstring bit is in */ +#define _bit_byte(bit) \ + ((bit) >> 3) + + /* mask for the bit within its byte */ +#define _bit_mask(bit) \ + (1 << ((bit)&0x7)) + +/* external macros */ + /* bytes in a bitstring of nbits bits */ +#define bitstr_size(nbits) \ + (((nbits) + 7) >> 3) + + /* allocate a bitstring */ +#define bit_alloc(nbits) \ + (bitstr_t *)calloc((size_t)bitstr_size(nbits), sizeof(bitstr_t)) + + /* allocate a bitstring on the stack */ +#define bit_decl(name, nbits) \ + ((name)[bitstr_size(nbits)]) + + /* is bit N of bitstring name set? */ +#define bit_test(name, bit) \ + ((name)[_bit_byte(bit)] & _bit_mask(bit)) + + /* set bit N of bitstring name */ +#define bit_set(name, bit) \ + ((name)[_bit_byte(bit)] |= _bit_mask(bit)) + + /* clear bit N of bitstring name */ +#define bit_clear(name, bit) \ + ((name)[_bit_byte(bit)] &= ~_bit_mask(bit)) + + /* clear bits start ... stop in bitstring */ +#define bit_nclear(name, start, stop) do { \ + register bitstr_t *_name = name; \ + register int _start = start, _stop = stop; \ + while (_start <= _stop) { \ + bit_clear(_name, _start); \ + _start++; \ + } \ +} while(0) + + /* set bits start ... stop in bitstring */ +#define bit_nset(name, start, stop) do { \ + register bitstr_t *_name = name; \ + register int _start = start, _stop = stop; \ + while (_start <= _stop) { \ + bit_set(_name, _start); \ + _start++; \ + } \ +} while(0) + + /* find first bit clear in name */ +#define bit_ffc(name, nbits, value) do { \ + register bitstr_t *_name = name; \ + register int _bit, _nbits = nbits, _value = -1; \ + for (_bit = 0; _bit < _nbits; ++_bit) \ + if (!bit_test(_name, _bit)) { \ + _value = _bit; \ + break; \ + } \ + *(value) = _value; \ +} while(0) + + /* find first bit set in name */ +#define bit_ffs(name, nbits, value) do { \ + register bitstr_t *_name = name; \ + register int _bit, _nbits = nbits, _value = -1; \ + for (_bit = 0; _bit < _nbits; ++_bit) \ + if (bit_test(_name, _bit)) { \ + _value = _bit; \ + break; \ + } \ + *(value) = _value; \ +} while(0) + +#endif /* !_BITSTRING_H_ */ diff --git a/keyexchange/isakmpd-20041012/sysdep/linux/include/bitstring.h b/keyexchange/isakmpd-20041012/sysdep/linux/include/bitstring.h new file mode 100644 index 0000000..1939615 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/linux/include/bitstring.h @@ -0,0 +1,132 @@ +/* $OpenBSD: bitstring.h,v 1.4 2002/06/19 02:50:10 millert Exp $ */ +/* $NetBSD: bitstring.h,v 1.5 1997/05/14 15:49:55 pk Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Paul Vixie. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + * + * @(#)bitstring.h 8.1 (Berkeley) 7/19/93 + */ + +#ifndef _BITSTRING_H_ +#define _BITSTRING_H_ + +/* modified for SV/AT and bitstring bugfix by M.R.Murphy, 11oct91 + * bitstr_size changed gratuitously, but shorter + * bit_alloc spelling error fixed + * the following were efficient, but didn't work, they've been made to + * work, but are no longer as efficient :-) + * bit_nclear, bit_nset, bit_ffc, bit_ffs + */ +typedef unsigned char bitstr_t; + +/* internal macros */ + /* byte of the bitstring bit is in */ +#define _bit_byte(bit) \ + ((bit) >> 3) + + /* mask for the bit within its byte */ +#define _bit_mask(bit) \ + (1 << ((bit)&0x7)) + +/* external macros */ + /* bytes in a bitstring of nbits bits */ +#define bitstr_size(nbits) \ + (((nbits) + 7) >> 3) + + /* allocate a bitstring */ +#define bit_alloc(nbits) \ + (bitstr_t *)calloc((size_t)bitstr_size(nbits), sizeof(bitstr_t)) + + /* allocate a bitstring on the stack */ +#define bit_decl(name, nbits) \ + ((name)[bitstr_size(nbits)]) + + /* is bit N of bitstring name set? */ +#define bit_test(name, bit) \ + ((name)[_bit_byte(bit)] & _bit_mask(bit)) + + /* set bit N of bitstring name */ +#define bit_set(name, bit) \ + ((name)[_bit_byte(bit)] |= _bit_mask(bit)) + + /* clear bit N of bitstring name */ +#define bit_clear(name, bit) \ + ((name)[_bit_byte(bit)] &= ~_bit_mask(bit)) + + /* clear bits start ... stop in bitstring */ +#define bit_nclear(name, start, stop) do { \ + register bitstr_t *_name = name; \ + register int _start = start, _stop = stop; \ + while (_start <= _stop) { \ + bit_clear(_name, _start); \ + _start++; \ + } \ +} while(0) + + /* set bits start ... stop in bitstring */ +#define bit_nset(name, start, stop) do { \ + register bitstr_t *_name = name; \ + register int _start = start, _stop = stop; \ + while (_start <= _stop) { \ + bit_set(_name, _start); \ + _start++; \ + } \ +} while(0) + + /* find first bit clear in name */ +#define bit_ffc(name, nbits, value) do { \ + register bitstr_t *_name = name; \ + register int _bit, _nbits = nbits, _value = -1; \ + for (_bit = 0; _bit < _nbits; ++_bit) \ + if (!bit_test(_name, _bit)) { \ + _value = _bit; \ + break; \ + } \ + *(value) = _value; \ +} while(0) + + /* find first bit set in name */ +#define bit_ffs(name, nbits, value) do { \ + register bitstr_t *_name = name; \ + register int _bit, _nbits = nbits, _value = -1; \ + for (_bit = 0; _bit < _nbits; ++_bit) \ + if (bit_test(_name, _bit)) { \ + _value = _bit; \ + break; \ + } \ + *(value) = _value; \ +} while(0) + +#endif /* !_BITSTRING_H_ */ diff --git a/keyexchange/isakmpd-20041012/sysdep/linux/include/sys/queue.h b/keyexchange/isakmpd-20041012/sysdep/linux/include/sys/queue.h new file mode 100644 index 0000000..c4ac33d --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/linux/include/sys/queue.h @@ -0,0 +1,453 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD: src/sys/sys/queue.h,v 1.45 2001/12/11 11:49:58 sheldonh Exp $ + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +//#include <machine/ansi.h> /* for __offsetof */ + +/* + * This file defines four types of data structures: singly-linked lists, + * singly-linked tail queues, lists and tail queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ + * _HEAD + + + + + * _HEAD_INITIALIZER + + + + + * _ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - - - + + * _LAST - - + + + * _FOREACH + + + + + * _FOREACH_REVERSE - - - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _REMOVE_HEAD + - + - + * _REMOVE + + + + + * + */ + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_NEXT(curelm, field) = \ + SLIST_NEXT(SLIST_NEXT(curelm, field), field); \ + } \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first;/* first element */ \ + struct type **stqh_last;/* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY(head) ? \ + NULL : \ + ((struct type *) \ + ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD(head, field); \ + } \ + else { \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + if ((STAILQ_NEXT(curelm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((curelm), field);\ + } \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \ + if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +/* + * List declarations. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_REMOVE(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ +} while (0) + +/* + * Tail queue declarations. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * Tail queue functions. + */ +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ +} while (0) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ +} while (0) + + +#ifdef _KERNEL + +/* + * XXX insque() and remque() are an old way of handling certain queues. + * They bogusly assumes that all queue heads look alike. + */ + +struct quehead { + struct quehead *qh_link; + struct quehead *qh_rlink; +}; + +#ifdef __GNUC__ + +static __inline void +insque(void *a, void *b) +{ + struct quehead *element = (struct quehead *)a, + *head = (struct quehead *)b; + + element->qh_link = head->qh_link; + element->qh_rlink = head; + head->qh_link = element; + element->qh_link->qh_rlink = element; +} + +static __inline void +remque(void *a) +{ + struct quehead *element = (struct quehead *)a; + + element->qh_link->qh_rlink = element->qh_rlink; + element->qh_rlink->qh_link = element->qh_link; + element->qh_rlink = 0; +} + +#else /* !__GNUC__ */ + +void insque __P((void *a, void *b)); +void remque __P((void *a)); + +#endif /* __GNUC__ */ + +#endif /* _KERNEL */ + +#endif /* !_SYS_QUEUE_H_ */ diff --git a/keyexchange/isakmpd-20041012/sysdep/linux/sys/queue.h b/keyexchange/isakmpd-20041012/sysdep/linux/sys/queue.h new file mode 100644 index 0000000..3f0be6c --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/linux/sys/queue.h @@ -0,0 +1,499 @@ +/* $OpenBSD: queue.h,v 1.7 2004/04/08 16:08:21 henning Exp $ */ +/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List access methods. + */ +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_END(head) NULL +#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = SLIST_FIRST(head); \ + (var) != SLIST_END(head); \ + (var) = SLIST_NEXT(var, field)) + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) { \ + SLIST_FIRST(head) = SLIST_END(head); \ +} + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = (head)->slh_first; \ + while( curelm->field.sle_next != (elm) ) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + } \ +} while (0) + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List access methods + */ +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_END(head) NULL +#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_FOREACH(var, head, field) \ + for((var) = LIST_FIRST(head); \ + (var)!= LIST_END(head); \ + (var) = LIST_NEXT(var, field)) + +/* + * List functions. + */ +#define LIST_INIT(head) do { \ + LIST_FIRST(head) = LIST_END(head); \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ +} while (0) + +#define LIST_REPLACE(elm, elm2, field) do { \ + if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ + (elm2)->field.le_next->field.le_prev = \ + &(elm2)->field.le_next; \ + (elm2)->field.le_prev = (elm)->field.le_prev; \ + *(elm2)->field.le_prev = (elm2); \ +} while (0) + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_END(head) NULL +#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for((var) = SIMPLEQ_FIRST(head); \ + (var) != SIMPLEQ_END(head); \ + (var) = SIMPLEQ_NEXT(var, field)) + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (0) + +#define SIMPLEQ_REMOVE_HEAD(head, elm, field) do { \ + if (((head)->sqh_first = (elm)->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +/* + * Tail queue definitions. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * tail queue access methods + */ +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_END(head) NULL +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +/* XXX */ +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define TAILQ_EMPTY(head) \ + (TAILQ_FIRST(head) == TAILQ_END(head)) + +#define TAILQ_FOREACH(var, head, field) \ + for((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_NEXT(var, field)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_PREV(var, headname, field)) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ + (elm2)->field.tqe_next->field.tqe_prev = \ + &(elm2)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm2)->field.tqe_next; \ + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ + *(elm2)->field.tqe_prev = (elm2); \ +} while (0) + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue access methods + */ +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_END(head) ((void *)(head)) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) +#define CIRCLEQ_EMPTY(head) \ + (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for((var) = CIRCLEQ_FIRST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_NEXT(var, field)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for((var) = CIRCLEQ_LAST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_PREV(var, field)) + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = CIRCLEQ_END(head); \ + (head)->cqh_last = CIRCLEQ_END(head); \ +} while (0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = CIRCLEQ_END(head); \ + if ((head)->cqh_last == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = CIRCLEQ_END(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ +} while (0) + +#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ + CIRCLEQ_END(head)) \ + (head).cqh_last = (elm2); \ + else \ + (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ + if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ + CIRCLEQ_END(head)) \ + (head).cqh_first = (elm2); \ + else \ + (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ +} while (0) + +#endif /* !_SYS_QUEUE_H_ */ diff --git a/keyexchange/isakmpd-20041012/sysdep/linux/sysdep-os.h b/keyexchange/isakmpd-20041012/sysdep/linux/sysdep-os.h new file mode 100644 index 0000000..4bd5dfd --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/linux/sysdep-os.h @@ -0,0 +1,64 @@ +/* $OpenBSD: sysdep-os.h,v 1.8 2003/06/03 15:20:41 ho Exp $ */ + +/* + * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2003 Thomas Walpuski. 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. + * + * 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. + */ + +#ifndef _SYSDEP_OS_H_ +#define _SYSDEP_OS_H_ + +#include <netinet/in.h> +#include <time.h> +#include <sys/types.h> +#include <linux/ipsec.h> + +#define KAME + +#define LINUX_IPSEC + +#define uh_sport source +#define uh_dport dest +#define uh_ulen len +#define uh_sum check + +#ifndef CPI_RESERVED_MAX +#define CPI_RESERVED_MIN 1 +#define CPI_RESERVED_MAX 255 +#define CPI_PRIVATE_MIN 61440 +#define CPI_PRIVATE_MAX 65536 +#endif + +#define SADB_X_EALG_AES SADB_X_EALG_AESCBC +#define SADB_X_EALG_CAST SADB_X_EALG_CASTCBC +#define SADB_X_EALG_BLF SADB_X_EALG_BLOWFISHCBC + +#define IP_IPSEC_POLICY 16 +#define IPV6_IPSEC_POLICY 34 + +#define IPV6_VERSION 0x1 + +size_t strlcat(char *dst, const char *src, size_t siz); +size_t strlcpy(char *dst, const char *src, size_t siz); + +#endif diff --git a/keyexchange/isakmpd-20041012/sysdep/linux/sysdep.c b/keyexchange/isakmpd-20041012/sysdep/linux/sysdep.c new file mode 100644 index 0000000..fc3b362 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/linux/sysdep.c @@ -0,0 +1,226 @@ +/* $OpenBSD: sysdep.c,v 1.16 2004/08/10 15:59:10 ho Exp $ */ + +/* + * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2003 Thomas Walpuski. 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. + * + * 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. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdlib.h> +#include <string.h> + +#include "sysdep.h" + +#include "util.h" + +#ifdef NEED_SYSDEP_APP +#include "app.h" +#include "conf.h" +#include "ipsec.h" +#include <linux/pfkeyv2.h> +#include <linux/ipsec.h> + +#ifdef USE_PF_KEY_V2 +#include "pf_key_v2.h" +#define KEY_API(x) pf_key_v2_##x +#endif + +#endif /* NEED_SYSDEP_APP */ +#include "log.h" + +extern char *__progname; + +/* + * An as strong as possible random number generator, reverting to a + * deterministic pseudo-random one if regrand is set. + */ +u_int32_t +sysdep_random () +{ + return arc4random(); +} + +/* Return the basename of the command used to invoke us. */ +char * +sysdep_progname () +{ + return __progname; +} + +/* Return the length of the sockaddr struct. */ +u_int8_t +sysdep_sa_len (struct sockaddr *sa) +{ + switch (sa->sa_family) + { + case AF_INET: + return sizeof (struct sockaddr_in); + case AF_INET6: + return sizeof (struct sockaddr_in6); + default: + log_print ("sysdep_sa_len: unknown sa family %d", sa->sa_family); + } + return sizeof (struct sockaddr_in); +} + +/* As regress/ use this file I protect the sysdep_app_* stuff like this. */ +#ifdef NEED_SYSDEP_APP +/* + * Prepare the application we negotiate SAs for (i.e. the IPsec stack) + * for communication. We return a file descriptor useable to select(2) on. + */ +int +sysdep_app_open () +{ + return KEY_API(open) (); +} + +/* + * When select(2) has noticed our application needs attendance, this is what + * gets called. FD is the file descriptor causing the alarm. + */ +void +sysdep_app_handler (int fd) +{ + KEY_API (handler) (fd); +} + +/* Check that the connection named NAME is active, or else make it active. */ +void +sysdep_connection_check (char *name) +{ + KEY_API (connection_check) (name); +} + +/* + * Generate a SPI for protocol PROTO and the source/destination pair given by + * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ. + */ +u_int8_t * +sysdep_ipsec_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src, + struct sockaddr *dst, u_int32_t seq) +{ + if (app_none) + { + *sz = IPSEC_SPI_SIZE; + /* XXX should be random instead I think. */ + return strdup ("\x12\x34\x56\x78"); + } + return KEY_API (get_spi) (sz, proto, src, dst, seq); +} + +struct sa_kinfo * +sysdep_ipsec_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto, + struct sockaddr *dst) +{ + if (app_none) + return 0; + /* XXX return KEY_API(get_kernel_sa)(spi, spi_sz, proto, dst); */ + return 0; +} + +/* Force communication on socket FD to go in the clear. */ +int +sysdep_cleartext (int fd, int af) +{ + struct sadb_x_policy pol_in = { + SADB_UPDATE, + SADB_EXT_SENSITIVITY, + IPSEC_POLICY_BYPASS, + IPSEC_DIR_INBOUND, + 0, + 0, + 0 + }; + struct sadb_x_policy pol_out = { + SADB_UPDATE, + SADB_EXT_SENSITIVITY, + IPSEC_POLICY_BYPASS, + IPSEC_DIR_OUTBOUND, + 0, + 0, + 0 + }; + + if (app_none) + return 0; + + if (!(af == AF_INET || af == AF_INET6)) + { + log_print ("sysdep_cleartext: unsupported protocol family %d", af); + return -1; + } + + if (setsockopt (fd, af == AF_INET ? IPPROTO_IP : IPPROTO_IPV6, + af == AF_INET ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY, + &pol_in, sizeof pol_in) < 0 || + setsockopt (fd, af == AF_INET ? IPPROTO_IP : IPPROTO_IPV6, + af == AF_INET ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY, + &pol_out, sizeof pol_out) < 0) + { + log_error ("sysdep_cleartext: " + "setsockopt (%d, IPPROTO_IP%s, IP%s_IPSEC_POLICY, ...) " + "failed", fd, af == AF_INET ? "" : "V6", + af == AF_INET ? "" : "V6"); + return -1; + } + return 0; +} + +int +sysdep_ipsec_delete_spi (struct sa *sa, struct proto *proto, int incoming) +{ + if (app_none) + return 0; + return KEY_API (delete_spi) (sa, proto, incoming); +} + +int +sysdep_ipsec_enable_sa (struct sa *sa, struct sa *isakmp_sa) +{ + if (app_none) + return 0; + return KEY_API (enable_sa) (sa, isakmp_sa); +} + +int +sysdep_ipsec_group_spis (struct sa *sa, struct proto *proto1, + struct proto *proto2, int incoming) +{ + if (app_none) + return 0; + return KEY_API (group_spis) (sa, proto1, proto2, incoming); +} + +int +sysdep_ipsec_set_spi (struct sa *sa, struct proto *proto, int incoming, + struct sa *isakmp_sa) +{ + if (app_none) + return 0; + return KEY_API (set_spi) (sa, proto, incoming, isakmp_sa); +} +#endif diff --git a/keyexchange/isakmpd-20041012/sysdep/netbsd/GNUmakefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/netbsd/GNUmakefile.sysdep new file mode 100644 index 0000000..e506ddc --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/netbsd/GNUmakefile.sysdep @@ -0,0 +1,63 @@ +# $OpenBSD: GNUmakefile.sysdep,v 1.8 2004/06/26 03:40:57 mcbride Exp $ + +# +# Copyright (c) 1999 Niklas Hallqvist. All rights reserved. +# Copyright (c) 2000 Håkan Olsson. 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. +# +# 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. +# + +LIBGMP:= /usr/pkg/lib/libgmp.a +LIBCRYPTO:= /usr/lib/libcrypto.a + +LIBSYSDEPDIR:= ${.CURDIR}/sysdep/common/libsysdep +LIBSYSDEP:= ${LIBSYSDEPDIR}/libsysdep.a + +LDADD+= ${LIBGMP} ${LIBSYSDEP} +DPADD+= ${LIBGMP} ${LIBSYSDEP} + +FEATURES= debug tripledes des blowfish cast ec aggressive x509 +# Not yet +#FEATURES+= policy + +CFLAGS+= -DNO_RSA -DNO_RC5 -DNO_IDEA \ + -I${.CURDIR}/sysdep/common -I/usr/include/openssl \ + -I/usr/include/machine -I/usr/pkg/include + +IPSEC_SRCS= pf_key_v2.c +IPSEC_CFLAGS= -DUSE_PF_KEY_V2 + +USE_LIBCRYPTO= defined + +# +# hack libsysdep.a dependency +# +${LIBSYSDEPDIR}/.depend ${LIBSYSDEP}: + @cd ${LIBSYSDEPDIR} && \ + ${MAKE} --no-print-directory ${MAKEFLAGS} \ + CFLAGS="${CFLAGS}" MKDEP="${MKDEP}" ${MAKECMDGOALS} + +depend: ${LIBSYSDEPDIR}/.depend + +ifeq ($(findstring clean, $(MAKECMDGOALS)), clean) +SUBDIR+= sysdep/common/libsysdep +MAKEFLAGS+= --no-print-directory +endif diff --git a/keyexchange/isakmpd-20041012/sysdep/netbsd/Makefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/netbsd/Makefile.sysdep new file mode 100644 index 0000000..fbc75cc --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/netbsd/Makefile.sysdep @@ -0,0 +1,79 @@ +# $OpenBSD: Makefile.sysdep,v 1.10 2004/06/26 03:40:57 mcbride Exp $ + +# +# Copyright (c) 1999 Niklas Hallqvist. All rights reserved. +# Copyright (c) 2000 Håkan Olsson. 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. +# +# 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 INN 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. +# + +# Override default features +FEATURES= tripledes des blowfish cast ec aggressive debug x509 +FEATURES+= rawkey +# Not yet +#FEATURES+= policy isakmp_cfg + +LIBGMP= /usr/pkg/lib/libgmp.a +LIBCRYPTO= /usr/lib/libcrypto.a +LIBSYSDEPDIR= ${.CURDIR}/sysdep/common/libsysdep + +LDADD+= ${LIBGMP} ${LIBSYSDEPDIR}/libsysdep.a -lipsec +DPADD+= ${LIBGMP} ${LIBSYSDEPDIR}/libsysdep.a ${LIBIPSEC} + +CFLAGS+= -DNO_RSA -DNO_IDEA -DNO_RC5 \ + -DHAVE_GETIFADDRS \ + -I${.CURDIR}/sysdep/common +.if exists(/usr/pkg/include/openssl/rsa.h) +CFLAGS+= -I/usr/pkg/include/openssl +.elif exists(/usr/include/openssl/rsa.h) +CFLAGS+= -I/usr/include -I/usr/include/openssl +.endif +# mandatory for gmp +CFLAGS+= -I/usr/pkg/include +LDADD+= -L/usr/pkg/lib + +IPSEC_SRCS= pf_key_v2.c +IPSEC_CFLAGS= -DUSE_PF_KEY_V2 + +USE_LIBCRYPTO= defined +USE_GMP= defined + +# This is a hack in order to make sure libsysdep is built before the +# linkstage of isakmpd. As a side effect the link is always done even if +# not necessary. Well, I just don't care. +GENERATED+= sysdep-target +sysdep-target: + cd ${.CURDIR}/sysdep/common/libsysdep; ${MAKE} ${.MAKEFLAGS} + +.if make(clean) || make(cleandir) +SUBDIR+= sysdep/common/libsysdep +.endif + +# Kludge around bug in /usr/share/mk/bsd.subdir.mk +NO_REGRESS= defined + +beforedepend: + rm -f ssl +.if exists(/usr/pkg/include/openssl/rsa.h) + ln -sf /usr/pkg/include/openssl ssl +.elif exists(/usr/include/openssl/rsa.h) + ln -sf /usr/include/openssl ssl +.endif diff --git a/keyexchange/isakmpd-20041012/sysdep/netbsd/sysdep-os.h b/keyexchange/isakmpd-20041012/sysdep/netbsd/sysdep-os.h new file mode 100644 index 0000000..b401bb1 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/netbsd/sysdep-os.h @@ -0,0 +1,51 @@ +/* $OpenBSD: sysdep-os.h,v 1.5 2003/08/06 11:20:00 markus Exp $ */ + +/* + * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2000 Håkan Olsson. 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. + * + * 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. + */ + +#ifndef _SYSDEP_OS_H_ + +#define _SYSDEP_OS_H_ + +#define KAME + +#include <netinet6/ipsec.h> + +#ifndef CPI_RESERVED_MAX +#define CPI_RESERVED_MIN 1 +#define CPI_RESERVED_MAX 255 +#define CPI_PRIVATE_MIN 61440 +#define CPI_PRIVATE_MAX 65536 +#endif + +#if !defined(SADB_X_EALG_CAST) && defined(SADB_X_EALG_CAST128CBC) +#define SADB_X_EALG_CAST SADB_X_EALG_CAST128CBC +#endif + +#if !defined(SADB_X_EALG_BLF) && defined(SADB_X_EALG_BLOWFISHCBC) +#define SADB_X_EALG_BLF SADB_X_EALG_BLOWFISHCBC +#endif + +#endif /* _SYSDEP_OS_H_ */ diff --git a/keyexchange/isakmpd-20041012/sysdep/netbsd/sysdep.c b/keyexchange/isakmpd-20041012/sysdep/netbsd/sysdep.c new file mode 100644 index 0000000..2720715 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/netbsd/sysdep.c @@ -0,0 +1,225 @@ +/* $OpenBSD: sysdep.c,v 1.13 2004/08/10 15:59:10 ho Exp $ */ + +/* + * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2000 Håkan Olsson. 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. + * + * 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. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdlib.h> +#include <string.h> + +#include "sysdep.h" + +#include "util.h" + +#ifdef NEED_SYSDEP_APP +#include "app.h" +#include "conf.h" +#include "ipsec.h" + +#ifdef USE_PF_KEY_V2 +#include "pf_key_v2.h" +#define KEY_API(x) pf_key_v2_##x +#endif + +#endif /* NEED_SYSDEP_APP */ +#include "log.h" + +extern char *__progname; + +/* + * An as strong as possible random number generator, reverting to a + * deterministic pseudo-random one if regrand is set. + */ +u_int32_t +sysdep_random () +{ + return random(); +} + +/* Return the basename of the command used to invoke us. */ +char * +sysdep_progname () +{ + return __progname; +} + +/* Return the length of the sockaddr struct. */ +u_int8_t +sysdep_sa_len (struct sockaddr *sa) +{ + return sa->sa_len; +} + +/* As regress/ use this file I protect the sysdep_app_* stuff like this. */ +#ifdef NEED_SYSDEP_APP +/* + * Prepare the application we negotiate SAs for (i.e. the IPsec stack) + * for communication. We return a file descriptor useable to select(2) on. + */ +int +sysdep_app_open () +{ + return KEY_API(open) (); +} + +/* + * When select(2) has noticed our application needs attendance, this is what + * gets called. FD is the file descriptor causing the alarm. + */ +void +sysdep_app_handler (int fd) +{ + KEY_API (handler) (fd); +} + +/* Check that the connection named NAME is active, or else make it active. */ +void +sysdep_connection_check (char *name) +{ + KEY_API (connection_check) (name); +} + +/* + * Generate a SPI for protocol PROTO and the source/destination pair given by + * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ. + */ +u_int8_t * +sysdep_ipsec_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src, + struct sockaddr *dst, u_int32_t seq) +{ + if (app_none) + { + *sz = IPSEC_SPI_SIZE; + /* XXX should be random instead I think. */ + return strdup ("\x12\x34\x56\x78"); + } + return KEY_API (get_spi) (sz, proto, src, dst, seq); +} + +struct sa_kinfo * +sysdep_ipsec_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto, + struct sockaddr *dst) +{ + if (app_none) + return 0; + /* XXX return KEY_API(get_kernel_sa)(spi, spi_sz, proto, dst); */ + return 0; +} + +/* Force communication on socket FD to go in the clear. */ +int +sysdep_cleartext (int fd, int af) +{ + char *buf; + char *policy[] = { "in bypass", "out bypass", NULL }; + char **p; + int ipp; + int opt; + char *msgstr; + + if (app_none) + return 0; + + switch (af) + { + case AF_INET: + ipp = IPPROTO_IP; + opt = IP_IPSEC_POLICY; + msgstr = ""; + break; + case AF_INET6: + ipp = IPPROTO_IPV6; + opt = IPV6_IPSEC_POLICY; + msgstr = "V6"; + break; + default: + log_print ("sysdep_cleartext: unsupported protocol family %d", af); + return -1; + } + + /* + * Need to bypass system security policy, so I can send and + * receive key management datagrams in the clear. + */ + + for (p = policy; p && *p; p++) + { + buf = ipsec_set_policy (*p, strlen(*p)); + if (buf == NULL) + { + log_error ("sysdep_cleartext: %s: %s", *p, ipsec_strerror()); + return -1; + } + + if (setsockopt(fd, ipp, opt, buf, ipsec_get_policylen(buf)) < 0) + { + log_error ("sysdep_cleartext: " + "setsockopt (%d, IPPROTO_IP%s, IP%s_IPSEC_POLICY, ...) " + "failed", fd, msgstr, msgstr); + return -1; + } + free(buf); + } + + return 0; +} + +int +sysdep_ipsec_delete_spi (struct sa *sa, struct proto *proto, int incoming) +{ + if (app_none) + return 0; + return KEY_API (delete_spi) (sa, proto, incoming); +} + +int +sysdep_ipsec_enable_sa (struct sa *sa, struct sa *isakmp_sa) +{ + if (app_none) + return 0; + return KEY_API (enable_sa) (sa, isakmp_sa); +} + +int +sysdep_ipsec_group_spis (struct sa *sa, struct proto *proto1, + struct proto *proto2, int incoming) +{ + if (app_none) + return 0; + return KEY_API (group_spis) (sa, proto1, proto2, incoming); +} + +int +sysdep_ipsec_set_spi (struct sa *sa, struct proto *proto, int incoming, + struct sa *isakmp_sa) +{ + if (app_none) + return 0; + return KEY_API (set_spi) (sa, proto, incoming, isakmp_sa); +} +#endif diff --git a/keyexchange/isakmpd-20041012/sysdep/openbsd/GNUmakefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/openbsd/GNUmakefile.sysdep new file mode 100644 index 0000000..8a46424 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/openbsd/GNUmakefile.sysdep @@ -0,0 +1,52 @@ +# $OpenBSD: GNUmakefile.sysdep,v 1.5 2004/06/26 03:40:57 mcbride Exp $ + +# +# Copyright (c) 1999 Håkan Olsson. All rights reserved. +# Copyright (c) 1999, 2000 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. +# +# 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. +# + + +LIBGMP:= /usr/lib/libgmp.a +LIBCRYPTO:= /usr/lib/libcrypto.a + +IPSEC_SRCS= pf_key_v2.c +IPSEC_CFLAGS= -DUSE_PF_KEY_V2 + +USE_LIBCRYPTO= defined +ifneq (${MACHINE_ARCH},alpha) +ifneq (${MACHINE_ARCH},vax) +ifneq (${MACHINE_ARCH},m88k) +SRCS+= keynote_compat.c +endif +endif +endif +USE_KEYNOTE= defined + +ifndef USE_LIBCRYPTO +DESLIB= -ldes +DESLIBDEP= ${LIBDES} +endif diff --git a/keyexchange/isakmpd-20041012/sysdep/openbsd/Makefile.sysdep b/keyexchange/isakmpd-20041012/sysdep/openbsd/Makefile.sysdep new file mode 100644 index 0000000..86688bd --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/openbsd/Makefile.sysdep @@ -0,0 +1,52 @@ +# $OpenBSD: Makefile.sysdep,v 1.24 2004/06/26 03:40:57 mcbride Exp $ +# $EOM: Makefile.sysdep,v 1.18 2001/01/26 10:55:22 niklas Exp $ + +# +# Copyright (c) 1999, 2000, 2001 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. +# +# 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 INN 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. +# + +IPSEC_SRCS= pf_key_v2.c +IPSEC_CFLAGS= -DUSE_PF_KEY_V2 + +CFLAGS+= -DHAVE_GETIFADDRS -DHAVE_PCAP +CFLAGS+= -DHAVE_CLOSEFROM + +USE_LIBCRYPTO= defined + +.ifdef FEATURES +.if ${FEATURES:Mpolicy} == "policy" +.if ${MACHINE_ARCH} != "alpha" && ${MACHINE_ARCH} != "vax" && ${MACHINE_ARCH} != "m88k" +POLICY+= keynote_compat.c +.endif +USE_KEYNOTE= defined +.endif +.endif + +.ifndef USE_LIBCRYPTO +DESLIB= -ldes +DESLIBDEP= ${LIBDES} +.endif diff --git a/keyexchange/isakmpd-20041012/sysdep/openbsd/keynote_compat.c b/keyexchange/isakmpd-20041012/sysdep/openbsd/keynote_compat.c new file mode 100644 index 0000000..a464375 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/openbsd/keynote_compat.c @@ -0,0 +1,82 @@ +/* $OpenBSD: keynote_compat.c,v 1.6 2004/04/15 18:39:30 deraadt Exp $ */ +/* $EOM: keynote_compat.c,v 1.1 2000/10/15 19:18:26 niklas Exp $ */ + +/* + * Copyright (c) 2000 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. + * + * 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. + */ + +/* + * By mistake these functions were introduced into libkeynote without + * updating some kind of version preprocessor symbol we can test. + * Provide weak functions that can be used if the libkeynote version + * we link against miss them. + */ + +#pragma weak kn_get_string=_kn_get_string +#pragma weak kn_free_key=_kn_free_key + +/* + * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu) + * + * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA, + * in April-May 1998 + * + * Copyright (C) 1998, 1999 by Angelos D. Keromytis. + * + * Permission to use, copy, and modify this software without fee + * is hereby granted, provided that this entire notice is included in + * all copies of any software which is or includes a copy or + * modification of this software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE + * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR + * PURPOSE. + */ + +#include <sys/types.h> +#include <regex.h> +#include <keynote.h> + +extern void keynote_free_key(void *, int); +extern char *keynote_get_private_key(char *); + +/* + * Exportable front-end to keynote_get_private_key(). + */ +char * +_kn_get_string(char *buf) +{ + return keynote_get_private_key(buf); +} + +/* + * Free a key. + */ +void +_kn_free_key(struct keynote_deckey *dc) +{ + if (dc) + keynote_free_key(dc->dec_key, dc->dec_algorithm); +} diff --git a/keyexchange/isakmpd-20041012/sysdep/openbsd/sysdep-os.h b/keyexchange/isakmpd-20041012/sysdep/openbsd/sysdep-os.h new file mode 100644 index 0000000..05200c6 --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/openbsd/sysdep-os.h @@ -0,0 +1,89 @@ +/* $OpenBSD: sysdep-os.h,v 1.6 2003/06/03 14:53:11 ho Exp $ */ +/* $EOM: sysdep-os.h,v 1.3 1999/07/08 16:48:40 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999 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. + * + * 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_OS_H_ +#define _SYSDEP_OS_H_ + +/* + * OpenBSD has at various times had non-conformant PF_KEYv2 definitions. + * Here we transform them into being conformant. + */ + +#ifdef SADB_EXT_X_SRC_MASK +#define SADB_X_EXT_SRC_MASK SADB_EXT_X_SRC_MASK +#define SADB_X_EXT_DST_MASK SADB_EXT_X_DST_MASK +#define SADB_X_EXT_PROTOCOL SADB_EXT_X_PROTOCOL +#define SADB_X_EXT_SA2 SADB_EXT_X_SA2 +#define SADB_X_EXT_SRC_FLOW SADB_EXT_X_SRC_FLOW +#define SADB_X_EXT_DST_FLOW SADB_EXT_X_DST_FLOW +#define SADB_X_EXT_DST2 SADB_EXT_X_DST2 + +#define SADB_X_SATYPE_AH_OLD SADB_SATYPE_X_AH_OLD +#define SADB_X_SATYPE_ESP_OLD SADB_SATYPE_X_ESP_OLD +#define SADB_X_SATYPE_IPIP SADB_SATYPE_X_IPIP + +#define SADB_X_AALG_RIPEMD160HMAC96 SADB_AALG_X_RIPEMD160HMAC96 +#define SADB_X_AALG_MD5 SADB_AALG_X_MD5 +#define SADB_X_AALG_SHA1 SADB_AALG_X_SHA1 + +#define SADB_X_EALG_BLF SADB_EALG_X_BLF +#define SADB_X_EALG_CAST SADB_EALG_X_CAST +#define SADB_X_EALG_SKIPJACK SADB_EALG_X_SKIPJACK + +#define SADB_X_SAFLAGS_HALFIV SADB_SAFLAGS_X_HALFIV +#define SADB_X_SAFLAGS_TUNNEL SADB_SAFLAGS_X_TUNNEL +#define SADB_X_SAFLAGS_CHAINDEL SADB_SAFLAGS_X_CHAINDEL +#define SADB_X_SAFLAGS_LOCALFLOW SADB_SAFLAGS_X_LOCALFLOW +#define SADB_X_SAFLAGS_REPLACEFLOW SADB_SAFLAGS_X_REPLACEFLOW + +#endif /* SADB_EXT_X_SRC_MASK */ + +#if defined (SADB_IDENTTYPE_MBOX) && !defined (SADB_IDENTTYPE_USERFQDN) +#define SADB_IDENTTYPE_USERFQDN SADB_IDENTTYPE_MBOX +#endif + +#ifdef FLOW_X_TYPE_USE +#define SADB_X_FLOW_TYPE_USE FLOW_X_TYPE_USE +#define SADB_X_FLOW_TYPE_ACQUIRE FLOW_X_TYPE_ACQUIRE +#define SADB_X_FLOW_TYPE_REQUIRE FLOW_X_TYPE_REQUIRE +#define SADB_X_FLOW_TYPE_BYPASS FLOW_X_TYPE_BYPASS +#define SADB_X_FLOW_TYPE_DENY FLOW_X_TYPE_DENY +#define SADB_X_FLOW_TYPE_DONTACQ FLOW_X_TYPE_DONTACQ +#endif + +#if OPENBSD_IPSEC_API_VERSION == 1 +#define sadb_x_policy sadb_policy +#define sadb_x_policy_len sadb_policy_len +#define sadb_x_policy_exttype sadb_policy_exttype +#define sadb_x_policy_seq sadb_policy_seq +#endif + +#endif /* _SYSDEP_OS_H_ */ diff --git a/keyexchange/isakmpd-20041012/sysdep/openbsd/sysdep.c b/keyexchange/isakmpd-20041012/sysdep/openbsd/sysdep.c new file mode 100644 index 0000000..f59922f --- /dev/null +++ b/keyexchange/isakmpd-20041012/sysdep/openbsd/sysdep.c @@ -0,0 +1,266 @@ +/* $OpenBSD: sysdep.c,v 1.28 2004/08/10 15:59:11 ho Exp $ */ +/* $EOM: sysdep.c,v 1.9 2000/12/04 04:46:35 angelos Exp $ */ + +/* + * Copyright (c) 1998, 1999 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. + * + * 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/errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdlib.h> +#include <string.h> + +#include "sysdep.h" + +#include "monitor.h" +#include "util.h" + +#ifdef NEED_SYSDEP_APP +#include "app.h" +#include "conf.h" +#include "ipsec.h" + +#ifdef USE_PF_KEY_V2 +#include "pf_key_v2.h" +#define KEY_API(x) pf_key_v2_##x +#endif + +#endif /* NEED_SYSDEP_APP */ +#include "log.h" + +extern char *__progname; + +/* + * An as strong as possible random number generator, reverting to a + * deterministic pseudo-random one if regrand is set. + */ +u_int32_t +sysdep_random() +{ + if (!regrand) + return arc4random(); + else + return random(); +} + +/* Return the basename of the command used to invoke us. */ +char * +sysdep_progname() +{ + return __progname; +} + +/* Return the length of the sockaddr struct. */ +u_int8_t +sysdep_sa_len(struct sockaddr *sa) +{ + return sa->sa_len; +} + +/* As regress/ use this file I protect the sysdep_app_* stuff like this. */ +#ifdef NEED_SYSDEP_APP +/* + * Prepare the application we negotiate SAs for (i.e. the IPsec stack) + * for communication. We return a file descriptor useable to select(2) on. + */ +int +sysdep_app_open() +{ +#ifdef USE_PRIVSEP + return monitor_pf_key_v2_open(); +#else + return KEY_API(open)(); +#endif +} + +/* + * When select(2) has noticed our application needs attendance, this is what + * gets called. FD is the file descriptor causing the alarm. + */ +void +sysdep_app_handler(int fd) +{ + KEY_API(handler)(fd); +} + +/* Check that the connection named NAME is active, or else make it active. */ +void +sysdep_connection_check(char *name) +{ + KEY_API(connection_check)(name); +} + +/* + * Generate a SPI for protocol PROTO and the source/destination pair given by + * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ. + */ +u_int8_t * +sysdep_ipsec_get_spi(size_t *sz, u_int8_t proto, struct sockaddr *src, + struct sockaddr *dst, u_int32_t seq) +{ + if (app_none) { + *sz = IPSEC_SPI_SIZE; + /* XXX should be random instead I think. */ + return (u_int8_t *)strdup("\x12\x34\x56\x78"); + } + return KEY_API(get_spi)(sz, proto, src, dst, seq); +} + +struct sa_kinfo * +sysdep_ipsec_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto, + struct sockaddr *dst) +{ + if (app_none) + return 0; + return KEY_API(get_kernel_sa)(spi, spi_sz, proto, dst); +} + +/* Force communication on socket FD to go in the clear. */ +int +sysdep_cleartext(int fd, int af) +{ + int level, sw; + struct { + int ip_proto; /* IP protocol */ + int auth_level; + int esp_trans_level; + int esp_network_level; + int ipcomp_level; + } optsw[] = { + { + IPPROTO_IP, + IP_AUTH_LEVEL, + IP_ESP_TRANS_LEVEL, + IP_ESP_NETWORK_LEVEL, +#ifdef IP_IPCOMP_LEVEL + IP_IPCOMP_LEVEL +#else + 0 +#endif + }, { + IPPROTO_IPV6, + IPV6_AUTH_LEVEL, + IPV6_ESP_TRANS_LEVEL, + IPV6_ESP_NETWORK_LEVEL, +#ifdef IPV6_IPCOMP_LEVEL + IPV6_IPCOMP_LEVEL +#else + 0 +#endif + }, + }; + + if (app_none) + return 0; + + switch (af) { + case AF_INET: + sw = 0; + break; + case AF_INET6: + sw = 1; + break; + default: + log_print("sysdep_cleartext: unsupported protocol family %d", af); + return -1; + } + + /* + * Need to bypass system security policy, so I can send and + * receive key management datagrams in the clear. + */ + level = IPSEC_LEVEL_BYPASS; + if (monitor_setsockopt(fd, optsw[sw].ip_proto, optsw[sw].auth_level, + (char *) &level, sizeof level) == -1) { + log_error("sysdep_cleartext: " + "setsockopt (%d, %d, IP_AUTH_LEVEL, ...) failed", fd, + optsw[sw].ip_proto); + return -1; + } + if (monitor_setsockopt(fd, optsw[sw].ip_proto, optsw[sw].esp_trans_level, + (char *) &level, sizeof level) == -1) { + log_error("sysdep_cleartext: " + "setsockopt (%d, %d, IP_ESP_TRANS_LEVEL, ...) failed", fd, + optsw[sw].ip_proto); + return -1; + } + if (monitor_setsockopt(fd, optsw[sw].ip_proto, optsw[sw].esp_network_level, + (char *) &level, sizeof level) == -1) { + log_error("sysdep_cleartext: " + "setsockopt (%d, %d, IP_ESP_NETWORK_LEVEL, ...) failed", fd, + optsw[sw].ip_proto); + return -1; + } + if (optsw[sw].ipcomp_level && + monitor_setsockopt(fd, optsw[sw].ip_proto, optsw[sw].ipcomp_level, + (char *) &level, sizeof level) == -1 && + errno != ENOPROTOOPT) { + log_error("sysdep_cleartext: " + "setsockopt (%d, %d, IP_IPCOMP_LEVEL, ...) failed,", fd, + optsw[sw].ip_proto); + return -1; + } + return 0; +} + +int +sysdep_ipsec_delete_spi(struct sa *sa, struct proto *proto, int incoming) +{ + if (app_none) + return 0; + return KEY_API(delete_spi)(sa, proto, incoming); +} + +int +sysdep_ipsec_enable_sa(struct sa *sa, struct sa *isakmp_sa) +{ + if (app_none) + return 0; + return KEY_API(enable_sa)(sa, isakmp_sa); +} + +int +sysdep_ipsec_group_spis(struct sa *sa, struct proto *proto1, + struct proto *proto2, int incoming) +{ + if (app_none) + return 0; + return KEY_API(group_spis)(sa, proto1, proto2, incoming); +} + +int +sysdep_ipsec_set_spi(struct sa *sa, struct proto *proto, int incoming, + struct sa *isakmp_sa) +{ + if (app_none) + return 0; + return KEY_API(set_spi) (sa,proto, incoming, isakmp_sa); +} +#endif diff --git a/keyexchange/isakmpd-20041012/timer.c b/keyexchange/isakmpd-20041012/timer.c new file mode 100644 index 0000000..45bcc49 --- /dev/null +++ b/keyexchange/isakmpd-20041012/timer.c @@ -0,0 +1,139 @@ +/* $OpenBSD: timer.c,v 1.14 2004/06/14 09:55:42 ho Exp $ */ +/* $EOM: timer.c,v 1.13 2000/02/20 19:58:42 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999 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. + * + * 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 "sysdep.h" + +#include "log.h" +#include "timer.h" + +static TAILQ_HEAD(event_list, event) events; + +void +timer_init(void) +{ + 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(void) +{ + struct timeval now; + struct event *n; + + gettimeofday(&now, 0); + for (n = TAILQ_FIRST(&events); n && timercmp(&now, &n->expiration, >=); + n = TAILQ_FIRST(&events)) { + LOG_DBG((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; + struct timeval now; + + if (!ev) + return 0; + ev->name = name; + ev->func = func; + ev->arg = arg; + gettimeofday(&now, 0); + memcpy(&ev->expiration, expiration, sizeof *expiration); + for (n = TAILQ_FIRST(&events); + n && timercmp(expiration, &n->expiration, >=); + n = TAILQ_NEXT(n, link)) + ; + if (n) { + LOG_DBG((LOG_TIMER, 10, + "timer_add_event: event %s(%p) added before %s(%p), " + "expiration in %lds", name, + arg, n->name, n->arg, expiration->tv_sec - now.tv_sec)); + TAILQ_INSERT_BEFORE(n, ev, link); + } else { + LOG_DBG((LOG_TIMER, 10, "timer_add_event: event %s(%p) added " + "last, expiration in %lds", name, arg, + expiration->tv_sec - now.tv_sec)); + TAILQ_INSERT_TAIL(&events, ev, link); + } + return ev; +} + +void +timer_remove_event(struct event *ev) +{ + LOG_DBG((LOG_TIMER, 10, "timer_remove_event: removing event %s(%p)", + ev->name, ev->arg)); + TAILQ_REMOVE(&events, ev, link); + free(ev); +} + +void +timer_report(void) +{ + struct event *ev; + struct timeval now; + + gettimeofday(&now, 0); + + for (ev = TAILQ_FIRST(&events); ev; ev = TAILQ_NEXT(ev, link)) + LOG_DBG((LOG_REPORT, 0, + "timer_report: event %s(%p) scheduled in %d seconds", + (ev->name ? ev->name : "<unknown>"), ev, + (int) (ev->expiration.tv_sec - now.tv_sec))); +} diff --git a/keyexchange/isakmpd-20041012/timer.h b/keyexchange/isakmpd-20041012/timer.h new file mode 100644 index 0000000..2e890a3 --- /dev/null +++ b/keyexchange/isakmpd-20041012/timer.h @@ -0,0 +1,55 @@ +/* $OpenBSD: timer.h,v 1.7 2004/05/23 18:17:56 hshoexer Exp $ */ +/* $EOM: timer.h,v 1.6 1999/04/11 22:35:55 ho Exp $ */ + +/* + * Copyright (c) 1998, 1999 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. + * + * 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 *); +extern void timer_report(void); + +#endif /* _TIMER_H_ */ diff --git a/keyexchange/isakmpd-20041012/transport.c b/keyexchange/isakmpd-20041012/transport.c new file mode 100644 index 0000000..023e819 --- /dev/null +++ b/keyexchange/isakmpd-20041012/transport.c @@ -0,0 +1,431 @@ +/* $OpenBSD: transport.c,v 1.30 2004/08/08 19:11:06 deraadt Exp $ */ +/* $EOM: transport.c,v 1.43 2000/10/10 12:36:39 provos Exp $ */ + +/* + * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2001, 2004 Håkan Olsson. 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. + * + * 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 <string.h> + +#include "sysdep.h" + +#include "conf.h" +#include "exchange.h" +#include "log.h" +#include "message.h" +#include "sa.h" +#include "timer.h" +#include "transport.h" +#include "virtual.h" + +/* If no retransmit limit is given, use this as a default. */ +#define RETRANSMIT_DEFAULT 10 + +LIST_HEAD(transport_list, transport) transport_list; +LIST_HEAD(transport_method_list, transport_vtbl) transport_method_list; + +/* Call the reinit function of the various transports. */ +void +transport_reinit(void) +{ + struct transport_vtbl *method; + + for (method = LIST_FIRST(&transport_method_list); method; + method = LIST_NEXT(method, link)) + if (method->reinit) + method->reinit(); +} + +/* Initialize the transport maintenance module. */ +void +transport_init(void) +{ + LIST_INIT(&transport_list); + LIST_INIT(&transport_method_list); +} + +/* Register another transport T. */ +void +transport_setup(struct transport *t, int toplevel) +{ + if (toplevel) { + /* Only the toplevel (virtual) transport has sendqueues. */ + LOG_DBG((LOG_TRANSPORT, 70, + "transport_setup: virtual transport %p", t)); + TAILQ_INIT(&t->sendq); + TAILQ_INIT(&t->prio_sendq); + t->refcnt = 0; + } else { + /* udp and udp_encap trp goes into the transport list. */ + LOG_DBG((LOG_TRANSPORT, 70, + "transport_setup: added %p to transport list", t)); + LIST_INSERT_HEAD(&transport_list, t, link); + t->refcnt = 1; + } + t->flags = 0; +} + +/* Add a referer to transport T. */ +void +transport_reference(struct transport *t) +{ + t->refcnt++; + LOG_DBG((LOG_TRANSPORT, 95, + "transport_reference: transport %p now has %d references", t, + t->refcnt)); +} + +/* + * Remove a referer from transport T, removing all of T when no referers left. + */ +void +transport_release(struct transport *t) +{ + LOG_DBG((LOG_TRANSPORT, 95, + "transport_release: transport %p had %d references", t, + t->refcnt)); + if (--t->refcnt) + return; + + LOG_DBG((LOG_TRANSPORT, 70, "transport_release: freeing %p", t)); + t->vtbl->remove(t); +} + +void +transport_report(void) +{ + struct virtual_transport *v; + struct transport *t; + struct message *msg; + + for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) { + LOG_DBG((LOG_REPORT, 0, + "transport_report: transport %p flags %x refcnt %d", t, + t->flags, t->refcnt)); + + /* XXX Report sth on the virtual transport? */ + t->vtbl->report(t); + + /* + * This is the reason message_dump_raw lives outside + * message.c. + */ + v = (struct virtual_transport *)t->virtual; + if ((v->encap_is_active && v->encap == t) || + (!v->encap_is_active && v->main == t)) { + for (msg = TAILQ_FIRST(&t->virtual->prio_sendq); msg; + msg = TAILQ_NEXT(msg, link)) + message_dump_raw("udp_report(prio)", msg, + LOG_REPORT); + + for (msg = TAILQ_FIRST(&t->virtual->sendq); msg; + msg = TAILQ_NEXT(msg, link)) + message_dump_raw("udp_report", msg, + LOG_REPORT); + } + } +} + +int +transport_prio_sendqs_empty(void) +{ + struct transport *t; + + for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) + if (TAILQ_FIRST(&t->virtual->prio_sendq)) + return 0; + return 1; +} + +/* 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 (non-toplevel) 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 descriptor 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) +{ + struct transport *t; + int n; + int max = -1; + + for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) + if (t->virtual->flags & TRANSPORT_LISTEN) { + n = t->vtbl->fd_set(t, fds, 1); + if (n > max) + max = n; + + LOG_DBG((LOG_TRANSPORT, 95, "transport_fd_set: " + "transport %p (virtual %p) fd %d", t, + t->virtual, n)); + } + return max + 1; +} + +/* + * Build up a file descriptor 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) +{ + struct transport *t; + int n; + int max = -1; + + for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) { + if (TAILQ_FIRST(&t->virtual->sendq) || + TAILQ_FIRST(&t->virtual->prio_sendq)) { + n = t->vtbl->fd_set(t, fds, 1); + LOG_DBG((LOG_TRANSPORT, 95, + "transport_pending_wfd_set: " + "transport %p (virtual %p) fd %d pending", t, + t->virtual, n)); + 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->virtual->vtbl->handle_message)(t); + (*t->vtbl->fd_set)(t, fds, 0); + } + } +} + +/* + * Send the first queued message on the transports found whose file + * descriptor is in FDS and has messages queued. Remove the fd bit from + * FDS as soon as one message has been sent on it so other transports + * sharing the socket won't get service without an intervening select + * call. Perhaps a fairness strategy should be implemented between + * such transports. Now early transports in the list will potentially + * be favoured to later ones sharing the file descriptor. + */ +void +transport_send_messages(fd_set * fds) +{ + struct transport *t, *next; + struct message *msg; + struct exchange *exchange; + struct timeval expiration; + int expiry, ok_to_drop_message; + + /* + * Reference all transports first so noone will disappear while in + * use. + */ + for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) + transport_reference(t->virtual); + + for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) { + if ((TAILQ_FIRST(&t->virtual->sendq) || + TAILQ_FIRST(&t->virtual->prio_sendq)) && + t->vtbl->fd_isset(t, fds)) { + /* Remove fd bit. */ + t->vtbl->fd_set(t, fds, 0); + + /* Prefer a message from the prioritized sendq. */ + if (TAILQ_FIRST(&t->virtual->prio_sendq)) { + msg = TAILQ_FIRST(&t->virtual->prio_sendq); + TAILQ_REMOVE(&t->virtual->prio_sendq, msg, + link); + } else { + msg = TAILQ_FIRST(&t->virtual->sendq); + TAILQ_REMOVE(&t->virtual->sendq, msg, link); + } + + msg->flags &= ~MSG_IN_TRANSIT; + exchange = msg->exchange; + exchange->in_transit = 0; + + /* + * We disregard the potential error message here, + * hoping that the retransmit will go better. + * XXX Consider a retry/fatal error discriminator. + */ + t->virtual->vtbl->send_message(msg, 0); + msg->xmits++; + + /* + * This piece of code has been proven to be quite + * delicate. Think twice for before altering. + * Here's an outline: + * + * If this message is not the one which finishes an + * exchange, check if we have reached the number of + * retransmit before queuing it up for another. + * + * If it is a finishing message we still may have to + * keep it around for an on-demand retransmit when + * seeing a duplicate of our peer's previous message. + * + */ + if ((msg->flags & MSG_LAST) == 0) { + if (msg->xmits > conf_get_num("General", + "retransmits", RETRANSMIT_DEFAULT)) { + log_print("transport_send_messages: " + "giving up on message %p, " + "exchange %s", msg, + exchange->name ? exchange->name : + "<unnamed>"); + /* Be more verbose here. */ + if (exchange->phase == 1) { + log_print( + "transport_send_messages: " + "either this message did " + "not reach the other " + "peer"); + if (exchange->initiator) + log_print("transport_send_messages: " + "or the response" + "message did not " + "reach us back"); + else + log_print("transport_send_messages: " + "or this is an " + "attempted IKE " + "scan"); + } + exchange->last_sent = 0; +#ifdef notyet + exchange_free(exchange); + exchange = 0; +#endif + } else { + gettimeofday(&expiration, 0); + + /* + * XXX Calculate from round trip + * timings and a backoff func. + */ + expiry = msg->xmits * 2 + 5; + expiration.tv_sec += expiry; + LOG_DBG((LOG_TRANSPORT, 30, + "transport_send_messages: " + "message %p scheduled for " + "retransmission %d in %d secs", + msg, msg->xmits, expiry)); + if (msg->retrans) + timer_remove_event(msg->retrans); + msg->retrans + = timer_add_event("message_send_expire", + (void (*) (void *)) message_send_expire, + msg, &expiration); + /* + * If we cannot retransmit, we + * cannot... + */ + exchange->last_sent = + msg->retrans ? msg : 0; + } + } else + exchange->last_sent = + exchange->last_received ? msg : 0; + + /* + * If this message is not referred to for later + * retransmission it will be ok for us to drop it + * after the post-send function. But as the post-send + * function may remove the exchange, we need to + * remember this fact here. + */ + ok_to_drop_message = exchange->last_sent == 0; + + /* + * 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. Note that a post-send function may take + * away the exchange we belong to, but only if no + * retransmits are possible. + */ + if (msg->xmits == 1) + message_post_send(msg); + + if (ok_to_drop_message) + message_free(msg); + } + } + + for (t = LIST_FIRST(&transport_list); t; t = next) { + next = LIST_NEXT(t, link); + transport_release(t->virtual); + } +} + +/* + * 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/keyexchange/isakmpd-20041012/transport.h b/keyexchange/isakmpd-20041012/transport.h new file mode 100644 index 0000000..0a68c73 --- /dev/null +++ b/keyexchange/isakmpd-20041012/transport.h @@ -0,0 +1,159 @@ +/* $OpenBSD: transport.h,v 1.15 2004/06/20 15:24:05 ho Exp $ */ +/* $EOM: transport.h,v 1.16 2000/07/17 18:57:59 provos Exp $ */ + +/* + * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2001, 2004 Håkan Olsson. 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. + * + * 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> + +#include "message.h" + +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 *); + + /* Reinitialize specific transport. */ + void (*reinit) (void); + + /* Remove a transport instance of this method. */ + void (*remove) (struct transport *); + + /* Report status of given transport */ + void (*report) (struct transport *); + + /* Let the given transport set it's bit in the fd_set passed in. */ + int (*fd_set) (struct transport *, fd_set *, int); + + /* 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 *, struct transport *); + + /* + * Fill out a sockaddr structure with the transport's destination end's + * address info. + */ + void (*get_dst) (struct transport *, struct sockaddr **); + + /* + * Fill out a sockaddr structure with the transport's source end's + * address info. + */ + void (*get_src) (struct transport *, struct sockaddr **); + + /* + * Return a string with decoded src and dst information + */ + char *(*decode_ids) (struct transport *); + + /* + * Clone a transport for outbound use. + */ + struct transport *(*clone) (struct transport *, struct sockaddr *); + + /* + * Locate the correct sendq to use for outbound messages. + */ + struct msg_head *(*get_queue) (struct message *); +}; + +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. */ + struct msg_head sendq; + + /* + * Prioritized send queue. Messages in this queue will be transmitted + * before the normal sendq, they will also all be transmitted prior + * to a daemon shutdown. Currently only used for DELETE notifications. + */ + struct msg_head prio_sendq; + + /* Flags describing the transport. */ + int flags; + + /* Reference counter. */ + int refcnt; + + /* Pointer to parent virtual transport, if any. */ + struct transport *virtual; +}; + +/* Set if this is a transport we want to listen on. */ +#define TRANSPORT_LISTEN 1 +/* Used for mark-and-sweep-type garbage collection of transports */ +#define TRANSPORT_MARK 2 + +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 int transport_prio_sendqs_empty(void); +extern void transport_reference(struct transport *); +extern void transport_reinit(void); +extern void transport_release(struct transport *); +extern void transport_report(void); +extern void transport_send_messages(fd_set *); +extern void transport_setup(struct transport *, int); +#endif /* _TRANSPORT_H_ */ diff --git a/keyexchange/isakmpd-20041012/udp.c b/keyexchange/isakmpd-20041012/udp.c new file mode 100644 index 0000000..090297b --- /dev/null +++ b/keyexchange/isakmpd-20041012/udp.c @@ -0,0 +1,573 @@ +/* $OpenBSD: udp.c,v 1.79 2004/08/08 19:11:06 deraadt Exp $ */ +/* $EOM: udp.c,v 1.57 2001/01/26 10:09:57 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2000 Angelos D. Keromytis. All rights reserved. + * Copyright (c) 2003, 2004 Håkan Olsson. 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. + * + * 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/ioctl.h> +#include <sys/socket.h> +#ifndef linux +#include <sys/sockio.h> +#endif +#include <net/if.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <ctype.h> +#include <err.h> +#include <limits.h> +#include <netdb.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "sysdep.h" + +#include "conf.h" +#include "if.h" +#include "isakmp.h" +#include "log.h" +#include "message.h" +#include "monitor.h" +#include "sysdep.h" +#include "transport.h" +#include "udp.h" +#include "util.h" +#include "virtual.h" + +#define UDP_SIZE 65536 + +/* If a system doesn't have SO_REUSEPORT, SO_REUSEADDR will have to do. */ +#ifndef SO_REUSEPORT +#define SO_REUSEPORT SO_REUSEADDR +#endif + +/* These are reused by udp_encap.c, thus not 'static' here. */ +struct transport *udp_clone(struct transport *, struct sockaddr *); +int udp_fd_set(struct transport *, fd_set *, int); +int udp_fd_isset(struct transport *, fd_set *); +void udp_get_dst(struct transport *, struct sockaddr **); +void udp_get_src(struct transport *, struct sockaddr **); +char *udp_decode_ids(struct transport *); +void udp_remove(struct transport *); + +static struct transport *udp_create(char *); +static void udp_report(struct transport *); +static void udp_handle_message(struct transport *); +static struct transport *udp_make(struct sockaddr *); +static int udp_send_message(struct message *, struct transport *); +#if 0 +static in_port_t udp_decode_port(char *); +#endif + +static struct transport_vtbl udp_transport_vtbl = { + {0}, "udp_physical", + udp_create, + 0, + udp_remove, + udp_report, + udp_fd_set, + udp_fd_isset, + udp_handle_message, + udp_send_message, + udp_get_dst, + udp_get_src, + udp_decode_ids, + udp_clone, + 0 +}; + +char *udp_default_port = 0; +char *udp_bind_port = 0; +int bind_family = 0; + +void +udp_init(void) +{ + transport_method_add(&udp_transport_vtbl); +} + +/* Create a UDP transport structure bound to LADDR just for listening. */ +static struct transport * +udp_make(struct sockaddr *laddr) +{ + struct udp_transport *t = 0; + int s, on, wildcardaddress = 0; + char *tstr; + + t = calloc(1, sizeof *t); + if (!t) { + log_print("udp_make: calloc (1, %lu) failed", + (unsigned long)sizeof *t); + free(laddr); + return 0; + } + t->src = laddr; + + s = socket(laddr->sa_family, SOCK_DGRAM, IPPROTO_UDP); + if (s == -1) { + log_error("udp_make: socket (%d, %d, %d)", laddr->sa_family, + SOCK_DGRAM, IPPROTO_UDP); + goto err; + } + /* Make sure we don't get our traffic encrypted. */ + if (sysdep_cleartext(s, laddr->sa_family) == -1) + goto err; + + /* Wildcard address ? */ + switch (laddr->sa_family) { + case AF_INET: + if (((struct sockaddr_in *)laddr)->sin_addr.s_addr == + INADDR_ANY) + wildcardaddress = 1; + break; + case AF_INET6: + if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)laddr)->sin6_addr)) + wildcardaddress = 1; + break; + } + + /* + * In order to have several bound specific address-port combinations + * with the same port SO_REUSEADDR is needed. If this is a wildcard + * socket and we are not listening there, but only sending from it + * make sure it is entirely reuseable with SO_REUSEPORT. + */ + on = 1; + if (setsockopt(s, SOL_SOCKET, + wildcardaddress ? SO_REUSEPORT : SO_REUSEADDR, + (void *)&on, sizeof on) == -1) { + log_error("udp_make: setsockopt (%d, %d, %d, %p, %lu)", s, + SOL_SOCKET, wildcardaddress ? SO_REUSEPORT : SO_REUSEADDR, + &on, (unsigned long)sizeof on); + goto err; + } + t->transport.vtbl = &udp_transport_vtbl; + if (monitor_bind(s, t->src, sysdep_sa_len(t->src))) { + if (sockaddr2text(t->src, &tstr, 0)) + log_error("udp_make: bind (%d, %p, %lu)", s, &t->src, + (unsigned long)sizeof t->src); + else { + log_error("udp_make: bind (%d, %s, %lu)", s, tstr, + (unsigned long)sizeof t->src); + free(tstr); + } + goto err; + } + t->s = s; + if (sockaddr2text(t->src, &tstr, 0)) + LOG_DBG((LOG_MISC, 20, "udp_make: " + "transport %p socket %d family %d", t, s, + t->src->sa_family == AF_INET ? 4 : 6)); + else { + LOG_DBG((LOG_MISC, 20, "udp_make: " + "transport %p socket %d ip %s port %d", t, s, + tstr, ntohs(sockaddr_port(t->src)))); + free (tstr); + } + transport_setup(&t->transport, 0); + t->transport.flags |= TRANSPORT_LISTEN; + return &t->transport; + +err: + if (s >= 0) + close(s); + if (t) { + /* Already closed. */ + t->s = -1; + udp_remove(&t->transport); + } + return 0; +} + +/* Clone a listen transport U, record a destination RADDR for outbound use. */ +struct transport * +udp_clone(struct transport *ut, struct sockaddr *raddr) +{ + struct udp_transport *u = (struct udp_transport *)ut; + struct udp_transport *u2; + struct transport *t; + + t = malloc(sizeof *u); + if (!t) { + log_error("udp_clone: malloc (%lu) failed", + (unsigned long)sizeof *u); + return 0; + } + u2 = (struct udp_transport *)t; + + memcpy(u2, u, sizeof *u); + + u2->src = malloc(sysdep_sa_len(u->src)); + if (!u2->src) { + log_error("udp_clone: malloc (%d) failed", + sysdep_sa_len(u->src)); + free(t); + return 0; + } + memcpy(u2->src, u->src, sysdep_sa_len(u->src)); + + u2->dst = malloc(sysdep_sa_len(raddr)); + if (!u2->dst) { + log_error("udp_clone: malloc (%d) failed", + sysdep_sa_len(raddr)); + free(u2->src); + free(t); + return 0; + } + memcpy(u2->dst, raddr, sysdep_sa_len(raddr)); + + t->flags &= ~TRANSPORT_LISTEN; + transport_setup(t, 0); + 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. + */ +struct transport * +udp_bind(const struct sockaddr *addr) +{ + struct sockaddr *src; + + src = malloc(sysdep_sa_len((struct sockaddr *)addr)); + if (!src) + return 0; + + memcpy(src, addr, sysdep_sa_len((struct sockaddr *)addr)); + return udp_make(src); +} + +/* + * NAME is a section name found in the config database. Setup and return + * a transport useable to talk to the peer specified by that name. + */ +static struct transport * +udp_create(char *name) +{ + struct virtual_transport *v; + struct udp_transport *u; + struct transport *rv, *t; + struct sockaddr *dst, *addr; + char *addr_str, *port_str; + struct conf_list *addr_list = 0; + struct conf_list_node *addr_node; + + port_str = conf_get_str(name, "Port"); + if (!port_str) + port_str = udp_default_port; + if (!port_str) + port_str = UDP_DEFAULT_PORT_STR; + + addr_str = conf_get_str(name, "Address"); + if (!addr_str) { + log_print("udp_create: no address configured for \"%s\"", + name); + return 0; + } + if (text2sockaddr(addr_str, port_str, &dst)) { + log_print("udp_create: address \"%s\" not understood", + addr_str); + return 0; + } + addr_str = conf_get_str(name, "Local-address"); + if (!addr_str) + addr_list = conf_get_list("General", "Listen-on"); + if (!addr_str && !addr_list) { + v = virtual_get_default(dst->sa_family); + u = (struct udp_transport *)v->main; + + if (!u) { + log_print("udp_create: no default transport"); + rv = 0; + goto ret; + } else { + rv = udp_clone((struct transport *)u, dst); + if (rv) + rv->vtbl = &udp_transport_vtbl; + goto ret; + } + } + + if (addr_list) { + for (addr_node = TAILQ_FIRST(&addr_list->fields); + addr_node; addr_node = TAILQ_NEXT(addr_node, link)) + if (text2sockaddr(addr_node->field, port_str, &addr) + == 0) { + v = virtual_listen_lookup(addr); + free(addr); + if (v) { + addr_str = addr_node->field; + break; + } + } + if (!addr_str) { + log_print("udp_create: no matching listener found"); + rv = 0; + goto ret; + } + } + if (text2sockaddr(addr_str, port_str, &addr)) { + log_print("udp_create: address \"%s\" not understood", + addr_str); + rv = 0; + goto ret; + } + + v = virtual_listen_lookup(addr); + free(addr); + if (!v) { + log_print("udp_create: %s:%s must exist as a listener too", + addr_str, port_str); + rv = 0; + goto ret; + } + t = (struct transport *)v; + rv = udp_clone(v->main, dst); + if (rv) + rv->vtbl = &udp_transport_vtbl; + +ret: + if (addr_list) + conf_free_list(addr_list); + free(dst); + return rv; +} + +void +udp_remove(struct transport *t) +{ + struct udp_transport *u = (struct udp_transport *)t; + + if (u->src) + free(u->src); + if (u->dst) + free(u->dst); + if ((t->flags & TRANSPORT_LISTEN) && u->s >= 0) + close(u->s); + if (t->link.le_prev) + LIST_REMOVE(t, link); + + LOG_DBG((LOG_TRANSPORT, 90, "udp_remove: removed transport %p", t)); + free(t); +} + +/* Report transport-method specifics of the T transport. */ +void +udp_report(struct transport *t) +{ + struct udp_transport *u = (struct udp_transport *)t; + char *src = NULL, *dst = NULL; + in_port_t sport, dport; + + if (sockaddr2text(u->src, &src, 0)) + goto ret; + sport = sockaddr_port(u->src); + + if (!u->dst || sockaddr2text(u->dst, &dst, 0)) + dst = 0; + dport = dst ? sockaddr_port(u->dst) : 0; + + LOG_DBG((LOG_REPORT, 0, "udp_report: fd %d src %s:%u dst %s:%u", u->s, + src, ntohs(sport), dst ? dst : "<none>", ntohs(dport))); + +ret: + if (dst) + free(dst); + if (src) + free(src); +} + +/* + * 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. + */ +static void +udp_handle_message(struct transport *t) +{ + struct udp_transport *u = (struct udp_transport *)t; + u_int8_t buf[UDP_SIZE]; + struct sockaddr_storage from; + u_int32_t 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 = t->virtual->vtbl->clone(t->virtual, (struct sockaddr *)&from); + if (!t) + return; + + msg = message_alloc(t, buf, n); + if (!msg) { + log_error("failed to allocate message structure, dropping " + "packet received on transport %p", u); + t->vtbl->remove(t); + return; + } + message_recv(msg); +} + +/* Physically send the message MSG over its associated transport. */ +static int +udp_send_message(struct message *msg, struct transport *t) +{ + struct udp_transport *u = (struct udp_transport *)t; + 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 = sysdep_sa_len(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) { + /* XXX We should check whether the address has gone away */ + log_error("sendmsg (%d, %p, %d)", u->s, &m, 0); + return -1; + } + return 0; +} + +int +udp_fd_set(struct transport *t, fd_set *fds, int bit) +{ + struct udp_transport *u = (struct udp_transport *)t; + + if (bit) + FD_SET(u->s, fds); + else + FD_CLR(u->s, fds); + + return u->s + 1; +} + +int +udp_fd_isset(struct transport *t, fd_set *fds) +{ + struct udp_transport *u = (struct udp_transport *)t; + + return FD_ISSET(u->s, fds); +} + +/* + * Get transport T's peer address and stuff it into the sockaddr pointed + * to by DST. + */ +void +udp_get_dst(struct transport *t, struct sockaddr **dst) +{ + *dst = ((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. + */ +void +udp_get_src(struct transport *t, struct sockaddr **src) +{ + *src = ((struct udp_transport *)t)->src; +} + +char * +udp_decode_ids(struct transport *t) +{ + struct sockaddr *src, *dst; + static char result[1024]; + char idsrc[256], iddst[256]; + + t->vtbl->get_src(t, &src); + t->vtbl->get_dst(t, &dst); + + if (getnameinfo(src, sysdep_sa_len(src), idsrc, sizeof idsrc, NULL, 0, + NI_NUMERICHOST) != 0) { + log_print("udp_decode_ids: getnameinfo () failed for 'src'"); + strlcpy(idsrc, "<error>", 256); + } + if (getnameinfo(dst, sysdep_sa_len(dst), iddst, sizeof iddst, NULL, 0, + NI_NUMERICHOST) != 0) { + log_print("udp_decode_ids: getnameinfo () failed for 'dst'"); + strlcpy(iddst, "<error>", 256); + } + + snprintf(result, sizeof result, "src: %s dst: %s", idsrc, iddst); + return result; +} + +#if 0 +/* + * Take a string containing an ext representation of port and return a + * binary port number in host byte order. Return zero if anything goes wrong. + * XXX Currently unused. + */ +static in_port_t +udp_decode_port(char *port_str) +{ + char *port_str_end; + long port_long; + struct servent *service; + + port_long = ntohl(strtol(port_str, &port_str_end, 0)); + if (port_str == port_str_end) { + service = getservbyname(port_str, "udp"); + if (!service) { + log_print("udp_decode_port: service \"%s\" unknown", + port_str); + return 0; + } + return ntohs(service->s_port); + } else if (port_long < 1 || port_long > 65535) { + log_print("udp_decode_port: port %ld out of range", port_long); + return 0; + } + return port_long; +} +#endif diff --git a/keyexchange/isakmpd-20041012/udp.h b/keyexchange/isakmpd-20041012/udp.h new file mode 100644 index 0000000..dd91a6c --- /dev/null +++ b/keyexchange/isakmpd-20041012/udp.h @@ -0,0 +1,52 @@ +/* $OpenBSD: udp.h,v 1.10 2004/08/03 10:54:09 ho Exp $ */ +/* $EOM: udp.h,v 1.4 1998/12/22 02:23:43 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. + * + * 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 char *udp_default_port; +extern char *udp_bind_port; +extern int bind_family; + +#define BIND_FAMILY_INET4 0x0001 +#define BIND_FAMILY_INET6 0x0002 + +struct transport *udp_bind(const struct sockaddr *); +void udp_init(void); + +struct udp_transport { + struct transport transport; + struct sockaddr *src; + struct sockaddr *dst; + int s; +}; + +#endif /* _UDP_H_ */ diff --git a/keyexchange/isakmpd-20041012/udp_encap.c b/keyexchange/isakmpd-20041012/udp_encap.c new file mode 100644 index 0000000..92f6404 --- /dev/null +++ b/keyexchange/isakmpd-20041012/udp_encap.c @@ -0,0 +1,473 @@ +/* $OpenBSD: udp_encap.c,v 1.8 2004/09/24 13:31:04 ho Exp $ */ + +/* + * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2000 Angelos D. Keromytis. All rights reserved. + * Copyright (c) 2004 Håkan Olsson. 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. + * + * 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. + */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#ifndef linux +#include <sys/sockio.h> +#endif +#include <net/if.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <ctype.h> +#include <err.h> +#include <limits.h> +#include <netdb.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "sysdep.h" + +#include "conf.h" +#include "if.h" +#include "ipsec_doi.h" +#include "isakmp.h" +#include "log.h" +#include "message.h" +#include "monitor.h" +#include "sysdep.h" +#include "transport.h" +#include "udp.h" +#include "udp_encap.h" +#include "util.h" +#include "virtual.h" + +#define UDP_SIZE 65536 + +#if defined(USE_NAT_TRAVERSAL) && defined (LINUX_IPSEC) +#include <linux/socket.h> +#include <linux/udp.h> +#endif + +/* If a system doesn't have SO_REUSEPORT, SO_REUSEADDR will have to do. */ +#ifndef SO_REUSEPORT +#define SO_REUSEPORT SO_REUSEADDR +#endif + +/* Reused, from udp.c */ +struct transport *udp_clone(struct transport *, struct sockaddr *); +int udp_fd_set(struct transport *, fd_set *, int); +int udp_fd_isset(struct transport *, fd_set *); +void udp_get_dst(struct transport *, struct sockaddr **); +void udp_get_src(struct transport *, struct sockaddr **); +char *udp_decode_ids(struct transport *); +void udp_remove(struct transport *); + +static struct transport *udp_encap_create(char *); +static void udp_encap_report(struct transport *); +static void udp_encap_handle_message(struct transport *); +static struct transport *udp_encap_make(struct sockaddr *); +static int udp_encap_send_message(struct message *, + struct transport *); + +static struct transport_vtbl udp_encap_transport_vtbl = { + { 0 }, "udp_encap", + udp_encap_create, + 0, + udp_remove, + udp_encap_report, + udp_fd_set, + udp_fd_isset, + udp_encap_handle_message, + udp_encap_send_message, + udp_get_dst, + udp_get_src, + udp_decode_ids, + udp_clone, + 0 +}; + +char *udp_encap_default_port = 0; +char *udp_encap_bind_port = 0; + +void +udp_encap_init(void) +{ + transport_method_add(&udp_encap_transport_vtbl); +} + +/* Create a UDP transport structure bound to LADDR just for listening. */ +static struct transport * +udp_encap_make(struct sockaddr *laddr) +{ + struct udp_transport *t = 0; + int s, on, wildcardaddress = 0; + char *tstr; + + t = calloc(1, sizeof *t); + if (!t) { + log_print("udp_encap_make: malloc (%lu) failed", + (unsigned long)sizeof *t); + return 0; + } + + s = socket(laddr->sa_family, SOCK_DGRAM, IPPROTO_UDP); + if (s == -1) { + log_error("udp_encap_make: socket (%d, %d, %d)", + laddr->sa_family, SOCK_DGRAM, IPPROTO_UDP); + goto err; + } + + /* Make sure we don't get our traffic encrypted. */ + if (sysdep_cleartext(s, laddr->sa_family) == -1) + goto err; + +#if defined(USE_NAT_TRAVERSAL) && defined (LINUX_IPSEC) + { +#ifndef SOL_UDP +#define SOL_UDP 17 +#endif + int option = UDP_ENCAP_ESPINUDP; + if(setsockopt(s, SOL_UDP, UDP_ENCAP, &option, + sizeof (option)) < 0) + goto err; + } +#endif + + /* Wildcard address ? */ + switch (laddr->sa_family) { + case AF_INET: + if (((struct sockaddr_in *)laddr)->sin_addr.s_addr + == INADDR_ANY) + wildcardaddress = 1; + break; + case AF_INET6: + if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)laddr)->sin6_addr)) + wildcardaddress = 1; + break; + } + + /* + * In order to have several bound specific address-port combinations + * with the same port SO_REUSEADDR is needed. + * If this is a wildcard socket and we are not listening there, but + * only sending from it make sure it is entirely reuseable with + * SO_REUSEPORT. + */ + on = 1; + if (setsockopt(s, SOL_SOCKET, + wildcardaddress ? SO_REUSEPORT : SO_REUSEADDR, + (void *)&on, sizeof on) == -1) { + log_error("udp_encap_make: setsockopt (%d, %d, %d, %p, %lu)", + s, SOL_SOCKET, + wildcardaddress ? SO_REUSEPORT : SO_REUSEADDR, &on, + (unsigned long)sizeof on); + goto err; + } + + t->transport.vtbl = &udp_encap_transport_vtbl; + t->src = laddr; + if (monitor_bind(s, t->src, sysdep_sa_len (t->src))) { + if (sockaddr2text(t->src, &tstr, 0)) + log_error("udp_encap_make: bind (%d, %p, %lu)", s, + &t->src, (unsigned long)sizeof t->src); + else { + log_error("udp_encap_make: bind (%d, %s, %lu)", s, + tstr, (unsigned long)sizeof t->src); + free(tstr); + } + goto err; + } + + t->s = s; + if (sockaddr2text(t->src, &tstr, 0)) + LOG_DBG((LOG_MISC, 20, "udp_encap_make: " + "transport %p socket %d family %d", t, s, + t->src->sa_family == AF_INET ? 4 : 6)); + else { + LOG_DBG((LOG_MISC, 20, "udp_encap_make: " + "transport %p socket %d ip %s port %d", t, s, + tstr, ntohs(sockaddr_port(t->src)))); + free(tstr); + } + transport_setup(&t->transport, 0); + t->transport.flags |= TRANSPORT_LISTEN; + return &t->transport; + +err: + if (s >= 0) + close (s); + if (t) { + /* Already closed. */ + t->s = -1; + udp_remove(&t->transport); + } + return 0; +} + +/* + * 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. + */ +struct transport * +udp_encap_bind(const struct sockaddr *addr) +{ + struct sockaddr *src = + malloc(sysdep_sa_len((struct sockaddr *)addr)); + + if (!src) + return 0; + + memcpy(src, addr, sysdep_sa_len((struct sockaddr *)addr)); + return udp_encap_make(src); +} + +/* + * NAME is a section name found in the config database. Setup and return + * a transport useable to talk to the peer specified by that name. + */ +static struct transport * +udp_encap_create(char *name) +{ + struct virtual_transport *v; + struct udp_transport *u; + struct transport *rv, *t; + struct sockaddr *dst, *addr; + struct conf_list *addr_list = 0; + struct conf_list_node *addr_node; + char *addr_str, *port_str; + + port_str = conf_get_str(name, "Port"); /* XXX "Encap-port" ? */ + if (!port_str) + port_str = udp_encap_default_port; + if (!port_str) + port_str = UDP_ENCAP_DEFAULT_PORT_STR; + + addr_str = conf_get_str(name, "Address"); + if (!addr_str) { + log_print("udp_encap_create: no address configured " + "for \"%s\"", name); + return 0; + } + if (text2sockaddr(addr_str, port_str, &dst)) { + log_print("udp_encap_create: address \"%s\" not understood", + addr_str); + return 0; + } + + addr_str = conf_get_str(name, "Local-address"); + if (!addr_str) + addr_list = conf_get_list("General", "Listen-on"); + if (!addr_str && !addr_list) { + v = virtual_get_default(dst->sa_family); + u = (struct udp_transport *)v->encap; + + if (!u) { + log_print("udp_encap_create: no default transport"); + rv = 0; + goto ret; + } else { + rv = udp_clone((struct transport *)u, dst); + if (rv) + rv->vtbl = &udp_encap_transport_vtbl; + goto ret; + } + } + + if (addr_list) { + for (addr_node = TAILQ_FIRST(&addr_list->fields); + addr_node; addr_node = TAILQ_NEXT(addr_node, link)) + if (text2sockaddr(addr_node->field, port_str, + &addr) == 0) { + v = virtual_listen_lookup(addr); + free(addr); + if (v) { + addr_str = addr_node->field; + break; + } + } + if (!addr_str) { + log_print("udp_encap_create: " + "no matching listener found"); + rv = 0; + goto ret; + } + } + if (text2sockaddr(addr_str, port_str, &addr)) { + log_print("udp_encap_create: " + "address \"%s\" not understood", addr_str); + rv = 0; + goto ret; + } + v = virtual_listen_lookup(addr); + free(addr); + if (!v) { + log_print("udp_encap_create: " + "%s:%s must exist as a listener too", addr_str, port_str); + rv = 0; + goto ret; + } + t = (struct transport *)v; + rv = udp_clone(v->encap, dst); + if (rv) + rv->vtbl = &udp_encap_transport_vtbl; + +ret: + if (addr_list) + conf_free_list(addr_list); + free(dst); + return rv; +} + +/* Report transport-method specifics of the T transport. */ +void +udp_encap_report(struct transport *t) +{ + struct udp_transport *u = (struct udp_transport *)t; + char *src, *dst; + in_port_t sport, dport; + + if (sockaddr2text(u->src, &src, 0)) + goto ret; + sport = sockaddr_port(u->src); + + if (!u->dst || sockaddr2text(u->dst, &dst, 0)) + dst = 0; + dport = dst ? sockaddr_port(u->dst) : 0; + + LOG_DBG ((LOG_REPORT, 0, "udp_encap_report: fd %d src %s:%u dst %s:%u", + u->s, src, ntohs(sport), dst ? dst : "*", ntohs(dport))); + + ret: + if (dst) + free(dst); + if (src) + free(src); +} + +/* + * 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. + */ +static void +udp_encap_handle_message(struct transport *t) +{ + struct udp_transport *u = (struct udp_transport *)t; + struct sockaddr_storage from; + struct message *msg; + u_int32_t len = sizeof from; + ssize_t n; + u_int8_t buf[UDP_SIZE]; + + 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 = t->virtual->vtbl->clone(t->virtual, (struct sockaddr *)&from); + if (!t) + return; + + /* Check NULL-ESP marker. */ + if (n < (ssize_t)sizeof(u_int32_t) || *(u_int32_t *)buf != 0) { + /* Should never happen. */ + log_print("udp_encap_handle_message: " + "Null-ESP marker not NULL or short message"); + return; + } + + /* NAT-Keepalive messages should not be processed further. */ + n -= sizeof(u_int32_t); + if (n == 1 && buf[sizeof(u_int32_t)] == 0xFF) + return; + + msg = message_alloc(t, buf + sizeof (u_int32_t), n); + if (!msg) { + log_error("failed to allocate message structure, dropping " + "packet received on transport %p", u); + return; + } + message_recv(msg); +} + +/* + * Physically send the message MSG over its associated transport. + * Special: if 'msg' is NULL, send a NAT-T keepalive message. + */ +static int +udp_encap_send_message(struct message *msg, struct transport *t) +{ + struct udp_transport *u = (struct udp_transport *)t; + struct msghdr m; + struct iovec *new_iov = 0, keepalive; + ssize_t n; + u_int32_t marker = 0; /* NULL-ESP Marker */ + + if (msg) { + /* Construct new iov array, prefixing NULL-ESP Marker. */ + new_iov = (struct iovec *)calloc (msg->iovlen + 1, + sizeof *new_iov); + if (!new_iov) { + log_error ("udp_encap_send_message: " + "calloc (%lu, %lu) failed", + (unsigned long)msg->iovlen + 1, + (unsigned long)sizeof *new_iov); + return -1; + } + new_iov[0].iov_base = ▮ + new_iov[0].iov_len = IPSEC_SPI_SIZE; + memcpy (new_iov + 1, msg->iov, msg->iovlen * sizeof *new_iov); + } else { + marker = ~marker; + keepalive.iov_base = ▮ + keepalive.iov_len = 1; + } + + /* + * 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 = sysdep_sa_len (u->dst); + m.msg_iov = msg ? new_iov : &keepalive; + m.msg_iovlen = msg ? msg->iovlen + 1 : 1; + m.msg_control = 0; + m.msg_controllen = 0; + m.msg_flags = 0; + n = sendmsg (u->s, &m, 0); + if (msg) + free (new_iov); + if (n == -1) { + /* XXX We should check whether the address has gone away */ + log_error ("sendmsg (%d, %p, %d)", u->s, &m, 0); + return -1; + } + return 0; +} diff --git a/keyexchange/isakmpd-20041012/udp_encap.h b/keyexchange/isakmpd-20041012/udp_encap.h new file mode 100644 index 0000000..bb08db2 --- /dev/null +++ b/keyexchange/isakmpd-20041012/udp_encap.h @@ -0,0 +1,37 @@ +/* $OpenBSD: udp_encap.h,v 1.1 2004/06/20 15:24:05 ho Exp $ */ + +/* + * Copyright (c) 1998 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2004 Håkan Olsson. 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. + * + * 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. + */ + +#ifndef _UDP_ENCAP_H_ +#define _UDP_ENCAP_H_ + +struct transport *udp_encap_bind (const struct sockaddr *); +void udp_encap_init (void); + +extern char *udp_encap_default_port; +extern char *udp_encap_bind_port; + +#endif /* _UDP_H_ */ diff --git a/keyexchange/isakmpd-20041012/ui.c b/keyexchange/isakmpd-20041012/ui.c new file mode 100644 index 0000000..7167873 --- /dev/null +++ b/keyexchange/isakmpd-20041012/ui.c @@ -0,0 +1,528 @@ +/* $OpenBSD: ui.c,v 1.42 2004/08/08 19:11:06 deraadt Exp $ */ +/* $EOM: ui.c,v 1.43 2000/10/05 09:25:12 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999, 2000 Niklas Hallqvist. All rights reserved. + * Copyright (c) 1999, 2000, 2001, 2002 Håkan Olsson. 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. + * + * 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> +#include <errno.h> + +#include "sysdep.h" + +#include "conf.h" +#include "connection.h" +#include "doi.h" +#include "exchange.h" +#include "init.h" +#include "isakmp.h" +#include "log.h" +#include "monitor.h" +#include "sa.h" +#include "timer.h" +#include "transport.h" +#include "ui.h" +#include "util.h" + +#define BUF_SZ 256 + +/* from isakmpd.c */ +void daemon_shutdown_now(int); + +/* Report all SA configuration information. */ +void ui_report_sa(char *); + +static FILE *ui_open_result(void); + +char *ui_fifo = FIFO; +int ui_socket; +struct event *ui_cr_event = NULL; + +/* Create and open the FIFO used for user control. */ +void +ui_init(void) +{ + struct stat st; + + /* -f- means control messages comes in via stdin. */ + if (strcmp(ui_fifo, "-") == 0) { + ui_socket = 0; + return; + } + + /* Don't overwrite a file, i.e '-f /etc/isakmpd/isakmpd.conf'. */ + if (lstat(ui_fifo, &st) == 0) { + if ((st.st_mode & S_IFMT) == S_IFREG) { + errno = EEXIST; + log_fatal("ui_init: could not create FIFO \"%s\"", + ui_fifo); + } + } + + /* No need to know about errors. */ + unlink(ui_fifo); + if (mkfifo(ui_fifo, 0600) == -1) + log_fatal("ui_init: mkfifo (\"%s\", 0600) failed", ui_fifo); + + ui_socket = open(ui_fifo, O_RDWR | O_NONBLOCK, 0); + if (ui_socket == -1) + log_fatal("ui_init: open (\"%s\", O_RDWR | O_NONBLOCK, 0) " + "failed", ui_fifo); +} + +/* + * Setup a phase 2 connection. + * XXX Maybe phase 1 works too, but teardown won't work then, fix? + */ +static void +ui_connect(char *cmd) +{ + char name[81]; + + if (sscanf(cmd, "c %80s", name) != 1) { + log_print("ui_connect: command \"%s\" malformed", cmd); + return; + } + LOG_DBG((LOG_UI, 10, "ui_connect: setup connection \"%s\"", name)); + connection_setup(name); +} + +/* Tear down a phase 2 connection. */ +static void +ui_teardown(char *cmd) +{ + char name[81]; + struct sa *sa; + + if (sscanf(cmd, "t %80s", name) != 1) { + log_print("ui_teardown: command \"%s\" malformed", cmd); + return; + } + LOG_DBG((LOG_UI, 10, "ui_teardown: teardown connection \"%s\"", name)); + connection_teardown(name); + while ((sa = sa_lookup_by_name(name, 2)) != 0) + sa_delete(sa, 1); +} + +/* Tear down all phase 2 connections. */ +static void +ui_teardown_all(char *cmd) +{ + /* Skip 'cmd' as arg. */ + sa_teardown_all(); +} + +static void +ui_conn_reinit_event(void *v) +{ + /* + * This event is required for isakmpd to reinitialize the connection + * and passive-connection lists. Otherwise a change to the + * "[Phase 2]:Connections" tag will not have any effect. + */ + connection_reinit(); + + ui_cr_event = NULL; +} + +static void +ui_conn_reinit(void) +{ + struct timeval tv; + + if (ui_cr_event) + timer_remove_event(ui_cr_event); + + gettimeofday(&tv, 0); + tv.tv_sec += 5; + + ui_cr_event = timer_add_event("ui_conn_reinit", ui_conn_reinit_event, + 0, &tv); + if (!ui_cr_event) + log_print("ui_conn_reinit: timer_add_event() failed. " + "Connections will not be updated."); +} + +/* + * Call the configuration API. + * XXX Error handling! How to do multi-line transactions? Too short arbitrary + * limit on the parameters? + */ +static void +ui_config(char *cmd) +{ + char subcmd[81], section[81], tag[81], value[81], tmp[81]; + char *v, *nv; + int trans = 0, items, nvlen; + FILE *fd; + + if (sscanf(cmd, "C %80s", subcmd) != 1) + goto fail; + + if (strcasecmp(subcmd, "get") == 0) { + if (sscanf(cmd, "C %*s [%80[^]]]:%80s", section, tag) != 2) + goto fail; + v = conf_get_str(section, tag); + fd = ui_open_result(); + if (fd) { + if (v) + fprintf(fd, "%s\n", v); + fclose(fd); + } + LOG_DBG((LOG_UI, 30, "ui_config: \"%s\"", cmd)); + return; + } + + trans = conf_begin(); + if (strcasecmp(subcmd, "set") == 0) { + items = sscanf(cmd, "C %*s [%80[^]]]:%80[^=]=%80s %80s", + section, tag, value, tmp); + if (!(items == 3 || items == 4)) + goto fail; + conf_set(trans, section, tag, value, items == 4 ? 1 : 0, 0); + if (strcasecmp(section, "Phase 2") == 0 && + (strcasecmp(tag, "Connections") == 0 || + strcasecmp(tag, "Passive-connections") == 0)) + ui_conn_reinit(); + } else if (strcasecmp(subcmd, "add") == 0) { + items = sscanf(cmd, "C %*s [%80[^]]]:%80[^=]=%80s %80s", + section, tag, value, tmp); + if (!(items == 3 || items == 4)) + goto fail; + v = conf_get_str(section, tag); + if (!v) + conf_set(trans, section, tag, value, 1, 0); + else { + /* Add the new value to the end of the 'v' list. */ + nvlen = strlen(v) + strlen(value) + 2; + nv = (char *)malloc(nvlen); + if (!nv) { + log_error("ui_config: malloc(%d) failed", + nvlen); + if (trans) + conf_end(trans, 0); + return; + } + snprintf(nv, nvlen, + v[strlen(v) - 1] == ',' ? "%s%s" : "%s,%s", v, + value); + conf_set(trans, section, tag, nv, 1, 0); + free(nv); + } + if (strcasecmp(section, "Phase 2") == 0 && + (strcasecmp(tag, "Connections") == 0 || + strcasecmp(tag, "Passive-connections") == 0)) + ui_conn_reinit(); + } else if (strcasecmp(subcmd, "rm") == 0) { + if (sscanf(cmd, "C %*s [%80[^]]]:%80s", section, tag) != 2) + goto fail; + conf_remove(trans, section, tag); + } else if (strcasecmp(subcmd, "rms") == 0) { + if (sscanf(cmd, "C %*s [%80[^]]]", section) != 1) + goto fail; + conf_remove_section(trans, section); + } else + goto fail; + + LOG_DBG((LOG_UI, 30, "ui_config: \"%s\"", cmd)); + conf_end(trans, 1); + return; + +fail: + if (trans) + conf_end(trans, 0); + log_print("ui_config: command \"%s\" malformed", cmd); +} + +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; + } + LOG_DBG((LOG_UI, 20, + "ui_delete: deleting SA for cookie \"%s\" msgid \"%s\"", + cookies_str, message_id_str)); + sa_delete(sa, 1); +} + +#ifdef USE_DEBUG +/* Parse the debug command found in CMD. */ +static void +ui_debug(char *cmd) +{ + int cls, level; + char subcmd[3]; + + if (sscanf(cmd, "D %d %d", &cls, &level) == 2) { + log_debug_cmd(cls, level); + return; + } else if (sscanf(cmd, "D %2s %d", subcmd, &level) == 2) { + switch (subcmd[0]) { + case 'A': + for (cls = 0; cls < LOG_ENDCLASS; cls++) + log_debug_cmd(cls, level); + return; + } + } else if (sscanf(cmd, "D %2s", subcmd) == 1) { + switch (subcmd[0]) { + case 'T': + log_debug_toggle(); + return; + } + } + log_print("ui_debug: command \"%s\" malformed", cmd); + return; +} + +static void +ui_packetlog(char *cmd) +{ + char subcmd[81]; + + if (sscanf(cmd, "p %80s", subcmd) != 1) + goto fail; + + if (strncasecmp(subcmd, "on=", 3) == 0) { + /* Start capture to a new file. */ + if (subcmd[strlen(subcmd) - 1] == '\n') + subcmd[strlen(subcmd) - 1] = 0; + log_packet_restart(subcmd + 3); + } else if (strcasecmp(subcmd, "on") == 0) + log_packet_restart(NULL); + else if (strcasecmp(subcmd, "off") == 0) + log_packet_stop(); + return; + +fail: + log_print("ui_packetlog: command \"%s\" malformed", cmd); +} +#endif /* USE_DEBUG */ + +static void +ui_shutdown_daemon(char *cmd) +{ + if (strlen(cmd) == 1) { + log_print("ui_shutdown_daemon: received shutdown command"); + daemon_shutdown_now(0); + } else + log_print("ui_shutdown_daemon: command \"%s\" malformed", cmd); +} + +/* Report SAs and ongoing exchanges. */ +void +ui_report(char *cmd) +{ + /* XXX Skip 'cmd' as arg? */ + sa_report(); + exchange_report(); + transport_report(); + connection_report(); + timer_report(); + conf_report(); +} + +/* Report all SA configuration information. */ +void +ui_report_sa(char *cmd) +{ + /* Skip 'cmd' as arg? */ + + FILE *fd = ui_open_result(); + if (!fd) + return; + + sa_report_all(fd); + + fclose(fd); +} + +/* + * 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 'C': + ui_config(line); + break; + + case 'd': + ui_delete(line); + break; + +#ifdef USE_DEBUG + case 'D': + ui_debug(line); + break; + + case 'p': + ui_packetlog(line); + break; +#endif + + case 'Q': + ui_shutdown_daemon(line); + break; + + case 'R': + reinit(); + break; + + case 'S': + ui_report_sa(line); + break; + + case 'r': + ui_report(line); + break; + + case 't': + ui_teardown(line); + break; + + case 'T': + ui_teardown_all(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(void) +{ + static char *buf = 0; + static char *p; + static size_t sz; + static size_t resid; + ssize_t n; + char *new_buf; + + /* If no buffer, set it up. */ + if (!buf) { + sz = BUF_SZ; + buf = malloc(sz); + if (!buf) { + log_print("ui_handler: malloc (%lu) failed", + (unsigned long)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("ui_handler: realloc (%p, %lu) failed", buf, + (unsigned long)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("ui_handler: read (%d, %p, %lu)", ui_socket, p, + (unsigned long)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++; + } +} + +static FILE * +ui_open_result(void) +{ + FILE *fd = monitor_fopen(RESULT_FILE, "w"); + if (!fd) + log_error("ui_open_result: fopen() failed"); + return fd; +} diff --git a/keyexchange/isakmpd-20041012/ui.h b/keyexchange/isakmpd-20041012/ui.h new file mode 100644 index 0000000..db9de7f --- /dev/null +++ b/keyexchange/isakmpd-20041012/ui.h @@ -0,0 +1,45 @@ +/* $OpenBSD: ui.h,v 1.7 2004/05/13 06:56:34 ho Exp $ */ +/* $EOM: ui.h,v 1.5 1998/12/01 10:20:12 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. + * + * 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" +#define RESULT_FILE "/var/run/isakmpd.result" + +extern char *ui_fifo; +extern int ui_socket; + +extern void ui_handler(void); +extern void ui_init(void); +extern void ui_report(char *); + +#endif /* _UI_H_ */ diff --git a/keyexchange/isakmpd-20041012/util.c b/keyexchange/isakmpd-20041012/util.c new file mode 100644 index 0000000..6504cb2 --- /dev/null +++ b/keyexchange/isakmpd-20041012/util.c @@ -0,0 +1,485 @@ +/* $OpenBSD: util.c,v 1.48 2004/08/08 19:11:06 deraadt Exp $ */ +/* $EOM: util.c,v 1.23 2000/11/23 12:22:08 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2000, 2001, 2004 Håkan Olsson. 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. + * + * 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 <sys/stat.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <limits.h> +#include <netdb.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +#include "sysdep.h" + +#include "log.h" +#include "message.h" +#include "monitor.h" +#include "sysdep.h" +#include "transport.h" +#include "util.h" + +/* + * Set if -N is given, allowing name lookups to be done, possibly stalling + * the daemon for quite a while. + */ +int allow_name_lookups = 0; + +/* + * This is set to true in case of regression-test mode, when it will + * cause predictable random numbers be generated. + */ +int regrand = 0; + +/* + * If in regression-test mode, this is the seed used. + */ +u_long seed; + +/* + * 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]; +} + +u_int64_t +decode_64(u_int8_t *cp) +{ + return (u_int64_t) cp[0] << 56 | (u_int64_t) cp[1] << 48 | + (u_int64_t) cp[2] << 40 | (u_int64_t) cp[3] << 32 | + cp[4] << 24 | cp[5] << 16 | cp[6] << 8 | cp[7]; +} + +#if 0 +/* + * XXX I severly doubt that we will need this. IPv6 does not have the legacy + * of representation in host byte order, AFAIK. + */ + +void +decode_128(u_int8_t *cp, u_int8_t *cpp) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + int i; + + for (i = 0; i < 16; i++) + cpp[i] = cp[15 - i]; +#elif BYTE_ORDER == BIG_ENDIAN + bcopy(cp, cpp, 16); +#else +#error "Byte order unknown!" +#endif +} +#endif + +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; +} + +void +encode_64(u_int8_t *cp, u_int64_t x) +{ + *cp++ = x >> 56; + *cp++ = (x >> 48) & 0xff; + *cp++ = (x >> 40) & 0xff; + *cp++ = (x >> 32) & 0xff; + *cp++ = (x >> 24) & 0xff; + *cp++ = (x >> 16) & 0xff; + *cp++ = (x >> 8) & 0xff; + *cp = x & 0xff; +} + +#if 0 +/* + * XXX I severly doubt that we will need this. IPv6 does not have the legacy + * of representation in host byte order, AFAIK. + */ + +void +encode_128(u_int8_t *cp, u_int8_t *cpp) +{ + decode_128(cpp, cp); +} +#endif + +/* 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; +} + +/* Check a buffer for all ones. */ +int +ones_test(const u_int8_t *p, size_t sz) +{ + while (sz-- > 0) + if (*p++ != 0xff) + 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; + size_t 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) +{ + u_int8_t *bp; + char *p; + 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; +} + +int +text2sockaddr(char *address, char *port, struct sockaddr **sa) +{ + struct addrinfo *ai, hints; + + memset(&hints, 0, sizeof hints); + if (!allow_name_lookups) + hints.ai_flags = AI_NUMERICHOST; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + + if (getaddrinfo(address, port, &hints, &ai)) + return -1; + + *sa = malloc(sysdep_sa_len(ai->ai_addr)); + if (!*sa) { + freeaddrinfo(ai); + return -1; + } + + memcpy(*sa, ai->ai_addr, sysdep_sa_len(ai->ai_addr)); + freeaddrinfo(ai); + return 0; +} + +/* + * Convert a sockaddr to text. With zflag non-zero fill out with zeroes, + * i.e 10.0.0.10 --> "010.000.000.010" + */ +int +sockaddr2text(struct sockaddr *sa, char **address, int zflag) +{ + char buf[NI_MAXHOST], *token, *bstart, *ep; + int addrlen, i, j; + long val; + + if (getnameinfo(sa, sysdep_sa_len(sa), buf, sizeof buf, 0, 0, + allow_name_lookups ? 0 : NI_NUMERICHOST)) + return -1; + + if (zflag == 0) { + *address = strdup(buf); + if (!*address) + return -1; + } else + switch (sa->sa_family) { + case AF_INET: + addrlen = sizeof "000.000.000.000"; + *address = malloc(addrlen); + if (!*address) + return -1; + buf[addrlen] = '\0'; + bstart = buf; + **address = '\0'; + while ((token = strsep(&bstart, ".")) != NULL) { + if (strlen(*address) > 12) { + free(*address); + return -1; + } + val = strtol(token, &ep, 10); + if (ep == token || val < (long)0 || + val > (long)UCHAR_MAX) { + free(*address); + return -1; + } + snprintf(*address + strlen(*address), + addrlen - strlen(*address), "%03ld", val); + if (bstart) + strlcat(*address, ".", addrlen); + } + break; + + case AF_INET6: + /* + * XXX In the algorithm below there are some magic + * numbers we probably could give explaining names. + */ + addrlen = + sizeof "0000:0000:0000:0000:0000:0000:0000:0000"; + *address = malloc(addrlen); + if (!*address) + return -1; + + for (i = 0, j = 0; i < 8; i++) { + snprintf((*address) + j, addrlen - j, + "%02x%02x", + ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[2*i], + ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[2*i + 1]); + j += 4; + (*address)[j] = + (j < (addrlen - 1)) ? ':' : '\0'; + j++; + } + break; + + default: + *address = strdup("<error>"); + if (!*address) + return -1; + } + + return 0; +} + +/* + * sockaddr_addrlen and sockaddr_addrdata return the relevant sockaddr info + * depending on address family. Useful to keep other code shorter(/clearer?). + */ +int +sockaddr_addrlen(struct sockaddr *sa) +{ + switch (sa->sa_family) { + case AF_INET6: + return sizeof((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr; + case AF_INET: + return sizeof((struct sockaddr_in *)sa)->sin_addr.s_addr; + default: + log_print("sockaddr_addrlen: unsupported protocol family %d", + sa->sa_family); + return 0; + } +} + +u_int8_t * +sockaddr_addrdata(struct sockaddr *sa) +{ + switch (sa->sa_family) { + case AF_INET6: + return (u_int8_t *)&((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr; + case AF_INET: + return (u_int8_t *)&((struct sockaddr_in *)sa)->sin_addr.s_addr; + default: + log_print("sockaddr_addrdata: unsupported protocol family %d", + sa->sa_family); + return 0; + } +} + +in_port_t +sockaddr_port(struct sockaddr *sa) +{ + switch (sa->sa_family) { + case AF_INET6: + return ((struct sockaddr_in6 *)sa)->sin6_port; + case AF_INET: + return ((struct sockaddr_in *)sa)->sin_port; + default: + log_print("sockaddr_port: unsupported protocol family %d", + sa->sa_family); + return 0; + } +} + +/* Utility function used to set the port of a sockaddr. */ +void +sockaddr_set_port(struct sockaddr *sa, in_port_t port) +{ + switch (sa->sa_family) { + case AF_INET: + ((struct sockaddr_in *)sa)->sin_port = htons (port); + break; + + case AF_INET6: + ((struct sockaddr_in6 *)sa)->sin6_port = htons (port); + break; + } +} + +/* + * Convert network address to text. The network address does not need + * to be properly aligned. + */ +void +util_ntoa(char **buf, int af, u_int8_t *addr) +{ + struct sockaddr_storage from; + struct sockaddr *sfrom = (struct sockaddr *) & from; + socklen_t fromlen = sizeof from; + + memset(&from, 0, fromlen); + sfrom->sa_family = af; +#ifndef USE_OLD_SOCKADDR + switch (af) { + case AF_INET: + sfrom->sa_len = sizeof(struct sockaddr_in); + break; + case AF_INET6: + sfrom->sa_len = sizeof(struct sockaddr_in6); + break; + } +#endif + memcpy(sockaddr_addrdata(sfrom), addr, sockaddr_addrlen(sfrom)); + + if (sockaddr2text(sfrom, buf, 0)) { + log_print("util_ntoa: could not make printable address out " + "of sockaddr %p", sfrom); + *buf = 0; + } +} + +/* + * Perform sanity check on files containing secret information. + * Returns -1 on failure, 0 otherwise. + * Also, if FILE_SIZE is a not a null pointer, store file size here. + */ + +int +check_file_secrecy_fd(int fd, char *name, size_t *file_size) +{ + struct stat st; + + if (fstat(fd, &st) == -1) { + log_error("check_file_secrecy: stat (\"%s\") failed", name); + return -1; + } + if (st.st_uid != 0 && st.st_uid != getuid()) { + log_print("check_file_secrecy_fd: " + "not loading %s - file owner is not process user", name); + errno = EPERM; + return -1; + } + if ((st.st_mode & (S_IRWXG | S_IRWXO)) != 0) { + log_print("check_file_secrecy_fd: not loading %s - too open " + "permissions", name); + errno = EPERM; + return -1; + } + if (file_size) + *file_size = (size_t)st.st_size; + + return 0; +} + +/* Special for compiling with Boehms GC. See Makefile and sysdep.h */ +#if defined (USE_BOEHM_GC) +char * +gc_strdup(const char *x) +{ + char *strcpy(char *,const char *); + char *y = malloc(strlen(x) + 1); + return strcpy(y,x); +} +#endif diff --git a/keyexchange/isakmpd-20041012/util.h b/keyexchange/isakmpd-20041012/util.h new file mode 100644 index 0000000..b370ff2 --- /dev/null +++ b/keyexchange/isakmpd-20041012/util.h @@ -0,0 +1,70 @@ +/* $OpenBSD: util.h,v 1.21 2004/06/23 03:01:53 hshoexer Exp $ */ +/* $EOM: util.h,v 1.10 2000/10/24 13:33:39 niklas Exp $ */ + +/* + * Copyright (c) 1998 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2001, 2004 Håkan Olsson. 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. + * + * 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> + +extern int allow_name_lookups; +extern int regrand; +extern unsigned long seed; + +struct message; +struct sockaddr; + +extern int check_file_secrecy_fd(int, char *, size_t *); +extern u_int16_t decode_16(u_int8_t *); +extern u_int32_t decode_32(u_int8_t *); +extern u_int64_t decode_64(u_int8_t *); +#if 0 +extern void decode_128(u_int8_t *, u_int8_t *); +#endif +extern void encode_16(u_int8_t *, u_int16_t); +extern void encode_32(u_int8_t *, u_int32_t); +extern void encode_64(u_int8_t *, u_int64_t); +#if 0 +extern void encode_128(u_int8_t *, u_int8_t *); +#endif +extern u_int8_t *getrandom(u_int8_t *, size_t); +extern int hex2raw(char *, u_int8_t *, size_t); +extern int ones_test(const u_int8_t *, size_t); +extern int sockaddr2text(struct sockaddr *, char **, int); +extern u_int8_t *sockaddr_addrdata(struct sockaddr *); +extern int sockaddr_addrlen(struct sockaddr *); +extern in_port_t sockaddr_port(struct sockaddr *); +extern void sockaddr_set_port(struct sockaddr *, in_port_t); +extern int text2sockaddr(char *, char *, struct sockaddr **); +extern void util_ntoa(char **, int, u_int8_t *); +extern int zero_test(const u_int8_t *, size_t); + +#endif /* _UTIL_H_ */ diff --git a/keyexchange/isakmpd-20041012/virtual.c b/keyexchange/isakmpd-20041012/virtual.c new file mode 100644 index 0000000..d6132fe --- /dev/null +++ b/keyexchange/isakmpd-20041012/virtual.c @@ -0,0 +1,722 @@ +/* $OpenBSD: virtual.c,v 1.9 2004/09/20 21:36:50 hshoexer Exp $ */ + +/* + * Copyright (c) 2004 Håkan Olsson. 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. + * + * 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. + */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#ifndef linux +#include <sys/sockio.h> +#endif +#include <net/if.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <ctype.h> +#include <err.h> +#include <limits.h> +#include <netdb.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "conf.h" +#include "if.h" +#include "exchange.h" +#include "log.h" +#include "transport.h" +#include "virtual.h" +#include "udp.h" +#include "util.h" + +#if defined (USE_NAT_TRAVERSAL) +#include "udp_encap.h" +#endif + +static struct transport *virtual_bind(const struct sockaddr *); +static struct transport *virtual_bind_ADDR_ANY(sa_family_t); +static int virtual_bind_if(char *, struct sockaddr *, void *); +static struct transport *virtual_clone(struct transport *, struct sockaddr *); +static struct transport *virtual_create(char *); +static char *virtual_decode_ids (struct transport *); +static void virtual_get_dst(struct transport *, + struct sockaddr **); +static struct msg_head *virtual_get_queue(struct message *); +static void virtual_get_src(struct transport *, + struct sockaddr **); +static void virtual_handle_message(struct transport *); +static void virtual_reinit(void); +static void virtual_remove(struct transport *); +static void virtual_report(struct transport *); +static int virtual_send_message(struct message *, + struct transport *); + +static struct transport_vtbl virtual_transport_vtbl = { + { 0 }, "udp", + virtual_create, + virtual_reinit, + virtual_remove, + virtual_report, + 0, + 0, + virtual_handle_message, + virtual_send_message, + virtual_get_dst, + virtual_get_src, + virtual_decode_ids, + virtual_clone, + virtual_get_queue +}; + +static LIST_HEAD (virtual_listen_list, virtual_transport) virtual_listen_list; +static struct transport *default_transport, *default_transport6; + +void +virtual_init(void) +{ + struct conf_list *listen_on; + + LIST_INIT(&virtual_listen_list); + + transport_method_add(&virtual_transport_vtbl); + + /* Bind the ISAKMP port(s) on all network interfaces we have. */ + if (if_map(virtual_bind_if, 0) == -1) + log_fatal("virtual_init: " + "could not bind the ISAKMP port(s) on all interfaces"); + + /* Only listen to the specified address if Listen-on is configured */ + listen_on = conf_get_list("General", "Listen-on"); + if (listen_on) { + LOG_DBG((LOG_TRANSPORT, 50, + "virtual_init: not binding ISAKMP port(s) to ADDR_ANY")); + conf_free_list(listen_on); + return; + } + + /* + * Bind to INADDR_ANY in case of new addresses popping up. + * Packet reception on this transport is taken as a hint to reprobe the + * interface list. + */ + if (!bind_family || (bind_family & BIND_FAMILY_INET4)) { + default_transport = virtual_bind_ADDR_ANY(AF_INET); + if (!default_transport) + return; + LIST_INSERT_HEAD(&virtual_listen_list, + (struct virtual_transport *)default_transport, link); + transport_reference(default_transport); + } + + if (!bind_family || (bind_family & BIND_FAMILY_INET6)) { + default_transport6 = virtual_bind_ADDR_ANY(AF_INET6); + if (!default_transport6) + return; + LIST_INSERT_HEAD(&virtual_listen_list, + (struct virtual_transport *)default_transport6, link); + transport_reference(default_transport6); + } + + return; +} + +struct virtual_transport * +virtual_get_default(sa_family_t af) +{ + switch (af) { + case AF_INET: + return (struct virtual_transport *)default_transport; + case AF_INET6: + return (struct virtual_transport *)default_transport6; + default: + return 0; + } +} + +/* + * Probe the interface list and determine what new interfaces have + * appeared. + * + * At the same time, we try to determine whether existing interfaces have + * been rendered invalid; we do this by marking all virtual transports before + * we call virtual_bind_if () through if_map (), and then releasing those + * transports that have not been unmarked. + */ +void +virtual_reinit(void) +{ + struct virtual_transport *v, *v2; + + /* Mark all UDP transports, except the default ones. */ + for (v = LIST_FIRST(&virtual_listen_list); v; v = LIST_NEXT(v, link)) + if (&v->transport != default_transport + && &v->transport != default_transport6) + v->transport.flags |= TRANSPORT_MARK; + + /* Re-probe interface list. */ + if (if_map(virtual_bind_if, 0) == -1) + log_print("virtual_init: " + "could not bind the ISAKMP port(s) on all interfaces"); + + /* + * Release listening transports for local addresses that no + * longer exist. virtual_bind_if () will have left those still marked. + */ + v = LIST_FIRST(&virtual_listen_list); + while (v) { + v2 = LIST_NEXT(v, link); + if (v->transport.flags & TRANSPORT_MARK) { + LIST_REMOVE(v, link); + transport_release(&v->transport); + } + v = v2; + } +} + +struct virtual_transport * +virtual_listen_lookup(struct sockaddr *addr) +{ + struct virtual_transport *v; + struct udp_transport *u; + + for (v = LIST_FIRST(&virtual_listen_list); v; + v = LIST_NEXT(v, link)) { + if (!(u = (struct udp_transport *)v->main)) + if (!(u = (struct udp_transport *)v->encap)) { + log_print("virtual_listen_lookup: " + "virtual %p has no low-level transports", + v); + continue; + } + + if (u->src->sa_family == addr->sa_family + && sockaddr_addrlen(u->src) == sockaddr_addrlen(addr) + && memcmp(sockaddr_addrdata (u->src), + sockaddr_addrdata(addr), + sockaddr_addrlen(addr)) == 0) + return v; + } + + LOG_DBG((LOG_TRANSPORT, 40, "virtual_listen_lookup: no match")); + return 0; +} + +/* + * Initialize an object of the VIRTUAL transport class. + */ +static struct transport * +virtual_bind(const struct sockaddr *addr) +{ + struct virtual_transport *v; + struct sockaddr_storage tmp_sa; + char *port; + char *ep; + long lport; + + v = (struct virtual_transport *)calloc(1, sizeof *v); + if (!v) { + log_error("virtual_bind: calloc(1, %lu) failed", + (unsigned long)sizeof *v); + return 0; + } + + v->transport.vtbl = &virtual_transport_vtbl; + + memcpy(&tmp_sa, addr, sysdep_sa_len((struct sockaddr *)addr)); + + /* + * Get port. + * XXX Use getservbyname too. + */ + port = udp_default_port ? udp_default_port : UDP_DEFAULT_PORT_STR; + lport = strtol(port, &ep, 10); + if (*ep != '\0' || lport < 0 || lport > (long)USHRT_MAX) { + log_print("virtual_bind: " + "port string \"%s\" not convertible to in_port_t", port); + free(v); + return 0; + } + + sockaddr_set_port((struct sockaddr *)&tmp_sa, (in_port_t)lport); + v->main = udp_bind((struct sockaddr *)&tmp_sa); + if (!v->main) { + free(v); + return 0; + } + ((struct transport *)v->main)->virtual = (struct transport *)v; + +#if defined (USE_NAT_TRAVERSAL) + memcpy(&tmp_sa, addr, sysdep_sa_len((struct sockaddr *)addr)); + + /* + * Get port. + * XXX Use getservbyname too. + */ + port = udp_encap_default_port + ? udp_encap_default_port : UDP_ENCAP_DEFAULT_PORT_STR; + lport = strtol(port, &ep, 10); + if (*ep != '\0' || lport < 0 || lport > (long)USHRT_MAX) { + log_print("virtual_bind: " + "port string \"%s\" not convertible to in_port_t", port); + v->main->vtbl->remove(v->main); + free(v); + return 0; + } + + sockaddr_set_port((struct sockaddr *)&tmp_sa, (in_port_t)lport); + v->encap = udp_encap_bind((struct sockaddr *)&tmp_sa); + if (!v->encap) { + v->main->vtbl->remove(v->main); + free(v); + return 0; + } + ((struct transport *)v->encap)->virtual = (struct transport *)v; +#endif + v->encap_is_active = 0; + + transport_setup(&v->transport, 1); + v->transport.flags |= TRANSPORT_LISTEN; + + return (struct transport *)v; +} + +static struct transport * +virtual_bind_ADDR_ANY(sa_family_t af) +{ + struct sockaddr_storage dflt_stor; + struct sockaddr_in *d4 = (struct sockaddr_in *)&dflt_stor; + struct sockaddr_in6 *d6 = (struct sockaddr_in6 *)&dflt_stor; + struct transport *t; + struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; + + memset(&dflt_stor, 0, sizeof dflt_stor); + switch (af) { + case AF_INET: + d4->sin_family = af; +#if !defined (LINUX_IPSEC) + d4->sin_len = sizeof(struct sockaddr_in); +#endif + d4->sin_addr.s_addr = INADDR_ANY; + break; + + case AF_INET6: + d6->sin6_family = af; +#if !defined (LINUX_IPSEC) + d6->sin6_len = sizeof(struct sockaddr_in6); +#endif + memcpy(&d6->sin6_addr.s6_addr, &in6addr_any, + sizeof in6addr_any); + break; + } + + t = virtual_bind((struct sockaddr *)&dflt_stor); + if (!t) + log_error("virtual_bind_ADDR_ANY: " + "could not allocate default IPv%s ISAKMP port(s)", + af == AF_INET ? "4" : "6"); + return t; +} + +static int +virtual_bind_if(char *ifname, struct sockaddr *if_addr, void *arg) +{ + struct conf_list *listen_on; + struct virtual_transport *v; + struct conf_list_node *address; + struct sockaddr *addr; + struct transport *t; + struct ifreq flags_ifr; + char *addr_str; + int s, error; + +#if defined (USE_DEBUG) + if (sockaddr2text(if_addr, &addr_str, 0)) + addr_str = 0; + + LOG_DBG((LOG_TRANSPORT, 90, + "virtual_bind_if: interface %s family %s address %s", + ifname ? ifname : "<unknown>", + if_addr->sa_family == AF_INET ? "v4" : + (if_addr->sa_family == AF_INET6 ? "v6" : "<unknown>"), + addr_str ? addr_str : "<invalid>")); + if (addr_str) + free(addr_str); +#endif + + /* + * Drop non-Internet stuff. + */ + if ((if_addr->sa_family != AF_INET + || sysdep_sa_len(if_addr) != sizeof (struct sockaddr_in)) + && (if_addr->sa_family != AF_INET6 + || sysdep_sa_len(if_addr) != sizeof (struct sockaddr_in6))) + return 0; + + /* + * Only create sockets for families we should listen to. + */ + if (bind_family) + switch (if_addr->sa_family) { + case AF_INET: + if ((bind_family & BIND_FAMILY_INET4) == 0) + return 0; + break; + case AF_INET6: + if ((bind_family & BIND_FAMILY_INET6) == 0) + return 0; + break; + default: + return 0; + } + + /* + * These special addresses are not useable as they have special meaning + * in the IP stack. + */ + if (if_addr->sa_family == AF_INET + && (((struct sockaddr_in *)if_addr)->sin_addr.s_addr == INADDR_ANY + || (((struct sockaddr_in *)if_addr)->sin_addr.s_addr + == INADDR_NONE))) + return 0; + + /* + * Go through the list of transports and see if we already have this + * address bound. If so, unmark the transport and skip it; this allows + * us to call this function when we suspect a new address has appeared. + */ + if ((v = virtual_listen_lookup(if_addr)) != 0) { + LOG_DBG ((LOG_TRANSPORT, 90, "virtual_bind_if: " + "already bound")); + v->transport.flags &= ~TRANSPORT_MARK; + return 0; + } + + /* + * Don't bother with interfaces that are down. + * Note: This socket is only used to collect the interface status. + */ + s = socket(if_addr->sa_family, SOCK_DGRAM, 0); + if (s == -1) { + log_error("virtual_bind_if: " + "socket (%d, SOCK_DGRAM, 0) failed", if_addr->sa_family); + return -1; + } + strlcpy(flags_ifr.ifr_name, ifname, sizeof flags_ifr.ifr_name); + if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&flags_ifr) == -1) { + log_error("virtual_bind_if: " + "ioctl (%d, SIOCGIFFLAGS, ...) failed", s); + close(s); + return -1; + } + close(s); + if (!(flags_ifr.ifr_flags & IFF_UP)) + return 0; + + /* Set the port number to zero. */ + switch (if_addr->sa_family) { + case AF_INET: + ((struct sockaddr_in *)if_addr)->sin_port = htons(0); + break; + case AF_INET6: + ((struct sockaddr_in6 *)if_addr)->sin6_port = htons(0); + break; + default: + log_print("virtual_bind_if: unsupported protocol family %d", + if_addr->sa_family); + break; + } + + /* + * If we are explicit about what addresses we can listen to, be sure + * to respect that option. + * This is quite wasteful redoing the list-run for every interface, + * but who cares? This is not an operation that needs to be fast. + */ + listen_on = conf_get_list("General", "Listen-on"); + if (listen_on) { + for (address = TAILQ_FIRST(&listen_on->fields); address; + address = TAILQ_NEXT(address, link)) { + if (text2sockaddr(address->field, 0, &addr)) { + log_print("virtual_bind_if: " + "invalid address %s in \"Listen-on\"", + address->field); + continue; + } + + /* If found, take the easy way out. */ + if (memcmp(addr, if_addr, + sysdep_sa_len(addr)) == 0) { + free(addr); + break; + } + free(addr); + } + conf_free_list(listen_on); + + /* + * If address is zero then we did not find the address among + * the ones we should listen to. + * XXX We do not discover if we do not find our listen + * addresses. Maybe this should be the other way round. + */ + if (!address) + return 0; + } + + t = virtual_bind(if_addr); + if (!t) { + error = sockaddr2text(if_addr, &addr_str, 0); + log_print("virtual_bind_if: failed to create a socket on %s", + error ? "unknown" : addr_str); + if (!error) + free(addr_str); + return -1; + } + LIST_INSERT_HEAD(&virtual_listen_list, (struct virtual_transport *)t, + link); + transport_reference(t); + return 0; +} + +static struct transport * +virtual_clone(struct transport *vt, struct sockaddr *raddr) +{ + struct virtual_transport *v = (struct virtual_transport *)vt; + struct virtual_transport *v2; + struct transport *t; + + t = malloc(sizeof *v); + if (!t) { + log_error("virtual_clone: malloc(%lu) failed", + (unsigned long)sizeof *v); + return 0; + } + v2 = (struct virtual_transport *)t; + + memcpy(v2, v, sizeof *v); + /* Remove the copy's links into virtual_listen_list. */ + v2->link.le_next = 0; + v2->link.le_prev = 0; + + if (v->encap_is_active) + v2->main = 0; /* No need to clone this. */ + else { + v2->main = v->main->vtbl->clone(v->main, raddr); + v2->main->virtual = (struct transport *)v2; + } +#if defined (USE_NAT_TRAVERSAL) + /* XXX fix strtol() call */ + sockaddr_set_port(raddr, udp_encap_default_port ? + strtol(udp_encap_default_port, NULL, 10) : UDP_ENCAP_DEFAULT_PORT); + v2->encap = v->encap->vtbl->clone(v->encap, raddr); + v2->encap->virtual = (struct transport *)v2; +#endif + LOG_DBG((LOG_TRANSPORT, 50, "virtual_clone: old %p new %p (%s is %p)", + v, t, v->encap_is_active ? "encap" : "main", + v->encap_is_active ? v2->encap : v2->main)); + + t->flags &= ~TRANSPORT_LISTEN; + transport_setup(t, 1); + return t; +} + +static struct transport * +virtual_create(char *name) +{ + struct virtual_transport *v; + struct transport *t, *t2; + + t = transport_create("udp_physical", name); + if (!t) + return 0; + +#if defined (USE_NAT_TRAVERSAL) + t2 = transport_create("udp_encap", name); + if (!t2) { + t->vtbl->remove(t); + return 0; + } +#else + t2 = 0; +#endif + + v = (struct virtual_transport *)calloc(1, sizeof *v); + if (!v) { + log_error("virtual_create: calloc(1, %lu) failed", + (unsigned long)sizeof *v); + t->vtbl->remove(t); + if (t2) + t2->vtbl->remove(t2); + return 0; + } + + memcpy(v, t, sizeof *t); + v->transport.virtual = 0; + v->main = t; + v->encap = t2; + v->transport.vtbl = &virtual_transport_vtbl; + t->virtual = (struct transport *)v; + if (t2) + t2->virtual = (struct transport *)v; + transport_setup(&v->transport, 1); + return (struct transport *)v; +} + +static void +virtual_remove(struct transport *t) +{ + struct virtual_transport *v = (struct virtual_transport *)t; + + if (v->encap) + v->encap->vtbl->remove(v->encap); + if (v->main) + v->main->vtbl->remove(v->main); + if (v->link.le_prev) + LIST_REMOVE(v, link); + + LOG_DBG((LOG_TRANSPORT, 90, "virtual_remove: removed %p", v)); + free(t); +} + +static void +virtual_report(struct transport *t) +{ + return; +} + +static void +virtual_handle_message(struct transport *t) +{ + if (t->virtual == default_transport || + t->virtual == default_transport6) { + /* XXX drain pending message. See udp_handle_message(). */ + + virtual_reinit(); + + /* + * As we don't know the actual destination address of the + * packet, we can't really deal with it. So, just ignore it + * and hope we catch the retransmission. + */ + return; + } + + /* + * As per the NAT-T draft, in case we have already switched ports, + * any messages recieved on the old (500) port SHOULD be discarded. + * (Actually, while phase 1 messages should be discarded, + * informational exchanges MAY be processed normally. For now, we + * discard them all.) + */ + if (((struct virtual_transport *)t->virtual)->encap_is_active && + ((struct virtual_transport *)t->virtual)->main == t) { + LOG_DBG((LOG_MESSAGE, 10, "virtual_handle_message: " + "message on old port discarded")); + return; + } + + t->vtbl->handle_message(t); +} + +static int +virtual_send_message(struct message *msg, struct transport *t) +{ + struct virtual_transport *v = + (struct virtual_transport *)msg->transport; +#if defined (USE_NAT_TRAVERSAL) + struct sockaddr *dst; + in_port_t port; + + /* + * Activate NAT-T Encapsulation if + * - the exchange says we can, and + * - in ID_PROT, after step 4 (draft-ietf-ipsec-nat-t-ike-03), or + * - in other exchange (Aggressive, ), asap + * XXX ISAKMP_EXCH_BASE etc? + */ + if (v->encap_is_active == 0 && + (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_ENABLE) && + (msg->exchange->type != ISAKMP_EXCH_ID_PROT || + msg->exchange->step > 4)) { + LOG_DBG((LOG_MESSAGE, 10, "virtual_send_message: " + "enabling NAT-T encapsulation for this exchange")); + v->encap_is_active++; + + /* Copy destination port if it is translated (NAT). */ + v->main->vtbl->get_dst(v->main, &dst); + port = ntohs(sockaddr_port(dst)); + if (port != UDP_DEFAULT_PORT) { + v->main->vtbl->get_dst(v->encap, &dst); + sockaddr_set_port(dst, port); + } + } +#endif /* USE_NAT_TRAVERSAL */ + + if (v->encap_is_active) + return v->encap->vtbl->send_message(msg, v->encap); + else + return v->main->vtbl->send_message(msg, v->main); +} + +static void +virtual_get_src(struct transport *t, struct sockaddr **s) +{ + struct virtual_transport *v = (struct virtual_transport *)t; + + if (v->encap_is_active) + v->encap->vtbl->get_src(v->encap, s); + else + v->main->vtbl->get_src(v->main, s); +} + +static void +virtual_get_dst(struct transport *t, struct sockaddr **s) +{ + struct virtual_transport *v = (struct virtual_transport *)t; + + if (v->encap_is_active) + v->encap->vtbl->get_dst(v->encap, s); + else + v->main->vtbl->get_dst(v->main, s); +} + +static char * +virtual_decode_ids(struct transport *t) +{ + struct virtual_transport *v = (struct virtual_transport *)t; + + if (v->encap_is_active) + return v->encap->vtbl->decode_ids(t); + else + return v->main->vtbl->decode_ids(t); +} + +static struct msg_head * +virtual_get_queue(struct message *msg) +{ + if (msg->flags & MSG_PRIORITIZED) + return &msg->transport->prio_sendq; + else + return &msg->transport->sendq; +} diff --git a/keyexchange/isakmpd-20041012/virtual.h b/keyexchange/isakmpd-20041012/virtual.h new file mode 100644 index 0000000..7a3bd21 --- /dev/null +++ b/keyexchange/isakmpd-20041012/virtual.h @@ -0,0 +1,42 @@ +/* $OpenBSD: virtual.h,v 1.1 2004/06/20 15:24:05 ho Exp $ */ + +/* + * Copyright (c) 2004 Håkan Olsson. 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. + * + * 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. + */ + +#ifndef _TRP_VIRTUAL_H_ +#define _TRP_VIRTUAL_H_ + +struct virtual_transport { + struct transport transport; + struct transport *main; /* Normally this transport is used. */ + struct transport *encap; /* Or this, depending on 'encap_is_active'. */ + int encap_is_active; + LIST_ENTRY (virtual_transport) link; +}; + +void virtual_init(void); +struct virtual_transport *virtual_get_default(sa_family_t); +struct virtual_transport *virtual_listen_lookup(struct sockaddr *); + +#endif /* _TRP_VIRTUAL_H_ */ diff --git a/keyexchange/isakmpd-20041012/x509.c b/keyexchange/isakmpd-20041012/x509.c new file mode 100644 index 0000000..0897557 --- /dev/null +++ b/keyexchange/isakmpd-20041012/x509.c @@ -0,0 +1,1439 @@ +/* $OpenBSD: x509.c,v 1.95 2004/08/10 19:21:01 deraadt Exp $ */ +/* $EOM: x509.c,v 1.54 2001/01/16 18:42:16 ho Exp $ */ + +/* + * Copyright (c) 1998, 1999 Niels Provos. All rights reserved. + * Copyright (c) 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 1999, 2000, 2001 Angelos D. Keromytis. 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. + * + * 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. + */ + +#ifdef USE_X509 + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#ifdef USE_POLICY +#include <regex.h> +#include <keynote.h> +#endif /* USE_POLICY */ + +#include "sysdep.h" + +#include "cert.h" +#include "conf.h" +#include "exchange.h" +#include "hash.h" +#include "ike_auth.h" +#include "ipsec.h" +#include "log.h" +#include "math_mp.h" +#include "monitor.h" +#include "policy.h" +#include "sa.h" +#include "util.h" +#include "x509.h" + +static u_int16_t x509_hash(u_int8_t *, size_t); +static void x509_hash_init(void); +static X509 *x509_hash_find(u_int8_t *, size_t); +static int x509_hash_enter(X509 *); + +/* + * X509_STOREs do not support subjectAltNames, so we have to build + * our own hash table. + */ + +/* + * XXX Actually this store is not really useful, we never use it as we have + * our own hash table. It also gets collisons if we have several certificates + * only differing in subjectAltName. + */ +static X509_STORE *x509_certs = 0; +static X509_STORE *x509_cas = 0; + +/* Initial number of bits used as hash. */ +#define INITIAL_BUCKET_BITS 6 + +struct x509_hash { + LIST_ENTRY(x509_hash) link; + + X509 *cert; +}; + +static LIST_HEAD(x509_list, x509_hash) *x509_tab = 0; + +/* Works both as a maximum index and a mask. */ +static int bucket_mask; + +#ifdef USE_POLICY +/* + * Given an X509 certificate, create a KeyNote assertion where + * Issuer/Subject -> Authorizer/Licensees. + * XXX RSA-specific. + */ +int +x509_generate_kn(int id, X509 *cert) +{ + char *fmt = "Authorizer: \"rsa-hex:%s\"\nLicensees: \"rsa-hex:%s" + "\"\nConditions: %s >= \"%s\" && %s <= \"%s\";\n"; + char *ikey, *skey, *buf, isname[256], subname[256]; + char *fmt2 = "Authorizer: \"DN:%s\"\nLicensees: \"DN:%s\"\n" + "Conditions: %s >= \"%s\" && %s <= \"%s\";\n"; + X509_NAME *issuer, *subject; + struct keynote_deckey dc; + X509_STORE_CTX csc; + X509_OBJECT obj; + X509 *icert; + RSA *key; + time_t tt; + char before[15], after[15], *timecomp, *timecomp2; + ASN1_TIME *tm; + int i, buf_len; + + LOG_DBG((LOG_POLICY, 90, + "x509_generate_kn: generating KeyNote policy for certificate %p", + cert)); + + issuer = X509_get_issuer_name(cert); + subject = X509_get_subject_name(cert); + + /* Missing or self-signed, ignore cert but don't report failure. */ + if (!issuer || !subject || !X509_name_cmp(issuer, subject)) + return 1; + + if (!x509_cert_get_key(cert, &key)) { + LOG_DBG((LOG_POLICY, 30, + "x509_generate_kn: failed to get public key from cert")); + return 0; + } + dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA; + dc.dec_key = key; + ikey = kn_encode_key(&dc, INTERNAL_ENC_PKCS1, ENCODING_HEX, + KEYNOTE_PUBLIC_KEY); + if (keynote_errno == ERROR_MEMORY) { + log_print("x509_generate_kn: failed to get memory for " + "public key"); + RSA_free(key); + LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get " + "subject key")); + return 0; + } + if (!ikey) { + RSA_free(key); + LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get " + "subject key")); + return 0; + } + RSA_free(key); + + /* Now find issuer's certificate so we can get the public key. */ + X509_STORE_CTX_init(&csc, x509_cas, cert, NULL); + if (X509_STORE_get_by_subject(&csc, X509_LU_X509, issuer, &obj) != + X509_LU_X509) { + X509_STORE_CTX_cleanup(&csc); + X509_STORE_CTX_init(&csc, x509_certs, cert, NULL); + if (X509_STORE_get_by_subject(&csc, X509_LU_X509, issuer, &obj) + != X509_LU_X509) { + X509_STORE_CTX_cleanup(&csc); + LOG_DBG((LOG_POLICY, 30, + "x509_generate_kn: no certificate found for " + "issuer")); + return 0; + } + } + X509_STORE_CTX_cleanup(&csc); + icert = obj.data.x509; + + if (icert == NULL) { + LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: " + "missing certificates, cannot construct X509 chain")); + free(ikey); + return 0; + } + if (!x509_cert_get_key(icert, &key)) { + LOG_DBG((LOG_POLICY, 30, + "x509_generate_kn: failed to get public key from cert")); + free(ikey); + return 0; + } + X509_OBJECT_free_contents(&obj); + + dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA; + dc.dec_key = key; + skey = kn_encode_key(&dc, INTERNAL_ENC_PKCS1, ENCODING_HEX, + KEYNOTE_PUBLIC_KEY); + if (keynote_errno == ERROR_MEMORY) { + log_error("x509_generate_kn: failed to get memory for public " + "key"); + free(ikey); + RSA_free(key); + LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get issuer " + "key")); + return 0; + } + if (!skey) { + free(ikey); + RSA_free(key); + LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get issuer " + "key")); + return 0; + } + RSA_free(key); + + buf_len = strlen(fmt) + strlen(ikey) + strlen(skey) + 56; + buf = calloc(buf_len, sizeof(char)); + buf_len *= sizeof(char); + if (!buf) { + log_error("x509_generate_kn: " + "failed to allocate memory for KeyNote credential"); + free(ikey); + free(skey); + return 0; + } + if (((tm = X509_get_notBefore(cert)) == NULL) || + (tm->type != V_ASN1_UTCTIME && + tm->type != V_ASN1_GENERALIZEDTIME)) { + tt = time(0); + strftime(before, 14, "%Y%m%d%H%M%S", localtime(&tt)); + timecomp = "LocalTimeOfDay"; + } else { + if (tm->data[tm->length - 1] == 'Z') { + timecomp = "GMTTimeOfDay"; + i = tm->length - 2; + } else { + timecomp = "LocalTimeOfDay"; + i = tm->length - 1; + } + + for (; i >= 0; i--) { + if (tm->data[i] < '0' || tm->data[i] > '9') { + LOG_DBG((LOG_POLICY, 30, + "x509_generate_kn: invalid data in " + "NotValidBefore time field")); + free(ikey); + free(skey); + free(buf); + return 0; + } + } + + if (tm->type == V_ASN1_UTCTIME) { + if ((tm->length < 10) || (tm->length > 13)) { + LOG_DBG((LOG_POLICY, 30, + "x509_generate_kn: invalid length " + "of NotValidBefore time field (%d)", + tm->length)); + free(ikey); + free(skey); + free(buf); + return 0; + } + /* Validity checks. */ + if ((tm->data[2] != '0' && tm->data[2] != '1') || + (tm->data[2] == '0' && tm->data[3] == '0') || + (tm->data[2] == '1' && tm->data[3] > '2') || + (tm->data[4] > '3') || + (tm->data[4] == '0' && tm->data[5] == '0') || + (tm->data[4] == '3' && tm->data[5] > '1') || + (tm->data[6] > '2') || + (tm->data[6] == '2' && tm->data[7] > '3') || + (tm->data[8] > '5')) { + LOG_DBG((LOG_POLICY, 30, + "x509_generate_kn: invalid value in " + "NotValidBefore time field")); + free(ikey); + free(skey); + free(buf); + return 0; + } + /* Stupid UTC tricks. */ + if (tm->data[0] < '5') + snprintf(before, sizeof before, "20%s", + tm->data); + else + snprintf(before, sizeof before, "19%s", + tm->data); + } else { /* V_ASN1_GENERICTIME */ + if ((tm->length < 12) || (tm->length > 15)) { + LOG_DBG((LOG_POLICY, 30, + "x509_generate_kn: invalid length of " + "NotValidBefore time field (%d)", + tm->length)); + free(ikey); + free(skey); + free(buf); + return 0; + } + /* Validity checks. */ + if ((tm->data[4] != '0' && tm->data[4] != '1') || + (tm->data[4] == '0' && tm->data[5] == '0') || + (tm->data[4] == '1' && tm->data[5] > '2') || + (tm->data[6] > '3') || + (tm->data[6] == '0' && tm->data[7] == '0') || + (tm->data[6] == '3' && tm->data[7] > '1') || + (tm->data[8] > '2') || + (tm->data[8] == '2' && tm->data[9] > '3') || + (tm->data[10] > '5')) { + LOG_DBG((LOG_POLICY, 30, + "x509_generate_kn: invalid value in " + "NotValidBefore time field")); + free(ikey); + free(skey); + free(buf); + return 0; + } + snprintf(before, sizeof before, "%s", tm->data); + } + + /* Fix missing seconds. */ + if (tm->length < 12) { + before[12] = '0'; + before[13] = '0'; + } + /* This will overwrite trailing 'Z'. */ + before[14] = '\0'; + } + + tm = X509_get_notAfter(cert); + if (tm == NULL && + (tm->type != V_ASN1_UTCTIME && + tm->type != V_ASN1_GENERALIZEDTIME)) { + tt = time(0); + strftime(after, 14, "%Y%m%d%H%M%S", localtime(&tt)); + timecomp2 = "LocalTimeOfDay"; + } else { + if (tm->data[tm->length - 1] == 'Z') { + timecomp2 = "GMTTimeOfDay"; + i = tm->length - 2; + } else { + timecomp2 = "LocalTimeOfDay"; + i = tm->length - 1; + } + + for (; i >= 0; i--) { + if (tm->data[i] < '0' || tm->data[i] > '9') { + LOG_DBG((LOG_POLICY, 30, + "x509_generate_kn: invalid data in " + "NotValidAfter time field")); + free(ikey); + free(skey); + free(buf); + return 0; + } + } + + if (tm->type == V_ASN1_UTCTIME) { + if ((tm->length < 10) || (tm->length > 13)) { + LOG_DBG((LOG_POLICY, 30, + "x509_generate_kn: invalid length of " + "NotValidAfter time field (%d)", + tm->length)); + free(ikey); + free(skey); + free(buf); + return 0; + } + /* Validity checks. */ + if ((tm->data[2] != '0' && tm->data[2] != '1') || + (tm->data[2] == '0' && tm->data[3] == '0') || + (tm->data[2] == '1' && tm->data[3] > '2') || + (tm->data[4] > '3') || + (tm->data[4] == '0' && tm->data[5] == '0') || + (tm->data[4] == '3' && tm->data[5] > '1') || + (tm->data[6] > '2') || + (tm->data[6] == '2' && tm->data[7] > '3') || + (tm->data[8] > '5')) { + LOG_DBG((LOG_POLICY, 30, + "x509_generate_kn: invalid value in " + "NotValidAfter time field")); + free(ikey); + free(skey); + free(buf); + return 0; + } + /* Stupid UTC tricks. */ + if (tm->data[0] < '5') + snprintf(after, sizeof after, "20%s", + tm->data); + else + snprintf(after, sizeof after, "19%s", + tm->data); + } else { /* V_ASN1_GENERICTIME */ + if ((tm->length < 12) || (tm->length > 15)) { + LOG_DBG((LOG_POLICY, 30, + "x509_generate_kn: invalid length of " + "NotValidAfter time field (%d)", + tm->length)); + free(ikey); + free(skey); + free(buf); + return 0; + } + /* Validity checks. */ + if ((tm->data[4] != '0' && tm->data[4] != '1') || + (tm->data[4] == '0' && tm->data[5] == '0') || + (tm->data[4] == '1' && tm->data[5] > '2') || + (tm->data[6] > '3') || + (tm->data[6] == '0' && tm->data[7] == '0') || + (tm->data[6] == '3' && tm->data[7] > '1') || + (tm->data[8] > '2') || + (tm->data[8] == '2' && tm->data[9] > '3') || + (tm->data[10] > '5')) { + LOG_DBG((LOG_POLICY, 30, + "x509_generate_kn: invalid value in " + "NotValidAfter time field")); + free(ikey); + free(skey); + free(buf); + return 0; + } + snprintf(after, sizeof after, "%s", tm->data); + } + + /* Fix missing seconds. */ + if (tm->length < 12) { + after[12] = '0'; + after[13] = '0'; + } + after[14] = '\0'; /* This will overwrite trailing 'Z' */ + } + + snprintf(buf, buf_len, fmt, skey, ikey, timecomp, before, timecomp2, + after); + free(ikey); + free(skey); + + if (kn_add_assertion(id, buf, strlen(buf), ASSERT_FLAG_LOCAL) == -1) { + LOG_DBG((LOG_POLICY, 30, + "x509_generate_kn: failed to add new KeyNote credential")); + free(buf); + return 0; + } + /* We could print the assertion here, but log_print() truncates... */ + LOG_DBG((LOG_POLICY, 60, "x509_generate_kn: added credential")); + + free(buf); + + if (!X509_NAME_oneline(issuer, isname, 256)) { + LOG_DBG((LOG_POLICY, 50, + "x509_generate_kn: " + "X509_NAME_oneline (issuer, ...) failed")); + return 0; + } + if (!X509_NAME_oneline(subject, subname, 256)) { + LOG_DBG((LOG_POLICY, 50, + "x509_generate_kn: " + "X509_NAME_oneline (subject, ...) failed")); + return 0; + } + buf_len = strlen(fmt2) + strlen(isname) + strlen(subname) + 56; + buf = malloc(buf_len); + if (!buf) { + log_error("x509_generate_kn: malloc (%d) failed", buf_len); + return 0; + } + snprintf(buf, buf_len, fmt2, isname, subname, timecomp, before, + timecomp2, after); + + if (kn_add_assertion(id, buf, strlen(buf), ASSERT_FLAG_LOCAL) == -1) { + LOG_DBG((LOG_POLICY, 30, + "x509_generate_kn: failed to add new KeyNote credential")); + free(buf); + return 0; + } + LOG_DBG((LOG_POLICY, 80, "x509_generate_kn: added credential:\n%s", + buf)); + + free(buf); + return 1; +} +#endif /* USE_POLICY */ + +static u_int16_t +x509_hash(u_int8_t *id, size_t len) +{ + u_int16_t bucket = 0; + size_t i; + + /* XXX We might resize if we are crossing a certain threshold. */ + for (i = 4; i < (len & ~1); i += 2) { + /* Doing it this way avoids alignment problems. */ + bucket ^= (id[i] + 1) * (id[i + 1] + 257); + } + /* Hash in the last character of odd length IDs too. */ + if (i < len) + bucket ^= (id[i] + 1) * (id[i] + 257); + + bucket &= bucket_mask; + return bucket; +} + +static void +x509_hash_init(void) +{ + struct x509_hash *certh; + int i; + + bucket_mask = (1 << INITIAL_BUCKET_BITS) - 1; + + /* If reinitializing, free existing entries. */ + if (x509_tab) { + for (i = 0; i <= bucket_mask; i++) + for (certh = LIST_FIRST(&x509_tab[i]); certh; + certh = LIST_FIRST(&x509_tab[i])) { + LIST_REMOVE(certh, link); + free(certh); + } + free(x509_tab); + } + x509_tab = malloc((bucket_mask + 1) * sizeof(struct x509_list)); + if (!x509_tab) + log_fatal("x509_hash_init: malloc (%lu) failed", + (bucket_mask + 1) * + (unsigned long)sizeof(struct x509_list)); + for (i = 0; i <= bucket_mask; i++) { + LIST_INIT(&x509_tab[i]); + } +} + +/* Lookup a certificate by an ID blob. */ +static X509 * +x509_hash_find(u_int8_t *id, size_t len) +{ + struct x509_hash *cert; + u_int8_t **cid; + u_int32_t *clen; + int n, i, id_found; + + for (cert = LIST_FIRST(&x509_tab[x509_hash(id, len)]); cert; + cert = LIST_NEXT(cert, link)) { + if (!x509_cert_get_subjects(cert->cert, &n, &cid, &clen)) + continue; + + id_found = 0; + for (i = 0; i < n; i++) { + LOG_DBG_BUF((LOG_CRYPTO, 70, "cert_cmp", id, len)); + LOG_DBG_BUF((LOG_CRYPTO, 70, "cert_cmp", cid[i], + clen[i])); + /* + * XXX This identity predicate needs to be + * understood. + */ + if (clen[i] == len && id[0] == cid[i][0] && + memcmp(id + 4, cid[i] + 4, len - 4) == 0) { + id_found++; + break; + } + } + cert_free_subjects(n, cid, clen); + if (!id_found) + continue; + + LOG_DBG((LOG_CRYPTO, 70, "x509_hash_find: return X509 %p", + cert->cert)); + return cert->cert; + } + + LOG_DBG((LOG_CRYPTO, 70, + "x509_hash_find: no certificate matched query")); + return 0; +} + +static int +x509_hash_enter(X509 *cert) +{ + u_int16_t bucket = 0; + u_int8_t **id; + u_int32_t *len; + struct x509_hash *certh; + int n, i; + + if (!x509_cert_get_subjects(cert, &n, &id, &len)) { + log_print("x509_hash_enter: cannot retrieve subjects"); + return 0; + } + for (i = 0; i < n; i++) { + certh = calloc(1, sizeof *certh); + if (!certh) { + cert_free_subjects(n, id, len); + log_error("x509_hash_enter: calloc (1, %lu) failed", + (unsigned long)sizeof *certh); + return 0; + } + certh->cert = cert; + + bucket = x509_hash(id[i], len[i]); + + LIST_INSERT_HEAD(&x509_tab[bucket], certh, link); + LOG_DBG((LOG_CRYPTO, 70, + "x509_hash_enter: cert %p added to bucket %d", + cert, bucket)); + } + cert_free_subjects(n, id, len); + + return 1; +} + +/* X509 Certificate Handling functions. */ + +int +x509_read_from_dir(X509_STORE *ctx, char *name, int hash) +{ + struct dirent *file; +#if defined (USE_PRIVSEP) + struct monitor_dirents *dir; +#else + DIR *dir; +#endif + FILE *certfp; + X509 *cert; + struct stat sb; + char fullname[PATH_MAX]; + int fd, off, size; + + if (strlen(name) >= sizeof fullname - 1) { + log_print("x509_read_from_dir: directory name too long"); + return 0; + } + LOG_DBG((LOG_CRYPTO, 40, "x509_read_from_dir: reading certs from %s", + name)); + + dir = monitor_opendir(name); + if (!dir) { + LOG_DBG((LOG_CRYPTO, 10, + "x509_read_from_dir: opendir (\"%s\") failed: %s", + name, strerror(errno))); + return 0; + } + strlcpy(fullname, name, sizeof fullname); + off = strlen(fullname); + size = sizeof fullname - off; + + while ((file = monitor_readdir(dir)) != NULL) { + strlcpy(fullname + off, file->d_name, size); + + if (file->d_type != DT_UNKNOWN) { + if (file->d_type != DT_REG && file->d_type != DT_LNK) + continue; + } + + LOG_DBG((LOG_CRYPTO, 60, + "x509_read_from_dir: reading certificate %s", + file->d_name)); + + if ((fd = monitor_open(fullname, O_RDONLY, 0)) == -1) { + log_error("x509_read_from_dir: monitor_open" + "(\"%s\", O_RDONLY, 0) failed", fullname); + continue; + } + + if (fstat(fd, &sb) == -1) { + log_error("x509_read_from_dir: fstat failed"); + close(fd); + continue; + } + + if (!(sb.st_mode & S_IFREG)) { + close(fd); + continue; + } + + if ((certfp = fdopen(fd, "r")) == NULL) { + log_error("x509_read_from_dir: fdopen failed"); + close(fd); + continue; + } + +#if SSLEAY_VERSION_NUMBER >= 0x00904100L + cert = PEM_read_X509(certfp, NULL, NULL, NULL); +#else + cert = PEM_read_X509(certfp, NULL, NULL); +#endif + fclose(certfp); + + if (cert == NULL) { + log_print("x509_read_from_dir: PEM_read_bio_X509 " + "failed for %s", file->d_name); + continue; + } + if (!X509_STORE_add_cert(ctx, cert)) { + /* + * This is actually expected if we have several + * certificates only differing in subjectAltName, + * which is not an something that is strange. + * Consider multi-homed machines. + */ + LOG_DBG((LOG_CRYPTO, 50, + "x509_read_from_dir: X509_STORE_add_cert failed " + "for %s", file->d_name)); + } + if (hash) + if (!x509_hash_enter(cert)) + log_print("x509_read_from_dir: " + "x509_hash_enter (%s) failed", + file->d_name); + } + + monitor_closedir(dir); + + return 1; +} + +/* XXX share code with x509_read_from_dir() ? */ +int +x509_read_crls_from_dir(X509_STORE *ctx, char *name) +{ +#if OPENSSL_VERSION_NUMBER >= 0x00907000L + struct dirent *file; +#if defined (USE_PRIVSEP) + struct monitor_dirents *dir; +#else + DIR *dir; +#endif + FILE *crlfp; + X509_CRL *crl; + struct stat sb; + char fullname[PATH_MAX]; + int fd, off, size; + + if (strlen(name) >= sizeof fullname - 1) { + log_print("x509_read_crls_from_dir: directory name too long"); + return 0; + } + LOG_DBG((LOG_CRYPTO, 40, "x509_read_crls_from_dir: reading CRLs " + "from %s", name)); + + dir = monitor_opendir(name); + if (!dir) { + LOG_DBG((LOG_CRYPTO, 10, "x509_read_crls_from_dir: opendir " + "(\"%s\") failed: %s", name, strerror(errno))); + return 0; + } + strlcpy(fullname, name, sizeof fullname); + off = strlen(fullname); + size = sizeof fullname - off; + + while ((file = monitor_readdir(dir)) != NULL) { + strlcpy(fullname + off, file->d_name, size); + + if (file->d_type != DT_UNKNOWN) { + if (file->d_type != DT_REG && file->d_type != DT_LNK) + continue; + } + + LOG_DBG((LOG_CRYPTO, 60, "x509_read_crls_from_dir: reading " + "CRL %s", file->d_name)); + + if ((fd = monitor_open(fullname, O_RDONLY, 0)) == -1) { + log_error("x509_read_crls_from_dir: monitor_open" + "(\"%s\", O_RDONLY, 0) failed", fullname); + continue; + } + + if (fstat(fd, &sb) == -1) { + log_error("x509_read_crls_from_dir: fstat failed"); + close(fd); + continue; + } + + if (!(sb.st_mode & S_IFREG)) { + close(fd); + continue; + } + + if ((crlfp = fdopen(fd, "r")) == NULL) { + log_error("x509_read_crls_from_dir: fdopen failed"); + close(fd); + continue; + } + + crl = PEM_read_X509_CRL(crlfp, NULL, NULL, NULL); + + fclose(crlfp); + + if (crl == NULL) { + log_print("x509_read_crls_from_dir: " + "PEM_read_X509_CRL failed for %s", + file->d_name); + continue; + } + if (!X509_STORE_add_crl(ctx, crl)) { + LOG_DBG((LOG_CRYPTO, 50, "x509_read_crls_from_dir: " + "X509_STORE_add_crl failed for %s", file->d_name)); + continue; + } + /* + * XXX This is to make x509_cert_validate set this (and + * XXX another) flag when validating certificates. Currently, + * XXX OpenSSL defaults to reject an otherwise valid + * XXX certificate (chain) if these flags are set but there + * XXX are no CRLs to check. The current workaround is to only + * XXX set the flags if we actually loaded some CRL data. + */ + X509_STORE_set_flags(ctx, X509_V_FLAG_CRL_CHECK); + } + + monitor_closedir(dir); +#endif /* OPENSSL_VERSION_NUMBER >= 0x00907000L */ + + return 1; +} + +/* Initialize our databases and load our own certificates. */ +int +x509_cert_init(void) +{ + char *dirname; + + x509_hash_init(); + + /* Process CA certificates we will trust. */ + dirname = conf_get_str("X509-certificates", "CA-directory"); + if (!dirname) { + log_print("x509_cert_init: no CA-directory"); + return 0; + } + /* Free if already initialized. */ + if (x509_cas) + X509_STORE_free(x509_cas); + + x509_cas = X509_STORE_new(); + if (!x509_cas) { + log_print("x509_cert_init: creating new X509_STORE failed"); + return 0; + } + if (!x509_read_from_dir(x509_cas, dirname, 0)) { + log_print("x509_cert_init: x509_read_from_dir failed"); + return 0; + } + /* Process client certificates we will accept. */ + dirname = conf_get_str("X509-certificates", "Cert-directory"); + if (!dirname) { + log_print("x509_cert_init: no Cert-directory"); + return 0; + } + /* Free if already initialized. */ + if (x509_certs) + X509_STORE_free(x509_certs); + + x509_certs = X509_STORE_new(); + if (!x509_certs) { + log_print("x509_cert_init: creating new X509_STORE failed"); + return 0; + } + if (!x509_read_from_dir(x509_certs, dirname, 1)) { + log_print("x509_cert_init: x509_read_from_dir failed"); + return 0; + } + return 1; +} + +int +x509_crl_init(void) +{ + /* + * XXX I'm not sure if the method to use CRLs in certificate validation + * is valid for OpenSSL versions prior to 0.9.7. For now, simply do not + * support it. + */ +#if OPENSSL_VERSION_NUMBER >= 0x00907000L + char *dirname; + dirname = conf_get_str("X509-certificates", "CRL-directory"); + if (!dirname) { + log_print("x509_crl_init: no CRL-directory"); + return 0; + } + if (!x509_read_crls_from_dir(x509_cas, dirname)) { + LOG_DBG((LOG_MISC, 10, + "x509_crl_init: x509_read_crls_from_dir failed")); + return 0; + } +#else + LOG_DBG((LOG_CRYPTO, 10, "x509_crl_init: CRL support only " + "with OpenSSL v0.9.7 or later")); +#endif + + return 1; +} + +void * +x509_cert_get(u_int8_t *asn, u_int32_t len) +{ + return x509_from_asn(asn, len); +} + +int +x509_cert_validate(void *scert) +{ + X509_STORE_CTX csc; + X509_NAME *issuer, *subject; + X509 *cert = (X509 *) scert; + EVP_PKEY *key; + int res, err; + + /* + * Validate the peer certificate by checking with the CA certificates + * we trust. + */ + X509_STORE_CTX_init(&csc, x509_cas, cert, NULL); +#if OPENSSL_VERSION_NUMBER >= 0x00907000L + /* XXX See comment in x509_read_crls_from_dir. */ +#if OPENSSL_VERSION_NUMBER >= 0x00908000L + if (x509_cas->param->flags & X509_V_FLAG_CRL_CHECK) { +#else + if (x509_cas->flags & X509_V_FLAG_CRL_CHECK) { +#endif + X509_STORE_CTX_set_flags(&csc, X509_V_FLAG_CRL_CHECK); + X509_STORE_CTX_set_flags(&csc, X509_V_FLAG_CRL_CHECK_ALL); + } +#endif + res = X509_verify_cert(&csc); + err = csc.error; + X509_STORE_CTX_cleanup(&csc); + + /* + * Return if validation succeeded or self-signed certs are not + * accepted. + * + * XXX X509_verify_cert seems to return -1 if the validation should be + * retried somehow. We take this as an error and give up. + */ + if (res > 0) + return 1; + else if (res < 0 || + (res == 0 && err != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)) { + if (err) + log_print("x509_cert_validate: %.100s", + X509_verify_cert_error_string(err)); + return 0; + } else if (!conf_get_str("X509-certificates", "Accept-self-signed")) { + if (err) + log_print("x509_cert_validate: %.100s", + X509_verify_cert_error_string(err)); + return 0; + } + issuer = X509_get_issuer_name(cert); + subject = X509_get_subject_name(cert); + + if (!issuer || !subject || X509_name_cmp(issuer, subject)) + return 0; + + key = X509_get_pubkey(cert); + if (!key) { + log_print("x509_cert_validate: could not get public key from " + "self-signed cert"); + return 0; + } + if (X509_verify(cert, key) == -1) { + log_print("x509_cert_validate: self-signed cert is bad"); + return 0; + } + return 1; +} + +int +x509_cert_insert(int id, void *scert) +{ + X509 *cert; + int res; + + cert = X509_dup((X509 *)scert); + if (!cert) { + log_print("x509_cert_insert: X509_dup failed"); + return 0; + } +#ifdef USE_POLICY + if (x509_generate_kn(id, cert) == 0) { + LOG_DBG((LOG_POLICY, 50, + "x509_cert_insert: x509_generate_kn failed")); + X509_free(cert); + return 0; + } +#endif /* USE_POLICY */ + + res = x509_hash_enter(cert); + if (!res) + X509_free(cert); + + return res; +} + +static struct x509_hash * +x509_hash_lookup(X509 *cert) +{ + struct x509_hash *certh; + int i; + + for (i = 0; i <= bucket_mask; i++) + for (certh = LIST_FIRST(&x509_tab[i]); certh; + certh = LIST_NEXT(certh, link)) + if (certh->cert == cert) + return certh; + return 0; +} + +void +x509_cert_free(void *cert) +{ + struct x509_hash *certh = x509_hash_lookup((X509 *) cert); + + if (certh) + LIST_REMOVE(certh, link); + X509_free((X509 *) cert); +} + +/* Validate the BER Encoding of a RDNSequence in the CERT_REQ payload. */ +int +x509_certreq_validate(u_int8_t *asn, u_int32_t len) +{ + int res = 1; +#if 0 + struct norm_type name = SEQOF("issuer", RDNSequence); + + if (!asn_template_clone(&name, 1) || + (asn = asn_decode_sequence(asn, len, &name)) == 0) { + log_print("x509_certreq_validate: can not decode 'acceptable " + "CA' info"); + res = 0; + } + asn_free(&name); +#endif + + /* XXX - not supported directly in SSL - later. */ + + 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) +{ +#if 0 + /* XXX This needs to be done later. */ + struct norm_type aca = SEQOF("aca", RDNSequence); + struct norm_type *tmp; + struct x509_aca naca, *ret; + + if (!asn_template_clone(&aca, 1) || + (asn = asn_decode_sequence(asn, len, &aca)) == 0) { + log_print("x509_certreq_decode: can not decode 'acceptable " + "CA' info"); + goto fail; + } + memset(&naca, 0, sizeof(naca)); + + tmp = asn_decompose("aca.RelativeDistinguishedName." + "AttributeValueAssertion", &aca); + if (!tmp) + goto fail; + x509_get_attribval(tmp, &naca.name1); + + tmp = asn_decompose("aca.RelativeDistinguishedName[1]" + ".AttributeValueAssertion", &aca); + if (tmp) + x509_get_attribval(tmp, &naca.name2); + + asn_free(&aca); + + ret = malloc(sizeof(struct x509_aca)); + if (ret) + memcpy(ret, &naca, sizeof(struct x509_aca)); + else { + log_error("x509_certreq_decode: malloc (%lu) failed", + (unsigned long) sizeof(struct x509_aca)); + x509_free_aca(&aca); + } + + return ret; + +fail: + asn_free(&aca); +#endif + return 0; +} + +void +x509_free_aca(void *blob) +{ + struct x509_aca *aca = blob; + + if (aca->name1.type) + free(aca->name1.type); + if (aca->name1.val) + free(aca->name1.val); + + if (aca->name2.type) + free(aca->name2.type); + if (aca->name2.val) + free(aca->name2.val); +} + +X509 * +x509_from_asn(u_char *asn, u_int len) +{ + BIO *certh; + X509 *scert = 0; + + certh = BIO_new(BIO_s_mem()); + if (!certh) { + log_error("x509_from_asn: BIO_new (BIO_s_mem ()) failed"); + return 0; + } + if (BIO_write(certh, asn, len) == -1) { + log_error("x509_from_asn: BIO_write failed\n"); + goto end; + } + scert = d2i_X509_bio(certh, NULL); + if (!scert) { + log_print("x509_from_asn: d2i_X509_bio failed\n"); + goto end; + } +end: + BIO_free(certh); + return scert; +} + +/* + * Obtain a certificate from an acceptable CA. + * XXX We don't check if the certificate we find is from an accepted CA. + */ +int +x509_cert_obtain(u_int8_t *id, size_t id_len, void *data, u_int8_t **cert, + u_int32_t *certlen) +{ + struct x509_aca *aca = data; + X509 *scert; + + if (aca) + LOG_DBG((LOG_CRYPTO, 60, "x509_cert_obtain: " + "acceptable certificate authorities here")); + + /* We need our ID to find a certificate. */ + if (!id) { + log_print("x509_cert_obtain: ID is missing"); + return 0; + } + scert = x509_hash_find(id, id_len); + if (!scert) + return 0; + + x509_serialize(scert, cert, certlen); + if (!*cert) + return 0; + return 1; +} + +/* Returns a pointer to the subjectAltName information of X509 certificate. */ +int +x509_cert_subjectaltname(X509 *scert, u_int8_t **altname, u_int32_t *len) +{ + X509_EXTENSION *subjectaltname; + u_int8_t *sandata; + int extpos, santype, sanlen; + + extpos = X509_get_ext_by_NID(scert, NID_subject_alt_name, -1); + if (extpos == -1) { + log_print("x509_cert_subjectaltname: " + "certificate does not contain subjectAltName"); + return 0; + } + subjectaltname = X509_get_ext(scert, extpos); + + if (!subjectaltname || !subjectaltname->value || + !subjectaltname->value->data || + subjectaltname->value->length < 4) { + log_print("x509_cert_subjectaltname: invalid " + "subjectaltname extension"); + return 0; + } + /* SSL does not handle unknown ASN stuff well, do it by hand. */ + sandata = subjectaltname->value->data; + santype = sandata[2] & 0x3f; + sanlen = sandata[3]; + sandata += 4; + + if (sanlen + 4 != subjectaltname->value->length) { + log_print("x509_cert_subjectaltname: subjectaltname invalid " + "length"); + return 0; + } + *len = sanlen; + *altname = sandata; + return santype; +} + +int +x509_cert_get_subjects(void *scert, int *cnt, u_int8_t ***id, + u_int32_t **id_len) +{ + X509 *cert = scert; + X509_NAME *subject; + int type; + u_int8_t *altname; + u_int32_t altlen; + u_int8_t *buf = 0; + unsigned char *ubuf; + int i; + + *id = 0; + *id_len = 0; + + /* + * XXX There can be a collection of subjectAltNames, but for now I + * only return the subjectName and a single subjectAltName, if + * present. + */ + type = x509_cert_subjectaltname(cert, &altname, &altlen); + if (!type) { + *cnt = 1; + altlen = 0; + } else + *cnt = 2; + + *id = calloc(*cnt, sizeof **id); + if (!*id) { + log_print("x509_cert_get_subject: malloc (%lu) failed", + *cnt * (unsigned long)sizeof **id); + goto fail; + } + *id_len = malloc(*cnt * sizeof **id_len); + if (!*id_len) { + log_print("x509_cert_get_subject: malloc (%lu) failed", + *cnt * (unsigned long)sizeof **id_len); + goto fail; + } + /* Stash the subjectName into the first slot. */ + subject = X509_get_subject_name(cert); + if (!subject) + goto fail; + + (*id_len)[0] = + ISAKMP_ID_DATA_OFF + i2d_X509_NAME(subject, NULL) - + ISAKMP_GEN_SZ; + (*id)[0] = malloc((*id_len)[0]); + if (!(*id)[0]) { + log_print("x509_cert_get_subject: malloc (%d) failed", + (*id_len)[0]); + goto fail; + } + SET_ISAKMP_ID_TYPE((*id)[0] - ISAKMP_GEN_SZ, IPSEC_ID_DER_ASN1_DN); + ubuf = (*id)[0] + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ; + i2d_X509_NAME(subject, &ubuf); + + if (altlen) { + /* Stash the subjectAltName into the second slot. */ + buf = malloc(altlen + ISAKMP_ID_DATA_OFF); + if (!buf) { + log_print("x509_cert_get_subject: malloc (%d) failed", + altlen + ISAKMP_ID_DATA_OFF); + goto fail; + } + switch (type) { + case X509v3_DNS_NAME: + SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_FQDN); + break; + + case X509v3_RFC_NAME: + SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_USER_FQDN); + break; + + case X509v3_IP_ADDR: + /* + * XXX I dislike the numeric constants, but I don't + * know what we should use otherwise. + */ + switch (altlen) { + case 4: + SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV4_ADDR); + break; + + case 16: + SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV6_ADDR); + break; + + default: + log_print("x509_cert_get_subject: invalid " + "subjectAltName IPaddress length %d ", + altlen); + goto fail; + } + break; + } + + SET_IPSEC_ID_PROTO(buf + ISAKMP_ID_DOI_DATA_OFF, 0); + SET_IPSEC_ID_PORT(buf + ISAKMP_ID_DOI_DATA_OFF, 0); + memcpy(buf + ISAKMP_ID_DATA_OFF, altname, altlen); + + (*id_len)[1] = ISAKMP_ID_DATA_OFF + altlen - ISAKMP_GEN_SZ; + (*id)[1] = malloc((*id_len)[1]); + if (!(*id)[1]) { + log_print("x509_cert_get_subject: malloc (%d) failed", + (*id_len)[1]); + goto fail; + } + memcpy((*id)[1], buf + ISAKMP_GEN_SZ, (*id_len)[1]); + + free(buf); + buf = 0; + } + return 1; + +fail: + for (i = 0; i < *cnt; i++) + if ((*id)[i]) + free((*id)[i]); + if (*id) + free(*id); + if (*id_len) + free(*id_len); + if (buf) + free(buf); + return 0; +} + +int +x509_cert_get_key(void *scert, void *keyp) +{ + X509 *cert = scert; + EVP_PKEY *key; + + key = X509_get_pubkey(cert); + + /* Check if we got the right key type. */ + if (key->type != EVP_PKEY_RSA) { + log_print("x509_cert_get_key: public key is not a RSA key"); + X509_free(cert); + return 0; + } + *(RSA **)keyp = RSAPublicKey_dup(key->pkey.rsa); + + return *(RSA **)keyp == NULL ? 0 : 1; +} + +void * +x509_cert_dup(void *scert) +{ + return X509_dup(scert); +} + +void +x509_serialize(void *scert, u_int8_t **data, u_int32_t *datalen) +{ + u_int8_t *p; + + *datalen = i2d_X509((X509 *)scert, NULL); + *data = p = malloc(*datalen); + if (!p) { + log_error("x509_serialize: malloc (%d) failed", *datalen); + return; + } + *datalen = i2d_X509((X509 *)scert, &p); +} + +/* From cert to printable */ +char * +x509_printable(void *cert) +{ + char *s; + u_int8_t *data; + u_int32_t datalen, i; + + x509_serialize(cert, &data, &datalen); + if (!data) + return 0; + + s = malloc(datalen * 2 + 1); + if (!s) { + free(data); + log_error("x509_printable: malloc (%d) failed", + datalen * 2 + 1); + return 0; + } + for (i = 0; i < datalen; i++) + snprintf(s + (2 * i), 2 * (datalen - i) + 1, "%02x", data[i]); + free(data); + return s; +} + +/* From printable to cert */ +void * +x509_from_printable(char *cert) +{ + u_int8_t *buf; + int plen, ret; + void *foo; + + plen = (strlen(cert) + 1) / 2; + buf = malloc(plen); + if (!buf) { + log_error("x509_from_printable: malloc (%d) failed", plen); + return 0; + } + ret = hex2raw(cert, buf, plen); + if (ret == -1) { + free(buf); + log_print("x509_from_printable: badly formatted cert"); + return 0; + } + foo = x509_cert_get(buf, plen); + free(buf); + if (!foo) + log_print("x509_from_printable: " + "could not retrieve certificate"); + return foo; +} + +char * +x509_DN_string(u_int8_t *asn1, size_t sz) +{ + X509_NAME *name; + u_int8_t *p = asn1; + char buf[256]; /* XXX Just a guess at a maximum length. */ + + name = d2i_X509_NAME(NULL, &p, sz); + if (!name) { + log_print("x509_DN_string: d2i_X509_NAME failed"); + return 0; + } + if (!X509_NAME_oneline(name, buf, sizeof buf - 1)) { + log_print("x509_DN_string: X509_NAME_oneline failed"); + X509_NAME_free(name); + return 0; + } + X509_NAME_free(name); + buf[sizeof buf - 1] = '\0'; + return strdup(buf); +} +#endif /* USE_X509 */ diff --git a/keyexchange/isakmpd-20041012/x509.h b/keyexchange/isakmpd-20041012/x509.h new file mode 100644 index 0000000..adba74e --- /dev/null +++ b/keyexchange/isakmpd-20041012/x509.h @@ -0,0 +1,90 @@ +/* $OpenBSD: x509.h,v 1.21 2004/05/23 18:17:56 hshoexer Exp $ */ +/* $EOM: x509.h,v 1.11 2000/09/28 12:53:27 niklas Exp $ */ + +/* + * Copyright (c) 1998, 1999 Niels Provos. All rights reserved. + * Copyright (c) 1999 Angelos D. Keromytis. All rights reserved. + * Copyright (c) 2000, 2001 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. + * + * 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 "libcrypto.h" + +#define X509v3_RFC_NAME 1 +#define X509v3_DNS_NAME 2 +#define X509v3_IP_ADDR 7 + +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 don't care for now. + */ +struct x509_aca { + struct x509_attribval name1; + struct x509_attribval name2; +}; + +struct X509; +struct X509_STORE; + +/* Functions provided by cert handler. */ + +int x509_certreq_validate(u_int8_t *, u_int32_t); +void *x509_certreq_decode(u_int8_t *, u_int32_t); +void x509_cert_free(void *); +void *x509_cert_get(u_int8_t *, u_int32_t); +int x509_cert_get_key(void *, void *); +int x509_cert_get_subjects(void *, int *, u_int8_t ***, u_int32_t **); +int x509_cert_init(void); +int x509_crl_init(void); +int x509_cert_obtain(u_int8_t *, size_t, void *, u_int8_t **, + u_int32_t *); +int x509_cert_validate(void *); +void x509_free_aca(void *); +void *x509_cert_dup(void *); +void x509_serialize(void *, u_int8_t **, u_int32_t *); +char *x509_printable(void *); +void *x509_from_printable(char *); + +/* Misc. X509 certificate functions. */ + +char *x509_DN_string(u_int8_t *, size_t); +int x509_cert_insert(int, void *); +int x509_cert_subjectaltname(X509 * cert, u_char **, u_int *); +X509 *x509_from_asn(u_char *, u_int); +int x509_generate_kn(int, X509 *); +int x509_read_from_dir(X509_STORE *, char *, int); +int x509_read_crls_from_dir(X509_STORE *, char *); + +#endif /* _X509_H_ */ diff --git a/keyexchange/isakmpd-20041012/x509v3.cnf b/keyexchange/isakmpd-20041012/x509v3.cnf new file mode 100644 index 0000000..1e98444 --- /dev/null +++ b/keyexchange/isakmpd-20041012/x509v3.cnf @@ -0,0 +1,26 @@ +# default settings +CERTPATHLEN = 1 +CERTUSAGE = digitalSignature,keyCertSign +CERTIP = 0.0.0.0 +CERTFQDN = nohost.nodomain + +# This section should be referenced when building an x509v3 CA +# Certificate. +# The default path length and the key usage can be overriden +# modified by setting the CERTPATHLEN and CERTUSAGE environment +# variables. +[x509v3_CA] +basicConstraints=critical,CA:true,pathlen:$ENV::CERTPATHLEN +keyUsage=$ENV::CERTUSAGE + +# This section should be referenced to add an IP Address +# as an alternate subject name, needed by isakmpd +# The address must be provided in the CERTIP environment variable +[x509v3_IPAddr] +subjectAltName=IP:$ENV::CERTIP + +# This section should be referenced to add a FQDN hostname +# as an alternate subject name, needed by isakmpd +# The address must be provided in the CERTFQDN environment variable +[x509v3_FQDN] +subjectAltName=DNS:$ENV::CERTFQDN |