diff -ruN freeswan-1.5.orig/doc/pkix/README.certificates freeswan-1.5/doc/pkix/README.certificates
--- freeswan-1.5.orig/doc/pkix/README.certificates	Wed Dec 31 19:00:00 1969
+++ freeswan-1.5/doc/pkix/README.certificates	Thu Oct  5 07:05:59 2000
@@ -0,0 +1,452 @@
+	     Readme for certificate setup under FreeS/WAN
+
+			     Neil Dunbar
+			  5th November, 1999
+
+The certificate patches are (almost) always against the most recent
+snapshots available from
+ftp://ftp.xs4all.nl/~freeswan/snapshot.tar.gz. The patches are
+available from ftp://hplose.hpl.hp.com/pub/nd/pluto-openssl.tar.gz.
+
+The patches count on your having OpenSSL-0.9.3 or above installed on
+your system. Check out http://www.openssl.org for details on how to
+get OpenSSL. NB: the patches will *not* work on OpenSSL-0.9.2 or
+below.
+
+1. Applying the patches
+
+To apply the patches, cd to the build directory for the snapshot,
+which is generally freeswan-snap1999MonthDayb, and untar the
+pluto-openssl.tar.gz.
+
+Then type 'patch -p0 < pluto.diff', followed by 'patch -p0 <
+utils.diff'.
+
+2. Building and Installing FreeS/WAN
+
+Go to the pluto directory in the snapshot source directory, and edit
+the Makefile. Find the line OPENSSLROOT=.... and change the value of
+that variable to be the location of where you have installed the
+includes and libraries for OpenSSL. By default this is set to
+/usr/local/ssl.
+
+After that, build the system as per the FreeS/WAN installation notes.
+
+Installation, similarly, is no different to the normal method.
+
+3. Configuring FreeS/WAN
+
+In order to allow Pluto to use digital signatures, rather than
+preshared secrets to generate key material for IPsec, there are
+several options within the connection section of the file
+/etc/ipsec.conf which need to be set.
+
+For examples, we assume the host to host connection as follows
+
+	      west === westhop ...... easthop ==== east
+
+3.1 certfile
+
+The certfile setting should be set to the full path name of the file
+which contains the certificate whose private key will be used to
+perform the digital signatures. This file must be set in order for
+pluto to send the certificate to the other side, if requested. The
+certificate can  be in PEM or DER format.
+
+Example : /etc/ipsec/west.certificate.pem
+
+3.2 keyfile
+
+This setting should be set to the full path name to the file which
+contains the key which will be used to perform the digital
+signature.
+
+The key file can be stored in several formats, but at the moment, only
+unencrypted private keys can be used. If you use an encrypted one, the
+key load will fail, and signature/public key modes will cease to be
+available.
+
+The key files can be stored in DER or PEM format, using the OpenSSL
+private key format, which is specific to OpenSSL. Alternatively, the
+key can be stored in PKCS-8 format, which is system independent. The
+problem is that, for the moment, the OpenSSL key generation
+applications only store keys in OpenSSL format. To convert a key file
+into PKCS-8 form, use the following command (assuming that the file
+key.pem stores the OpenSSL private key in PEM format).
+
+openssl -nocrypt -topk8 -in key.pem -inform PEM -outform DER \
+	-out key.pk8
+
+(If the original key is in DER format, change '-inform PEM' to
+'-inform DER'. Similarly, if you want a PEM PKCS-8 file, change
+'-outform DER' to '-outform PEM).
+
+The key can be either an RSA or DSA key. Note that if an RSA key is
+loaded, DSS signature modes will not be offered (or accepted) from the
+other side. Similarly, a DSA key will prevent RSA modes from being
+selected.
+
+Example : /etc/ipsec/west.key.pk8
+
+3.3 peerfile
+
+This option is obsolete. It used to specify the path to certificates
+used to start public key authentication mode. This function has been
+subsumed by the certpath option.
+
+Do not use peerfile any more.
+
+3.4 certpath
+
+This gives a comma separated list of maps (see README.xmap) which can
+be used to look up certificates and/or CRLs by specifying their
+subject names, issuer names and such like.
+
+At the moment, the XMAP types are file, dir, db, ldap.
+
+Example : ldap:/etc/ldap.conf:ldap_ipsec,dir:/etc/ipsec
+
+(The first item specifies an LDAP directory lookup, whose details are
+specified in the file /etc/ldap.conf, and the identifier of which LDAP
+lookup to use within that file is 'ldap_ipsec'. The second specifies a
+local directory called /etc/ipsec, which should have files and
+symbolic links which index the relevant certificates in the
+directory).
+
+For the format of ldap files, and certificate directories, read the
+file README.xmap.
+
+3.5 certopts
+
+This setting is a comma separated list which gives a set of switches
+which control the behaviour of the public key encryption/signatures
+within pluto.
+
+To set an option in the list, one simply includes its name.
+
+To clear an option in the list, one includes its name, with a '!'
+symbol before the name.
+
+Example : !send,!pkcs7,!pk,strict,dss-sha,dss-alt
+
+The example means: turn ON the options 'strict', 'dss-sha' and
+'dss-alt', but turn OFF the options 'send', 'pkcs7' and 'pk'.
+
+The options are as follows
+
+3.5.1 'send'
+
+Set this option if you want your side of the connection to send its
+certificate to the other side as part of the main mode
+negotiations. This certificate must be in the set of certificates
+which the other side is expecting on this connection.
+
+3.5.2 'pkcs7'
+
+***NOT IMPLEMENTED YET***
+
+When sending a certificate, if this option is set, a PKCS7 encoding
+for the certificate will be chosen. If not set, a standard DER
+encoding of the X.509 certificate will be used.
+
+3.5.3 'pk'
+
+When choosing between digital signature and public key encryption
+ISAKMP methods, this option forces pluto to select public key
+encryption. If not set, pluto will choose digital signature methods.
+
+Note that this option used to be called 'rsa', but this name makes
+little sense, since both RSA and El Gamal encryption methods are
+selected by this option.
+
+3.5.3 'rev'
+
+If using public key encryption for Phase 1 negotiations, this option
+makes pluto prefer to use the revised mode method, rather than the
+standard public key mode. Revised public key mode uses fewer public
+key encryptions and transmits fewer bytes in the protocol (since
+public key ciphertexts are much larger than their symmetric key
+counterparts). Probably not a bad idea to use this one all the time if
+you want ID protection.
+
+3.5.4 'strict'
+
+This option forces verification to be very strict on the acceptability
+of certificates from the peer. If 'strict' mode is on, the following
+conditions must apply to the peer's certificate --
+
+1. For every signing certificate in the chain up to the root CA
+   certificate a valid CRL *must* be present. If a CRL is not
+   available, or the CRL is not valid (badly signed, expired, etc),
+   the verification of the certificate will fail.
+
+2. The name on the certificate must bear some relation to the name of
+   the peer, as given in the ISAKMP ID field. Assuming that the name
+   of the peer is an IPv4 address, which is the only supported one,
+   then the Common Name on the subject of the certificate must start
+   with the fully qualified domain name of the peer. Failing that, the
+   subjectAltName extension must contain an entry of type IP, which is
+   equal to the IP address given as the peer's name, or it must
+   contain an entry of type DNS, which must be equal to the name of
+   the resoved FQDN of the IP address given as the peer's name. If any
+   of these conditions are met, the certificate will be accepted. If
+   none of these conditions succeed, the verification will fail.
+
+If strict mode is not set, and these conditions fail, then debugging
+warnings will be logged, but verification will succeed. Be warned that
+this makes the setup less secure than would strict mode.
+
+3.5.5 'dss-sha'
+
+RFC2409 stipulates that the DSS signature method requires the output
+of a SHA1 hash to sign and send to the other side. It does not say
+whether this hash is a keyed one (eg HMAC) or unkeyed (ie plain SHA1).
+
+A subsequent document, draft-ietf-ipsec-ike-01.txt, given a formula
+for the plain SHA1 output. However, as Tero Kivinen of SSH has pointed
+out, most implementations of IKE use the standard HMAC method.
+
+This option forces pluto to use the plain SHA1 method outlined in the
+draft document. Clearing this option forces the HMAC method to be
+used.
+
+3.5.6 'dss-alt'
+
+RFC2409 stipulates that the encoding of a DSS signature should be 'r
+followed by s'. It does not say what format this should take. ANSI
+document X9.30 states that DSS output should be the DER encoding of
+the ASN.1 construct -
+
+ SEQUENCE {
+  r INTEGER;
+  s INTEGER;
+ };
+
+This puts some wrapper bytes around the 160 bit integers r and s, so
+that the signature is some 45-48 bytes long (depending on leading
+zeros within the integers).
+
+draft-ietf-ipsec-ike-01.txt states that the signature should be a
+single 320 bit string, with r occupying the first 160 bits and s
+occupying the next 160, without wrappers, such that all signatures are
+exactly 40 bytes long.
+
+By using the 'dss-alt' option, pluto is forced into the draft document
+mode of operation. By clearing it, the X9.30 implementation is used.
+
+4. Creating the certificates
+
+This section summarises the far more useful guide within the OpenSSL
+documentation, but should serve to generate the certificates and keys
+required for a connection. The document assumes that OpenSSL has been
+compiled and installed in /usr/local/ssl. Furthermore, it assumes that
+that configuration file for OpenSSL is stored in
+/usr/local/ssl/lib/openssl.cnf. If this is not the case, all 'openssl
+<command>' entries should be replaced by 'openssl <command> -config
+/path/to/openssl.cnf'.
+
+I am heavily indebted to Peter Onion of BT Labs for his efforts to
+debug and clarify this documentation. Peter: Your efforts are much
+appreciated.
+
+NB: This isn't the "correct" way to generate certs/CRLs. It's just my
+own recipe (largely from memory - it's been a while!) for doing
+so. It's not efficient, and you really should read the OpenSSL docs
+for better guidance.
+
+4.1 Edit openssl.cnf
+
+Ensure that the following settings for the CA_default section are more
+or less as follows -
+
+dir             = /usr/local/ssl
+certs           = $dir/certs
+crl_dir         = $dir/crl
+database        = $dir/index.txt
+new_certs_dir   = $dir/newcerts
+ 
+certificate     = $dir/cacert.pem
+serial          = $dir/serial
+crl             = $dir/crl.pem
+private_key     = $dir/private/cakey.pem
+RANDFILE        = $dir/private/.rand
+
+Fill in the default fields (country, organization, etc) as seems right
+for your setup.
+
+Create a file ca.ext containing the following -
+
+-----------------------------------
+# Extensions for a typical CA - PKIX recommendation.
+ 
+subjectKeyIdentifier=hash
+ 
+authorityKeyIdentifier=keyid:always,issuer:always
+basicConstraints = CA:true 
+keyUsage = cRLSign, keyCertSign
+nsCertType = sslCA, emailCA
+subjectAltName=email:copy
+----------------------------------
+
+4.2 Make the CA certificate
+
+Go to the directory /usr/local/ssl
+
+Generate your CA cert by the usual method
+
+openssl req -new -newkey rsa:1024 \
+  -keyout /usr/local/ssl/private/cakey.pem \
+  -out careq.pem
+
+Now sign the CA cert, citing the extensions for [v3_ca]
+
+openssl x509 -CAcreateserial -signkey private/cakey.pem -req \
+  -in careq.pem -out cacert.pem -days 2000 -extfile ca.ext
+
+This creates the self signed certificate which can be used to sign
+further certificates. Ensure that this cacert.pem file is made widely
+available to all hosts which will communicate via IPsec.
+
+4.3 Make an empty certificate database
+
+Execute the following commands, whilst in the directory /usr/local/ssl
+
+touch index.txt
+
+echo "01" > serial
+
+This creates the database, and starts issued certificates with the
+serial number starting at 1.
+
+4.4 Generate a CRL
+
+Use the command
+
+openssl ca -gencrl -out crl.pem
+
+to generate an (initially empty) CRL.  You should always have a
+current CRL, even if nothing has been revoked, since that proves
+*actively* that no certificates have been cancelled. Without a CRL,
+you are forced into the assumption that no certificates have been
+revoked.
+
+The CRL is placed in /usr/local/ssl/crl.pem. Distribute this file to
+all hosts holding the cacert.pem file. (Or, if you have an LDAP
+directory handy, publish the CRL there, so that all hosts can contact
+it).
+
+4.5 Generate the host certificate requests.
+
+On each host, generate a key and certificate request with the
+following command (I'll assume that ipsec certificates are in the
+directory /etc/ipsec, which must exist beforehand).
+
+I'll assume that the host is called foo, and lives in .mydomain.com,
+and has IP address aa.bb.cc.dd.
+
+openssl req -new -newkey rsa:1024 \
+  -nodes -keyout /etc/ipsec/foo.key -out foo.req.pem
+
+Fill in the fields for the subject name, and ensure that the common
+name section is set to 'foo.mydomain.com IPsec certificate #1', or
+some such thing - either way, it should start with foo.mydomain.com.
+
+See section 3.2 (keyfile) on converting private key files to the
+standard PKCS-8 format (which pluto can also understand). If you do
+this, you can delete the original private key file 'foo.key', once you
+have a PKCS-8 equivalent of it.
+
+Change the file permissions on foo.key to be 400 - Owner read only,
+and change to owner to be root.
+
+Transport the file foo.req.pem to the host which will sign certificate
+requests. This should be done via some secure method of
+transmission. In an ideal setup, your CA host shouldn't be connected
+to any network at all - but that's a site specific decision)
+
+4.6 Sign the certificate requests.
+
+On the CA host, edit the openssl.cnf file such that there is a section
+[svr_cert] at the bottom of the file with the following contents. 
+
+[ svr_cert ]
+basicConstraints=CA:FALSE
+nsCertType = server
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+nsComment = $ENV::NSCOMMENT
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer:always
+subjectAltName=email:copy,DNS:$ENV::HOSTFQDN,IP:$ENV::HOSTIP
+issuerAltName=issuer:copy       
+
+If this is not already done, alter the x509_extensions in the
+[CA_default] section such that it looks like -
+
+x509_extensions = $ENV::EXTENSION
+
+Now sign the request with the wrapper script 'signIPSEC', which
+is produced below. The script was written by Peter Onion.
+
+-----------------8<-------CUT HERE------8<----------------------------
+#! /bin/bash
+
+# Simple wrapper for "openssl ca" that sets environment to pass in
+# values for the svr_cert extension
+# P.J.Onion  23/9/1999
+
+if test $# -ne 3 ; then
+        echo "Usage: signIPSEC hostname ipaddress reqfile"
+        exit 1
+fi
+
+
+HOSTFQDN=$1
+HOSTIP=$2
+NSCOMMENT="IPsec Certificate for $1"
+EXTENSION=svr_cert
+
+export HOSTFQDN HOSTIP NSCOMMENT EXTENSION
+# Change /usr/local/ssl to be the directory in which OpenSSL
+# is installed.
+
+/usr/local/ssl/bin/openssl ca -in $3
+
+-----------8<----------CUT TO HERE --------8<-------------------------
+
+
+In the case above, you would do
+
+signIPSEC foo.mydomain.com 192.168.1.5 foo.req
+
+(assuming that foo.mydomain.com has the IP address 192.168.1.5, and
+that foo.req contains the PEM certificate request).
+
+Check the details that it prints, and commit the new certificate to
+the database. The new certificate will be in the directory
+/usr/local/ssl/newcerts. Tranport this file back to the requesting
+host and place it in the file /etc/ipsec/foo.pem. You can delete the
+file foo.req.pem now.
+
+Once the certificate has been delivered, move the file from newcerts
+into certs and run the command
+
+c_rehash /usr/local/ssl/certs
+
+to create the hashed directory.
+
+4.7 Renewing a certificate
+
+When you want to replace a certificate stored in file foo.pem, issue
+the command
+
+openssl ca -revoke foo.pem
+
+This changes the database to reflect the fact that the certificate has
+been cancelled, but does not update the CRL. Do that with the
+instructions in section 4.4. Make sure that the new CRL is propagated
+to all participating hosts.
+
+Now create the key/request/certificate as per sections 4.5 onwards.
+
+   ******************* End of document ********************
+
diff -ruN freeswan-1.5.orig/doc/pkix/README.xmap freeswan-1.5/doc/pkix/README.xmap
--- freeswan-1.5.orig/doc/pkix/README.xmap	Wed Dec 31 19:00:00 1969
+++ freeswan-1.5/doc/pkix/README.xmap	Thu Oct  5 07:05:59 2000
@@ -0,0 +1,389 @@
+			     README.xmap
+
+			     Neil Dunbar
+			  21st October, 1999
+
+1. Introduction
+
+As of the October release of the pluto-openssl patches, the
+certificate paths parameter has been replaced by a list of
+XMAPs. XMAPs are an abstraction of a dictionary lookup, which are
+designed to look up public key information. This includes X.509
+certificates, X.509 certificate revocation lists, and, in theory,
+simple public key values (NB: raw public keys are not supported yet).
+
+An XMAP is similar to the X509_LOOKUP system employed within OpenSSL
+to specify file and directory lookup. Indeed, XMAP has two mechanisms
+for lookup via file and directory, as well as others.
+
+The specification for an XMAP consists of a text string of the format
+<type>:<details>. The type denotes the sort of search which the XMAP
+library will carry out, and the details give appropriate parameter
+information so that the search can execute. As an example, a file XMAP
+on the file /etc/ipsec/certs.txt would have the form
+"file:/etc/ipsec/certs.txt".
+
+2. XMAP lookup
+
+(Programmer stuff - ignore if not interested)
+
+A lookup is a search which is identified by three parameters: the type
+of the thing being looked for, the search identifier and a search
+parameter (which is governed by the search identifier).
+
+The result of the search is a list (actually an OpenSSL STACK) of type
+X509_OBJECT (all of which fit the search criteria specified, sorted to
+be age order [most recent first, oldest last]. The type X509_OBJECT is
+defined in the OpenSSL header file x509_vfy.h. Note: this is NOT the
+same as the file X509_OBJECTS defined in x509.h. The C type
+declaration is reproduced here.
+
+typedef struct x509_object_st {
+   /* one of the above types */
+   int type;
+   union  {
+     char *ptr;
+     X509 *x509;
+     X509_CRL *crl;
+     EVP_PKEY *pkey;
+   } data; 
+} X509_OBJECT;
+
+Thus, if an X.509 certificate is stored in such an object, the type
+field will be set to X509_LU_X509, and <object>.data.x509 holds a
+pointer to the actual certificate data.
+
+Thus, to iterate through all certificates returned in a search, a C
+program fragment would look like the following.
+
+XMAP *xmap;
+int i;
+STACK_OF(X509_OBJECT) *sk;
+X509_OBJECT *obj;
+X509 *x;
+ :
+ :
+sk = XMAP_lookup(xmap, X509_LU_X509, <search id>, <search parameter>);
+for (i=0; i<sk_X509_OBJECT_num(sk); i++) {
+    obj = sk_X509_OBJECT_value(sk, i);
+    x = obj->data.x509;
+
+    /* Operations on the certificate 'x' */
+} 
+
+3. XMAP Search types
+
+The various search types are detailed in the following sections. The
+list of items are sorted (if possible) in date descending order, ie
+the most recent object is first in the return list, and the oldest
+object comes last. All duplicates are removed from the return list.
+
+3.1 "subject" (returns X.509 cert)
+
+The search looks for a certificate whose name is the the same as the
+X.509 name given in the parameter to the search.
+
+3.2 "issuer" (returns X.509 CRL)
+
+The search looks for a certificate revocation list (CRL) whose issuer
+is the same as the X.509 given as a search parameter.
+
+3.3 "uid" (returns X.509 cert)
+
+The search looks for the certificates which are listed as belonging to
+the user whose ID is given by the null terminated character string
+given as the search parameter.
+
+3.4 "dns" (returns X.509 cert)
+
+The search returns a list of the certificates which are listed as
+belonging to the fully qualified domain name (FQDN) as given in the
+search parameter, which is a null terminated character string.
+
+NB: Any certificate MUST have a subjectAltName which includes a DNS
+entry which is the same as the search string. This requirement is in
+addition to any indexing which is required for the individual XMAP
+search type.
+
+3.5 "ip" (returns X.509 cert)
+
+The search returns a list of the certificates which are listed as
+belonging to the IPv4 address given as a search parameter. The search
+parameter is a 4 octet string, which gives the IP address in network
+order; for example the ip address 15.144.59.30 would have the search
+parameter (in hex) 0F903B1E.
+
+As with DNS indexed certificates, the certificates must contain a
+subjectAltName with the correct IP entry within it.
+
+3.6 "ca" (returns X.509 cert)
+
+This search returns all CA certificates indexed in the list. A CA
+certificate is one which has a basicConstraints extension with the CA
+flag set to true. Also the CA has the subjectName and issuerName set
+to be the same.
+
+There is no search parameter for this search. It should be set to NULL
+in the XMAP_lookup() call.
+
+4. XMAP Types
+
+There are currently four types of XMAP: File, Directory, Berkeley DB
+and LDAP. Respectively, their type specifiers are "file", "dir", "db"
+and "ldap". Each subsection will detail the exact representation and
+expectations of the XMAP.
+
+4.1 File
+
+Type Specifier: "file"
+Syntax: file:<file name>
+
+This implements a simple flat file structure for lookups. The file can
+contain as many certificates in PEM format as desired. In order to
+index them, certain fields should be prepended to the certificates.
+
+For example a file might look like this.
+
+-----BEGIN CERTIFICATE-----
+MIIEHzCCAwegAwIBAgIBADANBgkqhkiG9w0BAQQFADCBpzELMAkGA1UEBhMCR0Ix
+HQ0Qb72dPlXYO20xtdMR9fX92PfSQSgAulNITYzusd8KE6yvJ8+HEbUuwXLHXZh4
+  :
+  :
+  :
+pk/Bv8iFUiZhH8EAr6SvF0AkpULi46bVcoQlr36Ax59uQ8OcJeNmljKYdbrN5uFL
+62In
+-----END CERTIFICATE-----
+
+uid: nd
+-----BEGIN CERTIFICATE-----
+MIIETDCCA7WgAwIBAgIQE9hfeRmSr51Wzgvm4B19JjANBgkqhkiG9w0BAQQFADCB
+njEPMA0GA1UEChMGaHAuY29tMRowGAYDVQQLExFJVCBJbmZyYXN0cnVjdHVyZTEL
+  :
+  :
+  :
+6pZk+pEpZ5S55lFP1QspTsBVbrBgsEuGFyGpHTo9sIEaQYxfRGNEvW+ZaEPU1HKo
+YVkAahuv5T21GdvouWdelA6l6uWMK/hfsQo9PdpBLDaUrwH5lkDuXcNk+LHZvVDt
+-----END CERTIFICATE-----                                       
+
+-----BEGIN X509 CRL-----
+MIICLTCCARUwDQYJKoZIhvcNAQEEBQAwgacxCzAJBgNVBAYTAkdCMR4wHAYDVQQI
+ExVTb3V0aCBHbG91Y2VzdGVyc2hpcmUxEDAOBgNVBAcTB0JyaXN0b2wxJTAjBgNV
+  :
+  :
+  :
+++lOGcX1WTtZ2dnV6Lb5r5xQ3IGavf2TKnu1/nCyAKFlF34+j7/+fIxT4iQiEDjk
+Z8Q76UEWVRMw7Tk63aAf0Yf5qaI1Tpd+SKhSTgc4arJH
+-----END X509 CRL-----
+
+ip: 15.144.59.30
+dns: pinky.hpl.hp.com
+-----BEGIN CERTIFICATE-----
+MIIHgTCCBmmgAwIBAgIBCjANBgkqhkiG9w0BAQQFADCBpzELMAkGA1UEBhMCR0Ix
+HjAcBgNVBAgTFVNvdXRoIEdsb3VjZXN0ZXJzaGlyZTEQMA4GA1UEBxMHQnJpc3Rv
+  :
+  :
+  :
+KkW/kYOxRrmg9KGnSVOolD1ueLYg9D4CtY30r1JGE/wixmIvQEP8JEv+X6Cr4Wiu
+VfENrF8=
+-----END CERTIFICATE-----
+
+This example indexes the fourth certificate as belonging to the IP
+address 15.144.59.30, as well as the DNS name "pinky.hpl.hp.com". The
+second certificate belongs to the user ID "nd".
+
+The file also contains a CRL embedded within it.
+
+Note: indexed searches in files are done by simple linear search. It's
+not an efficient means for searching serious amounts of data - use the
+other types for anything other than trivial data.
+
+
+4.2 Directory
+
+Type Specifier: "dir"
+Syntax: dir:<path to directory>
+
+The directory type is a derivation of the hashed directory used in the
+OpenSSL applications. The certificates are stored within a single
+level directory. Each certificate (or CRL) is stored in exactly one
+file in the directory. These files can be in either DER or PEM format,
+unlike the flat file above. To index the files for subject and issuer
+searches, you need to make a symbolic link from a hashed
+representation of the X.509 name of the certificate subject name (or
+CRL issuer name).
+
+To do this, you should execute the command -
+
+[for certificate files -- all on one line]
+
+ln -s certificate.pem
+  `openssl x509 -noout -hash -in certificate.pem`.cert.0
+
+NB: The .0 on the end is an arbitrary extension to the link name in
+case there might be a hash clash in the directory. You can call it
+anythin you like, but the ".cert" extension MUST be present -- unlike
+standard OpenSSL hash directories.
+
+[ for CRL files ]
+ln -s crl.pem
+  `openssl crl -noout -hash -in certificate.pem`.crl.0
+
+Again, the .0 is a differentiating extension, but the ".crl" is
+mandatory for marking out certificates.
+
+To index other attributes, you should make links which have the
+following appearance -
+
+uid-<user ID>.cert.0 [ denotes a user file ]
+dns-<fully qualified domain name>.cert.0 [ a DNS indexed cert ]
+ip-<IPv4 dotted form address>.cert.0 [ an IP indexed cert ]
+
+For example, assume that file pinky.pem held the certificate for DNS
+pinky.hpl.hp.com and/or IP address 15.144.59.30, the links would look
+like -
+
+dns-pinky.hpl.hp.com.cert.0  )__________\. pinky.pem
+ip-15.144.59.30.cert.0       )          /
+
+CA certificates don't need to be indexed. CA searches are performed by
+loading every certificate file in the directory and checking for a CA
+certificate, so it's failrly slow for this type of search.
+
+What Directories *are* good for is converting into a Berkeley DB file
+database - which is the fastest of all searches.
+
+3.3 - Berkeley DB searches
+
+Type Specifier: "db"
+Syntax: db:<path to db file>
+
+Assuming you have a Berkeley DB 1.85 library available on your system,
+you can index the certificates/CRLs in a DB hash file, which provides
+the fastest lookup of any of the methods.
+
+The internal details of the DB file are maintained in a separate file
+(README.XMAP.DB -- to be written -- nd). To make a DB file, you should
+create a directory as in the above section, then run the utility
+command "dir2hash" as follows, assuming that the directory to be
+hashed is called "my_dir" and the output DB file should be called
+certs.db :-
+
+  dir2hash -o dbhash.db my_dir
+
+Note: You don't have to make the hashed, DNS or IP links as in the
+directory above (they are automatically figured out by the dir2hash
+program from the subjectNames and subjectAltNames of the
+certificates/CRLs). You DO have to index the uid entries manually,
+since the certificates don't necessarily have the means of
+indentifying which users they belong to.
+
+Note that IPsec knows nothing of uid's and doesn;t use them yet, so a
+perfectly valid IPsec DB file can be mafe by putting all the
+certificates into a directory without any links at all, then running
+dir2hash on the directory.
+
+However, this still creates a single file which must be copied to all
+hosts participating in the IPsec process. Therefore, this mechanism
+will not scale past a few, easily managed hosts. For scalability you
+should use LDAP.
+
+3.4 - LDAP searches
+
+Type Specifier: "ldap"
+Syntax: ldap:<LDAP config file>:<LDAP identifier>
+
+Assuming that you have at least one LDAP server available on your
+network, you can make a config file (which is NOT the same as
+ipsec.conf) to specify how to search for entries in one or more LDAP
+servers. A single ldap configuration file can hold search details for
+many ldap servers. Each server specification must be identified by a
+unique ldap ID. This ID can be any alphanumeric string. If the LDAP
+identifier is omitted, then the first specification in the file will
+be used by default.
+
+The entries in the configuration file can be of the following form:
+
+<ID>_host_name: <FQDN of the LDAP server host. Default: localhost>
+
+<ID>_port: <port number on the server. Default: 389>
+
+<ID>_base: <base search string for server. Default: NONE>
+
+<ID>_timeout: <timeout for searches, in seconds: Default: 10>
+
+<ID>_bindDN: <DN to bind to the LDAP server as: Default: "">
+
+<ID>_bindPW: <Password for the bind DN: Default: "">
+
+Note that you MUST supply a base search string: the software cannot
+guess a reasonable default. Also, the bind DN and password is the only
+supported authentication mechanism. PLEASE don't put the LDAP server
+on a host which needs to reached via IPsec. If you're relying on it to
+serve all certificates, the LDAP connection won't work (since the
+IPsec connection might not be up yet).
+
+For each search type, you must specify the filter string and
+attributes which should be searched for from the LDAP directory.
+
+The filter string specification has the form
+
+<ID>_filter:<search index>:<return type>: <LDAP search filter>
+
+where <search index> is either "uid", "subject", "issuer", "dns" or
+"ip" as above, and <return type> is either "cert" (for X.509
+certificates) or "crl" for CRL searches. Either the <search index> or
+<return type> can be set to "*", which is a wildcard, meaning any
+index or any return type.
+
+Similarly, the attribute specification looks like:
+
+<ID>_attributes:<search index>:<return type>: <list of attributes>
+
+The <search string> and <return type> are as above, with the list of
+attributes a comma separated list of attributes.
+
+For an example, let us use the following file
+
+ldapnd_host_name = ldap.hpl.hp.com
+ldapnd_base = o=Hewlett-Packard Laboratories, c=GB
+ldapnd_filter:uid = (uid=%s)
+
+ldapnd_attributes:*:crl = certificaterevocationlist, certificaterevocationlist;binary
+
+ldapnd_filter:*:crl = (&(objectclass=certificationAuthority)(cn=%s))
+
+ldapnd_filter:ca = (objectclass=certificationauthority)
+
+ldapnd_filter:dns = (&(objectclass=hostRecord)(dNSRecord=%s))
+ldapnd_attributes:dns = servercertificate, servercertificate;binary
+
+ldapnd_filter:ip = (&(objectclass=hostRecord)(ipv4Address=%s))   
+ldapnd_attributes:ip = servercertificate, servercertificate;binary
+
+This stipulates an anonymous bind search of the LDAP server on
+ldap.hpl.hp.com port 389 (the default), whose base for searches is
+"o=Hewlett-Packard Laboratories,c=GB".
+
+For DNS searches, the filter used will be
+
+"(&(objectClass=hostRecord)(dNSRecord=%s))"
+
+where "%s" will be replaced by the DNS name being searched for. In the
+case of a search for pinky.hpl.hp.com, the search string will be -
+
+"(&(objectClass=hostRecord)(dNSRecord=pinky.hpl.hp.com))"
+
+For IP address searches, the filter used will be
+
+"(&(objectclass=hostRecord)(ipv4Address=%s))"
+
+Again, searching for the host with IP address 15.144.59.30, the host
+search filter will be -
+
+"(&(objectclass=hostRecord)(ipv4Address=15.144.59.30))"
+
+In both DNS and IP searches, the search will return the attributes
+"serverCertificate" and "serverCertificate;binary".
+
+Note that the return type is missing from many of the
+specifications. Return types default to "cert".
diff -ruN freeswan-1.5.orig/doc/pkix/ldap-ca.quickstart freeswan-1.5/doc/pkix/ldap-ca.quickstart
--- freeswan-1.5.orig/doc/pkix/ldap-ca.quickstart	Wed Dec 31 19:00:00 1969
+++ freeswan-1.5/doc/pkix/ldap-ca.quickstart	Thu Oct  5 07:05:59 2000
@@ -0,0 +1,169 @@
+
+Quick Instructions on how I set up my own LDAP CA.
+-- Luc Lanthier, 20001004
+
+1- openldap server for CA use:
+-----------------------------------------------------------------
+cd /usr/src
+tar xfvz openldap-stable-20000704.tgz 
+cd openldap-1.2.11
+./configure --enable-shared --with-gnu-ld --enable-ldapd 
+make depend
+make
+cd tests
+make
+cd ..
+make install
+-----------------------------------------------------------------
+
+
+2: Notes on LDIF files:
+-----------------------------------------------------------------
+
+Use your favorite editor and create an LDIF file that contains:
+            dn: dc=<MY-DOMAIN>, dc=<COM> 
+            objectclass: dcObject 
+            objectclass: organization 
+            o: <MY ORGANIZATION> 
+            dc: <MY-DOMAIN> 
+
+            dn: cn=Manager, dc=<MY-DOMAIN>, dc=<COM> 
+            objectclass: organizationalRole 
+            cn: Manager
+
+Now, you may run ldapadd(1) to insert these entries into your directory.
+            ldapadd -D "cn=Manager, dc=<MY-DOMAIN>, dc=<COM>" -W -f example.ldif
+
+
+Now we're ready to verify the added entries are in your directory. You 
+can use any LDAP client to do this, but our example uses the 
+ldapsearch(1) tool. Remember to replace dc=example,dc=com with the correct 
+values for your site:
+            ldapsearch -b 'dc=example,dc=com' '(objectclass=*)'
+
+-----------------------------------------------------------------
+
+3- How I created my own LDIF file
+-----------------------------------------------------------------
+----------- LDIF.sh:
+#!/bin/sh 
+parser="./parsecert.pl"
+
+cat <<EOM
+dn: dc=netwinder, dc=org
+objectclass: dcObject 
+objectclass: organization 
+o: Rebel.com
+dc: SoftEng
+
+dn: cn=Manager, dc=netwinder, dc=org
+objectclass: organizationalRole 
+cn: Manager
+
+dn: cn=CA, dc=netwinder, dc=org
+cn: CA
+objectclass: certificationAuthority
+EOM
+
+# the crl and the certs HAVE to be in DER format.
+openssl crl -in /var/lib/ssl/crl.pem -inform PEM -outform DER | \
+	ldif -b certificationrevocationlist 
+openssl x509 -in /var/lib/ssl/cacert.pem -inform PEM -outform DER | \
+	ldif -b cACertificate 
+cat <<EOM
+
+dn: cn=sticky, dc=netwinder, dc=org
+cn: sticky
+objectclass: hostRecord
+ipv4Address: 10.1.49.233
+EOM
+
+openssl x509 -in /var/lib/ssl/certs/01.pem -inform PEM -outform DER | \
+	ldif -b servercertificate 
+
+cat <<EOM
+dNSRecord: sticky.netwinder.org
+
+dn: cn=x86rack1, dc=netwinder, dc=org
+cn: x86rack1
+objectclass: hostRecord
+ipv4Address: 10.8.49.101
+EOM
+
+openssl x509 -in /var/lib/ssl/certs/02.pem -inform PEM -outform DER | \
+	ldif -b servercertificate 
+echo "dNSRecord: x86rack1.netwinder.org"
+-----------------------------------------------------------------
+
+
+4- Additional files to set up:
+
+----------- /usr/local/etc/openldap/slapd.oc-x509.conf 
+--------------------------------------
+objectclass hostRecord
+	requires
+		objectClass
+	allows
+		dNSRecord,
+		ipv4Address,
+		servercertificate
+--------------------------------------
+
+------------ /usr/local/etc/openldap/slapd.at-x509.conf 
+--------------------------------------
+attribute	servercertificate			bin
+--------------------------------------
+
+------------ /usr/local/etc/openldap/slapd.conf 
+--------------------------------------
+#
+# See slapd.conf(5) for details on configuration options.
+# This file should NOT be world readable.
+#
+include		/usr/local/etc/openldap/slapd.at.conf
+include		/usr/local/etc/openldap/slapd.oc.conf
+schemacheck	off
+#referral	ldap://root.openldap.org/
+
+pidfile		/usr/local/var/slapd.pid
+argsfile	/usr/local/var/slapd.args
+
+#################
+# x509
+include		/usr/local/etc/openldap/slapd.at-x509.conf
+include		/usr/local/etc/openldap/slapd.oc-x509.conf
+
+#######################################################################
+# ldbm database definitions
+#######################################################################
+
+database	ldbm
+suffix		"dc=netwinder, dc=org"
+#suffix		"o=My Organization Name, c=US"
+rootdn		"cn=Manager, dc=netwinder, dc=org"
+#rootdn		"cn=Manager, o=My Organization Name, c=US"
+# cleartext passwords, especially for the rootdn, should
+# be avoid.  See slapd.conf(5) for details.
+rootpw		ipsecsecret
+# database directory
+# this directory MUST exist prior to running slapd AND
+# should only be accessable by the slapd/tools  Mode 700 recommended.
+#directory	/usr/local/var/openldap-ldbm
+directory	/var/lib/ssl/ldap-ldbm
+
+index default pres,eq
+index objectClass,uid
+index cn,sn eq,sub,approx
+--------------------------------------
+-----------------------------------------------------------------
+
+
+
+5- How I regen'd my ldap DB:
+-----------------------------------------------------------------
+killall slapd
+rm -f /var/lib/ssl/ldap-ldbm/*
+sh LDIF.sh > LDIF
+/usr/local/libexec/slapd -s 1
+ldapadd -D "cn=Manager, dc=netwinder, dc=org" -W -f LDIF
+-----------------------------------------------------------------
diff -ruN freeswan-1.5.orig/doc/pkix/openssl-ca.quickstart freeswan-1.5/doc/pkix/openssl-ca.quickstart
--- freeswan-1.5.orig/doc/pkix/openssl-ca.quickstart	Wed Dec 31 19:00:00 1969
+++ freeswan-1.5/doc/pkix/openssl-ca.quickstart	Thu Oct  5 07:05:59 2000
@@ -0,0 +1,66 @@
+How I set up a CA on RedHat 6.2 and used it:
+
+1- install openssl...
+cd /usr/src/redhat/SRPMS
+scp root@10.8.49.101:/usr/src/redhat/SRPMS/openssl*.src.rpm .
+rpm --rebuild openssl-0.9.5a-1.src.rpm
+cd ../RPMS/i386/
+rpm -i openssl-*
+
+2- Setting up the openssl CA.
+cd /var/lib/ssl
+ln -s /etc etc
+vi /etc/openssl.cnf; # (see README.certificates section 4.1)
+vi ca.ext; # (see README.certificates section 4.2)
+openssl req -new -newkey rsa:1024 -keyout \
+	/var/lib/ssl/private/cakey.pem -out careq.pem
+openssl x509 -CAcreateserial -signkey private/cakey.pem -req \
+	-in careq.pem -out cacert.pem -days 2000 -extfile ca.ext
+touch index.txt
+echo "01" > serial
+openssl ca -gencrl -out crl.pem; # distribute/make available to all hosts.
+
+3- adding to hosts (presuming flat file format)
+scp crl.pem 10.1.49.233:/etc/ipsec
+scp cacert.pem 10.1.49.233:/etc/ipsec
+scp crl.pem 10.8.49.101:/etc/ipsec
+scp cacert.pem 10.8.49.101:/etc/ipsec
+
+4- Each client host -- generate certificate requests.
+cd /etc/ipsec
+# make sure the info entered for each client is DIFFERENT.
+openssl req -new -newkey rsa:1024 -nodes -keyout \
+	/etc/ipsec/`hostname`.key -out /etc/ipsec/`hostname`.req.pem
+ln -fs `hostname`.key privkey.pem
+ln -fs `hostname`.pem pubcert.pem; # will be created soon.
+chmod 400 `hostname`.key
+
+5- CA host -- Signing certificates 
+vi /etc/openssl.cnf; # (see README.certificates section 4.6)
+vi /usr/local/bin/signIPSEC; # (see README.certificates section 4.6)
+chmod 700 /usr/local/bin/signIPSEC
+# use: signIPSEC foo.mydomain.com 192.168.1.5 foo.req
+cd /var/lib/ssl/
+mkdir -p newcerts
+scp root@10.1.49.233:/etc/ipsec/*.req.pem .
+scp root@10.8.49.101:/etc/ipsec/*.req.pem .
+signIPSEC sticky.netwinder.org 10.1.49.233 sticky.req.pem
+scp newcerts/`cat serial.old`.pem root@10.1.49.233:/etc/ipsec/sticky.pem
+signIPSEC x86rack1.netwinder.org 10.8.49.101 x86rack1.req.pem
+scp newcerts/`cat serial.old`.pem root@10.8.49.101:/etc/ipsec/x86rack1.pem
+mv /var/lib/ssl/newcerts/* /var/lib/ssl/certs
+c_rehash /var/lib/ssl/certs
+
+6- CA host: prepping flat file for client hosts
+cd /var/lib/ssl
+for ii in certs/01.pem certs/02.pem cacert.pem crl.pem;
+do
+  cat $ii | \
+  perl -e '$printme = 0; while (<>) { if (/---BEGIN/) {$printme = 1;}; if ($printme) {print STDOUT $_;} }; print STDOUT "\n";' \
+  >> flatfile.txt
+done
+# flatfile is created. Send to Client hosts.
+scp flatfile.txt root@10.1.49.233:/etc/ipsec
+scp flatfile.txt root@10.8.49.101:/etc/ipsec
+
+
diff -ruN freeswan-1.5.orig/pluto/Makefile freeswan-1.5/pluto/Makefile
--- freeswan-1.5.orig/pluto/Makefile	Sat May 20 15:50:00 2000
+++ freeswan-1.5/pluto/Makefile	Thu Oct  5 07:18:12 2000
@@ -32,16 +32,39 @@
 LIBDESLITE=$(FREESWANLIBDIR)/libdes.a
 LIBGMP=$(FREESWANLIBDIR)/libgmp.a
 
+#OPENSSLROOT=/opt/ssl
+#OPENSSLINCLS=-I$(OPENSSLROOT)/include
+#OPENSSLLIBS=-L$(OPENSSLROOT)/lib -Wl,-rpath $(OPENSSLROOT)/lib -lcrypto
+#OPENSSLDEFS=-DOPENSSL
+
+OPENSSLROOT=/usr/lib
+OPENSSLINCLS=
+OPENSSLLIBS=-lcrypto
+OPENSSLDEFS=-DOPENSSL
+
+OPENSSLOBJS=openssl.o xmap.o xmap_file.o xmap_dir.o xmap_db.o xmap_ldap.o \
+            x_sobj.o
+ 
+LDAPROOT=/usr/local
+LDAPINCS=-I$(LDAPROOT)/include
+LDAPLIBS=-L$(LDAPROOT)/lib -lldap -llber -Wl,-rpath $(LDAPROOT)/lib
+LDAPDEFS=-DHAVE_LDAP
+ 
+DBROOT=/usr
+DBINCS=-I$(DBROOT)/include
+DBLIBS=-L$(DBROOT)/lib -ldb
+DBDEFS=-DHAVE_DB -DHAVE_DB185
+                   
 KLIPSD=../klips/src
 
 INSTALL=install
 
 # -O on Linux makes gcc coredump when compiling sha1.c
-CFLAGS = -g -Wall -W -Wmissing-prototypes -Wpointer-arith -Wbad-function-cast \
-	-Wcast-qual -Wmissing-declarations -Wwrite-strings -Wstrict-prototypes
+CFLAGS = -g -Wall -Wmissing-prototypes -Wpointer-arith -Wbad-function-cast \
+	-Wcast-qual -Wmissing-declarations -Wwrite-strings
 
 # where to find klips headers and FreeS/WAN headers
-HDRDIRS = -I$(KLIPSD) $(FREESWANINCLS)
+HDRDIRS = -I$(KLIPSD) $(FREESWANINCLS) $(OPENSSLINCLS) $(LDAPINCS) $(DBINCS) 
 
 # On non-LINUX systems, these one of these may be needed (see endian.h)
 # BYTE_ORDER = -DBIG_ENDIAN=4321 -DLITTLE_ENDIAN=1234 -DBYTE_ORDER=BIG_ENDIAN
@@ -74,22 +97,28 @@
 
 CPPFLAGS = $(HDRDIRS) $(BYTE_ORDER) \
 	-DPLUTO -DKLIPS -DDODGE_DH_MISSING_ZERO_BUG -DOLD_RESOLVER \
-	-DDEBUG -DGCC_LINT
+	-DDEBUG -DGCC_LINT $(OPENSSLDEFS) $(LDAPDEFS) $(DBDEFS)
 
 ALLFLAGS = $(CPPFLAGS) $(CFLAGS)
 
 # libefence is a free memory allocation debugger
 # Solaris 2 needs -lsocket -lnsl
-LIBSPLUTO = -lresolv # -lefence
+LIBSPLUTO = -lresolv $(OPENSSLLIBS) $(LDAPLIBS) $(DBLIBS) # -lefence
 
 LDFLAGS =
 
 # Solaris needs -lsocket -lnsl
 LIBSWHACK =
 
+LIBSD2H   = $(OPENSSLLIBS) $(DBLIBS)
+
 BINNAMEPLUTO = pluto
 BINNAMEWHACK = whack
 
+# Comment this out if you don't have Berkeley DB available, which,
+# if you're running Linux is a bit strange...
+BINNAMED2H   = dir2hash
+
 RM = /bin/rm
 RMFLAGS = -f
 
@@ -102,11 +131,11 @@
 	 pluto.8 ipsec.secrets.5
 
 DISTGCRYPT = \
-	gcryptfix.c gcryptfix.h \
-	dsa.c dsa.h \
-	elgamal.c elgamal.h \
-	primegen.c \
-	smallprime.c
+        gcryptfix.c gcryptfix.h \
+        g10_dsa.c g10_dsa.h \
+        elgamal.c elgamal.h \
+        primegen.c \
+        smallprime.c
 
 DISTSRC = \
 	connections.c connections.h \
@@ -140,19 +169,23 @@
 
 # start of support for DSS/DSA.  Not currently used.
 # OBJSGCRYPT =  gcryptfix.o dsa.o elgamal.o primegen.o smallprime.o
-OBJSGCRYPT =
+OBJSGCRYPT =  gcryptfix.o g10_dsa.o elgamal.o primegen.o smallprime.o
+
 
 OBJSPLUTO = connections.o constants.o cookie.o crypto.o defs.o log.o \
 	state.o main.o server.o timer.o id.o ipsec_doi.o kernel.o \
 	kernel_comm.o demux.o packet.o preshared.o dnskey.o rnd.o spdb.o \
-	sha1.o md5.o $(OBJSGCRYPT) $(LIBDESLITE) $(LIBGMP) $(FREESWANLIB)
+	sha1.o md5.o $(OBJSGCRYPT) $(LIBDESLITE) $(LIBGMP) $(FREESWANLIB) \
+	$(OPENSSLOBJS)
 
 OBJSWHACK = whack.o $(FREESWANLIB)
 
-all: $(BINNAMEPLUTO) $(BINNAMEWHACK)
+OBJSD2H = dir2hash.o
+
+all: $(BINNAMEPLUTO) $(BINNAMEWHACK) $(BINNAMED2H)
 
 install: all
-	$(INSTALL) $(BINNAMEPLUTO) $(BINNAMEWHACK) $(BINDIR)
+	$(INSTALL) $(BINNAMEPLUTO) $(BINNAMEWHACK) $(BINNAMED2H) $(BINDIR)
 	$(INSTALL) pluto.8 $(PMANDIR)/ipsec_pluto.8
 	../utils/manlink $(PMANDIR) ipsec_pluto.8
 	$(INSTALL) ipsec.secrets.5 $(FMANDIR)
@@ -164,6 +197,9 @@
 $(BINNAMEWHACK): $(OBJSWHACK)
 	$(CC) -o $(BINNAMEWHACK) $(OBJSWHACK) $(LIBSWHACK)
 
+$(BINNAMED2H): $(OBJSD2H)
+	$(CC) -o $(BINNAMED2H) $(OBJSD2H) $(LIBSD2H)
+
 distlist:
 	@echo $(DIST)
 
@@ -183,8 +219,10 @@
 realclean: clean
 
 clean:
-	$(RM) $(RMFLAGS) $(OBJSPLUTO) *.core core *~ a.out ktrace.out
-	$(RM) $(RMFLAGS) $(BINNAMEPLUTO) $(OBJSWHACK) $(BINNAMEWHACK)
+	$(RM) $(RMFLAGS) $(OBJSPLUTO) $(OBJSD2H) \
+		*.core core *~ a.out ktrace.out
+	$(RM) $(RMFLAGS) $(BINNAMEPLUTO) $(OBJSWHACK) $(BINNAMEWHACK) \
+		$(BINNAMED2H)
 
 .c.o:
 	$(CC) $(COPTS) $(ALLFLAGS) -c $<
@@ -222,9 +260,6 @@
 defs.o: defs.c
 demux.o: demux.c
 dnskey.o: dnskey.c
-dsa.o: dsa.c
-elgamal.o: elgamal.c
-gcryptfix.o: gcryptfix.c
 id.o: id.c
 ipsec_doi.o: ipsec_doi.c
 kernel.o: kernel.c
@@ -234,11 +269,9 @@
 md5.o: md5.c
 packet.o: packet.c
 preshared.o: preshared.c
-primegen.o: primegen.c
 rnd.o: rnd.c
 server.o: server.c
 sha1.o: sha1.c
-smallprime.o: smallprime.c
 spdb.o: spdb.c
 state.o: state.c
 timer.o: timer.c
@@ -298,23 +331,6 @@
 dnskey.o: preshared.h
 dnskey.o: dnskey.h
 dnskey.o: packet.h
-dsa.o: constants.h
-dsa.o: defs.h
-dsa.o: log.h
-dsa.o: rnd.h
-dsa.o: gcryptfix.h
-dsa.o: dsa.h
-elgamal.o: constants.h
-elgamal.o: defs.h
-elgamal.o: log.h
-elgamal.o: rnd.h
-elgamal.o: gcryptfix.h
-elgamal.o: elgamal.h
-gcryptfix.o: constants.h
-gcryptfix.o: defs.h
-gcryptfix.o: log.h
-gcryptfix.o: rnd.h
-gcryptfix.o: gcryptfix.h
 id.o: constants.h
 id.o: defs.h
 id.o: id.h
@@ -400,11 +416,6 @@
 preshared.o: state.h
 preshared.o: preshared.h
 preshared.o: log.h
-primegen.o: constants.h
-primegen.o: defs.h
-primegen.o: log.h
-primegen.o: rnd.h
-primegen.o: gcryptfix.h
 rnd.o: sha1.h
 rnd.o: constants.h
 rnd.o: defs.h
@@ -425,9 +436,6 @@
 server.o: kernel_comm.h
 sha1.o: sha1.h
 sha1.o: endian.h
-smallprime.o: constants.h
-smallprime.o: defs.h
-smallprime.o: gcryptfix.h
 spdb.o: constants.h
 spdb.o: defs.h
 spdb.o: id.h
diff -ruN freeswan-1.5.orig/pluto/connections.c freeswan-1.5/pluto/connections.c
--- freeswan-1.5.orig/pluto/connections.c	Wed Jun 21 14:24:31 2000
+++ freeswan-1.5/pluto/connections.c	Thu Oct  5 07:05:59 2000
@@ -39,6 +39,11 @@
 #include "preshared.h"
 #include "whack.h"
 
+#ifdef OPENSSL
+#include "openssl.h"
+#include "xmap.h"
+#endif
+
 static struct connection *connections = NULL;
 
 /* host_pair: a nexus of information about a pair of hosts.
@@ -242,6 +247,20 @@
     }
     unorient_connection(c);	/* won't delete c */
 
+#ifdef OPENSSL
+    {
+      int i;
+
+      for (i=0; i<MAX_OTHER; i++)
+	if (c->other[i].cert)
+	  X509_free((X509 *)(c->other[i].cert));
+    }
+
+    if (c->cert) X509_free((X509 *)(c->cert));
+    if (c->key) EVP_PKEY_free((EVP_PKEY *)(c->key));
+    if (c->lu) sk_XMAP_pop_free(c->lu, XMAP_free);
+#endif
+   
     /* find and delete c from connections list */
     list_rm(struct connection, next, c, connections);
     cur_connection = old_cur_connection;
@@ -444,7 +463,11 @@
 
 	for (; c != NULL; c = c->hp_next)
 	{
+#ifndef OPENSSL
 	    if ((c->policy ^ wm->policy) & (POLICY_PSK | POLICY_RSASIG))
+#else
+	    if ((c->policy ^ wm->policy) & (POLICY_PSK | POLICY_OPENSSL))
+#endif
 	    {
 		loglog(RC_CLASH
 		    , "authentication method disagrees with \"%s\", which is also for an unspecified peer"
@@ -499,6 +522,22 @@
 	    c->that = t;
 	}
 
+#ifdef OPENSSL
+	{
+		int i;
+
+		for(i=0; i<MAX_OTHER; i++) {
+			c->other[i].cert = NULL;
+			c->other[i].type = 0;
+		}
+	}
+	load_cert_and_key(wm->whack_certfile, wm->whack_keyfile,
+		(X509 **)&(c->cert), (EVP_PKEY **)&(c->key));
+	c->cert_options = parse_options(wm->whack_certopts);
+	make_lookups((STACK_OF(XMAP) **)(&(c->lu)), wm->whack_certpath);
+	strncpy(c->path, wm->whack_certpath, PATH_NAME_LIMIT);
+#endif
+
 	/* set internal fields */
 	c->next = connections;
 	connections = c;
@@ -806,7 +845,11 @@
 	    return NULL;	/* cannot determine PSK! */
 	break;
     case OAKLEY_RSA_SIG:
+#ifndef OPENSSL
 	auth_policy = POLICY_RSASIG;
+#else
+	auth_policy = POLICY_OPENSSL;
+#endif
 	my_RSA_pri = get_RSA_private_key(c);
 	if (my_RSA_pri == NULL)
 	    return NULL;	/* cannot determine my RSA private key! */
diff -ruN freeswan-1.5.orig/pluto/connections.h freeswan-1.5/pluto/connections.h
--- freeswan-1.5.orig/pluto/connections.h	Wed Jun 21 14:24:31 2000
+++ freeswan-1.5/pluto/connections.h	Thu Oct  5 07:05:59 2000
@@ -14,6 +14,10 @@
  * RCSID $Id: connections.h,v 1.38 2000/06/21 18:24:31 dhr Exp $
  */
 
+#ifdef OPENSSL
+#include "openssl_defs.h"
+#endif
+
 /* There are two kinds of connections:
  * - ISAKMP connections, between hosts (for IKE communication)
  * - IPsec connections, between clients (for secure IP communication)
@@ -78,6 +82,13 @@
  * the old one.  It is deleted when no longer in use.
  */
 
+#ifdef OPENSSL
+struct other_st {
+  u_int32_t type; /* type of certificate in 'cert': EVP_PKEY_RSA or EVP_PKEY_DSA */
+  void *cert;
+};
+#endif
+
 struct end {
     struct id id;
     struct in_addr	/* network order */
@@ -108,6 +119,18 @@
 
 struct connection {
     char *name;
+#ifdef OPENSSL
+    /* The declaration of these as void is truly horrific - they */
+    /* should be X509 and EVP_PKEY pointers. Unfortunately, if this */
+    /* is declared, the MD5 header files from OpenSSL conflict with those */
+    /* in the KLIPS source. Hence we cast these pointers to the right */
+    /* type at the time of use. It's disgusting, but I can't think of */
+    /* another way -- ND */
+    void *cert, *key, *lu;
+    struct other_st other[MAX_OTHER];
+    u_char path[PATH_NAME_LIMIT];
+    u_int32_t cert_options;
+#endif
     lset_t policy;
     time_t sa_ike_life_seconds;
     time_t sa_ipsec_life_seconds;
diff -ruN freeswan-1.5.orig/pluto/constants.c freeswan-1.5/pluto/constants.c
--- freeswan-1.5.orig/pluto/constants.c	Sun Jun 18 15:15:34 2000
+++ freeswan-1.5/pluto/constants.c	Thu Oct  5 07:05:59 2000
@@ -277,11 +277,37 @@
 enum_names ident_names =
     { ID_IPV4_ADDR, ID_KEY_ID, ident_name, NULL };
 
+#ifdef OPENSSL
+
+/* Certificate type values */
+static const char *const cert_name[] = {
+        "CERT_TYPE_NONE",
+	"CERT_TYPE_PKCS7",
+	"CERT_TYPE_PGP",
+	"CERT_TYPE_DNSKEY",
+	"CERT_TYPE_X509_SIG",
+	"CERT_TYPE_X509_KEX",
+	"CERT_TYPE_KERBEROS",
+	"CERT_TYPE_CRL",
+	"CERT_TYPE_ARL",
+	"CERT_TYPE_SPKI",
+	"CERT_TYPE_X509_ATTR",
+    };
+
+enum_names cert_names = 
+    { CERT_TYPE_NONE, CERT_TYPE_X509_ATTR, cert_name, NULL };
+
+#endif
+
 /* Goal BITs for establishing an SA */
 
 const char *const sa_policy_bit_names[] = {
 	"POLICY_PSK",
+#ifndef OPENSSL
 	"POLICY_RSASIG",
+#else
+	"POLICY_OPENSSL",
+#endif
 	"POLICY_ENCRYPT",
 	"POLICY_AUTHENTICATE",
 	"POLICY_TUNNEL",
diff -ruN freeswan-1.5.orig/pluto/constants.h freeswan-1.5/pluto/constants.h
--- freeswan-1.5.orig/pluto/constants.h	Tue Jun 20 16:09:45 2000
+++ freeswan-1.5/pluto/constants.h	Thu Oct  5 07:05:59 2000
@@ -433,17 +433,45 @@
 #define ID_DER_ASN1_GN              10
 #define ID_KEY_ID                   11
 
+#ifdef OPENSSL
+#define CERT_OPTION_SEND           0x01
+#define CERT_OPTION_PKCS7          0x02
+#define CERT_OPTION_PK             0x04
+#define CERT_OPTION_REV            0x08
+#define CERT_OPTION_STRICT         0x10
+#define CERT_OPTION_DSS_SHA        0x20
+#define CERT_OPTION_DSS_ALT        0x40
+
+extern enum_names cert_names;
+
+#define CERT_TYPE_NONE              0
+#define CERT_TYPE_PKCS7             1
+#define CERT_TYPE_PGP               2
+#define CERT_TYPE_DNSKEY            3
+#define CERT_TYPE_X509_SIG          4
+#define CERT_TYPE_X509_KEX          5
+#define CERT_TYPE_KERBEROS          6
+#define CERT_TYPE_CRL               7
+#define CERT_TYPE_ARL               8
+#define CERT_TYPE_SPKI              9
+#define CERT_TYPE_X509_ATTR        10
+#endif
+
 /* Policies for establishing an SA
  *
  * These are used to specify attributes (eg. encryption) and techniques for
- * (eg PFS) required of an SA.  POLICY_PSK and POLICY_RSASIG are for
+ * (eg PFS) required of an SA.  POLICY_PSK and POLICY_RSASIG/OPENSSL are for
  * ISAKMP SAs; the rest are about IPsec SAs
  */
 
 extern const char *const sa_policy_bit_names[];
 
 #define POLICY_PSK           LELEM(0)
+#ifndef OPENSSL
 #define POLICY_RSASIG        LELEM(1)
+#else
+#define POLICY_OPENSSL       LELEM(1)
+#endif
 
 #define POLICY_ENCRYPT       LELEM(2)
 #define POLICY_AUTHENTICATE  LELEM(3)
@@ -451,7 +479,11 @@
 #define POLICY_PFS           LELEM(5)
 
 #define POLICY_ISAKMP_SHIFT	0	/* log2(POLICY_PSK) */
+#ifndef OPENSSL
 #define POLICY_ISAKMP_MASK	(POLICY_PSK | POLICY_RSASIG)
+#else
+#define POLICY_ISAKMP_MASK  (POLICY_PSK | POLICY_OPENSSL)
+#endif
 #define POLICY_IPSEC_SHIFT	2	/* log2(POLICY_ENCRYPT) */
 
 /* Oakley transform attributes
diff -ruN freeswan-1.5.orig/pluto/crypto.h freeswan-1.5/pluto/crypto.h
--- freeswan-1.5.orig/pluto/crypto.h	Sun Dec 12 19:40:50 1999
+++ freeswan-1.5/pluto/crypto.h	Thu Oct  5 07:05:59 2000
@@ -56,7 +56,11 @@
 /* unification of cryptographic hashing mechanisms */
 
 union hash_ctx {
+#ifndef OPENSSL
 	MD5_CTX ctx_md5;
+#else
+	PLUTO_MD5_CTX ctx_md5;
+#endif
 	SHA1_CTX ctx_sha1;
     };
 
diff -ruN freeswan-1.5.orig/pluto/defs.c freeswan-1.5/pluto/defs.c
--- freeswan-1.5.orig/pluto/defs.c	Wed Jun 21 14:24:31 2000
+++ freeswan-1.5/pluto/defs.c	Thu Oct  5 07:05:59 2000
@@ -22,6 +22,8 @@
 #include "constants.h"
 #include "defs.h"
 #include "log.h"
+#include "id.h"
+#include "connections.h" /* needs id.h */
 #include "whack.h"	/* for RC_LOG_SERIOUS */
 
 const chunk_t empty_chunk = { NULL, 0 };
diff -ruN freeswan-1.5.orig/pluto/defs.h freeswan-1.5/pluto/defs.h
--- freeswan-1.5.orig/pluto/defs.h	Fri Feb 25 17:37:10 2000
+++ freeswan-1.5/pluto/defs.h	Thu Oct  5 07:05:59 2000
@@ -39,6 +39,22 @@
 typedef unsigned long so_serial_t;
 #define SOS_NOBODY  0	/* null serial number */
 
+#ifdef OPENSSL
+#include <des.h>
+
+typedef union _keysched_u {
+  struct _des3_ks { des_key_schedule ks[3]; } des3_ks;
+
+#if 0 /* *Please* don't define this - you *really* don't want single DES */
+  des_key_schedule des_ks;
+#endif
+
+#ifdef NOTYET
+  /* Other ciphers, eg CAST, RC5, etc... */
+#endif
+
+} keysched;
+#endif
 
 /* memory allocation */
 
diff -ruN freeswan-1.5.orig/pluto/demux.c freeswan-1.5/pluto/demux.c
--- freeswan-1.5.orig/pluto/demux.c	Wed Jun 21 14:24:32 2000
+++ freeswan-1.5/pluto/demux.c	Thu Oct  5 07:05:59 2000
@@ -132,6 +132,10 @@
 #include "whack.h"	/* requires connections.h */
 #include "server.h"
 
+#ifdef OPENSSL
+#include "openssl.h"
+#endif
+
 /* This file does basic header checking and demux of
  * incoming packets.
  */
@@ -234,11 +238,19 @@
 
     { STATE_MAIN_R1, SMF_PKE_AUTH
     , P(KE) | P(ID) | P(NONCE), P(VID) | P(HASH), PT(KE)
+#ifndef OPENSSL
     , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ },
+#else
+    , EVENT_RETRANSMIT, main_inI2_outR2_pk },
+#endif
 
     { STATE_MAIN_R1, SMF_RPKE_AUTH
     , P(NONCE) | P(KE) | P(ID), P(VID) | P(HASH) | P(CERT), PT(NONCE)
+#ifndef OPENSSL
     , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ },
+#else
+    , EVENT_RETRANSMIT, main_inI2_outR2_rpk },
+#endif
 
     /* for states from here on, output message must be encrypted */
 
@@ -256,11 +268,19 @@
 
     { STATE_MAIN_I2, SMF_PKE_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED
     , P(KE) | P(ID) | P(NONCE), P(VID), PT(HASH)
+#ifndef OPENSSL
     , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ },
+#else
+    , EVENT_RETRANSMIT, main_inR2_outI3_pk /* ??? not yet implemented */ },
+#endif
 
-    { STATE_MAIN_I2, SMF_ALL_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED
+    { STATE_MAIN_I2, SMF_RPKE_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED
     ,  P(NONCE) | P(KE) | P(ID), P(VID), PT(HASH)
+#ifndef OPENSSL
     , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ },
+#else
+    , EVENT_RETRANSMIT, main_inR2_outI3_rpk /* ??? not yet implemented */ },
+#endif
 
     /* for states from here on, input message must be encrypted */
 
@@ -275,11 +295,19 @@
 
     { STATE_MAIN_R2, SMF_DS_AUTH | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED
     , P(ID) | P(SIG), P(VID) | P(CERT), PT(ID)
+#ifndef OPENSSL
     , EVENT_SA_REPLACE, main_inI3_outR3 },
+#else
+    , EVENT_SA_REPLACE, main_inI3_outR3_whichds},
+#endif
 
     { STATE_MAIN_R2, SMF_PKE_AUTH | SMF_RPKE_AUTH | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED
     , P(HASH), P(VID), PT(HASH)
+#ifndef OPENSSL
     , EVENT_SA_REPLACE, unexpected /* ??? not yet implemented */ },
+#else
+    , EVENT_SA_REPLACE, main_inI3_outR3_pk},
+#endif
 
     /* STATE_MAIN_I3: R3 --> done
      * SMF_PSK_AUTH: HDR*, IDr1, HASH_R --> done
@@ -293,11 +321,20 @@
 
     { STATE_MAIN_I3, SMF_DS_AUTH | SMF_INITIATOR | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED
     , P(ID) | P(SIG), P(VID) | P(CERT), PT(NONE)
+#ifndef OPENSSL
     , EVENT_SA_REPLACE, main_inR3 },
+#else
+    , EVENT_SA_REPLACE, main_inR3_whichds },
+#endif
 
     { STATE_MAIN_I3, SMF_PKE_AUTH | SMF_RPKE_AUTH | SMF_INITIATOR | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED
     , P(HASH), P(VID), PT(NONE)
+#ifndef OPENSSL
     , EVENT_SA_REPLACE, unexpected /* ??? not yet implemented */ },
+#else
+    , EVENT_SA_REPLACE, main_inR3_pk },
+#endif
+
 
     /* STATE_MAIN_R3: can only get here due to packet loss */
     { STATE_MAIN_R3, SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RETRANSMIT_ON_DUPLICATE, LEMPTY, LEMPTY
@@ -397,7 +434,9 @@
     struct connection *c = st->st_connection;
 
     mksin(peer, c->that.host_addr.s_addr, c->that.host_port);
-    DBG_cond_dump_chunk(DBG_RAW, "sending:\n", st->st_tpacket);
+	DBG(DBG_RAW, 
+    	DBG_cond_dump_chunk(DBG_RAW, "sending:\n", st->st_tpacket);
+	);
     if (sendto(c->interface->fd
     , st->st_tpacket.ptr, st->st_tpacket.len, 0
     , (struct sockaddr *)&peer, sizeof(peer)) != (ssize_t)st->st_tpacket.len)
@@ -986,6 +1025,7 @@
 	    {
 		lset_t s = LELEM(np);
 
+// loglog(RC_LOG_SERIOUS, "parsing: (%s)", enum_show(&payload_names, np));
 		if (0 == (s & (needed | smc->opt_payloads
 		| LELEM(ISAKMP_NEXT_N) | LELEM(ISAKMP_NEXT_D))))
 		{
@@ -998,6 +1038,220 @@
 		needed &= ~s;
 	    }
 
+#ifdef OPENSSL
+            {
+              /* This code really shouldn't be here - it should be in */
+              /* the ipsec_doi code section with all the other protocol */
+              /* spec. Unfortunately, the "syntax checking" of the payload */
+              /* is done here, and the "semantic checking" of the payload */
+              /* is over in ipsec_doi. Since the fields of the ID payload */
+              /* are encrypted, and the ipsec_doi code checks those fields */
+              /* before processing the ID payload, we must ensure that the */
+              /* payload is decrypted and stored in the identification */
+              /* structure *before* the main mode routines process it. So */
+              /* the code is here. */
+ 
+              if ((IS_PHASE1(md.from_state)) && (md.st)) {
+                if ((md.st->st_oakley.auth == OAKLEY_RSA_ENC) || (md.st->st_oakley.auth == OAKLEY_ELGAMAL_ENC)) {
+                  if ((sd == &isakmp_identification_desc) ||
+                      (sd == &isakmp_nonce_desc)) {
+                    /* We need to decrypt this packet */
+                    char cpl[65], ppl[65];
+                    u_int16_t paylen;
+                    chunk_t ch;
+ 
+ 
+                    paylen = ntohs(*((u_int16_t *)(&(md.message_pbs.cur[2]))));
+                    clonetochunk(ch, &(md.message_pbs.cur[4]), paylen-4, "Ciphertext payload");
+ 
+                    /* Make a copy chunk of the payload after the generic */
+                    /* header, which should be the ciphertext of the ID payload
+*/
+                    if (sd == &isakmp_identification_desc) {
+                      snprintf(cpl, sizeof(cpl)-1, "ID payload (ciphertext): ");
+                      snprintf(ppl, sizeof(ppl)-1, "ID payload (plaintext): ");
+                    } else if (sd == &isakmp_nonce_desc) {
+                      snprintf(cpl, sizeof(cpl)-1,
+                               "Nonce payload (ciphertext): ");
+                      snprintf(ppl, sizeof(ppl)-1,
+                               "Nonce payload (plaintext): ");
+                    } else {
+                      snprintf(cpl, sizeof(cpl)-1,
+                               "Unknown payload (ciphertext): ");
+                      snprintf(ppl, sizeof(ppl)-1,
+                               "Unknown payload (plaintext): ");
+                    }
+ 
+                    if (!valid_ciphertext_length(paylen - 4, md.st->st_connection)) {
+                      log("Ciphertext length not a multiple of key modulus length for %s", cpl );
+                      free_md(&md);
+                      return;
+                    }
+					DBG(DBG_RAW,
+	                    DBG_dump_chunk(cpl, ch);
+					);
+                    privkey_decrypt_chunk( &ch, md.st );
+                    if ((ch.len == 0) || (ch.len > paylen)) {
+                      /* Error - the decryption has failed */
+                      log("Decryption failure - malformed payload in packet");
+                      free_md(&md);
+                      return;
+                    }
+					DBG(DBG_RAW,
+                    	DBG_dump_chunk(ppl, ch);
+					);
+                    /* Now restructure the message_pbs block, so that the */ 
+                    /* plaintext is now stored in the ID payload space */
+                    /* Adjust the length first */
+                    *((u_int16_t *)(&(md.message_pbs.cur[2]))) = htons(ch.len +
+4);
+                    /* Now copy the plaintext */
+                    memcpy(&(md.message_pbs.cur[4]), ch.ptr, ch.len);
+                    /* Clear the source plaintext */
+                    memset(ch.ptr, 0, ch.len);
+                    /* Shift down all subsequent payloads */
+                    memmove(&(md.message_pbs.cur[ch.len+4]),
+                            &(md.message_pbs.cur[paylen]),
+                            md.message_pbs.roof - &(md.message_pbs.cur[paylen]));
+                    /* Adjust the size of root downwards */
+                    md.message_pbs.roof -= paylen - ch.len - 4;
+                    freeanychunk(ch);
+                  }
+                } else if ((md.st->st_oakley.auth == OAKLEY_RSA_ENC_REV) ||
+			   (md.st->st_oakley.auth == OAKLEY_ELGAMAL_ENC_REV)) {
+                  if ((sd == &isakmp_identification_desc) ||
+                      (sd == &isakmp_nonce_desc) ||
+                      (sd == &isakmp_keyex_desc) ||
+                      (sd == &isakmp_ipsec_certificate_desc)) {
+                    if (sd == &isakmp_nonce_desc) {
+                      /* Nonce is public key encrypted */
+                      u_int16_t paylen;
+                      chunk_t ch;
+ 
+                      paylen = ntohs(*((u_int16_t *)(&(md.message_pbs.cur[2]))));
+                      clonetochunk(ch, &(md.message_pbs.cur[4]), paylen-4, "Ciphertext payload");
+ 
+                      if (!valid_ciphertext_length(paylen - 4, md.st->st_connection)) {
+                        log("Ciphertext length not a multiple of key modulus length for nonce" );
+                        free_md(&md);
+                        return;
+                      }
+						DBG(DBG_PARSING | DBG_CRYPT, 
+							DBG_dump_chunk("Nonce payload (ciphertext)", ch);
+						);
+                      privkey_decrypt_chunk( &ch, md.st );
+                      if ((ch.len == 0) || (ch.len > paylen)) {
+                        /* Error - the decryption has failed */
+                        log("Decryption failure - malformed payload in packet");
+                        free_md(&md);
+                        return;
+                      }
+						DBG(DBG_PARSING | DBG_CRYPT, 
+							DBG_dump_chunk("Nonce payload (plaintext)", ch);
+						);
+
+		      if ((md.st->st_state == STATE_MAIN_I1) ||
+			  (md.st->st_state == STATE_MAIN_I2) ||
+			  (md.st->st_state == STATE_MAIN_I3) ||
+			  (md.st->st_state == STATE_MAIN_I4)) {
+			if (derive_symmetric_key(md.st, ch,
+						 md.st->st_rcookie,
+						 COOKIE_SIZE,
+						 &md.st->st_ks_r,
+						 &md.st->st_ne_r) < 0) {
+			  log("Unable to derive symmetric key");
+			  free(&md);
+			  return;
+			}
+			memset(&md.st->st_ne_r_iv, 0, MAX_DIGEST_LEN);
+			DBG(DBG_PARSING,
+				DBG_dump_chunk("Received Ke_r:", md.st->st_ne_r);
+			);
+		      } else {
+			if (derive_symmetric_key(md.st, ch,
+						 md.st->st_icookie,
+						 COOKIE_SIZE,
+						 &md.st->st_ks_i,
+						 &md.st->st_ne_i) < 0) {
+			  log("Unable to derive symmetric key");
+			  free(&md);
+			  return;
+			}
+			memset(&md.st->st_ne_i_iv, 0, MAX_DIGEST_LEN);
+			DBG(DBG_PARSING,
+				DBG_dump_chunk("Received Ke_i:", md.st->st_ne_i);
+			);
+		      }
+
+                      /* Now restructure the message_pbs block, so that the */
+                      /* plaintext is now stored in the payload space */
+                      /* Adjust the length first */
+                      *((u_int16_t *)(&(md.message_pbs.cur[2]))) = htons(ch.len + 4);
+                      /* Now copy the plaintext */
+                      memcpy(&(md.message_pbs.cur[4]), ch.ptr, ch.len);
+                      /* Clear the source plaintext */
+                      memset(ch.ptr, 0, ch.len);
+                      /* Shift down all subsequent payloads */
+                      memmove(&(md.message_pbs.cur[ch.len+4]),
+                              &(md.message_pbs.cur[paylen]),
+                              md.message_pbs.roof - &(md.message_pbs.cur[paylen]));
+		      /* Adjust the size of roof downwards */
+                      md.message_pbs.roof -= paylen - ch.len - 4;
+
+		      /* Discard the plaintext chunk */
+		      memset(ch.ptr, 0, ch.len);
+		      freeanychunk(ch);
+		    } else {
+                      u_int16_t paylen;
+                      chunk_t ch, pch;
+ 
+                      paylen = ntohs(*((u_int16_t *)(&(md.message_pbs.cur[2]))));
+			DBG(DBG_CRYPT, 
+		      DBG_log("Encrypted payload length = %d", paylen);
+			);
+                      clonetochunk(ch, &(md.message_pbs.cur[4]), paylen-4, "Ciphertext payload");
+		      setchunk(pch, NULL, 0);
+		      if ((md.st->st_state == STATE_MAIN_I1) ||
+			  (md.st->st_state == STATE_MAIN_I2) ||
+			  (md.st->st_state == STATE_MAIN_I3) ||
+			  (md.st->st_state == STATE_MAIN_I4)) {
+			if (! decrypt_payload(md.st, &md.st->st_ks_r,
+					      md.st->st_ne_r_iv,
+					      ch, &pch) ) {
+			  log("Unable to decrypt responder payload");
+			  free(&md);
+			  return;
+			}
+		      } else {
+			if (!decrypt_payload(md.st, &md.st->st_ks_i,
+					     md.st->st_ne_i_iv,
+					     ch, &pch) ) {
+			  log("Unable to decrypt initiator payload");
+			  free(&md);
+			  return;
+			}
+		      }
+                      *((u_int16_t *)(&(md.message_pbs.cur[2]))) =
+			htons(pch.len + 4);
+                      /* Now copy the plaintext */
+                      memcpy(&(md.message_pbs.cur[4]), pch.ptr, pch.len);
+                      /* Shift down all subsequent payloads */
+                      memmove(&(md.message_pbs.cur[pch.len+4]),
+                              &(md.message_pbs.cur[paylen]),
+                              md.message_pbs.roof - &(md.message_pbs.cur[paylen]));
+		      /* Adjust the size of roof downwards */
+                      md.message_pbs.roof -= paylen - pch.len - 4;
+
+		      freeanychunk(ch);
+		      memset(pch.ptr, 0, pch.len);
+		      freeanychunk(pch);
+		    }
+		  } /* Otherwise, let everything else pass */
+		} /* end if (revised PK mode ) */
+	      } /* end if Phase 1 */
+	    } /* end OPENSSL handling */
+#endif /* OPENSSL */
+                                                                             
 	    if (!in_struct(&pd->payload, sd, &md.message_pbs, &pd->pbs))
 	    {
 		loglog(RC_LOG_SERIOUS, "%smalformed payload in packet", excuse);
@@ -1141,25 +1395,25 @@
 	{
 	    loglog(RC_LOG_SERIOUS, "ignoring informational payload, type %s"
 		, enum_show(&ipsec_notification_names, p->payload.notification.isan_type));
-	    DBG_cond_dump(DBG_PARSING, "info:", p->pbs.cur, pbs_left(&p->pbs));
+	   	DBG_cond_dump(DBG_RAW, "info:", p->pbs.cur, pbs_left(&p->pbs));
 	}
 
 	for (p = md.chain[ISAKMP_NEXT_D]; p != NULL; p = p->next)
 	{
 	    loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload");
-	    DBG_cond_dump(DBG_PARSING, "del:", p->pbs.cur, pbs_left(&p->pbs));
+	    DBG_cond_dump(DBG_RAW, "del:", p->pbs.cur, pbs_left(&p->pbs));
 	}
 
 	for (p = md.chain[ISAKMP_NEXT_VID]; p != NULL; p = p->next)
 	{
 	    loglog(RC_LOG_SERIOUS, "ignoring Vendor ID payload");
-	    DBG_cond_dump(DBG_PARSING, "VID:", p->pbs.cur, pbs_left(&p->pbs));
+	    DBG_cond_dump(DBG_RAW, "VID:", p->pbs.cur, pbs_left(&p->pbs));
 	}
 
 	for (p = md.chain[ISAKMP_NEXT_CERT]; p != NULL; p = p->next)
 	{
 	    loglog(RC_LOG_SERIOUS, "ignoring Certificate payload");
-	    DBG_cond_dump(DBG_PARSING, "CERT:", p->pbs.cur, pbs_left(&p->pbs));
+	    DBG_cond_dump(DBG_RAW, "CERT:", p->pbs.cur, pbs_left(&p->pbs));
 	}
     }
 
@@ -1408,3 +1662,306 @@
     }
     free_md(&md);
 }
+
+#ifdef OPENSSL
+int
+derive_symmetric_key( struct state *st, const chunk_t nonce,
+		      const u_char *seedptr, const size_t seedlen,
+		      keysched *ks,
+		      chunk_t *key )
+{
+  struct hmac_ctx ctx;
+  chunk_t k, kk, kchain;
+  chunk_t ne;
+  char nestr[8];
+  int needed_len;
+
+  DBG(DBG_PARSING, 
+	  DBG_dump_chunk("Deriving symmetric key from: ", nonce);
+	  DBG_dump("Initial Cookie:", seedptr, seedlen);
+	);
+  switch(st->st_oakley.encrypt) {
+#if 0
+    /* We really shouldn't deal with DES, */
+    /* uncomment this if you must have it */
+  case OAKLEY_DES_CBC:
+    needed_len = DES_CBC_BLOCK_SIZE;
+    break;
+#endif
+#ifdef NOTYET
+  case OAKLEY_IDEA_CBC:
+    needed_len = IDEA_CBC_KEY_LEN;
+    break;
+  case OAKLEY_BLOWFISH_CBC:
+    needed_len = BLOWFISH_CBC_KEY_LEN;
+    break;
+  case OAKLEY_RC5_R16_B64_CBC:
+    needed_len = RC5_CBC_KEY_LEN;
+    break;
+#endif
+  case OAKLEY_3DES_CBC:
+    needed_len = DES_CBC_BLOCK_SIZE * 3;
+    break;
+#ifdef NOTYET
+  case OAKLEY_CAST_CBC:
+    needed_len = CAST_CBC_KEY_LEN;
+    break;
+#endif
+  default:
+    log("Unknown block cipher ID for symmetric cipher");
+    return -1;
+  }
+
+  /* Generate initial decryption key material */
+  /* key = prf(Nonce-X, Cookie-X); X={I,R} */
+  ne.ptr = NULL;
+  hmac_init_chunk(&ctx, st->st_oakley.hasher, nonce);
+  hmac_update(&ctx, seedptr, seedlen);
+  hmac_final_chunk(ne, nestr, &ctx);
+  clonetochunk(*key, ne.ptr, ne.len, "Initial key material");
+
+  if (key->len < needed_len) {
+    freeanychunk(*key);
+    kchain.ptr = alloc_bytes(1, "initial zero octet");
+    kchain.len = 1;
+    memset(kchain.ptr, 0, kchain.len);
+    while (key->len < needed_len) {
+      kk.ptr = NULL;
+      hmac_init_chunk(&ctx, st->st_oakley.hasher, ne);
+      hmac_update_chunk(&ctx, kchain);
+      hmac_final_chunk(kk, "extra key material", &ctx);
+      clonereplacechunk(kchain, kk.ptr, kk.len, "chain key material");
+      /* Now append kk to key */
+      if (! key->ptr ) {
+	clonetochunk(*key, kk.ptr, kk.len, "initial extra key material");
+      } else {
+	k.ptr = alloc_bytes(key->len + kk.len, "appended key material");
+	k.len = key->len + kk.len;
+	memcpy(k.ptr, key->ptr, key->len);
+	memcpy(&(k.ptr[key->len]), kk.ptr, kk.len);
+	freeanychunk(*key);
+	key->len = k.len;
+	key->ptr = k.ptr;
+      }
+      freeanychunk(kk);
+    }
+    freeanychunk(kchain);
+  }
+
+  switch(st->st_oakley.encrypt) {
+#if 0
+    /* We really shouldn't deal with DES, */
+    /* uncomment this if you must have it */
+  case OAKLEY_DES_CBC:
+    (void)des_set_key((des_cblock *)key->ptr, ks->des_ks);
+    break;
+#endif
+#ifdef NOTYET
+  case OAKLEY_IDEA_CBC:
+    break;
+  case OAKLEY_BLOWFISH_CBC:
+    break;
+  case OAKLEY_RC5_R16_B64_CBC:
+    break;
+#endif
+  case OAKLEY_3DES_CBC:
+    (void)des_set_key((des_cblock *)key->ptr + 0, ks->des3_ks.ks[0]);
+    (void)des_set_key((des_cblock *)key->ptr + 1, ks->des3_ks.ks[1]);
+    (void)des_set_key((des_cblock *)key->ptr + 2, ks->des3_ks.ks[2]);
+    break;
+#ifdef NOTYET
+  case OAKLEY_CAST_CBC:
+    break;
+#endif
+  }
+
+  return 0;
+}
+
+bool
+encrypt_payload( struct state *st, keysched *ks, u_char *iv,
+		 chunk_t inp, chunk_t *out )
+{
+  chunk_t temp;
+  int blocklen;
+  u_char pv;
+
+  switch(st->st_oakley.encrypt) {
+#if 0
+  case OAKLEY_DES_CBC:
+    blocklen = DES_CBC_BLOCK_SIZE;
+    break;
+#endif
+#ifdef NOTYET
+  case OAKLEY_IDEA_CBC:
+    break;
+  case OAKLEY_BLOWFISH_CBC:
+    break;
+  case OAKLEY_RC5_R16_B64_CBC:
+    break;
+#endif
+  case OAKLEY_3DES_CBC:
+    blocklen = DES_CBC_BLOCK_SIZE;
+    break;
+#ifdef NOTYET
+  case OAKLEY_CAST_CBC:
+    break;
+#endif
+  }
+
+  /* Pad the input up to a block size multiple */
+  if (inp.len % blocklen == 0) { /* Add a full block for padding */
+    pv = (u_char)blocklen;
+    temp.len = inp.len + (size_t)pv;
+  } else {
+    pv = (u_char)(blocklen - 1  - ((inp.len + blocklen - 1) % blocklen));
+    temp.len = inp.len + (size_t)pv;
+  }
+
+  temp.ptr = alloc_bytes(temp.len, "padded plaintext");
+  memset(temp.ptr, 0, temp.len);
+  clonetochunk(*out, temp.ptr, temp.len, "ciphertext");
+  memcpy(temp.ptr, inp.ptr, inp.len);
+  temp.ptr[temp.len-1] = pv;
+  
+  DBG(DBG_PARSING | DBG_CRYPT,
+	  DBG_dump_chunk("Plaintext:", temp);
+	  DBG_dump("Old IV: ", iv, blocklen);
+	);
+
+  switch(st->st_oakley.encrypt) {
+#if 0
+  case OAKLEY_DES_CBC:
+    des_ncbc_encrypt((des_cblock *)temp.ptr, (des_cblock *)out->ptr,
+		     temp.len, ks->des_ks, (des_cblock *)iv, TRUE);
+    break;
+#endif
+#ifdef NOTYET
+  case OAKLEY_IDEA_CBC:
+    break;
+  case OAKLEY_BLOWFISH_CBC:
+    break;
+  case OAKLEY_RC5_R16_B64_CBC:
+    break;
+#endif
+  case OAKLEY_3DES_CBC:
+    des_ede3_cbc_encrypt((des_cblock *)temp.ptr, (des_cblock *)out->ptr,
+			 temp.len,
+			 ks->des3_ks.ks[0],
+			 ks->des3_ks.ks[1],
+			 ks->des3_ks.ks[2],
+			 (des_cblock *)iv, TRUE);
+    break;
+#ifdef NOTYET
+  case OAKLEY_CAST_CBC:
+    break;
+#endif
+  }
+
+  DBG(DBG_PARSING | DBG_CRYPT,
+	DBG_dump_chunk("Ciphertext: ", *out);
+	DBG_dump("New IV: ", iv, blocklen);
+	);
+  freeanychunk(temp);
+  return TRUE;
+}
+
+bool
+decrypt_payload( struct state *st, keysched *ks, u_char *iv,
+		 chunk_t inp, chunk_t *out )
+{
+  chunk_t temp;
+  int blocklen;
+
+  switch(st->st_oakley.encrypt) {
+#if 0
+  case OAKLEY_DES_CBC:
+    blocklen = DES_CBC_BLOCK_SIZE;
+    break;
+#endif
+#ifdef NOTYET
+  case OAKLEY_IDEA_CBC:
+    break;
+  case OAKLEY_BLOWFISH_CBC:
+    break;
+  case OAKLEY_RC5_R16_B64_CBC:
+    break;
+#endif
+  case OAKLEY_3DES_CBC:
+    blocklen = DES_CBC_BLOCK_SIZE;
+    break;
+#ifdef NOTYET
+  case OAKLEY_CAST_CBC:
+    break;
+#endif
+  }
+
+  if (inp.len % blocklen != 0) {
+    log("Ciphertext is not a multiple of block length");
+    return FALSE;
+  }
+
+  DBG(DBG_PARSING | DBG_CRYPT,
+	DBG_dump_chunk("Ciphertext: ", inp);
+	DBG_dump("Old IV: ", iv, blocklen);
+	);
+
+  temp.ptr = alloc_bytes(inp.len, "temporary plaintext");
+  temp.len = inp.len;
+  memset(temp.ptr, 0, temp.len);
+
+  switch(st->st_oakley.encrypt) {
+#if 0
+  case OAKLEY_DES_CBC:
+    des_ncbc_encrypt((des_cblock *)inp.ptr, (des_cblock *)temp.ptr,
+		     inp.len, ks->des_ks, (des_cblock *)iv, FALSE);
+    break;
+#endif
+#ifdef NOTYET
+  case OAKLEY_IDEA_CBC:
+    break;
+  case OAKLEY_BLOWFISH_CBC:
+    break;
+  case OAKLEY_RC5_R16_B64_CBC:
+    break;
+#endif
+  case OAKLEY_3DES_CBC:
+    des_ede3_cbc_encrypt((des_cblock *)inp.ptr, (des_cblock *)temp.ptr,
+			 inp.len,
+			 ks->des3_ks.ks[0],
+			 ks->des3_ks.ks[1],
+			 ks->des3_ks.ks[2],
+			 (des_cblock *)iv, FALSE);
+    break;
+#ifdef NOTYET
+  case OAKLEY_CAST_CBC:
+    break;
+#endif
+  }
+
+  /* Strip padding from plaintext */
+  if ((temp.ptr[temp.len-1] < (u_char)1) ||
+      (temp.ptr[temp.len-1] > (u_char)blocklen) ||
+      (temp.ptr[temp.len-1] > temp.len)) {
+    /* Impossible padding value */
+    log("Impossible plaintext padding value: %d", temp.ptr[temp.len-1]);
+    memset(temp.ptr, 0, temp.len);
+    freeanychunk(temp);
+    return FALSE;
+  }
+
+  out->len = temp.len - (size_t)(temp.ptr[temp.len-1]);
+  out->ptr = alloc_bytes(inp.len, "plaintext");
+  memcpy(out->ptr, temp.ptr, out->len);
+
+  DBG(DBG_PARSING | DBG_CRYPT,
+	DBG_dump_chunk("Plaintext: ", *out);
+	DBG_dump("New IV: ", iv, blocklen);
+	);
+
+  memset(temp.ptr, 0, temp.len);
+  freeanychunk(temp);
+  return TRUE;
+}
+
+#endif
diff -ruN freeswan-1.5.orig/pluto/demux.h freeswan-1.5/pluto/demux.h
--- freeswan-1.5.orig/pluto/demux.h	Tue Dec 14 15:31:02 1999
+++ freeswan-1.5/pluto/demux.h	Thu Oct  5 07:05:59 2000
@@ -76,3 +76,17 @@
 } stf_status;
 
 typedef stf_status state_transition_fn(struct msg_digest *md);
+
+#ifdef OPENSSL
+
+extern int derive_symmetric_key( struct state *st, const chunk_t nonce,
+				 const u_char *seedptr,
+				 const size_t seedlen,
+				 keysched *ks,
+				 chunk_t *key );
+extern bool encrypt_payload( struct state *st, keysched *ks, u_char *iv,
+			   chunk_t inp, chunk_t *out );
+extern bool decrypt_payload( struct state *st, keysched *ks, u_char *iv,
+			     chunk_t inp, chunk_t *out );
+
+#endif /* OPENSSL */
diff -ruN freeswan-1.5.orig/pluto/dir2hash.c freeswan-1.5/pluto/dir2hash.c
--- freeswan-1.5.orig/pluto/dir2hash.c	Wed Dec 31 19:00:00 1969
+++ freeswan-1.5/pluto/dir2hash.c	Thu Oct  5 07:05:59 2000
@@ -0,0 +1,1071 @@
+/*
+ * Convert an XMAP hash directory to a Berkeley DB hash file
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <ctype.h>
+
+#ifdef HAVE_DB185
+#include <db_185.h>
+#else
+#include <db.h>
+#endif
+
+#include <openssl/pem.h>
+#include <openssl/bio.h>
+#include <openssl/sha.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#define VERSION_SIZE 4
+static unsigned char version_data[] = { '\00', '\00', '\00', '\01' };
+
+#define TAGLEN 4
+
+#define UID_PREFIX "uid-"
+
+#define X509_TYPE 0
+#define X509_CRL_TYPE 1
+
+typedef struct _cert_st {
+  u_int8_t type;
+  union _inf {
+    X509 *x;
+    X509_CRL *c;
+  } info;
+  unsigned char *d;
+  size_t dlen;
+  unsigned char digest[SHA_DIGEST_LENGTH];
+  struct _cert_st *next;
+} CERT;
+
+typedef struct _xname_list_st {
+  unsigned char digest[SHA_DIGEST_LENGTH];
+  struct _xname_list_st *next;
+} XNAME_LIST;
+
+typedef struct _xname_st {
+  unsigned char *d;
+  size_t dlen;
+  int lcount;
+  XNAME_LIST *list;
+  struct _xname_st *next;
+} XNAME;
+
+static const char *hashout = "certhash.db";
+
+void *nalloc( size_t s );
+void dump( unsigned char *p, size_t l, const char *name );
+void free_xname_list_node( XNAME_LIST *node );
+void free_xname_node( XNAME *node );
+void free_xnames( XNAME **nl );
+XNAME *alloc_xname_node( const unsigned char *n, const size_t s );
+int add_unique_xname( XNAME **nl, X509_NAME *name,
+		      const unsigned char *digest );
+int add_unique_xname( XNAME **nl, X509_NAME *name,
+		      const unsigned char *digest );
+void add_unique_dns(XNAME **nl, X509 *x, const unsigned char *digest );
+void add_unique_ip(XNAME **nl, X509 *x, const unsigned char *digest );
+int isCA( X509 *x );
+void free_cert_node( CERT *c );
+int add_unique_xinf( CERT **cl, XNAME **xl,
+		     XNAME **cal, XNAME **dnl, XNAME **ipl,
+		     unsigned int type, void *x );
+void putcerts(DB *db, int start, int end, char *argv[],
+	      CERT **cl, XNAME **xl, XNAME **cal, XNAME **dnl, XNAME **ipl);
+void free_cert_list( CERT **cl );
+void putcrls(DB *db, int start, int end, char *argv[], CERT **cl, XNAME **xl);
+int add_unique_uid(XNAME **ul, X509 *x, const char *uid);
+void putuids(DB *db, int start, int end, char *argv[], XNAME **ul);
+
+void *
+nalloc( size_t s )
+{
+  void *t = malloc(s);
+
+  if (!t) {
+    fprintf(stderr, "cannot allocate %d bytes\n", s);
+    exit(-1);
+  }
+  return t;
+}
+
+void
+dump( unsigned char *p, size_t l, const char *name )
+{
+  int i;
+
+  printf("%s: (length %d)\n", name, l);
+  for(i=0; i<l; i++) {
+    printf("%02X", p[i]);
+    if (i < l-1) putchar((i % 16 == 15) ? '\n' : ':');
+  }
+  printf("\n");
+}
+
+void
+free_xname_list_node( XNAME_LIST *node )
+{
+  free(node);
+}
+
+void
+free_xname_node( XNAME *node )
+{
+  XNAME_LIST *xl, *p;
+
+  if (node->d) free(node->d);
+  for(xl=node->list; xl;) {
+    p = xl->next;
+    free_xname_list_node(xl);
+    xl = p;
+  }
+  free(node);
+}
+
+void
+free_xnames( XNAME **nl )
+{
+  XNAME *l, *p;
+
+  if (!nl) return;
+  for(l = *nl; l; ) {
+    p = l->next;
+    free_xname_node(l);
+    l = p;
+  }
+  *nl = NULL;
+}
+
+XNAME *
+alloc_xname_node( const unsigned char *n, const size_t s )
+{
+  /* Create an empty list for name store in n */
+  XNAME *ret;
+
+  ret = nalloc(sizeof(XNAME));
+  ret->lcount = 0;
+  ret->list = NULL;
+  ret->dlen = s;
+  ret->d = nalloc(s);
+  memcpy(ret->d, n, s);
+  ret->next = NULL;
+
+  return ret;
+}
+
+int
+add_unique_xname( XNAME **nl, X509_NAME *name,
+		  const unsigned char *digest )
+{
+  unsigned char *d, *dum;
+  size_t dlen;
+  XNAME *p;
+  int found, res = 1;
+
+  /* Create DER form of name */
+
+  if (name == NULL) {
+    dlen = 1;
+    d = nalloc(dlen);
+    d[0] = '\0';
+  } else {
+    dlen = i2d_X509_NAME(name, NULL);
+    d = nalloc(dlen); dum = d;
+    i2d_X509_NAME(name, &dum);
+  }
+
+  /* Search nl for name */
+  for (p=*nl, found = 0; ((!found) && (p));
+       (!found) ? p=p->next : p)
+    if ((dlen == p->dlen) && (memcmp(d, p->d, dlen) == 0)) found = 1;
+
+  if (found) {
+    XNAME_LIST *pp;
+
+    /* add digest to list of names if not already there */
+    for(pp = p->list, found = 0; ((!found) && (pp));
+	(!found) ? pp=pp->next : pp)
+      if (memcmp(pp->digest, digest, SHA_DIGEST_LENGTH) == 0) found = 1;
+    
+    if (!found) {
+      XNAME_LIST *n = nalloc(sizeof(XNAME_LIST));
+      n->next = p->list;
+      memcpy(n->digest, digest, SHA_DIGEST_LENGTH);
+      p->list = n;
+      p->lcount++;
+    } else
+      res = 0;
+  } else {
+    p = alloc_xname_node(d, dlen);
+    p->list = nalloc(sizeof(XNAME_LIST));
+    p->list->next = NULL;
+    memcpy(p->list->digest, digest, SHA_DIGEST_LENGTH);
+    p->lcount = 1;
+    p->next = *nl;
+    *nl = p;
+  }
+  free(d);
+  return res;
+}
+
+void
+add_unique_dns(XNAME **nl, X509 *x, const unsigned char *digest )
+{
+  unsigned char *d;
+  size_t dlen;
+  XNAME *p;
+  int found, res = 1;
+  int i, loc;
+  u_char *pp;
+  STACK_OF(GENERAL_NAME) *nsk = NULL;
+  X509_EXTENSION *ext;
+  GENERAL_NAME *gn;
+
+  if ((loc = X509_get_ext_by_NID(x, NID_subject_alt_name, -1)) < 0) return;
+  if ((ext = X509_get_ext(x, loc)) == NULL) return;
+  pp = ext->value->data;
+  d2i_GENERAL_NAMES(&nsk, &pp, ext->value->length);
+  if (!nsk) return;
+  for(i=0; i<sk_GENERAL_NAME_num(nsk); i++) {
+    gn = sk_GENERAL_NAME_value(nsk, i);
+
+    if (gn->type == GEN_DNS) {
+      dlen = gn->d.ia5->length;
+      d = nalloc(dlen);
+      memcpy(d, gn->d.ia5->data, dlen);
+
+      for (p=*nl, found = 0; ((!found) && (p));
+	   (!found) ? p=p->next : p)
+	if ((dlen == p->dlen) && (memcmp(d, p->d, dlen) == 0)) found = 1;
+
+      if (found) {
+	XNAME_LIST *pp;
+	
+	/* add digest to list of names if not already there */
+	for(pp = p->list, found = 0; ((!found) && (pp));
+	    (!found) ? pp=pp->next : pp)
+	  if (memcmp(pp->digest, digest, SHA_DIGEST_LENGTH) == 0) found = 1;
+	
+	if (!found) {
+	  XNAME_LIST *n = nalloc(sizeof(XNAME_LIST));
+	  n->next = p->list;
+	  memcpy(n->digest, digest, SHA_DIGEST_LENGTH);
+	  p->list = n;
+	  p->lcount++;
+	} else
+	  res = 0;
+      } else {
+	p = alloc_xname_node(d, dlen);
+	p->list = nalloc(sizeof(XNAME_LIST));
+	p->list->next = NULL;
+	memcpy(p->list->digest, digest, SHA_DIGEST_LENGTH);
+	p->lcount = 1;
+	p->next = *nl;
+	*nl = p;
+      }
+      free(d);
+    }
+  }
+  sk_GENERAL_NAME_free(nsk);
+}
+
+void
+add_unique_ip(XNAME **nl, X509 *x, const unsigned char *digest )
+{
+  unsigned char *d;
+  size_t dlen;
+  XNAME *p;
+  int found, res = 1;
+  int i, loc;
+  u_char *pp;
+  STACK_OF(GENERAL_NAME) *nsk = NULL;
+  X509_EXTENSION *ext;
+  GENERAL_NAME *gn;
+
+  if ((loc = X509_get_ext_by_NID(x, NID_subject_alt_name, -1)) < 0) return;
+  if ((ext = X509_get_ext(x, loc)) == NULL) return;
+  pp = ext->value->data;
+  d2i_GENERAL_NAMES(&nsk, &pp, ext->value->length);
+  if (!nsk) return;
+  for(i=0; i<sk_GENERAL_NAME_num(nsk); i++) {
+    gn = sk_GENERAL_NAME_value(nsk, i);
+
+    if (gn->type == GEN_IPADD) {
+      dlen = gn->d.ip->length;
+      d = nalloc(dlen);
+      memcpy(d, gn->d.ip->data, dlen);
+
+      for (p=*nl, found = 0; ((!found) && (p));
+	   (!found) ? p=p->next : p)
+	if ((dlen == p->dlen) && (memcmp(d, p->d, dlen) == 0)) found = 1;
+
+      if (found) {
+	XNAME_LIST *pp;
+	
+	/* add digest to list of names if not already there */
+	for(pp = p->list, found = 0; ((!found) && (pp));
+	    (!found) ? pp=pp->next : pp)
+	  if (memcmp(pp->digest, digest, SHA_DIGEST_LENGTH) == 0) found = 1;
+	
+	if (!found) {
+	  XNAME_LIST *n = nalloc(sizeof(XNAME_LIST));
+	  n->next = p->list;
+	  memcpy(n->digest, digest, SHA_DIGEST_LENGTH);
+	  p->list = n;
+	  p->lcount++;
+	} else
+	  res = 0;
+      } else {
+	p = alloc_xname_node(d, dlen);
+	p->list = nalloc(sizeof(XNAME_LIST));
+	p->list->next = NULL;
+	memcpy(p->list->digest, digest, SHA_DIGEST_LENGTH);
+	p->lcount = 1;
+	p->next = *nl;
+	*nl = p;
+      }
+      free(d);
+    }
+  }
+  sk_GENERAL_NAME_free(nsk);
+}
+
+int
+isCA( X509 *x )
+{
+  X509_EXTENSION *ext;
+  BASIC_CONSTRAINTS *p = NULL;
+  int loc;
+  
+  loc = X509_get_ext_by_NID(x, NID_basic_constraints, -1);
+  if (loc >= 0) {
+    ext = X509_get_ext(x, loc);
+    if (ext) {
+      p = X509V3_EXT_d2i(ext);
+      if (! p->ca) {
+	BASIC_CONSTRAINTS_free(p);
+	return 0;
+      } else {
+	BASIC_CONSTRAINTS_free(p);
+	return 1; /* This is a CA certificate */
+      }
+    } else
+      return 0;
+  } else
+    return 0;
+}
+
+void
+free_cert_node( CERT *c )
+{
+  if (c->d) free(c->d);
+  c->d = NULL;
+  switch(c->type) {
+    case X509_TYPE: if (c->info.x) X509_free(c->info.x); break;
+    case X509_CRL_TYPE: if (c->info.c) X509_CRL_free(c->info.c); break;
+  }
+  c->info.x = NULL;
+  memset(c->digest, 0, SHA_DIGEST_LENGTH);
+  c->next = NULL;
+  free(c);
+}
+
+int
+add_unique_xinf( CERT **cl, XNAME **xl,
+		 XNAME **cal, XNAME **dnl, XNAME **ipl,
+		 unsigned int type, void *x )
+{
+  int f;
+  CERT *p, *node;
+  unsigned char *dum;
+
+  if (!cl) return 0;
+
+  node = nalloc(sizeof(CERT));
+  node->next = NULL;
+  node->type = type;
+  switch(type) {
+  case X509_TYPE:
+    node->info.x = (X509 *)x;
+    node->dlen = i2d_X509((X509 *)x, NULL);
+    node->d = nalloc(node->dlen);
+    dum = node->d;
+    i2d_X509( (X509 *)x, &dum );
+    break;
+  case X509_CRL_TYPE:
+    node->info.c = (X509_CRL *)x;
+    node->dlen = i2d_X509_CRL((X509_CRL *)x, NULL);
+    node->d = nalloc(node->dlen);
+    dum = node->d;
+    i2d_X509_CRL( (X509_CRL *)x, &dum );
+    break;
+  default:
+    fprintf(stderr, "Unknown info type: %d\n", type);
+    free(node);
+    return 0;
+  }
+
+  SHA1(node->d, node->dlen, node->digest);
+
+  for(p=*cl, f=0; (!f) && (p); p=p->next)
+    if (memcmp(p->digest, node->digest, SHA_DIGEST_LENGTH) == 0) f=1;
+    /* found a duplicate */
+
+  if (!f) {
+    /* insert at head of list */
+    node->next = *cl;
+    *cl = node;
+    switch(type) {
+    case X509_TYPE:
+      add_unique_xname(xl, X509_get_subject_name((X509 *)x), node->digest);
+      if (isCA(x)) add_unique_xname(cal, NULL, node->digest);
+      add_unique_dns(dnl, (X509 *)x, node->digest);
+      add_unique_ip(ipl, (X509 *)x, node->digest);
+      break;
+    case X509_CRL_TYPE:
+      add_unique_xname(xl, X509_CRL_get_issuer((X509_CRL *)x), node->digest);
+      break;
+    }
+    return 1;
+  } else
+    return 0;
+}
+
+void
+free_cert_list( CERT **cl )
+{
+  CERT *c;
+
+  if (!cl) return;
+
+  for(c=*cl; c;) {
+    CERT *p = c->next;
+
+    free_cert_node(c);
+    c = p;
+  }
+  *cl = NULL;
+}
+
+static char dirname[PATH_MAX+1];
+static int
+select_files(const struct dirent *de)
+{
+  struct stat st;
+  char path[PATH_MAX+1];
+
+  snprintf(path, sizeof(path), "%s/%s", dirname, de->d_name);
+  if (lstat(path, &st) == 0) {
+    if (S_ISREG(st.st_mode))
+      return 1;
+    else
+      return 0;
+  } else {
+    perror("stat");
+    return 0;
+  }
+}
+
+static int
+select_uid_files(const struct dirent *de)
+{
+  struct stat st;
+  char path[PATH_MAX+1];
+
+  if (strncasecmp(UID_PREFIX, de->d_name, strlen(UID_PREFIX)) != 0) return 0;
+  snprintf(path, sizeof(path), "%s/%s", dirname, de->d_name);
+  if (lstat(path, &st) == 0) {
+    if ((S_ISREG(st.st_mode)) || (S_ISLNK(st.st_mode)))
+      return 1;
+    else
+      return 0;
+  } else {
+    perror("stat");
+    return 0;
+  }
+}
+
+void
+putcerts(DB *db, int start, int end, char *argv[],
+	 CERT **cl, XNAME **xl, XNAME **cal, XNAME **dnl, XNAME **ipl)
+{
+  int i, j, n;
+  struct dirent **namelist = NULL;
+  char path[PATH_MAX+1];
+
+  for(i=start; i<end; i++) {
+    printf("Dumping certs from directory \"%s\"\n", argv[i]);
+    snprintf(dirname, sizeof(dirname)-1, "%s", argv[i]);
+    if ((n = scandir(argv[i], &namelist, select_files, alphasort)) >= 0) {
+      for(j=0; j<n; j++) {
+	BIO *b;
+
+	printf("File: %s\n", namelist[j]->d_name);
+	snprintf(path, sizeof(path), "%s/%s", argv[i], namelist[j]->d_name);
+	if ((b = BIO_new_file(path, "r")) != NULL) {
+	  X509 *x;
+
+	  if (!(x = PEM_read_bio_X509(b, NULL, NULL, NULL))) {
+	    BIO_ctrl(b, BIO_CTRL_RESET, 0, NULL);
+	    x = d2i_X509_bio(b, NULL);
+	  }
+	  if ((x) && (!add_unique_xinf(cl, xl, cal, dnl, ipl, X509_TYPE, x)))
+	    X509_free(x);
+	  BIO_free(b);
+	}
+      }
+      free(namelist);
+    } else
+      perror("scandir");
+  }
+}
+
+void
+putcrls(DB *db, int start, int end, char *argv[], CERT **cl, XNAME **xl)
+{
+  int i, j, n;
+  struct dirent **namelist = NULL;
+  char path[PATH_MAX+1];
+
+  for(i=start; i<end; i++) {
+    printf("Dumping CRLs from directory \"%s\"\n", argv[i]);
+    snprintf(dirname, sizeof(dirname)-1, "%s", argv[i]);
+    if ((n = scandir(argv[i], &namelist, select_files, alphasort)) >= 0) {
+      for(j=0; j<n; j++) {
+	BIO *b;
+
+	printf("File: %s\n", namelist[j]->d_name);
+	snprintf(path, sizeof(path), "%s/%s", argv[i], namelist[j]->d_name);
+	if ((b = BIO_new_file(path, "r")) != NULL) {
+	  X509_CRL *c;
+
+	  if (!(c = PEM_read_bio_X509_CRL(b, NULL, NULL, NULL))) {
+	    BIO_ctrl(b, BIO_CTRL_RESET, 0, NULL);
+	    c = d2i_X509_CRL_bio(b, NULL);
+	  }
+	  if ((c) &&
+	      (!add_unique_xinf(cl, xl, NULL, NULL, NULL,X509_CRL_TYPE, c)))
+	    X509_CRL_free(c);
+
+	  BIO_free(b);
+	}
+      }
+      free(namelist);
+    } else
+      perror("scandir");
+  }
+}
+
+int
+add_unique_uid(XNAME **ul, X509 *x, const char *uid)
+{
+  int found;
+  XNAME *p;
+  unsigned char digest[SHA_DIGEST_LENGTH], *d, *dum;
+  size_t dlen;
+
+  if (!x || !ul) return 0;
+
+  dlen = i2d_X509(x, NULL);
+  d = nalloc(dlen);
+  dum = d;
+  i2d_X509( x, &dum );
+
+  SHA1(d, dlen, digest);
+  free(d);
+
+  printf("Adding user id \"%s\"\n", uid);
+  for(found=0, p=*ul; ((!found) && (p)); 
+      (!found) ? p=p->next : p)
+    if ((strlen(uid) == p->dlen) && (memcmp(p->d, uid, p->dlen) == 0))
+      found = 1;
+
+  if (found) {
+    XNAME_LIST *pp;
+    
+    for(pp = p->list, found = 0; ((!found) && (pp));
+	pp=(!found) ? pp->next : pp)
+      if (memcmp(pp->digest, digest, SHA_DIGEST_LENGTH) == 0) found = 1;
+    
+    if (!found) {
+      XNAME_LIST *n = nalloc(sizeof(XNAME_LIST));
+      n->next = p->list;
+      memcpy(n->digest, digest, SHA_DIGEST_LENGTH);
+      p->list = n;
+      p->lcount++;
+    } else
+      return 0;
+  } else {
+    p = alloc_xname_node(uid, strlen(uid));
+    p->list = nalloc(sizeof(XNAME_LIST));
+    p->list->next = NULL;
+    memcpy(p->list->digest, digest, SHA_DIGEST_LENGTH);
+    p->lcount = 1;
+    p->next = *ul;
+    *ul = p;
+    return 1;
+  }
+  return 0;
+}
+
+static int
+isuidchar( char c )
+{
+  if (isalnum(c)) return 1;
+  if (c == '_') return 1;
+  return 0;
+}
+
+void
+putuids(DB *db, int start, int end, char *argv[], XNAME **ul)
+{
+  int i, j, n;
+  struct dirent **namelist = NULL;
+  char path[PATH_MAX+1];
+
+  for(i=start; i<end; i++) {
+    printf("Dumping uids from directory \"%s\"\n", argv[i]);
+    snprintf(dirname, sizeof(dirname)-1, "%s", argv[i]);
+    if ((n = scandir(argv[i], &namelist, select_uid_files, alphasort)) >= 0) {
+      for(j=0; j<n; j++) {
+	BIO *b;
+	char *n, *nn;
+
+	printf("File: %s\n", namelist[j]->d_name);
+	snprintf(path, sizeof(path), "%s/%s", argv[i], namelist[j]->d_name);
+	if ((b = BIO_new_file(path, "r")) != NULL) {
+	  X509 *x;
+
+	  if (!(x = PEM_read_bio_X509(b, NULL, NULL, NULL))) {
+	    BIO_ctrl(b, BIO_CTRL_RESET, 0, NULL);
+	    x = d2i_X509_bio(b, NULL);
+	  }
+
+	  n = nn = strdup(&(namelist[j]->d_name[strlen(UID_PREFIX)]));
+	  while ((*nn) && (isuidchar(*nn))) nn++;
+	  *nn = '\0';
+	  if ((x) && (!add_unique_uid(ul, x, n))) X509_free(x);
+
+	  BIO_free(b);
+	}
+      }
+      free(namelist);
+    } else
+      perror("scandir");
+  }
+}
+
+int
+main( int argc, char *argv[] )
+{
+  int c;
+  DB *db;
+  CERT *clist = NULL, *crlist = NULL;
+  XNAME *xlist = NULL, *nlist = NULL, *xcrlist = NULL, *calist = NULL;
+  XNAME *dnlist = NULL, *iplist = NULL;
+
+  while(1) {
+    int option_index = 0;
+    static struct option long_options[] = {
+      { "output", 1, 0, 0 },
+      { 0, 0, 0, 0 }
+    };
+
+    c = getopt_long(argc, argv, "o:",
+		    long_options, &option_index);
+    if (c == -1) break;
+
+    switch(c) {
+    case 0:
+      if (strcasecmp(long_options[option_index].name, "output") == 0)
+	hashout = optarg;
+      break;
+    case 'o':
+      hashout = optarg;
+      break;
+    case '?':
+      break;
+    default:
+      printf("?? getopt returned character code 0%o ??\n", c);
+    }
+  }
+
+  X509V3_add_standard_extensions();
+
+  if ((db = dbopen(hashout, O_CREAT | O_TRUNC | O_RDWR, 0644, DB_HASH, NULL)) == NULL) {
+    perror("dbopen");
+  } else {
+    DBT k, v;
+    CERT *c;
+    XNAME *x;
+    unsigned char *kk, *vv;
+
+    memset(&k, 0, sizeof(DBT));
+    memset(&v, 0, sizeof(DBT));
+    k.data = strdup("\xFF\xFF\xFF\xFFversion");
+    k.size = strlen("version") + TAGLEN;
+    v.data = version_data;
+    v.size = VERSION_SIZE;
+
+    if (db->put(db, &k, &v, 0) != 0) perror("dbput");
+    db->sync(db, 0);
+    free(k.data);
+
+    putcerts(db, optind, argc, argv,
+	     &clist, &xlist,
+	     &calist, &dnlist, &iplist);
+    putcrls(db, optind, argc, argv, &crlist, &xcrlist);
+    putuids(db, optind, argc, argv, &nlist);
+
+    for(c=clist; c; c=c->next) {
+      k.size = SHA_DIGEST_LENGTH+TAGLEN;
+      k.data = nalloc(k.size);
+      v.size = c->dlen;
+      v.data = nalloc(v.size);
+
+      kk = k.data;
+      vv = v.data;
+      memset(kk, 0, TAGLEN);
+      memcpy(&kk[TAGLEN], c->digest, SHA_DIGEST_LENGTH);
+      memcpy(vv, c->d, c->dlen);
+
+      if (db->put(db, &k, &v, 0) != 0) perror("dbput");
+      free(k.data);
+      free(v.data);
+    }
+    free_cert_list(&clist);
+
+    for(x=xlist; x; x=x->next) {
+      u_int32_t cnt;
+      int i;
+      XNAME_LIST *p;
+
+      k.size = x->dlen + TAGLEN;
+      k.data = nalloc(k.size);
+      v.size = TAGLEN + x->lcount * SHA_DIGEST_LENGTH;
+      v.data = nalloc(v.size);
+      kk = k.data;
+      vv = v.data;
+
+      memset(kk, 0, TAGLEN-1); kk[TAGLEN-1] = '\01';
+      memcpy(&kk[TAGLEN], x->d, x->dlen);
+      cnt = htonl(x->lcount);
+      memcpy(vv, (unsigned char *)&cnt, TAGLEN);
+      for(i=0, p=x->list; i<x->lcount; i++, p=p->next)
+	memcpy(&vv[TAGLEN + i*SHA_DIGEST_LENGTH],
+	       p->digest, SHA_DIGEST_LENGTH);
+      if (db->put(db, &k, &v, 0) < 0) perror("dbput");
+      free(k.data);
+      free(v.data);
+    }
+    free_xnames(&xlist);
+
+    for(x=calist; x; x=x->next) {
+      u_int32_t cnt;
+      int i;
+      XNAME_LIST *p;
+
+      k.size = TAGLEN;
+      k.data = nalloc(k.size);
+      v.size = TAGLEN + x->lcount * SHA_DIGEST_LENGTH;
+      v.data = nalloc(v.size);
+      kk = k.data;
+      vv = v.data;
+
+      memset(kk, 0, TAGLEN-1); kk[TAGLEN-1] = '\05';
+      cnt = htonl(x->lcount);
+      memcpy(vv, (unsigned char *)&cnt, TAGLEN);
+      for(i=0, p=x->list; i<x->lcount; i++, p=p->next)
+	memcpy(&vv[TAGLEN + i*SHA_DIGEST_LENGTH],
+	       p->digest, SHA_DIGEST_LENGTH);
+      if (db->put(db, &k, &v, 0) != 0) perror("dbput");
+      free(k.data);
+      free(v.data);
+    }
+    free_xnames(&calist);
+
+    for(x=dnlist; x; x=x->next) {
+      u_int32_t cnt;
+      int i;
+      XNAME_LIST *p;
+
+      k.size = x->dlen + TAGLEN;
+      k.data = nalloc(k.size);
+      v.size = TAGLEN + x->lcount * SHA_DIGEST_LENGTH;
+      v.data = nalloc(v.size);
+      kk = k.data;
+      vv = v.data;
+
+      memset(kk, 0, TAGLEN-1); kk[TAGLEN-1] = '\06';
+      memcpy(&kk[TAGLEN], x->d, x->dlen);
+      cnt = htonl(x->lcount);
+      memcpy(vv, (unsigned char *)&cnt, TAGLEN);
+      for(i=0, p=x->list; i<x->lcount; i++, p=p->next)
+	memcpy(&vv[TAGLEN + i*SHA_DIGEST_LENGTH],
+	       p->digest, SHA_DIGEST_LENGTH);
+      if (db->put(db, &k, &v, 0) != 0) perror("dbput");
+      free(k.data);
+      free(v.data);
+    }
+    free_xnames(&dnlist);
+
+    for(x=iplist; x; x=x->next) {
+      u_int32_t cnt;
+      int i;
+      XNAME_LIST *p;
+
+      k.size = x->dlen + TAGLEN;
+      k.data = nalloc(k.size);
+      v.size = TAGLEN + x->lcount * SHA_DIGEST_LENGTH;
+      v.data = nalloc(v.size);
+      kk = k.data;
+      vv = v.data;
+
+      memset(kk, 0, TAGLEN-1); kk[TAGLEN-1] = '\07';
+      memcpy(&kk[TAGLEN], x->d, x->dlen);
+      cnt = htonl(x->lcount);
+      memcpy(vv, (unsigned char *)&cnt, TAGLEN);
+      for(i=0, p=x->list; i<x->lcount; i++, p=p->next)
+	memcpy(&vv[TAGLEN + i*SHA_DIGEST_LENGTH],
+	       p->digest, SHA_DIGEST_LENGTH);
+      if (db->put(db, &k, &v, 0) != 0) perror("dbput");
+      free(k.data);
+      free(v.data);
+    }
+    free_xnames(&iplist);
+
+    for(c=crlist; c; c=c->next) {
+      k.size = SHA_DIGEST_LENGTH+TAGLEN;
+      k.data = nalloc(k.size);
+      v.size = c->dlen;
+      v.data = nalloc(v.size);
+
+      kk = k.data;
+      vv = v.data;
+      memset(kk, 0, TAGLEN-1); kk[TAGLEN-1] = '\04';
+      memcpy(&kk[TAGLEN], c->digest, SHA_DIGEST_LENGTH);
+      memcpy(vv, c->d, c->dlen);
+
+      if (db->put(db, &k, &v, 0) != 0) perror("dbput");
+      free(k.data);
+      free(v.data);
+    }
+    free_cert_list(&crlist);
+
+    for(x=xcrlist; x; x=x->next) {
+      u_int32_t cnt;
+      int i;
+      XNAME_LIST *p;
+
+      k.size = x->dlen + TAGLEN;
+      k.data = nalloc(k.size);
+      v.size = TAGLEN + x->lcount * SHA_DIGEST_LENGTH;
+      v.data = nalloc(v.size);
+      kk = k.data;
+      vv = v.data;
+
+      memset(kk, 0, TAGLEN-1); kk[TAGLEN-1] = '\02';
+      memcpy(&kk[TAGLEN], x->d, x->dlen);
+      cnt = htonl(x->lcount);
+      memcpy(vv, (unsigned char *)&cnt, TAGLEN);
+      for(i=0, p=x->list; i<x->lcount; i++, p=p->next)
+	memcpy(&vv[TAGLEN + i*SHA_DIGEST_LENGTH],
+	       p->digest, SHA_DIGEST_LENGTH);
+      if (db->put(db, &k, &v, 0) != 0) perror("dbput");
+      free(k.data);
+      free(v.data);
+    }
+    free_xnames(&xcrlist);
+
+    for(x=nlist; x; x=x->next) {
+      u_int32_t cnt;
+      int i;
+      XNAME_LIST *p;
+
+      k.size = x->dlen + TAGLEN;
+      k.data = nalloc(k.size);
+      v.size = TAGLEN + x->lcount * SHA_DIGEST_LENGTH;
+      v.data = nalloc(v.size);
+      kk = k.data;
+      vv = v.data;
+
+      memset(kk, 0, TAGLEN-1); kk[TAGLEN-1] = '\03';
+      memcpy(&kk[TAGLEN], x->d, x->dlen);
+      cnt = htonl(x->lcount);
+      memcpy(vv, (unsigned char *)&cnt, TAGLEN);
+      for(i=0, p=x->list; i<x->lcount; i++, p=p->next)
+	memcpy(&vv[TAGLEN + i*SHA_DIGEST_LENGTH],
+	       p->digest, SHA_DIGEST_LENGTH);
+      if (db->put(db, &k, &v, 0) != 0) perror("dbput");
+      free(k.data);
+      free(v.data);
+    }
+    free_xnames(&nlist);
+    db->close(db);
+  }
+
+  printf("Dumping keys from DB file\n");
+  if ((db = dbopen(hashout, 0, 0, DB_HASH, NULL)) == NULL) {
+    perror("db_open");
+  } else {
+    DBT k, v;
+    int i;
+
+    memset(&k, 0, sizeof(k));
+    memset(&v, 0, sizeof(v));
+    while (db->seq(db, &k, &v, R_NEXT) == 0) {
+      if (k.size < TAGLEN)
+	fprintf(stderr, "Error: key value too short\n");
+      else {
+	unsigned char *kk = k.data, *vv = v.data, *p;
+	u_int32_t c1, c2;
+	X509_NAME *xn;
+	
+	switch(kk[TAGLEN-1]) {
+	case 0:
+	  printf("X509 Certificate\n");
+	  dump(&kk[TAGLEN], k.size-TAGLEN, "SHA-DIGEST");
+	  printf("Data Length %d\n", v.size);
+	  break;
+	case 1:
+	  printf("X509 Subject Name\n");
+	  p = &kk[TAGLEN];
+	  if ((xn = d2i_X509_NAME(NULL, &p, k.size-TAGLEN)) != NULL) {
+	    char buf[256];
+	    
+	    X509_NAME_oneline(xn, buf, sizeof(buf));
+	    printf("%s:\n", buf);
+	    X509_NAME_free(xn);
+	    memcpy((unsigned char *)(&c1), v.data, TAGLEN);
+	    c2 = ntohl(c1);
+	    if (v.size != TAGLEN + (SHA_DIGEST_LENGTH * c2)) {
+	      fprintf(stderr, "X509 name length error\n");
+	    } else {
+	      for(i=0; i<c2; i++)
+		dump( &vv[TAGLEN + i*SHA_DIGEST_LENGTH],
+		      SHA_DIGEST_LENGTH, "SHA-DIGEST");
+	    }
+	    printf("\n");
+	  }
+	  break;
+	case 0x02:
+	  printf("X509 CRL Issuer Name\n");
+	  p = &kk[TAGLEN];
+	  if ((xn = d2i_X509_NAME(NULL, &p, k.size-TAGLEN)) != NULL) {
+	    char buf[256];
+	    
+	    X509_NAME_oneline(xn, buf, sizeof(buf));
+	    printf("%s:\n", buf);
+	    X509_NAME_free(xn);
+	    memcpy((unsigned char *)(&c1), v.data, TAGLEN);
+	    c2 = ntohl(c1);
+	    if (v.size != TAGLEN + (SHA_DIGEST_LENGTH * c2)) {
+	      fprintf(stderr, "X509 name length error\n");
+	    } else {
+	      for(i=0; i<c2; i++)
+		dump( &vv[TAGLEN + i*SHA_DIGEST_LENGTH],
+		      SHA_DIGEST_LENGTH, "SHA-DIGEST");
+	    }
+	    printf("\n");
+	  }
+	  break;
+	case 0x03:
+	  printf("UID: ");
+	  for(i=TAGLEN; i<k.size; i++)
+	    printf("%c", isprint(kk[i]) ? kk[i] : '?');
+	  printf("\n");
+	  memcpy((unsigned char *)(&c1), v.data, TAGLEN);
+	  c2 = ntohl(c1);
+	  if (v.size != TAGLEN + (SHA_DIGEST_LENGTH * c2)) {
+	    fprintf(stderr, "X509 name length error\n");
+	  } else {
+	    for(i=0; i<c2; i++)
+	      dump( &vv[TAGLEN + i*SHA_DIGEST_LENGTH],
+		    SHA_DIGEST_LENGTH, "SHA-DIGEST");
+	  }
+	  printf("\n");
+	  break;
+	case 0x04:
+	  printf("X509 Certificate Revocation List\n");
+	  dump(&kk[TAGLEN], k.size-TAGLEN, "SHA-DIGEST");
+	  printf("Data Length %d\n", v.size);
+	  break;
+	case 0x05:
+	  printf("CA Certificate:\n");
+	  memcpy((unsigned char *)(&c1), v.data, TAGLEN);
+	  c2 = ntohl(c1);
+	  if (v.size != TAGLEN + (SHA_DIGEST_LENGTH * c2)) {
+	    fprintf(stderr, "X509 name length error\n");
+	  } else {
+	    for(i=0; i<c2; i++)
+	      dump( &vv[TAGLEN + i*SHA_DIGEST_LENGTH],
+		    SHA_DIGEST_LENGTH, "SHA-DIGEST");
+	  }
+	  printf("\n");
+	  break;
+	case 0x06:
+	  printf("DNS: ");
+	  for(i=TAGLEN; i<k.size; i++)
+	    printf("%c", isprint(kk[i]) ? kk[i] : '?');
+	  printf("\n");
+	  memcpy((unsigned char *)(&c1), v.data, TAGLEN);
+	  c2 = ntohl(c1);
+	  if (v.size != TAGLEN + (SHA_DIGEST_LENGTH * c2)) {
+	    fprintf(stderr, "X509 name length error\n");
+	  } else {
+	    for(i=0; i<c2; i++)
+	      dump( &vv[TAGLEN + i*SHA_DIGEST_LENGTH],
+		    SHA_DIGEST_LENGTH, "SHA-DIGEST");
+	  }
+	  printf("\n");
+	  break;
+	case 0x07:
+	  printf("IPv4: ");
+	  for(i=TAGLEN; i<k.size; i++)
+	    printf("%d.", kk[i]);
+	  printf("\n");
+	  memcpy((unsigned char *)(&c1), v.data, TAGLEN);
+	  c2 = ntohl(c1);
+	  if (v.size != TAGLEN + (SHA_DIGEST_LENGTH * c2)) {
+	    fprintf(stderr, "X509 name length error\n");
+	  } else {
+	    for(i=0; i<c2; i++)
+	      dump( &vv[TAGLEN + i*SHA_DIGEST_LENGTH],
+		    SHA_DIGEST_LENGTH, "SHA-DIGEST");
+	  }
+	  printf("\n");
+	  break;
+	case 0xFF:
+	  printf("Metainfo: ");
+	  for(i=TAGLEN; i<k.size; i++)
+	    printf("%c", isprint(kk[i]) ? kk[i] : '?');
+	  printf(":- ");
+	  dump(v.data, v.size, "Value");
+	  printf("\n");
+	  break;
+	default:
+	  fprintf(stderr, "Error in type field: %02X\n", kk[TAGLEN-1]);
+	  break;
+	}
+      }
+    }
+    db->close(db);
+  }
+  printf("Done\n");
+
+  X509V3_EXT_cleanup();
+  return 0;
+}
+
+
diff -ruN freeswan-1.5.orig/pluto/dsa.c freeswan-1.5/pluto/dsa.c
--- freeswan-1.5.orig/pluto/dsa.c	Mon Nov  1 16:52:39 1999
+++ freeswan-1.5/pluto/dsa.c	Wed Dec 31 19:00:00 1969
@@ -1,476 +0,0 @@
-/* dsa.c  -  DSA signature scheme
- *	Copyright (C) 1998 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#ifdef PLUTO
-#include <gmp.h>
-#include <freeswan.h>
-#include "constants.h"
-#include "defs.h"
-#include "log.h"
-#include "rnd.h"
-#include "gcryptfix.h"
-#else /*! PLUTO */
-/* #include <config.h> */
-#endif /* !PLUTO */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifndef PLUTO
-/* #include <assert.h> */
-/* #include "util.h" */
-/* #include "mpi.h" */
-/* #include "cipher.h" */
-#endif
-
-#include "dsa.h"
-
-typedef struct {
-    MPI p;	    /* prime */
-    MPI q;	    /* group order */
-    MPI g;	    /* group generator */
-    MPI y;	    /* g^x mod p */
-} DSA_public_key;
-
-
-typedef struct {
-    MPI p;	    /* prime */
-    MPI q;	    /* group order */
-    MPI g;	    /* group generator */
-    MPI y;	    /* g^x mod p */
-    MPI x;	    /* secret exponent */
-} DSA_secret_key;
-
-
-static MPI gen_k( MPI q );
-static void test_keys( DSA_secret_key *sk, unsigned qbits );
-static int  check_secret_key( DSA_secret_key *sk );
-static void generate( DSA_secret_key *sk, unsigned nbits, MPI **ret_factors );
-static void sign(MPI r, MPI s, MPI input, DSA_secret_key *skey);
-static int  verify(MPI r, MPI s, MPI input, DSA_public_key *pkey);
-
-static void
-progress( int c )
-{
-    fputc( c, stderr );
-}
-
-
-/****************
- * Generate a random secret exponent k less than q
- */
-static MPI
-gen_k( MPI q )
-{
-    MPI k = mpi_alloc_secure( mpi_get_nlimbs(q) );
-    unsigned int nbits = mpi_get_nbits(q);
-    unsigned int nbytes = (nbits+7)/8;
-    char *rndbuf = NULL;
-
-    if( DBG_CIPHER )
-	log_debug("choosing a random k ");
-    for(;;) {
-	if( DBG_CIPHER )
-	    progress('.');
-
-	if( !rndbuf || nbits < 32 ) {
-	    m_free(rndbuf);
-	    rndbuf = get_random_bits( nbits, 1, 1 );
-	}
-	else { /* change only some of the higher bits */
-	    /* we could imporove this by directly requesting more memory
-	     * at the first call to get_random_bits() and use this the here
-	     * maybe it is easier to do this directly in random.c */
-	    char *pp = get_random_bits( 32, 1, 1 );
-	    memcpy( rndbuf,pp, 4 );
-	    m_free(pp);
-	}
-	mpi_set_buffer( k, rndbuf, nbytes, 0 );
-	if( mpi_test_bit( k, nbits-1 ) )
-	    mpi_set_highbit( k, nbits-1 );
-	else {
-	    mpi_set_highbit( k, nbits-1 );
-	    mpi_clear_bit( k, nbits-1 );
-	}
-
-	if( !(mpi_cmp( k, q ) < 0) ) {	/* check: k < q */
-	    if( DBG_CIPHER )
-		progress('+');
-	    continue; /* no  */
-	}
-	if( !(mpi_cmp_ui( k, 0 ) > 0) ) { /* check: k > 0 */
-	    if( DBG_CIPHER )
-		progress('-');
-	    continue; /* no */
-	}
-	break;	/* okay */
-    }
-    m_free(rndbuf);
-    if( DBG_CIPHER )
-	progress('\n');
-
-    return k;
-}
-
-
-static void
-test_keys( DSA_secret_key *sk, unsigned qbits )
-{
-    DSA_public_key pk;
-    MPI test = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
-    MPI out1_a = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
-    MPI out1_b = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
-
-    pk.p = sk->p;
-    pk.q = sk->q;
-    pk.g = sk->g;
-    pk.y = sk->y;
-    /*mpi_set_bytes( test, qbits, get_random_byte, 0 );*/
-    {	char *p = get_random_bits( qbits, 0, 0 );
-	mpi_set_buffer( test, p, (qbits+7)/8, 0 );
-	m_free(p);
-    }
-
-    sign( out1_a, out1_b, test, sk );
-    if( !verify( out1_a, out1_b, test, &pk ) )
-	log_fatal("DSA:: sign, verify failed\n");
-
-    mpi_free( test );
-    mpi_free( out1_a );
-    mpi_free( out1_b );
-}
-
-
-
-/****************
- * Generate a DSA key pair with a key of size NBITS
- * Returns: 2 structures filled with all needed values
- *	    and an array with the n-1 factors of (p-1)
- */
-static void
-generate( DSA_secret_key *sk, unsigned nbits, MPI **ret_factors )
-{
-    MPI p;    /* the prime */
-    MPI q;    /* the 160 bit prime factor */
-    MPI g;    /* the generator */
-    MPI y;    /* g^x mod p */
-    MPI x;    /* the secret exponent */
-    MPI h, e;  /* helper */
-    unsigned qbits;
-    byte *rndbuf;
-
-    assert( nbits >= 512 && nbits <= 1024 );
-
-    qbits = 160;
-    p = generate_elg_prime( 1, nbits, qbits, NULL, ret_factors );
-    /* get q out of factors */
-    q = mpi_copy((*ret_factors)[0]);
-    if( mpi_get_nbits(q) != qbits )
-	BUG();
-
-    /* find a generator g (h and e are helpers)*/
-    /* e = (p-1)/q */
-    e = mpi_alloc( mpi_get_nlimbs(p) );
-    mpi_sub_ui( e, p, 1 );
-    mpi_fdiv_q( e, e, q );
-    g = mpi_alloc( mpi_get_nlimbs(p) );
-    h = mpi_alloc_set_ui( 1 ); /* we start with 2 */
-    do {
-	mpi_add_ui( h, h, 1 );
-	/* g = h^e mod p */
-	mpi_powm( g, h, e, p );
-    } while( !mpi_cmp_ui( g, 1 ) );  /* continue until g != 1 */
-
-    /* select a random number which has these properties:
-     *	 0 < x < q-1
-     * This must be a very good random number because this
-     * is the secret part. */
-    if( DBG_CIPHER )
-	log_debug("choosing a random x ");
-    assert( qbits >= 160 );
-    x = mpi_alloc_secure( mpi_get_nlimbs(q) );
-    mpi_sub_ui( h, q, 1 );  /* put q-1 into h */
-    rndbuf = NULL;
-    do {
-	if( DBG_CIPHER )
-	    progress('.');
-	if( !rndbuf )
-	    rndbuf = get_random_bits( qbits, 2, 1 );
-	else { /* change only some of the higher bits (= 2 bytes)*/
-	    char *r = get_random_bits( 16, 2, 1 );
-	    memcpy(rndbuf, r, 16/8 );
-	    m_free(r);
-	}
-	mpi_set_buffer( x, rndbuf, (qbits+7)/8, 0 );
-	mpi_clear_highbit( x, qbits+1 );
-    } while( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, h )<0 ) );
-    m_free(rndbuf);
-    mpi_free( e );
-    mpi_free( h );
-
-    /* y = g^x mod p */
-    y = mpi_alloc( mpi_get_nlimbs(p) );
-    mpi_powm( y, g, x, p );
-
-    if( DBG_CIPHER ) {
-	progress('\n');
-	log_mpidump("dsa  p= ", p );
-	log_mpidump("dsa  q= ", q );
-	log_mpidump("dsa  g= ", g );
-	log_mpidump("dsa  y= ", y );
-	log_mpidump("dsa  x= ", x );
-    }
-
-    /* copy the stuff to the key structures */
-    sk->p = p;
-    sk->q = q;
-    sk->g = g;
-    sk->y = y;
-    sk->x = x;
-
-    /* now we can test our keys (this should never fail!) */
-    test_keys( sk, qbits );
-}
-
-
-
-/****************
- * Test whether the secret key is valid.
- * Returns: if this is a valid key.
- */
-static int
-check_secret_key( DSA_secret_key *sk )
-{
-    int rc;
-    MPI y = mpi_alloc( mpi_get_nlimbs(sk->y) );
-
-    mpi_powm( y, sk->g, sk->x, sk->p );
-    rc = !mpi_cmp( y, sk->y );
-    mpi_free( y );
-    return rc;
-}
-
-
-
-/****************
- * Make a DSA signature from HASH and put it into r and s.
- */
-
-static void
-sign(MPI r, MPI s, MPI hash, DSA_secret_key *skey )
-{
-    MPI k;
-    MPI kinv;
-    MPI tmp;
-
-    /* select a random k with 0 < k < q */
-    k = gen_k( skey->q );
-
-    /* r = (a^k mod p) mod q */
-    mpi_powm( r, skey->g, k, skey->p );
-    mpi_fdiv_r( r, r, skey->q );
-
-    /* kinv = k^(-1) mod q */
-    kinv = mpi_alloc( mpi_get_nlimbs(k) );
-    mpi_invm(kinv, k, skey->q );
-
-    /* s = (kinv * ( hash + x * r)) mod q */
-    tmp = mpi_alloc( mpi_get_nlimbs(skey->p) );
-    mpi_mul( tmp, skey->x, r );
-    mpi_add( tmp, tmp, hash );
-    mpi_mulm( s , kinv, tmp, skey->q );
-
-    mpi_free(k);
-    mpi_free(kinv);
-    mpi_free(tmp);
-}
-
-
-/****************
- * Returns true if the signature composed from R and S is valid.
- */
-static int
-verify(MPI r, MPI s, MPI hash, DSA_public_key *pkey )
-{
-    int rc;
-    MPI w, u1, u2, v;
-    MPI base[3];
-    MPI exp[3];
-
-
-    if( !(mpi_cmp_ui( r, 0 ) > 0 && mpi_cmp( r, pkey->q ) < 0) )
-	return 0; /* assertion	0 < r < q  failed */
-    if( !(mpi_cmp_ui( s, 0 ) > 0 && mpi_cmp( s, pkey->q ) < 0) )
-	return 0; /* assertion	0 < s < q  failed */
-
-    w  = mpi_alloc( mpi_get_nlimbs(pkey->q) );
-    u1 = mpi_alloc( mpi_get_nlimbs(pkey->q) );
-    u2 = mpi_alloc( mpi_get_nlimbs(pkey->q) );
-    v  = mpi_alloc( mpi_get_nlimbs(pkey->p) );
-
-    /* w = s^(-1) mod q */
-    mpi_invm( w, s, pkey->q );
-
-    /* u1 = (hash * w) mod q */
-    mpi_mulm( u1, hash, w, pkey->q );
-
-    /* u2 = r * w mod q  */
-    mpi_mulm( u2, r, w, pkey->q );
-
-    /* v =  g^u1 * y^u2 mod p mod q */
-    base[0] = pkey->g; exp[0] = u1;
-    base[1] = pkey->y; exp[1] = u2;
-    base[2] = NULL;    exp[2] = NULL;
-    mpi_mulpowm( v, base, exp, pkey->p );
-    mpi_fdiv_r( v, v, pkey->q );
-
-    rc = !mpi_cmp( v, r );
-
-    mpi_free(w);
-    mpi_free(u1);
-    mpi_free(u2);
-    mpi_free(v);
-    return rc;
-}
-
-
-/*********************************************
- **************  interface  ******************
- *********************************************/
-
-int
-dsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
-{
-    DSA_secret_key sk;
-
-    if( algo != PUBKEY_ALGO_DSA )
-	return G10ERR_PUBKEY_ALGO;
-
-    generate( &sk, nbits, retfactors );
-    skey[0] = sk.p;
-    skey[1] = sk.q;
-    skey[2] = sk.g;
-    skey[3] = sk.y;
-    skey[4] = sk.x;
-    return 0;
-}
-
-
-int
-dsa_check_secret_key( int algo, MPI *skey )
-{
-    DSA_secret_key sk;
-
-    if( algo != PUBKEY_ALGO_DSA )
-	return G10ERR_PUBKEY_ALGO;
-    if( !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] )
-	return G10ERR_BAD_MPI;
-
-    sk.p = skey[0];
-    sk.q = skey[1];
-    sk.g = skey[2];
-    sk.y = skey[3];
-    sk.x = skey[4];
-    if( !check_secret_key( &sk ) )
-	return G10ERR_BAD_SECKEY;
-
-    return 0;
-}
-
-
-
-int
-dsa_sign( int algo, MPI *resarr, MPI data, MPI *skey )
-{
-    DSA_secret_key sk;
-
-    if( algo != PUBKEY_ALGO_DSA )
-	return G10ERR_PUBKEY_ALGO;
-    if( !data || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] )
-	return G10ERR_BAD_MPI;
-
-    sk.p = skey[0];
-    sk.q = skey[1];
-    sk.g = skey[2];
-    sk.y = skey[3];
-    sk.x = skey[4];
-    resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
-    resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
-    sign( resarr[0], resarr[1], data, &sk );
-    return 0;
-}
-
-int
-dsa_verify( int algo, MPI hash, MPI *data, MPI *pkey,
-		    int (*cmp)(void *, MPI) UNUSED, void *opaquev UNUSED)
-{
-    DSA_public_key pk;
-
-    if( algo != PUBKEY_ALGO_DSA )
-	return G10ERR_PUBKEY_ALGO;
-    if( !data[0] || !data[1] || !hash
-	|| !pkey[0] || !pkey[1] || !pkey[2] || !pkey[3] )
-	return G10ERR_BAD_MPI;
-
-    pk.p = pkey[0];
-    pk.q = pkey[1];
-    pk.g = pkey[2];
-    pk.y = pkey[3];
-    if( !verify( data[0], data[1], hash, &pk ) )
-	return G10ERR_BAD_SIGN;
-    return 0;
-}
-
-
-
-unsigned
-dsa_get_nbits( int algo, MPI *pkey )
-{
-    if( algo != PUBKEY_ALGO_DSA )
-	return 0;
-    return mpi_get_nbits( pkey[0] );
-}
-
-
-/****************
- * Return some information about the algorithm.  We need algo here to
- * distinguish different flavors of the algorithm.
- * Returns: A pointer to string describing the algorithm or NULL if
- *	    the ALGO is invalid.
- * Usage: Bit 0 set : allows signing
- *	      1 set : allows encryption
- */
-const char *
-dsa_get_info( int algo, int *npkey, int *nskey, int *nenc, int *nsig,
-							 int *use )
-{
-    *npkey = 4;
-    *nskey = 5;
-    *nenc = 0;
-    *nsig = 2;
-
-    switch( algo ) {
-      case PUBKEY_ALGO_DSA:   *use = PUBKEY_USAGE_SIG; return "DSA";
-      default: *use = 0; return NULL;
-    }
-}
-
-
diff -ruN freeswan-1.5.orig/pluto/dsa.h freeswan-1.5/pluto/dsa.h
--- freeswan-1.5.orig/pluto/dsa.h	Mon Nov  1 16:48:08 1999
+++ freeswan-1.5/pluto/dsa.h	Wed Dec 31 19:00:00 1969
@@ -1,32 +0,0 @@
-/* dsa.h  -  DSA signature scheme
- *	Copyright (C) 1998 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-#ifndef G10_DSA_H
-#define G10_DSA_H
-
-int dsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors );
-int dsa_check_secret_key( int algo, MPI *skey );
-int dsa_sign( int algo, MPI *resarr, MPI data, MPI *skey );
-int dsa_verify( int algo, MPI hash, MPI *data, MPI *pkey,
-		    int (*cmp)(void *, MPI), void *opaquev );
-unsigned dsa_get_nbits( int algo, MPI *pkey );
-const char *dsa_get_info( int algo, int *npkey, int *nskey,
-				    int *nenc, int *nsig, int *use );
-
-#endif /*G10_DSA_H*/
diff -ruN freeswan-1.5.orig/pluto/g10_dsa.c freeswan-1.5/pluto/g10_dsa.c
--- freeswan-1.5.orig/pluto/g10_dsa.c	Wed Dec 31 19:00:00 1969
+++ freeswan-1.5/pluto/g10_dsa.c	Thu Oct  5 07:05:59 2000
@@ -0,0 +1,476 @@
+/* g10_dsa.c  -  DSA signature scheme
+ *	Copyright (C) 1998 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef PLUTO
+#include <gmp.h>
+#include <freeswan.h>
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "rnd.h"
+#include "gcryptfix.h"
+#else /*! PLUTO */
+/* #include <config.h> */
+#endif /* !PLUTO */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef PLUTO
+/* #include <assert.h> */
+/* #include "util.h" */
+/* #include "mpi.h" */
+/* #include "cipher.h" */
+#endif
+
+#include "g10_dsa.h"
+
+typedef struct {
+    MPI p;	    /* prime */
+    MPI q;	    /* group order */
+    MPI g;	    /* group generator */
+    MPI y;	    /* g^x mod p */
+} DSA_public_key;
+
+
+typedef struct {
+    MPI p;	    /* prime */
+    MPI q;	    /* group order */
+    MPI g;	    /* group generator */
+    MPI y;	    /* g^x mod p */
+    MPI x;	    /* secret exponent */
+} DSA_secret_key;
+
+
+static MPI gen_k( MPI q );
+static void test_keys( DSA_secret_key *sk, unsigned qbits );
+static int  check_secret_key( DSA_secret_key *sk );
+static void generate( DSA_secret_key *sk, unsigned nbits, MPI **ret_factors );
+static void sign(MPI r, MPI s, MPI input, DSA_secret_key *skey);
+static int  verify(MPI r, MPI s, MPI input, DSA_public_key *pkey);
+
+static void
+progress( int c )
+{
+    fputc( c, stderr );
+}
+
+
+/****************
+ * Generate a random secret exponent k less than q
+ */
+static MPI
+gen_k( MPI q )
+{
+    MPI k = mpi_alloc_secure( mpi_get_nlimbs(q) );
+    unsigned int nbits = mpi_get_nbits(q);
+    unsigned int nbytes = (nbits+7)/8;
+    char *rndbuf = NULL;
+
+    if( DBG_CIPHER )
+	log_debug("choosing a random k ");
+    for(;;) {
+	if( DBG_CIPHER )
+	    progress('.');
+
+	if( !rndbuf || nbits < 32 ) {
+	    m_free(rndbuf);
+	    rndbuf = get_random_bits( nbits, 1, 1 );
+	}
+	else { /* change only some of the higher bits */
+	    /* we could imporove this by directly requesting more memory
+	     * at the first call to get_random_bits() and use this the here
+	     * maybe it is easier to do this directly in random.c */
+	    char *pp = get_random_bits( 32, 1, 1 );
+	    memcpy( rndbuf,pp, 4 );
+	    m_free(pp);
+	}
+	mpi_set_buffer( k, rndbuf, nbytes, 0 );
+	if( mpi_test_bit( k, nbits-1 ) )
+	    mpi_set_highbit( k, nbits-1 );
+	else {
+	    mpi_set_highbit( k, nbits-1 );
+	    mpi_clear_bit( k, nbits-1 );
+	}
+
+	if( !(mpi_cmp( k, q ) < 0) ) {	/* check: k < q */
+	    if( DBG_CIPHER )
+		progress('+');
+	    continue; /* no  */
+	}
+	if( !(mpi_cmp_ui( k, 0 ) > 0) ) { /* check: k > 0 */
+	    if( DBG_CIPHER )
+		progress('-');
+	    continue; /* no */
+	}
+	break;	/* okay */
+    }
+    m_free(rndbuf);
+    if( DBG_CIPHER )
+	progress('\n');
+
+    return k;
+}
+
+
+static void
+test_keys( DSA_secret_key *sk, unsigned qbits )
+{
+    DSA_public_key pk;
+    MPI test = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
+    MPI out1_a = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
+    MPI out1_b = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
+
+    pk.p = sk->p;
+    pk.q = sk->q;
+    pk.g = sk->g;
+    pk.y = sk->y;
+    /*mpi_set_bytes( test, qbits, get_random_byte, 0 );*/
+    {	char *p = get_random_bits( qbits, 0, 0 );
+	mpi_set_buffer( test, p, (qbits+7)/8, 0 );
+	m_free(p);
+    }
+
+    sign( out1_a, out1_b, test, sk );
+    if( !verify( out1_a, out1_b, test, &pk ) )
+	log_fatal("DSA:: sign, verify failed\n");
+
+    mpi_free( test );
+    mpi_free( out1_a );
+    mpi_free( out1_b );
+}
+
+
+
+/****************
+ * Generate a DSA key pair with a key of size NBITS
+ * Returns: 2 structures filled with all needed values
+ *	    and an array with the n-1 factors of (p-1)
+ */
+static void
+generate( DSA_secret_key *sk, unsigned nbits, MPI **ret_factors )
+{
+    MPI p;    /* the prime */
+    MPI q;    /* the 160 bit prime factor */
+    MPI g;    /* the generator */
+    MPI y;    /* g^x mod p */
+    MPI x;    /* the secret exponent */
+    MPI h, e;  /* helper */
+    unsigned qbits;
+    byte *rndbuf;
+
+    assert( nbits >= 512 && nbits <= 1024 );
+
+    qbits = 160;
+    p = generate_elg_prime( 1, nbits, qbits, NULL, ret_factors );
+    /* get q out of factors */
+    q = mpi_copy((*ret_factors)[0]);
+    if( mpi_get_nbits(q) != qbits )
+	BUG();
+
+    /* find a generator g (h and e are helpers)*/
+    /* e = (p-1)/q */
+    e = mpi_alloc( mpi_get_nlimbs(p) );
+    mpi_sub_ui( e, p, 1 );
+    mpi_fdiv_q( e, e, q );
+    g = mpi_alloc( mpi_get_nlimbs(p) );
+    h = mpi_alloc_set_ui( 1 ); /* we start with 2 */
+    do {
+	mpi_add_ui( h, h, 1 );
+	/* g = h^e mod p */
+	mpi_powm( g, h, e, p );
+    } while( !mpi_cmp_ui( g, 1 ) );  /* continue until g != 1 */
+
+    /* select a random number which has these properties:
+     *	 0 < x < q-1
+     * This must be a very good random number because this
+     * is the secret part. */
+    if( DBG_CIPHER )
+	log_debug("choosing a random x ");
+    assert( qbits >= 160 );
+    x = mpi_alloc_secure( mpi_get_nlimbs(q) );
+    mpi_sub_ui( h, q, 1 );  /* put q-1 into h */
+    rndbuf = NULL;
+    do {
+	if( DBG_CIPHER )
+	    progress('.');
+	if( !rndbuf )
+	    rndbuf = get_random_bits( qbits, 2, 1 );
+	else { /* change only some of the higher bits (= 2 bytes)*/
+	    char *r = get_random_bits( 16, 2, 1 );
+	    memcpy(rndbuf, r, 16/8 );
+	    m_free(r);
+	}
+	mpi_set_buffer( x, rndbuf, (qbits+7)/8, 0 );
+	mpi_clear_highbit( x, qbits+1 );
+    } while( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, h )<0 ) );
+    m_free(rndbuf);
+    mpi_free( e );
+    mpi_free( h );
+
+    /* y = g^x mod p */
+    y = mpi_alloc( mpi_get_nlimbs(p) );
+    mpi_powm( y, g, x, p );
+
+    if( DBG_CIPHER ) {
+	progress('\n');
+	log_mpidump("dsa  p= ", p );
+	log_mpidump("dsa  q= ", q );
+	log_mpidump("dsa  g= ", g );
+	log_mpidump("dsa  y= ", y );
+	log_mpidump("dsa  x= ", x );
+    }
+
+    /* copy the stuff to the key structures */
+    sk->p = p;
+    sk->q = q;
+    sk->g = g;
+    sk->y = y;
+    sk->x = x;
+
+    /* now we can test our keys (this should never fail!) */
+    test_keys( sk, qbits );
+}
+
+
+
+/****************
+ * Test whether the secret key is valid.
+ * Returns: if this is a valid key.
+ */
+static int
+check_secret_key( DSA_secret_key *sk )
+{
+    int rc;
+    MPI y = mpi_alloc( mpi_get_nlimbs(sk->y) );
+
+    mpi_powm( y, sk->g, sk->x, sk->p );
+    rc = !mpi_cmp( y, sk->y );
+    mpi_free( y );
+    return rc;
+}
+
+
+
+/****************
+ * Make a DSA signature from HASH and put it into r and s.
+ */
+
+static void
+sign(MPI r, MPI s, MPI hash, DSA_secret_key *skey )
+{
+    MPI k;
+    MPI kinv;
+    MPI tmp;
+
+    /* select a random k with 0 < k < q */
+    k = gen_k( skey->q );
+
+    /* r = (a^k mod p) mod q */
+    mpi_powm( r, skey->g, k, skey->p );
+    mpi_fdiv_r( r, r, skey->q );
+
+    /* kinv = k^(-1) mod q */
+    kinv = mpi_alloc( mpi_get_nlimbs(k) );
+    mpi_invm(kinv, k, skey->q );
+
+    /* s = (kinv * ( hash + x * r)) mod q */
+    tmp = mpi_alloc( mpi_get_nlimbs(skey->p) );
+    mpi_mul( tmp, skey->x, r );
+    mpi_add( tmp, tmp, hash );
+    mpi_mulm( s , kinv, tmp, skey->q );
+
+    mpi_free(k);
+    mpi_free(kinv);
+    mpi_free(tmp);
+}
+
+
+/****************
+ * Returns true if the signature composed from R and S is valid.
+ */
+static int
+verify(MPI r, MPI s, MPI hash, DSA_public_key *pkey )
+{
+    int rc;
+    MPI w, u1, u2, v;
+    MPI base[3];
+    MPI exp[3];
+
+
+    if( !(mpi_cmp_ui( r, 0 ) > 0 && mpi_cmp( r, pkey->q ) < 0) )
+	return 0; /* assertion	0 < r < q  failed */
+    if( !(mpi_cmp_ui( s, 0 ) > 0 && mpi_cmp( s, pkey->q ) < 0) )
+	return 0; /* assertion	0 < s < q  failed */
+
+    w  = mpi_alloc( mpi_get_nlimbs(pkey->q) );
+    u1 = mpi_alloc( mpi_get_nlimbs(pkey->q) );
+    u2 = mpi_alloc( mpi_get_nlimbs(pkey->q) );
+    v  = mpi_alloc( mpi_get_nlimbs(pkey->p) );
+
+    /* w = s^(-1) mod q */
+    mpi_invm( w, s, pkey->q );
+
+    /* u1 = (hash * w) mod q */
+    mpi_mulm( u1, hash, w, pkey->q );
+
+    /* u2 = r * w mod q  */
+    mpi_mulm( u2, r, w, pkey->q );
+
+    /* v =  g^u1 * y^u2 mod p mod q */
+    base[0] = pkey->g; exp[0] = u1;
+    base[1] = pkey->y; exp[1] = u2;
+    base[2] = NULL;    exp[2] = NULL;
+    mpi_mulpowm( v, base, exp, pkey->p );
+    mpi_fdiv_r( v, v, pkey->q );
+
+    rc = !mpi_cmp( v, r );
+
+    mpi_free(w);
+    mpi_free(u1);
+    mpi_free(u2);
+    mpi_free(v);
+    return rc;
+}
+
+
+/*********************************************
+ **************  interface  ******************
+ *********************************************/
+
+int
+dsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
+{
+    DSA_secret_key sk;
+
+    if( algo != PUBKEY_ALGO_DSA )
+	return G10ERR_PUBKEY_ALGO;
+
+    generate( &sk, nbits, retfactors );
+    skey[0] = sk.p;
+    skey[1] = sk.q;
+    skey[2] = sk.g;
+    skey[3] = sk.y;
+    skey[4] = sk.x;
+    return 0;
+}
+
+
+int
+dsa_check_secret_key( int algo, MPI *skey )
+{
+    DSA_secret_key sk;
+
+    if( algo != PUBKEY_ALGO_DSA )
+	return G10ERR_PUBKEY_ALGO;
+    if( !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] )
+	return G10ERR_BAD_MPI;
+
+    sk.p = skey[0];
+    sk.q = skey[1];
+    sk.g = skey[2];
+    sk.y = skey[3];
+    sk.x = skey[4];
+    if( !check_secret_key( &sk ) )
+	return G10ERR_BAD_SECKEY;
+
+    return 0;
+}
+
+
+
+int
+dsa_sign( int algo, MPI *resarr, MPI data, MPI *skey )
+{
+    DSA_secret_key sk;
+
+    if( algo != PUBKEY_ALGO_DSA )
+	return G10ERR_PUBKEY_ALGO;
+    if( !data || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] )
+	return G10ERR_BAD_MPI;
+
+    sk.p = skey[0];
+    sk.q = skey[1];
+    sk.g = skey[2];
+    sk.y = skey[3];
+    sk.x = skey[4];
+    resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
+    resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
+    sign( resarr[0], resarr[1], data, &sk );
+    return 0;
+}
+
+int
+dsa_verify( int algo, MPI hash, MPI *data, MPI *pkey,
+		    int (*cmp)(void *, MPI) UNUSED, void *opaquev UNUSED)
+{
+    DSA_public_key pk;
+
+    if( algo != PUBKEY_ALGO_DSA )
+	return G10ERR_PUBKEY_ALGO;
+    if( !data[0] || !data[1] || !hash
+	|| !pkey[0] || !pkey[1] || !pkey[2] || !pkey[3] )
+	return G10ERR_BAD_MPI;
+
+    pk.p = pkey[0];
+    pk.q = pkey[1];
+    pk.g = pkey[2];
+    pk.y = pkey[3];
+    if( !verify( data[0], data[1], hash, &pk ) )
+	return G10ERR_BAD_SIGN;
+    return 0;
+}
+
+
+
+unsigned
+dsa_get_nbits( int algo, MPI *pkey )
+{
+    if( algo != PUBKEY_ALGO_DSA )
+	return 0;
+    return mpi_get_nbits( pkey[0] );
+}
+
+
+/****************
+ * Return some information about the algorithm.  We need algo here to
+ * distinguish different flavors of the algorithm.
+ * Returns: A pointer to string describing the algorithm or NULL if
+ *	    the ALGO is invalid.
+ * Usage: Bit 0 set : allows signing
+ *	      1 set : allows encryption
+ */
+const char *
+dsa_get_info( int algo, int *npkey, int *nskey, int *nenc, int *nsig,
+							 int *use )
+{
+    *npkey = 4;
+    *nskey = 5;
+    *nenc = 0;
+    *nsig = 2;
+
+    switch( algo ) {
+      case PUBKEY_ALGO_DSA:   *use = PUBKEY_USAGE_SIG; return "DSA";
+      default: *use = 0; return NULL;
+    }
+}
+
+
diff -ruN freeswan-1.5.orig/pluto/g10_dsa.h freeswan-1.5/pluto/g10_dsa.h
--- freeswan-1.5.orig/pluto/g10_dsa.h	Wed Dec 31 19:00:00 1969
+++ freeswan-1.5/pluto/g10_dsa.h	Thu Oct  5 07:05:59 2000
@@ -0,0 +1,32 @@
+/* dsa.h  -  DSA signature scheme
+ *	Copyright (C) 1998 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_DSA_H
+#define G10_DSA_H
+
+int dsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors );
+int dsa_check_secret_key( int algo, MPI *skey );
+int dsa_sign( int algo, MPI *resarr, MPI data, MPI *skey );
+int dsa_verify( int algo, MPI hash, MPI *data, MPI *pkey,
+		    int (*cmp)(void *, MPI), void *opaquev );
+unsigned dsa_get_nbits( int algo, MPI *pkey );
+const char *dsa_get_info( int algo, int *npkey, int *nskey,
+				    int *nenc, int *nsig, int *use );
+
+#endif /*G10_DSA_H*/
diff -ruN freeswan-1.5.orig/pluto/ipsec_doi.c freeswan-1.5/pluto/ipsec_doi.c
--- freeswan-1.5.orig/pluto/ipsec_doi.c	Wed Jun 21 14:24:32 2000
+++ freeswan-1.5/pluto/ipsec_doi.c	Thu Oct  5 07:05:59 2000
@@ -47,6 +47,10 @@
 #include "md5.h"
 #include "crypto.h" /* requires sha1.h and md5.h */
 
+#ifdef OPENSSL
+#include "openssl.h"
+#endif
+
 /* MAGIC: perform f, a function that returns notification_t
  * and return from the ENCLOSING stf_status returning function if it fails.
  */
@@ -56,6 +60,65 @@
 /* if we haven't already done so, compute a local DH secret (st->st_sec) and
  * the corresponding public value (g).  This is emitted as a KE payload.
  */
+#ifdef OPENSSL
+static bool
+build_and_ship_KE_rpk(struct state *st, bool init,
+		      chunk_t *g,
+		      const struct oakley_group_desc *group, pb_stream *outs,
+		      u_int8_t np)
+{
+  keysched *ks;
+  u_char *iv;
+  chunk_t op;
+  bool res;
+
+    if (!st->st_sec_in_use)
+    {
+	u_char tmp[LOCALSECRETSIZE];
+	MP_INT mp_g;
+
+	get_rnd_bytes(tmp, LOCALSECRETSIZE);
+	st->st_sec_in_use = TRUE;
+	n_to_mpz(&st->st_sec, tmp, LOCALSECRETSIZE);
+
+	mpz_init(&mp_g);
+	mpz_powm(&mp_g, &groupgenerator, &st->st_sec, group->modulus);
+	*g = mpz_to_n(&mp_g, group->bytes);
+	mpz_clear(&mp_g);
+#ifdef DODGE_DH_MISSING_ZERO_BUG
+	if (g->ptr[0] == 0)
+	{
+	    /* generate a new secret to avoid this situation */
+	    log("regenerating DH private secret to avoid Pluto 1.0 bug"
+		" handling public value with leading zero");
+	    mpz_clear(&st->st_sec);
+	    st->st_sec_in_use = FALSE;
+	    freeanychunk(*g);
+	    return build_and_ship_KE_rpk(st, init, g, group, outs, np);
+	}
+#endif
+
+	DBG(DBG_CRYPT,
+	    DBG_dump("Local DH secret:\n", tmp, LOCALSECRETSIZE);
+	    DBG_dump_chunk("Public DH value sent:\n", *g));
+    }
+    /* Encrypt the chunk */
+    if (init) {
+      ks = &st->st_ks_i;
+      iv = st->st_ne_i_iv;
+    } else {
+      ks = &st->st_ks_r;
+      iv = st->st_ne_r_iv;
+    }
+    setchunk(op, NULL, 0);
+    if (!encrypt_payload( st, ks, iv, *g, &op )) return FALSE;
+    res = out_generic_chunk(np, &isakmp_keyex_desc, outs, op,
+			    "encrypted keyex value");
+    freeanychunk(op);
+    return res;
+}
+#endif
+
 static bool
 build_and_ship_KE(struct state *st, chunk_t *g
     , const struct oakley_group_desc *group, pb_stream *outs, u_int8_t np)
@@ -192,6 +255,21 @@
     return out_generic_chunk(np, &isakmp_nonce_desc, outs, *n, name);
 }
 
+#ifdef OPENSSL
+static bool
+build_and_ship_nonce_pk(struct state *st, chunk_t *n, pb_stream *outs, u_int8_t np, const char *name)
+{
+    chunk_t c;
+
+    setchunk(*n, alloc_bytes(DEFAULT_NONCE_SIZE, name), DEFAULT_NONCE_SIZE);
+    get_rnd_bytes(n->ptr, DEFAULT_NONCE_SIZE);
+    c.len = n->len;
+    c.ptr = clone_bytes(n->ptr, c.len, name);
+    pubkey_encrypt_chunk(&c, st);
+    return out_generic_chunk(np, &isakmp_nonce_desc, outs, c, name);
+}
+#endif
+
 /*
  * Send a notification to the peer. We could make a decision on
  * whether to send the notification, based on the type and the
@@ -290,6 +368,9 @@
 
     struct state *st;
 
+	DBG(DBG_PARSING,
+	    DBG_log("in main_outI1");
+	);
     /* set up new state */
     cur_state = st = new_state();
     st->st_connection = c;
@@ -347,7 +428,11 @@
 
 	    if (get_RSA_private_key(c) != NULL
 	    && get_RSA_public_key(&c->that.id) != NULL)
+#ifndef OPENSSL
 		auth_policy |= POLICY_RSASIG;
+#else
+		auth_policy |= POLICY_OPENSSL;
+#endif
 	    /* Not clear what we should do if neither is possible.
 	     * Perhaps we should not have entered negotiations at all.
 	     */
@@ -358,6 +443,23 @@
 		return STF_INTERNAL_ERROR;
 	    }
 	}
+
+#ifdef OPENSSL
+if (use_openssl(c)) 
+{
+	loglog(RC_LOG_SERIOUS, "Using OPENSSL sadb.");
+	if (!out_sa(&rbody
+	, &oakley_sadb2[auth_policy >> POLICY_ISAKMP_SHIFT]
+	, st, TRUE, ISAKMP_NEXT_NONE))
+	{
+	    cur_state = NULL;
+	    return STF_INTERNAL_ERROR;
+	}
+}
+else
+{
+#endif /* OPENSSL */
+	loglog(RC_LOG_SERIOUS, "Using standard sadb.");
 	if (!out_sa(&rbody
 	, &oakley_sadb[auth_policy >> POLICY_ISAKMP_SHIFT]
 	, st, TRUE, ISAKMP_NEXT_NONE))
@@ -365,6 +467,10 @@
 	    cur_state = NULL;
 	    return STF_INTERNAL_ERROR;
 	}
+#ifdef OPENSSL
+}
+#endif /* ! OPENSSL */
+
 
 	/* save initiator SA for later HASH */
 	passert(st->st_p1isa.ptr == NULL);	/* no leak!  (MUST be first time) */
@@ -517,6 +623,70 @@
     hmac_final_chunk(st->st_skeyid, "st_skeyid in skeyid_digisig()", &ctx);
     return TRUE;
 }
+// static bool
+// skeyid_digisig(struct state *st)
+// {
+//     struct hmac_ctx ctx;
+//     const chunk_t cat = chunk_concat( st->st_ni, st->st_nr );
+// 
+//     hmac_init_chunk(&ctx, st->st_oakley.hasher, cat);
+//     hmac_update_chunk(&ctx, st->st_shared);
+//     hmac_final_chunk(st->st_skeyid, "st_skeyid in skeyid_digisig()", &ctx);
+//     memset(cat.ptr, 0, cat.len);
+//     free(cat.ptr);
+//     return TRUE;
+// }
+
+#ifdef OPENSSL
+// static const chunk_t
+// chunk_concat( const chunk_t c1, const chunk_t c2 )
+// {
+//     chunk_t cc;
+// 
+//     cc.len = c1.len + c2.len;
+//     if ((cc.ptr = malloc(cc.len)) != NULL) {
+//       memcpy(cc.ptr, c1.ptr, c1.len);
+//       memcpy(&(cc.ptr[c1.len]), c2.ptr, c2.len);
+//     }
+//     return cc;
+// }
+
+
+static bool
+skeyid_pke(struct state *st)
+{
+    /* This routine lifted straight from Kai Martius' patches */
+    /* and updated to use chunks */
+    struct hmac_ctx ctx;
+    union hash_ctx ictx;
+    const struct hash_desc *h = st->st_oakley.hasher;
+    u_char *nonce;
+    u_int16_t nonce_len;
+    chunk_t noncechunk, cky_i, cky_r;
+
+    nonce_len = h->hash_digest_len;
+    nonce=alloc_bytes(nonce_len, "nonce in skeyid_pke()");
+
+    h->hash_init(&ictx);
+    h->hash_update(&ictx, st->st_ni.ptr, st->st_ni.len);
+    h->hash_update(&ictx, st->st_nr.ptr, st->st_nr.len);
+    h->hash_final(nonce, &ictx);
+
+    setchunk(noncechunk, nonce, nonce_len);
+    setchunk(cky_i, st->st_icookie, COOKIE_SIZE);
+    setchunk(cky_r, st->st_rcookie, COOKIE_SIZE);
+
+    hmac_init_chunk(&ctx, h, noncechunk);
+    hmac_update_chunk(&ctx, cky_i);
+    hmac_update_chunk(&ctx, cky_r);
+    hmac_final_chunk(st->st_skeyid, "st_skeyid in skeyid_pke()", &ctx);
+
+    free(nonce);
+
+    return TRUE;
+}
+#endif
+
 
 /* Generate the SKEYID_* and new IV
  * See draft-ietf-ipsec-ike-01.txt 4.1
@@ -539,13 +709,21 @@
 
 	case OAKLEY_DSS_SIG:
 	    /* XXX */
-
+#ifdef OPENSSL
+	    if (!skeyid_digisig(st))
+	        return FALSE;
+	    break;
+#endif
 	case OAKLEY_RSA_ENC:
 	case OAKLEY_RSA_ENC_REV:
 	case OAKLEY_ELGAMAL_ENC:
 	case OAKLEY_ELGAMAL_ENC_REV:
 	    /* XXX */
-
+#ifdef OPENSSL
+	    if (!skeyid_pke(st))
+	        return FALSE;
+	    break;
+#endif
 	default:
 	    exit_log("generate_skeyids_iv(): unsupported authentication method %s",
 		enum_show(&oakley_auth_names, st->st_oakley.auth));
@@ -733,7 +911,7 @@
     return ctx.hmac_digest_len;
 }
 
-#if 0	/* only needed for DSS */
+#ifdef OPENSSL
 static void
 main_mode_sha1(struct state *st, u_char *hash_val, size_t *hash_len
 , bool hashi, bool hashus)
@@ -749,6 +927,7 @@
 }
 #endif
 
+
 /* Create an RSA signature of a hash.
  * Poorly specified in draft-ietf-ipsec-ike-01.txt 6.1.1.2.
  * Use PKCS#1 version 1.5 encryption of hash (called
@@ -936,6 +1115,13 @@
     switch (st->st_oakley.auth)
     {
     case OAKLEY_PRESHARED_KEY:
+#ifdef OPENSSL
+	case OAKLEY_RSA_ENC:
+	case OAKLEY_RSA_ENC_REV:
+	case OAKLEY_DSS_SIG:
+	case OAKLEY_ELGAMAL_ENC:
+	case OAKLEY_ELGAMAL_ENC_REV:
+#endif
 	{
 	    pb_stream *const hash_pbs = &md->chain[ISAKMP_NEXT_HASH]->pbs;
 
@@ -1041,7 +1227,8 @@
 	}
     }
 
-    DBG(DBG_CRYPT, DBG_log("encrypting using %s", enum_show(&oakley_enc_names, st->st_oakley.encrypt)));
+    DBG(DBG_CRYPT, DBG_log("encrypting using %s", 
+		enum_show(&oakley_enc_names, st->st_oakley.encrypt)));
 
     e->crypt(TRUE, enc_start, enc_len, st);
 
@@ -1721,6 +1908,9 @@
 
     pb_stream r_sa_pbs;
 
+	DBG(DBG_PARSING,
+	    DBG_log("in main_inI1_outR1");
+	);
     if (c == NULL)
     {
 	/* see if a wildcarded connection can be found */
@@ -1825,6 +2015,13 @@
 main_inR1_outI2(struct msg_digest *md)
 {
     struct state *const st = md->st;
+#ifdef OPENSSL
+    u_int8_t np;
+#endif
+
+	DBG(DBG_PARSING,
+	    DBG_log("in main_inR1_outI2");
+	);
 
     /* verify echoed SA */
     {
@@ -1834,12 +2031,19 @@
 	    , &sapd->payload.sa, NULL, TRUE, st));
     }
 
+// Here, we have to decide if the outgoing packet is going to be created 
+// for the classic RSASIG, or the OPENSSL functions.
+#ifdef OPENSSL
+if (!use_openssl(st->st_connection)) 
+{
+#endif
     /**************** build output packet HDR;KE;Ni ****************/
 
     /* HDR out.
      * We can't leave this to comm_handle() because the isa_np
      * depends on the type of Auth (eventually).
      */
+
     {
 	struct isakmp_hdr r_hdr = md->hdr;
 
@@ -1852,11 +2056,135 @@
     if (!build_and_ship_KE(st, &st->st_gi, st->st_oakley.group
     , &md->rbody, ISAKMP_NEXT_NONCE))
 	return STF_INTERNAL_ERROR;
-
+    
     /* Ni out */
     if (!build_and_ship_nonce(&st->st_ni, &md->rbody, ISAKMP_NEXT_NONE, "Ni"))
+      return STF_INTERNAL_ERROR;
+
+#ifdef OPENSSL
+}
+else /* use_openssl == TRUE */
+{
+
+	DBG(DBG_PARSING, 
+	    DBG_log("main_inR1_outI2: auth chosen is %s",
+			enum_show(&oakley_auth_names, st->st_oakley.auth));
+	);
+
+    if ((st->st_oakley.auth == OAKLEY_RSA_ENC_REV) ||
+	(st->st_oakley.auth == OAKLEY_ELGAMAL_ENC_REV)) {
+      struct isakmp_hdr r_hdr = md->hdr;
+
+      /* HDR out */
+      r_hdr.isa_np = ISAKMP_NEXT_NONCE;
+      if (!out_struct(&r_hdr, &isakmp_hdr_desc, &md->reply, &md->rbody))
+	return STF_INTERNAL_ERROR;
+      
+      if (!build_and_ship_nonce_pk(st, &st->st_ni, &md->rbody,
+				   ISAKMP_NEXT_KE, "<Ni_b>PubKey_r"))
+	return STF_INTERNAL_ERROR;
+
+      if (derive_symmetric_key(st, st->st_ni,
+			       st->st_icookie, COOKIE_SIZE,
+			       &st->st_ks_i,
+			       &st->st_ne_i) < 0) {
+	log("error while deriving symmetric key in revised mode");
+	return STF_INTERNAL_ERROR;
+	}
+	memset(st->st_ne_i_iv, 0, MAX_DIGEST_LEN);
+	DBG(DBG_PARSING,
+      DBG_dump_chunk("Generated Ke_i:", st->st_ne_i);
+	);
+
+      /* KE out */
+      if (!build_and_ship_KE_rpk(st, TRUE, &st->st_gi, st->st_oakley.group
+				 , &md->rbody, ISAKMP_NEXT_ID))
+	return STF_INTERNAL_ERROR;
+
+	/* <IDi1_b>Ke_i out */
+	{
+		chunk_t ch, out;
+	
+		// ch.len = st->st_myidentity.len + 4;
+		ch.len = sizeof(st->st_connection->this.id.ip_addr) + 4;
+		ch.ptr = alloc_bytes(ch.len, "encrypted identity");
+		// ch.ptr[0] = (u_int8_t)st->st_myidentity_type;
+		ch.ptr[0] = (u_int8_t)st->st_connection->this.id.kind;
+		memset(&(ch.ptr[1]), 0, 1);
+		memset(&(ch.ptr[2]), 0, 2);
+		// memcpy(&(ch.ptr[4]), st->st_myidentity.ptr, st->st_myidentity.len);
+		memcpy(&(ch.ptr[4]), &(st->st_connection->this.id.ip_addr), 
+			sizeof(st->st_connection->this.id.ip_addr));
+
+		if (!encrypt_payload(st, &st->st_ks_i, st->st_ne_i_iv,
+			ch, &out))
+			return STF_INTERNAL_ERROR;
+		freeanychunk(ch);
+		if (!out_generic_chunk(ISAKMP_NEXT_NONE, &isakmp_generic_desc,
+			&md->rbody, out, "my identity (ciphertext)")) 
+		{
+			freeanychunk(out);
+			return STF_INTERNAL_ERROR;
+		}
+		freeanychunk(out);
+	}
+
+    } else {
+      struct isakmp_hdr r_hdr = md->hdr;
+      
+      r_hdr.isa_np = ISAKMP_NEXT_KE;
+      if (!out_struct(&r_hdr, &isakmp_hdr_desc, &md->reply, &md->rbody))
 	return STF_INTERNAL_ERROR;
 
+      if ((st->st_oakley.auth == OAKLEY_RSA_ENC) ||
+	  (st->st_oakley.auth == OAKLEY_ELGAMAL_ENC))
+	np = ISAKMP_NEXT_ID;
+      else /* Digital Sig or Preshared key */
+	np = ISAKMP_NEXT_NONCE;
+      
+      /* KE out */
+      if (!build_and_ship_KE(st, &st->st_gi, st->st_oakley.group
+			     , &md->rbody, np))
+	return STF_INTERNAL_ERROR;
+      
+      if ((st->st_oakley.auth == OAKLEY_RSA_ENC) ||
+	  (st->st_oakley.auth == OAKLEY_ELGAMAL_ENC)) {
+	/* <IDii_b>PubKey_r out */
+	chunk_t ch;
+	
+	// ch.len = st->st_myidentity.len + 4;
+	ch.len = sizeof(st->st_connection->this.id.ip_addr) + 4;
+	ch.ptr = alloc_bytes(ch.len, "my identity (plaintext)");
+	/* Store the identity type */
+	// ch.ptr[0] = (u_int8_t)st->st_myidentity_type;
+	ch.ptr[0] = (u_int8_t)st->st_connection->this.id.kind;
+	memset(&(ch.ptr[1]), 0, 1); /* Set protoid to be 0 - perhaps it should be IPPROTO_UDP */
+	memset(&(ch.ptr[2]), 0, 2); /* Set the port to be 0 - perhaps it should be our_port */
+	// memcpy(&(ch.ptr[4]), st->st_myidentity.ptr, st->st_myidentity.len);
+	memcpy(&(ch.ptr[4]), &(st->st_connection->this.id.ip_addr), 
+		sizeof(st->st_connection->this.id.ip_addr));
+	/* PK encrypt this */
+	pubkey_encrypt_chunk( &ch, st );
+	if (!out_generic_chunk(ISAKMP_NEXT_NONCE, &isakmp_generic_desc,
+			       &md->rbody, ch, "my identity (ciphertext)"))
+	  return STF_INTERNAL_ERROR;
+	memset(ch.ptr, 0, ch.len);
+	freeanychunk(ch);
+
+	if (!build_and_ship_nonce_pk(st, &st->st_ni, &md->rbody,
+				     ISAKMP_NEXT_NONE, "<Ni_b>PubKey_r"))
+	  return STF_INTERNAL_ERROR;
+      } else {
+	DBG(DBG_PARSING,
+		DBG_log("Shipping nonce_i");
+	);
+	if (!build_and_ship_nonce(&st->st_ni, &md->rbody, ISAKMP_NEXT_NONE, "Ni"))
+	  return STF_INTERNAL_ERROR;
+      }
+    }
+}
+#endif
+
     /* finish message */
     close_message(&md->rbody);
 
@@ -1886,6 +2214,9 @@
     struct state *const st = md->st;
     pb_stream *keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs;
 
+	DBG(DBG_PARSING,
+	    DBG_log("in main_inI2_outR2");
+	);
     /* KE in */
     RETURN_STF_FAILURE(accept_KE(&st->st_gi, "Gi", st->st_oakley.group, keyex_pbs));
 
@@ -1927,6 +2258,191 @@
     return STF_REPLY;
 }
 
+#ifdef OPENSSL
+/* Handle HDR;KE;<IDii_b>PubKey_r;<Ni_b>PubKey_r from Initiator.
+ * Send a HDR;KE;<IDir_b>PubKey_i;<Nr_b>PubKey_i back.
+ */
+stf_status
+main_inI2_outR2_pk(struct msg_digest *md)
+{
+    struct state *const st = md->st;
+
+    pb_stream *keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs;
+
+	DBG(DBG_PARSING,
+	    DBG_log("in main_inI2_outR2_pk");
+	);
+    /* KE in */
+    // ACCEPT_KE(st->st_gi, "Gi", st->st_oakley.group, *keyex_pbs);
+	RETURN_STF_FAILURE(accept_KE(&st->st_gi, "Gi", 
+		st->st_oakley.group, keyex_pbs));
+
+    if (!decode_peer_id(md, FALSE))
+	return STF_FAIL + INVALID_ID_INFORMATION;
+
+    /* Ni_b<PubKey_r> in */
+    // ACCEPT_NONCE(st->st_ni, "<Ni_b>PubKey_r");
+    RETURN_STF_FAILURE(accept_nonce(md, &st->st_ni, "<Ni_b>PubKey_r"));
+
+    /** build output packet HDR;KE;<IDir_b>_PubKey_i;<Nr_b>PubKey_i*********/
+
+    /* HDR out done */
+
+    /* KE out */
+    if (!build_and_ship_KE(st, &st->st_gr, st->st_oakley.group
+    , &md->rbody, ISAKMP_NEXT_ID))
+	return STF_INTERNAL_ERROR;
+
+    {
+      /* <IDir_b>PubKey_i out */
+      chunk_t ch;
+      
+      // ch.len = st->st_myidentity.len + 4;
+	  ch.len = sizeof(st->st_connection->this.id.ip_addr) + 4;
+      ch.ptr = alloc_bytes(ch.len, "my identity (plaintext)");
+      /* Store the identity type */
+      // ch.ptr[0] = (u_int8_t)st->st_myidentity_type;
+	  ch.ptr[0] = (u_int8_t)st->st_connection->this.id.kind;
+      memset(&(ch.ptr[1]), 0, 1); /* Set protoid to be 0 - perhaps it should be IPPROTO_UDP */
+      memset(&(ch.ptr[2]), 0, 2); /* Set the port to be 0 - perhaps it should be our_port */
+      // memcpy(&(ch.ptr[4]), st->st_myidentity.ptr, st->st_myidentity.len);
+	  memcpy(&(ch.ptr[4]), &(st->st_connection->this.id.ip_addr), 
+		sizeof(st->st_connection->this.id.ip_addr));
+      /* PK encrypt this */
+      pubkey_encrypt_chunk( &ch, st );
+      if (!out_generic_chunk(ISAKMP_NEXT_NONCE, &isakmp_generic_desc, &md->rbody, ch, "my identity (ciphertext)"))
+	return STF_INTERNAL_ERROR;
+      memset(ch.ptr, 0, ch.len);
+      freeanychunk(ch);
+    }
+    
+    /* Nr out */
+    if (!build_and_ship_nonce_pk(st, &st->st_nr, &md->rbody, ISAKMP_NEXT_NONE, "<Nr_b>PubKey_i"))
+      return STF_INTERNAL_ERROR;
+
+    /* finish message */
+    close_message(&md->rbody);
+
+    /* next message will be encrypted, but not this one.
+     * We could defer this calculation.
+     */
+    compute_dh_shared(st, st->st_gi, st->st_oakley.group);
+#ifdef DODGE_DH_MISSING_ZERO_BUG
+    if (st->st_shared.ptr[0] == 0)
+	return STF_DROP_DOOMED_EXCHANGE;
+#endif
+    if (!generate_skeyids_iv(st))
+	return STF_FAIL + AUTHENTICATION_FAILED;
+    update_iv(st);
+
+    /* Advance state */
+    st->st_state = STATE_MAIN_R2;
+
+    return STF_REPLY;
+}
+#endif /* OPENSSL */
+
+#ifdef OPENSSL
+/* Handle HDR;<Ni_b>Pubkey_r;<KE_b>Ke_i;<IDi1_b>Ke_i from Initiator
+ * Send a HDR;<Nr_b>Pubkey_i;<KE_b>Ke_r;<IDr1_b>Ke_r back.
+ */
+stf_status
+main_inI2_outR2_rpk(struct msg_digest *md)
+{
+    struct state *const st = md->st;
+    pb_stream *keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs;
+
+	DBG(DBG_PARSING,
+		DBG_log("in main_inI2_outR2_rpk");
+	);
+
+    /* Ni_b<PubKey_r> in */
+    // ACCEPT_NONCE(st->st_ni, "<Ni_b>PubKey_r");
+    RETURN_STF_FAILURE(accept_nonce(md, &st->st_ni, "<Ni_b>PubKey_r"));
+
+    /* KE<Ke_r> in */
+    // ACCEPT_KE(st->st_gi, "Gi", st->st_oakley.group, *keyex_pbs);
+	RETURN_STF_FAILURE(accept_KE(&st->st_gi, "Gi", 
+		st->st_oakley.group, keyex_pbs));
+
+    if (!decode_peer_id(md, FALSE))
+	return STF_FAIL + INVALID_ID_INFORMATION;
+
+    /**************** build output packet ****************/
+
+    /* HDR out done */
+
+    /* Nr out */
+    if (!build_and_ship_nonce_pk(st, &st->st_nr, &md->rbody, ISAKMP_NEXT_KE, "<Nr_b>PubKey_i"))
+      return STF_INTERNAL_ERROR;
+
+    if (derive_symmetric_key(st, st->st_nr,
+			     st->st_rcookie, COOKIE_SIZE,
+			     &st->st_ks_r,
+			     &st->st_ne_r) < 0) {
+      log("error while deriving symmetric key in revised mode");
+      return STF_INTERNAL_ERROR;
+    }
+    memset(st->st_ne_r_iv, 0, MAX_DIGEST_LEN);
+
+	DBG(DBG_PARSING,
+	    DBG_dump_chunk("Generated Ke_r:", st->st_ne_r);
+	);
+
+    /* KE out */
+    if (!build_and_ship_KE_rpk(st, FALSE, &st->st_gr, st->st_oakley.group
+			       , &md->rbody, ISAKMP_NEXT_ID))
+      return STF_INTERNAL_ERROR;
+
+    /* <IDr1_b>Ke_r out */
+    {
+      chunk_t ch, out;
+      
+      // ch.len = st->st_myidentity.len + 4;
+	  ch.len = sizeof(st->st_connection->this.id.ip_addr) + 4;
+      ch.ptr = alloc_bytes(ch.len, "encrypted identity");
+      // ch.ptr[0] = (u_int8_t)st->st_myidentity_type;
+	  ch.ptr[0] = (u_int8_t)st->st_connection->this.id.kind;
+      memset(&(ch.ptr[1]), 0, 1);
+      memset(&(ch.ptr[2]), 0, 2);
+      // memcpy(&(ch.ptr[4]), st->st_myidentity.ptr, st->st_myidentity.len);
+	  memcpy(&(ch.ptr[4]), &(st->st_connection->this.id.ip_addr),
+		sizeof(st->st_connection->this.id.ip_addr));
+      if (!encrypt_payload(st, &st->st_ks_r, st->st_ne_r_iv,
+			   ch, &out))
+	return STF_INTERNAL_ERROR;
+      freeanychunk(ch);
+      if (!out_generic_chunk(ISAKMP_NEXT_NONE, &isakmp_generic_desc,
+			     &md->rbody, out, "my identity (ciphertext)")) {
+	freeanychunk(out);
+	return STF_INTERNAL_ERROR;
+      }
+      freeanychunk(out);
+    }
+    
+    /* finish message */
+    close_message(&md->rbody);
+
+    /* next message will be encrypted, but not this one.
+     * We could defer this calculation.
+     */
+    compute_dh_shared(st, st->st_gi, st->st_oakley.group);
+#ifdef DODGE_DH_MISSING_ZERO_BUG
+    if (st->st_shared.ptr[0] == 0)
+	return STF_DROP_DOOMED_EXCHANGE;
+#endif
+    if (!generate_skeyids_iv(st))
+	return STF_FAIL + AUTHENTICATION_FAILED;
+    update_iv(st);
+
+    /* Advance state */
+    st->st_state = STATE_MAIN_R2;
+
+    return STF_REPLY;
+}
+#endif /* OPENSSL */
+
+
 /* STATE_MAIN_I2:
  * SMF_PSK_AUTH: HDR, KE, Nr --> HDR*, IDi1, HASH_I
  * SMF_DS_AUTH: HDR, KE, Nr --> HDR*, IDi1, [ CERT, ] SIG_I
@@ -1941,12 +2457,22 @@
 main_inR2_outI3(struct msg_digest *md)
 {
     struct state *const st = md->st;
+#ifdef OPENSSL
+    struct connection *c = st->st_connection;
+#endif
+
     pb_stream *const keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs;
+
     int auth_payload = st->st_oakley.auth == OAKLEY_PRESHARED_KEY
 	? ISAKMP_NEXT_HASH : ISAKMP_NEXT_SIG;
 
+	DBG(DBG_PARSING,
+	    DBG_log("in main_inR2_outI3");
+	);
+
     /* KE in */
-    RETURN_STF_FAILURE(accept_KE(&st->st_gr, "Gr", st->st_oakley.group, keyex_pbs));
+    RETURN_STF_FAILURE(accept_KE(&st->st_gr, "Gr", 
+		st->st_oakley.group, keyex_pbs));
 
     /* Nr in */
     RETURN_STF_FAILURE(accept_nonce(md, &st->st_nr, "Nr"));
@@ -1962,7 +2488,6 @@
 	return STF_FAIL + AUTHENTICATION_FAILED;
 
     /*************** build output packet HDR*;IDii;HASH/SIG_I ***************/
-    /* ??? NOTE: this is almost the same as main_inI3_outR3's code */
 
     /* HDR* out done */
 
@@ -1972,16 +2497,144 @@
 	chunk_t id_b;
 	pb_stream id_pbs;
 
-	build_id_payload(&id_hd, &id_b, &st->st_connection->this);
+	build_id_payload(&id_hd, &id_b, &(st->st_connection->this));
+#ifdef OPENSSL
+if (use_openssl(st->st_connection)) 
+{
+  switch(st->st_oakley.auth) {
+  case OAKLEY_RSA_SIG:
+  case OAKLEY_DSS_SIG:
+    if ((c->cert_options & CERT_OPTION_SEND) == 0)
+      id_hd.isaiid_np = ISAKMP_NEXT_SIG;
+    else
+      id_hd.isaiid_np = ISAKMP_NEXT_CERT;
+    break;
+  case OAKLEY_RSA_ENC:
+  case OAKLEY_RSA_ENC_REV:
+    log("RSA method not supported yet");
+    return STF_INTERNAL_ERROR;
+    break;
+  default:
+    id_hd.isaiid_np = ISAKMP_NEXT_HASH;
+    break;
+  }
+}
+else
+{
+#endif /* OPENSSL */
 	id_hd.isaiid_np = auth_payload;
+#ifdef OPENSSL
+}
+#endif /* OPENSSL */
+
 	if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &md->rbody, &id_pbs)
-	|| !out_chunk(id_b, &id_pbs, "my identity"))
-	    return STF_INTERNAL_ERROR;
+		|| !out_chunk(id_b, &id_pbs, "my identity")) 
+		return STF_INTERNAL_ERROR;
 	close_output_pbs(&id_pbs);
+    } /* IDii out done */
+
+#ifdef OPENSSL
+if (use_openssl(st->st_connection)) 
+{
+    if (((c->cert_options & CERT_OPTION_SEND) != 0) &&
+  ((st->st_oakley.auth == OAKLEY_RSA_SIG) ||
+   (st->st_oakley.auth == OAKLEY_DSS_SIG))) {
+      u_char *crt, *cx;
+      unsigned long ulen;
+      /* Send the signing certificate */
+
+      ulen = i2d_X509(c->cert, NULL);
+      ulen++;
+      if ((cx = alloc_bytes(ulen, "ASN.1 cert")) == NULL)
+  { return STF_INTERNAL_ERROR; }
+      cx[0] = (u_char)(CERT_TYPE_X509_SIG);
+      crt = &(cx[1]);
+      i2d_X509(c->cert, &crt);
+      if (!out_generic_raw(ISAKMP_NEXT_SIG, &isakmp_ipsec_certificate_desc
+             , &md->rbody, cx, ulen, "CERT_I"))
+  return STF_INTERNAL_ERROR;
+      pfree(cx);
     }
 
-    /* HASH_I or SIG_I out */
-    {
+  /* HASH_I out, OPENSSL */
+  {
+	u_char hash_val[MAX_DIGEST_LEN];
+	size_t hash_len = main_mode_hash(st, hash_val, TRUE, TRUE);
+    u_char *buf;
+    u_int elen;
+    bool ok;
+
+  /* Output the signature/hash as defined by the selected Oakley transform */
+
+  switch (st->st_oakley.auth) {
+  case OAKLEY_RSA_SIG: /* output signed HASH_I */
+    if ((buf = alloc_bytes(EVP_PKEY_size(c->key) + 32 /* bit of slack */,
+               "RSA signature")) == NULL)
+        return STF_INTERNAL_ERROR;
+    elen = RSA_private_encrypt(hash_len, hash_val, buf,
+                   ((EVP_PKEY *)(c->key))->pkey.rsa,
+                   RSA_PKCS1_PADDING);
+    if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_signature_desc, &md->rbody
+                 , buf, elen, "SIG_I"))
+      return STF_INTERNAL_ERROR;
+    pfree(buf);
+   
+	DBG(DBG_PARSING,
+	    DBG_log("Selected auth mechanism is %s",
+        	enum_show(&oakley_auth_names, st->st_oakley.auth));
+	)
+    break;
+
+  case OAKLEY_DSS_SIG:
+    /* We don't have to check whether the hash is a SHA1 */
+    /* one, since the ciphersuite offering DSA is only */
+    /* configured with SHA1. Don't change this configuration */
+    if (c->cert_options & CERT_OPTION_DSS_SHA)
+      main_mode_sha1(st, hash_val, &hash_len, TRUE, TRUE);
+
+    buf = alloc_bytes(EVP_PKEY_size(c->key) + 32 /* bit of slack */,
+              "DSA signature");
+    if (buf) {
+      ok = (c->cert_options & CERT_OPTION_DSS_ALT)
+        ? DSA_sign_raw(hash_val, hash_len,
+               buf, &elen, ((EVP_PKEY *)(c->key))->pkey.dsa)
+        : DSA_sign(EVP_PKEY_DSA, hash_val, hash_len,
+           buf, &elen, ((EVP_PKEY *)(c->key))->pkey.dsa);
+      if (!ok) {
+        /* DSA signing failed */
+        log_err();
+        return STF_INTERNAL_ERROR;
+      }
+      if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_signature_desc,
+               &md->rbody, buf, elen, "SIG_I"))
+        return STF_INTERNAL_ERROR;
+      pfree(buf);
+    } else
+      return STF_INTERNAL_ERROR;
+   
+	DBG(DBG_PARSING | DBG_CONTROL, 
+	    DBG_log("Selected auth mechanism is %s",
+			enum_show(&oakley_auth_names, st->st_oakley.auth));
+	);
+    break;
+    /* If we get to any of these, something has gone WAY wrong */
+  case OAKLEY_RSA_ENC:
+    return STF_INTERNAL_ERROR;
+  case OAKLEY_ELGAMAL_ENC:
+    return STF_INTERNAL_ERROR;
+  case OAKLEY_RSA_ENC_REV:
+    return STF_INTERNAL_ERROR;
+  case OAKLEY_ELGAMAL_ENC_REV:
+    return STF_INTERNAL_ERROR;
+  default:
+	} /* switch done */
+  } /* HASH_I out, openssl done. */
+}
+else
+{
+#endif /* OPENSSL */
+  /* HASH_I or SIG_I out, !OPENSSL */
+  {
 	u_char hash_val[MAX_DIGEST_LEN];
 	size_t hash_len = main_mode_hash(st, hash_val, TRUE, TRUE);
 
@@ -1996,8 +2649,8 @@
 	{
 	    /* SIG_I out */
 	    u_char sig_val[RSA_MAX_OCTETS];
-	    size_t sig_len = RSA_sign_hash(st->st_connection
-		, sig_val, hash_val, hash_len);
+	    size_t sig_len = RSA_sign_hash(st->st_connection, 
+			sig_val, hash_val, hash_len);
 
 	    if (sig_len == 0)
 	    {
@@ -2009,7 +2662,10 @@
 	    , &md->rbody, sig_val, sig_len, "SIG_I"))
 		return STF_INTERNAL_ERROR;
 	}
-    }
+  }
+#ifdef OPENSSL
+}
+#endif /* OPENSSL */
 
     /* encrypt message, except for fixed part of header */
 
@@ -2019,9 +2675,159 @@
 
     /* Advance state */
     st->st_state = STATE_MAIN_I3;
+    return STF_REPLY;
+}
+
+#ifdef OPENSSL
+/*
+ * Handle HDR;KE;<IDir_b>PubKey_i;<Nr_b>PubKey_i from responder.
+ * Send a HDR*;HASH_I back.
+ */
+stf_status main_inR2_outI3_pk(struct msg_digest *md)
+{
+    struct state *const st = md->st;
+    pb_stream *const keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs;
+
+	DBG(DBG_PARSING,
+	    DBG_log("in main_inR2_outI3_pk");
+	);
+
+    /* KE in */
+    // ACCEPT_KE(st->st_gr, "Gr", st->st_oakley.group, *keyex_pbs);
+	RETURN_STF_FAILURE(accept_KE(&st->st_gr, "Gr", 
+		st->st_oakley.group, keyex_pbs));
+
+    /* IDir in */
+    if (!decode_peer_id(md, TRUE))
+    return STF_FAIL + INVALID_ID_INFORMATION;
+
+    /* Nr in */
+    // ACCEPT_NONCE(st->st_nr, "<Nr_b>PubKey_i");
+    RETURN_STF_FAILURE(accept_nonce(md, &st->st_nr, "<Nr_b>PubKey_i"));
+
+    /* done parsing; initialize crypto  */
+
+    compute_dh_shared(st, st->st_gr, st->st_oakley.group);
+#ifdef DODGE_DH_MISSING_ZERO_BUG
+    if (st->st_shared.ptr[0] == 0)
+    return STF_REPLACE_DOOMED_EXCHANGE;
+#endif
+    if (!generate_skeyids_iv(st))
+    return STF_FAIL + AUTHENTICATION_FAILED;
+
+    /**************** build output packet HDR*;HASH_I ****************/
+
+    /* HDR* out done */
+
+    /* HASH_I out */
+    {
+  u_char hash_val[MAX_DIGEST_LEN];
+  size_t hash_len = main_mode_hash(st, hash_val, TRUE, TRUE);
+
+  // size_t hash_len;
+  // main_mode_hash(st, hash_val, &hash_len, TRUE, TRUE);
+
+  if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_hash_desc, &md->rbody
+  , hash_val, hash_len, "HASH_I"))
+      return STF_INTERNAL_ERROR;
+    }
+
+    /* encrypt message, except for fixed part of header */
+
+    /* st_new_iv was computed by generate_skeyids_iv */
+    if (!encrypt_message(&md->rbody, st))
+    return STF_INTERNAL_ERROR;  /* ??? we may be partly committed */
+
+    /* Advance state */
+    st->st_state = STATE_MAIN_I3;
 
     return STF_REPLY;
 }
+#endif /* OPENSSL */
+
+#ifdef OPENSSL
+/* Handle HDR;KE;<Nr_b>PubKey_i;<KE_b>Ke_r;<IDr1_b>Ke_r from responder.
+ * Send a HDR*;HASH_I back.
+ */
+stf_status
+main_inR2_outI3_rpk(struct msg_digest *md)
+{
+    struct state *const st = md->st;
+    pb_stream *const keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs;
+
+	DBG(DBG_PARSING,
+	    DBG_log("in main_inR2_outI3_rpk");
+	);
+
+    /* Nr in */
+    // ACCEPT_NONCE(st->st_nr, "<Nr_b>PubKey_i");
+    RETURN_STF_FAILURE(accept_nonce(md, &st->st_nr, "<Nr_b>PubKey_i"));
+
+    /* KE in */
+    // ACCEPT_KE(st->st_gr, "Gr", st->st_oakley.group, *keyex_pbs);
+	RETURN_STF_FAILURE(accept_KE(&st->st_gr, "Gr", 
+		st->st_oakley.group, keyex_pbs));
+
+    /* IDir in */
+    if (!decode_peer_id(md, TRUE))
+  return STF_FAIL + INVALID_ID_INFORMATION;
+
+    /* done parsing; initialize crypto  */
+
+    compute_dh_shared(st, st->st_gr, st->st_oakley.group);
+#ifdef DODGE_DH_MISSING_ZERO_BUG
+    if (st->st_shared.ptr[0] == 0)
+  return STF_REPLACE_DOOMED_EXCHANGE;
+#endif
+    if (!generate_skeyids_iv(st))
+  return STF_FAIL + AUTHENTICATION_FAILED;
+
+    /**************** build output packet HDR*;HASH_I ****************/
+
+    /* HDR* out done */
+
+    /* HASH_I out */
+    {
+  u_char hash_val[MAX_DIGEST_LEN];
+
+  // size_t hash_len;
+  // main_mode_hash(st, hash_val, &hash_len, TRUE, TRUE);
+  size_t hash_len = main_mode_hash(st, hash_val, TRUE, TRUE);
+
+  if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_hash_desc, &md->rbody
+  , hash_val, hash_len, "HASH_I"))
+      return STF_INTERNAL_ERROR;
+    }
+
+    /* encrypt message, except for fixed part of header */
+
+    /* st_new_iv was computed by generate_skeyids_iv */
+    if (!encrypt_message(&md->rbody, st))
+    return STF_INTERNAL_ERROR;  /* ??? we may be partly committed */
+
+    /* Advance state */
+    st->st_state = STATE_MAIN_I3;
+
+    return STF_REPLY;
+}
+#endif /* OPENSSL */
+
+
+#ifdef OPENSSL
+/* STATE_MAIN_R2:
+ * Which type of DS are we currently handling?
+ * Classic? OPENSSL?
+ */
+stf_status
+main_inI3_outR3_whichds(struct msg_digest *md)
+{ 
+	if (! use_openssl(md->st->st_connection)) {
+		return main_inI3_outR3(md);
+	} else {
+		return main_inI3_outR3_ds(md);
+	}
+}
+#endif /* OPENSSL */
 
 /* STATE_MAIN_R2:
  * PSK_AUTH: HDR*, IDi1, HASH_I --> HDR*, IDr1, HASH_R
@@ -2030,11 +2836,16 @@
  */
 stf_status
 main_inI3_outR3(struct msg_digest *md)
-{
+{ 
     struct state *const st = md->st;
+
     int auth_payload = st->st_oakley.auth == OAKLEY_PRESHARED_KEY
 	? ISAKMP_NEXT_HASH : ISAKMP_NEXT_SIG;
 
+	DBG(DBG_PARSING,
+	    DBG_log("in main_inI3_outR3");
+	);
+
     /* input code similar to main_inR3 -- should be factored */
 
     /* IDii in */
@@ -2108,6 +2919,496 @@
     return STF_REPLY;
 }
 
+#ifdef OPENSSL
+/*
+ * Handle HDR*;IDii;HASH_I from initiator. Send a HDR*;IDir;HASH_R back.
+ */
+stf_status
+main_inI3_outR3_ds(struct msg_digest *md)
+{
+    struct state *const st = md->st;
+
+    struct connection *c = st->st_connection;
+    u_char hash_val[MAX_DIGEST_LEN], *buf;
+    pb_stream *sig_pbs;
+    unsigned int dlen;
+    struct payload_digest *id_pld;
+    size_t hash_len = main_mode_hash(st, hash_val, TRUE, FALSE);
+    // size_t hash_len;
+    // main_mode_hash(st, hash_val, &hash_len, TRUE, FALSE);
+
+	DBG(DBG_PARSING,
+	    DBG_log("in main_inI3_outR3_ds");
+	);
+    /* input code similar to main_inR3 -- should be factored */
+
+    /* IDii in */
+    if (!decode_peer_id(md, FALSE))
+    return STF_FAIL + INVALID_ID_INFORMATION;
+
+    switch (st->st_oakley.auth) {
+    case OAKLEY_RSA_SIG: /* check SIG_I */
+      {
+  RSA *rsa;
+  STACK_OF(X509) *peerlist;
+  X509 *recv_cert, *cert;
+  pb_stream *cert_pbs;
+  int i, success;
+
+  recv_cert = NULL;
+  /* First check to see if we have a certificate sent to us */
+  if ((md->chain[ISAKMP_NEXT_CERT] != NULL) &&
+      ((cert_pbs = &md->chain[ISAKMP_NEXT_CERT]->pbs) != NULL)) {
+    u_char *crt;
+    unsigned long len;
+
+    switch(cert_pbs->cur[0]) {
+    case CERT_TYPE_X509_SIG:
+      crt = &(cert_pbs->cur[1]);
+      len = pbs_left(cert_pbs)-1;
+      recv_cert = d2i_X509(NULL, &crt, len);
+      break;
+    default:
+		DBG(DBG_PARSING,
+			DBG_log("Unhandled certificate encoding: %s",
+				enum_show(&cert_names, cert_pbs->cur[0]));
+		);
+      break;
+    }
+  }
+
+  if (recv_cert) {
+    char buf[200];
+
+    X509_NAME_oneline(X509_get_subject_name(recv_cert)
+              , buf, sizeof(buf));
+	DBG(DBG_PARSING,
+	    DBG_log("Received certificate \"%s\"", buf);
+	);
+  }
+
+  /* We know this field is legitimate, because the */
+  /* decode_peer_id has been called before */
+  id_pld = md->chain[ISAKMP_NEXT_ID];
+
+  if ((peerlist = peer_cert_list((STACK_OF(XMAP) *)(c->lu),
+                     EVP_PKEY_RSA,
+                     recv_cert,
+                     id_pld,
+                     (c->cert_options & CERT_OPTION_STRICT)
+                     ? TRUE : FALSE)) == NULL) {
+    log("Verification certificate(s) unavailable to check signature in Main R3");
+    return STF_FAIL + INVALID_SIGNATURE;
+  }
+
+  if (sk_X509_num(peerlist) == 0) {
+    log("Unable to get any certificate for peer in Main R3");
+    return STF_FAIL + INVALID_SIGNATURE;
+  }
+
+  if ((md->chain[ISAKMP_NEXT_SIG] == NULL) ||
+      ((sig_pbs = &md->chain[ISAKMP_NEXT_SIG]->pbs) == NULL)) {
+    log("Signature not present in Main R3");
+    return STF_FAIL + INVALID_SIGNATURE;
+  }
+  DBG(DBG_PARSING,
+	  DBG_dump("Computed hash", hash_val, hash_len);
+  );
+  /* Iterate through all certificates in the peer list until */
+  /* we have one which verifies the signature, or we have no */
+  /* more certificates to verify with */
+  for (i=0, success = 0; (success == 0) && (i<sk_X509_num(peerlist)); i++) {
+    X509 *xx = sk_X509_value(peerlist, i);
+
+    rsa = X509_get_pubkey(xx)->pkey.rsa;
+    if ((buf = alloc_bytes(EVP_PKEY_size(X509_get_pubkey(xx)),
+               "RSA decrypt sig")) != NULL) {
+      dlen = RSA_public_decrypt(pbs_left(sig_pbs), sig_pbs->cur, buf,
+                    rsa, RSA_PKCS1_PADDING);
+		DBG(DBG_PARSING,
+			DBG_dump("Decrypted hash", buf, (dlen > hash_len) 
+				? hash_len : dlen);
+		);
+      if ((dlen == hash_len) && (memcmp(buf, hash_val, hash_len) == 0)) {
+		DBG(DBG_PARSING,
+	        DBG_log("SIG_I matches computed hash");
+		);
+        success = 1;
+        cert = X509_dup(xx);
+      } else {
+		DBG(DBG_PARSING,
+	        DBG_log("SIG_I does not computed hash");
+		);
+      }
+      pfree(buf);
+    }
+  }
+  if (!success) {
+    log_err();
+    DBG_cond_dump(DBG_CRYPT, "received SIG_I does not match computed value in Main I3:"
+          , sig_pbs->cur, pbs_left(sig_pbs));
+    sk_X509_pop_free(peerlist, X509_free);
+    return STF_FAIL + INVALID_SIGNATURE;
+  } else {
+    /* We know that certificate 'cert' was used to */
+    /* sign the accurate hash which accompanied the method */
+    /* Now we have to verify that it is a valid certificate */
+    /* to be signing anything */
+	DBG(DBG_PARSING,
+	    DBG_log("Verifying certificate along path %s", c->path);
+	);
+    if (verify_certificate( cert, c->lu, c->path, (c->cert_options & CERT_OPTION_STRICT) ? TRUE : FALSE ))
+	{
+		DBG(DBG_PARSING,
+			DBG_log("Signing certificate is valid");
+		);
+	}
+    else {
+      sk_X509_pop_free(peerlist, X509_free);
+      return STF_FAIL + INVALID_CERTIFICATE;
+    }
+  }
+  sk_X509_pop_free(peerlist, X509_free);
+      }
+      break;
+    case OAKLEY_DSS_SIG:
+      {
+  DSA *dsa;
+  STACK_OF(X509) *peerlist;
+  X509 *recv_cert, *cert;
+  pb_stream *cert_pbs;
+  int i, success;
+
+  if (c->cert_options & CERT_OPTION_DSS_SHA)
+    main_mode_sha1(st, hash_val, &hash_len, TRUE, FALSE);
+  recv_cert = NULL;
+  /* First check to see if we have a certificate sent to us */
+  if ((md->chain[ISAKMP_NEXT_CERT] != NULL) &&
+      ((cert_pbs = &md->chain[ISAKMP_NEXT_CERT]->pbs) != NULL)) {
+    u_char *crt;
+    unsigned long len;
+
+    switch(cert_pbs->cur[0]) {
+    case CERT_TYPE_X509_SIG:
+      crt = &(cert_pbs->cur[1]);
+      len = pbs_left(cert_pbs)-1;
+      recv_cert = d2i_X509(NULL, &crt, len);
+      break;
+    default:
+		DBG(DBG_PARSING,
+			DBG_log("Unhandled certificate encoding: %s",
+				enum_show(&cert_names, cert_pbs->cur[0]));
+		);
+      break;
+    }
+  }
+
+  if (recv_cert) {
+    char buf[200];
+
+    X509_NAME_oneline(X509_get_subject_name(recv_cert)
+              , buf, sizeof(buf));
+	DBG(DBG_PARSING,
+	    DBG_log("Received certificate \"%s\"", buf);
+	);
+  }
+
+  /* We know this field is legitimate, because the */
+  /* decode_peer_id has been called before */
+  id_pld = md->chain[ISAKMP_NEXT_ID];
+
+  if ((peerlist =
+       peer_cert_list((STACK_OF(XMAP) *)(c->lu), EVP_PKEY_DSA,
+              recv_cert, id_pld,
+              (c->cert_options & CERT_OPTION_STRICT) ? TRUE : FALSE)) == NULL) {
+    log("Verification certificate(s) unavailable to check signature in Main R3");
+    return STF_FAIL + INVALID_SIGNATURE;
+  }
+
+  if (sk_X509_num(peerlist) == 0) {
+    log("Unable to get any certificate for peer in Main R3");
+    return STF_FAIL + INVALID_SIGNATURE;
+  }
+
+  if ((md->chain[ISAKMP_NEXT_SIG] == NULL) ||
+      ((sig_pbs = &md->chain[ISAKMP_NEXT_SIG]->pbs) == NULL)) {
+    log("Signature not present in Main R3");
+    return STF_FAIL + INVALID_SIGNATURE;
+  }
+
+  DBG(DBG_PARSING,
+		DBG_dump("Computed hash", hash_val, hash_len);
+  );
+  /* Iterate through all certificates in the peer list until */
+  /* we have one which verifies the signature, or we have no */
+  /* more certificates to verify with */
+  for(i=0, success=0, buf = NULL;
+      ((success == 0) && (i < sk_X509_num(peerlist))); i++) {
+    dsa = X509_get_pubkey(sk_X509_value(peerlist, i))->pkey.dsa;
+    if ((buf = alloc_bytes(SHA1_DIGEST_SIZE, "DSA sig space")) != NULL) {
+      success = (c->cert_options & CERT_OPTION_DSS_ALT)
+        ? DSA_verify_raw(hash_val, hash_len,
+                 sig_pbs->cur, pbs_left(sig_pbs),
+                 dsa)
+        : DSA_verify(EVP_PKEY_DSA,
+             hash_val, hash_len,
+             sig_pbs->cur, pbs_left(sig_pbs),
+             dsa)
+        ;
+      if (success == 1) {
+		DBG(DBG_PARSING,
+	        DBG_log("SIG_I matches computed hash");
+		);
+        cert = X509_dup(sk_X509_value(peerlist, i));
+      } else if (success == 0) {
+		DBG(DBG_PARSING,
+        	DBG_log("SIG_I does not computed hash");
+		);
+      } else {
+		DBG(DBG_PARSING,
+        	DBG_log("Verification error");
+		);
+        log_err();
+      }
+      pfree(buf);
+      buf = NULL;
+    }
+  }
+  if (buf) pfree(buf);
+  if (!success) {
+    log_err();
+    DBG_cond_dump(DBG_CRYPT, "received SIG_I does not match computed value in Main I3:"
+          , sig_pbs->cur, pbs_left(sig_pbs));
+    sk_X509_pop_free(peerlist, X509_free);
+    return STF_FAIL + INVALID_SIGNATURE;
+  } else {
+    /* We know that certificate 'cert' was used to */
+    /* sign the accurate hash which accompanied the method */
+    /* Now we have to verify that it is a valid certificate */
+    /* to be signing anything */
+	DBG(DBG_PARSING,
+    	DBG_log("Verifying certificate along path %s", c->path);
+	);
+    if (verify_certificate( cert, c->lu, c->path, (c->cert_options & CERT_OPTION_STRICT) ? TRUE : FALSE ))
+	{
+		DBG(DBG_PARSING,
+			DBG_log("Signing certificate is valid");
+		);
+	}
+    else {
+      sk_X509_pop_free(peerlist, X509_free);
+      return STF_FAIL + INVALID_CERTIFICATE;
+    }
+  }
+  sk_X509_pop_free(peerlist, X509_free);
+      }
+      break;
+      /* Should never get here */
+    default:
+      return STF_INTERNAL_ERROR;
+    }
+
+    /************* build output packet HDR*;IDir;[CERT];SIG_R ******/
+    /* ??? NOTE: this is almost the same as main_inR2_outI3's code */
+
+    /* IDir out */
+    {
+  struct isakmp_ipsec_id r_id;
+  pb_stream r_id_pbs;
+  chunk_t r_id_chunk;
+
+  // r_id.isaiid_idtype = st->st_myidentity_type;
+  r_id.isaiid_idtype = st->st_connection->this.id.kind;
+  r_id.isaiid_protoid = 0;    /* ??? is this right? */
+  r_id.isaiid_port = 0;   /* ??? is this right? */
+
+  build_id_payload(&r_id, &r_id_chunk, &st->st_connection->this);
+
+  if ((c->cert_options & CERT_OPTION_SEND) == 0)
+    r_id.isaiid_np = ISAKMP_NEXT_SIG;
+  else
+    r_id.isaiid_np = ISAKMP_NEXT_CERT;
+
+  if (!out_struct(&r_id, &isakmp_ipsec_identification_desc, &md->rbody, &r_id_pbs)
+  || !out_chunk(r_id_chunk, &r_id_pbs, "my identity"))
+      return STF_INTERNAL_ERROR;
+  close_output_pbs(&r_id_pbs);
+
+// ########################
+//  // if a permanent cast is needed, we'll need to rethink this.
+//  //// r_id_chunk.len = sizeof(st->st_connection->this.id);
+//  //// memcpy(&(r_id_chunk.ptr), &(st->st_connection->this.id), r_id_chunk.len);
+//  r_id_chunk.len = sizeof(st->st_connection->this.id.ip_addr);
+//  memcpy(&(r_id_chunk.ptr), &(st->st_connection->this.id.ip_addr), r_id_chunk.len);
+//  
+//  if (!out_struct(&r_id, &isakmp_ipsec_identification_desc,
+//          &md->rbody, &r_id_pbs)
+//      || !out_chunk(r_id_chunk, &r_id_pbs, "my identity"))
+//      // || !out_chunk(st->st_myidentity, &r_id_pbs, "my identity"))
+//    return STF_INTERNAL_ERROR;
+//  close_output_pbs(&r_id_pbs);
+// ########################
+    }
+
+    if ((c->cert_options & CERT_OPTION_SEND) != 0) {
+      /* Send the signing certificate */
+      u_char *crt, *cx;
+      unsigned long ulen;
+      /* Send the signing certificate */
+    
+      ulen = i2d_X509(c->cert, NULL);
+      ulen++;
+      if ((cx = alloc_bytes(ulen, "ASN.1 cert")) == NULL)
+  { return STF_INTERNAL_ERROR; }
+      cx[0] = (u_char)(CERT_TYPE_X509_SIG);
+      crt = &(cx[1]);
+      i2d_X509(c->cert, &crt);
+      if (!out_generic_raw(ISAKMP_NEXT_SIG, &isakmp_ipsec_certificate_desc
+             , &md->rbody, cx, ulen, "CERT_R"))
+  return STF_INTERNAL_ERROR;
+      pfree(cx);
+    }
+
+    /* SIG_R out */
+    {
+  u_char hash_val[MAX_DIGEST_LEN];
+  u_int elen;
+  bool ok;
+
+  // size_t hash_len;
+  // main_mode_hash(st, hash_val, &hash_len, FALSE, TRUE);
+  size_t hash_len = main_mode_hash(st, hash_val, FALSE, TRUE);
+
+  /* Output the signature/hash as defined by the selected Oakley transform */
+  switch (st->st_oakley.auth) {
+  case OAKLEY_RSA_SIG: /* output signed HASH_R */
+    if ((buf = alloc_bytes(EVP_PKEY_size(c->key) + 32 /* bit of slack */,
+               "RSA sig")) == NULL)
+      return STF_INTERNAL_ERROR;
+    elen = RSA_private_encrypt(hash_len, hash_val, buf,
+                   ((EVP_PKEY *)(c->key))->pkey.rsa,
+                   RSA_PKCS1_PADDING);
+    if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_signature_desc,
+                 &md->rbody, buf, elen, "SIG_R"))
+      return STF_INTERNAL_ERROR;
+    break;
+  case OAKLEY_DSS_SIG:
+    if (c->cert_options & CERT_OPTION_DSS_SHA)
+      main_mode_sha1(st, hash_val, &hash_len, FALSE, TRUE);
+
+    if ((buf = alloc_bytes(EVP_PKEY_size(c->key) + 32 /* bit of slack */,
+              "DSA sig")) == NULL)
+      return STF_INTERNAL_ERROR;
+    ok = (c->cert_options & CERT_OPTION_DSS_ALT)
+      ? DSA_sign_raw(hash_val, hash_len,
+             buf, &elen,
+             ((EVP_PKEY *)(c->key))->pkey.dsa)
+      : DSA_sign(EVP_PKEY_DSA, hash_val, hash_len,
+             buf, &elen,
+             ((EVP_PKEY *)(c->key))->pkey.dsa);
+    if (!ok) {
+      log_err();
+      return STF_INTERNAL_ERROR;
+    }
+    if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_signature_desc,
+                 &md->rbody, buf, elen, "SIG_I"))
+      return STF_INTERNAL_ERROR;
+   
+	DBG(DBG_PARSING,
+	    DBG_log("Selected auth mechanism is %s",
+			enum_show(&oakley_auth_names, st->st_oakley.auth));
+	);
+    break;
+  default:
+    return STF_INTERNAL_ERROR;
+  }
+  pfree(buf);
+    }
+
+    /* encrypt message, sans fixed part of header */
+
+    if (!encrypt_message(&md->rbody, st))
+  return STF_INTERNAL_ERROR;  /* ??? we may be partly committed */
+
+    /* Last block of Phase 1 (R3), kept for Phase 2 IV generation */
+    DBG_cond_dump(DBG_CRYPT, "last encrypted block of Phase 1:"
+  , st->st_new_iv, st->st_new_iv_len);
+
+    /* Advance state */
+    st->st_state = STATE_MAIN_R3;
+    st->st_connection->newest_isakmp_sa = st->st_serialno;
+
+    return STF_REPLY;
+}
+#endif /* OPENSSL */
+
+#ifdef OPENSSL
+/*
+ * Handle HDR*;HASH_I from initiator. Send a HDR*;HASH_R back.
+ */
+stf_status
+main_inI3_outR3_pk(struct msg_digest *md)
+{
+    struct state *const st = md->st;
+
+    /* input code similar to main_inR3 -- should be factored */
+
+	DBG(DBG_PARSING,
+	    DBG_log("in main_inI3_outR3_pk");
+	);
+
+    /* HASH_I in */
+    // CHECK_HASH(main_mode_hash(st, hash_val, &hash_len, TRUE, FALSE)
+  	// , "HASH_I", "Main I3");
+	RETURN_STF_FAILURE(check_main_authenticator(md, TRUE));
+
+    /**************** build output packet HDR*;HASH_R ****************/
+
+    /* HASH_R out */
+    {
+  u_char hash_val[MAX_DIGEST_LEN];
+  
+  // size_t hash_len;
+  // main_mode_hash(st, hash_val, &hash_len, FALSE, TRUE);
+  size_t hash_len = main_mode_hash(st, hash_val, FALSE, TRUE);
+
+  if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_hash_desc, &md->rbody
+  , hash_val, hash_len, "HASH_R"))
+      return STF_INTERNAL_ERROR;
+    }
+   
+    /* encrypt message, sans fixed part of header */
+    if (!encrypt_message(&md->rbody, st))
+  return STF_INTERNAL_ERROR;  /* ??? we may be partly committed */
+
+    /* Last block of Phase 1 (R3), kept for Phase 2 IV generation */
+    DBG_cond_dump(DBG_CRYPT, "last encrypted block of Phase 1:"
+  , st->st_new_iv, st->st_new_iv_len);
+
+    /* Advance state */
+    st->st_state = STATE_MAIN_R3;
+    st->st_connection->newest_isakmp_sa = st->st_serialno;
+
+    return STF_REPLY;
+}
+#endif
+
+#ifdef OPENSSL
+/* STATE_MAIN_I3:
+ * Handle HDR*;IDir;HASH/SIG_R from responder.
+ */
+stf_status
+main_inR3_whichds(struct msg_digest *md)
+{
+	if (!use_openssl(md->st->st_connection)) {
+		return main_inR3(md);
+	} else {
+		return main_inR3_ds(md);
+	}
+}
+#endif /* OPENSSL */
+
+
 /* STATE_MAIN_I3:
  * Handle HDR*;IDir;HASH/SIG_R from responder.
  */
@@ -2117,6 +3418,9 @@
     struct state *const st = md->st;
     struct connection *c = st->st_connection;
 
+	DBG(DBG_PARSING,
+		DBG_log("in main_inR3");
+	);
     /* input code similar to main_inI3_outR3 -- should be factored */
 
     /* IDir in */
@@ -2136,6 +3440,332 @@
 
     return STF_UNPEND_QUICK;
 }
+
+#ifdef OPENSSL
+/* Handle HDR*;IDir;[CERT];SIG_R from responder.
+ */
+stf_status
+main_inR3_ds(struct msg_digest *md)
+{
+    struct state *const st = md->st;
+    struct connection *c = st->st_connection;
+    u_char hash_val[MAX_DIGEST_LEN], *buf;
+    pb_stream *sig_pbs;
+    unsigned int dlen;
+    struct payload_digest *id_pld;
+    size_t hash_len = main_mode_hash(st, hash_val, FALSE, FALSE);
+    // size_t hash_len;
+    // main_mode_hash(st, hash_val, &hash_len, FALSE, FALSE);
+
+    /* input code similar to main_inI3_outR3 -- should be factored */
+ 
+	DBG(DBG_PARSING,
+		DBG_log("in main_inR3_ds");
+	);
+    /* IDir in */
+    if (!decode_peer_id(md, TRUE))
+	return STF_FAIL + INVALID_ID_INFORMATION;
+
+    switch (st->st_oakley.auth) {
+    case OAKLEY_RSA_SIG: /* check SIG_I */
+      {
+	RSA *rsa;
+	STACK_OF(X509) *peerlist;
+	X509 *recv_cert, *cert;
+	pb_stream *cert_pbs;
+	int i, success;
+	
+	recv_cert = NULL;
+	/* First check to see if we have a certificate sent to us */
+	if ((md->chain[ISAKMP_NEXT_CERT] != NULL) &&
+	    ((cert_pbs = &md->chain[ISAKMP_NEXT_CERT]->pbs) != NULL)) {
+	  u_char *crt;
+	  unsigned long len;
+
+	  switch(cert_pbs->cur[0]) {
+	  case CERT_TYPE_X509_SIG:
+	    crt = &(cert_pbs->cur[1]);
+	    len = pbs_left(cert_pbs)-1;
+	    recv_cert = d2i_X509(NULL, &crt, len);
+	    break;
+	  default:
+		DBG(DBG_PARSING,
+			DBG_log("Unhandled certificate encoding: %s",
+			enum_show(&cert_names, cert_pbs->cur[0]));
+		);
+	    break;
+	  }
+	}
+
+	if (recv_cert) {
+	  char buf[200];
+
+	  X509_NAME_oneline(X509_get_subject_name(recv_cert)
+			    , buf, sizeof(buf));
+		DBG(DBG_PARSING,
+			DBG_log("Sent certificate \"%s\"", buf);
+		);
+	}
+
+	id_pld = md->chain[ISAKMP_NEXT_ID];
+	if ((peerlist =
+	     peer_cert_list((STACK_OF(XMAP) *)c->lu,
+			    EVP_PKEY_RSA, recv_cert, id_pld,
+			    (c->cert_options & CERT_OPTION_STRICT) ? TRUE : FALSE)) == NULL) {
+	  log("Verification certificate(s) unavailable to check signature in Main R3");
+	  return STF_FAIL + INVALID_SIGNATURE;
+	}
+
+	if (sk_X509_num(peerlist) == 0) {
+	  log("Unable to get any certificate for peer in Main R3");
+	  return STF_FAIL + INVALID_SIGNATURE;
+	}
+
+	if ((md->chain[ISAKMP_NEXT_SIG] == NULL) ||
+		((sig_pbs = &md->chain[ISAKMP_NEXT_SIG]->pbs) == NULL)) {
+	  log("Signature not present in Main R3");
+	  return STF_FAIL + INVALID_SIGNATURE;
+	}
+	DBG(DBG_PARSING,
+		DBG_dump("Computed hash", hash_val, hash_len);
+	);
+	/* Iterate through all certificates in the peer list until */
+	/* we have one which verifies the signature, or we have no */
+	/* more certificates to verify with */
+	for(i=0, success=0, buf = NULL; ((success == 0) && (i < sk_X509_num(peerlist))); i++) {
+	  rsa = X509_get_pubkey(sk_X509_value(peerlist, i))->pkey.rsa;
+	  if ((buf = alloc_bytes(EVP_PKEY_size(X509_get_pubkey(sk_X509_value(peerlist, i))),
+				 "RSA decrypt sig")) != NULL) {
+	    dlen = RSA_public_decrypt(pbs_left(sig_pbs), sig_pbs->cur, buf, rsa
+				      , RSA_PKCS1_PADDING);
+		DBG(DBG_PARSING,
+			DBG_dump("Decrypted hash", buf, (dlen > hash_len) 
+				? hash_len : dlen);
+		);
+	    if ((dlen == hash_len) && (memcmp(buf, hash_val, hash_len) == 0)) {
+			DBG(DBG_PARSING,
+				DBG_log("SIG_R matches computed hash");
+			)
+	      success = 1;
+	      cert = X509_dup(sk_X509_value(peerlist, i));
+	    } else {
+			DBG(DBG_PARSING,
+				DBG_log("SIG_R does not match computed hash");
+			);
+	    }
+	    pfree(buf);
+	    buf = NULL;
+	  }
+	}
+	if (buf) pfree(buf);
+
+	if (!success) {
+	  log_err();
+	  DBG_cond_dump(DBG_CRYPT,
+			"received SIG_R does not match computed value in Main R3:"
+			, sig_pbs->cur, pbs_left(sig_pbs));
+	  sk_X509_pop_free(peerlist, X509_free);
+	  return STF_FAIL + INVALID_SIGNATURE;
+	} else {
+	  /* We know that certificate 'cert' was used to */
+	  /* sign the accurate hash which accompanied the method */
+	  /* Now we have to verify that it is a valid certificate */
+	  /* to be signing anything */
+		DBG(DBG_PARSING,
+			DBG_log("Verifying certificate along path %s", c->path);
+		);
+		if (verify_certificate( cert, c->lu, c->path, 
+			(c->cert_options & CERT_OPTION_STRICT) ? TRUE : FALSE ))
+		{
+			DBG(DBG_PARSING,
+				DBG_log("Signing certificate is valid");
+			);
+		} else {
+			sk_X509_pop_free(peerlist, X509_free);
+			return STF_FAIL + INVALID_CERTIFICATE;
+		}
+	}
+	sk_X509_pop_free(peerlist, X509_free);
+      }
+      break;
+    case OAKLEY_DSS_SIG:
+      {
+	DSA *dsa;
+	STACK_OF(X509) *peerlist;
+	X509 *recv_cert, *cert;
+	pb_stream *cert_pbs;
+	int i, success;
+
+	if (c->cert_options & CERT_OPTION_DSS_SHA)
+	  main_mode_sha1(st, hash_val, &hash_len, FALSE, FALSE);
+	recv_cert = NULL;
+	/* First check to see if we have a certificate sent to us */
+	if ((md->chain[ISAKMP_NEXT_CERT] != NULL) &&
+	    ((cert_pbs = &md->chain[ISAKMP_NEXT_CERT]->pbs) != NULL)) {
+	  u_char *crt;
+	  unsigned long len;
+
+	  switch(cert_pbs->cur[0]) {
+	  case CERT_TYPE_X509_SIG:
+	    crt = &(cert_pbs->cur[1]);
+	    len = pbs_left(cert_pbs)-1;
+	    recv_cert = d2i_X509(NULL, &crt, len);
+	    break;
+	  default:
+		DBG(DBG_PARSING,
+		    DBG_log("Unhandled certificate encoding: %s",
+			    enum_show(&cert_names, cert_pbs->cur[0]));
+		);
+	    break;
+	  }
+	}
+
+	if (recv_cert) {
+	  char buf[200];
+
+	  X509_NAME_oneline(X509_get_subject_name(recv_cert)
+			    , buf, sizeof(buf));
+		DBG(DBG_PARSING,
+			DBG_log("Sent certificate \"%s\"", buf);
+		);
+	}
+
+	/* We know this field is legitimate, because the */
+	/* decode_peer_id has been called before */
+	id_pld = md->chain[ISAKMP_NEXT_ID];
+
+	if ((peerlist =
+	     peer_cert_list((STACK_OF(XMAP) *)c->lu,
+			    EVP_PKEY_DSA, recv_cert,
+			    id_pld,
+			    (c->cert_options & CERT_OPTION_STRICT) ? TRUE : FALSE )) == NULL) {
+	  log("Verification certificate(s) unavailable to check signature in Main R3");
+	  return STF_FAIL + INVALID_SIGNATURE;
+	}
+
+	if (sk_X509_num(peerlist) == 0) {
+	  log("Unable to get any certificate for peer in Main R3");
+	  return STF_FAIL + INVALID_SIGNATURE;
+	}
+
+	if ((md->chain[ISAKMP_NEXT_SIG] == NULL) ||
+	    ((sig_pbs = &md->chain[ISAKMP_NEXT_SIG]->pbs) == NULL)) {
+	  log("Signature not present in Main R3");
+	  return STF_FAIL + INVALID_SIGNATURE;
+	}
+	DBG(DBG_PARSING,
+		DBG_dump("Computed hash", hash_val, hash_len);
+	);
+	/* Iterate through all certificates in the peer list until */
+	/* we have one which verifies the signature, or we have no */
+	/* more certificates to verify with */
+	for(i=0, success=0, buf=NULL; ((success == 0) && (i < sk_X509_num(peerlist))); i++) {
+	  dsa = X509_get_pubkey(sk_X509_value(peerlist, i))->pkey.dsa;
+	  if ((buf = alloc_bytes(SHA1_DIGEST_SIZE, "DSA decrypt sig")) != NULL) {
+	    success = (c->cert_options & CERT_OPTION_DSS_ALT)
+	      ? DSA_verify_raw(hash_val, hash_len,
+			       sig_pbs->cur, pbs_left(sig_pbs),
+			       dsa)
+	      : DSA_verify(EVP_PKEY_DSA,
+			   hash_val, hash_len,
+			   sig_pbs->cur, pbs_left(sig_pbs),
+			   dsa);
+	    if (success == 1) {
+			DBG(DBG_PARSING,
+				DBG_log("SIG_I matches computed hash");
+			);
+	      cert = X509_dup(sk_X509_value(peerlist, i));;
+	    } else if (success == 0) {
+			DBG(DBG_PARSING,
+				DBG_log("SIG_I does not match computed hash");
+			);
+	    } else {
+			DBG(DBG_PARSING,
+		      DBG_log("Verification error");
+			);
+	      log_err();
+	    }
+	    pfree(buf);
+	    buf = NULL;
+	  }
+	}
+	if (buf) pfree(buf);
+	if (!success) {
+	  log_err();
+	  DBG_cond_dump(DBG_CRYPT, "received SIG_I does not match computed value in Main I3:"
+			, sig_pbs->cur, pbs_left(sig_pbs));
+	  sk_X509_pop_free(peerlist, X509_free);
+	  return STF_FAIL + INVALID_SIGNATURE;
+	} else {
+	  /* We know that certificate 'cert' was used to */
+	  /* sign the accurate hash which accompanied the method */
+	  /* Now we have to verify that it is a valid certificate */
+	  /* to be signing anything */
+		DBG(DBG_PARSING,
+			DBG_log("Verifying certificate along path %s", c->path);
+		);
+	  if (verify_certificate( cert, c->lu, c->path, (c->cert_options & CERT_OPTION_STRICT) ? TRUE : FALSE ))
+		{
+			DBG(DBG_PARSING,
+				DBG_log("Signing certificate is valid");
+			);
+		}
+	  else {
+	    sk_X509_pop_free(peerlist, X509_free);
+	    return STF_FAIL + INVALID_CERTIFICATE;
+	  }
+	}
+	sk_X509_pop_free(peerlist, X509_free);
+      }
+      break;
+    default:
+      return STF_INTERNAL_ERROR;
+      break;
+    }
+
+    /**************** done input ****************/
+
+    /* Advance state */
+    st->st_state = STATE_MAIN_I4;
+    c->newest_isakmp_sa = st->st_serialno;
+
+    update_iv(st);	/* finalize our Phase 1 IV */
+
+    return STF_UNPEND_QUICK;
+}
+#endif
+
+#ifdef OPENSSL
+/* Handle HDR*;HASH_R from responder.
+ */
+stf_status
+main_inR3_pk(struct msg_digest *md)
+{
+    struct state *const st = md->st;
+    struct connection *c = st->st_connection;
+
+    /* input code similar to main_inI3_outR3 -- should be factored */
+
+	DBG(DBG_PARSING,
+	    DBG_log("in main_inR3_pk");
+	);
+
+    /* HASH_R in */
+    // CHECK_HASH(main_mode_hash(st, hash_val, &hash_len, FALSE, FALSE)
+	// , "HASH_R", "Main R3");
+	RETURN_STF_FAILURE(check_main_authenticator(md, FALSE));
+
+    /**************** done input ****************/
+
+    /* Advance state */
+    st->st_state = STATE_MAIN_I4;
+    c->newest_isakmp_sa = st->st_serialno;
+
+    update_iv(st);	/* finalize our Phase 1 IV */
+
+    return STF_UNPEND_QUICK;
+}
+#endif
 
 /* Handle first message of Phase 2 -- Quick Mode.
  * HDR*, HASH(1), SA, Ni [, KE ] [, IDci, IDcr ] -->
diff -ruN freeswan-1.5.orig/pluto/ipsec_doi.h freeswan-1.5/pluto/ipsec_doi.h
--- freeswan-1.5.orig/pluto/ipsec_doi.h	Tue Jun 20 22:27:28 2000
+++ freeswan-1.5/pluto/ipsec_doi.h	Thu Oct  5 07:05:59 2000
@@ -28,9 +28,27 @@
     main_inI1_outR1,
     main_inR1_outI2,
     main_inI2_outR2,
+#ifdef OPENSSL
+    main_inI2_outR2_pk,
+    main_inI2_outR2_rpk,
+#endif
     main_inR2_outI3,
+#ifdef OPENSSL
+    main_inR2_outI3_pk,
+    main_inR2_outI3_rpk,
+#endif
     main_inI3_outR3,
+#ifdef OPENSSL
+    main_inI3_outR3_whichds,
+    main_inI3_outR3_ds,
+    main_inI3_outR3_pk,
+#endif
     main_inR3,
+#ifdef OPENSSL
+    main_inR3_whichds,
+    main_inR3_ds,
+    main_inR3_pk,
+#endif
     quick_inI1_outR1,
     quick_inR1_outI2,
     quick_inI2;
diff -ruN freeswan-1.5.orig/pluto/main.c freeswan-1.5/pluto/main.c
--- freeswan-1.5.orig/pluto/main.c	Fri Jan 21 21:51:17 2000
+++ freeswan-1.5/pluto/main.c	Thu Oct  5 07:05:59 2000
@@ -29,6 +29,11 @@
 
 #include <freeswan.h>
 
+#ifdef OPENSSL
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#endif
+
 #include "constants.h"
 #include "defs.h"
 #include "id.h"
@@ -42,6 +47,20 @@
 #include "rnd.h"
 #include "state.h"
 
+#ifdef OPENSSL
+#include "openssl.h"
+#include "xmap_dir.h"
+#include "xmap_file.h"
+#ifdef HAVE_DB
+#include "xmap_db.h"
+#endif
+#ifdef HAVE_LDAP
+#include "xmap_ldap.h"
+#endif
+#include "xmap.h"
+
+#endif /* OPENSSL */
+
 #include "sha1.h"
 #include "md5.h"
 #include "crypto.h"	/* requires sha1.h and md5.h */
@@ -156,6 +175,21 @@
     bool log_to_stderr_desired = FALSE;
     int lockfd;
 
+#ifdef OPENSSL
+    SSLeay_add_all_algorithms();
+    X509V3_add_standard_extensions();
+    ERR_load_crypto_strings();
+    ERR_load_ElGamal_strings();
+    XMAP_register(XMAP_METHOD_file());
+    XMAP_register(XMAP_METHOD_dir());
+#ifdef HAVE_DB
+    XMAP_register(XMAP_METHOD_db());
+#endif /* HAVE_DB */
+#ifdef HAVE_LDAP
+    XMAP_register(XMAP_METHOD_ldap());
+#endif /* HAVE_LDAP */
+#endif
+
     /* handle arguments */
     for (;;)
     {
@@ -409,6 +443,10 @@
 #ifdef LEAK_DETECTIVE
     report_leaks();
 #endif /* LEAK_DETECTIVE */
+#ifdef OPENSSL
+    X509V3_EXT_cleanup();
+    ERR_free_strings();
+#endif
     close_log();
     exit(status);
 }
diff -ruN freeswan-1.5.orig/pluto/md5.c freeswan-1.5/pluto/md5.c
--- freeswan-1.5.orig/pluto/md5.c	Sat Dec 11 20:31:36 1999
+++ freeswan-1.5/pluto/md5.c	Thu Oct  5 07:05:59 2000
@@ -139,7 +139,11 @@
 /* MD5 initialization. Begins an MD5 operation, writing a new context.
  */
 void MD5Init (context)
+#ifndef OPENSSL
 MD5_CTX *context;                                        /* context */
+#else
+PLUTO_MD5_CTX *context;                                  /* context */
+#endif
 {
   context->count[0] = context->count[1] = 0;
   /* Load magic initialization constants.
@@ -155,7 +159,11 @@
   context.
  */
 void MD5Update (context, input, inputLen)
+#ifndef OPENSSL
 MD5_CTX *context;                                        /* context */
+#else
+PLUTO_MD5_CTX *context;                                  /* context */
+#endif
 unsigned char *input;                                /* input block */
 UINT4 inputLen;                            /* length of input block */
 {
@@ -194,7 +202,11 @@
  */
 void MD5Final (digest, context)
 unsigned char digest[16];                         /* message digest */
-MD5_CTX *context;                                       /* context */
+#ifndef OPENSSL
+MD5_CTX *context;                                 /* context */
+#else
+PLUTO_MD5_CTX *context;
+#endif /* OPENSSL */
 {
   unsigned char bits[8];
   unsigned int index, padLen;
diff -ruN freeswan-1.5.orig/pluto/md5.h freeswan-1.5/pluto/md5.h
--- freeswan-1.5.orig/pluto/md5.h	Sat Dec 11 20:31:36 1999
+++ freeswan-1.5/pluto/md5.h	Thu Oct  5 07:05:59 2000
@@ -61,11 +61,22 @@
   UINT4 state[4];                                   /* state (ABCD) */
   UINT4 count[2];        /* number of bits, modulo 2^64 (lsb first) */
   unsigned char buffer[64];                         /* input buffer */
+#ifndef OPENSSL
 } MD5_CTX;
+#else
+} PLUTO_MD5_CTX;
+#endif /* OPENSSL */
 
+#ifndef OPENSSL
 void MD5Init PROTO_LIST ((MD5_CTX *));
 void MD5Update PROTO_LIST
   ((MD5_CTX *, unsigned char *, UINT4));
 void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
+#else
+void MD5Init PROTO_LIST ((PLUTO_MD5_CTX *));
+void MD5Update PROTO_LIST
+  ((PLUTO_MD5_CTX *, unsigned char *, unsigned int));
+void MD5Final PROTO_LIST ((unsigned char [16], PLUTO_MD5_CTX *));
+#endif /* OPENSSL */
 
 #define _MD5_H_
diff -ruN freeswan-1.5.orig/pluto/openssl.c freeswan-1.5/pluto/openssl.c
--- freeswan-1.5.orig/pluto/openssl.c	Wed Dec 31 19:00:00 1969
+++ freeswan-1.5/pluto/openssl.c	Thu Oct  5 07:05:59 2000
@@ -0,0 +1,1827 @@
+#ifdef OPENSSL
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <sys/types.h>
+#include <dirent.h>
+
+#include <freeswan.h>
+
+#include <openssl/pem.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "id.h"
+#include "connections.h" /* needs id.h */
+#include "state.h"
+#include "kernel.h"
+#include "log.h"
+#include "packet.h"
+#include "spdb.h"
+#include "demux.h"
+#include "openssl.h"
+#include "xmap.h"
+
+
+struct _tok_node {
+  char *s;
+  struct _tok_node *next;
+};
+
+typedef struct _tok_node *tok_list;
+
+enum tok_state { TOK_NORMAL, TOK_QUOTE, TOK_BACKSLASH, TOK_BACKSLASH_Q };
+
+void tok_append(tok_list *t, const char *s);
+tok_list tokenize( const char *s, const char sep );
+void tok_free( tok_list t );
+X509_CRL *lookup_crl(STACK_OF(XMAP) *lu, X509_NAME *name);
+X509 *lookup_cert_by_subject(STACK_OF(XMAP) *lu, X509_NAME *name);
+void build_cert_chain( STACK_OF(X509) **ch, STACK_OF(XMAP) *lu, X509 *x );
+static int cert_compare(X509 *a, X509 *b);
+static STACK_OF(X509) *lookup_certs_by_ip(STACK_OF(XMAP) *lu,
+					  const char *id,
+					  const size_t len);
+static int ASN1_UTCTIME_cmp(ASN1_UTCTIME *a, ASN1_UTCTIME *b);
+static bool have_othercert( struct state *st, int type );
+static int cb( int ok, X509_STORE_CTX *ctx );
+
+void
+tok_append(tok_list *t, const char *s) {
+  tok_list p, pp;
+
+  if (!t) return;
+  if ((p = malloc(sizeof(struct _tok_node))) == NULL) return;
+  if ((p->s = strdup(s)) == NULL) { free(p); return; }
+  p->next = NULL;
+
+  if (*t == NULL) { *t = p; return; }; /* Empty list */
+  pp = *t;
+  while (pp->next != NULL) pp = pp->next;
+  pp->next = p;
+}
+
+tok_list
+tokenize( const char *s, const char sep )
+{
+  tok_list t = NULL;
+  int len, i, cnt, size;
+  char *buf;
+  enum tok_state st = TOK_NORMAL;
+
+  cnt = 0;
+  len = strlen(s);
+  size = 256; /* Initial size */
+  if ((buf = malloc(size)) == NULL) return t;
+  memset(buf, 0, size);
+  for(i=0; i<len; i++) {
+    /* resize buf if necessary */
+    if (cnt == size-1) {
+      size += 256;
+      if ((buf = realloc(buf, size)) == NULL) return t;
+    }
+    switch(st) {
+    case TOK_NORMAL:
+      if (s[i] == '\\')
+	st = TOK_BACKSLASH;
+      else if (s[i] == '\'')
+	st = TOK_QUOTE;
+      else if (s[i] == sep) {
+	/* Reached the end of a token */
+	tok_append(&t, buf);
+	memset(buf, 0, size);
+	cnt = 0;
+      } else {
+	buf[cnt] = s[i];
+	cnt++;
+	buf[cnt] = '\0';
+      }
+      break;
+    case TOK_QUOTE:
+      if (s[i] == '\\')
+	st = TOK_BACKSLASH_Q;
+      else if (s[i] == '\'') {
+	st = TOK_NORMAL;
+      } else {
+	buf[cnt] = s[i];
+	cnt++;
+	buf[cnt] = '\0';
+      }
+      break;
+    case TOK_BACKSLASH:
+      buf[cnt] = s[i];
+      cnt++;
+      buf[cnt] = '\0';
+      st = TOK_NORMAL;
+      break;
+    case TOK_BACKSLASH_Q:
+      buf[cnt] = s[i];
+      cnt++;
+      buf[cnt] = '\0';
+      st = TOK_QUOTE;
+      break;
+    }
+  }
+  tok_append(&t, buf);
+  memset(buf, 0, size);
+  cnt = 0;
+  free(buf);
+  return t;
+}
+
+void
+tok_free( tok_list t )
+{
+  tok_list p = t;
+
+  while (p) {
+    tok_list pp = p->next;
+
+    free(p->s);
+    free(p);
+    p = pp;
+  }
+}
+
+void
+log_err( void )
+{
+  unsigned long l;
+  char buf[200];
+  const char *file, *data;
+  int line, flags;
+  unsigned long es;
+  
+  es=CRYPTO_thread_id();
+  while ((l=ERR_get_error_line_data(&file,&line,&data,&flags)) != 0)
+    {
+      log("%lu:%s:%s:%d:%s\n",es,ERR_error_string(l,buf),
+	  file,line,(flags&ERR_TXT_STRING)?data:"");
+    }
+}
+
+void
+make_lookups( STACK_OF(XMAP) **lu, const char *spec )
+{
+#define MAXSPEC 10
+  const char *delim = ", ";
+  char *s, *p, *specs[MAXSPEC];
+  int i;
+  XMAP *xm;
+
+  for(i=0; i<MAXSPEC; i++) specs[i] = NULL;
+  s = clone_bytes(spec, strlen(spec)+1, "lookup specification");
+  p = strtok(s, delim);
+  i = 0;
+  while ((i < MAXSPEC) && (p)) {
+    char *sp = clone_bytes(p, strlen(p)+1, "lookup spec");
+    specs[i++] = sp;
+    p = strtok( NULL, delim );
+  }
+
+  if ((*lu = sk_XMAP_new_null()) != NULL) {
+    for(i=0; specs[i]; i++) {
+      DBG(DBG_PARSING,
+      DBG_log("Adding LU spec: %s", specs[i]);
+      );
+      if ((xm = XMAP_new(specs[i])) != NULL) sk_XMAP_push(*lu, xm);
+    }
+  }
+  
+  for(i=0; specs[i]; i++) pfree(specs[i]);
+  pfree(s);
+}
+
+/* Really need to make this routine far more tolerant */
+/* of other formats for certs & keys. For example, it */
+/* would be nice to be able to use PKCS8 private key forms */
+/* or a PKCS12 bag to hold both certificate and key */
+/* For the moment, though, we can handle certs in DER or */
+/* PEM format, and keys in PEM format only -- nd */
+void
+load_cert_and_key( const char *cert, const char *key,
+		   X509 **x, EVP_PKEY **k )
+{
+  BIO *b = NULL;
+  char keystr[32] = "PEM private key";
+
+  log("Loading certificates and key");
+  if ((! x) || (! k)) return;
+  *x = NULL;
+  *k = NULL;
+  if (cert[0] == '\0') return;
+  if (key[0] == '\0') return;
+
+  if ((b = BIO_new_file(cert, "r")) == NULL) {
+    log_err();
+    return;
+  }
+#if OPENSSL_VERSION_NUMBER > 0x00903000L
+  *x = PEM_read_bio_X509(b, NULL, NULL, NULL);
+#else
+  *x = PEM_read_bio_X509(b, NULL, NULL);
+#endif
+  if (*x == NULL) {
+    /* Try DER read */
+    BIO_ctrl(b, BIO_CTRL_RESET, 0, NULL);
+    if ((*x = d2i_X509_bio(b, NULL)) == NULL) {
+      log_err();
+      BIO_free(b);
+      return;
+    }
+  }
+  DBG(DBG_PARSING,
+  DBG_log("Read certificate from %s", cert);
+  );
+  BIO_free(b);
+  
+  if ((b = BIO_new_file(key, "r")) == NULL) {
+    log_err();
+    X509_free(*x);
+    *x = NULL;
+    return;
+  }
+  
+#if OPENSSL_VERSION_NUMBER > 0x00903000L
+  *k = PEM_read_bio_PrivateKey(b, NULL, NULL, NULL);
+#else
+  *k = PEM_read_bio_PrivateKey(b, NULL, NULL);
+#endif
+  if (!*k) {
+    RSA *r;
+    
+    /* Try DER reading of RSA Key */
+    BIO_ctrl(b, BIO_CTRL_RESET, 0, NULL);
+    r = d2i_RSAPrivateKey_bio(b, NULL);
+    if (r) {
+      if ((*k = EVP_PKEY_new()) != NULL) {
+	(*k)->type = EVP_PKEY_RSA;
+	(*k)->pkey.rsa = r;
+	strncpy(keystr, "DER RSA private key", sizeof(keystr)-1);
+      } else
+	RSA_free(r);
+    }
+  }
+  
+  if (!*k) {
+    DSA *d;
+    
+    /* Try DER reading of DSA/El Gamal Key */
+    BIO_ctrl(b, BIO_CTRL_RESET, 0, NULL);
+    d = d2i_DSAPrivateKey_bio(b, NULL);
+    if (d) {
+      if ((*k = EVP_PKEY_new()) != NULL) {
+	(*k)->type = EVP_PKEY_DSA;
+	(*k)->pkey.dsa = d;
+	strncpy(keystr, "DER DSA private key", sizeof(keystr)-1);
+      } else
+	DSA_free(d);
+    }
+  }
+  
+  if (!*k) {
+    PKCS8_PRIV_KEY_INFO *p8inf = NULL;
+    
+    BIO_ctrl(b, BIO_CTRL_RESET, 0, NULL);
+    /* try PKCS8 (unencrypted) keyform */
+    
+    BIO_ctrl(b, BIO_CTRL_RESET, 0, NULL);
+    p8inf = PEM_read_bio_PKCS8_PRIV_KEY_INFO(b, NULL, NULL, NULL);
+    if (!p8inf) {
+      /* Try reading PKCS8 in DER format */
+      BIO_ctrl(b, BIO_CTRL_RESET, 0, NULL);
+      p8inf = d2i_PKCS8_PRIV_KEY_INFO_bio(b, NULL);
+    } else 
+      strncpy(keystr, "PEM PKCS-8 private key", sizeof(keystr)-1);
+    if (!p8inf) {
+      log("Error in loading PKCS-8 private key");
+      log_err();
+      X509_free(*x);
+      *x = NULL;
+      BIO_free(b);
+      return;
+    } else
+      strncpy(keystr, "DER PKCS-8 private key", sizeof(keystr)-1);
+    if ((*k = EVP_PKCS82PKEY(p8inf)) == NULL) {
+      log("Error in converting PKCS-8 private key");
+      log_err();
+      X509_free(*x);
+      *x = NULL;
+      BIO_free(b);
+      return;
+    }
+  }
+  DBG(DBG_PARSING,
+  DBG_log("Read %s from %s", keystr, key);
+  );
+  BIO_free(b);
+}
+
+static int
+cert_compare(X509 *a, X509 *b)
+{
+  /* Check for equality of 2 X509 certificates */
+  /* certs are equal if their issuers, serial numbers */
+  /* subject names and public keys are the same */
+  /* We could probably do all of this by converting the */
+  /* certs to DER format and comparing the byte streams */
+  /* but that's likely to be inefficient -- nd */
+  int c;
+  EVP_PKEY *ka, *kb;
+
+  if ((c = X509_issuer_and_serial_cmp(a, b)) != 0)
+    return c;
+  if ((c = X509_NAME_cmp(X509_get_issuer_name(a),
+			 X509_get_issuer_name(b))) != 0)
+    return c;
+  ka = X509_get_pubkey(a);
+  kb = X509_get_pubkey(b);
+  if (ka->type != kb->type) return 1;
+  switch (ka->type) {
+  case EVP_PKEY_RSA:
+    {
+      /* RSA compare - if public exponent and modulus are equal, return 0 */
+      RSA *ra, *rb;
+
+      ra = ka->pkey.rsa;
+      rb = ka->pkey.rsa;
+
+      if (BN_cmp(ra->e, rb->e) != 0) return 1;
+      if (BN_cmp(ra->n, rb->n) != 0) return 1;
+    }
+    break;
+  case EVP_PKEY_DSA:
+    {
+      /* DSA compare, g, modulus and pubkey must be equal */
+      DSA *da, *db;
+
+      da = ka->pkey.dsa;
+      db = ka->pkey.dsa;
+
+      if (BN_cmp(da->g, db->g) != 0) return 1;
+      if (BN_cmp(da->p, db->p) != 0) return 1;
+      if (BN_cmp(da->pub_key, db->pub_key) != 0) return 1;
+    }
+    break;
+  default:
+    DBG(DBG_PARSING,
+    DBG_log("Unknown key type presented: %d", ka->type);
+    );
+    return 1;
+    break;
+  }
+  return 0;
+}
+
+static STACK_OF(X509) *
+lookup_certs_by_ip(STACK_OF(XMAP) *lu,
+		   const char *id,
+		   const size_t len)
+{
+  STACK_OF(X509) *osk = sk_X509_new_null();
+  int i;
+
+  for(i=0; i<sk_XMAP_num(lu); i++) {
+    XMAP *xm = sk_XMAP_value(lu, i);
+    u_char *cl = clone_bytes(id, len, "IPv4 address");
+    STACK_OF(X509_OBJECT) *op = NULL;
+
+	DBG(DBG_PARSING | DBG_CONTROL,
+    DBG_log("Searching map %d", i+1);
+    DBG_dump("IPv4:", cl, len);
+	);
+    if ((op = XMAP_lookup(xm, X509_LU_X509, "ip", cl)) != NULL) {
+      int j;
+
+      DBG(DBG_PARSING,
+      DBG_log("Search returns %d certificates", sk_X509_OBJECT_num(op));
+      );
+      for(j=0; j < sk_X509_OBJECT_num(op); j++) {
+	X509_OBJECT *o = sk_X509_OBJECT_value(op, j);
+	X509 *c = X509_dup(o->data.x509);
+	int k, found;
+
+	for(k=0, found=0; (!found) && (k < sk_X509_num(osk)); k++) {
+	  if (cert_compare(sk_X509_value(osk, k), c) == 0)
+	    found = 1;
+	}
+
+	if (!found) {
+	  if (sk_X509_num(osk) == 0) {
+	    sk_X509_push(osk, c);
+	  } else {
+	    ASN1_UTCTIME *new_notBefore = X509_get_notBefore(c);
+	    ASN1_UTCTIME *new_notAfter = X509_get_notAfter(c);
+	    
+	    for(k=0; k<sk_X509_num(osk); k++) {
+	      X509 *tx = sk_X509_value(osk, k); /* certificate already in stack */
+	      ASN1_UTCTIME *notBefore = X509_get_notBefore(tx);
+	      ASN1_UTCTIME *notAfter = X509_get_notAfter(tx);
+	      int c1 = ASN1_UTCTIME_cmp(new_notBefore, notBefore);
+	      int c2 = ASN1_UTCTIME_cmp(new_notAfter, notAfter);
+	      
+	      if (c1 == 0) {
+		/* certs start at same time */
+		if (c2 > 0) break; /* insert here if c expiry is later than tx */
+	      } else
+	      if (c1 > 0) break; /* insert here is c start date is later than tx */
+	      /* else move on to the next certificate in the current output stack */
+	    }
+	    sk_X509_insert(osk, c, k); /* Insert into the output stack */
+	  }
+	}
+      }
+      sk_X509_OBJECT_pop_free(op, X509_OBJECT_free);
+      pfree(cl);
+    }
+  }
+  if (osk) DBG(DBG_PARSING,
+	DBG_log("Returning %d certs in list", sk_X509_num(osk)));
+  return osk;
+} 
+
+/* peer_cert_list takes a supplied list of XMAPs */
+/* and adds all of the X509 certificates whose */
+/* public key matches 'type' into a safe stack certificates */
+/* If the parameter 'cert' is non-NULL, only the certificate */
+/* which matches it will be added to the list */
+STACK_OF(X509) *
+peer_cert_list( STACK_OF(XMAP) *lu, int type, X509 *cert,
+		struct payload_digest *const id_pld,
+		bool strict )
+{
+  STACK_OF(X509) *sk = NULL, *osk = NULL;
+  pb_stream *const id_pbs = &id_pld->pbs;
+  struct isakmp_id *const id = &id_pld->payload.id;
+  int i, found;
+
+  switch(id->isaid_idtype) {
+  case ID_IPV4_ADDR:
+    if (pbs_left(id_pbs) != sizeof(struct in_addr)) {
+      DBG(DBG_PARSING,
+      DBG_log("ID size is not equal to that of an IPv4 address");
+      );
+      return NULL;
+    }
+    if ((sk = lookup_certs_by_ip(lu,
+				id_pbs->cur,
+				sizeof(struct in_addr))) == NULL) {
+      DBG(DBG_PARSING,
+      DBG_log("No certs for this IP address");
+      );
+      return NULL;
+    }
+    break;
+  default:
+    DBG(DBG_PARSING,
+    DBG_log("No means to check certificates for ID type = %s",
+	    enum_show(&ident_names, id->isaid_idtype));
+    );
+    return NULL;
+  }
+
+  /* Now filter out any certificates not of type 'type' */
+  if ((osk = sk_X509_new_null()) != NULL) {
+    for(i=0; i<sk_X509_num(sk); i++) {
+      X509 *x = sk_X509_value(sk, i);
+      EVP_PKEY *pk = X509_get_pubkey(x);
+
+      if (pk->type == type) {
+	sk_X509_push(osk, X509_dup(x));
+      } else {
+    DBG(DBG_PARSING,
+	DBG_log("Rejecting certificate: wrong type: %d", pk->type);
+    );
+      }
+    }
+    sk_X509_pop_free(sk, X509_free);
+    sk = osk; /* Make sk the new filtered list */
+  } else {
+    DBG(DBG_PARSING,
+    DBG_log("Error in allocating new sk_X509");
+    );
+    sk_X509_pop_free(sk, X509_free);
+    sk = NULL;
+  }
+
+  if ((sk) && (cert)) {
+    /* If a certificate was presupplied, we want to check */
+    /* whether it is in the list of acceptable certificates */
+    /* for this connection. If no certificate is presupplied */
+    /* then it is assumed that one of the certificates in */
+    /* the list will correctly decrypt the signature/nonces */
+
+    for(i=0, found=0; ((!found) && (i < sk_X509_num(sk))); i++)
+      if (cert_compare(sk_X509_value(sk, i), cert) == 0) found = 1;
+
+    if (found) {
+      DBG(DBG_PARSING,
+      DBG_log("Certificate supplied is in list");
+      );
+    } else {
+      DBG(DBG_PARSING,
+      DBG_log("Certificate supplied is NOT in list");
+      );
+
+      /* If strict is not set, this certificate will be allowed */
+      /* to pass, even though the host cannot recognise it as */
+      /* in the list of known certificates for this ID. Otherwise */
+      /* we erase the list and return NULL -- an error condition */
+      if (strict) {
+	sk_X509_pop_free(sk, X509_free);
+	sk = NULL;
+      }
+    }
+  }
+
+  return sk;
+}
+
+bool
+have_rsa_key( struct state *st )
+{
+  struct connection *c = st->st_connection;
+
+  if (c->key == NULL) { 
+	DBG(DBG_PARSING,
+	DBG_log("No key present");
+	);
+	return FALSE; 
+  }
+  if ( ((EVP_PKEY *)(c->key))->type != EVP_PKEY_RSA ) { return FALSE; }
+  return TRUE;
+}
+
+bool
+have_dss_key( struct state *st )
+{
+  struct connection *c = st->st_connection;
+
+  if (c->key == NULL) { 
+	DBG(DBG_PARSING,
+	DBG_log("No key present"); 
+	);
+	return FALSE; 
+  }
+  if ( ((EVP_PKEY *)(c->key))->type != EVP_PKEY_DSA ) { return FALSE; }
+  return TRUE;
+}
+
+static bool
+have_othercert( struct state *st, int type )
+{
+  struct connection *c = st->st_connection;
+  struct end *that = &st->st_connection->that;
+  STACK_OF(X509) *op = NULL;
+  X509 *x;
+  int i;
+  bool found;
+
+  /* First check to see if we've already done */
+  /* this lookup and stored the certificate in */
+  /* c->other[] */
+
+  for(i=0; i<MAX_OTHER; i++)
+    if ((c->other[i].type == type) &&
+	(c->other[i].cert != NULL)) {
+      DBG(DBG_PARSING,
+      DBG_log("Already stored a type %d cert", type);
+      );
+      return TRUE;
+    }
+
+  op = lookup_certs_by_ip((STACK_OF(XMAP) *)c->lu,
+			  (const char *)&that->host_addr,
+			  sizeof(that->host_addr));
+  if (!op) {
+	DBG(DBG_PARSING,
+    DBG_log("IP lookup returns NULL");
+	);
+  } else {
+    int i;
+
+    for(i=0, found = FALSE; ((!found) && (i < sk_X509_num(op))); i++) {
+      x = sk_X509_value(op, i);
+      if (X509_get_pubkey(x)->type == type) {
+	found = TRUE;
+	for(i=0; i<MAX_OTHER; i++) {
+ 	  if (c->other[i].cert == NULL) {
+		DBG(DBG_PARSING,
+	    DBG_log("Storing type %d cert at position %d", type, i);
+		);
+	    c->other[i].type = type;
+	    c->other[i].cert = (void *)X509_dup(x);
+	    break;
+	  }
+	}
+      }
+    }
+
+    if (found) {
+      DBG(DBG_PARSING,
+      DBG_log("Found type %d cert at position %d:",
+	      type, i+1);
+      );
+    } else {
+      DBG(DBG_PARSING,
+      DBG_log("No appropriate cert found");
+      );
+    }
+    sk_X509_pop_free(op, X509_free);
+  }
+  return (found);
+}
+
+bool
+have_rsa_keypair( struct state *st )
+{
+  bool r = have_othercert(st, EVP_PKEY_RSA);
+
+  if (r) r = have_rsa_key(st);
+
+  DBG(DBG_PARSING,
+  DBG_log("Have RSA other cert = %s", r  ? "TRUE" : "FALSE");
+  );
+  return r;
+}
+
+bool
+have_elgamal_keypair( struct state *st )
+{
+  bool r = have_othercert(st, EVP_PKEY_DSA); 
+  if (r) r = have_dss_key(st);
+  DBG(DBG_PARSING,
+  DBG_log("Have El Gamal other cert = %s", r  ? "TRUE" : "FALSE");
+  );
+  return r;
+}
+
+static int
+cb( int ok, X509_STORE_CTX *ctx )
+{
+  char buf[200];
+  
+  if (!ok) {
+    if (ctx->error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) {
+      /* Check to see if it is a CA certificate, ie with */
+      /* basicConstraints, and perhaps other checks */
+      /* For the moment, we just let it slide */
+      ok = 1;
+    } else {
+      X509_NAME_oneline(X509_get_subject_name(ctx->current_cert), buf, sizeof(buf));
+      
+      DBG(DBG_PARSING,
+      DBG_log("Error for certificate: %s", buf);
+      DBG_log("Error %d: Depth %d: %s",
+              ctx->error,
+              ctx->error_depth,
+              X509_verify_cert_error_string(ctx->error));
+      );
+    }
+  }
+  return (ok);
+}
+
+static int
+ASN1_UTCTIME_cmp(ASN1_UTCTIME *a, ASN1_UTCTIME *b)
+{
+  char buff1[14],buff2[14],*p;
+  int i,j;
+ 
+  /* Degenerate cases */
+  if (!a && !b) return 0;
+  if (a && !b) return 1;
+  if (!a && b) return -1;
+ 
+  memset(buff1, 0, sizeof(buff1));
+  memset(buff2, 0, sizeof(buff2));
+ 
+  p=buff1;
+  i=a->length;
+  if ((i < 11) || (i > 17)) return(0);
+  memcpy(p,a->data,12);
+ 
+  p=buff2;
+  j=b->length;
+  if ((j < 11) || (j > 17)) return(0);
+  memcpy(p,b->data,12);
+ 
+  /* Correct for Y2K */
+  i=(buff1[0]-'0')*10+(buff1[1]-'0');
+  if (i < 50) i+=100; /* cf. RFC 2459 */
+  j=(buff2[0]-'0')*10+(buff2[1]-'0');
+  if (j < 50) j+=100;
+ 
+  if (i < j) return (-1);
+  if (i > j) return (1);
+ 
+  i=strcmp(buff1,buff2);
+ 
+  if (i == 0)
+    return 0;
+  else if (i < 0)
+    return(-1);
+  else
+    return(1);
+}
+
+X509_CRL *
+lookup_crl(STACK_OF(XMAP) *lu, X509_NAME *name)
+{
+  X509_CRL *x = NULL;
+  STACK_OF(X509_CRL) *osk = sk_X509_CRL_new_null();
+  int i, j, k, found;
+
+  for(i=0; i<sk_XMAP_num(lu); i++) {
+    XMAP *xm = sk_XMAP_value(lu, i);
+    STACK_OF(X509_OBJECT) *xo = NULL;
+
+    if (xm) {
+      XMAP_dump(xm);
+      if ((xo = XMAP_lookup(xm, X509_LU_CRL, "issuer", name)) != NULL) {
+	for(j=0; j<sk_X509_OBJECT_num(xo); j++) {
+	  X509_OBJECT *o = sk_X509_OBJECT_value(xo, j);
+	  X509_CRL *xx = X509_CRL_dup(o->data.crl);
+	  
+	  for(k=0, found = 0; (!found) && (k<sk_X509_CRL_num(osk)); k++) {
+	    X509_CRL *tx = sk_X509_CRL_value(osk, k);
+	    
+	    if ((X509_NAME_cmp(X509_CRL_get_issuer(xx),
+			       X509_CRL_get_issuer(tx))==0) &&
+		(ASN1_UTCTIME_cmp(X509_CRL_get_lastUpdate(xx),
+				  X509_CRL_get_lastUpdate(tx)) == 0) &&
+		(ASN1_UTCTIME_cmp(X509_CRL_get_nextUpdate(xx),
+				  X509_CRL_get_nextUpdate(tx)) == 0))
+	      found = 1;
+	  }
+	  
+	  if (!found) {
+	    if (sk_X509_CRL_num(osk) == 0)
+	      sk_X509_CRL_push(osk, xx);
+	    else {
+	      /* insert the certificate into the stack in date order */
+	      for(k=0; k<sk_X509_CRL_num(osk); k++) {
+		X509_CRL *tx = sk_X509_CRL_value(osk, k); /* certificate already in stack */
+		
+		if (ASN1_UTCTIME_cmp(X509_CRL_get_lastUpdate(xx),
+				     X509_CRL_get_lastUpdate(tx)) > 0)
+		  break; /* insert here if last Update is newer than current crl */
+	      }
+	      
+	      sk_X509_CRL_insert(osk, xx, k); /* Insert into the output stack */            }
+	  } else
+	    X509_CRL_free(xx);
+	}
+	sk_X509_OBJECT_pop_free(xo, X509_OBJECT_free); /* drop search return values */
+      }
+    }
+  }
+
+  if (sk_X509_CRL_num(osk) > 0)
+    x = X509_CRL_dup(sk_X509_CRL_value(osk, 0)); /* use first certificate in stack */
+  sk_X509_CRL_pop_free(osk, X509_CRL_free); /* get rid of output stack */
+  return x; 
+}
+
+static STACK_OF(XMAP) *lookups = NULL;
+static bool verify_strict;
+/* only way I can think to get the verify function (which is) */
+/* used as a callback to access the 'strict verification' flag */
+/* The problem is that there isn't any space in the parameters */
+/* to the verify_func in which to add this flag. Pity, because */
+/* a static global controlling verification policy is a fairly */
+/* stinky idea -- nd */
+
+/* The following code is simply the code from x509_vfy.c */
+/* with CRL checking added, and basicConstraints checking */
+static int
+verify_func(X509_STORE_CTX *ctx)
+{
+  int i,ok=0,n;
+  X509 *xs,*xi;
+  EVP_PKEY *pkey=NULL;
+  int (*cb)();
+  X509_CRL *crl;
+  
+  cb=ctx->ctx->verify_cb;
+  
+  n=sk_X509_num(ctx->chain);
+  DBG(DBG_PARSING,
+  DBG_log("%d certs in chain", n);
+  );
+  ctx->error_depth=n-1;
+  n--;
+  xi=sk_X509_value(ctx->chain,n);
+  DBG(DBG_PARSING,
+  DBG_log("xi = %08X", (u_int32_t)xi);
+  );
+  if (X509_NAME_cmp(X509_get_subject_name(xi),
+		    X509_get_issuer_name(xi)) == 0)
+    xs=xi;
+  else {
+    if (n <= 0) {
+      ctx->error=X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE;
+      ctx->current_cert=xi;
+      ok=cb(0,ctx);
+      goto end;
+    } else {
+      n--;
+      ctx->error_depth=n;
+      xs=sk_X509_value(ctx->chain,n);
+    }
+  }
+  
+  while (n >= 0) {
+    ctx->error_depth=n;
+    if (!xs->valid) {
+      if ((pkey=X509_get_pubkey(xi)) == NULL)
+	{
+	  ctx->error=X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;
+	  ctx->current_cert=xi;
+	  ok=(*cb)(0,ctx);
+	  if (!ok) goto end;
+	}
+      if (X509_verify(xs,pkey) <= 0) {
+	EVP_PKEY_free(pkey);
+	ctx->error=X509_V_ERR_CERT_SIGNATURE_FAILURE;
+	ctx->current_cert=xs;
+	ok=(*cb)(0,ctx);
+	if (!ok) goto end;
+      }
+      EVP_PKEY_free(pkey);
+      pkey=NULL;
+
+      i=X509_cmp_current_time(X509_get_notBefore(xs));
+      if (i == 0) {
+	ctx->error=X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD;
+	ctx->current_cert=xs;
+	ok=(*cb)(0,ctx);
+	if (!ok) goto end;
+      }
+      if (i > 0) {
+	ctx->error=X509_V_ERR_CERT_NOT_YET_VALID;
+	ctx->current_cert=xs;
+	ok=(*cb)(0,ctx);
+	if (!ok) goto end;
+      }
+      xs->valid=1;
+    }
+
+    i=X509_cmp_current_time(X509_get_notAfter(xs));
+    if (i == 0) {
+      ctx->error=X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD;
+      ctx->current_cert=xs;
+      ok=(*cb)(0,ctx);
+      if (!ok) goto end;
+    }
+    
+    if (i < 0) {
+      ctx->error=X509_V_ERR_CERT_HAS_EXPIRED;
+      ctx->current_cert=xs;
+      ok=(*cb)(0,ctx);
+      if (!ok) goto end;
+    }
+
+    if (n == sk_X509_num(ctx->chain)-1) {
+      /* This is the root certificate */
+      int loc = X509_get_ext_by_NID(xs, NID_basic_constraints, -1);
+      if (loc >= 0) {
+	X509_EXTENSION *ext;
+	BASIC_CONSTRAINTS *p = NULL;
+	
+	ext = X509_get_ext(xs, loc);
+	if (ext) {
+	  p = X509V3_EXT_d2i(ext);
+	  if (! p->ca) {
+	    BASIC_CONSTRAINTS_free(p);
+	    ctx->error=X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
+	    ctx->current_cert=xs;
+	    ok=(*cb)(0,ctx);
+	    if (!ok) goto end;
+	  } else {
+        DBG(DBG_PARSING,
+	    DBG_log("Root certificate has CA = True");
+        );
+	    BASIC_CONSTRAINTS_free(p);
+	  }
+	} else {
+	  /* The cert has a basicConstraints extension, but */
+	  /* we couldn't get it */
+	  ctx->error=X509_V_ERR_APPLICATION_VERIFICATION;
+	  ctx->current_cert=xs;
+	  ok=(*cb)(0,ctx);
+	  if (!ok) goto end;
+	}
+      } else {
+#ifndef DONT_BE_FASCIST
+	ctx->error=X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
+	ctx->current_cert=xs;
+	ok=(*cb)(0,ctx);
+	if (!ok) goto end;
+#endif
+      }
+    }
+
+    /* CRL CHECK */
+    if ((crl = lookup_crl(lookups, X509_get_issuer_name(xs))) != NULL) {
+      EVP_PKEY *pkey = X509_get_pubkey(xi);
+      STACK_OF(X509_REVOKED) *rev;
+      int nrev;
+      
+      DBG(DBG_PARSING,
+      DBG_log("Checking CRL for issuer");
+      );
+      
+      if (pkey == NULL) {
+	ctx->error=X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;
+	X509_CRL_free(crl);
+	ctx->current_cert=xs;
+	ok=(*cb)(0,ctx);
+	if (!ok) goto end;
+      }
+      
+      if (X509_CRL_verify(crl, pkey) <= 0) {
+	ctx->error=X509_V_ERR_CRL_SIGNATURE_FAILURE;
+	X509_CRL_free(crl);
+	ctx->current_cert=xs;
+	ok=(*cb)(0,ctx);
+	if (!ok) goto end;
+      }
+      
+      i = X509_cmp_current_time(X509_CRL_get_lastUpdate(crl));
+      if (i == 0) {
+	ctx->error=X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD;
+	X509_CRL_free(crl);
+	ctx->current_cert=xs;
+	ok=(*cb)(0,ctx);
+	if (!ok) goto end;
+      }
+      if (i > 0) {
+	ctx->error=X509_V_ERR_CRL_NOT_YET_VALID;
+	X509_CRL_free(crl);
+	ctx->current_cert=xs;
+	ok=(*cb)(0,ctx);
+	if (!ok) goto end;
+      }
+      
+      i = X509_cmp_current_time(X509_CRL_get_nextUpdate(crl));
+      if (i == 0) {
+	ctx->error=X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD;
+	X509_CRL_free(crl);
+	ctx->current_cert=xs;
+	ok=(*cb)(0,ctx);
+	if (!ok) goto end;
+      }
+      if (i < 0) {
+	ctx->error=X509_V_ERR_CRL_HAS_EXPIRED;
+	X509_CRL_free(crl);
+	ctx->current_cert=xs;
+	ok=(*cb)(0,ctx);
+	if (!ok) goto end;
+      }
+      
+      rev = X509_CRL_get_REVOKED(crl);
+      nrev = sk_X509_REVOKED_num(rev);
+      DBG(DBG_PARSING,
+      DBG_log("%d certificates revoked in CRL", nrev);
+      );
+      for(i=0; i<nrev; i++) {
+	X509_REVOKED *rv = sk_X509_REVOKED_value(rev, i);
+	
+	if (ASN1_INTEGER_cmp(X509_get_serialNumber(xs), rv->serialNumber) == 0) {
+	  /* It's this certificate that's been revoked */
+	  int c = X509_cmp_current_time(rv->revocationDate);
+	  if (c < 0) {
+	    ctx->error=X509_V_ERR_CERT_REVOKED;
+	    X509_CRL_free(crl);
+	    ctx->current_cert=xs;
+	    ok=(*cb)(0,ctx);
+	    if (!ok) goto end;
+	  }
+      DBG(DBG_PARSING,
+	  DBG_log("Serial Number matches");
+      );
+	}
+      }
+
+      X509_CRL_free(crl);
+    } else {
+      char buf[200];
+      
+      X509_NAME_oneline(X509_get_issuer_name(xs), buf, sizeof(buf));
+      DBG(DBG_PARSING,
+      DBG_log("Cant locate a CRL for issuer %s", buf);
+      );
+      /* If we're being paranoid here, we really should fail */
+      /* the verification. An attacker capable of mounting */
+      /* a denial of service attack could cause us fail to */
+      /* load the CRL, and use a revoked, but otherwise valid */
+      /* certificate in the  exchange to set up a valid SA */
+      /* In this case, we let it go, but an idea might be */
+      /* to have an ipsec.conf specified policy on how mandatory */
+      /* CRLs are in the verification sequence -- nd */
+      if (verify_strict) {
+	ctx->error=X509_V_ERR_UNABLE_TO_GET_CRL;
+	ctx->current_cert=xs;
+	ok=(*cb)(0,ctx);
+	if (!ok) goto end;
+      }
+    }
+
+    /* The last error (if any) is still in the error value */
+    ctx->current_cert=xs;
+    ok=(*cb)(1,ctx);
+    if (!ok) goto end;
+
+    n--;
+    if (n >= 0) {
+      xi=xs;
+      xs=sk_X509_value(ctx->chain,n);
+    }
+  }
+  ok=1;
+ end:
+  return(ok);
+}
+
+X509 *
+lookup_cert_by_subject(STACK_OF(XMAP) *lu, X509_NAME *xn)
+{
+  X509 *x = NULL; /* return value */
+  STACK_OF(X509) *osk = sk_X509_new_null(); /* output stack - concatenation of certificates */
+  int i, j, k, found;
+  
+  DBG(DBG_PARSING,
+  DBG_log("Looking up certificate by subject");
+  );
+  for(i=0; i<sk_XMAP_num(lu); i++) {
+    XMAP *xm = sk_XMAP_value(lu, i); /* individual searchable directory */
+    STACK_OF(X509_OBJECT) *xo = NULL; /* list of objects from individual searches */
+ 
+    if (xm) {
+      DBG(DBG_PARSING,
+      DBG_log("Searching map %d", i+1);
+      );
+      if ((xo = XMAP_lookup( xm, X509_LU_X509, "subject", xn)) != NULL) {
+        DBG(DBG_PARSING,
+        DBG_log("Got %d certificates", sk_X509_OBJECT_num(xo));
+        );
+        for(j=0; j<sk_X509_OBJECT_num(xo); j++) {
+          X509_OBJECT *o = sk_X509_OBJECT_value(xo, j);
+          X509 *xx = X509_dup(o->data.x509);
+ 
+          for(k=0, found = 0; (!found) && (k<sk_X509_num(osk)); k++) {
+            X509 *tx = sk_X509_value(osk, k);
+ 
+            if (X509_issuer_and_serial_cmp(xx, tx) == 0) found = 1;
+          }
+ 
+          DBG(DBG_PARSING,
+          DBG_log("Found = %d", found);
+          );
+          if (!found) {
+            if (sk_X509_num(osk) == 0) {
+              sk_X509_push(osk, xx);
+              DBG(DBG_PARSING,
+              DBG_log("Initialised cert stack");
+              );
+            } else {
+              /* insert the certificate into the stack in date order */
+              ASN1_UTCTIME *new_notBefore = X509_get_notBefore(xx);
+              ASN1_UTCTIME *new_notAfter = X509_get_notAfter(xx);
+ 
+              for(k=0; k<sk_X509_num(osk); k++) {
+                X509 *tx = sk_X509_value(osk, k); /* certificate already in stack */
+                ASN1_UTCTIME *notBefore = X509_get_notBefore(tx);
+                ASN1_UTCTIME *notAfter = X509_get_notAfter(tx);
+                int c1 = ASN1_UTCTIME_cmp(new_notBefore, notBefore);
+                int c2 = ASN1_UTCTIME_cmp(new_notAfter, notAfter);
+ 
+                if (c1 == 0) {
+                  /* certs start at same time */
+                  if (c2 > 0) break; /* insert here if xx expiry is later than tx */
+                } else
+                  if (c1 > 0) break; /* insert here is xx start date is later than tx */
+                /* else move on to the next certificate in the current output stack */
+              }
+              sk_X509_insert(osk, xx, k); /* Insert into the output stack */
+            }
+          } else
+            X509_free(xx);
+        }
+        sk_X509_OBJECT_pop_free(xo, X509_OBJECT_free);
+      }
+    }
+  }
+  DBG(DBG_PARSING,
+  DBG_log("Finished lookups");
+  );
+ 
+  if (sk_X509_num(osk) > 0)
+    x = X509_dup(sk_X509_value(osk, 0));
+  sk_X509_pop_free(osk, X509_free); /* get rid of output stack */
+  return x; 
+}
+
+void
+build_cert_chain( STACK_OF(X509) **ch, STACK_OF(XMAP) *lu, X509 *x )
+{
+  int done = 0;
+  X509 *xx;
+
+  if (!ch) return;
+  if ((*ch = sk_X509_new_null()) == NULL) return;
+  xx = x;
+  sk_X509_push(*ch, X509_dup(xx));
+  while (!done) {
+    X509 *xi;
+
+    DBG(DBG_PARSING,
+    DBG_log("Looking up certificate issuer");
+    );
+    if ((xi = lookup_cert_by_subject(lu, X509_get_issuer_name(xx))) != NULL) {
+      DBG(DBG_PARSING,
+      DBG_log("Pushing certificate onto stack");
+      );
+      sk_X509_push(*ch, xi);
+      DBG(DBG_PARSING,
+      DBG_log("Comparing subject and issuer");
+      );
+      if (X509_NAME_cmp(X509_get_subject_name(xi),
+			X509_get_issuer_name(xi)) == 0) {
+	done = 1;
+      } else {
+	xx = xi;
+      }
+      DBG(DBG_PARSING,
+      DBG_log("Done = %d", done);
+      );
+    } else 
+      done = 1; /* Cant find certificate */
+  }
+}
+
+bool
+verify_certificate( X509 *x, STACK_OF(XMAP) *lu,
+		    const char *path, bool strict )
+{
+  X509_STORE *ctx = NULL;
+  X509_STORE_CTX csc;
+  int ver;
+
+
+  if ((ctx = X509_STORE_new()) == NULL) {
+    DBG(DBG_PARSING,
+    DBG_log("Cant allocate file lookup");
+    );
+    log_err();
+    return 0;
+  }
+
+  X509_STORE_set_verify_cb_func(ctx, cb);
+
+  ERR_clear_error();
+  verify_strict = strict;
+  lookups = lu;
+  X509_STORE_CTX_init(&csc, ctx, x, NULL);
+  build_cert_chain(&(csc.chain), lu, x);
+  ver = verify_func(&csc);
+  X509_STORE_CTX_cleanup(&csc);
+
+  if (ctx) X509_STORE_free(ctx);
+
+  if (ver) {
+    DBG(DBG_PARSING,
+    DBG_log("Certificate verification succeeded");
+    );
+  } else {
+    DBG(DBG_PARSING,
+    DBG_log("Verification failed");
+    );
+    log_err();
+  }
+
+  return ver;
+}
+
+struct cert_options {
+  const char *opt;
+  u_int32_t optflag;
+};
+
+static struct cert_options certopts[] = {
+  { "send", CERT_OPTION_SEND },
+  { "pkcs7", CERT_OPTION_PKCS7 },
+  { "pk", CERT_OPTION_PK },
+  { "rev", CERT_OPTION_REV },
+  { "strict", CERT_OPTION_STRICT },
+  { "dss-sha", CERT_OPTION_DSS_SHA },
+  { "dss-alt", CERT_OPTION_DSS_ALT },
+  { NULL, 0 }
+};
+
+u_int32_t
+parse_options( const char *s )
+{
+  tok_list tl, p;
+  u_int32_t i, ret = 0, b4;
+
+  tl = tokenize(s, ',');
+  for(p=tl; p; p=p->next) {
+    int found = 0;
+    char *st = p->s;
+
+    while (isspace(*st)) st++; /* skip whitespace */
+    for(i=0; (!found) && (certopts[i].opt != NULL); i++) {
+      if ((st[0] == '!') &&
+	  (strncasecmp(&(st[1]), certopts[i].opt,
+		       strlen(certopts[i].opt)) == 0)) {
+	found = 1;
+	b4 = ret;
+	ret &= ~certopts[i].optflag;
+    DBG(DBG_PARSING,
+	DBG_log("Cert option: Clearing option %s: %08x -> %08x", certopts[i].opt, b4, ret);
+    );
+      } else if (strncasecmp(st, certopts[i].opt,
+			     strlen(certopts[i].opt)) == 0) {
+	found = 1;
+	b4 = ret;
+	ret |= certopts[i].optflag;
+    DBG(DBG_PARSING,
+	DBG_log("Cert option: Setting option %s: %08x -> %08x", certopts[i].opt, b4, ret);
+    );
+      }
+    }
+  }
+  tok_free(tl);
+  return ret;
+}
+int
+DSA_sign_raw(unsigned char *dgst,int dlen,
+	     unsigned char *sig, unsigned int *siglen, DSA *dsa)
+{
+  DSA_SIG *s;
+  int offset;
+
+  DBG(DBG_PARSING,
+  DBG_log("DSA_sign_raw called");
+  );
+  s= DSA_do_sign(dgst, dlen, dsa);
+  if (s == NULL) {
+    *siglen=0;
+    return 0;
+  }
+  memset(sig, 0, SHA1_DIGEST_SIZE * 2);
+  offset = SHA1_DIGEST_SIZE - BN_num_bytes(s->r);
+  BN_bn2bin(s->r, &(sig[offset]));
+  offset = SHA1_DIGEST_SIZE - BN_num_bytes(s->s);
+  BN_bn2bin(s->s, &(sig[SHA1_DIGEST_SIZE + offset]));
+  *siglen = SHA1_DIGEST_SIZE * 2;
+  DSA_SIG_free(s);
+  return 1;
+}
+
+int DSA_verify_raw(const unsigned char *dgst,int dgst_len,
+		   unsigned char *sigbuf, int siglen, DSA *dsa)
+{
+  DSA_SIG *s;
+  int ret = -1;
+
+  DBG(DBG_PARSING,
+  DBG_log("DSA_verify_raw called");
+  );
+  if (siglen != (2 * SHA1_DIGEST_SIZE)) return ret;
+  s = DSA_SIG_new();
+  if (s == NULL) return ret;
+  s->r = BN_bin2bn(sigbuf, SHA1_DIGEST_SIZE,
+		   s->r);
+  s->s = BN_bin2bn(&(sigbuf[SHA1_DIGEST_SIZE]),
+		   SHA1_DIGEST_SIZE,
+		   s->s);
+  ret=DSA_do_verify(dgst, dgst_len,s,dsa);
+  DSA_SIG_free(s);
+  return ret;
+}
+
+/*
+ * The following code implements ElGamal encryption using DSA keys
+ * in a (hopefully) OpenSSL compatible fashion. It really belongs in 
+ * OpenSSL itself, when the code approaches being both tested and
+ * more efficient. In order to make things a bit faster, the modular
+ * operations use montogomery representation.
+ *
+ * NB - this implementation is pretty naive, and contains just the
+ * simplest implementation of ElGamal as per HAC, Ch8, Section 8.4,
+ * pp 294-295.
+ */
+
+static ERR_STRING_DATA ElGamal_str_functs[] =
+{
+  {ERR_PACK(0,ELGAMAL_F_ELGAMAL_PUBLIC_ENCRYPT,0),  "ElGamal_public_encrypt"},
+  {ERR_PACK(0,ELGAMAL_F_ELGAMAL_PRIVATE_DECRYPT,0), "ElGamal_private_decrypt"},
+  { 0, NULL }
+};
+
+static ERR_STRING_DATA ElGamal_str_reasons[] = 
+{
+  { ELGAMAL_R_UNKNOWN_PADDING_TYPE, "unknown padding type" },
+  { ELGAMAL_R_DATA_GREATER_THAN_MOD_LEN, "data longer than modulus length" },
+  { ELGAMAL_R_PADDING_CHECK_FAILED, "padding check failed" },
+  { 0, NULL }
+};
+
+void
+ERR_load_ElGamal_strings( void )
+{
+  static int init = 1;
+
+  if (init)
+    {
+      init = 0;
+
+      ERR_load_strings(ERR_LIB_ELGAMAL, ElGamal_str_functs);
+      ERR_load_strings(ERR_LIB_ELGAMAL, ElGamal_str_reasons);
+    }
+}
+
+int
+ElGamal_public_check( DSA *dsa )
+{
+  BIGNUM res;
+  BN_MONT_CTX *mont;
+  BN_CTX *ctx;
+  int r = 0;
+
+  /* Check that g^q = 1 (mod p), and that y^q = 1 (mod p) */
+  /* to avoid attacks involving generators which produce small */
+  /* subgroups */
+
+  BN_init(&res);
+  if ((ctx = BN_CTX_new()) == NULL) goto err;
+  if ((mont = BN_MONT_CTX_new()) == NULL) goto err;
+  if (! BN_MONT_CTX_set(mont, dsa->p, ctx)) goto err;
+
+  if (! BN_mod_exp_mont(&res, dsa->g, dsa->q, dsa->p, ctx, mont)) goto err;
+  if (! BN_is_one(&res)) goto err;
+  if (! BN_mod_exp_mont(&res, dsa->pub_key, dsa->q, dsa->p, ctx, mont)) goto err;
+  if (! BN_is_one(&res)) goto err;
+  r = 1; /* Key is OK */
+
+ err:
+  BN_clear_free(&res);
+  if (ctx) BN_CTX_free(ctx);
+  if (mont) BN_MONT_CTX_free(mont);
+
+  return r;
+}
+
+int
+ElGamal_public_encrypt( int flen, unsigned char *from,
+			unsigned char *to,
+			DSA *dsa, int padding )
+			    
+{
+  unsigned char *buf, *p;
+  int num = 0, i, j, k, r = -1;
+  BIGNUM kappa, alpha, beta, f;
+  BIGNUM BETA, F;
+  BN_MONT_CTX *pmont;
+  BN_CTX *ctx = NULL;
+
+  num = BN_num_bytes(dsa->p) ;
+  BN_init(&alpha);
+  BN_init(&beta);
+  BN_init(&kappa);
+  BN_init(&f);
+  BN_init(&BETA);
+  BN_init(&F);
+
+  if ((ctx = BN_CTX_new()) == NULL) goto err;
+  if ((pmont = BN_MONT_CTX_new()) == NULL) goto err;
+  if (! BN_MONT_CTX_set(pmont, dsa->p, ctx)) goto err;
+  if ((buf = (unsigned char *)Malloc(num)) == NULL) {
+    ElGamalerr(ELGAMAL_F_ELGAMAL_PUBLIC_ENCRYPT, ERR_R_MALLOC_FAILURE);
+    goto err;
+  }
+
+  /* generate k s.t. 1 <= k <= q-1 */
+  do {
+    if (! BN_rand(&kappa, BN_num_bits(dsa->q), 1, 1)) goto err;
+  } while (BN_cmp(&kappa, dsa->q) < 0);
+
+  switch (padding) {
+  case ELGAMAL_PKCS1_PADDING:
+    i = RSA_padding_add_PKCS1_type_2(buf, num, from, flen);
+    break;
+  case ELGAMAL_PKCS1_OAEP_PADDING:
+    i = RSA_padding_add_PKCS1_OAEP(buf, num, from, flen, NULL, 0);
+    break;
+  case ELGAMAL_NO_PADDING:
+    i = RSA_padding_add_none(buf, num, from, flen);
+    break;
+  default:
+    ElGamalerr( ELGAMAL_F_ELGAMAL_PUBLIC_ENCRYPT, ELGAMAL_R_UNKNOWN_PADDING_TYPE );
+    goto err;
+  }
+
+  if (i <= 0) goto err;
+
+  if (BN_bin2bn(buf, num, &f) == NULL) goto err;
+
+  /* Set alpha = g^k (mod p) */
+  if (!BN_mod_exp_mont(&alpha, dsa->g, &kappa, dsa->p, ctx, pmont)) goto err;
+
+  /* Set beta = M * y^k (mod p) */
+  if (!BN_mod_exp_mont(&beta, dsa->pub_key, &kappa, dsa->p, ctx, pmont)) goto err;
+
+  BN_to_montgomery(&F, &f, pmont, ctx);
+  BN_to_montgomery(&BETA, &beta, pmont, ctx);
+  if (!BN_mod_mul_montgomery(&BETA, &BETA, &F, pmont, ctx)) goto err;
+  BN_from_montgomery(&beta, &BETA, pmont, ctx);
+
+  /* Squirt out alpha, left padded to modulus size with zero bytes */
+  j = BN_num_bytes(&alpha);
+  i = BN_bn2bin(&alpha, &(to[num-j]));
+  for(k=0; k<(num-i); k++) to[k]=0;
+
+  /* Follow this with beta */
+  p = &(to[num]);
+  j = BN_num_bytes(&beta);
+  i = BN_bn2bin(&beta, &(p[num-j]));
+  for(k=0; k<(num-i); k++) p[k]=0;
+
+  r = num*2;
+
+ err:
+  if (ctx != NULL) BN_CTX_free(ctx);
+  if (pmont != NULL) BN_MONT_CTX_free(pmont);
+  BN_clear_free(&alpha);
+  BN_clear_free(&beta);
+  BN_clear_free(&beta);
+  BN_clear_free(&kappa);
+  BN_clear_free(&f);
+  BN_clear_free(&BETA);
+  BN_clear_free(&F);
+  if (buf != NULL) {
+    memset(buf, 0, num);
+    Free(buf);
+  }
+  return r;
+}
+
+int ElGamal_private_decrypt( int flen, unsigned char *from,
+			     unsigned char *to,
+			     DSA *dsa, int padding )
+{
+
+  BIGNUM alpha, beta, gamma, delta, p1a;
+  BIGNUM BETA, GAMMA, DELTA;
+  BN_CTX *ctx;
+  BN_MONT_CTX *pmont;
+  unsigned char *p, *buf = NULL;
+  int j, r = -1, num;
+
+  BN_init(&alpha);
+  BN_init(&beta);
+  BN_init(&gamma);
+  BN_init(&delta);
+  BN_init(&p1a);
+  BN_init(&BETA);
+  BN_init(&GAMMA);
+  BN_init(&DELTA);
+  if ((ctx = BN_CTX_new()) == NULL) goto err;
+  if ((pmont = BN_MONT_CTX_new()) == NULL) goto err;
+  if (! BN_MONT_CTX_set(pmont, dsa->p, ctx)) goto err;
+
+  num = BN_num_bytes(dsa->p);
+
+  /* set p1a to be equal to p-1-x, where x is the private key */
+  if (BN_copy(&p1a, dsa->p) == NULL) goto err;
+  if (! BN_sub_word(&p1a, 1)) goto err;
+  if (! BN_sub(&p1a, &p1a, dsa->priv_key)) goto err;
+
+  if ((buf = (unsigned char *)Malloc(num)) == NULL) {
+    ElGamalerr(ELGAMAL_F_ELGAMAL_PRIVATE_DECRYPT, ERR_R_MALLOC_FAILURE);
+    goto err;
+  }
+
+  if (flen > num*2) {
+    ElGamalerr(ELGAMAL_F_ELGAMAL_PRIVATE_DECRYPT, ELGAMAL_R_DATA_GREATER_THAN_MOD_LEN);
+    goto err;
+  }
+
+  /* Copy the cipher text into the two numbers alpha and beta */
+  if (BN_bin2bn(from, flen / 2, &alpha) == NULL) goto err;
+  if (BN_bin2bn(&(from[flen/2]), flen / 2, &beta) == NULL) goto err;
+  
+  if (! BN_mod_exp_mont(&gamma, &alpha, &p1a, dsa->p, ctx, pmont)) goto err;
+  BN_to_montgomery(&GAMMA, &gamma, pmont, ctx);
+  BN_to_montgomery(&BETA, &beta, pmont, ctx);
+  if (! BN_mod_mul_montgomery(&DELTA, &GAMMA, &BETA, pmont, ctx)) goto err;
+  BN_from_montgomery(&delta, &DELTA, pmont, ctx);
+
+  /* Now delta should contain the (possibly padded) plaintext */
+  p = buf;
+  j = BN_bn2bin(&delta, p);
+
+  switch( padding ) {
+  case ELGAMAL_PKCS1_PADDING:
+    r = RSA_padding_check_PKCS1_type_2(to, num, buf, j, num);
+    break;
+  case ELGAMAL_PKCS1_OAEP_PADDING:
+    r = RSA_padding_check_PKCS1_OAEP(to, num, buf, j, num, NULL, 0);
+    break;
+  case ELGAMAL_NO_PADDING:
+    r = RSA_padding_check_none(to, num, buf, j, num);
+    break;
+  default:
+    ElGamalerr(ELGAMAL_F_ELGAMAL_PRIVATE_DECRYPT, ELGAMAL_R_UNKNOWN_PADDING_TYPE);
+    goto err;
+  }
+
+  if (r < 0)
+    ElGamalerr(ELGAMAL_F_ELGAMAL_PRIVATE_DECRYPT, ELGAMAL_R_PADDING_CHECK_FAILED);
+
+ err:
+  if (ctx != NULL) BN_CTX_free(ctx);
+  if (pmont != NULL) BN_MONT_CTX_free(pmont);
+  BN_clear_free(&alpha);
+  BN_clear_free(&beta);
+  BN_clear_free(&gamma);
+  BN_clear_free(&delta);
+  BN_clear_free(&p1a);
+  BN_clear_free(&BETA);
+  BN_clear_free(&GAMMA);
+  BN_clear_free(&DELTA);
+  if (buf != NULL) {
+    memset(buf, 0, num);
+    Free(buf);
+  }
+  return r;
+}
+bool
+valid_ciphertext_length( const u_int32_t len, struct connection *c )
+{
+  EVP_PKEY *pk = c->key;
+  bool ret = FALSE;
+
+  if ((!pk) || (len == 0)) return FALSE;
+  switch(pk->type) {
+  case EVP_PKEY_RSA:
+    if (len % BN_num_bytes(pk->pkey.rsa->n) == 0) ret = TRUE;
+    break;
+  case EVP_PKEY_DSA:
+    if (len % (2 * BN_num_bytes(pk->pkey.dsa->p)) == 0) ret = TRUE;
+    break;
+  default:
+    return FALSE;
+  }
+
+  return ret;
+}
+
+static void
+alloc_ciphertext( const u_int32_t len,
+		  EVP_PKEY *pk,
+		  u_char **c,
+		  u_int32_t *ms,
+		  u_int32_t *bsize,
+		  u_int32_t *bl )
+{
+  int modsize, chunksize, blocks;
+  const int padsize = 2 * SHA1_DIGEST_SIZE - 1;
+  u_int32_t clen;
+
+  switch(pk->type)
+    {
+    case EVP_PKEY_RSA:
+      {
+	RSA *rsa = pk->pkey.rsa;
+	modsize = BN_num_bytes(rsa->n);
+      }
+      break;
+    case EVP_PKEY_DSA:
+      {
+	DSA *dsa = pk->pkey.dsa;
+	modsize = BN_num_bytes(dsa->p) * 2;
+      }
+      break;
+    }
+  chunksize = modsize - padsize;
+  blocks = (len + chunksize - 1) / chunksize;
+  clen = blocks * modsize;
+  *c = malloc(clen);
+  *bsize = chunksize;
+  *bl = blocks;
+  *ms = modsize;
+}
+
+void
+pubkey_encrypt_chunk( chunk_t *ch, struct state *st )
+{
+  struct connection *c = st->st_connection;
+  u_char *str = ch->ptr;
+  u_int32_t len = ch->len;
+  EVP_PKEY *pk = NULL;
+  u_char *ciph;
+  u_int32_t ms, bs, bl, clen;
+  u_int16_t auth = st->st_oakley.auth;
+  int i;
+
+  switch(auth) {
+  case OAKLEY_RSA_ENC:
+  case OAKLEY_RSA_ENC_REV:
+    for(i=0; i<MAX_OTHER; i++) {
+      if ((c->other[i].type == EVP_PKEY_RSA) &&
+	  (c->other[i].cert != NULL)) {
+	pk = X509_get_pubkey((X509 *)c->other[i].cert);
+	break;
+      }
+    }
+    break;
+  case OAKLEY_ELGAMAL_ENC:
+  case OAKLEY_ELGAMAL_ENC_REV:
+    for(i=0; i<MAX_OTHER; i++) {
+      if ((c->other[i].type == EVP_PKEY_DSA) &&
+	  (c->other[i].cert != NULL)) {
+	pk = X509_get_pubkey((X509 *)c->other[i].cert);
+	break;
+      }
+    }
+    break;
+  default:
+    DBG(DBG_PARSING,
+    DBG_log("Non PK authentication scheme in state");
+    );
+    return;
+  }
+
+  if (!pk) {
+    DBG(DBG_PARSING,
+    log("Unable to select an encryption key");
+    );
+    return;
+  }
+
+  switch(pk->type) {
+  case EVP_PKEY_RSA:
+    {
+      alloc_ciphertext(len, pk, &ciph, &ms, &bs, &bl);
+    }
+    break;
+  case EVP_PKEY_DSA:
+    {
+      alloc_ciphertext(len, pk, &ciph, &ms, &bs, &bl);
+    }
+    break;
+  default:
+    log("Unknown key type: %d", pk->type);
+    break;
+  }
+
+  for(i=0; i<bl; i++) {
+    u_char *pst = &str[i * bs];
+    u_char *cst = &ciph[i * ms];
+    u_int32_t plen = (i < bl-1) ? bs : len % bs;
+
+    switch(pk->type) {
+    case EVP_PKEY_RSA:
+      {
+	RSA *rsa = pk->pkey.rsa;
+	
+	clen = RSA_public_encrypt(plen, pst, cst, rsa, RSA_PKCS1_OAEP_PADDING);
+      }
+      break;
+    case EVP_PKEY_DSA:
+      {
+	DSA *dsa = pk->pkey.dsa;
+
+	clen = ElGamal_public_encrypt(plen, pst, cst, dsa, ELGAMAL_PKCS1_OAEP_PADDING);
+      }
+      break;
+    default:
+      log("Unknown cert type: %d", pk->type);
+      break;
+    }
+  }
+
+  memset(ch->ptr, 0, ch->len);
+  freeanychunk(*ch);
+  ch->len=bl*ms;
+  ch->ptr=ciph;
+}
+
+void
+privkey_decrypt_chunk( chunk_t *ch, struct state *st )
+{
+  u_int32_t i, bl, bs, clen;
+  struct connection *c = st->st_connection;
+  EVP_PKEY *pk = c->key;
+  u_char *str = ch->ptr;
+  u_char *pst;
+  u_int32_t ptr, plen;
+
+  switch(pk->type) {
+  case EVP_PKEY_RSA:
+    {
+      RSA *rsa = pk->pkey.rsa;
+      bs = BN_num_bytes(rsa->n);
+    }
+    break;
+  case EVP_PKEY_DSA:
+    {
+      DSA *dsa = pk->pkey.dsa;
+      bs = 2 * BN_num_bytes(dsa->p);
+    }
+    break;
+  default:
+    log("Unknown key type: %d", pk->type);
+    break;
+  }
+  clen = ch->len;
+  bl = clen / bs;
+  pst = malloc(clen);
+  ptr = 0;
+  for(i=0; i<bl; i++) {
+    switch(pk->type) {
+    case EVP_PKEY_RSA:
+      {
+	RSA *rsa = pk->pkey.rsa;
+	if (clen >= bs) {
+	  plen = RSA_private_decrypt( bs, &str[i * bs], &pst[ptr], rsa, RSA_PKCS1_OAEP_PADDING );
+	  if (plen == 0) {
+	    log_err();
+	  }
+	} else /* Ciphertext is too short */
+	  plen = 0;
+      }
+      break;
+    case EVP_PKEY_DSA:
+      {
+	DSA *dsa = pk->pkey.dsa;
+	
+	if (clen >= bs) {
+	  plen = ElGamal_private_decrypt( bs, &str[i * bs], &pst[ptr], dsa, ELGAMAL_PKCS1_OAEP_PADDING );
+	  if (plen == 0) {
+	    log_err();
+	  }
+	} else /* Short ciphertext - don't try and decrypt */
+	  plen = 0;
+      }
+      break;
+    default:
+      log("Unknown key type: %d", pk->type);
+      plen = 0;
+      break;
+    }
+    ptr += plen;
+  }
+  freeanychunk(*ch);
+  ch->ptr = pst;
+  ch->len = ptr;
+}
+
+bool
+use_openssl( struct connection *c )
+{
+// Using data from connection *c, we can determine if we are currently using 
+// the openssl-related functions or not.
+// ie: 
+//   c->cert
+//   c->key
+//   c->cert_options
+//
+// also use c->policy to determine policy.
+//
+// Return 0 if openssl, otherwise 1.
+
+	if (c->policy & POLICY_OPENSSL) {
+		if ((c->cert != NULL) || 
+			(c->key != NULL) || 
+			(c->cert_options != 0)) 
+		{
+			// OPENSSL
+			return 1;
+		}
+		else
+		{
+			// RSASIG only
+			return 0;
+		}
+	}
+    else 
+	{
+		// PSK
+		return 0;
+	}
+}
+
+#endif /* OPENSSL */
diff -ruN freeswan-1.5.orig/pluto/openssl.h freeswan-1.5/pluto/openssl.h
--- freeswan-1.5.orig/pluto/openssl.h	Wed Dec 31 19:00:00 1969
+++ freeswan-1.5/pluto/openssl.h	Thu Oct  5 07:05:59 2000
@@ -0,0 +1,87 @@
+#ifdef OPENSSL
+#ifndef OPENSSL_INC_H
+#define OPENSSL_INC_H
+
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/safestack.h>
+
+#include <freeswan.h>
+
+#include "xmap.h"
+
+struct _x509_cert_node {
+  X509 *x;
+  struct _x509_cert_node *next;
+};
+
+typedef struct _x509_cert_node *X509_cert_list;
+
+typedef bool discrim_fn( X509 *x, STACK_OF(XMAP) *lu,
+			 struct payload_digest *const id_pld, bool strict);
+
+extern void make_lookups(STACK_OF(XMAP) **lu, const char *spec );
+extern void log_err( void );
+extern void load_cert_and_key( const char *cert, const char *key,
+			       X509 **x, EVP_PKEY **k );
+extern bool use_openssl( struct connection *c );
+extern STACK_OF(X509) *
+peer_cert_list( STACK_OF(XMAP) *lu,
+		int type,
+		X509 *cert, struct payload_digest *const id_pld,
+		bool strict );
+
+extern bool have_rsa_key( struct state *st );
+extern bool have_dss_key( struct state *st );
+extern bool have_rsa_keypair( struct state *st );
+extern bool have_elgamal_keypair( struct state *st );
+
+extern bool verify_certificate( X509 *x, STACK_OF(XMAP) *lu,
+				const char *path, bool strict );
+
+extern u_int32_t parse_options( const char *s );
+
+extern int DSA_sign_raw(unsigned char *dgst,int dlen,
+			unsigned char *sig, unsigned int *siglen, DSA *dsa);
+
+extern int DSA_verify_raw(const unsigned char *dgst,int dgst_len,
+			  unsigned char *sigbuf, int siglen, DSA *dsa);
+
+#define ERR_LIB_ELGAMAL 127
+
+#define ELGAMAL_F_ELGAMAL_PRIVATE_DECRYPT 100
+#define ELGAMAL_F_ELGAMAL_PUBLIC_ENCRYPT  101
+
+#define ELGAMAL_R_UNKNOWN_PADDING_TYPE      100
+#define ELGAMAL_R_DATA_GREATER_THAN_MOD_LEN 101
+#define ELGAMAL_R_PADDING_CHECK_FAILED      102
+
+#define ELGAMAL_PKCS1_PADDING RSA_PKCS1_PADDING
+#define ELGAMAL_PKCS1_OAEP_PADDING RSA_PKCS1_OAEP_PADDING
+#define ELGAMAL_NO_PADDING RSA_NO_PADDING
+
+#define ElGamalerr(f, r) ERR_PUT_error(ERR_LIB_ELGAMAL, (f), (r), ERR_file_name, __LINE__)
+
+void ERR_load_ElGamal_strings( void );
+int ElGamal_public_check( DSA *dsa );
+int ElGamal_public_encrypt( int flen, unsigned char *from,
+			    unsigned char *to,
+			    DSA *dsa, int padding );
+int ElGamal_private_decrypt( int flen, unsigned char *from,
+			     unsigned char *to,
+			     DSA *dsa, int padding );
+
+/* Function pointer pointing to an encryption routine */
+typedef void encryptor_fn( chunk_t *ch, struct state *c );
+
+extern bool valid_ciphertext_length( const u_int32_t len,
+				     struct connection *c );
+extern encryptor_fn pubkey_encrypt_chunk, privkey_decrypt_chunk;
+
+#endif
+#endif
+
+
diff -ruN freeswan-1.5.orig/pluto/openssl_defs.h freeswan-1.5/pluto/openssl_defs.h
--- freeswan-1.5.orig/pluto/openssl_defs.h	Wed Dec 31 19:00:00 1969
+++ freeswan-1.5/pluto/openssl_defs.h	Thu Oct  5 07:05:59 2000
@@ -0,0 +1,5 @@
+
+#define FILE_NAME_LIMIT 80
+#define PATH_NAME_LIMIT 256
+#define CERT_OPTIONS_LIMIT 128
+#define MAX_OTHER 2 /* only know about two type of certificate at the moment (RSA,DSA) */
diff -ruN freeswan-1.5.orig/pluto/packet.c freeswan-1.5/pluto/packet.c
--- freeswan-1.5.orig/pluto/packet.c	Wed Jun 21 14:24:34 2000
+++ freeswan-1.5/pluto/packet.c	Thu Oct  5 07:05:59 2000
@@ -623,7 +623,7 @@
 	/* put at least one * out */
 	for (;;)
 	{
-	    if (pre <= space)
+	  if (pre <= space)
 		break;
 	    *--pre = '*';
 	    if (p == NULL)
diff -ruN freeswan-1.5.orig/pluto/spdb.c freeswan-1.5/pluto/spdb.c
--- freeswan-1.5.orig/pluto/spdb.c	Wed Jun 21 14:24:35 2000
+++ freeswan-1.5/pluto/spdb.c	Thu Oct  5 07:05:59 2000
@@ -39,6 +39,11 @@
 #include "md5.h"
 #include "crypto.h" /* requires sha1.h and md5.h */
 
+#ifdef OPENSSL
+#include "demux.h"
+#include "openssl.h"
+#endif
+
 #define AD(x) x, elemsof(x)	/* Array Description */
 
 /**************** Oakely (main mode) SA database ****************/
@@ -103,6 +108,86 @@
 	{ OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 },
 	};
 
+#ifdef OPENSSL /* !OPENSSL */
+
+static struct db_attr ot1024des3md5_ds_rsa[] = {
+	{ OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC },
+	{ OAKLEY_HASH_ALGORITHM, OAKLEY_MD5 },
+	{ OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG },
+	{ OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 },
+	};
+
+static struct db_attr ot1024des3sha_ds_rsa[] = {
+	{ OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC },
+	{ OAKLEY_HASH_ALGORITHM, OAKLEY_SHA },
+	{ OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG },
+	{ OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 },
+	};
+
+static struct db_attr ot1024des3sha_ds_dss[] = {
+	{ OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC },
+	{ OAKLEY_HASH_ALGORITHM, OAKLEY_SHA },
+	{ OAKLEY_AUTHENTICATION_METHOD, OAKLEY_DSS_SIG },
+	{ OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 },
+	};
+
+static struct db_attr ot1024des3md5_pk_rsa[] = {
+	{ OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC },
+	{ OAKLEY_HASH_ALGORITHM, OAKLEY_MD5 },
+	{ OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_ENC },
+	{ OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 },
+	};
+
+static struct db_attr ot1024des3sha_pk_rsa[] = {
+	{ OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC },
+	{ OAKLEY_HASH_ALGORITHM, OAKLEY_SHA },
+	{ OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_ENC },
+	{ OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 },
+	};
+
+static struct db_attr ot1024des3sha_pk_elgamal[] = {
+	{ OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC },
+	{ OAKLEY_HASH_ALGORITHM, OAKLEY_SHA },
+	{ OAKLEY_AUTHENTICATION_METHOD, OAKLEY_ELGAMAL_ENC },
+	{ OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 },
+	};
+
+static struct db_attr ot1024des3md5_pk_elgamal[] = {
+	{ OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC },
+	{ OAKLEY_HASH_ALGORITHM, OAKLEY_MD5 },
+	{ OAKLEY_AUTHENTICATION_METHOD, OAKLEY_ELGAMAL_ENC },
+	{ OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 },
+	};
+
+static struct db_attr ot1024des3md5_rpk_rsa[] = {
+	{ OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC },
+	{ OAKLEY_HASH_ALGORITHM, OAKLEY_MD5 },
+	{ OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_ENC_REV },
+	{ OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 },
+	};
+
+static struct db_attr ot1024des3sha_rpk_rsa[] = {
+	{ OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC },
+	{ OAKLEY_HASH_ALGORITHM, OAKLEY_SHA },
+	{ OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_ENC_REV },
+	{ OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 },
+	};
+
+static struct db_attr ot1024des3sha_rpk_elgamal[] = {
+	{ OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC },
+	{ OAKLEY_HASH_ALGORITHM, OAKLEY_SHA },
+	{ OAKLEY_AUTHENTICATION_METHOD, OAKLEY_ELGAMAL_ENC_REV },
+	{ OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 },
+	};
+
+static struct db_attr ot1024des3md5_rpk_elgamal[] = {
+	{ OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC },
+	{ OAKLEY_HASH_ALGORITHM, OAKLEY_MD5 },
+	{ OAKLEY_AUTHENTICATION_METHOD, OAKLEY_ELGAMAL_ENC_REV },
+	{ OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 },
+	};
+#endif /* OPENSSL */
+
 /* We won't accept this, but by proposing it, we get to test
  * our rejection.  We better not propose it to an IKE daemon
  * that will accept it!
@@ -118,6 +203,7 @@
 
 /* tables of transforms, in preference order (select based on AUTH) */
 
+
 static struct db_trans oakley_trans_psk[] = {
 #ifdef TEST_INDECENT_PROPOSAL
 	{ KEY_IKE, AD(otpsk1024des3tiger) },
@@ -152,6 +238,53 @@
 	{ KEY_IKE, AD(otpsk768des3sha) },
     };
 
+#ifdef OPENSSL
+
+static struct db_trans oakley_trans_psk2[] = {
+#ifdef TEST_INDECENT_PROPOSAL
+	{ KEY_IKE, AD(otpsk1024des3tiger), NULL },
+#endif
+	{ KEY_IKE, AD(otpsk1024des3sha), NULL },
+	{ KEY_IKE, AD(otpsk1024des3md5), NULL },
+	{ KEY_IKE, AD(otpsk768des3md5), NULL },
+	{ KEY_IKE, AD(otpsk768des3sha), NULL },
+    };
+
+static struct db_trans oakley_trans_openssl[] = {
+  { KEY_IKE, AD(ot1024des3sha_rpk_elgamal), have_elgamal_keypair },
+  { KEY_IKE, AD(ot1024des3sha_rpk_rsa), have_rsa_keypair },
+  { KEY_IKE, AD(ot1024des3md5_rpk_elgamal), have_elgamal_keypair },
+  { KEY_IKE, AD(ot1024des3md5_rpk_rsa), have_rsa_keypair },
+  { KEY_IKE, AD(ot1024des3sha_pk_elgamal), have_elgamal_keypair },
+  { KEY_IKE, AD(ot1024des3sha_pk_rsa), have_rsa_keypair },
+  { KEY_IKE, AD(ot1024des3md5_pk_elgamal), have_elgamal_keypair },
+  { KEY_IKE, AD(ot1024des3md5_pk_rsa), have_rsa_keypair },
+  { KEY_IKE, AD(ot1024des3sha_ds_dss), have_dss_key },
+  { KEY_IKE, AD(ot1024des3sha_ds_rsa), have_rsa_key },
+  { KEY_IKE, AD(ot1024des3md5_ds_rsa), have_rsa_key },
+  };
+
+static struct db_trans oakley_trans_psk2openssl[] = {
+  { KEY_IKE, AD(ot1024des3sha_rpk_elgamal), have_elgamal_keypair },
+  { KEY_IKE, AD(ot1024des3sha_rpk_rsa), have_rsa_keypair },
+  { KEY_IKE, AD(ot1024des3md5_rpk_elgamal), have_elgamal_keypair },
+  { KEY_IKE, AD(ot1024des3md5_rpk_rsa), have_rsa_keypair },
+  { KEY_IKE, AD(ot1024des3sha_pk_elgamal), have_elgamal_keypair },
+  { KEY_IKE, AD(ot1024des3sha_pk_rsa), have_rsa_keypair },
+  { KEY_IKE, AD(ot1024des3md5_pk_elgamal), have_elgamal_keypair },
+  { KEY_IKE, AD(ot1024des3md5_pk_rsa), have_rsa_keypair },
+  { KEY_IKE, AD(ot1024des3sha_ds_dss), have_dss_key },
+  { KEY_IKE, AD(ot1024des3sha_ds_rsa), have_rsa_key },
+  { KEY_IKE, AD(ot1024des3md5_ds_rsa), have_rsa_key },
+  { KEY_IKE, AD(otpsk1024des3sha), NULL },
+  { KEY_IKE, AD(otpsk1024des3md5), NULL },
+  { KEY_IKE, AD(otpsk768des3md5), NULL },
+  { KEY_IKE, AD(otpsk768des3sha), NULL },
+  };
+#endif
+
+
+
 /* array of proposals to be conjoined (can only be one for Oakley) */
 
 static struct db_prop oakley_pc_psk[] =
@@ -163,6 +296,17 @@
 static struct db_prop oakley_pc_pskrsasig[] =
     { { PROTO_ISAKMP, AD(oakley_trans_pskrsasig) } };
 
+#ifdef OPENSSL
+static struct db_prop oakley_pc_psk2[] =
+    { { PROTO_ISAKMP, AD(oakley_trans_psk2) } };
+
+static struct db_prop oakley_pc_openssl[] =
+    { { PROTO_ISAKMP, AD(oakley_trans_openssl) } };
+
+static struct db_prop oakley_pc_psk2openssl[] =
+    { { PROTO_ISAKMP, AD(oakley_trans_psk2openssl) } };
+#endif
+
 /* array of proposal conjuncts (can only be one) */
 
 static struct db_prop_conj oakley_props_psk[] = { { AD(oakley_pc_psk) } };
@@ -171,6 +315,14 @@
 
 static struct db_prop_conj oakley_props_pskrsasig[] = { { AD(oakley_pc_pskrsasig) } };
 
+#ifdef OPENSSL
+static struct db_prop_conj oakley_props_psk2[] = { { AD(oakley_pc_psk2) } };
+
+static struct db_prop_conj oakley_props_openssl[] = { { AD(oakley_pc_openssl) } };
+
+static struct db_prop_conj oakley_props_psk2openssl[] = { { AD(oakley_pc_psk2openssl) } };
+#endif
+
 /* the sadb entry, subscripted by POLICY_PSK and POLICY_RSASIG bits */
 struct db_sa oakley_sadb[] = {
     { NULL, 0 },	/* none */
@@ -179,6 +331,16 @@
     { AD(oakley_props_pskrsasig) },	/* POLICY_PSK + POLICY_RSASIG */
     };
 
+#ifdef OPENSSL
+/* the sadb entry, subscripted by POLICY_PSK and POLICY_OPENSSL bits */
+struct db_sa oakley_sadb2[] = {
+    { NULL, 0 },	/* none */
+    { AD(oakley_props_psk2) },	/* POLICY_PSK */
+    { AD(oakley_props_openssl) },	/* POLICY_OPENSSL */
+    { AD(oakley_props_psk2openssl) },	/* POLICY_PSK + POLICY_OPENSSL */
+    };
+#endif
+
 /**************** IPsec (quick mode) SA database ****************/
 
 /* arrays of attributes for transforms */
@@ -234,27 +396,51 @@
 /* arrays of transforms, each in in preference order */
 
 static struct db_trans espa_trans_tunnel[] = {
+#ifndef OPENSSL
     { ESP_3DES, AD(espmd5_attr_tunnel) },
     { ESP_3DES, AD(espsha1_attr_tunnel) },
+#else
+    { ESP_3DES, AD(espmd5_attr_tunnel), NULL },
+    { ESP_3DES, AD(espsha1_attr_tunnel), NULL },
+#endif
     };
 
 static struct db_trans espa_trans_transport[] = {
+#ifndef OPENSSL
     { ESP_3DES, AD(espmd5_attr_transport) },
     { ESP_3DES, AD(espsha1_attr_transport) },
+#else
+    { ESP_3DES, AD(espmd5_attr_transport), NULL },
+    { ESP_3DES, AD(espsha1_attr_transport), NULL },
+#endif
     };
 
 static struct db_trans esp_trans_tunnel[] = {
+#ifndef OPENSSL
     { ESP_3DES, AD(esp_attr_tunnel) },
+#else
+    { ESP_3DES, AD(esp_attr_tunnel), NULL },
+#endif
     };
 
 static struct db_trans esp_trans_transport[] = {
+#ifndef OPENSSL
     { ESP_3DES, AD(esp_attr_transport) },
+#else
+    { ESP_3DES, AD(esp_attr_transport), NULL },
+#endif
     };
 
 #ifdef SUPPORT_ESP_NULL
 static struct db_trans espnull_trans_tunnel[] = {
+#ifndef OPENSSL
     { ESP_NULL, AD(espmd5_attr_tunnel) },
     { ESP_NULL, AD(espsha1_attr_tunnel) },
+#else
+    { ESP_NULL, AD(espmd5_attr_tunnel), NULL },
+    { ESP_NULL, AD(espsha1_attr_tunnel), NULL },
+#endif
+
     };
 
 static struct db_trans espnull_trans_transport[] = {
@@ -264,13 +450,23 @@
 #endif /* SUPPORT_ESP_NULL */
 
 static struct db_trans ah_trans_tunnel[] = {
+#ifndef OPENSSL
     { AH_MD5, AD(ah_HMAC_MD5_attr_tunnel) },
     { AH_SHA, AD(ah_HMAC_SHA1_attr_tunnel) },
+#else
+    { AH_MD5, AD(ah_HMAC_MD5_attr_tunnel), NULL },
+    { AH_MD5, AD(ah_HMAC_SHA1_attr_tunnel), NULL },
+#endif
     };
 
 static struct db_trans ah_trans_transport[] = {
+#ifndef OPENSSL
     { AH_MD5, AD(ah_HMAC_MD5_attr_transport) },
     { AH_SHA, AD(ah_HMAC_SHA1_attr_transport) },
+#else
+    { AH_MD5, AD(ah_HMAC_MD5_attr_transport), NULL },
+    { AH_MD5, AD(ah_HMAC_SHA1_attr_transport), NULL },
+#endif
     };
 
 /* arrays of proposals to be conjoined */
@@ -464,7 +660,18 @@
 	    proposal.isap_proposal = pcn;
 	    proposal.isap_protoid = p->protoid;
 	    proposal.isap_spisize = oakley_mode? 0 : IPSEC_DOI_SPI_SIZE;
+#ifndef OPENSSL
 	    proposal.isap_notrans = p->trans_cnt;
+#else
+	    proposal.isap_notrans = 0;
+	    for(tn = 0; tn < p->trans_cnt; tn++) {
+	      struct db_trans *t = &(p->trans[tn]);
+	      if (t->offer == NULL)
+		proposal.isap_notrans++;
+	      else if ((t->offer(st))) /* only offer a propsal if we can carry it out */
+		proposal.isap_notrans++;
+	    }
+#endif
 	    if (!out_struct(&proposal, &isakmp_proposal_desc, &sa_pbs, &proposal_pbs))
 		return FALSE;
 
@@ -537,6 +744,14 @@
 
 		trans.isat_np = (tn == p->trans_cnt - 1)
 		    ? ISAKMP_NEXT_NONE : ISAKMP_NEXT_T;
+#ifdef OPENSSL
+		if ((t->offer != NULL) && ((t->offer)(st) == FALSE)) {
+		  DBG(DBG_PARSING,
+		  DBG_log("Skipping unavailable cipher: %d", tn);
+		  );
+		  continue; /* skip unavailable cipher */
+		}
+#endif
 		trans.isat_transnum = tn;
 		trans.isat_transid = t->transid;
 		if (!out_struct(&trans, trans_desc, &proposal_pbs, &trans_pbs))
@@ -629,6 +844,180 @@
     return val;
 }
 
+#ifdef OPENSSL
+struct _trans_node {
+  struct oakley_trans_attrs ta;
+  struct isakmp_transform trans;
+  u_char *attr_start;
+  size_t attr_len;
+  bool elim; /* has this node been eliminated from the selection process */
+  struct _trans_node *next;
+};
+
+typedef struct _trans_node *trans_list;
+
+/* Free a list of Oakley transforms */
+static void
+trans_list_free( trans_list *l )
+{
+  trans_list p;
+
+  if (!l) return;
+  while (*l) {
+    p = *l;
+    *l = p->next;
+    pfree(p->attr_start);
+    pfree(p);
+  }
+}
+
+static void
+trans_list_append(trans_list *l,
+		  struct oakley_trans_attrs *ta,
+		  struct isakmp_transform *trans,
+		  u_char *attr_start,
+		  size_t attr_len) {
+  trans_list p, pp;
+
+  if (!l) return;
+  if ((p = alloc_bytes(sizeof(struct _trans_node),
+		       "transformation node")) == NULL) return;
+  p->ta = *ta;
+  p->trans = *trans;
+  p->attr_len = attr_len;
+  if ((p->attr_start = alloc_bytes(attr_len, "attribute")) == NULL) {
+    pfree(p);
+    return;
+  }
+  memcpy(p->attr_start, attr_start, attr_len);
+  p->elim = FALSE;
+  p->next = NULL;
+  if (*l == NULL) {
+    *l = p;
+  } else {
+    for(pp = *l; pp->next ; pp = pp->next);
+    pp->next = p;
+  }
+}
+
+static bool
+select_trans_candidate(trans_list l,
+		       struct oakley_trans_attrs *ta,
+		       struct isakmp_transform *trans,
+		       u_char **attr_start,
+		       size_t *attr_len,
+		       u_int32_t opts)
+{
+  bool ret = FALSE;
+  trans_list auth[OAKLEY_ELGAMAL_ENC_REV+1], p;
+  uint i, numprefs, pref[10];
+
+  if (!l) {
+	DBG(DBG_PARSING,
+    DBG_log("No candidate transforms to choose from");
+	);
+    return FALSE;
+  }
+
+  if ((!ta) || (!attr_len) || (!trans) || (!attr_start)) {
+	DBG(DBG_PARSING,
+    DBG_log("No space to store selected transform");
+	);
+    return FALSE;
+  }
+
+  /* Separate all elements of the list by authentication method */
+
+  for(i=OAKLEY_PRESHARED_KEY; i<=OAKLEY_ELGAMAL_ENC_REV; i++)
+    auth[i] = NULL;
+  for(p=l; p; p=p->next)
+    if ((p->ta.auth >= OAKLEY_PRESHARED_KEY) &&
+	(p->ta.auth <= OAKLEY_ELGAMAL_ENC_REV )) {
+      trans_list_append(&(auth[p->ta.auth]),
+			&(p->ta),
+			&(p->trans),
+			p->attr_start,
+			p->attr_len);
+    }
+
+  numprefs = 7;
+  pref[numprefs-1] = OAKLEY_PRESHARED_KEY;
+  DBG(DBG_PARSING | DBG_CRYPT,
+  DBG_log("select_trans_candidate: %08x", opts);
+  );
+  if (opts & CERT_OPTION_PK) {
+    if (opts & CERT_OPTION_REV) {
+      DBG(DBG_PARSING | DBG_CRYPT,
+      DBG_log("Preferring revised PK encryption schemes");
+      );
+      pref[0] = OAKLEY_ELGAMAL_ENC_REV;
+      pref[1] = OAKLEY_RSA_ENC_REV;
+      pref[2] = OAKLEY_ELGAMAL_ENC;
+      pref[3] = OAKLEY_RSA_ENC;
+      pref[4] = OAKLEY_RSA_SIG;
+      pref[5] = OAKLEY_DSS_SIG;
+    } else {
+      DBG(DBG_PARSING | DBG_CRYPT,
+      DBG_log("Preferring standard PK encryption schemes");
+      );
+      pref[0] = OAKLEY_ELGAMAL_ENC;
+      pref[1] = OAKLEY_RSA_ENC;
+      pref[2] = OAKLEY_ELGAMAL_ENC_REV;
+      pref[3] = OAKLEY_RSA_ENC_REV;
+      pref[4] = OAKLEY_RSA_SIG;
+      pref[5] = OAKLEY_DSS_SIG;
+    }
+  } else {
+    if (opts & CERT_OPTION_REV) {
+      DBG(DBG_PARSING | DBG_CRYPT,
+      DBG_log("Preferring digisig schemes, then revised pk");
+      );
+      pref[0] = OAKLEY_RSA_SIG;
+      pref[1] = OAKLEY_DSS_SIG;
+      pref[2] = OAKLEY_ELGAMAL_ENC_REV;
+      pref[3] = OAKLEY_RSA_ENC_REV;
+      pref[4] = OAKLEY_ELGAMAL_ENC;
+      pref[5] = OAKLEY_RSA_ENC;
+    } else {
+      DBG(DBG_PARSING | DBG_CRYPT,
+      DBG_log("Preferring digisig schemes, then standard pk");
+      );
+      pref[0] = OAKLEY_RSA_SIG;
+      pref[1] = OAKLEY_DSS_SIG;
+      pref[2] = OAKLEY_ELGAMAL_ENC;
+      pref[3] = OAKLEY_RSA_ENC;
+      pref[4] = OAKLEY_ELGAMAL_ENC_REV;
+      pref[5] = OAKLEY_RSA_ENC_REV;
+    }
+  }
+
+  for(i=0; ((i<numprefs) && (!ret)); i++) {
+    DBG(DBG_PARSING,
+    DBG_log("Trying out: %s", enum_show(&oakley_auth_names, pref[i]));
+    );
+    if ((pref[i]) && (auth[pref[i]])) {
+      ret = TRUE;
+      *ta = auth[pref[i]]->ta;
+      *trans = auth[pref[i]]->trans;
+      *attr_start = alloc_bytes(auth[pref[i]]->attr_len, "attribute");
+      if (*attr_start) {
+	*attr_len = auth[pref[i]]->attr_len;
+	memcpy(*attr_start, auth[pref[i]]->attr_start, *attr_len);
+      }
+      DBG(DBG_PARSING,
+      DBG_log("Candidate selected: %s", 
+        enum_show(&oakley_auth_names, pref[i]));
+      );
+    }
+}
+  
+  for(i=OAKLEY_PRESHARED_KEY; i<=OAKLEY_RSA_ENC_REV; i++) {
+    trans_list_free(&auth[i]);
+  }
+  return ret;
+}
+#endif
+
 /* Parse the body of an ISAKMP SA Payload (i.e. Phase 1 / Main Mode).
  * Various shortcuts are taken.  In particular, the policy, such as
  * it is, is hardwired.
@@ -658,6 +1047,10 @@
     struct isakmp_proposal proposal;
     unsigned no_trans_left;
     int last_transnum;
+#ifdef OPENSSL
+    bool selected;
+    trans_list tl = NULL;
+#endif
 
     /* DOI */
     if (sa->isasa_doi != ISAKMP_DOI_IPSEC)
@@ -893,10 +1286,48 @@
 				, "policy does not allow OAKLEY_PRESHARED_KEY authentication");
 			}
 			break;
+#ifdef OPENSSL
+		    case OAKLEY_DSS_SIG:
+		      if ((st->st_connection->key == NULL) ||
+			  (((EVP_PKEY *)(st->st_connection->key))->type != EVP_PKEY_DSA))
+			snprintf(ugh, sizeof(ugh), "OAKLEY_DSS_SIG requested, but no DSA key available to sign with");
+		      ta.auth = val;
+		      break;
+//		    case OAKLEY_RSA_SIG:
+		    case OAKLEY_RSA_ENC:
+		      if (!have_rsa_keypair(st))
+			snprintf(ugh, sizeof(ugh), "OAKLEY_RSA_ENC requested, but no cert available to encrypt with");
+		      ta.auth = val;
+		      break;
+		    case OAKLEY_ELGAMAL_ENC:
+		      if (!have_elgamal_keypair(st))
+			snprintf(ugh, sizeof(ugh), "OAKLEY_ELGAMAL_ENC requested, but no cert available to encrypt with");
+		      ta.auth = val;
+		      break;
+		    case OAKLEY_RSA_ENC_REV:
+		      if (!have_rsa_keypair(st))
+			snprintf(ugh, sizeof(ugh), "OAKLEY_RSA_ENC_REV requested, but no cert available to encrypt with");
+		      ta.auth = val;
+		      break;
+		    case OAKLEY_ELGAMAL_ENC_REV:
+		      if (!have_elgamal_keypair(st))
+			snprintf(ugh, sizeof(ugh), "OAKLEY_ELGAMAL_ENC_REV requested, but no cert available to encrypt with");
+		      ta.auth = val;
+		      break;
+#endif /* ! OPENSSL */
+
 #ifndef NO_RSA	/* if this is defined, don't accept OAKLEY_RSA_SIG */
+#ifdef OPENSSL
+if (!use_openssl(st->st_connection)) 
+{
+#endif /* OPENSSL, !use_openssl */
 		    case OAKLEY_RSA_SIG:
-			/* Accept if policy specifies RSASIG or is default */
+			/* Accept if policy specifies RSASIG/OPENSSL or is default */
+#ifndef OPENSSL
 			if ((st->st_policy & POLICY_RSASIG)
+#else
+			if ((st->st_policy & POLICY_OPENSSL)
+#endif /* OPENSSL */
 			|| (st->st_policy & POLICY_ISAKMP_MASK) == LEMPTY)
 			{
 			    /* We'd like to check that we can find a public
@@ -915,7 +1346,19 @@
 				, "policy does not allow OAKLEY_RSA_SIG authentication");
 			}
 			break;
-#endif
+#ifdef OPENSSL
+}
+else /* use_openssl */
+{
+		      if ((st->st_connection->key == NULL) ||
+			  (((EVP_PKEY *)(st->st_connection->key))->type != EVP_PKEY_RSA))
+			snprintf(ugh, sizeof(ugh), "OAKLEY_RSA_SIG requested, but no key available to sign with");
+		      ta.auth = val;
+		      break;
+}
+#endif /* OPENSSL, use_openssl */
+#endif /* NO_RSA */
+
 		    default:
 			snprintf(ugh, sizeof(ugh)
 			    , "Pluto does not support %s authentication"
@@ -1030,6 +1473,15 @@
 	     * Lets finish early and leave.
 	     */
 
+#ifdef OPENSSL
+	    /*
+	     * Alternatively, we like this transform, so push it into
+	     * a list of potential winners, and rely on the site policy
+	     * to pick which of the candidates should be chosen
+	     */
+#endif
+
+#ifndef OPENSSL
 	    DBG(DBG_PARSING | DBG_CRYPT,
 		DBG_log("Oakley Transform %u accepted", trans.isat_transnum));
 
@@ -1083,6 +1535,14 @@
 	    /* copy over the results */
 	    st->st_oakley = ta;
 	    return NOTHING_WRONG;
+#else
+	    /*
+	     * We store the ta result into the list of candidates
+	     * Afterwards, site policy dictates which of the
+	     * candidates we should select
+	     */
+	    trans_list_append(&tl, &ta, &trans, attr_start, attr_len);
+#endif
 	}
 
 	/* on to next transform */
@@ -1104,8 +1564,73 @@
 	    return BAD_PROPOSAL_SYNTAX;
 	}
     }
+#ifndef OPENSSL
     loglog(RC_LOG_SERIOUS, "no acceptable Oakley Transform");
     return NO_PROPOSAL_CHOSEN;
+#else
+    /* We should have a list of hopefuls in the list tl */
+    {
+      u_char *attr_start;
+      size_t attr_len;
+      struct isakmp_transform trans;
+
+      selected = select_trans_candidate(tl, &st->st_oakley, &trans, &attr_start, &attr_len, st->st_connection->cert_options);
+      trans_list_free(&tl);
+      if (! selected) {
+  log("no acceptable Oakley Transform");
+  return NO_PROPOSAL_CHOSEN;
+      } else {
+  DBG(DBG_PARSING | DBG_CRYPT,
+      DBG_log("Oakley Transform %u accepted", trans.isat_transnum));
+
+  if (r_sa_pbs != NULL)
+    {
+      struct isakmp_proposal r_proposal = proposal;
+      pb_stream r_proposal_pbs;
+      struct isakmp_transform r_trans = trans;
+      pb_stream r_trans_pbs;
+
+      /* Situation */
+      if (!out_struct(&ipsecdoisit, &ipsec_sit_desc, r_sa_pbs, NULL))
+        passert(FALSE);
+
+      /* Proposal */
+#ifdef EMIT_ISAKMP_SPI
+      r_proposal.isap_spisize = COOKIE_SIZE;
+#else
+      r_proposal.isap_spisize = 0;
+#endif
+      r_proposal.isap_notrans = 1;
+      if (!out_struct(&r_proposal, &isakmp_proposal_desc, r_sa_pbs, &r_proposal_pbs))
+        passert(FALSE);
+
+      /* SPI */
+#ifdef EMIT_ISAKMP_SPI
+      if (!out_raw(my_cookie, COOKIE_SIZE, &r_proposal_pbs, "SPI"))
+        passert(FALSE);
+      r_proposal.isap_spisize = COOKIE_SIZE;
+#else
+      /* none (0) */
+#endif
+
+      /* Transform */
+      r_trans.isat_np = ISAKMP_NEXT_NONE;
+      if (!out_struct(&r_trans, &isakmp_isakmp_transform_desc, &r_proposal_pbs, &r_trans_pbs))
+        passert(FALSE);
+
+      if (!out_raw(attr_start, attr_len, &r_trans_pbs, "attributes"))
+        passert(FALSE);
+      if (attr_start) pfree(attr_start);
+
+      close_output_pbs(&r_trans_pbs);
+      close_output_pbs(&r_proposal_pbs);
+      close_output_pbs(r_sa_pbs);
+    }
+  return NOTHING_WRONG;
+      }
+    }
+#endif
+
 }
 
 /* Parse the body of an IPsec SA Payload (i.e. Phase 2 / Quick Mode).
diff -ruN freeswan-1.5.orig/pluto/spdb.h freeswan-1.5/pluto/spdb.h
--- freeswan-1.5.orig/pluto/spdb.h	Sun Dec 12 19:40:57 1999
+++ freeswan-1.5/pluto/spdb.h	Thu Oct  5 07:05:59 2000
@@ -24,11 +24,32 @@
     u_int16_t val;
 };
 
+#ifdef OPENSSL
+typedef bool offer_fn(struct state *st);
+/* Addition for OpenSSL: we don't want to offer cipher suites */
+/* which we aren't capable of generating, so I added a function */
+/* parameter 'offer', which takes the state as a parameter, and */
+/* returns either TRUE or FALSE, depending on whether the cipher */
+/* suite is supportable. For instance, there's no point in */
+/* offering to sign things with a DSA signature key, if all you've */
+/* got is an RSA one. */
+/* NB: If the function pointer is set to NULL, it means offer the */
+/* cipher suite under all conditions. The downside to this is that */
+/* another parameter must be added to all the IPsec cipher transforms */
+/* which is always NULL. I suppose we could embed policy information */
+/* within that parameter, e.g. If a pair of endpoints must have */
+/* a particular cipher between them. Trouble is, that information is */
+/* present within ipsec.conf, to some extent -- nd */
+#endif
+
 /* transform */
 struct db_trans {
     u_int8_t transid;	/* Transform-Id */
     struct db_attr *attrs;	/* array */
     int attr_cnt;	/* number of elements */
+#ifdef OPENSSL
+    offer_fn *offer;
+#endif
 };
 
 /* proposal */
@@ -56,9 +77,12 @@
 };
 
 /* The oakley sadb is subscripted by a bitset with members
- * from POLICY_PSK and POLICY_RSASIG.
+ * from POLICY_PSK and POLICY_RSASIG/OPENSSL.
  */
 extern struct db_sa oakley_sadb[1 << 2];
+#ifdef OPENSSL
+extern struct db_sa oakley_sadb2[1 << 2];
+#endif
 
 /* The ipsec sadb is subscripted by a bitset with members
  * from POLICY_ENCRYPT, POLICY_AUTHENTICATE, POLICY_TUNNEL
diff -ruN freeswan-1.5.orig/pluto/state.c freeswan-1.5/pluto/state.c
--- freeswan-1.5.orig/pluto/state.c	Wed Jun 21 14:24:35 2000
+++ freeswan-1.5/pluto/state.c	Thu Oct  5 07:05:59 2000
@@ -324,6 +324,16 @@
     pfreeany(st->st_esp.our_keymat);
     pfreeany(st->st_esp.peer_keymat);
 
+#ifdef OPENSSL
+    /* Clean out the stuff for revised PK encryption mode */
+    pfreeany(st->st_ne_i.ptr);
+    memset(&st->st_ks_i, 0, sizeof(st->st_ks_i));
+    memset(st->st_ne_i_iv, 0, MAX_DIGEST_LEN);
+    pfreeany(st->st_ne_r.ptr);
+    memset(&st->st_ks_r, 0, sizeof(st->st_ks_r));
+    memset(st->st_ne_r_iv, 0, MAX_DIGEST_LEN);
+#endif
+
     pfree(st);
 }
 
diff -ruN freeswan-1.5.orig/pluto/state.h freeswan-1.5/pluto/state.h
--- freeswan-1.5.orig/pluto/state.h	Wed Jun 21 14:24:36 2000
+++ freeswan-1.5/pluto/state.h	Thu Oct  5 07:05:59 2000
@@ -64,6 +64,7 @@
 #endif
 };
 
+
 /* IPsec (Phase 2 / Quick Mode) transform and attributes
  * This is a flattened/decoded version of what is represented
  * by a Transaction Payload.  There may be one for AH and one
@@ -144,6 +145,16 @@
     chunk_t            st_gr;                  /* Responder public value */
     u_int8_t           st_rcookie[COOKIE_SIZE];/* Responder Cookie */
     chunk_t            st_nr;                  /* Nr nonce */
+
+#ifdef OPENSSL
+    /* key material for revised public key information */
+    u_int8_t           st_ne_i_iv[MAX_DIGEST_LEN];
+    chunk_t            st_ne_i;                /* key for initiator payloads */
+    keysched           st_ks_i;
+    u_int8_t           st_ne_r_iv[MAX_DIGEST_LEN];
+    chunk_t            st_ne_r;                /* key for responder payloads */
+    keysched           st_ks_r;
+#endif
 
 
   /* my stuff */
diff -ruN freeswan-1.5.orig/pluto/whack.c freeswan-1.5/pluto/whack.c
--- freeswan-1.5.orig/pluto/whack.c	Sun Jun 18 17:20:35 2000
+++ freeswan-1.5/pluto/whack.c	Thu Oct  5 07:05:59 2000
@@ -1,4 +1,6 @@
 /* command interface to Pluto
+ *
+ * Modified by Luc Lanthier based on work from:
  * Copyright (C) 1997 Angelos D. Keromytis.
  * Copyright (C) 1998, 1999  D. Hugh Redelmeier.
  *
@@ -77,6 +79,10 @@
 	    " [--authenticate]"
 	    " [--tunnel]"
 	    " [--pfs]"
+#ifdef OPENSSL
+	    " [--openssl]"
+#endif
+
 	    " \\\n   "
 	    " [--ikelifetime <seconds>]"
 	    " [--ipseclifetime <seconds>]"
@@ -84,6 +90,14 @@
 	    " [--reykeymargin <seconds>]"
 	    " [--reykeyfuzz <percentage>]"
 	    " [--keyingtries <count>]"
+#ifdef OPENSSL
+	    " \\\n   "
+	    " [--certfile <file name>]"
+	    " [--certopts <[!]opt1,[!]opt2,...,[!]optN>]"
+	    " [--peerfile <file name>]"
+	    " [--keyfile <file name>]"
+	    " [--certpath <file name>]"
+#endif
 	    "\n\n"
 	"routing: whack"
 	    " (--route | --unroute)"
@@ -158,47 +172,44 @@
 {
     if (ugh != NULL)
     {
-	char buf[120];
-
-	snprintf(buf, sizeof(buf), "%s \"%s\"", ugh, this);
-	diag(buf);
+      if (this == NULL)
+      {
+          diag(ugh);
+      }
+      else
+      {
+		char buf[120]; /* arbitrary limit */
+
+		snprintf(buf, sizeof(buf), "%s \"%s\"", ugh, this);
+		diag(buf);
+	  }
     }
 }
 
 /* complex combined operands return one of these enumerated values
- * Note: we are close to the limit of 32 flags in an unsigned long!
+ * Note: these become flags in an lset_t.  Since there are more than
+ * 32, we partition them into:
+ * - OPT_* options (most random options)
+ * - DBGOPT_* option (DEBUG options)
+ * - CD_* options (Connection Description options)
  */
 enum {
     OPT_CTLBASE,
     OPT_NAME,
 
-#   define OPT_CD_FIRST OPT_TO	/* first connection description */
-    OPT_TO,
-    OPT_HOST,	/* first per-end */
-    OPT_ID,
-    OPT_IKEPORT,
-    OPT_NEXTHOP,
-    OPT_CLIENT,
-    OPT_UPDOWN,	/* last per-end */
-
-#   define OPT_POLICY_FIRST  OPT_PSK
-    OPT_PSK,	/* same order as POLICY_* */
-    OPT_RSASIG,	/* same order as POLICY_* */
-    OPT_ENCRYPT,	/* same order as POLICY_* */
-    OPT_AUTHENTICATE,	/* same order as POLICY_* */
-    OPT_TUNNEL,	/* same order as POLICY_* */
-    OPT_PFS,	/* same order as POLICY_* */
-
-    OPT_IKELIFETIME,
-    OPT_IPSECLIFETIME,
-    OPT_RKMARGIN,
-    OPT_RKFUZZ,
-    OPT_KTRIES,
-#   define OPT_CD_LAST OPT_KTRIES	/* last connection description */
+	OPT_CD,
 
     OPT_KEYID,
     OPT_PUBKEYRSA,
 
+#ifdef OPENSSL
+    OPT_CERTFILE,
+    OPT_CERTOPTS,
+    OPT_PEERFILE,
+    OPT_KEYFILE,
+    OPT_CERTPATH,
+#endif
+
     OPT_ROUTE,
     OPT_UNROUTE,
 
@@ -210,21 +221,56 @@
     OPT_STATUS,
     OPT_SHUTDOWN,
 
-    OPT_ASYNC
+    OPT_ASYNC,
+#   define OPT_LAST OPT_ASYNC  /* last "normal" option */
+
+/* Connection Description options -- segregated */
+
+#   define CD_FIRST CD_TO      /* first connection description */
+    CD_TO,
+    CD_HOST,   /* first per-end */
+    CD_ID,
+    CD_IKEPORT,
+    CD_NEXTHOP,
+    CD_CLIENT,
+    CD_UPDOWN, /* last per-end */
+
+#   define CD_POLICY_FIRST  CD_PSK
+    CD_PSK,    /* same order as POLICY_* */
+#ifndef OPENSSL
+    CD_RSASIG, /* same order as POLICY_* */
+#else
+    CD_OPENSSL, /* same order as POLICY_* */
+#endif
+    CD_ENCRYPT,        /* same order as POLICY_* */
+    CD_AUTHENTICATE,   /* same order as POLICY_* */
+    CD_TUNNEL, /* same order as POLICY_* */
+    CD_PFS,    /* same order as POLICY_* */
+
+    CD_IKELIFETIME,
+    CD_IPSECLIFETIME,
+    CD_RKMARGIN,
+    CD_RKFUZZ,
+    CD_KTRIES
+#   define CD_LAST CD_KTRIES   /* last connection description */
+
 
 #ifdef DEBUG	/* must be last so others are less than 32 to fit in lset_t */
+#   define DBGOPT_FIRST DBGOPT_NONE
     ,
-    OPT_DEBUG_NONE,
-    OPT_DEBUG_ALL,
+    DBGOPT_NONE,
+    DBGOPT_ALL,
 
-    OPT_DEBUG_RAW,	/* same order as DBG_* */
-    OPT_DEBUG_CRYPT,	/* same order as DBG_* */
-    OPT_DEBUG_PARSING,	/* same order as DBG_* */
-    OPT_DEBUG_EMITTING,	/* same order as DBG_* */
-    OPT_DEBUG_CONTROL,	/* same order as DBG_* */
-    OPT_DEBUG_KLIPS,	/* same order as DBG_* */
-    OPT_DEBUG_PRIVATE	/* same order as DBG_* */
+    DBGOPT_RAW,	/* same order as DBG_* */
+    DBGOPT_CRYPT,	/* same order as DBG_* */
+    DBGOPT_PARSING,	/* same order as DBG_* */
+    DBGOPT_EMITTING,	/* same order as DBG_* */
+    DBGOPT_CONTROL,	/* same order as DBG_* */
+    DBGOPT_KLIPS,	/* same order as DBG_* */
+    DBGOPT_PRIVATE	/* same order as DBG_* */
+#   define DBGOPT_LAST DBGOPT_PRIVATE
 #endif
+
 };
 
 #define OPTION_OFFSET	256	/* to get out of the way of letter options */
@@ -242,30 +288,6 @@
     { "ctlbase", required_argument, NULL, OPT_CTLBASE + OO },
     { "name", required_argument, NULL, OPT_NAME + OO },
 
-    { "to", no_argument, NULL, OPT_TO + OO },
-
-    { "host", required_argument, NULL, OPT_HOST + OO },
-    { "id", required_argument, NULL, OPT_ID + OO },
-    { "ikeport", required_argument, NULL, OPT_IKEPORT + OO + NUMERIC_ARG },
-    { "nexthop", required_argument, NULL, OPT_NEXTHOP + OO },
-    { "client", required_argument, NULL, OPT_CLIENT + OO },
-    { "updown", required_argument, NULL, OPT_UPDOWN + OO },
-
-    { "psk", no_argument, NULL, OPT_PSK + OO },
-    { "rsasig", no_argument, NULL, OPT_RSASIG + OO },
-
-    { "encrypt", no_argument, NULL, OPT_ENCRYPT + OO },
-    { "authenticate", no_argument, NULL, OPT_AUTHENTICATE + OO },
-    { "tunnel", no_argument, NULL, OPT_TUNNEL + OO },
-    { "pfs", no_argument, NULL, OPT_PFS + OO },
-
-    { "ikelifetime", required_argument, NULL, OPT_IKELIFETIME + OO + NUMERIC_ARG },
-    { "ipseclifetime", required_argument, NULL, OPT_IPSECLIFETIME + OO + NUMERIC_ARG },
-    { "rekeymargin", required_argument, NULL, OPT_RKMARGIN + OO + NUMERIC_ARG },
-    { "rekeywindow", required_argument, NULL, OPT_RKMARGIN + OO + NUMERIC_ARG },	/* OBSOLETE */
-    { "rekeyfuzz", required_argument, NULL, OPT_RKFUZZ + OO + NUMERIC_ARG },
-    { "keyingtries", required_argument, NULL, OPT_KTRIES + OO + NUMERIC_ARG },
-
     { "keyid", required_argument, NULL, OPT_KEYID + OO },
     { "pubkeyrsa", required_argument, NULL, OPT_PUBKEYRSA + OO },
 
@@ -282,18 +304,56 @@
 
     { "asynchronous", no_argument, NULL, OPT_ASYNC + OO },
 
+/* options for a connection description */
+    { "to", no_argument, NULL, CD_TO + OO },
+
+    { "host", required_argument, NULL, CD_HOST + OO },
+    { "id", required_argument, NULL, CD_ID + OO },
+    { "ikeport", required_argument, NULL, CD_IKEPORT + OO + NUMERIC_ARG },
+    { "nexthop", required_argument, NULL, CD_NEXTHOP + OO },
+    { "client", required_argument, NULL, CD_CLIENT + OO },
+    { "updown", required_argument, NULL, CD_UPDOWN + OO },
+
+    { "psk", no_argument, NULL, CD_PSK + OO },
+#ifndef OPENSSL
+    { "rsasig", no_argument, NULL, CD_RSASIG + OO },
+#else
+    { "rsasig", no_argument, NULL, CD_OPENSSL + OO },
+    { "openssl", no_argument, NULL, CD_OPENSSL + OO },
+#endif
+
+    { "encrypt", no_argument, NULL, CD_ENCRYPT + OO },
+    { "authenticate", no_argument, NULL, CD_AUTHENTICATE + OO },
+    { "tunnel", no_argument, NULL, CD_TUNNEL + OO },
+    { "pfs", no_argument, NULL, CD_PFS + OO },
+
+    { "ikelifetime", required_argument, NULL, CD_IKELIFETIME + OO + NUMERIC_ARG },
+    { "ipseclifetime", required_argument, NULL, CD_IPSECLIFETIME + OO + NUMERIC_ARG },
+    { "rekeymargin", required_argument, NULL, CD_RKMARGIN + OO + NUMERIC_ARG },
+    { "rekeywindow", required_argument, NULL, CD_RKMARGIN + OO + NUMERIC_ARG },	/* OBSOLETE */
+    { "rekeyfuzz", required_argument, NULL, CD_RKFUZZ + OO + NUMERIC_ARG },
+    { "keyingtries", required_argument, NULL, CD_KTRIES + OO + NUMERIC_ARG },
+
+#ifdef OPENSSL
+    { "certfile", required_argument, NULL, OPT_CERTFILE + OO },
+    { "certopts", required_argument, NULL, OPT_CERTOPTS + OO },
+    { "peerfile", required_argument, NULL, OPT_PEERFILE + OO },
+    { "keyfile", required_argument, NULL, OPT_KEYFILE + OO },
+    { "certpath", required_argument, NULL, OPT_CERTPATH + OO },
+#endif
+
 #ifdef DEBUG
-    { "debug-none", no_argument, NULL, OPT_DEBUG_NONE + OO },
-    { "debug-all]", no_argument, NULL, OPT_DEBUG_ALL + OO },
-    { "debug-raw", no_argument, NULL, OPT_DEBUG_RAW + OO },
-    { "debug-crypt", no_argument, NULL, OPT_DEBUG_CRYPT + OO },
-    { "debug-parsing", no_argument, NULL, OPT_DEBUG_PARSING + OO },
-    { "debug-emitting", no_argument, NULL, OPT_DEBUG_EMITTING + OO },
-    { "debug-control", no_argument, NULL, OPT_DEBUG_CONTROL + OO },
-    { "debug-klips", no_argument, NULL, OPT_DEBUG_KLIPS + OO },
-    { "debug-private", no_argument, NULL, OPT_DEBUG_PRIVATE + OO },
+    { "debug-none", no_argument, NULL, DBGOPT_NONE + OO },
+    { "debug-all", no_argument, NULL, DBGOPT_ALL + OO },
+    { "debug-raw", no_argument, NULL, DBGOPT_RAW + OO },
+    { "debug-crypt", no_argument, NULL, DBGOPT_CRYPT + OO },
+    { "debug-parsing", no_argument, NULL, DBGOPT_PARSING + OO },
+    { "debug-emitting", no_argument, NULL, DBGOPT_EMITTING + OO },
+    { "debug-control", no_argument, NULL, DBGOPT_CONTROL + OO },
+    { "debug-klips", no_argument, NULL, DBGOPT_KLIPS + OO },
+    { "debug-private", no_argument, NULL, DBGOPT_PRIVATE + OO },
 #endif
-#   undef OO
+#undef OO
     { 0,0,0,0 }
 };
 
@@ -332,7 +392,7 @@
 
     if (life > limit)
     {
-	char buf[200];
+	char buf[200]; /* arbitrary limit */
 
 	snprintf(buf, sizeof(buf)
 	    , "%s [%lu seconds] must be less than %lu seconds"
@@ -341,7 +401,7 @@
     }
     if (life <= mint)
     {
-	char buf[200];
+	char buf[200]; /* arbitrary limit */
 
 	snprintf(buf, sizeof(buf)
 	    , "%s [%lu] must be greater than"
@@ -354,6 +414,7 @@
     }
 }
 
+
 /* This is a hack for initiating ISAKMP exchanges. */
 
 int
@@ -362,7 +423,8 @@
     struct whack_message msg;
     lset_t
 	opts_seen = LEMPTY,
-	opts_seen_before_to;
+	cd_seen = LEMPTY,
+	cd_seen_before_to;
     memset(&msg, '\0', sizeof(msg));
     msg.magic = WHACK_MAGIC;
     msg.right.host_port = IKE_UDP_PORT;
@@ -404,24 +466,41 @@
 		diagq("badly formed numeric argument", optarg);
 	}
 
-	/* all of our non-letter flags except OPT_DEBUG_* get
-	 * added to opts_seen.  The OP_DEBUG_* exception is because
-	 * we have too many to fit in a 32-bit string!
-	 * Unless other code intervenes, we reject repeated options.
-	 */
+	/* per-class option processing */
 
-	if (0 <= c
+       if (0 <= c && c <= OPT_LAST)
+       {
+           /* OPT_* options get added opts_seen.
+            * Reject repeated options (unless later code intervenes).
+            */
+           lset_t f = LELEM(c);
+ 
+           if (opts_seen & f)
+               diagq("duplicated flag", long_opts[long_index].name);
+           opts_seen |= f;
+       }
 #ifdef DEBUG
-	&& c < OPT_DEBUG_NONE
+       else if (DBGOPT_FIRST <= c && c <= DBGOPT_LAST)
+       {
+           /* DBGOPT_* options are treated separately to reduce
+            * potential members of opts_seen.
+            */
+           msg.whack_options = TRUE;
+       }
 #endif
-	)
-	{
-	    lset_t f = LELEM(c);
-
-	    if (opts_seen & f)
-		diagq("duplicated flag", long_opts[long_index].name);
-	    opts_seen |= f;
-	}
+       else if (CD_FIRST <= c && c <= CD_LAST)
+       {
+           /* CD_* options are added to cd_seen.
+            * Reject repeated options (unless later code intervenes).
+            */
+           lset_t f = LELEM(c - CD_FIRST);
+
+           if (cd_seen & f)
+             diagq("duplicated flag", long_opts[long_index].name);
+
+	       cd_seen |= f;
+		   opts_seen |= LELEM(OPT_CD);
+	   }
 
 	/* Note: "break"ing from switch terminates loop.
 	 * most cases should end with "continue".
@@ -469,77 +548,6 @@
 	    msg.name = optarg;
 	    continue;
 
-	case OPT_HOST:	/* --host <ip-address> */
-	    diagq(atoaddr(optarg, 0, &msg.right.host_addr), optarg);
-	    continue;
-
-	case OPT_ID:	/* --id <identity> */
-	    msg.right.id = optarg;	/* decoded by Pluto */
-	    continue;
-
-	case OPT_IKEPORT:	/* --ikeport <port-number> */
-	    if (opt_whole<=0 || opt_whole >= 0x10000)
-		diagq("<port-number> must be a number between 1 and 65535", optarg);
-	    msg.right.host_port = opt_whole;
-	    continue;
-
-	case OPT_NEXTHOP:	/* --nexthop <ip-address> */
-	    diagq(atoaddr(optarg, 0, &msg.right.host_nexthop), optarg);
-	    continue;
-
-	case OPT_CLIENT:	/* --client <subnet> */
-	    diagq(atosubnet(optarg, 0, &msg.right.client_net, &msg.right.client_mask), optarg);
-	    msg.right.has_client = TRUE;
-	    msg.policy |= POLICY_TUNNEL;	/* client => tunnel */
-	    continue;
-
-	case OPT_UPDOWN:	/* --updown <updown> */
-	    msg.right.updown = optarg;
-	    continue;
-
-
-	case OPT_TO:		/* --to */
-	    /* process right end, move it to left, reset it */
-	    if ((opts_seen & (LELEM(OPT_HOST) | LELEM(OPT_ID))) == 0)
-		diag("connection missing both --host and --id (before --to)");
-	    msg.left = msg.right;
-	    memset(&msg.right, '\0', sizeof(msg.right));
-	    msg.right.id = NULL;
-	    msg.right.updown = NULL;
-	    msg.right.host_port = IKE_UDP_PORT;
-	    opts_seen_before_to = opts_seen;
-	    opts_seen = (opts_seen & ~LRANGE(OPT_HOST,OPT_UPDOWN));
-	    continue;
-
-	case OPT_PSK:		/* --psk */
-	case OPT_RSASIG:	/* --rsasig */
-	case OPT_ENCRYPT:	/* --encrypt */
-	case OPT_AUTHENTICATE:	/* --authenticate */
-	case OPT_TUNNEL:	/* --tunnel */
-	case OPT_PFS:	/* -- pfs */
-	    msg.policy |= LELEM(c - OPT_POLICY_FIRST);
-	    continue;
-
-	case OPT_IKELIFETIME:	/* --ikelifetime <seconds> */
-	    msg.sa_ike_life_seconds = opt_whole;
-	    continue;
-
-	case OPT_IPSECLIFETIME:	/* --ipseclifetime <seconds> */
-	    msg.sa_ipsec_life_seconds = opt_whole;
-	    continue;
-
-	case OPT_RKMARGIN:	/* --rekeymargin <seconds> */
-	    msg.sa_rekey_margin = opt_whole;
-	    continue;
-
-	case OPT_RKFUZZ:	/* --rekeyfuzz <percentage> */
-	    msg.sa_rekey_fuzz = opt_whole;
-	    continue;
-
-	case OPT_KTRIES:	/* --keyingtries <count> */
-	    msg.sa_keying_tries = opt_whole;
-	    continue;
-
 	case OPT_KEYID:	/* --keyid <identity> */
 	    msg.whack_key = TRUE;
 	    msg.keyid = optarg;	/* decoded by Pluto */
@@ -548,7 +556,7 @@
 	case OPT_PUBKEYRSA:
 	    {
 		const char *ugh;
-		static char keyspace[1024];
+		static char keyspace[1024 + 4]; /* room for 8K bit key */
 
 		msg.pubkey_alg = PUBKEY_ALG_RSA;
 		ugh = atobytes(optarg, 0, keyspace, sizeof(keyspace), &msg.keyval.len);
@@ -604,26 +612,135 @@
 	    msg.whack_async = TRUE;
 	    continue;
 
+#ifdef OPENSSL
+	case OPT_CERTFILE:
+	    if (strlen(optarg) >= FILE_NAME_LIMIT)
+		diagq("certificate file name too long", optarg);
+		strcpy(msg.whack_certfile, optarg);
+        continue;
+
+	case OPT_CERTOPTS:
+	    if (strlen(optarg) >= CERT_OPTIONS_LIMIT)
+		diagq("certificate file name too long", optarg);
+		strcpy(msg.whack_certopts, optarg);
+        continue;
+
+	case OPT_PEERFILE:
+	    if (strlen(optarg) >= FILE_NAME_LIMIT)
+		diagq("peer certificate file name too long", optarg);
+		strcpy(msg.whack_peerfile, optarg);
+        continue;
+
+	case OPT_KEYFILE:
+	    if (strlen(optarg) >= FILE_NAME_LIMIT)
+		diagq("key file name too long", optarg);
+		strcpy(msg.whack_keyfile, optarg);
+        continue;
+
+	case OPT_CERTPATH:
+	    if (strlen(optarg) >= PATH_NAME_LIMIT)
+		diagq("certificate path name too long", optarg);
+		strcpy(msg.whack_certpath, optarg);
+        continue;
+#endif
+
+	/* Connection Description options */
+
+	case CD_HOST:	/* --host <ip-address> */
+	    diagq(atoaddr(optarg, 0, &msg.right.host_addr), optarg);
+	    continue;
+
+	case CD_ID:	/* --id <identity> */
+	    msg.right.id = optarg;	/* decoded by Pluto */
+	    continue;
+
+	case CD_IKEPORT:	/* --ikeport <port-number> */
+	    if (opt_whole<=0 || opt_whole >= 0x10000)
+		diagq("<port-number> must be a number between 1 and 65535", optarg);
+	    msg.right.host_port = opt_whole;
+	    continue;
+
+	case CD_NEXTHOP:	/* --nexthop <ip-address> */
+	    diagq(atoaddr(optarg, 0, &msg.right.host_nexthop), optarg);
+	    continue;
+
+	case CD_CLIENT:	/* --client <subnet> */
+	    diagq(atosubnet(optarg, 0, &msg.right.client_net, &msg.right.client_mask), optarg);
+	    msg.right.has_client = TRUE;
+	    msg.policy |= POLICY_TUNNEL;	/* client => tunnel */
+	    continue;
+
+	case CD_UPDOWN:	/* --updown <updown> */
+	    msg.right.updown = optarg;
+	    continue;
+
+
+	case CD_TO:		/* --to */
+	    /* process right end, move it to left, reset it */
+	    if ((opts_seen & (LELEM(CD_HOST-CD_FIRST) | LELEM(CD_ID-CD_FIRST))) == 0)
+		  diag("connection missing both --host and --id (before --to)");
+	    msg.left = msg.right;
+	    memset(&msg.right, '\0', sizeof(msg.right));
+	    msg.right.id = NULL;
+	    msg.right.updown = NULL;
+	    msg.right.host_port = IKE_UDP_PORT;
+	    cd_seen_before_to = cd_seen;
+	    cd_seen &= ~LRANGE(CD_HOST-CD_FIRST, CD_UPDOWN-CD_FIRST);
+	    continue;
+
+	case CD_PSK:		/* --psk */
+#ifndef OPENSSL
+	case CD_RSASIG:	/* --rsasig */
+#else
+	case CD_OPENSSL:	/* --rsasig */
+#endif
+	case CD_ENCRYPT:	/* --encrypt */
+	case CD_AUTHENTICATE:	/* --authenticate */
+	case CD_TUNNEL:	/* --tunnel */
+	case CD_PFS:	/* -- pfs */
+	    msg.policy |= LELEM(c - CD_POLICY_FIRST);
+	    continue;
+
+	case CD_IKELIFETIME:	/* --ikelifetime <seconds> */
+	    msg.sa_ike_life_seconds = opt_whole;
+	    continue;
+
+	case CD_IPSECLIFETIME:	/* --ipseclifetime <seconds> */
+	    msg.sa_ipsec_life_seconds = opt_whole;
+	    continue;
+
+	case CD_RKMARGIN:	/* --rekeymargin <seconds> */
+	    msg.sa_rekey_margin = opt_whole;
+	    continue;
+
+	case CD_RKFUZZ:	/* --rekeyfuzz <percentage> */
+	    msg.sa_rekey_fuzz = opt_whole;
+	    continue;
+
+	case CD_KTRIES:	/* --keyingtries <count> */
+	    msg.sa_keying_tries = opt_whole;
+	    continue;
+
 #ifdef DEBUG
-	case OPT_DEBUG_NONE:	/* --debug-none */
+	case DBGOPT_NONE:	/* --debug-none */
 	    msg.whack_options = TRUE;
 	    msg.debugging = DBG_NONE;
 	    continue;
 
-	case OPT_DEBUG_ALL:	/* --debug-all */
+	case DBGOPT_ALL:	/* --debug-all */
 	    msg.whack_options = TRUE;
 	    msg.debugging |= DBG_ALL;	/* note: does not include PRIVATE */
 	    continue;
 
-	case OPT_DEBUG_RAW:	/* --debug-raw */
-	case OPT_DEBUG_CRYPT:	/* --debug-crypt */
-	case OPT_DEBUG_PARSING:	/* --debug-parsing */
-	case OPT_DEBUG_EMITTING:	/* --debug-emitting */
-	case OPT_DEBUG_CONTROL:	/* --debug-control */
-	case OPT_DEBUG_KLIPS:	/* --debug-klips */
-	case OPT_DEBUG_PRIVATE:	/* --debug-private */
+	case DBGOPT_RAW:	/* --debug-raw */
+	case DBGOPT_CRYPT:	/* --debug-crypt */
+	case DBGOPT_PARSING:	/* --debug-parsing */
+	case DBGOPT_EMITTING:	/* --debug-emitting */
+	case DBGOPT_CONTROL:	/* --debug-control */
+	case DBGOPT_KLIPS:	/* --debug-klips */
+	case DBGOPT_PRIVATE:	/* --debug-private */
 	    msg.whack_options = TRUE;
-	    msg.debugging |= LELEM(c-OPT_DEBUG_RAW);
+	    msg.debugging |= LELEM(c-DBGOPT_RAW);
 	    continue;
 #endif
 	default:
@@ -640,25 +757,26 @@
      * required information was supplied.
      */
 
-    if (opts_seen & LRANGE(OPT_CD_FIRST, OPT_CD_LAST))
+//    if (opts_seen & LRANGE(CD_FIRST, CD_LAST))
+    if (opts_seen & LELEM(OPT_CD))
     {
-	if (!LALLIN(opts_seen, LELEM(OPT_TO)))
+	if (!LALLIN(cd_seen, LELEM(CD_TO-CD_FIRST)))
 	    diag("connection description option, but no --to");
 
-	if ((opts_seen & (LELEM(OPT_HOST) | LELEM(OPT_ID))) == 0)
+	if ((cd_seen & (LELEM(CD_HOST-CD_FIRST) | LELEM(CD_ID-CD_FIRST))) == 0)
 	    diag("connection missing both --host and --id (after --to)");
 
 	if (is_NO_IP(msg.left.host_addr)
-	&& is_NO_IP(msg.right.host_addr))
-	    diag("hosts cannot both be 0.0.0.0");
+	  && is_NO_IP(msg.right.host_addr))
+	  diag("hosts cannot both be 0.0.0.0");
 
-	if ((opts_seen_before_to & LELEM(OPT_NEXTHOP)) == 0)
+	if ((cd_seen_before_to & LELEM(CD_NEXTHOP-CD_FIRST)) == 0)
 	{
 	    if (is_NO_IP(msg.right.host_addr))
 		diag("left nexthop must be specified when right is Road Warrior");
 	    msg.left.host_nexthop = msg.right.host_addr;
 	}
-	if ((opts_seen & LELEM(OPT_NEXTHOP)) == 0)
+	if ((cd_seen & LELEM(CD_NEXTHOP-CD_FIRST)) == 0)
 	{
 	    if (is_NO_IP(msg.left.host_addr))
 		diag("right nexthop must be specified when left is Road Warrior");
@@ -671,7 +789,7 @@
     /* decide whether --name is mandatory or forbidden */
     if (opts_seen & (LELEM(OPT_ROUTE) | LELEM(OPT_UNROUTE)
     | LELEM(OPT_INITIATE) | LELEM(OPT_TERMINATE)
-    | LELEM(OPT_DELETE) | LELEM(OPT_TO)))
+    | LELEM(OPT_DELETE) | LELEM(OPT_CD)))
     {
 	if ((opts_seen & LELEM(OPT_NAME)) == 0)
 	    diag("missing --name <connection_name>");
@@ -761,7 +879,7 @@
 	/* for now, just copy reply back to stdout */
 
 	{
-	    char buf[4097];
+	    char buf[4097]; /* arbitrary limit on log line length */
 	    char *be = buf;
 
 	    for (;;)
diff -ruN freeswan-1.5.orig/pluto/whack.h freeswan-1.5/pluto/whack.h
--- freeswan-1.5.orig/pluto/whack.h	Sat Apr 15 04:56:04 2000
+++ freeswan-1.5/pluto/whack.h	Thu Oct  5 07:05:59 2000
@@ -14,6 +14,11 @@
  * RCSID $Id: whack.h,v 1.31 2000/04/15 08:56:04 dhr Exp $
  */
 
+#ifdef OPENSSL
+#include "openssl_defs.h"
+#endif
+#include <freeswan.h>
+
 /*
  * Since the message remains on one host, native representation is used.
  * Think of this as horizontal microcode: all selected operations are
@@ -24,6 +29,7 @@
  * meaning, change this value (probably by changing the last number).
  */
 #define WHACK_MAGIC (('w' << 24) + ('h' << 16) + ('k' << 8) + 10)
+// #define WHACK_MAGIC (('w' << 24) + ('h' << 16) + ('k' << 8) + 12)
 
 /* struct whack_end is a lot like connection.h's struct end
  * It differs because it is going to be shipped down a socket
@@ -77,36 +83,42 @@
     enum pubkey_alg pubkey_alg;
     chunk_t keyval;	/* chunk */
 
-    /* for WHACK_ROUTE: */
+#ifdef OPENSSL
+// hm. Are the sizes necessary?
+//    char *whack_certfile;
+//    char *whack_certopts;
+//    char *whack_peerfile;
+//    char *whack_keyfile;
+//    char *whack_certpath;
+    char whack_certfile[FILE_NAME_LIMIT];
+    char whack_certopts[CERT_OPTIONS_LIMIT];
+    char whack_peerfile[FILE_NAME_LIMIT];
+    char whack_keyfile[FILE_NAME_LIMIT];
+    char whack_certpath[PATH_NAME_LIMIT];
+#endif
 
+    /* for WHACK_ROUTE: */
     bool whack_route;
 
     /* for WHACK_UNROUTE: */
-
     bool whack_unroute;
 
     /* for WHACK_INITIATE: */
-
     bool whack_initiate;
 
     /* for WHACK_TERMINATE: */
-
     bool whack_terminate;
 
     /* for WHACK_DELETE: */
-
     bool whack_delete;
 
     /* for WHACK_LISTEN: */
-
     bool whack_listen, whack_unlisten;
 
     /* for WHACK_STATUS: */
-
     bool whack_status;
 
     /* for WHACK_SHUTDOWN */
-
     bool whack_shutdown;
 
     /* space for strings (hope there is enough room):
@@ -117,7 +129,7 @@
      * 4 right's name [left.host.name.len]
      * 5 right's updown
      * 6 keyid
-     * plus keyval, a chunk.
+     * plus keyval  (limit: 8K bits + overhead), a chunk.
      */
     size_t str_size;
     char string[2048];
diff -ruN freeswan-1.5.orig/pluto/x_sobj.c freeswan-1.5/pluto/x_sobj.c
--- freeswan-1.5.orig/pluto/x_sobj.c	Wed Dec 31 19:00:00 1969
+++ freeswan-1.5/pluto/x_sobj.c	Thu Oct  5 07:05:59 2000
@@ -0,0 +1,34 @@
+#include "x_sobj.h"
+
+IMPLEMENT_STACK_OF(X509_OBJECT)
+
+X509_OBJECT *
+X509_OBJECT_new( const int type, void *p )
+{
+  X509_OBJECT *ret = Malloc(sizeof(X509_OBJECT));
+
+  if (ret == NULL) return ret;
+  switch(type) {
+  case X509_LU_X509:
+    ret->type = type;
+    ret->data.x509 = (X509 *)p;
+    break;
+  case X509_LU_CRL:
+    ret->type = type;
+    ret->data.crl = (X509_CRL *)p;
+    break;
+  default: /* Unknown type */
+    Free((char *)ret);
+    ret = NULL;
+    break;
+  }
+  return ret;
+}
+
+void
+X509_OBJECT_free(X509_OBJECT *x)
+{
+  if (!x) return;
+  X509_OBJECT_free_contents(x);
+  Free((char *)x);
+}
diff -ruN freeswan-1.5.orig/pluto/x_sobj.h freeswan-1.5/pluto/x_sobj.h
--- freeswan-1.5.orig/pluto/x_sobj.h	Wed Dec 31 19:00:00 1969
+++ freeswan-1.5/pluto/x_sobj.h	Thu Oct  5 07:05:59 2000
@@ -0,0 +1,12 @@
+#ifndef X_SOBJ_H
+#define X_SOBJ_H
+
+#include <openssl/x509.h>
+#include <openssl/x509_vfy.h>
+
+DECLARE_STACK_OF(X509_OBJECT)
+
+X509_OBJECT *X509_OBJECT_new( const int type, void *ptr );
+void X509_OBJECT_free(X509_OBJECT *x);
+
+#endif
diff -ruN freeswan-1.5.orig/pluto/xmap.c freeswan-1.5/pluto/xmap.c
--- freeswan-1.5.orig/pluto/xmap.c	Wed Dec 31 19:00:00 1969
+++ freeswan-1.5/pluto/xmap.c	Thu Oct  5 07:05:59 2000
@@ -0,0 +1,249 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <openssl/stack.h>
+#include <openssl/asn1.h>
+#include <openssl/safestack.h>
+#include <openssl/pem.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include "x_sobj.h"
+#include "xmap_file.h"
+#include "xmap_dir.h"
+#include "xmap_db.h"
+#include "xmap_ldap.h"
+#include "xmap.h"
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+
+static XMAP_METHOD_LIST *xmth = NULL;
+
+XMAP *XMAP_new(const char *spec);
+STACK_OF(X509_OBJECT) *
+XMAP_lookup( XMAP *xm, const int type, const char *index, void *p );
+void XMAP_free(XMAP *xm);
+void XMAP_dump(XMAP *xm);
+
+int
+XMAP_register(XMAP_METHOD *meth)
+{
+  XMAP_METHOD_LIST *p;
+  int found;
+  
+  for(p=xmth,found=0; ((!found) && (p)); p=p->next)
+    if (strcasecmp(meth->prefix, p->meth->prefix) == 0) found=1;
+
+  if (found) {
+    return 0;
+  } else {
+    p = malloc(sizeof(XMAP_METHOD_LIST));
+    if (p) {
+      p->next = xmth;
+      p->meth = meth;
+      xmth = p;
+    } else
+      return 0;
+  }
+  return 1;
+}
+
+void
+XMAP_METHOD_LIST_free( void )
+{
+  XMAP_METHOD_LIST *p, *q;
+
+  for(p=xmth; p;) {
+    q = p->next;
+    free(p);
+    q = p;
+  }
+}
+
+int
+XMAP_unregister(const char *prefix)
+{
+  XMAP_METHOD_LIST *p, *q;
+  int found;
+
+  for(p = xmth, found = 0; ((!found) && (p)); )
+    if (strcasecmp(p->meth->prefix, prefix) == 0)
+      found = 1;
+    else
+      p=p->next;
+
+  if (!found)
+    return 0;
+  else {
+    if ( p == xmth ) {
+      xmth = xmth->next;
+      free(p);
+    } else {
+      for(q = xmth; q->next != p; q = q->next);
+      q->next = p->next;
+      free(p);
+    }
+  }
+  return 1;
+}
+
+XMAP *
+XMAP_new(const char *spec)
+{
+  XMAP *ret;
+  char *s;
+
+  if ((ret = malloc(sizeof(XMAP))) == NULL) goto end;
+  if ((ret->spec = strdup(spec)) == NULL) goto end;
+  ret->methp = NULL;
+
+  if ((s = strchr(spec, DICT_SEPARATOR)) == NULL) {
+    log("No type prefix");
+  } else {
+    int l = (int)(s - spec) + 1;
+    XMAP_METHOD_LIST *p;
+    int found;
+
+    for(p=xmth, found = 0; ((!found) && (p));) {
+      if (strncasecmp(p->meth->prefix, spec, l-1) == 0)
+	found = 1;
+      else
+	p = p->next;
+    }
+
+    if (found) {
+      ret->pmap = p->meth->new(&s[1]);
+      if (! ret->pmap) goto end;
+      ret->methp = p;
+    } else {
+      log("Unknown map type spec: %s", spec);
+      goto end;
+    }
+  }
+  return ret;
+ end:
+  if (ret->spec) free(ret->spec);
+  if (ret) free(ret);
+  return NULL;
+}
+
+static int
+check_methp(XMAP *xm)
+{
+  XMAP_METHOD_LIST *p;
+
+  for(p = xmth; p; p = p->next)
+    if (xm->methp == p)
+      return 1;
+
+  return 0;
+}
+
+STACK_OF(X509_OBJECT) *
+XMAP_lookup( XMAP *xm, const int type, const char *index, void *p )
+{
+  if ((!xm) || (!check_methp(xm)) || (! xm->methp->meth->lookup) )
+  {
+	DBG(DBG_PARSING,
+    DBG_log("XMAP_lookup returns NULL.");
+	);
+    return NULL;
+  }
+  return xm->methp->meth->lookup(xm->pmap, type, index, p);
+}
+
+void
+XMAP_free(XMAP *xm)
+{
+  if (!xm) return;
+  if (!xm->pmap) return;
+  if (!check_methp(xm)) return;
+  if (xm->methp->meth->free) xm->methp->meth->free(xm->pmap);
+  if (xm->spec) free(xm->spec);
+  free(xm);
+}
+
+void
+XMAP_dump(XMAP *xm)
+{
+  if (! xm->pmap) return;
+  if (!check_methp(xm)) return;
+  if (! xm->methp->meth->dump) return;
+  xm->methp->meth->dump(xm->pmap);
+}
+
+int
+X509_subjAltName_check_dns(X509 *x, const char *dns)
+{
+  int i, loc, ret;
+  X509_EXTENSION *ext;
+  u_char *p;
+  STACK_OF(GENERAL_NAME) *nsk = NULL;
+  GENERAL_NAME *gn;
+
+  ret = 0;
+  if ((loc = X509_get_ext_by_NID(x, NID_subject_alt_name, -1)) >= 0) {
+    if ((ext = X509_get_ext(x, loc)) != NULL) {
+      p = ext->value->data;
+      d2i_GENERAL_NAMES(&nsk, &p, ext->value->length);
+      if (nsk) {
+	for(i=0; i < sk_GENERAL_NAME_num(nsk); i++) {
+	  gn = sk_GENERAL_NAME_value(nsk, i);
+	  
+	  if (gn->type == GEN_DNS) {
+	    if (strncasecmp(dns, gn->d.ia5->data, gn->d.ia5->length) == 0) {
+	      ret = 1;
+	      break;
+	    }
+	  }
+	}
+	sk_GENERAL_NAME_free(nsk);
+	nsk = NULL;
+      }
+    }
+  }
+  return ret;
+}
+
+int
+X509_subjAltName_check_ip(X509 *x, const struct in_addr ip)
+{
+  int i, loc, ret;
+  X509_EXTENSION *ext;
+  u_char *p;
+  STACK_OF(GENERAL_NAME) *nsk = NULL;
+  GENERAL_NAME *gn;
+
+  ret = 0;
+  if ((loc = X509_get_ext_by_NID(x, NID_subject_alt_name, -1)) >= 0) {
+	if ((ext = X509_get_ext(x, loc)) != NULL) {
+		p = ext->value->data;
+		d2i_GENERAL_NAMES(&nsk, &p, ext->value->length);
+		if (nsk) {
+			for(i=0; i < sk_GENERAL_NAME_num(nsk); i++) {
+				gn = sk_GENERAL_NAME_value(nsk, i);
+	  
+				if (gn->type == GEN_IPADD) {
+					if (memcmp(&ip.s_addr, gn->d.ip->data, gn->d.ip->length) == 0) {
+						ret = 1;
+						break;
+					}
+				}
+			}
+			sk_GENERAL_NAME_free(nsk);
+			nsk = NULL;
+		}
+ 	 }
+  }
+  return ret;
+}
+
+IMPLEMENT_STACK_OF(XMAP)
diff -ruN freeswan-1.5.orig/pluto/xmap.h freeswan-1.5/pluto/xmap.h
--- freeswan-1.5.orig/pluto/xmap.h	Wed Dec 31 19:00:00 1969
+++ freeswan-1.5/pluto/xmap.h	Thu Oct  5 07:05:59 2000
@@ -0,0 +1,56 @@
+#ifndef XMAP_H
+#define XMAP_H
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <openssl/safestack.h>
+#include <openssl/x509.h>
+#include <openssl/x509_vfy.h>
+
+#include "x_sobj.h"
+
+typedef struct _xmap_method_st {
+  char *prefix;
+    STACK_OF(X509_OBJECT) *(*lookup)( void *this, const int type, const char *index, void *p );
+  void (*dump)(void *pmap);
+  void (*free)(void *pmap);
+  void *(*new) (const char *spec);
+} XMAP_METHOD;
+
+typedef struct _xmap_method_list_st {
+  XMAP_METHOD *meth;
+  struct _xmap_method_list_st *next;
+} XMAP_METHOD_LIST;
+
+typedef struct _xmap_st {
+  char *spec;
+  void *pmap;
+  XMAP_METHOD_LIST *methp;
+} XMAP;
+
+DECLARE_STACK_OF(XMAP)
+
+#ifndef DICT_SEPARATOR
+#define DICT_SEPARATOR ':'
+#endif
+
+#define XMAP_UNKNOWN_TYPE 0
+#define XMAP_FILE_TYPE    1
+#define XMAP_DIR_TYPE     2
+#define XMAP_DB_TYPE      3
+
+int XMAP_register(XMAP_METHOD *meth);
+void XMAP_METHOD_LIST_free( void );
+int XMAP_unregister(const char *prefix);
+
+int X509_subjAltName_check_dns(X509 *x, const char *dns);
+int X509_subjAltName_check_ip(X509 *x, const struct in_addr in);
+
+XMAP *XMAP_new(const char *spec);
+STACK_OF(X509_OBJECT) *XMAP_lookup( XMAP *xm, const int type, const char *index, void *p );
+void XMAP_free(XMAP *xm);
+void XMAP_dump(XMAP *xm);
+
+#endif /* XMAP_H */
diff -ruN freeswan-1.5.orig/pluto/xmap_db.c freeswan-1.5/pluto/xmap_db.c
--- freeswan-1.5.orig/pluto/xmap_db.c	Wed Dec 31 19:00:00 1969
+++ freeswan-1.5/pluto/xmap_db.c	Thu Oct  5 07:05:59 2000
@@ -0,0 +1,513 @@
+#if defined(HAVE_DB) || (HAVE_DB185)
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifdef HAVE_DB185
+#include <db_185.h>
+#else
+#include <db.h>
+#endif
+
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+#include <openssl/x509v3.h>
+
+#include "xmap_db.h"
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+
+static void XMAP_DB_dump(void *this);
+static void XMAP_DB_free(void *this);
+static void *XMAP_DB_new(const char *dbname);
+static STACK_OF(X509_OBJECT) *
+XMAP_DB_lookup( void *this, const int type, const char *index, void *p );
+static STACK_OF(X509_OBJECT) *
+XMAP_DB_lookup_cert_by_subject( XMAP_DB *xm, X509_NAME *name );
+static STACK_OF(X509_OBJECT) *
+XMAP_DB_lookup_crl_by_issuer( XMAP_DB *xm, X509_NAME *name );
+static STACK_OF(X509_OBJECT) *
+XMAP_DB_lookup_cert_by_uid( XMAP_DB *xm, const char *uid );
+static STACK_OF(X509_OBJECT) *
+XMAP_DB_lookup_cert_by_dns( XMAP_DB *xm, const char *dns );
+static STACK_OF(X509_OBJECT) *
+XMAP_DB_lookup_cert_by_ip( XMAP_DB *xm, const struct in_addr ip);
+static STACK_OF(X509_OBJECT) *
+XMAP_DB_lookup_ca_certs( XMAP_DB *xm );
+
+#define TAGLEN 4
+
+static unsigned char tag_cert[] = { 0x00, 0x00, 0x00, 0x00 };
+static unsigned char tag_subj[] = { 0x00, 0x00, 0x00, 0x01 };
+static unsigned char tag_csub[] = { 0x00, 0x00, 0x00, 0x02 };
+static unsigned char tag_uid[] = { 0x00, 0x00, 0x00, 0x03 };
+static unsigned char tag_crl[] = { 0x00, 0x00, 0x00, 0x04 };
+static unsigned char tag_ca[] = { 0x00, 0x00, 0x00, 0x05 };
+static unsigned char tag_dns[] = { 0x00, 0x00, 0x00, 0x06 };
+static unsigned char tag_ip[] = { 0x00, 0x00, 0x00, 0x07 };
+
+#define DBZ(x) memset(&(x), 0, sizeof((x)))
+
+static XMAP_METHOD xmap_db_methods = {
+  "db",
+  XMAP_DB_lookup,
+  XMAP_DB_dump,
+  XMAP_DB_free,
+  XMAP_DB_new
+};
+
+void *
+XMAP_DB_new(const char *dbname)
+{
+  XMAP_DB *ret;
+
+  if ((ret = alloc_thing(XMAP_DB, "xmap_db")) == NULL) goto end;
+  if ((ret->dbname = clone_bytes(dbname, strlen(dbname)+1, "dbname")) == NULL)
+    goto end;
+  if ((ret->db = dbopen(dbname, O_RDONLY, 0, DB_HASH, NULL)) == NULL)
+    goto end;
+
+  ret->meth = &xmap_db_methods;
+
+  return (void *)ret;
+ end:
+  if (ret->db) ret->db->close(ret->db);
+  if (ret->dbname) pfree(ret->dbname);
+  if (ret) pfree(ret);
+  return NULL;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_DB_lookup( void *this, const int type, const char *index, void *p )
+{
+  XMAP_DB *xm = (XMAP_DB *)this;
+
+  switch(type) {
+  case X509_LU_X509:
+    if (strcasecmp(index, "subject") == 0)
+      return XMAP_DB_lookup_cert_by_subject( xm, (X509_NAME *)p);
+    else if (strcasecmp(index, "uid") == 0)
+      return XMAP_DB_lookup_cert_by_uid( xm, (char  *)p);
+    else if (strcasecmp(index, "dns") == 0)
+      return XMAP_DB_lookup_cert_by_dns( xm, (char  *)p);
+    else if (strcasecmp(index, "ip") == 0)
+      return XMAP_DB_lookup_cert_by_ip( xm, *((struct in_addr *)p));
+    else if (strcasecmp(index, "ca") == 0)
+      return XMAP_DB_lookup_ca_certs( xm );
+    else
+      return NULL;
+    break;
+  case X509_LU_CRL:
+    if (strcasecmp(index, "issuer") == 0)
+      return XMAP_DB_lookup_crl_by_issuer( xm, (X509_NAME *)p);
+    else
+      return NULL;
+    break;
+  default:
+    return NULL;
+  }
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_DB_lookup_cert_by_subject(XMAP_DB *xm, X509_NAME *name)
+{
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+  DBT k, v;
+  unsigned char *d, *dum;
+  unsigned int i, dlen;
+
+  DBZ(k);
+  DBZ(v);
+  if (!xm->db) goto end;
+  dlen = i2d_X509_NAME(name, NULL);
+  if ((d = alloc_bytes(dlen + TAGLEN, "ASN.1 name")) == NULL) goto end;
+  dum = &d[TAGLEN];
+  memcpy(d, tag_subj, TAGLEN);
+  i2d_X509_NAME(name, &dum);
+  k.data = d;
+  k.size = dlen + TAGLEN;
+  if (xm->db->get(xm->db, &k, &v, 0) == 0) {
+    u_int32_t c1, c2;
+
+    memcpy((unsigned char *)&c1, v.data, sizeof(c1));
+    c2 = ntohl(c1);
+    pfree(d); d = NULL;
+    dlen = SHA_DIGEST_LENGTH + TAGLEN;
+    if ((d = alloc_bytes(dlen, "SHA-1 tag")) == NULL) goto end;
+    memcpy(d, tag_cert, TAGLEN);
+    for(i=0; i<c2; i++) {
+      unsigned char *vv = v.data;
+      DBT v2;
+
+      DBZ(v2);
+      memcpy(&(d[TAGLEN]), &vv[i*SHA_DIGEST_LENGTH+TAGLEN], SHA_DIGEST_LENGTH);
+      k.data = d;
+      k.size = dlen;
+      if (xm->db->get(xm->db, &k, &v2, 0) == 0) {
+	X509 *x;
+	dum = (unsigned char *)v2.data;
+	if ((x = d2i_X509(NULL, &dum, v2.size)) != NULL) {
+	  X509_OBJECT *xo = X509_OBJECT_new( X509_LU_X509, x);
+	  if (x)
+	    sk_X509_OBJECT_push(sk, xo);
+	  else
+	    X509_free(x);
+	}
+      }
+    }
+    pfree(d); d = NULL;
+  }
+ end:
+  if (d) pfree(d);
+  return sk;
+}
+
+static int
+isCA( X509 *x )
+{
+  X509_EXTENSION *ext;
+  BASIC_CONSTRAINTS *p = NULL;
+  int loc;
+  
+  loc = X509_get_ext_by_NID(x, NID_basic_constraints, -1);
+  if (loc >= 0) {
+    ext = X509_get_ext(x, loc);
+    if (ext) {
+      p = X509V3_EXT_d2i(ext);
+      if (! p->ca) {
+	BASIC_CONSTRAINTS_free(p);
+	return 0;
+      } else {
+	BASIC_CONSTRAINTS_free(p);
+	return 1; /* This is a CA certificate */
+      }
+    } else
+      return 0;
+  } else
+    return 0;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_DB_lookup_crl_by_issuer(XMAP_DB *xm, X509_NAME *name)
+{
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+  DBT k, v;
+  unsigned char *d, *dum;
+  unsigned int i, dlen;
+
+  DBZ(k);
+  DBZ(v);
+  if (!xm->db) goto end;
+  dlen = i2d_X509_NAME(name, NULL);
+  if ((d = alloc_bytes(dlen + TAGLEN, "ASN.1 name")) == NULL) goto end;
+  dum = &d[TAGLEN];
+  memcpy(d, tag_csub, TAGLEN);
+  i2d_X509_NAME(name, &dum);
+  k.data = d;
+  k.size = dlen + TAGLEN;
+  if (xm->db->get(xm->db, &k, &v, 0) == 0) {
+    u_int32_t c1, c2;
+
+    memcpy((unsigned char *)&c1, v.data, sizeof(c1));
+    c2 = ntohl(c1);
+    pfree(d); d = NULL;
+    dlen = SHA_DIGEST_LENGTH + TAGLEN;
+    if ((d = alloc_bytes(dlen, "SHA-1 tag")) == NULL) goto end;
+    memcpy(d, tag_crl, TAGLEN);
+    for(i=0; i<c2; i++) {
+      unsigned char *vv = v.data;
+      DBT v2;
+
+      DBZ(v2);
+      memcpy(&(d[TAGLEN]), &vv[i*SHA_DIGEST_LENGTH+TAGLEN], SHA_DIGEST_LENGTH);
+      k.data = d;
+      k.size = dlen;
+      if (xm->db->get(xm->db, &k, &v2, 0) == 0) {
+	X509_CRL *c;
+	dum = (unsigned char *)v2.data;
+	if ((c = d2i_X509_CRL(NULL, &dum, v2.size)) != NULL) {
+	  X509_OBJECT *xo = X509_OBJECT_new(X509_LU_CRL, c);
+
+	  if (xo)
+	    sk_X509_OBJECT_push(sk, xo);
+	  else
+	    X509_CRL_free(c);
+	}
+      }
+    }
+    pfree(d); d = NULL;
+  }
+ end:
+  if (d) pfree(d);
+  return sk;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_DB_lookup_ca_certs( XMAP_DB *xm )
+{
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+  DBT k, v;
+  unsigned char *d, *dum;
+  unsigned int i, dlen;
+
+  DBZ(k);
+  DBZ(v);
+  if (!xm->db) goto end;
+  if ((d = alloc_bytes(TAGLEN, "CA tag")) == NULL) goto end;
+  memcpy(d, tag_ca, TAGLEN);
+  k.data = d;
+  k.size = TAGLEN;
+  if (xm->db->get(xm->db, &k, &v, 0) == 0) {
+    u_int32_t c1, c2;
+
+    memcpy((unsigned char *)&c1, v.data, sizeof(c1));
+    c2 = ntohl(c1);
+    pfree(d); d = NULL;
+    dlen = SHA_DIGEST_LENGTH + TAGLEN;
+    if ((d = alloc_bytes(dlen, "SHA-1 tag")) == NULL) goto end;
+    memcpy(d, tag_cert, TAGLEN);
+    for(i=0; i<c2; i++) {
+      unsigned char *vv = v.data;
+      DBT v2;
+
+      DBZ(v2);
+      memcpy(&(d[TAGLEN]), &vv[(i*SHA_DIGEST_LENGTH)+TAGLEN],
+	     SHA_DIGEST_LENGTH);
+      k.data = d;
+      k.size = dlen;
+      if (xm->db->get(xm->db, &k, &v2, 0) == 0) {
+	X509 *x;
+	dum = (unsigned char *)v2.data;
+	if (((x = d2i_X509(NULL, &dum, v2.size)) != NULL) && (isCA(x))) {
+	  X509_OBJECT *xo = X509_OBJECT_new( X509_LU_X509, x);
+
+	  if (xo) 
+	    sk_X509_OBJECT_push(sk, xo);
+	  else
+	    X509_free(x);
+	}
+      }
+    }
+    pfree(d); d = NULL;
+  }
+ end:
+  if (d) pfree(d);
+  return sk;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_DB_lookup_cert_by_uid(XMAP_DB *xm, const char *uid)
+{
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+  DBT k, v;
+  unsigned char *d, *dum;
+  unsigned int i, ulen, dlen;
+
+  DBZ(k);
+  DBZ(v);
+  if (!xm->db) goto end;
+  ulen = strlen(uid);
+  if ((d = alloc_bytes(ulen + TAGLEN, "uid tag")) == NULL) goto end;
+  memcpy(d, tag_uid, TAGLEN);
+  strncpy(&d[TAGLEN], uid, ulen);
+  k.data = d;
+  k.size = ulen + TAGLEN;
+  if (xm->db->get(xm->db, &k, &v, 0) == 0) {
+    u_int32_t c1, c2;
+
+    memcpy((unsigned char *)&c1, v.data, sizeof(c1));
+    c2 = ntohl(c1);
+    pfree(d); d = NULL;
+    dlen = SHA_DIGEST_LENGTH + TAGLEN;
+    if ((d = alloc_bytes(dlen, "SHA-1 tag")) == NULL) goto end;
+    memcpy(d, tag_cert, TAGLEN);
+    for(i=0; i<c2; i++) {
+      unsigned char *vv = v.data;
+      DBT v2;
+
+      DBZ(v2);
+      memcpy(&(d[TAGLEN]), &vv[(i*SHA_DIGEST_LENGTH)+TAGLEN],
+	     SHA_DIGEST_LENGTH);
+      k.data = d;
+      k.size = dlen;
+      if (xm->db->get(xm->db, &k, &v2, 0) == 0) {
+	X509 *x;
+	dum = (unsigned char *)v2.data;
+	if ((x = d2i_X509(NULL, &dum, v2.size)) != NULL) {
+	  X509_OBJECT *xo = X509_OBJECT_new( X509_LU_X509, x);
+
+	  if (xo) 
+	    sk_X509_OBJECT_push(sk, xo);
+	  else
+	    X509_free(x);
+	}
+      }
+    }
+    pfree(d); d = NULL;
+  }
+ end:
+  if (d) pfree(d);
+  return sk;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_DB_lookup_cert_by_dns(XMAP_DB *xm, const char *dns)
+{
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+  DBT k, v;
+  unsigned char *d, *dum;
+  unsigned int i, ulen, dlen;
+
+  DBZ(k);
+  DBZ(v);
+  if (!xm->db) goto end;
+  ulen = strlen(dns);
+  if ((d = alloc_bytes(ulen + TAGLEN, "dns tag")) == NULL) goto end;
+  memcpy(d, tag_dns, TAGLEN);
+  strncpy(&d[TAGLEN], dns, ulen);
+  k.data = d;
+  k.size = ulen + TAGLEN;
+  if (xm->db->get(xm->db, &k, &v, 0) == 0) {
+    u_int32_t c1, c2;
+
+    memcpy((unsigned char *)&c1, v.data, sizeof(c1));
+    c2 = ntohl(c1);
+    pfree(d); d = NULL;
+    dlen = SHA_DIGEST_LENGTH + TAGLEN;
+    if ((d = alloc_bytes(dlen, "SHA-1 tag")) == NULL) goto end;
+    memcpy(d, tag_cert, TAGLEN);
+    for(i=0; i<c2; i++) {
+      unsigned char *vv = v.data;
+      DBT v2;
+
+      DBZ(v2);
+      memcpy(&(d[TAGLEN]), &vv[(i*SHA_DIGEST_LENGTH)+TAGLEN],
+	     SHA_DIGEST_LENGTH);
+      k.data = d;
+      k.size = dlen;
+      if (xm->db->get(xm->db, &k, &v2, 0) == 0) {
+	X509 *x;
+	dum = (unsigned char *)v2.data;
+	if ((x = d2i_X509(NULL, &dum, v2.size)) != NULL) {
+	  if (X509_subjAltName_check_dns(x, dns)) {
+	    X509_OBJECT *xo = X509_OBJECT_new( X509_LU_X509, x);
+	    
+	    if (xo) 
+	      sk_X509_OBJECT_push(sk, xo);
+	    else
+	      X509_free(x);
+	  } else 
+	    X509_free(x);
+	}
+      }
+    }
+    pfree(d); d = NULL;
+  }
+ end:
+  if (d) free(d);
+  return sk;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_DB_lookup_cert_by_ip(XMAP_DB *xm, const struct in_addr ip)
+{
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+  DBT k, v;
+  unsigned char *d, *dum;
+  unsigned int i, ulen, dlen;
+
+  DBZ(k);
+  DBZ(v);
+  if (!xm->db) goto end;
+  ulen = sizeof(ip.s_addr);
+  if ((d = alloc_bytes(ulen + TAGLEN, "ip tag")) == NULL) goto end;
+  memcpy(d, tag_ip, TAGLEN);
+  memcpy(&d[TAGLEN], &ip.s_addr, ulen);
+  k.data = d;
+  k.size = ulen + TAGLEN;
+  if (xm->db->get(xm->db, &k, &v, 0) == 0) {
+    u_int32_t c1, c2;
+
+    memcpy((unsigned char *)&c1, v.data, sizeof(c1));
+    c2 = ntohl(c1);
+    pfree(d); d = NULL;
+    dlen = SHA_DIGEST_LENGTH + TAGLEN;
+    if ((d = alloc_bytes(dlen, "SHA-1 tag")) == NULL) goto end;
+    memcpy(d, tag_cert, TAGLEN);
+    for(i=0; i<c2; i++) {
+      unsigned char *vv = v.data;
+      DBT v2;
+
+      DBZ(v2);
+      memcpy(&(d[TAGLEN]), &vv[(i*SHA_DIGEST_LENGTH)+TAGLEN],
+	     SHA_DIGEST_LENGTH);
+      k.data = d;
+      k.size = dlen;
+      if (xm->db->get(xm->db, &k, &v2, 0) == 0) {
+	X509 *x;
+	dum = (unsigned char *)v2.data;
+
+	DBG(DBG_PARSING | DBG_RAW,
+	DBG_log("** v2 length: %d", v2.size);
+	);
+    DBG(DBG_RAW,
+    DBG_dump("** v2: ", v2.data, v2.size);
+	);
+
+	if ((x = d2i_X509(NULL, &dum, v2.size)) != NULL) {
+	  if (X509_subjAltName_check_ip(x, ip)) {
+	    X509_OBJECT *xo = X509_OBJECT_new( X509_LU_X509, x);
+	    
+	    if (xo) 
+	      sk_X509_OBJECT_push(sk, xo);
+	    else
+	      X509_free(x);
+	  }
+	} else
+	  X509_free(x);
+      }
+    }
+    pfree(d); d = NULL;
+  }
+ end:
+  if (d) pfree(d);
+  return sk;
+}
+
+static void
+XMAP_DB_dump(void *this)
+{
+  XMAP_DB *xm = (XMAP_DB *)this;
+  DBG(DBG_PARSING,
+  DBG_log("XMAP_DB: %s", xm->dbname);
+  );
+}
+
+static void
+XMAP_DB_free(void *this)
+{
+  XMAP_DB *xm = (XMAP_DB *)this;
+
+  if (!xm) return;
+  if (xm->dbname) pfree(xm->dbname);
+  if (xm->db) xm->db->close(xm->db);
+  pfree(xm);
+}
+
+XMAP_METHOD *
+XMAP_METHOD_db( void )
+{
+  return (&xmap_db_methods);
+}
+#endif /* HAVE_DB */
diff -ruN freeswan-1.5.orig/pluto/xmap_db.h freeswan-1.5/pluto/xmap_db.h
--- freeswan-1.5.orig/pluto/xmap_db.h	Wed Dec 31 19:00:00 1969
+++ freeswan-1.5/pluto/xmap_db.h	Thu Oct  5 07:05:59 2000
@@ -0,0 +1,27 @@
+#ifndef XMAP_DB_H
+#define XMAP_DB_H
+
+#if defined(HAVE_DB) || defined(HAVE_DB185)
+
+#include <openssl/safestack.h>
+#include <openssl/x509.h>
+
+#ifdef HAVE_DB185
+#include <db_185.h>
+#else
+#include <db.h>
+#endif
+
+#include "x_sobj.h"
+#include "xmap.h"
+
+typedef struct xmap_db_st {
+  char *dbname;
+  DB *db;
+  XMAP_METHOD *meth;
+} XMAP_DB;
+
+XMAP_METHOD *XMAP_METHOD_db( void );
+
+#endif /* HAVE_DB */
+#endif /* XMAP_DB_H */
diff -ruN freeswan-1.5.orig/pluto/xmap_dir.c freeswan-1.5/pluto/xmap_dir.c
--- freeswan-1.5.orig/pluto/xmap_dir.c	Wed Dec 31 19:00:00 1969
+++ freeswan-1.5/pluto/xmap_dir.c	Thu Oct  5 07:05:59 2000
@@ -0,0 +1,486 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include "xmap_dir.h"
+#include "xmap.h"
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+
+static void XMAP_DIR_dump(void *this);
+static void XMAP_DIR_free(void *this);
+static void *XMAP_DIR_new(const char *dir);
+static STACK_OF(X509_OBJECT) *
+XMAP_DIR_lookup( void *this, const int type, const char *index, void *p );
+static STACK_OF(X509_OBJECT) *
+XMAP_DIR_lookup_cert_by_subject( XMAP_DIR *xm, X509_NAME *name );
+static STACK_OF(X509_OBJECT) *
+XMAP_DIR_lookup_crl_by_issuer( XMAP_DIR *xm, X509_NAME *name );
+static STACK_OF(X509_OBJECT) *
+XMAP_DIR_lookup_cert_by_uid( XMAP_DIR *xm, const char *uid );
+static STACK_OF(X509_OBJECT) *
+XMAP_DIR_lookup_cert_by_dns( XMAP_DIR *xm, const char *dns );
+static STACK_OF(X509_OBJECT) *
+XMAP_DIR_lookup_cert_by_ip( XMAP_DIR *xm, const struct in_addr ip );
+static STACK_OF(X509_OBJECT) *
+XMAP_DIR_lookup_ca_certs( XMAP_DIR *xm );
+
+static XMAP_METHOD xmap_dir_methods = {
+  "dir",
+  XMAP_DIR_lookup,
+  XMAP_DIR_dump,
+  XMAP_DIR_free,
+  XMAP_DIR_new
+};
+
+static void *
+XMAP_DIR_new(const char *dir)
+{
+  XMAP_DIR *ret;
+
+  if ((ret = alloc_thing(XMAP_DIR, "xmap_dir")) == NULL) goto end;
+  if ((ret->dir = clone_bytes(dir, strlen(dir)+1, "directory name")) == NULL)
+    goto end;
+  ret->meth = &xmap_dir_methods;
+
+  return (void *)ret;
+ end:
+  if (ret->dir) pfree(ret->dir);
+  if (ret) pfree(ret);
+  return NULL;
+}
+
+static int
+isCA( X509 *x )
+{
+  X509_EXTENSION *ext;
+  BASIC_CONSTRAINTS *p = NULL;
+  int loc;
+  
+  loc = X509_get_ext_by_NID(x, NID_basic_constraints, -1);
+  if (loc >= 0) {
+    ext = X509_get_ext(x, loc);
+    if (ext) {
+      p = X509V3_EXT_d2i(ext);
+      if (! p->ca) {
+	BASIC_CONSTRAINTS_free(p);
+	return 0;
+      } else {
+	BASIC_CONSTRAINTS_free(p);
+	return 1; /* This is a CA certificate */
+      }
+    } else
+      return 0;
+  } else
+    return 0;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_DIR_lookup( void *this, const int type, const char *index, void *p )
+{
+  XMAP_DIR *xm = (XMAP_DIR *)this;
+
+  switch(type) {
+  case X509_LU_X509:
+    if (strcasecmp(index, "subject") == 0)
+      return XMAP_DIR_lookup_cert_by_subject( xm, (X509_NAME *)p);
+    else if (strcasecmp(index, "uid") == 0)
+      return XMAP_DIR_lookup_cert_by_uid( xm, (char  *)p);
+    else if (strcasecmp(index, "dns") == 0)
+      return XMAP_DIR_lookup_cert_by_dns( xm, (char  *)p);
+    else if (strcasecmp(index, "ip") == 0)
+      return XMAP_DIR_lookup_cert_by_ip( xm, *(struct in_addr *)p);
+    else if (strcasecmp(index, "ca") == 0)
+      return XMAP_DIR_lookup_ca_certs( xm );
+    else
+      return NULL;
+    break;
+  case X509_LU_CRL:
+    if (strcasecmp(index, "issuer") == 0)
+      return XMAP_DIR_lookup_crl_by_issuer( xm, (X509_NAME *)p);
+    else
+      return NULL;
+    break;
+  default:
+    return NULL;
+  }
+}
+
+static char hashval[PATH_MAX+1] = "";
+static char dirname[PATH_MAX+1] = "";
+
+static int
+hash_select(const struct dirent *de)
+{
+  int l = strlen(hashval);
+
+  if (strncmp(de->d_name, hashval, l) == 0) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+static int
+select_files(const struct dirent *de)
+{
+  struct stat st;
+  char path[PATH_MAX+1];
+  
+  snprintf(path, sizeof(path), "%s/%s", dirname, de->d_name);
+  if (lstat(path, &st) == 0) {
+    if (S_ISREG(st.st_mode))
+      return 1;
+    else
+      return 0;
+  } else {
+    log("error in stat: %s", strerror(errno));
+    return 0;
+  }     
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_DIR_lookup_cert_by_subject( XMAP_DIR *xm, X509_NAME *name )
+{
+  char path[PATH_MAX+1];
+  int n;
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+  struct dirent **flist;
+
+  if (!sk) return sk;
+  snprintf(hashval, sizeof(hashval)-1, "%08lx.cert", X509_NAME_hash(name));
+  n = scandir(xm->dir, &flist, hash_select, alphasort);
+  if (n < 0)
+    log("error on scandir: %s", strerror(errno));
+  else {
+    int i;
+
+    for(i=0; i<n; i++) {
+      BIO *b;
+
+      snprintf(path, sizeof(path)-1, "%s/%s", xm->dir, flist[i]->d_name);
+      
+      if ((b = BIO_new_file(path, "r")) != NULL) {
+	X509 *x;
+
+	/* Try a PEM load first, then try DER if it fails */
+	if ((x = PEM_read_bio_X509(b, NULL, NULL, NULL)) == NULL) {
+	  BIO_ctrl(b, BIO_CTRL_RESET, 0, NULL);
+	  x = d2i_X509_bio(b, NULL); /* Try DER loading */
+	}
+
+	if (x) {
+	  if (X509_NAME_cmp(X509_get_subject_name(x), name) == 0) {
+	    X509_OBJECT *xo = X509_OBJECT_new(X509_LU_X509, x);
+
+	    if (x) {
+	      sk_X509_OBJECT_push(sk, xo);
+	    } else
+	      X509_free(x);
+	  } else
+	    X509_free(x);
+	}
+
+	BIO_free(b);
+      } else {
+	ERR_print_errors_fp(stderr);
+      }
+    }
+    if (n > 0) free(flist);
+  }
+  return sk;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_DIR_lookup_ca_certs( XMAP_DIR *xm )
+{
+  char path[PATH_MAX+1];
+  int n;
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+  struct dirent **flist;
+
+  if (!sk) return sk;
+  strncpy(dirname, xm->dir, sizeof(dirname)-1);
+  n = scandir(xm->dir, &flist, select_files, alphasort);
+  if (n < 0)
+    log("error in scandir: %s", strerror(errno));
+  else {
+    int i;
+
+    for(i=0; i<n; i++) {
+      BIO *b;
+
+      snprintf(path, sizeof(path)-1, "%s/%s", xm->dir, flist[i]->d_name);
+      
+      if ((b = BIO_new_file(path, "r")) != NULL) {
+	X509 *x;
+
+	/* Try a PEM load first, then try DER if it fails */
+	if ((x = PEM_read_bio_X509(b, NULL, NULL, NULL)) == NULL) {
+	  BIO_ctrl(b, BIO_CTRL_RESET, 0, NULL);
+	  x = d2i_X509_bio(b, NULL); /* Try DER loading */
+	}
+
+	if (x) {
+	  if (isCA(x)) {
+	    X509_OBJECT *xo = X509_OBJECT_new(X509_LU_X509, x);
+
+	    if (xo) {
+	      sk_X509_OBJECT_push(sk, xo);
+	    } else
+	      X509_free(x);
+	  } else
+	    X509_free(x);
+	}
+
+	BIO_free(b);
+      } else {
+	ERR_print_errors_fp(stderr);
+      }
+    }
+    if (n > 0) free(flist);
+  }
+  return sk;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_DIR_lookup_crl_by_issuer( XMAP_DIR *xm, X509_NAME *name )
+{
+  char path[PATH_MAX+1];
+  int n;
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+  struct dirent **flist;
+
+  if (!sk) return sk;
+  snprintf(hashval, sizeof(hashval)-1, "%08lx.crl", X509_NAME_hash(name));
+  n = scandir(xm->dir, &flist, hash_select, alphasort);
+  if (n < 0)
+    log("error in scandir: %s", strerror(errno));
+  else {
+    int i;
+
+    for(i=0; i<n; i++) {
+      BIO *b;
+
+      snprintf(path, sizeof(path)-1, "%s/%s", xm->dir, flist[i]->d_name);
+
+      if ((b = BIO_new_file(path, "r")) != NULL) {
+	X509_CRL *c;
+
+	/* Try a PEM load first, then try DER if it fails */
+	if ((c = PEM_read_bio_X509_CRL(b, NULL, NULL, NULL)) == NULL) {
+	  BIO_ctrl(b, BIO_CTRL_RESET, 0, NULL);
+	  c = d2i_X509_CRL_bio(b, NULL); /* Try DER loading */
+	}
+
+	if (c) {
+	  if (X509_NAME_cmp(X509_CRL_get_issuer(c), name) == 0) {
+	    X509_OBJECT *xo = X509_OBJECT_new(X509_LU_CRL, c);
+	    if (xo)
+	      sk_X509_OBJECT_push(sk, xo);
+	    else
+	      X509_CRL_free(c);
+	  } else
+	    X509_CRL_free(c);
+	}
+
+	BIO_free(b);
+      } else {
+	ERR_print_errors_fp(stderr);
+      }
+    }
+    if (n > 0) free(flist);
+  }
+  return sk;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_DIR_lookup_cert_by_uid( XMAP_DIR *xm, const char *uid )
+{
+  char path[PATH_MAX+1];
+  int n;
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+  struct dirent **flist;
+
+  if (!sk) return sk;
+  snprintf(hashval, sizeof(hashval)-1, "uid-%s", uid);
+  n = scandir(xm->dir, &flist, hash_select, alphasort);
+  if (n < 0)
+    log("error in scandir: %s", strerror(errno));
+  else {
+    int i;
+
+    for(i=0; i<n; i++) {
+      BIO *b;
+
+      snprintf(path, sizeof(path)-1, "%s/%s", xm->dir, flist[i]->d_name);
+      
+      if ((b = BIO_new_file(path, "r")) != NULL) {
+	X509 *x;
+
+	/* Try a PEM load first, then try DER if it fails */
+	if ((x = PEM_read_bio_X509(b, NULL, NULL, NULL)) == NULL) {
+	  BIO_ctrl(b, BIO_CTRL_RESET, 0, NULL);
+	  x = d2i_X509_bio(b, NULL); /* Try DER loading */
+	}
+
+	if (x) {
+	  X509_OBJECT *xo = X509_OBJECT_new(X509_LU_X509, x);
+	  if (xo)
+	    sk_X509_OBJECT_push(sk, xo);
+	  else 
+	    X509_free(x);
+	}
+
+	BIO_free(b);
+      } else {
+	ERR_print_errors_fp(stderr);
+      }
+    }
+    if (n > 0) free(flist);
+  }
+  return sk;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_DIR_lookup_cert_by_dns( XMAP_DIR *xm, const char *dns )
+{
+  char path[PATH_MAX+1];
+  int n;
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+  struct dirent **flist;
+
+  if (!sk) return sk;
+  snprintf(hashval, sizeof(hashval)-1, "dns-%s", dns);
+  n = scandir(xm->dir, &flist, hash_select, alphasort);
+  if (n < 0)
+    log("error in scandir: %s", strerror(errno));
+  else {
+    int i;
+
+    for(i=0; i<n; i++) {
+      BIO *b;
+
+      snprintf(path, sizeof(path)-1, "%s/%s", xm->dir, flist[i]->d_name);
+      
+      if ((b = BIO_new_file(path, "r")) != NULL) {
+	X509 *x;
+
+	/* Try a PEM load first, then try DER if it fails */
+	if ((x = PEM_read_bio_X509(b, NULL, NULL, NULL)) == NULL) {
+	  BIO_ctrl(b, BIO_CTRL_RESET, 0, NULL);
+	  x = d2i_X509_bio(b, NULL); /* Try DER loading */
+	}
+
+	if (x) {
+	  if (X509_subjAltName_check_dns(x, dns)) {
+	    X509_OBJECT *xo = X509_OBJECT_new(X509_LU_X509, x);
+	    if (xo)
+	      sk_X509_OBJECT_push(sk, xo);
+	    else 
+	      X509_free(x);
+	  }
+	} else {
+	  X509_free(x);
+	}
+
+	BIO_free(b);
+      } else {
+	ERR_print_errors_fp(stderr);
+      }
+    }
+    if (n > 0) free(flist);
+  }
+  return sk;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_DIR_lookup_cert_by_ip( XMAP_DIR *xm, const struct in_addr ip )
+{
+  char path[PATH_MAX+1];
+  int n;
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+  struct dirent **flist;
+
+  if (!sk) return sk;
+  
+  snprintf(hashval, sizeof(hashval)-1, "ip-%s", inet_ntoa(ip));
+  n = scandir(xm->dir, &flist, hash_select, alphasort);
+  if (n < 0)
+    log("error in scandir: %s", strerror(errno));
+  else {
+    int i;
+
+    for(i=0; i<n; i++) {
+      BIO *b;
+
+      snprintf(path, sizeof(path)-1, "%s/%s", xm->dir, flist[i]->d_name);
+      
+      if ((b = BIO_new_file(path, "r")) != NULL) {
+	X509 *x;
+
+	/* Try a PEM load first, then try DER if it fails */
+	if ((x = PEM_read_bio_X509(b, NULL, NULL, NULL)) == NULL) {
+	  BIO_ctrl(b, BIO_CTRL_RESET, 0, NULL);
+	  x = d2i_X509_bio(b, NULL); /* Try DER loading */
+	}
+
+	if (x) {
+	  if (X509_subjAltName_check_ip(x, ip)) {
+	    X509_OBJECT *xo = X509_OBJECT_new(X509_LU_X509, x);
+	    if (xo)
+	      sk_X509_OBJECT_push(sk, xo);
+	    else 
+	      X509_free(x);
+	  }
+	} else {
+	  X509_free(x);
+	}
+
+	BIO_free(b);
+      } else {
+	ERR_print_errors_fp(stderr);
+      }
+    }
+    if (n > 0) free(flist);
+  }
+  return sk;
+}
+
+static void
+XMAP_DIR_dump(void *this)
+{
+  XMAP_DIR *xm = (XMAP_DIR *)this;
+  DBG_log("XMAP_DIR: %s", xm->dir);
+}
+
+static void
+XMAP_DIR_free(void *this)
+{
+  XMAP_DIR *xm = (XMAP_DIR *)this;
+
+  if (!xm) return;
+  if (xm->dir) pfree(xm->dir);
+  free(xm);
+}
+
+XMAP_METHOD *
+XMAP_METHOD_dir( void )
+{
+  return (&xmap_dir_methods);
+}
diff -ruN freeswan-1.5.orig/pluto/xmap_dir.h freeswan-1.5/pluto/xmap_dir.h
--- freeswan-1.5.orig/pluto/xmap_dir.h	Wed Dec 31 19:00:00 1969
+++ freeswan-1.5/pluto/xmap_dir.h	Thu Oct  5 07:05:59 2000
@@ -0,0 +1,17 @@
+#ifndef XMAP_DIR_H
+#define XMAP_DIR_H
+
+#include <openssl/safestack.h>
+#include <openssl/x509.h>
+
+#include "x_sobj.h"
+#include "xmap.h"
+
+typedef struct xmap_dir_st {
+  char *dir;
+  XMAP_METHOD *meth;
+} XMAP_DIR;
+
+XMAP_METHOD *XMAP_METHOD_dir( void );
+
+#endif /* XMAP_DIR_H */
diff -ruN freeswan-1.5.orig/pluto/xmap_file.c freeswan-1.5/pluto/xmap_file.c
--- freeswan-1.5.orig/pluto/xmap_file.c	Wed Dec 31 19:00:00 1969
+++ freeswan-1.5/pluto/xmap_file.c	Thu Oct  5 07:05:59 2000
@@ -0,0 +1,329 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <regex.h>
+
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+#include <openssl/x509v3.h>
+
+#include "xmap.h"
+#include "xmap_file.h"
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+
+static void XMAP_FILE_dump(void *this);
+static void XMAP_FILE_free(void *this);
+static void *XMAP_FILE_new(const char *file);
+static int isCA( X509 *x );
+static STACK_OF(X509_OBJECT) *
+XMAP_FILE_lookup( void *this, const int type, const char *index, void *p );
+static STACK_OF(X509_OBJECT) *
+XMAP_FILE_lookup_cert_by_subject( XMAP_FILE *xm, X509_NAME *name );
+static STACK_OF(X509_OBJECT) *
+XMAP_FILE_lookup_crl_by_issuer( XMAP_FILE *xm, X509_NAME *name );
+static STACK_OF(X509_OBJECT) *
+XMAP_FILE_lookup_cert_by_uid( XMAP_FILE *xm, const char *uid );
+static STACK_OF(X509_OBJECT) *
+XMAP_FILE_lookup_cert_by_dns( XMAP_FILE *xm, const char *dns );
+static STACK_OF(X509_OBJECT) *
+XMAP_FILE_lookup_cert_by_ip( XMAP_FILE *xm, const struct in_addr ip );
+static STACK_OF(X509_OBJECT) *
+XMAP_FILE_lookup_ca_certs( XMAP_FILE *xm );
+
+static XMAP_METHOD xmap_file_methods = {
+  "file",
+  XMAP_FILE_lookup,
+  XMAP_FILE_dump,
+  XMAP_FILE_free,
+  XMAP_FILE_new
+};
+
+/* Pattern is (ignoring lower/upper case --
+ * <whitespace>uid:<whitespace><alphanumeric user id><whitespace>
+ */
+#define UID_REGEX \
+"^[[:space:]]*[Uu][Ii][Dd]:[[:space:]]*([[:alnum:]]+)[[:space:]]$"
+
+static int
+isCA( X509 *x )
+{
+  X509_EXTENSION *ext;
+  BASIC_CONSTRAINTS *p = NULL;
+  int loc;
+  
+  loc = X509_get_ext_by_NID(x, NID_basic_constraints, -1);
+  if (loc >= 0) {
+    ext = X509_get_ext(x, loc);
+    if (ext) {
+      p = X509V3_EXT_d2i(ext);
+      if (! p->ca) {
+	BASIC_CONSTRAINTS_free(p);
+	return 0;
+      } else {
+	BASIC_CONSTRAINTS_free(p);
+	return 1; /* This is a CA certificate */
+      }
+    } else
+      return 0;
+  } else
+    return 0;
+}
+
+XMAP_METHOD *
+XMAP_METHOD_file( void )
+{
+  return (&xmap_file_methods);
+}
+
+static void *
+XMAP_FILE_new(const char *file)
+{
+  XMAP_FILE *ret;
+  int re_code;
+  char errbuf[257];
+
+  if ((ret = alloc_thing(XMAP_FILE, "xmap_file")) == NULL) goto end;
+  if ((ret->file = clone_bytes(file, strlen(file), "file name")) == NULL)
+    goto end;
+  if ((ret->bio = BIO_new_file(ret->file, "r")) == NULL) goto end;
+
+  if ((re_code = regcomp(&ret->uidreg, UID_REGEX, REG_EXTENDED)) != 0) {
+    regerror(re_code, &ret->uidreg, errbuf, sizeof(errbuf-1));
+    log("Regex Error: %s", errbuf);
+    goto end;
+  }
+
+  ret->meth = &xmap_file_methods;
+  return (void *)ret;
+ end:
+  if (ret->bio) BIO_free(ret->bio);
+  if (ret->file) pfree(ret->file);
+  if (ret) pfree(ret);
+  return NULL;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_FILE_lookup( void *this, const int type, const char *index, void *p )
+{
+  XMAP_FILE *xm = (XMAP_FILE *)this;
+
+  switch(type) {
+  case X509_LU_X509:
+    if (strcasecmp(index, "subject") == 0)
+	{
+		return XMAP_FILE_lookup_cert_by_subject( xm, (X509_NAME *)p);
+	}
+    else if (strcasecmp(index, "uid") == 0)
+	{
+		return XMAP_FILE_lookup_cert_by_uid( xm, (char  *)p);
+	}
+    else if (strcasecmp(index, "dns") == 0)
+	{
+		return XMAP_FILE_lookup_cert_by_dns( xm, (char  *)p);
+	}
+    else if (strcasecmp(index, "ip") == 0)
+	{
+		return XMAP_FILE_lookup_cert_by_ip( xm, *((struct in_addr *)p));
+	}
+    else if (strcasecmp(index, "ca") == 0)
+	{
+		return XMAP_FILE_lookup_ca_certs( xm );
+	}
+    else
+	{
+		return NULL;
+	}
+    break;
+  case X509_LU_CRL:
+    if (strcasecmp(index, "issuer") == 0)
+      return XMAP_FILE_lookup_crl_by_issuer( xm, (X509_NAME *)p);
+    else
+      return NULL;
+    break;
+  default:
+    return NULL;
+  }
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_FILE_lookup_cert_by_subject( XMAP_FILE *xm, X509_NAME *name )
+{
+  X509 *x;
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+
+  if (sk == NULL) return sk;
+  BIO_ctrl(xm->bio, BIO_CTRL_RESET, 0, NULL);
+  while ((x = PEM_read_bio_X509(xm->bio, NULL, NULL, NULL)) != NULL) {
+    if (X509_NAME_cmp(X509_get_subject_name(x), name) == 0) {
+      X509_OBJECT *xo = X509_OBJECT_new(X509_LU_X509, x);
+      if (xo) {
+	sk_X509_OBJECT_push(sk, xo);
+      } else
+	X509_free(x);
+    } else
+      X509_free(x);
+  }
+  return sk;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_FILE_lookup_ca_certs( XMAP_FILE *xm  )
+{
+  X509 *x;
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+
+  if (sk == NULL) return sk;
+  BIO_ctrl(xm->bio, BIO_CTRL_RESET, 0, NULL);
+  while ((x = PEM_read_bio_X509(xm->bio, NULL, NULL, NULL)) != NULL) {
+    if (isCA(x)) {
+      X509_OBJECT *xo = X509_OBJECT_new(X509_LU_X509, x);
+      if (xo) {
+	sk_X509_OBJECT_push(sk, xo);
+      } else
+	X509_free(x);
+    } else
+      X509_free(x);
+  }
+  return sk;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_FILE_lookup_crl_by_issuer( XMAP_FILE *xm, X509_NAME *name )
+{
+  X509_CRL *c;
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+
+  if (sk == NULL) return sk;
+  BIO_ctrl(xm->bio, BIO_CTRL_RESET, 0, NULL);
+  while ((c = PEM_read_bio_X509_CRL(xm->bio, NULL, NULL, NULL)) != NULL) {
+    if (X509_NAME_cmp(X509_CRL_get_issuer(c), name) == 0) {
+      X509_OBJECT *xo = X509_OBJECT_new(X509_LU_CRL, c);
+      if (xo) {
+	sk_X509_OBJECT_push(sk, xo);
+      } else
+	X509_CRL_free(c);
+    } else
+      X509_CRL_free(c);
+  }
+  return sk;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_FILE_lookup_cert_by_uid( XMAP_FILE *xm, const char *uid )
+{
+  char line[BUFSIZ+1], user[BUFSIZ+1];
+  regmatch_t pmatch[2];
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+  X509 *x;
+
+  if (sk == NULL) return sk;
+  BIO_ctrl(xm->bio, BIO_CTRL_RESET, 0, NULL);
+  while (BIO_gets(xm->bio, line, sizeof(line)-1)) {
+    if (!regexec(&xm->uidreg, line, 2, pmatch, 0))
+      if ((pmatch[1].rm_so != -1) && (pmatch[1].rm_eo != -1)) {
+	memset(user, 0, sizeof(user));
+	strncpy(user, &line[pmatch[1].rm_so],
+		pmatch[1].rm_eo - pmatch[1].rm_so);
+	if (strcmp(uid, user) == 0) {
+	  /* Found a match for the user id */
+	  if ((x = PEM_read_bio_X509(xm->bio, NULL, NULL, NULL)) != NULL) {
+	    X509_OBJECT *xo = X509_OBJECT_new( X509_LU_X509, x);
+	    if (xo) {
+	      sk_X509_OBJECT_push(sk, xo);
+	    } else 
+	      X509_free(x);
+	  }
+	}
+      }
+  }
+
+  return sk;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_FILE_lookup_cert_by_dns( XMAP_FILE *xm, const char *dns )
+{
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+  X509 *x;
+  int zap;
+  X509_OBJECT *xo;
+
+  if (sk == NULL) return sk;
+  BIO_ctrl(xm->bio, BIO_CTRL_RESET, 0, NULL);
+  while ((x = PEM_read_bio_X509(xm->bio, NULL, NULL, NULL)) != NULL) {
+    zap = X509_subjAltName_check_dns(x, dns) ? 0 : 1;
+    
+    if (zap)
+      X509_free(x);
+    else {
+      xo = X509_OBJECT_new( X509_LU_X509, x);
+      if (xo)
+	sk_X509_OBJECT_push(sk, xo);
+      else 
+	X509_free(x);
+    }
+  }
+
+  return sk;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_FILE_lookup_cert_by_ip( XMAP_FILE *xm, struct in_addr ip )
+{
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+  X509 *x;
+  int zap;
+  X509_OBJECT *xo;
+
+  if (sk == NULL) {
+    DBG(DBG_PARSING,
+    DBG_log("sk is NULL, returning NULL.");
+    );
+	return sk;
+  }
+  BIO_ctrl(xm->bio, BIO_CTRL_RESET, 0, NULL);
+  while ((x = PEM_read_bio_X509(xm->bio, NULL, NULL, NULL)) != NULL) {
+    zap = X509_subjAltName_check_ip(x, ip) ? 0 : 1;
+
+    if (zap)
+      X509_free(x);
+    else {
+      xo = X509_OBJECT_new( X509_LU_X509, x);
+      if (xo)
+		sk_X509_OBJECT_push(sk, xo);
+      else 
+		X509_free(x);
+    }
+  }
+
+  return sk;
+}
+
+static void
+XMAP_FILE_dump(void *this)
+{
+  XMAP_FILE *xm = (XMAP_FILE *)this;
+  DBG(DBG_CONTROL | DBG_PARSING,
+  DBG_log("XMAP_FILE: %s\n", xm->file);
+  );
+}
+
+static void
+XMAP_FILE_free(void *this)
+{
+  XMAP_FILE *xm = (XMAP_FILE *)this;
+
+  if (!xm) return;
+  regfree(&xm->uidreg);
+  if (xm->bio) BIO_free(xm->bio);
+  if (xm->file) pfree(xm->file);
+  pfree(xm);
+}
diff -ruN freeswan-1.5.orig/pluto/xmap_file.h freeswan-1.5/pluto/xmap_file.h
--- freeswan-1.5.orig/pluto/xmap_file.h	Wed Dec 31 19:00:00 1969
+++ freeswan-1.5/pluto/xmap_file.h	Thu Oct  5 07:05:59 2000
@@ -0,0 +1,28 @@
+#ifndef XMAP_FILE_H
+#define XMAP_FILE_H
+
+#include <regex.h>
+
+#include <openssl/safestack.h>
+#include <openssl/bio.h>
+#include <openssl/x509.h>
+#include <openssl/x509_vfy.h>
+
+#include "x_sobj.h"
+#include "xmap.h"
+
+typedef struct xmap_file_st {
+  char *file;
+  BIO *bio;
+  regex_t uidreg;
+  regex_t ipreg;
+  XMAP_METHOD *meth;
+} XMAP_FILE;
+
+XMAP_METHOD *XMAP_METHOD_file( void );
+#endif /* XMAP_FILE_H */
+
+
+
+
+
diff -ruN freeswan-1.5.orig/pluto/xmap_ldap.c freeswan-1.5/pluto/xmap_ldap.c
--- freeswan-1.5.orig/pluto/xmap_ldap.c	Wed Dec 31 19:00:00 1969
+++ freeswan-1.5/pluto/xmap_ldap.c	Thu Oct  5 07:05:59 2000
@@ -0,0 +1,1265 @@
+#ifdef HAVE_LDAP
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <regex.h>
+
+#include <lber.h>
+#include <ldap.h>
+
+#include "x_sobj.h"
+#include "xmap.h"
+#include "xmap_ldap.h"
+
+#include <openssl/x509v3.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+
+static void XMAP_LDAP_dump(void *this);
+static void XMAP_LDAP_free(void *this);
+static void *XMAP_LDAP_new(const char *ldap);
+static STACK_OF(X509_OBJECT) *
+XMAP_LDAP_lookup( void *this, const int type, const char *index, void *p );
+static STACK_OF(X509_OBJECT) *
+XMAP_LDAP_lookup_cert_by_subject( XMAP_LDAP *xm, X509_NAME *name );
+static STACK_OF(X509_OBJECT) *
+XMAP_LDAP_lookup_crl_by_issuer( XMAP_LDAP *xm, X509_NAME *name );
+static STACK_OF(X509_OBJECT) *
+XMAP_LDAP_lookup_cert_by_uid( XMAP_LDAP *xm, const char *uid );
+static STACK_OF(X509_OBJECT) *
+XMAP_LDAP_lookup_cert_by_dns( XMAP_LDAP *xm, const char *dns );
+static STACK_OF(X509_OBJECT) *
+XMAP_LDAP_lookup_cert_by_ip( XMAP_LDAP *xm, const struct in_addr ip );
+static STACK_OF(X509_OBJECT) *
+XMAP_LDAP_lookup_ca_certs( XMAP_LDAP *xm );
+static char **make_attrs( const char *a );
+static void attrs_free( char **attrs );
+
+char *find_filter( const char *index, const int type, flist *fl );
+char **find_attrs( const char *index, const int type, alist *al );
+
+static XMAP_METHOD xmap_ldap_methods = {
+  "ldap",
+  XMAP_LDAP_lookup,
+  XMAP_LDAP_dump,
+  XMAP_LDAP_free,
+  XMAP_LDAP_new
+};
+
+#define HOST_REGEX "^([[:alnum:]]+)_host_name[[:space:]]*=[[:space:]]*([[:punct:][:alnum:]]+)"
+#define PORT_REGEX "^([[:alnum:]]+)_port[[:space:]]*=[[:space:]]*([[:digit:]]+)"
+#define BASE_REGEX "^([[:alnum:]]+)_base[[:space:]]*=[[:space:]]*([^[:space:]].*)"
+#define TIMEOUT_REGEX "^([[:alnum:]]+)_timeout[[:space:]]*=[[:space:]]*([[:digit:]]+)"
+#define BINDDN_REGEX "^([[:alnum:]]+)_bind_dn[[:space:]]*=[[:space:]]*([^[:space:]].*)"
+#define BINDPW_REGEX "^([[:alnum:]]+)_password[[:space:]]*=[[:space:]]*([^[:space:]].*)"
+#define FILTER_REGEX "^([[:alnum:]]+)_filter(:(([\\*[:alnum:]]+)(:([[:alnum:]]+))?))?[[:space:]]*=[[:space:]]*([^[:space:]].*)"
+#define ATTRS_REGEX "^([[:alnum:]]+)_attributes(:(([\\*[:alnum:]]+)(:([[:alnum:]]+))?))?[[:space:]]*=[[:space:]]*([^[:space:]].*)"
+
+static void
+insert_filter( const char *index, const int type, const char *filter, flist *fl )
+{
+  int i;
+  char *f, *in;
+
+  for(i=0; ((i < MAXFLIST) && (fl[i].index)) ;i++)
+    if ((strcasecmp(index, fl[i].index) == 0) && (fl[i].type == type)) break;
+
+  if (i == MAXFLIST) return; /* No more room */
+  if (fl[i].index) {
+    /* A replacement operation */
+    if ((f = clone_bytes(filter, strlen(filter)+1, "filter")) == NULL) return;
+    pfree(fl[i].filter);
+    fl[i].filter = f;
+  } else {
+    if ((in = clone_bytes(index, strlen(index)+1, "index string")) == NULL)
+      return;
+    if ((f = clone_bytes(filter, strlen(filter)+1, "filter string")) == NULL)
+      { pfree(in); return; }
+    fl[i].index = in;
+    fl[i].type = type;
+    fl[i].filter = f;
+	DBG(DBG_PARSING,
+    DBG_log("Insert filter: %d (%s,%d,%s)", i+1, in, type, f);
+    );
+  }
+}
+
+static void
+insert_attrs( const char *index, const int type, const char *attr, alist *al )
+{
+  int i, j;
+  char **af, *in;
+
+  for(i=0; ((i < MAXFLIST) && (al[i].index)) ;i++) {
+    if ((strcasecmp(index, al[i].index) == 0) && (al[i].type == type)) {
+      break;
+    }
+  }
+
+  if (i == MAXFLIST) return; /* No more room */
+  if (al[i].index) {
+    /* A replacement operation */
+    if ((af = make_attrs(attr)) == NULL) return;
+    attrs_free(al[i].attrs);
+    al[i].attrs = af;
+  } else {
+    if ((in = clone_bytes(index, strlen(index)+1, "index string")) == NULL)
+      return;
+    if ((af = make_attrs(attr)) == NULL) { pfree(in); return; }
+    al[i].index = in;
+    al[i].type = type;
+    al[i].attrs = af;
+	DBG(DBG_PARSING,
+    DBG_log("Insert attribute: %d (%s,%d)", i+1, in, type);
+    );
+    for(j=0; af[j]; j++)
+      DBG(DBG_PARSING,
+      DBG_log("Attribute %d: %s", j+1, af[j]);
+      );
+  }
+}
+
+char *
+find_filter( const char *index, const int type, flist *fl )
+{
+  int i, OKind;
+  unsigned char OK, indOK, typeOK;
+
+  OK = 0x00;
+  for(i=0, OKind=0; ((i < MAXFLIST) && (fl[i].index)); i++) {
+    typeOK = (fl[i].type == X509_LU_FAIL) ? 0x01 :
+      ((fl[i].type == type) ? 0x04 : 0);
+    indOK = (strcasecmp(fl[i].index, "*") == 0) ? 0x02 :
+      ((strcasecmp(fl[i].index, index) == 0) ? 0x08 : 0);
+    if ((typeOK | indOK) > OK) { OKind = i; OK = typeOK | indOK; }
+  }
+
+  return fl[OKind].filter;
+}
+
+char **
+find_attrs( const char *index, const int type, alist *al )
+{
+  int i, OKind;
+  unsigned char OK, indOK, typeOK;
+
+  OK = 0x00;
+  for(i=0, OKind=0; ((i < MAXFLIST) && (al[i].index)); i++) {
+    typeOK = (al[i].type == X509_LU_FAIL) ? 0x01 :
+      ((al[i].type == type) ? 0x04 : 0);
+    indOK = (strcasecmp(al[i].index, "*") == 0) ? 0x02 :
+      ((strcasecmp(al[i].index, index) == 0) ? 0x08 : 0);
+    if ((typeOK | indOK) > OK) { OKind = i; OK = typeOK | indOK; }
+  }
+
+  return al[OKind].attrs;
+}
+
+static void
+extract_re_sub( const char *buf, regmatch_t *rm, char **lv)
+{
+  if (!buf || !lv || !rm) return;
+  if (*lv) return;
+  if ((rm->rm_so == -1) || (rm->rm_eo == -1)) return;
+  if ((*lv = alloc_bytes(rm->rm_eo - rm->rm_so + 1, "subexpression")) == NULL)
+    return;
+  strncpy(*lv, &buf[rm->rm_so], rm->rm_eo - rm->rm_so);
+  (*lv)[rm->rm_eo - rm->rm_so] = '\0';
+}
+
+static char **
+make_attrs( const char *a )
+{
+  char *s = clone_bytes(a, strlen(a)+1, "attribute list");
+  char *at;
+  int i = 0, j;
+  char **ret = NULL;
+  const char *delim = ", ";
+
+  if (!s) return NULL;
+  at = strtok(s, delim);
+  while (at != NULL) {
+    i++;
+    at = strtok(NULL, delim);
+  }
+  ret = alloc_bytes((i+1) * sizeof(char *), "attribute array");
+  if (!ret) { pfree(s); return NULL; }
+  for(j=0; j<=i; j++) ret[j] = NULL;
+  pfree(s);
+
+  if ((s = clone_bytes(a, strlen(a)+1, "attribute list")) == NULL) return NULL;
+  at = strtok(s, delim);
+  i = 0;
+  while (at != NULL) {
+    if ((ret[i++] = clone_bytes(at, strlen(at)+1, "attribute")) == NULL) {
+      for(i=0; ret[i]; i++) pfree(ret[i]);
+      pfree(ret);
+      pfree(s);
+      return NULL;
+    }
+    at = strtok(NULL, delim);
+  }
+  
+  pfree(s);
+  return ret;
+}
+
+static void
+attrs_free( char **attrs )
+{
+  int i=0;
+
+  for(i=0; attrs[i]; i++) pfree(attrs[i]);
+  pfree(attrs);
+}
+
+static jmp_buf env;
+static void
+ldap_timeout(int unused_sig __attribute__((unused)))
+{
+  longjmp(env, 1);
+}
+
+static int
+open_bind( XMAP_LDAP *xm )
+{
+  void (*saved_alarm)(int);
+
+  if ((saved_alarm = signal(SIGALRM, ldap_timeout)) == SIG_ERR) {
+    log("signal: %s", strerror(errno));
+    return 0;
+  }
+
+  alarm(xm->ldap_timeout);
+  if (setjmp(env) == 0) {
+    if ((xm->ld = ldap_open(xm->ldap_host, xm->ldap_port)) == NULL) {
+      DBG(DBG_PARSING,
+      DBG_log("Open to %s:%d failed", xm->ldap_host, xm->ldap_port);
+      );
+      log("ldap_open: %s", strerror(errno));
+      return 0;
+    }
+  }
+  alarm(0);
+
+  if ((ldap_bind_s(xm->ld, xm->ldap_bindDN, xm->ldap_bindPW,
+		   LDAP_AUTH_SIMPLE)) != LDAP_SUCCESS) return 0;
+
+  return 1;
+}
+
+void *
+XMAP_LDAP_new(const char *ldapspec)
+{
+  char *ls = NULL, *s, *ldapvar = NULL, *ldapfile;
+  FILE *fp;
+  XMAP_LDAP *ret = NULL;
+  int i, re_code;
+  char re_err[256];
+  regmatch_t re_match[10];
+
+  regex_t host_re;
+  regex_t port_re;
+  regex_t timeout_re;
+  regex_t base_re;
+  regex_t binddn_re;
+  regex_t bindpw_re;
+  regex_t filter_re;
+  regex_t attrs_re;
+
+  /* Default values */
+  char *ldap_host = clone_bytes("localhost", strlen("localhost")+1,
+				"ldap_host");
+  int ldap_port = LDAP_PORT;
+  int ldap_timeout = 10; /* seconds */
+  char *ldap_bindDN = clone_bytes("", 1, "bindDN");
+  char *ldap_bindPW = clone_bytes("", 1, "bindPW");
+  char *ldap_base = NULL;
+  flist ldap_filter[MAXFLIST];
+  alist ldap_attrs[MAXFLIST];
+
+  memset(ldap_filter, 0, sizeof(ldap_filter));
+  insert_filter("*", X509_LU_FAIL, "(cn=%s)", ldap_filter);
+
+  memset(ldap_attrs, 0, sizeof(ldap_attrs));
+  insert_attrs("*", X509_LU_FAIL, "usercertificate, usercertificate;binary, cacertificate, cacertificate;binary", ldap_attrs);
+
+  if ((re_code = regcomp(&host_re, HOST_REGEX, REG_EXTENDED)) != 0) {
+    regerror(re_code, &host_re, re_err, sizeof(re_err));
+    log("Regex error: %s", re_err);
+    goto end;
+  }
+
+  if ((re_code = regcomp(&port_re, PORT_REGEX, REG_EXTENDED)) != 0) {
+    regerror(re_code, &port_re, re_err, sizeof(re_err));
+    log("Regex error: %s", re_err);
+    goto end;
+  }
+
+  if ((re_code = regcomp(&base_re, BASE_REGEX, REG_EXTENDED)) != 0) {
+    regerror(re_code, &base_re, re_err, sizeof(re_err));
+    log("Regex error: %s", re_err);
+    goto end;
+  }
+
+  if ((re_code = regcomp(&timeout_re, TIMEOUT_REGEX, REG_EXTENDED)) != 0) {
+    regerror(re_code, &timeout_re, re_err, sizeof(re_err));
+    log("Regex error: %s", re_err);
+    goto end;
+  }
+
+  if ((re_code = regcomp(&binddn_re, BINDDN_REGEX, REG_EXTENDED)) != 0) {
+    regerror(re_code, &binddn_re, re_err, sizeof(re_err));
+    log("Regex error: %s", re_err);
+    goto end;
+  }
+
+  if ((re_code = regcomp(&bindpw_re, BINDPW_REGEX, REG_EXTENDED)) != 0) {
+    regerror(re_code, &bindpw_re, re_err, sizeof(re_err));
+    log("Regex error: %s", re_err);
+    goto end;
+  }
+
+  if ((re_code = regcomp(&filter_re, FILTER_REGEX, REG_EXTENDED)) != 0) {
+    regerror(re_code, &filter_re, re_err, sizeof(re_err));
+    log("Regex error: %s", re_err);
+    goto end;
+  }
+
+  if ((re_code = regcomp(&attrs_re, ATTRS_REGEX, REG_EXTENDED)) != 0) {
+    regerror(re_code, &attrs_re, re_err, sizeof(re_err));
+    log("Regex error: %s", re_err);
+    goto end;
+  }
+
+  if ((!ldap_host) || (!ldap_bindDN) || (!ldap_bindPW) ||
+      (!ldap_filter) || (!ldap_attrs)) goto end;
+
+  ls = clone_bytes(ldapspec, strlen(ldapspec)+1, "ldap spec");
+  if (!ls) goto end;
+  s = strchr(ls, ':');
+  ldapfile = ls;
+  if (s) {
+    ldapvar = clone_bytes(&s[1], strlen(&s[1])+1, "ldap name");
+    *s = '\0';
+  } else {
+    ldapvar = NULL;
+  }
+
+  fp = fopen( ldapfile, "r" );
+  if (!fp) {
+    perror("fopen");
+    goto end;
+  }
+
+  while (!feof(fp)) {
+    char buf[BUFSIZ], *ptr;
+
+    if (fgets(buf, sizeof(buf), fp)) {
+      int l;
+
+      for(ptr = buf; ((*ptr) && (isspace(*ptr))); ptr++);
+      if (! *ptr) continue; /* Blank Line */
+      if (*ptr == '#') continue; /* Comment */
+      l = strlen(buf)-1;
+      while ((l > 0) && (isspace(buf[l]))) { buf[l] = '\0'; l--; }
+
+      /* Check for host name spec */
+      if ((re_code = regexec(&host_re, buf, 10, re_match, 0)) == 0) {
+	char *lv = NULL;
+
+	extract_re_sub(buf, &re_match[1], &lv);
+	if (!ldapvar) extract_re_sub(buf, &re_match[1], &ldapvar);
+	if (strcmp(ldapvar, lv) == 0) {
+	  if (ldap_host) { pfree(ldap_host); ldap_host = NULL; }
+	  extract_re_sub(buf, &re_match[2], &ldap_host);
+	}
+	pfree(lv);
+      }
+
+      /* Check for port spec */
+      if ((re_code = regexec(&port_re, buf, 10, re_match, 0)) == 0) {
+	char *lv = NULL;
+
+	extract_re_sub(buf, &re_match[1], &lv);
+	if (!ldapvar) extract_re_sub(buf, &re_match[1], &ldapvar);
+	if (strcmp(ldapvar, lv) == 0) {
+	  char *ps = NULL;
+
+	  extract_re_sub(buf, &re_match[2], &ps);
+	  ldap_port = atoi(ps);
+	  pfree(ps);
+	}
+	pfree(lv);
+      }
+
+      /* Check for base spec */
+      if ((re_code = regexec(&base_re, buf, 10, re_match, 0)) == 0) {
+	char *lv = NULL;
+
+	extract_re_sub(buf, &re_match[1], &lv);
+	if (!ldapvar) extract_re_sub(buf, &re_match[1], &ldapvar);
+	if (strcmp(ldapvar, lv) == 0) {
+	  if (ldap_base) { free(ldap_base); ldap_base = NULL; }
+	  extract_re_sub(buf, &re_match[2], &ldap_base);
+	}
+	pfree(lv);
+      }
+
+      /* Check for timeout spec */
+      if ((re_code = regexec(&timeout_re, buf, 10, re_match, 0)) == 0) {
+	char *lv = NULL;
+
+	extract_re_sub(buf, &re_match[1], &lv);
+	if (!ldapvar) extract_re_sub(buf, &re_match[1], &ldapvar);
+	if (strcmp(ldapvar, lv) == 0) {
+	  char *to = NULL;
+
+	  extract_re_sub(buf, &re_match[2], &to);
+	  ldap_timeout = atoi(to);
+	  free(to);
+	}
+	pfree(lv);
+      }
+
+      /* Check for bind DN spec */
+      if ((re_code = regexec(&binddn_re, buf, 10, re_match, 0)) == 0) {
+	char *lv = NULL;
+
+	extract_re_sub(buf, &re_match[1], &lv);
+	if (!ldapvar) extract_re_sub(buf, &re_match[1], &ldapvar);
+	if (strcmp(ldapvar, lv) == 0) {
+	  if (ldap_bindDN) { free(ldap_bindDN); ldap_bindDN = NULL; }
+	  extract_re_sub(buf, &re_match[2], &ldap_bindDN);
+	}
+	pfree(lv);
+      }
+
+      /* Check for bind PW spec */
+      if ((re_code = regexec(&bindpw_re, buf, 10, re_match, 0)) == 0) {
+	char *lv = NULL;
+
+	extract_re_sub(buf, &re_match[1], &lv);
+	if (!ldapvar) extract_re_sub(buf, &re_match[1], &ldapvar);
+	if (strcmp(ldapvar, lv) == 0) {
+	  if (ldap_bindPW) { free(ldap_bindPW); ldap_bindPW = NULL; }
+	  extract_re_sub(buf, &re_match[2], &ldap_bindPW);
+	}
+	pfree(lv);
+      }
+
+      /* Check for filter spec */
+      if ((re_code = regexec(&filter_re, buf, 10, re_match, 0)) == 0) {
+	char *lv = NULL;
+
+	extract_re_sub(buf, &re_match[1], &lv);
+	if (!ldapvar) extract_re_sub(buf, &re_match[1], &ldapvar);
+	if (strcmp(ldapvar, lv) == 0) {
+	  char *filt = NULL, *sf = NULL, *ssf = NULL;
+	  int ssftype = X509_LU_FAIL; /* Use this as a catchall */
+
+	  if (re_match[2].rm_so != -1) {
+	    extract_re_sub(buf, &re_match[4], &sf);
+	    if (re_match[5].rm_so != -1) {
+	      extract_re_sub(buf, &re_match[6], &ssf);
+	      if (strcasecmp(ssf, "cert") == 0)
+		ssftype = X509_LU_X509;
+	      else if (strcasecmp(ssf, "crl") == 0)
+		ssftype = X509_LU_CRL;
+	      else
+		ssftype = X509_LU_RETRY; /* Use as an "invalid" value */
+	      pfree(ssf);
+	    }
+	  }
+	  extract_re_sub(buf, &re_match[7], &filt);
+	  if (ssftype != X509_LU_RETRY)
+	    insert_filter((sf == NULL) ? "*" : sf, ssftype, filt, ldap_filter);
+	  else
+	    if (filt) pfree(filt);
+	  if (sf) pfree(sf);
+	}
+	pfree(lv);
+      }
+
+      /* Check for attributes spec */
+      if ((re_code = regexec(&attrs_re, buf, 10, re_match, 0)) == 0) {
+	char *lv = NULL;
+
+	extract_re_sub(buf, &re_match[1], &lv);
+	if (!ldapvar) extract_re_sub(buf, &re_match[1], &ldapvar);
+	if (strcmp(ldapvar, lv) == 0) {
+	  char *attr = NULL;
+	  char *sf = NULL, *ssf = NULL;
+	  int ssftype = X509_LU_FAIL; /* Use this as a catchall */
+
+	  if (re_match[2].rm_so != -1) {
+	    extract_re_sub(buf, &re_match[4], &sf);
+	    if (re_match[5].rm_so != -1) {
+	      extract_re_sub(buf, &re_match[6], &ssf);
+	      if (strcasecmp(ssf, "cert") == 0)
+		ssftype = X509_LU_X509;
+	      else if (strcasecmp(ssf, "crl") == 0)
+		ssftype = X509_LU_CRL;
+	      else if (strcasecmp(ssf, "*") == 0)
+		ssftype = X509_LU_FAIL;
+	      else
+		ssftype = X509_LU_RETRY; /* Use as an "invalid" value */
+	      pfree(ssf);
+	    }
+	  }
+	  extract_re_sub(buf, &re_match[7], &attr);
+	  if (ssftype != X509_LU_RETRY)
+	    insert_attrs((sf == NULL) ? "*" : sf, ssftype, attr, ldap_attrs);
+	  else
+	    if (attr) pfree(attr);
+	  if (sf) pfree(sf);
+	}
+	pfree(lv);
+      }
+
+    }
+  }
+
+  if (!ldap_base) goto end; /* No search base - and we can't default to one */
+
+  if ((ret = alloc_thing(XMAP_LDAP, "xmap_ldap")) == NULL) goto end;
+
+  ret->ldapsource = ldapvar;
+  ret->ldap_host = ldap_host;
+  ret->ldap_port = ldap_port;
+  ret->ldap_base = ldap_base;
+  ret->ldap_timeout = ldap_timeout;
+  ret->ldap_bindDN = ldap_bindDN;
+  ret->ldap_bindPW = ldap_bindPW;
+  memcpy(ret->ldap_filter, ldap_filter, MAXFLIST * sizeof(flist));
+  memcpy(ret->ldap_attrs, ldap_attrs, MAXFLIST * sizeof(alist));
+  
+  fclose(fp); fp = NULL;
+
+  if (!open_bind(ret)) goto end;
+
+  if (ls) pfree(ls);
+  return (void *)ret;
+
+ end:
+  if (ldap_host) pfree(ldap_host);
+  if (ldap_base) pfree(ldap_base);
+  if (ldap_bindDN) pfree(ldap_bindDN);
+  if (ldap_bindPW) pfree(ldap_bindPW);
+  for(i=0; ldap_filter[i].index; i++)
+    { pfree(ldap_filter[i].index); pfree(ldap_filter[i].filter); }
+  for(i=0; ldap_attrs[i].index; i++)
+    { pfree(ldap_attrs[i].index); attrs_free(ldap_attrs[i].attrs); }
+  if (ldapvar) pfree(ldapvar);
+  if (ls) pfree(ls);
+  if (fp) fclose(fp);
+  return NULL;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_LDAP_lookup( void *this, const int type, const char *index, void *p )
+{
+  XMAP_LDAP *xm = (XMAP_LDAP *)this;
+
+  if (type == X509_LU_X509) {
+    if (strcasecmp(index, "subject") == 0)
+      return XMAP_LDAP_lookup_cert_by_subject(xm, (X509_NAME *)p);
+    else if (strcasecmp(index, "uid") == 0)
+      return XMAP_LDAP_lookup_cert_by_uid(xm, (char *)p);
+    else if (strcasecmp(index, "dns") == 0)
+      return XMAP_LDAP_lookup_cert_by_dns(xm, (char *)p);
+    else if (strcasecmp(index, "ip") == 0)
+      return XMAP_LDAP_lookup_cert_by_ip(xm, *((struct in_addr *)p));
+    else if (strcasecmp(index, "ca") == 0)
+      return XMAP_LDAP_lookup_ca_certs( xm );
+    else
+      return NULL;
+  } else if (type == X509_LU_CRL) {
+    if (strcasecmp(index, "issuer") == 0)
+      return XMAP_LDAP_lookup_crl_by_issuer(xm, (X509_NAME *)p);
+    else
+      return NULL;
+  } else {
+    log("Unknown search type");
+    return NULL;
+  }
+}
+
+static int
+ASN1_UTCTIME_cmp(ASN1_UTCTIME *a, ASN1_UTCTIME *b)
+{
+  char buff1[14],buff2[14],*p;
+  int i,j;
+ 
+  /* Degenerate cases */
+  if (!a && !b) return 0;
+  if (a && !b) return 1;
+  if (!a && b) return -1;
+ 
+  memset(buff1, 0, sizeof(buff1));
+  memset(buff2, 0, sizeof(buff2));
+ 
+  p=buff1;
+  i=a->length;
+  if ((i < 11) || (i > 17)) return(0);
+  memcpy(p,a->data,12);
+ 
+  p=buff2;
+  j=b->length;
+  if ((j < 11) || (j > 17)) return(0);
+  memcpy(p,b->data,12);
+ 
+  /* Correct for Y2K */
+  i=(buff1[0]-'0')*10+(buff1[1]-'0');
+  if (i < 50) i+=100; /* cf. RFC 2459 */
+  j=(buff2[0]-'0')*10+(buff2[1]-'0');
+  if (j < 50) j+=100;
+ 
+  if (i < j) return (-1);
+  if (i > j) return (1);
+ 
+  i=strcmp(buff1,buff2);
+ 
+  if (i == 0)
+    return 0;
+  else if (i < 0)
+    return(-1);
+  else
+    return(1);
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_LDAP_lookup_cert_by_subject( XMAP_LDAP *xm, X509_NAME *name )
+{
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+  STACK_OF(X509_NAME_ENTRY) *ns = name->entries;
+  char *str, *s1, *ff, **af;
+  int i, j, tlen, rc;
+  LDAPMessage *res = NULL, *ent = NULL;
+  struct timeval tv;
+  struct berval **bv;
+
+  if (!sk) return NULL;
+  if (!xm->ld)
+    if (!open_bind(xm)) return NULL;
+
+  /* First find the 'common name' attribute from the subject */
+  for(i=0; i<sk_X509_NAME_ENTRY_num(ns); i++) {
+    X509_NAME_ENTRY *ne = sk_X509_NAME_ENTRY_value(ns, i);
+    int nid = OBJ_obj2nid(ne->object);
+
+    if (nid == NID_commonName) {
+      if (!(str = alloc_bytes(ASN1_STRING_length(ne->value)+1, "common name")))
+	return sk;
+      memset(str, 0, ASN1_STRING_length(ne->value)+1);
+      memcpy(str, ASN1_STRING_data(ne->value),
+             ASN1_STRING_length(ne->value));
+      break; 
+    }
+  }
+  ff = find_filter("subject", X509_LU_X509, xm->ldap_filter);
+  af = find_attrs("subject", X509_LU_X509, xm->ldap_attrs);
+  tlen = strlen(ff) + strlen(str);
+  if ((s1 = alloc_bytes(tlen, "filter pattern")) != NULL) {
+    snprintf(s1, tlen, ff, str);
+    tv.tv_sec = xm->ldap_timeout; tv.tv_usec = 0;
+    rc = ldap_search_st(xm->ld, xm->ldap_base, LDAP_SCOPE_SUBTREE,
+			s1, af, 0,
+			&tv, &res);
+    if (rc == LDAP_SUCCESS) {
+      for(ent = ldap_first_entry(xm->ld, res); ent ;
+	  ent = ldap_next_entry(xm->ld, ent)) {
+	for(i = 0; af[i]; i++) {
+	  bv = ldap_get_values_len(xm->ld, ent, af[i]);
+	  if (bv) {
+	    for(j=0; bv[j]; j++) {
+	      unsigned char *p;
+	      X509 *x;
+	      
+	      p = bv[j]->bv_val;
+	      x = d2i_X509(NULL, &p, bv[j]->bv_len);
+	      if (x) {
+		if (X509_NAME_cmp(X509_get_subject_name(x), name) == 0) {
+		  X509_OBJECT *xo = X509_OBJECT_new(X509_LU_X509, x);
+		  if (xo) {
+		    int i, found = 0;
+
+		    for(i=0; (!found) && (i<sk_X509_OBJECT_num(sk)); i++) {
+		      X509_OBJECT *o = sk_X509_OBJECT_value(sk, i);
+
+		      if (X509_issuer_and_serial_cmp(x, o->data.x509) == 0)
+			found = 1;
+		    }
+		    if (!found)
+		      sk_X509_OBJECT_push(sk, xo);
+		    else {
+		      X509_free(x); /* duplicate of existing item */
+		    }
+		  } else {
+		    X509_free(x); /* cannot allocate X509_OBJECT */
+		  }
+		} else {
+		  X509_free(x); /* subject name doesn't match */
+		}
+	      }
+	    }
+	    ldap_value_free_len(bv);
+	  }
+	}
+      }
+    } else {
+      log("ldap_search_st error: %s", ldap_err2string(rc));
+      ldap_unbind(xm->ld);
+      xm->ld = NULL;
+    }
+    pfree(s1);
+  }
+  pfree(str);
+  return sk;
+}
+
+static int
+isCA( X509 *x )
+{
+  X509_EXTENSION *ext;
+  BASIC_CONSTRAINTS *p = NULL;
+  int loc;
+  
+  loc = X509_get_ext_by_NID(x, NID_basic_constraints, -1);
+  if (loc >= 0) {
+    ext = X509_get_ext(x, loc);
+    if (ext) {
+      p = X509V3_EXT_d2i(ext);
+      if (! p->ca) {
+	BASIC_CONSTRAINTS_free(p);
+	return 0;
+      } else {
+	BASIC_CONSTRAINTS_free(p);
+	return 1; /* This is a CA certificate */
+      }
+    } else
+      return 0;
+  } else
+    return 0;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_LDAP_lookup_ca_certs( XMAP_LDAP *xm )
+{
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+  char *ff, **af;
+  int i, j, rc;
+  LDAPMessage *res = NULL, *ent = NULL;
+  struct timeval tv;
+  struct berval **bv;
+
+  if (!sk) return NULL;
+  if (!xm->ld)
+    if (!open_bind(xm)) return NULL;
+
+  ff = find_filter("ca", X509_LU_X509, xm->ldap_filter);
+  af = find_attrs("ca", X509_LU_X509, xm->ldap_attrs);
+  tv.tv_sec = xm->ldap_timeout; tv.tv_usec = 0;
+  rc = ldap_search_st(xm->ld, xm->ldap_base, LDAP_SCOPE_SUBTREE,
+		      ff, af, 0, &tv, &res);
+  if (rc == LDAP_SUCCESS) {
+    for(ent = ldap_first_entry(xm->ld, res); ent ;
+	ent = ldap_next_entry(xm->ld, ent)) {
+      for(i = 0; af[i]; i++) {
+	bv = ldap_get_values_len(xm->ld, ent, af[i]);
+	if (bv) {
+	  for(j=0; bv[j]; j++) {
+	    unsigned char *p;
+	    X509 *x;
+	    
+	    p = bv[j]->bv_val;
+	    x = d2i_X509(NULL, &p, bv[j]->bv_len);
+	    if ((x) && (isCA(x))) {
+	      X509_OBJECT *xo = X509_OBJECT_new(X509_LU_X509, x);
+	      if (xo) {
+		int i, found = 0;
+		
+		for(i=0; (!found) && (i<sk_X509_OBJECT_num(sk)); i++) {
+		  X509_OBJECT *o = sk_X509_OBJECT_value(sk, i);
+		  
+		  if (X509_issuer_and_serial_cmp(x, o->data.x509) == 0)
+		    found = 1;
+		}
+		if (!found)
+		  sk_X509_OBJECT_push(sk, xo);
+		else
+		  X509_free(x); /* duplicate of existing item */
+	      } else
+		X509_free(x); /* cannot allocate X509_OBJECT */
+	    } else
+	      X509_free(x); /* subject name doesn't match */
+	  }
+	  ldap_value_free_len(bv);
+	}
+      }
+    }
+  } else {
+    log("ldap_search_st error: %s", ldap_err2string(rc));
+    ldap_unbind(xm->ld);
+    xm->ld = NULL;
+  }
+  return sk;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_LDAP_lookup_crl_by_issuer( XMAP_LDAP *xm, X509_NAME *name )
+{
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+  STACK_OF(X509_NAME_ENTRY) *ns = name->entries;
+  char *str, *s1, *ff, **af;
+  int i, j, tlen, rc;
+  LDAPMessage *res = NULL, *ent = NULL;
+  struct timeval tv;
+  struct berval **bv;
+
+  if (!sk) return NULL;
+  if (!xm->ld)
+    if (!open_bind(xm)) return NULL;
+
+  /* First find the 'common name' attribute from the subject */
+  for(i=0; i<sk_X509_NAME_ENTRY_num(ns); i++) {
+    X509_NAME_ENTRY *ne = sk_X509_NAME_ENTRY_value(ns, i);
+    int nid = OBJ_obj2nid(ne->object);
+
+    if (nid == NID_commonName) {
+      if (!(str = alloc_bytes(ASN1_STRING_length(ne->value)+1,
+			      "common name")))
+	return sk;
+      memset(str, 0, ASN1_STRING_length(ne->value)+1);
+      memcpy(str, ASN1_STRING_data(ne->value),
+             ASN1_STRING_length(ne->value));
+      break; 
+    }
+  }
+  ff = find_filter("issuer", X509_LU_CRL, xm->ldap_filter);
+  af = find_attrs("issuer", X509_LU_CRL, xm->ldap_attrs);
+  tlen = strlen(ff) + strlen(str);
+  if ((s1 = alloc_bytes(tlen, "filter pattern")) != NULL) {
+    snprintf(s1, tlen, ff, str);
+    tv.tv_sec = xm->ldap_timeout; tv.tv_usec = 0;
+    DBG(DBG_PARSING,
+    DBG_log("LDAP search: \"%s\"", s1);
+    );
+    for(i=0; af[i]; i++) {
+		DBG(DBG_PARSING,
+		DBG_log("Attr %d: %s", i+1, af[i]);
+		);
+    }
+    rc = ldap_search_st(xm->ld, xm->ldap_base, LDAP_SCOPE_SUBTREE,
+			s1, af, 0,
+			&tv, &res);
+    if (rc == LDAP_SUCCESS) {
+      for(ent = ldap_first_entry(xm->ld, res); ent ;
+	  ent = ldap_next_entry(xm->ld, ent)) {
+	for(i = 0; af[i]; i++) {
+	  bv = ldap_get_values_len(xm->ld, ent, af[i]);
+	  if (bv) {
+	    for(j=0; bv[j]; j++) {
+	      unsigned char *p;
+	      X509_CRL *x;
+	      
+	      p = bv[j]->bv_val;
+	      x = d2i_X509_CRL(NULL, &p, bv[j]->bv_len);
+	      if (x) {
+		if (X509_NAME_cmp(X509_CRL_get_issuer(x), name) == 0) {
+		  X509_OBJECT *xo = X509_OBJECT_new(X509_LU_CRL, x);
+
+		  if (xo) {
+		    int i, found = 0;
+
+		    for(i=0; (!found) && (i<sk_X509_OBJECT_num(sk)); i++) {
+		      X509_OBJECT *o = sk_X509_OBJECT_value(sk, i);
+
+		      if ((X509_CRL_cmp(o->data.crl, x) == 0) &&
+			  (ASN1_UTCTIME_cmp(X509_CRL_get_lastUpdate(o->data.crl),
+					    X509_CRL_get_lastUpdate(x)) == 0) &&
+			  (ASN1_UTCTIME_cmp(X509_CRL_get_nextUpdate(o->data.crl),
+					    X509_CRL_get_nextUpdate(x)) == 0))
+			  found = 1;
+		    }
+		    if (!found)
+		      sk_X509_OBJECT_push(sk, xo);
+		    else
+		      X509_CRL_free(x); /* duplicate of existing item */
+		  } else
+		    X509_CRL_free(x); /* cannot allocate X509_OBJECT */
+		} else
+		  X509_CRL_free(x); /* subject name doesn't match */
+	      }
+	    }
+	    ldap_value_free_len(bv);
+	  }
+	}
+      }
+    } else {
+      log("ldap_search_st error: %s", ldap_err2string(rc));
+      ldap_unbind(xm->ld);
+      xm->ld = NULL;
+    }
+    pfree(s1);
+  }
+  pfree(str);
+  return sk;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_LDAP_lookup_cert_by_uid( XMAP_LDAP *xm, const char *uid )
+{
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+  char *s1, *ff, **af;
+  int i, j, tlen, rc;
+  LDAPMessage *res = NULL, *ent = NULL;
+  struct timeval tv;
+  struct berval **bv;
+
+  if (!sk) return NULL;
+  if (!xm->ld)
+    if (!open_bind(xm)) return NULL;
+
+  ff = find_filter("uid", X509_LU_X509, xm->ldap_filter);
+  af = find_attrs("uid", X509_LU_X509, xm->ldap_attrs);
+  tlen = strlen(ff) + strlen(uid);
+  if ((s1 = alloc_bytes(tlen, "filter pattern")) != NULL) {
+    snprintf(s1, tlen, ff, uid);
+    tv.tv_sec = xm->ldap_timeout; tv.tv_usec = 0;
+    rc = ldap_search_st(xm->ld, xm->ldap_base, LDAP_SCOPE_SUBTREE,
+			s1, af, 0,
+			&tv, &res);
+    if (rc == LDAP_SUCCESS) {
+      for(ent = ldap_first_entry(xm->ld, res); ent ;
+	  ent = ldap_next_entry(xm->ld, ent)) {
+	for(i = 0; af[i]; i++) {
+	  bv = ldap_get_values_len(xm->ld, ent, af[i]);
+	  if (bv) {
+	    for(j=0; bv[j]; j++) {
+	      unsigned char *p;
+	      X509 *x;
+	      
+	      p = bv[j]->bv_val;
+	      x = d2i_X509(NULL, &p, bv[j]->bv_len);
+	      if (x) {
+		X509_OBJECT *xo = X509_OBJECT_new(X509_LU_X509, x);
+		if (xo) {
+		  int i, found = 0;
+		  
+		  for(i=0; (!found) && (i<sk_X509_OBJECT_num(sk)); i++) {
+		    X509_OBJECT *o = sk_X509_OBJECT_value(sk, i);
+		    
+		    if (X509_issuer_and_serial_cmp(x, o->data.x509) == 0)
+		      found = 1;
+		  }
+		  if (!found)
+		    sk_X509_OBJECT_push(sk, xo);
+		  else
+		    X509_free(x); /* duplicate of existing item */
+		} else
+		  X509_free(x); /* cannot allocate X509_OBJECT */
+	      }
+	    }
+	    ldap_value_free_len(bv);
+	  }
+	}
+      }
+    } else {
+      log("ldap_search_st error: %s", ldap_err2string(rc));
+      ldap_unbind(xm->ld);
+      xm->ld = NULL;
+    }
+    pfree(s1);
+  }
+  return sk;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_LDAP_lookup_cert_by_dns( XMAP_LDAP *xm, const char *dns )
+{
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+  char *s1, *ff, **af;
+  int i, j, tlen, rc;
+  LDAPMessage *res = NULL, *ent = NULL;
+  struct timeval tv;
+  struct berval **bv;
+
+  if (!sk) return NULL;
+  if (!xm->ld)
+    if (!open_bind(xm)) return NULL;
+
+  ff = find_filter("dns", X509_LU_X509, xm->ldap_filter);
+  af = find_attrs("dns", X509_LU_X509, xm->ldap_attrs);
+  tlen = strlen(ff) + strlen(dns);
+  if ((s1 = alloc_bytes(tlen, "filter patten")) != NULL) {
+    snprintf(s1, tlen, ff, dns);
+    tv.tv_sec = xm->ldap_timeout; tv.tv_usec = 0;
+    rc = ldap_search_st(xm->ld, xm->ldap_base, LDAP_SCOPE_SUBTREE,
+			s1, af, 0,
+			&tv, &res);
+    if (rc == LDAP_SUCCESS) {
+      for(ent = ldap_first_entry(xm->ld, res); ent ;
+	  ent = ldap_next_entry(xm->ld, ent)) {
+	for(i = 0; af[i]; i++) {
+	  bv = ldap_get_values_len(xm->ld, ent, af[i]);
+	  if (bv) {
+	    for(j=0; bv[j]; j++) {
+	      unsigned char *p;
+	      X509 *x;
+	      
+	      p = bv[j]->bv_val;
+	      x = d2i_X509(NULL, &p, bv[j]->bv_len);
+	      if (x) {
+		if (X509_subjAltName_check_dns(x, dns)) {
+		  X509_OBJECT *xo = X509_OBJECT_new(X509_LU_X509, x);
+		  if (xo) {
+		    int i, found = 0;
+		    
+		    for(i=0; (!found) && (i<sk_X509_OBJECT_num(sk)); i++) {
+		      X509_OBJECT *o = sk_X509_OBJECT_value(sk, i);
+		      
+		      if (X509_issuer_and_serial_cmp(x, o->data.x509) == 0)
+			found = 1;
+		    }
+		    if (!found)
+		      sk_X509_OBJECT_push(sk, xo);
+		    else
+		      X509_free(x); /* duplicate of existing item */
+		  } else
+		    X509_free(x); /* cannot allocate X509_OBJECT */
+		} else
+		  X509_free(x); /* subjAltName mismatch */
+	      }
+	    }
+	    ldap_value_free_len(bv);
+	  }
+	}
+      }
+    } else {
+      log("ldap_search_st error: %s", ldap_err2string(rc));
+      ldap_unbind(xm->ld);
+      xm->ld = NULL;
+    }
+    pfree(s1);
+  }
+  return sk;
+}
+
+static STACK_OF(X509_OBJECT) *
+XMAP_LDAP_lookup_cert_by_ip( XMAP_LDAP *xm, const struct in_addr ip )
+{
+  STACK_OF(X509_OBJECT) *sk = sk_X509_OBJECT_new_null();
+  char *s1, *ff, **af, *ipt;
+  int i, j, tlen, rc;
+  LDAPMessage *res = NULL, *ent = NULL;
+  struct timeval tv;
+  struct berval **bv;
+
+  if (!sk) return NULL;
+  if (!xm->ld)
+    if (!open_bind(xm)) return NULL;
+
+  if ((ipt = inet_ntoa(ip)) == NULL) return NULL;
+  ff = find_filter("ip", X509_LU_X509, xm->ldap_filter);
+  af = find_attrs("ip", X509_LU_X509, xm->ldap_attrs);
+  
+  tlen = strlen(ff) + strlen(ipt);
+  if ((s1 = alloc_bytes(tlen, "filter pattern")) != NULL) {
+    snprintf(s1, tlen, ff, ipt);
+    tv.tv_sec = xm->ldap_timeout; tv.tv_usec = 0;
+
+	DBG(DBG_PARSING, 
+	DBG_log("xm->ldap_base: %s -- s1: %s -- *af: %s", xm->ldap_base, s1, *af);
+	);
+
+    rc = ldap_search_st(xm->ld, xm->ldap_base, LDAP_SCOPE_SUBTREE,
+			s1, af, 0,
+			&tv, &res);
+    if (rc == LDAP_SUCCESS) {
+      for(ent = ldap_first_entry(xm->ld, res); ent ;
+	  ent = ldap_next_entry(xm->ld, ent)) {
+        for(i = 0; af[i]; i++) {
+
+		DBG(DBG_PARSING,
+		DBG_log("af[%d]: [%s]", i, af[i]);
+		);
+
+	      bv = ldap_get_values_len(xm->ld, ent, af[i]);
+	  if (bv) {
+	    for(j=0; bv[j]; j++) {
+	      signed char *p;
+	      X509 *x;
+	      
+          DBG(DBG_PARSING,
+          DBG_log("** We got LDAP. Trying to process. j=%d.", j);
+          );
+	
+	      p = bv[j]->bv_val;
+
+          DBG(DBG_PARSING | DBG_RAW,
+          DBG_log("** length of X509 cert: %d", bv[j]->bv_len);
+          );
+          DBG(DBG_RAW,
+          DBG_dump("** p: ", bv[j]->bv_val, bv[j]->bv_len);
+          );
+
+	      x = d2i_X509(NULL, &p, bv[j]->bv_len);
+	      if (x) {
+            if (X509_subjAltName_check_ip(x, ip)) {
+              X509_OBJECT *xo = X509_OBJECT_new(X509_LU_X509, x);
+              if (xo) {
+                int i, found = 0;
+		    
+                for(i=0; (!found) && (i<sk_X509_OBJECT_num(sk)); i++) {
+                  X509_OBJECT *o = sk_X509_OBJECT_value(sk, i);
+		      
+                  if (X509_issuer_and_serial_cmp(x, o->data.x509) == 0)
+                    found = 1;
+                } /* end for */
+                if (!found)
+                  sk_X509_OBJECT_push(sk, xo);
+                else
+                  X509_free(x); /* duplicate of existing item */
+              }  /* end if (xo) */
+              else
+                X509_free(x); /* cannot allocate X509_OBJECT */
+            } /* end if (X509_subjAltName_check_ip(x, ip)) */
+            else
+              X509_free(x); /* SubjectAltName mismatch */
+          } /* end if (x) */
+          else
+          {
+          }
+        }
+        ldap_value_free_len(bv);
+      }
+    }
+  }
+    } else {
+      DBG(DBG_PARSING,
+      DBG_log("ldap_search_st error: %s", ldap_err2string(rc));
+      );
+      ldap_unbind(xm->ld);
+      xm->ld = NULL;
+    }
+    pfree(s1);
+  }
+  return sk;
+}
+
+static void
+sanitize(const char *buf, char *buf2, int buf2len)
+{
+  int l = strlen(buf), i, nl, p;
+  char *b;
+
+  for(i=0, nl=l; i<l; i++) if (buf[i] == '%') nl++;
+  b = alloc_bytes(nl+1, "temporary string");
+  memset(b, 0, nl+1);
+  for(i=0, p=0; i < nl; i++) {
+    if (buf[i] == '%') {
+      b[p] = '%';
+      b[p+1] = '%';
+      p++;
+    } else {
+      b[p] = buf[i];
+    }
+    p++;
+  }
+  strncpy(buf2, b, buf2len-1);
+  pfree(b);
+}
+
+static void
+XMAP_LDAP_dump(void *this)
+{
+  char buf[256];
+  XMAP_LDAP *xm = (XMAP_LDAP *)this;
+  int i, j;
+
+  DBG(DBG_PARSING,
+  DBG_log("XMAP_LDAP: %s", xm->ldapsource);
+  DBG_log("Host = %s:%d (Timeout = %d seconds)",
+	  xm->ldap_host, xm->ldap_port, xm->ldap_timeout);
+  DBG_log("Search base = %s", xm->ldap_base);
+  DBG_log("Bind = (\"%s\", \"%s\")", xm->ldap_bindDN, xm->ldap_bindPW);
+  );
+  for(i=0; ((i < MAXFLIST) && (xm->ldap_filter[i].index)); i++) {
+    snprintf(buf, sizeof(buf)-1, "Filter[%d] (%s,",
+	     i+1, xm->ldap_filter[i].index);
+    switch(xm->ldap_filter[i].type) {
+      case X509_LU_X509: strncat(buf, "Cert", sizeof(buf)-1); break;
+      case X509_LU_CRL: strncat(buf, "CRL", sizeof(buf)-1); break;
+      default: strncat(buf, "*", sizeof(buf)-1); break;
+    }
+    strncat(buf, ") ", sizeof(buf)-1);
+    strncat(buf, xm->ldap_filter[i].filter, sizeof(buf)-1);
+    sanitize(buf, buf, sizeof(buf)-1);
+    DBG(DBG_PARSING,
+    DBG_log(buf);
+    );
+  }
+  for(i=0; ((i < MAXFLIST) && (xm->ldap_attrs[i].index)); i++) {
+    snprintf(buf, sizeof(buf), "Attributes[%d] (%s,",
+	     i+1, xm->ldap_attrs[i].index);
+    switch(xm->ldap_attrs[i].type) {
+      case X509_LU_X509: strncat(buf, "Cert", sizeof(buf)-1); break;
+      case X509_LU_CRL: strncat(buf, "CRL", sizeof(buf)-1); break;
+      default: strncat(buf, "*", sizeof(buf)-1); break;
+    }
+    strncat(buf, ") ", sizeof(buf)-1);
+    for(j=0; xm->ldap_attrs[i].attrs[j]; j++) {
+      strncat(buf, ",", sizeof(buf)-1);
+      strncat(buf, xm->ldap_attrs[i].attrs[j], sizeof(buf)-1);
+    }
+    sanitize(buf, buf, sizeof(buf)-1);
+    DBG(DBG_PARSING,
+    DBG_log(buf);
+    );
+  }
+}
+
+static void
+XMAP_LDAP_free(void *this)
+{
+  XMAP_LDAP *xm = (XMAP_LDAP *)this;
+  int i;
+
+  if (!xm) return;
+  if (xm->ld) ldap_unbind(xm->ld);
+  if (xm->ldapsource) pfree(xm->ldapsource);
+  if (xm->ldap_host) pfree(xm->ldap_host);
+  if (xm->ldap_base) pfree(xm->ldap_base);
+  if (xm->ldap_bindDN) pfree(xm->ldap_bindDN);
+  if (xm->ldap_bindPW) pfree(xm->ldap_bindPW);
+
+  for(i=0; ((i < MAXFLIST) && (xm->ldap_filter[i].index)); i++) {
+    pfree(xm->ldap_filter[i].index);
+    pfree(xm->ldap_filter[i].filter);
+  }
+  
+  for(i=0; ((i < MAXFLIST) && (xm->ldap_attrs[i].index)); i++) {
+    pfree(xm->ldap_attrs[i].index);
+    attrs_free(xm->ldap_attrs[i].attrs);
+  }
+
+  pfree(xm);
+}
+
+XMAP_METHOD *
+XMAP_METHOD_ldap( void )
+{
+  return (&xmap_ldap_methods);
+}
+
+#endif /* HAVE_LDAP */
diff -ruN freeswan-1.5.orig/pluto/xmap_ldap.h freeswan-1.5/pluto/xmap_ldap.h
--- freeswan-1.5.orig/pluto/xmap_ldap.h	Wed Dec 31 19:00:00 1969
+++ freeswan-1.5/pluto/xmap_ldap.h	Thu Oct  5 07:05:59 2000
@@ -0,0 +1,49 @@
+#ifndef XMAP_LDAP_H
+#define XMAP_LDAP_H
+
+#ifdef HAVE_LDAP
+
+#include <openssl/safestack.h>
+#include <openssl/x509.h>
+
+#include <lber.h>
+#include <ldap.h>
+
+#include "x_sobj.h"
+#include "xmap.h"
+
+typedef struct _flist_st {
+  char *index;
+  int type;
+  char *filter;
+} flist;
+
+#define MAXFLIST 10
+
+typedef struct _alist_st {
+  char *index;
+  int type;
+  char **attrs;
+} alist;
+
+typedef struct xmap_ldap_st {
+  char *ldapsource;
+  char *ldap_host;
+  int ldap_port;
+  char *ldap_base;
+  int ldap_timeout;
+  char *ldap_bindDN;
+  char *ldap_bindPW;
+  flist ldap_filter[MAXFLIST];
+  alist ldap_attrs[MAXFLIST];
+
+  LDAP *ld;
+
+  XMAP_METHOD *meth;
+} XMAP_LDAP;
+
+XMAP_METHOD *XMAP_METHOD_ldap( void );
+
+#endif /* HAVE_LDAP */
+
+#endif /* XMAP_LDAP_H */
diff -ruN freeswan-1.5.orig/utils/_confread freeswan-1.5/utils/_confread
--- freeswan-1.5.orig/utils/_confread	Wed May 31 08:10:40 2000
+++ freeswan-1.5/utils/_confread	Thu Oct  5 07:05:59 2000
@@ -118,6 +118,7 @@
 	left = " left leftsubnet leftnexthop leftfirewall leftupdown"
 	akey = " keyexchange auth pfs keylife rekeymargin rekeyfuzz"
 	obs = " lifetime rekeystart rekeytries"
+	cert = " certfile keyfile peerfile certopts certpath"
 	akey = akey " keyingtries ikelifetime" obs
 	mkey = " spibase spi esp espenckey espauthkey espreplay_window"
 	left = left " leftespenckey leftespauthkey leftahkey"
@@ -125,7 +126,7 @@
 	mkey = mkey " ah ahkey ahreplay_window"
 	right = left
 	gsub(/left/, "right", right)
-	n = split(good left right akey mkey, g)
+	n = split(good left right akey mkey cert, g)
 	for (i = 1; i <= n; i++)
 		goodnames["conn:" g[i]] = 1
 
diff -ruN freeswan-1.5.orig/utils/auto freeswan-1.5/utils/auto
--- freeswan-1.5.orig/utils/auto	Sat Apr 15 12:25:07 2000
+++ freeswan-1.5/utils/auto	Thu Oct  5 07:05:59 2000
@@ -307,6 +307,18 @@
 			need("rightrsasigkey")
 		}
 
+		if (s["authby"] == "cert") {
+			default("certfile", "")
+			default("certopts", "send")
+			default("keyfile", "")
+			default("certpath", "")
+			authtype = "--openssl"
+			need("certfile")
+			need("certopts")
+			need("keyfile")
+			need("certpath")
+		}
+
 		print "PATH=\"'"$PATH"'\""
 		print "export PATH"
 
@@ -341,6 +353,17 @@
 		if ("rekeyfuzz" in s)
 			fuzz = "--rekeyfuzz " s["rekeyfuzz"]
 
+		if (authtype == "--openssl") {
+			if ("certfile" in s)
+				certfile = "--certfile " s["certfile"]
+			if ("certopts" in s)
+				certopts = "--certopts " s["certopts"]
+			if ("keyfile" in s)
+				keyfile = "--keyfile " s["keyfile"]
+			if ("certpath" in s)
+				certpath = "--certpath " s["certpath"]
+		}
+
 		print "ipsec whack --name", name, settings, "\\"
 		print "\t--host", s["left"], lc,
 				"--nexthop", s["leftnexthop"], lud, lid, "\\"
@@ -348,8 +371,19 @@
 				"--nexthop", s["rightnexthop"], rud, rid, "\\"
 		print "\t--ipseclifetime", s["keylife"],
 			"--rekeywindow", s["rekeymargin"], "\\"
+		if (authtype == "--openssl") {
+			if (certfile != "--certfile ")
+				print certfile, "\\"
+			if (certopts != "--certopts ")
+				print certopts, "\\"
+			if (keyfile != "--keyfile ")
+				print keyfile, "\\"
+			if (certpath != "--certpath ")
+				print certpath, "\\"
+		}
+
 		print "\t--keyingtries", s["keyingtries"], fuzz
-		if (authtype != "--psk") {
+		if (authtype == "--rsasig") {
 			whackkey("left")
 			whackkey("right")
 		}
