[hipl-dev] [Merge] lp:~hipl-core/hipl/certificate-exchange into lp:hipl

  • From: Diego Biurrun <diego@xxxxxxxxxx>
  • To: mp+96786@xxxxxxxxxxxxxxxxxx
  • Date: Fri, 09 Mar 2012 16:20:33 -0000

Diego Biurrun has proposed merging lp:~hipl-core/hipl/certificate-exchange into 
lp:hipl.

Requested reviews:
  HIPL core team (hipl-core)

For more details, see:
https://code.launchpad.net/~hipl-core/hipl/certificate-exchange/+merge/96786

.. and another version, now with David's exponential backoff branch already 
merged in via trunk.
-- 
https://code.launchpad.net/~hipl-core/hipl/certificate-exchange/+merge/96786
Your team HIPL core team is requested to review the proposed merge of 
lp:~hipl-core/hipl/certificate-exchange into lp:hipl.
=== modified file 'Makefile.am'
--- Makefile.am 2012-03-09 14:42:31 +0000
+++ Makefile.am 2012-03-09 16:18:06 +0000
@@ -31,10 +31,10 @@
 EXTRA_DIST += .vimrc process_modules.py version.h
 EXTRA_DIST += debian doc patches packaging tools/bazaar tools/maintainer
 EXTRA_DIST += $(wildcard modules/*/module_info.xml)
+EXTRA_DIST += $(wildcard $(addprefix $(srcdir)/test/lib/core/,*.pem))
 EXTRA_DIST += $(wildcard $(addprefix $(srcdir)/tools/,*.cfg *.pl *.sh *.xml))
 EXTRA_DIST += $(wildcard $(addprefix $(srcdir)/hipfw/,*.cfg))
 EXTRA_DIST += $(HIPL_HEADER_LIST)
-EXTRA_DIST += hipd/pisa.c hipfw/pisa.c hipfw/pisa_cert.c
 
 ### user programs ###
 bin_PROGRAMS = test/auth_performance                                    \
@@ -122,6 +122,7 @@
                     hipd/user_ipsec_sadb_api.c                          \
                     modules/heartbeat/hipd/heartbeat.c                  \
                     modules/heartbeat_update/hipd/hb_update.c           \
+                    modules/cert/hipd/cert.c                            \
                     modules/update/hipd/update.c                        \
                     modules/update/hipd/update_builder.c                \
                     modules/update/hipd/update_locator.c                \
@@ -139,6 +140,7 @@
                     tools/nsupdate/nsupdate.conf
 
 hipfw_hipfw_sources = hipfw/cache.c                                     \
+                      hipfw/cert.c                                      \
                       hipfw/dlist.c                                     \
                       hipfw/esp_prot_api.c                              \
                       hipfw/esp_prot_config.c                           \
@@ -170,6 +172,7 @@
 
 lib_core_libhipcore_la_SOURCES = lib/core/builder.c                     \
                                  lib/core/capability.c                  \
+                                 lib/core/cert.c                        \
                                  lib/core/certtools.c                   \
                                  lib/core/conf.c                        \
                                  lib/core/crypto.c                      \
@@ -220,6 +223,7 @@
                            $(hipfw_hipfw_sources)
 
 test_check_lib_core_SOURCES = test/check_lib_core.c                     \
+                              test/lib/core/cert.c                      \
                               test/lib/core/crypto.c                    \
                               test/lib/core/hit.c                       \
                               test/lib/core/hostid.c                    \

=== modified file 'configure.ac'
--- configure.ac        2012-03-09 14:42:31 +0000
+++ configure.ac        2012-03-09 16:18:06 +0000
@@ -101,6 +101,8 @@
 AC_DEFINE_UNQUOTED(HIPL_LOCKDIR, "$(eval echo $lockdir)")
 AH_TEMPLATE(HIPL_LOCKDIR, [default lock file location])
 
+AC_DEFINE_UNQUOTED(HIPL_SOURCEDIR, "$(eval echo $srcdir)")
+AH_TEMPLATE(HIPL_SOURCEDIR, [HIPL source directory location])
 # Make sure that pythondir does not contain ${prefix} or similar so that it
 # can be substituted into our Python scripts.
 AC_SUBST(pythondir, $(eval echo $pythondir))

=== modified file 'doc/HOWTO.xml.in'
--- doc/HOWTO.xml.in    2012-01-25 10:44:48 +0000
+++ doc/HOWTO.xml.in    2012-03-09 16:18:06 +0000
@@ -2532,6 +2532,81 @@
 
   </chapter>
 
+<chapter id="ch_cert_exchange">
+    <title>Certificate Exchange</title>
+
+  <section id="ch_cert_functionality">
+    <title>Provided functionality</title>
+    <para>At the protocol level, HIPL implements the HIP_CERT parameter as
+    defined in RFC 6253. Specifically, X509 certificates are supported, whereas
+    no functionality is provided for SPKI certificates. HIP does not define
+    the usage of certificates in the protocol exchange. In HIPL, we currently
+    add certificates to the R2 in the BEX and the second update message U2
+    (e.g. during the mobility-triggered update exchange). The HIP firewall
+    verifies the certificate in the R2 and U2 if configured accordingly. If 
your
+    use case requires certificates to be included in different messages, 
changes
+    in the source code will be necessary.</para>
+  </section>
+
+  <section id="ch_cert_usage">
+    <title>Setting up a network scenario with certificates</title>
+    <para>For the following guide, we assume a setup consisting of three
+    machines (A, B, and C), where B is situated on the forwarding path between
+    A and C. A and C execute the hipd, while B executes the hipfw. The hipd
+    automatically adds a certificate to R2s and U2s if a file called
+    host-cert.der is located in @sysconfdir@. The hipfw checks for certificates
+    if certificate-based rules exist in @sysconfdir@/hipfw.conf.</para>
+    <para>To set up certificates, you have to perform the following 
steps:</para>
+    <itemizedlist>
+      <listitem><para>Generate a root certificate in PEM format (e.g. with
+      OpenSSL).</para></listitem>
+      <listitem><para>Copy the root certificate to 
@sysconfdir@/ca-root-cert.pem on
+      B.</para></listitem>
+      <listitem><para>Add a certificate-based rule to @sysconfdir@/hipfw.conf 
on B
+      (e.g. 'FORWARD -cert @sysconfdir@/ca-root-cert.pem ACCEPT').</para>
+      </listitem>
+      <listitem><para>Generate a certificate in DER format for the HI used by C
+      and place it at @sysconfdir@/host-cert.der on C.</para></listitem>
+      <listitem><para>No changes are required for A if its role is restricted 
to
+      an initiator. Otherwise, A requires the same setup as 
C.</para></listitem>
+    </itemizedlist>
+    <para>The setup of a certificate-based network scenario can be vastly
+    simplified by using a fourth HIPL-enabled host D as the certificate
+    authority. In this case, generate the root certificate on D by running:
+    </para>
+    <para><programlisting>
+    openssl req -new -x509 -key @sysconfdir@/hip_host_rsa_key_pub -out 
ca-root-cert.pem
+    </programlisting></para>
+    <para>NOTE: Apart from the common name, all fields in the certificate can 
be
+    empty. The common name must contain the HIT of D.</para>
+    <para>Now, run a BEX between C and D. After the BEX has succeeded, run the
+    following command on D as root in order to generate the certificate for C:
+    </para>
+    <para><programlisting>
+    hipconf acquire certificate #HIT_OF_C# > host-cert.der
+    </programlisting></para>
+    <para>As the final step, copy the certificates to the places mentioned in
+    the guide above.</para>
+  </section>
+
+  <section id="ch_cert_troubleshooting">
+    <title>Troubleshooting</title>
+    <para>There are a couple of things that may go wrong in a certificate-based
+    setup. The most common ones are listed below. Please, make sure to check
+    the listed items before asking questions on the hipl-users mailing 
list.</para>
+    <itemizedlist>
+      <listitem><para>Ensure that the certificates have not yet expired (e.g.
+      by checking the certificate lifetime with OpenSSL).</para></listitem>
+      <listitem><para>Validate that the time is set correctly on all hosts.
+      </para></listitem>
+      <listitem><para>Verify the certificate chain consisting of
+      root-ca-cert.pem and host-cert.der with an external tool (e.g. with
+      OpenSSL).</para></listitem>
+      </itemizedlist>
+  </section>
+
+</chapter> <!-- ch_cert_exchange -->
+
 <chapter id="ch_exp_extensions">
     <title>Other Experimental HIP Extensions</title>
 

=== modified file 'hipd/cert.c'
--- hipd/cert.c 2012-03-01 14:06:24 +0000
+++ hipd/cert.c 2012-03-09 16:18:06 +0000
@@ -49,10 +49,13 @@
 #include "lib/core/common.h"
 #include "lib/core/crypto.h"
 #include "lib/core/debug.h"
+#include "lib/core/hit.h"
 #include "lib/core/ife.h"
+#include "lib/core/prefix.h"
 #include "lib/core/protodefs.h"
 #include "lib/core/straddr.h"
 #include "lib/core/gpl/pk.h"
+#include "hadb.h"
 #include "hidb.h"
 #include "cert.h"
 
@@ -661,20 +664,19 @@
  */
 int hip_cert_x509v3_handle_request_to_sign(struct hip_common *msg)
 {
-    int                   err = 0, i = 0, nid = 0, ret = 0, secs = 0, algo = 0;
-    CONF                 *conf;
+    int                   err  = 0, i = 0, ret = 0, secs = 0, algo = 0;
+    CONF                 *conf = NULL;
     CONF_VALUE           *item;
     STACK_OF(CONF_VALUE) *sec_general = NULL;
-    STACK_OF(CONF_VALUE) *sec_name    = NULL;
     STACK_OF(CONF_VALUE) *sec_ext     = NULL;
 
-    X509_REQ                 *req     = NULL;
     X509_NAME                *issuer  = NULL;
     X509_NAME                *subj    = NULL;
     X509_EXTENSION           *ext     = NULL;
     STACK_OF(X509_EXTENSION) *extlist = NULL;
-    X509_NAME_ENTRY          *ent;
-    EVP_PKEY                 *pkey;
+    X509_NAME_ENTRY          *ent     = NULL;
+    EVP_PKEY                 *pkey    = NULL;
+    EVP_PKEY                 *sig_key = NULL;
     /** XX TODO THIS should come from a configuration file
      *  monotonically increasing counter */
     long                            serial = 0;
@@ -682,89 +684,108 @@
     X509                           *cert;
     X509V3_CTX                      ctx;
     const struct hip_cert_x509_req *subject;
-    char                            subject_hit[41];
-    char                            issuer_hit[41];
-    char                            ialtname[45];
-    char                            saltname[45];
-    struct in6_addr                *issuer_hit_n;
-    struct hip_host_id             *host_id;
-    RSA                            *rsa          = NULL;
-    DSA                            *dsa          = NULL;
+    char                            subject_hit[INET6_ADDRSTRLEN];
+    char                            issuer_hit[INET6_ADDRSTRLEN] = { 0 };
+    char                            ialtname[INET6_ADDRSTRLEN + 3];
+    char                            saltname[INET6_ADDRSTRLEN + 3];
+    hip_hit_t                      *issuer_hit_n = NULL;
+    struct hip_host_id             *host_id      = NULL;
+    void                           *key          = NULL;
     unsigned char                  *der_cert     = NULL;
     int                             der_cert_len = 0;
     char                            arg1[21];
     char                            arg2[21];
-
-    HIP_IFEL(!(issuer_hit_n = malloc(sizeof(struct in6_addr))), -1,
+    const struct hip_tlv_common    *validity_param = NULL;
+    time_t                          expiry_time    = 0;
+    const struct hip_hadb_state    *ha             = NULL;
+
+
+    HIP_IFEL(!(issuer_hit_n = malloc(sizeof(hip_hit_t))), -1,
              "Malloc for subject failed\n");
-    HIP_IFEL(!(pkey = malloc(sizeof(EVP_PKEY))), -1,
-             "Malloc for pkey failed\n");
+    HIP_IFEL(!(pkey = EVP_PKEY_new()), -1,
+             "Allocating subject pub key failed\n");
+    HIP_IFEL(!(sig_key = EVP_PKEY_new()), -1,
+             "Allocating issuer signature key failed\n");
 
-    OpenSSL_add_all_algorithms();
     ERR_load_crypto_strings();
 
     HIP_DEBUG("Reading configuration file (%s)\n", HIP_CERT_CONF_PATH);
     conf        = hip_open_conf(HIP_CERT_CONF_PATH);
     sec_general = hip_read_conf_section("hip_x509v3", conf);
-    sec_name    = hip_read_conf_section("hip_x509v3_name", conf);
     sec_ext     = hip_read_conf_section("hip_x509v3_extensions", conf);
-    NCONF_free(conf);
 
-    /* Get the general information */
+    /* Fail if the hip_x509v3 or hip_x509v3_name sections are not found. */
     HIP_IFEL(sec_general == NULL, -1,
              "Failed to load general certificate information\n");
-    HIP_IFEL(!(req = X509_REQ_new()), -1, "Failed to create X509_REQ object");
-
-    HIP_IFEL(sec_name == NULL, -1,
-             "Failed to load issuer naming information for the certificate\n");
 
     /* Issuer naming */
-    if (sec_general != NULL) {
-        /* Loop through the conf stack for general information */
-        extlist = sk_X509_EXTENSION_new_null();
-        for (i = 0; i < sk_CONF_VALUE_num(sec_general); i++) {
-            item = sk_CONF_VALUE_value(sec_general, i);
-            if (!strcmp(item->name, "issuerhit")) {
-                strcpy(issuer_hit, item->value);
-                ret = inet_pton(AF_INET6, item->value, issuer_hit_n);
-                HIP_IFEL(ret < 0 && errno == EAFNOSUPPORT, -1,
-                         "Failed to convert issuer HIT to hip_hit_t\n");
-                HIP_DEBUG_HIT("Issuer HIT", issuer_hit_n);
-                HIP_IFEL(!inet_ntop(AF_INET6, issuer_hit_n,
-                                    issuer_hit, sizeof(issuer_hit)),
-                         -1, "Failed to convert subject hit to "
-                             "presentation format\n");
-            }
-            if (!strcmp(item->name, "days")) {
-                secs = HIP_CERT_DAY * atoi(item->value);
-            }
-        }
-    }
-    HIP_IFEL(!(issuer = X509_NAME_new()), -1, "Failed to set create issuer 
name");
-    nid = OBJ_txt2nid("commonName");
-    HIP_IFEL(nid == NID_undef, -1, "NID text not defined\n");
-    HIP_IFEL(!(ent = X509_NAME_ENTRY_create_by_NID(NULL, nid, MBSTRING_ASC,
+    /* Loop through the conf stack for general information */
+    for (i = 0; i < sk_CONF_VALUE_num(sec_general); i++) {
+        item = sk_CONF_VALUE_value(sec_general, i);
+        if (!strcmp(item->name, "issuerhit")) {
+            ret = inet_pton(AF_INET6, item->value, issuer_hit_n);
+            HIP_IFEL(ret != 1, -1,
+                     "Failed to convert issuer HIT to hip_hit_t\n");
+            HIP_DEBUG_HIT("Issuer  HIT", issuer_hit_n);
+            hip_convert_hit_to_str(issuer_hit_n, NULL, issuer_hit);
+        }
+        if (!strcmp(item->name, "days")) {
+            secs = HIP_CERT_DAY * atoi(item->value);
+        }
+    }
+
+    /* In case no issuerhit was in the config, just use our default HIT. */
+    if (issuer_hit[0] == 0) {
+        HIP_IFEL(hip_get_default_hit(issuer_hit_n), -1,
+                 "Unable to determine default HIT\n");
+        hip_convert_hit_to_str(issuer_hit_n, NULL, issuer_hit);
+    }
+
+    HIP_IFEL(!(issuer = X509_NAME_new()), -1, "Failed to create issuer name");
+
+    HIP_IFEL(!(ent = X509_NAME_ENTRY_create_by_NID(NULL, NID_commonName, 
MBSTRING_ASC,
                                                    (unsigned char *) 
issuer_hit, -1)), -1,
              "Failed to create name entry for issuer\n");
     HIP_IFEL(X509_NAME_add_entry(issuer, ent, -1, 0) != 1, -1,
              "Failed to add entry to issuer name\n");
 
+    X509_NAME_ENTRY_free(ent);            /* "ent" var will be re-used */
+    ent = NULL;
+
     /* Subject naming */
     /* Get the subject hit from msg */
     HIP_IFEL(!(subject = hip_get_param(msg, HIP_PARAM_CERT_X509_REQ)),
-             -1, "No cert_info struct found\n");
-    HIP_IFEL(!inet_ntop(AF_INET6, &subject->addr, subject_hit, 
sizeof(subject_hit)),
-             -1, "Failed to convert subject hit to presentation format\n");
-    HIP_IFEL(!(subj = X509_NAME_new()), -1, "Failed to set create subject 
name");
-    nid = OBJ_txt2nid("commonName");
-    HIP_IFEL(nid == NID_undef, -1, "NID text not defined\n");
-    HIP_IFEL(!(ent = X509_NAME_ENTRY_create_by_NID(NULL, nid, MBSTRING_ASC,
+             -1, "No cert_x509_req struct found\n");
+    HIP_IFEL(!ipv6_addr_is_hit(&subject->addr),
+             -1, "Address in certificate request is no HIT.\n");
+    HIP_DEBUG_HIT("Subject HIT", &subject->addr);
+    hip_convert_hit_to_str(&subject->addr, NULL, subject_hit);
+
+    HIP_IFEL(!(subj = X509_NAME_new()), -1, "Failed to create subject name");
+
+    HIP_IFEL(!(ent = X509_NAME_ENTRY_create_by_NID(NULL, NID_commonName, 
MBSTRING_ASC,
                                                    (unsigned char *) 
subject_hit, -1)), -1,
              "Failed to create name entry for subject\n");
     HIP_IFEL(X509_NAME_add_entry(subj, ent, -1, 0) != 1, -1,
              "Failed to add entry to subject name\n");
-    HIP_IFEL(X509_REQ_set_subject_name(req, subj) != 1, -1,
-             "Failed to add subject name to certificate request\n");
+
+    /* Were we sent a timestamp which indicates a requested cert validity? */
+    validity_param = hip_get_param(msg, HIP_PARAM_UINT);
+
+    if (validity_param) {
+        const uint32_t *valid_until_n = 
hip_get_param_contents_direct(validity_param);
+        const uint32_t valid_until_h  = ntohl(*valid_until_n);
+
+        /* If time_t is only 32 bits wide and signed, we cannot copy a value of
+         * valid_until_h which has its MSB set since it would be misunderstood
+         * as being negative; so only set the value if this is not the case. */
+        if (!(sizeof(time_t) == 4 && ((time_t) -1 < 0) &&
+              (0x80000000 & valid_until_h))) {
+            expiry_time = valid_until_h;
+        } else {
+            HIP_OUT_ERR(-1, "Received invalid timestamp parameter.\n");
+        }
+    }
 
     /* XX TODO add a check to skip subjectAltName and issuerAltName because 
they are
      * already in use by with IP:<hit> stuff */
@@ -778,8 +799,6 @@
                      "Failed to create extension\n");
             sk_X509_EXTENSION_push(extlist, ext);
         }
-        HIP_IFEL(!X509_REQ_add_extensions(req, extlist), -1,
-                 "Failed to add extensions to the request\n");
     }
 
     /** NOW WE ARE READY TO CREATE A CERTIFICATE FROM THE REQUEST */
@@ -797,33 +816,63 @@
              "Failed to set subject name of certificate\n");
     HIP_IFEL(X509_set_issuer_name(cert, issuer) != 1, -1,
              "Failed to set issuer name of certificate\n");
-    HIP_IFEL(!X509_gmtime_adj(X509_get_notBefore(cert), 0), -1,
+
+    X509_get_notBefore(cert)->type = V_ASN1_GENERALIZEDTIME;
+    X509_get_notAfter(cert)->type  = V_ASN1_GENERALIZEDTIME;
+
+    const time_t now         = time(NULL);
+    time_t       starttime   = 0, endtime     = 0;
+    time_t      *starttime_p = NULL, *endtime_p   = NULL;
+
+    if (expiry_time) {
+        /* A specific expiry time is demanded by the caller. */
+        if (now < expiry_time) {
+            /* Just set it up as wanted. */
+            starttime = now;
+            endtime   = expiry_time;
+        } else {
+            /* Just set the start time to one second before the expiry time.
+             * This yields a - syntactically - valid certificate. It is not
+             * our task to second-guess the motives for requesting an expiry
+             * time from the past. */
+            if (expiry_time == 1) {
+                expiry_time++;           /* another pathological case */
+            }
+            starttime = expiry_time - 1;
+            endtime   = expiry_time;
+        }
+
+        starttime_p = &starttime;
+        endtime_p   = &endtime;
+        secs        = 0;
+    } else {
+        starttime_p = NULL;
+        endtime_p   = NULL;
+        if (secs <= 0) {
+            secs = 10;                   /* and yet another one */
+        }
+    }
+
+    HIP_IFEL(!X509_time_adj(X509_get_notBefore(cert), 0, starttime_p), -1,
              "Error setting beginning time of the certificate");
-    HIP_IFEL(!X509_gmtime_adj(X509_get_notAfter(cert), secs), -1,
+    HIP_IFEL(!X509_time_adj(X509_get_notAfter(cert), secs, endtime_p), -1,
              "Error setting ending time of the certificate");
 
-    HIP_DEBUG("Getting the key\n");
-
-    HIP_IFEL(hip_get_host_id_and_priv_key(issuer_hit_n,
-                                          HIP_ANY_ALGO,
-                                          &host_id,
-                                          (void *) &rsa),
-             -1, "Private key not found\n");
-
-    algo = host_id->rdata.algorithm;
-    if (algo == HIP_HI_DSA) {
-        dsa = (DSA *) rsa;
-    }
+    /* Get the subject public key from HADB */
+    HIP_IFEL(!(ha = hip_hadb_find_byhits(issuer_hit_n, &subject->addr)),
+             -1, "Could not retrieve host association for subject HIT\n");
+
+    algo = ha->peer_pub->rdata.algorithm;
 
     switch (algo) {
     case HIP_HI_RSA:
-        HIP_IFEL(!EVP_PKEY_assign_RSA(pkey, rsa), -1,
+        HIP_IFEL(!EVP_PKEY_set1_RSA(pkey, ha->peer_pub_key), -1,
                  "Failed to convert RSA to EVP_PKEY\n");
         HIP_IFEL(X509_set_pubkey(cert, pkey) != 1, -1,
                  "Failed to set public key of the certificate\n");
         break;
     case HIP_HI_DSA:
-        HIP_IFEL(!EVP_PKEY_assign_DSA(pkey, dsa), -1,
+        HIP_IFEL(!EVP_PKEY_set1_DSA(pkey, ha->peer_pub_key), -1,
                  "Failed to convert DSA to EVP_PKEY\n");
         HIP_IFEL(X509_set_pubkey(cert, pkey) != 1, -1,
                  "Failed to set public key of the certificate\n");
@@ -926,7 +975,25 @@
         HIP_OUT_ERR(-1, "Unknown algorithm\n");
     }
 
-    HIP_IFEL(!X509_sign(cert, pkey, digest), -1,
+    /* Get the issuer key for signing */
+    HIP_IFEL(hip_get_host_id_and_priv_key(issuer_hit_n, HIP_ANY_ALGO,
+                                          &host_id, &key),
+             -1, "Private key not found\n");
+
+    switch (host_id->rdata.algorithm) {
+    case HIP_HI_RSA:
+        HIP_IFEL(!EVP_PKEY_set1_RSA(sig_key, key), -1,
+                 "Failed to convert RSA to EVP_PKEY\n");
+        break;
+    case HIP_HI_DSA:
+        HIP_IFEL(!EVP_PKEY_set1_DSA(sig_key, key), -1,
+                 "Failed to convert DSA to EVP_PKEY\n");
+        break;
+    default:
+        HIP_OUT_ERR(-1, "Unknown algorithm\n");
+    }
+
+    HIP_IFEL(!X509_sign(cert, sig_key, digest), -1,
              "Failed to sign x509v3 certificate\n");
 
     /** DER */
@@ -943,8 +1010,15 @@
 
 out_err:
     free(host_id);
-    X509_REQ_free(req);
     sk_X509_EXTENSION_pop_free(extlist, X509_EXTENSION_free);
+    X509_NAME_ENTRY_free(ent);
+    X509_NAME_free(subj);
+    X509_NAME_free(issuer);
+    NCONF_free(conf);
+    ERR_free_strings();
+    EVP_PKEY_free(pkey);
+    EVP_PKEY_free(sig_key);
+    free(issuer_hit_n);
     return err;
 }
 
@@ -985,7 +1059,7 @@
     der_cert = (unsigned char *) &p->der;
 
     vessel = p->der;
-    HIP_IFEL((cert = d2i_X509(NULL, &vessel, verify.der_len)) == NULL, -1,
+    HIP_IFEL((cert = d2i_X509(NULL, &vessel, ntohl(verify.der_len))) == NULL, 
-1,
              "Failed to convert cert from DER to internal format\n");
     /*
      * HIP_IFEL(!X509_print_fp(stdout, cert), -1,

=== modified file 'hipd/input.c'
--- hipd/input.c        2012-03-09 13:38:34 +0000
+++ hipd/input.c        2012-03-09 16:18:06 +0000
@@ -73,7 +73,6 @@
 #include "netdev.h"
 #include "opp_mode.h"
 #include "output.h"
-#include "pisa.h"
 #include "pkt_handling.h"
 #include "registration.h"
 #include "input.h"

=== modified file 'hipd/output.c'
--- hipd/output.c       2012-03-09 13:38:34 +0000
+++ hipd/output.c       2012-03-09 16:18:06 +0000
@@ -65,7 +65,6 @@
 #include "hiprelay.h"
 #include "nat.h"
 #include "netdev.h"
-#include "pisa.h"
 #include "registration.h"
 #include "output.h"
 

=== renamed file 'hipfw/pisa.c' => 'hipfw/cert.c'
--- hipfw/pisa.c        2011-11-25 13:52:20 +0000
+++ hipfw/cert.c        2012-03-09 16:18:06 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Aalto University and RWTH Aachen University.
+ * Copyright (c) 2010-2011 Aalto University and RWTH Aachen University.
  *
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation
@@ -25,551 +25,190 @@
 
 /**
  * @file
- * This file contains PISA specific functions for the firewall. The basic idea
- * is to modify the HIP messages and manage state for allowed connections to
- * allow or reject associated ESP traffic.
+ * certifcate functionality for the firewall
  *
- * @brief PISA functions for the firewall
+ * @brief certificate functions for the firewall
  */
 
 #define _BSD_SOURCE
 
+#include <limits.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <time.h>
-#include <arpa/inet.h>
 #include <netinet/in.h>
 #include <linux/netfilter.h>
-#include <openssl/hmac.h>
+#include <linux/netfilter_ipv6.h>
+#include <openssl/x509.h>
 
-#include "config.h"
+#include "lib/core/common.h"
+#include "lib/core/ife.h"
 #include "lib/core/builder.h"
-#include "lib/core/certtools.h"
-#include "lib/core/crypto.h"
+#include "lib/core/cert.h"
 #include "lib/core/debug.h"
-#include "lib/core/ife.h"
-#include "lib/core/performance.h"
-#include "lib/core/prefix.h"
-#include "modules/midauth/hipd/midauth.h"
 #include "conntrack.h"
 #include "hipfw_defines.h"
-#include "midauth.h"
-#include "pisa_cert.h"
-#include "pisa.h"
-
-
-#define PISA_RANDOM_LEN 16
-#define PISA_PUZZLE_SEED 0xDEADC0DE
-#define PISA_PUZZLE_OPAQUE_LEN (4 + HIP_AH_SHA_LEN)
-
-/* pisa_check_for_random_update is called at least every PISA_RANDOM_TTL
- * seconds. Worst case timer resolution depends on the timeout in the select
- * call */
-#define PISA_RANDOM_TTL 2.0
-
-static char            pisa_random_data[2][PISA_RANDOM_LEN];
-static struct in6_addr community_operator_hit;
-
-/* @todo make this configurable, issuer HIT */
-#define CO_HIT "2001:001a:b1b0:0aad:0f92:15ca:280c:9430"
-#define CO_HIT_FILE HIPL_SYSCONFDIR "/co_hit"
-
-/**
- * Generate a new random number and shift the old one down.
- */
-static void pisa_generate_random(void)
-{
-    void *p0, *p1;
-
-    p0 = &pisa_random_data[0][0];
-    p1 = &pisa_random_data[1][0];
-
-    memcpy(p0, p1, PISA_RANDOM_LEN);
-    get_random_bytes(p1, PISA_RANDOM_LEN);
-}
-
-/**
- * Reads out the HIT of the Community-Operator
- * from file CO_HIT_FILE
- * @param hit A pointer to the char where the HIT should be stored
- * @return 1-> success
- * @return 0-> error
- */
-static int pisa_read_communit_operator_hit(char *hit)
-{
-    FILE *f;
-    char *eofline;
-
-    f = fopen(CO_HIT_FILE, "r");
-
-    if (f == NULL) {
+#include "rule_management.h"
+#include "cert.h"
+
+// runtime configuration
+static int  use_cert              = false;
+
+static STACK_OF(X509) *root_chain = NULL;
+
+/**
+ * Init function for certificate functionality.
+ *
+ * Iterate the firewall rules and look for the cert option. If found,
+ * certificates are used and the root certificate is preloaded to verify
+ * certificates. If no such rule is found, certificates are deactivated.
+ *
+ * @return 0 on success, negative if an error occurred
+ */
+int cert_init(void)
+{
+    X509         *cert = NULL;
+    struct rule  *rule = NULL;
+    struct dlist *list = NULL;
+
+    if (!(list = get_rule_list(NF_IP6_FORWARD))) {
+        use_cert = false;
+        HIP_DEBUG("certificates deactivated\n");
         return 0;
     }
 
-    if (fgets(hit, INET6_ADDRSTRLEN, f) != NULL) {
-        eofline = strchr(hit, '\n');
-        if (eofline) {
-            *eofline = '\0';
-        }
-    } else {
-        HIP_ERROR("Fgets failed");
-    }
-    fclose(f);
-
-    return 1;
-}
-
-void pisa_check_for_random_update(void)
-{
-    static time_t lastupdate = 0;
-    time_t        now;
-
-    time(&now);
-    if (difftime(now, lastupdate) > PISA_RANDOM_TTL) {
-        pisa_generate_random();
-        lastupdate = now;
-    }
-}
-
-/**
- * Appends HMAC/SHA1 to a block of data.
- *
- * @param hit1 first HIT
- * @param hit2 second HIT
- * @param rnd which random number to use, either 0 or 1
- * @param data pointer to buffer for data and the HMAC
- * @param data_len length of data
- * @return 0 on success
- */
-static int pisa_append_hmac(struct in6_addr *hit1, struct in6_addr *hit2,
-                            int rnd, void *data, int data_len)
-{
-    uint8_t      key[32 + PISA_RANDOM_LEN];
-    int          err = 0;
-    unsigned int len = HIP_AH_SHA_LEN;
-
-    /* sanity checks for arguments */
-    HIP_IFEL(data == NULL, -1, "No data given.\n");
-    HIP_IFEL(hit1 == NULL, -1, "No first HIT given.\n");
-    HIP_IFEL(hit2 == NULL, -1, "No second HIT given.\n");
-    HIP_IFEL(data_len < 1, -1, "Data has invalid length.\n");
-    HIP_IFEL(rnd != 0 && rnd != 1, -1, "Random ID is neither 0 nor 1.\n");
-
-    /* The key for HMAC/SHA1 consists of:
-     *                16 bytes HIT1
-     *                16 bytes HIT2
-     *   PISA_RANDOM_LEN bytes pisa_random_data
-     */
-
-    ipv6_addr_copy((struct in6_addr *) (key + 0), hit1);
-    ipv6_addr_copy((struct in6_addr *) (key + 16), hit2);
-    memcpy(key + 32, &pisa_random_data[rnd][0], PISA_RANDOM_LEN);
-
-    HMAC(EVP_sha1(), key, 32 + PISA_RANDOM_LEN, data, data_len,
-         (uint8_t *) data + data_len, &len);
-
-out_err:
-    return err;
-}
-
-/**
- * Insert a PISA puzzle into a packet.
- *
- * @param ctx context of the packet where the puzzle will be inserted
- * @return success (0) or failure
- */
-static int pisa_insert_puzzle(struct hip_fw_context *ctx)
-{
-    uint8_t opaque[PISA_PUZZLE_OPAQUE_LEN];
-
-    struct hip_common *hip  = ctx->transport_hdr.hip;
-    int                seed = PISA_PUZZLE_SEED;
-
-    memcpy(&opaque, &seed, 4);
-
-    /* here we switch order of initiator and receiver to obtain a
-     * different SHA1 hash */
-    pisa_append_hmac(&hip->hitr, &hip->hits, 1, &opaque, 4);
-
-    return midauth_add_challenge_request(ctx, 3, 4, opaque, 
PISA_PUZZLE_OPAQUE_LEN);
-}
-
-/**
- * Check the validity of a PISA challenge_response.
- *
- * @param ctx context of the packet with the puzzle to check
- * @return pointer to the puzzle we accepted or NULL at failure
- */
-static struct hip_challenge_response *pisa_check_challenge_response(struct 
hip_fw_context *ctx)
-{
-    struct hip_challenge_response *response;
-    struct hip_common             *hip = ctx->transport_hdr.hip;
-    uint8_t                        hash[2][PISA_PUZZLE_OPAQUE_LEN];
-    int                            seed = PISA_PUZZLE_SEED;
-
-    memcpy(&hash[0][0], &seed, 4);
-    memcpy(&hash[1][0], &seed, 4);
-
-    pisa_append_hmac(&hip->hits, &hip->hitr, 0, &hash[0], 4);
-    pisa_append_hmac(&hip->hits, &hip->hitr, 1, &hash[1], 4);
-
-    response = hip_get_param_readwrite(hip, HIP_PARAM_CHALLENGE_RESPONSE);
-
-    while (response) {
-        /* loop over all HIP_PARAM_CHALLENGE_RESPONSE */
-        if (hip_get_param_type(response) != HIP_PARAM_CHALLENGE_RESPONSE) {
-            break;
-        }
-        if ((!memcmp(response->opaque, &hash[1][0], PISA_PUZZLE_OPAQUE_LEN)) ||
-            (!memcmp(response->opaque, &hash[0][0], PISA_PUZZLE_OPAQUE_LEN))) {
-            if (!midauth_verify_challenge_response(response,
-                                                   hip->hits,
-                                                   hip->hitr)) {
-                return response;
+    if (!(root_chain = sk_X509_new_null())) {
+        HIP_ERROR("Memory allocation failure.\n");
+        return -ENOMEM;
+    }
+
+    /* Search for rules with cert option */
+    while (list) {
+        rule = list->data;
+        if (rule->cert) {
+            HIP_DEBUG("allowed cert: %s\n", rule->cert->value);
+            use_cert = true;
+            if (!(cert = cert_load_x509_certificate(rule->cert->value,
+                                                    ENCODING_FORMAT_PEM))) {
+                HIP_ERROR("Could not load certificate of community operator 
from file: %s \n",
+                          rule->cert->value);
+                return -1;
             }
-        }
-
-        response = (struct hip_challenge_response *)
-                   hip_get_next_param_readwrite(hip,
-                                                (struct hip_tlv_common *) 
response);
-    }
-
-    return NULL;
-}
-
-/**
- * Check the certificate of the packet.
- *
- * @param ctx context of the packet with the certificate to check
- * @return success (0) or failure
- */
-static int pisa_check_certificate(struct hip_fw_context *ctx)
-{
-    struct hip_common        *hip = ctx->transport_hdr.hip;
-    const struct hip_cert    *cert;
-    struct hip_cert_spki_info ci;
-    struct pisa_cert          pc;
-    char                     *buf = NULL;
-    int                       err = 0, len;
-    time_t                    now = time(NULL);
-
-    cert = hip_get_param(hip, HIP_PARAM_CERT);
-    HIP_IFEL(cert == NULL, -1, "No certificate found.\n");
-
-    len = ntohs(cert->length);
-    buf = calloc(1, len);
-    memcpy(buf, cert + 1, len);
-
-    HIP_IFEL(hip_cert_spki_char2certinfo(buf, &ci), -1,
-             "Certificate could not be parsed.\n");
-    HIP_IFEL(hip_cert_spki_lib_verify(&ci), -1,
-             "Certificate could not be verified.\n");
-
-    pisa_split_cert(ci.cert, &pc);
-
-    /* Three conditions must be fulfilled for a certificate to be valid:
-     *
-     *  - The current time on the middlebox must be in the before/after
-     *    interval
-     *  - The certificate must be issued by the community operator (i.e.
-     *    the CO HIT must be used by the issuer)
-     *  - The host sending the certificate must be the one mentioned in
-     *    the certificate
-     */
-    HIP_IFEL(now < pc.not_before, -1,
-             "Certificate is not valid yet.\n");
-    HIP_IFEL(now > pc.not_after, -1,
-             "Certificate has expired.\n");
-
-
-    HIP_IFEL(ipv6_addr_cmp(&pc.hit_issuer, &community_operator_hit) != 0,
-             -1, "Certificate not issued by the community operator.\n");
-    HIP_IFEL(ipv6_addr_cmp(&pc.hit_subject, &hip->hits) != 0, -1,
-             "Certificate does not belong to subject.\n");
-
-    HIP_INFO("Certificate successfully verified.\n");
-
-out_err:
-    free(buf);
-    return err;
-}
-
-/**
- * Accept a connection via PISA. Update firewall to allow data packets to
- * pass through.
- *
- * @param ctx context of the packet that belongs to that connection
- */
-static void pisa_accept_connection(const struct hip_fw_context *ctx)
-{
-    struct hip_common *hip = ctx->transport_hdr.hip;
-    struct tuple      *t   = get_tuple_by_hits(&hip->hits, &hip->hitr);
-
-    if (t) {
-        t->connection->pisa_state = PISA_STATE_ALLOW;
-        HIP_INFO("PISA accepted the connection.\n");
-        hip_fw_manage_all_esp_tuples(t, true);
-    } else {
-        HIP_ERROR("Connection not found.\n");
-    }
-}
-
-/**
- * Remove a connection from the list of accepted connections based on the hits
- * of a packet.
- *
- * @param ctx context of the packet that contains HITs of the connection
- */
-static void pisa_remove_connection(const struct hip_fw_context *ctx)
-{
-    struct hip_common *hip = ctx->transport_hdr.hip;
-    struct tuple      *t   = get_tuple_by_hits(&hip->hits, &hip->hitr);
-
-    if (t) {
-        t->connection->pisa_state = PISA_STATE_DISALLOW;
-        HIP_INFO("PISA removed the connection.\n");
-        hip_fw_manage_all_esp_tuples(t, false);
-    } else {
-        HIP_ERROR("Connection not found.\n");
-    }
-}
-
-/**
- * Reject a connection via PISA. Update firewall to allow no data packets
- * to pass through.
- *
- * @param ctx context of the packet that belongs to that connection
- */
-static void pisa_reject_connection(const struct hip_fw_context *ctx)
-{
-    HIP_INFO("PISA rejected the connection.\n");
-    pisa_remove_connection(ctx);
-}
-
-/**
- * Dummy function, necessary only for performance measurements.
- *
- * @param ctx context of the packet containing the I1
- * @return NF_ACCEPT verdict
- */
-static int pisa_handler_i1(UNUSED struct hip_fw_context *ctx)
-{
-#ifdef CONFIG_HIP_PERFORMANCE
-    HIP_DEBUG("Start PERF_BASE, PERF_I1\n");
-    hip_perf_start_benchmark(perf_set, PERF_BASE);
-    hip_perf_start_benchmark(perf_set, PERF_I1);
-#endif
-
-#ifdef CONFIG_HIP_PERFORMANCE
-    HIP_DEBUG("Stop and write PERF_I1\n");
-    hip_perf_stop_benchmark(perf_set, PERF_I1);
-    hip_perf_write_benchmark(perf_set, PERF_I1);
-#endif
-
-    return NF_ACCEPT;
-}
-
-/**
- * Dummy function, necessary only for performance measurements.
- *
- * @param ctx context of the packet containing the R1
- * @return NF_ACCEPT verdict
- */
-static int pisa_handler_r1(UNUSED struct hip_fw_context *ctx)
-{
-#ifdef CONFIG_HIP_PERFORMANCE
-    HIP_DEBUG("Start PERF_R1\n");
-    hip_perf_start_benchmark(perf_set, PERF_R1);
-#endif
-
-#ifdef CONFIG_HIP_PERFORMANCE
-    HIP_DEBUG("Stop and write PERF_R1\n");
-    hip_perf_stop_benchmark(perf_set, PERF_R1);
-    hip_perf_write_benchmark(perf_set, PERF_R1);
-#endif
-
-    return NF_ACCEPT;
-}
-
-/**
- * Insert a PISA puzzle into the I2 packet.
- *
- * @param ctx context of the packet to modify
- * @return NF_ACCEPT verdict
- */
-static int pisa_handler_i2(struct hip_fw_context *ctx)
-{
-#ifdef CONFIG_HIP_PERFORMANCE
-    HIP_DEBUG("Start PERF_I2\n");
-    hip_perf_start_benchmark(perf_set, PERF_I2);
-#endif
-    pisa_insert_puzzle(ctx);
-
-#ifdef CONFIG_HIP_PERFORMANCE
-    HIP_DEBUG("Stop and write PERF_I2\n");
-    hip_perf_stop_benchmark(perf_set, PERF_I2);
-    hip_perf_write_benchmark(perf_set, PERF_I2);
-#endif
-
-    return NF_ACCEPT;
-}
-
-/**
- * Check for a PISA puzzle, a valid signature and a valid
- * certificate in the R2 packet.
- *
- * @param ctx context of the packet to check
- * @return verdict, either NF_ACCEPT or NF_DROP
- */
-static int pisa_handler_r2(struct hip_fw_context *ctx)
-{
-    int                            verdict  = NF_DROP, sig = 0, cert = 0;
-    struct hip_challenge_response *solution = NULL;
-
-#ifdef CONFIG_HIP_PERFORMANCE
-    HIP_DEBUG("Start PERF_R2\n");
-    hip_perf_start_benchmark(perf_set, PERF_R2);
-#endif
-
-    solution = pisa_check_challenge_response(ctx);
-    cert     = pisa_check_certificate(ctx);
-
-    if (solution == NULL || sig != 0 || cert != 0) {
-        /* disallow further communication if either nonce, solution,
-         * signature or certificate were not correct */
-        pisa_reject_connection(ctx);
-        verdict = NF_DROP;
-    } else {
-        /* allow futher communication otherwise */
-        pisa_accept_connection(ctx);
-        verdict = NF_ACCEPT;
-    }
-
-#ifdef CONFIG_HIP_PERFORMANCE
-    HIP_DEBUG("Stop and write PERF_R2, PERF_BASE\n");
-    hip_perf_stop_benchmark(perf_set, PERF_R2);
-    hip_perf_stop_benchmark(perf_set, PERF_BASE);
-    hip_perf_write_benchmark(perf_set, PERF_R2);
-    hip_perf_write_benchmark(perf_set, PERF_BASE);
-#endif
-
-    return verdict;
-}
-
-/**
- * Insert a PISA nonce and a PISA puzzle into the U1 packet.
- *
- * @param ctx context of the packet to modify
- * @return NF_ACCEPT verdict
- */
-static int pisa_handler_u1(struct hip_fw_context *ctx)
-{
-    pisa_insert_puzzle(ctx);
-
-    return NF_ACCEPT;
-}
-
-/**
- * Check for a PISA nonce, a PISA puzzle, a valid signature and a valid
- * certificate in the U2 packet.
- *
- * @param ctx context of the packet to check
- * @return verdict, either NF_ACCEPT or NF_DROP
- */
-static int pisa_handler_u2(struct hip_fw_context *ctx)
-{
-    int                            verdict  = NF_DROP;
-    int                            sig      = 0;
-    int                            cert     = 0;
-    struct hip_challenge_response *solution = NULL;
-
-    solution = pisa_check_challenge_response(ctx);
-    cert     = pisa_check_certificate(ctx);
-
-    if (solution == NULL || sig != 0 || cert != 0) {
-        HIP_DEBUG("U2 packet did not match criteria:  "
-                  "solution %p, signature %i, cert %i\n",
-                  solution, sig, cert);
-        verdict = NF_DROP;
-    } else {
-        /* packet was ok, insert another puzzle */
-        pisa_insert_puzzle(ctx);
-        verdict = NF_ACCEPT;
-    }
-
-    return verdict;
-}
-
-/**
- * Check for a PISA nonce and a valid signature in the U3 packet.
- *
- * @param ctx context of the packet to check
- * @return verdict, either NF_ACCEPT or NF_DROP
- */
-static int pisa_handler_u3(struct hip_fw_context *ctx)
-{
-    int                            verdict  = NF_DROP;
-    int                            sig      = 0;
-    struct hip_challenge_response *solution = NULL;
-
-    solution = pisa_check_challenge_response(ctx);
-
-    if (solution == NULL || sig != 0) {
-        HIP_DEBUG("U2 packet did not match criteria:  "
-                  "solution %p\n",
-                  solution);
-        pisa_reject_connection(ctx);
-        verdict = NF_DROP;
-    } else {
-        pisa_accept_connection(ctx);
-        verdict = NF_ACCEPT;
-    }
-    return verdict;
-}
-
-/**
- * Handle CLOSE_ACK packet. Remove the connection from the list of accepted
- * connections
- *
- * @param ctx context of the packet
- * @return verdict, either NF_ACCEPT or NF_DROP
- */
-static int pisa_handler_close_ack(struct hip_fw_context *ctx)
-{
-    pisa_remove_connection(ctx);
-    return NF_ACCEPT;
-}
-
-/**
- * Initialize basic PISA functionality
- *
- * @param h function pointers for packet handlers
- */
-void pisa_init(struct midauth_handlers *h)
-{
-    char hit[INET6_ADDRSTRLEN];
-    h->i1        = pisa_handler_i1;
-    h->r1        = pisa_handler_r1;
-    h->i2        = pisa_handler_i2;
-    h->r2        = pisa_handler_r2;
-    h->u1        = pisa_handler_u1;
-    h->u2        = pisa_handler_u2;
-    h->u3        = pisa_handler_u3;
-    h->close     = midauth_handler_accept;
-    h->close_ack = pisa_handler_close_ack;
-
-    pisa_generate_random();
-    pisa_generate_random();
-
-    if (!pisa_read_communit_operator_hit(hit)) {
-        hit[0] = '\0';
-        HIP_ERROR("Could not load Communit-Operator HIT from file %s\n",
-                  CO_HIT_FILE);
-    }
-
-    if (inet_pton(AF_INET6, hit, &community_operator_hit) <= 0) {
-        HIP_ERROR("Coult not parse Community-Operator HIT\n");
-    }
+            sk_X509_push(root_chain, cert);
+        }
+        list = list->next;
+    }
+
+    if (use_cert) {
+        HIP_DEBUG("certificates activated\n");
+    }
+
+    return 0;
+}
+
+/**
+ * Uninit function for certificate functionality.
+ *
+ * @return 0
+ */
+int cert_uninit(void)
+{
+    sk_X509_free(root_chain);
+    return 0;
+}
+
+/**
+ * Helper function that converts the special RSA and DSA key structures
+ * to the generic EVP_PKEY structure.
+ *
+ * @param key   the RSA or DSA key structure
+ * @param algo  either HIP_HI_RSA or HIP_HI_DSA
+ *
+ * @return      the EVP_PKEY structure that wraps the original key,
+ *              or NULL on error
+ */
+static EVP_PKEY *any_key_to_evp_key(void *key, int algo)
+{
+    int       err = 0;
+    EVP_PKEY *ret = NULL;
+
+    if (!(ret = EVP_PKEY_new())) {
+        HIP_ERROR("Could not init EVP_PKEY wrapper\n");
+        return NULL;
+    }
+
+    switch (algo) {
+    case HIP_HI_RSA:
+        err = EVP_PKEY_assign_RSA(ret, key);
+        break;
+    case HIP_HI_DSA:
+        err = EVP_PKEY_assign_DSA(ret, key);
+        break;
+    default:
+        HIP_DEBUG("Unknown algorithm \n");
+    }
+    if (err == 0) {
+        HIP_ERROR("Could not assign key to EVP_PKEY.\n");
+        EVP_PKEY_free(ret);
+        return NULL;
+    }
+
+    return ret;
+}
+
+/**
+ * Extract the certificate from the R2 packet and match the contained public
+ * key against the HI provided in the R1 and try to build and verify
+ * a certificate chain.
+ *
+ * For an update exchange, a certificate must be contained either in the U2
+ * (if the exchange was started by the Initiator) or in the U3
+ * (if the exchange was started by the Responder). If a certificate cannot be
+ * found in these situations an error is returned.
+ *
+ * @param common    the R2 or U2 packet
+ * @param tuple     the connection tracking tuple
+ * @param ctx       the firewall context
+ * @return          0 on success, negative error code otherwise
+ */
+int cert_handle_certificate(const struct hip_common *const common,
+                            UNUSED struct tuple *const tuple,
+                            UNUSED const struct hip_fw_context *const ctx)
+{
+    X509     *cert = NULL;
+    EVP_PKEY *pkey = NULL;
+
+    if (use_cert) {
+        /* Should there be a certificate?
+         * Not if this update is not sent by the Responder. */
+        if (!(tuple->direction == REPLY_DIR)) {
+            return 0;
+        }
+
+        /* Extract certificate of trust point from the packet. */
+        if (!(cert = cert_get_X509_from_msg(common))) {
+            HIP_DEBUG("Could not find trust-point certificate in R2/U2.\n");
+            return -1;
+        }
+
+        /* Match HI against public key in given certificate. */
+        pkey = any_key_to_evp_key(tuple->hip_tuple->data->src_pub_key,
+                                  
hip_get_host_id_algo(tuple->hip_tuple->data->src_hi));
+        if (!cert_match_public_key(cert, pkey)) {
+            HIP_ERROR("HI does not match public key in given certificate.\n");
+            return -1;
+        }
+        HIP_DEBUG("HI matches given certificate.\n");
+
+        /* Check certificate of trust point. */
+        if (cert_verify_chain(cert, NULL, root_chain, NULL)) {
+            HIP_ERROR("Could not verify trust point certificate.\n");
+            return -1;
+        }
+
+        HIP_DEBUG("Verified trust-point certificate.\n");
+    }
+
+    return 0;
 }

=== renamed file 'hipfw/pisa.h' => 'hipfw/cert.h'
--- hipfw/pisa.h        2011-11-25 13:52:20 +0000
+++ hipfw/cert.h        2012-03-09 16:18:06 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Aalto University and RWTH Aachen University.
+ * Copyright (c) 2010-2011 Aalto University and RWTH Aachen University.
  *
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation
@@ -23,26 +23,16 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#ifndef HIPL_HIPFW_PISA_H
-#define HIPL_HIPFW_PISA_H
-
-#include "midauth.h"
-
-#define PISA_STATE_DISALLOW     0
-#define PISA_STATE_ALLOW        1
-
-#ifdef CONFIG_HIP_PISA
-/**
- * Register PISA handlers with midauth and initialize data structures.
- *
- * @param h pointer to the handlers
- */
-void pisa_init(struct midauth_handlers *h);
-#endif
-
-/**
- * Check if a new random number is necessary.
- */
-void pisa_check_for_random_update(void);
-
-#endif /* HIPL_HIPFW_PISA_H */
+#ifndef HIPL_HIPFW_CERT_H
+#define HIPL_HIPFW_CERT_H
+
+#include "hipfw_defines.h"
+
+int cert_init(void);
+int cert_uninit(void);
+
+int cert_handle_certificate(const struct hip_common *const common,
+                            struct tuple *const tuple,
+                            const struct hip_fw_context *const ctx);
+
+#endif /* HIPL_HIPFW_CERT_H */

=== modified file 'hipfw/conntrack.c'
--- hipfw/conntrack.c   2012-03-08 14:33:33 +0000
+++ hipfw/conntrack.c   2012-03-09 16:18:06 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2011 Aalto University and RWTH Aachen University.
+ * Copyright (c) 2010-2012 Aalto University and RWTH Aachen University.
  *
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation
@@ -62,8 +62,9 @@
 #include "lib/core/state.h"
 #include "lib/core/gpl/pk.h"
 #include "modules/update/hipd/update.h"
+#include "config.h"
+#include "cert.h"
 #include "common_types.h"
-#include "config.h"
 #include "conntrack.h"
 #include "dlist.h"
 #include "hslist.h"
@@ -72,7 +73,7 @@
 #include "hipfw.h"
 #include "helpers.h"
 #include "hslist.h"
-#include "pisa.h"
+#include "midauth.h"
 #include "reinject.h"
 
 
@@ -1296,6 +1297,11 @@
         return 0;
     }
 
+    if (cert_handle_certificate(common, tuple, ctx)) {
+        HIP_ERROR("certificate error on R2\n");
+        return 0;
+    }
+
     /* check if the R2 contains ESP protection anchor and store state */
     if (esp_prot_conntrack_R2_anchor(common, tuple)) {
         HIP_ERROR("failed to track esp protection extension state\n");
@@ -1330,7 +1336,7 @@
     uint8_t                locator_type;
 
     ptr = (const char *) (locator + 1);
-    while (ptr < ptr + hip_get_param_contents_len(locator)) {
+    while (ptr < ((const char *) (locator + 1)) + 
hip_get_param_contents_len(locator)) {
         locator_type = ((const struct hip_locator_type_0 *) 
ptr)->header.locator_type;
         if (locator_type == HIP_LOCATOR_LOCATOR_TYPE_IPV6) {
             esp_dest_addr = &((const struct hip_locator_type_0 *) 
ptr)->address;
@@ -1368,11 +1374,6 @@
 {
     int err = 1;
 
-    if (hip_get_param_total_len(locator) - sizeof(struct hip_locator) < 
sizeof(struct hip_locator_type_0)) {
-        HIP_ERROR("no locator param found\n");
-        return 0;
-    }
-
     if (esp_info && locator && seq) {
         HIP_DEBUG("esp_info, locator and seq\n");
 
@@ -1386,6 +1387,11 @@
         esp_tuple->spi           = ntohl(esp_info->new_spi);
         esp_tuple->spi_update_id = seq->update_id;
 
+        if (hip_get_param_total_len(locator) - sizeof(struct hip_locator) < 
sizeof(struct hip_locator_type_0)) {
+            HIP_ERROR("no locator param found\n");
+            return 0;
+        }
+
         HIP_IFEL(!update_esp_dest_addr(locator, seq, esp_tuple),
                  0, "error updateing ESP destination addresses\n");
     } else if (esp_info && seq) {
@@ -1597,6 +1603,11 @@
             return 0;
         }
 
+        if (cert_handle_certificate(common, tuple, ctx)) {
+            HIP_ERROR("certificate error on U2\n");
+            return 0;
+        }
+
         if (handle_second_update(tuple, ctx, esp_info, seq)) {
             HIP_ERROR("unable to process second UPDATE message\n");
             return 0;

=== modified file 'hipfw/hipfw.c'
--- hipfw/hipfw.c       2012-03-08 12:28:00 +0000
+++ hipfw/hipfw.c       2012-03-09 16:18:06 +0000
@@ -78,6 +78,7 @@
 #include "hipd/hipd.h"
 #include "config.h"
 #include "cache.h"
+#include "cert.h"
 #include "common_types.h"
 #include "conntrack.h"
 #include "esp_prot_api.h"
@@ -87,7 +88,6 @@
 #include "helpers.h"
 #include "lsi.h"
 #include "midauth.h"
-#include "pisa.h"
 #include "port_bindings.h"
 #include "reinject.h"
 #include "rewrite.h"
@@ -481,6 +481,8 @@
 
     midauth_init();
 
+    HIP_IFEL(cert_init(), -1, "failed to load extension (cert)\n");
+
     // Initializing local port cache database
     hip_port_bindings_init(true);
     /* Initialize raw sockets for packet reinjection */
@@ -628,6 +630,8 @@
     fw_uninit_lsi_support();
     hip_fw_uninit_conntrack();
 
+    cert_uninit();
+
 #ifdef CONFIG_HIP_PERFORMANCE
     /* Deallocate memory of perf_set after finishing all of tests */
     hip_perf_destroy(perf_set);
@@ -1876,12 +1880,6 @@
             continue;
         }
 
-#ifdef CONFIG_HIP_PISA
-        if (use_midauth) {
-            pisa_check_for_random_update();
-        }
-#endif
-
         if (FD_ISSET(h4->fd, &read_fdset)) {
             HIP_DEBUG("received IPv4 packet from iptables queue\n");
             err = fw_handle_packet(buf, h4, 4, &ctx);

=== modified file 'hipfw/hipfw.conf'
--- hipfw/hipfw.conf    2011-12-15 13:25:00 +0000
+++ hipfw/hipfw.conf    2012-03-09 16:18:06 +0000
@@ -7,5 +7,6 @@
 #            -i [!] <incoming interface>
 #            -o [!] <outgoing interface>
 #            -state [!] <state> --verify_responder --accept_mobile 
--decrypt_contents
+#            -cert <root certificate>"
 #
 

=== modified file 'hipfw/hipfw_defines.h'
--- hipfw/hipfw_defines.h       2012-02-17 18:01:18 +0000
+++ hipfw/hipfw_defines.h       2012-03-09 16:18:06 +0000
@@ -158,7 +158,6 @@
     /* members needed for ESP protection extension */
     int     num_esp_prot_tfms;
     uint8_t esp_prot_tfms[MAX_NUM_TRANSFORMS];
-    int     pisa_state;
 };
 
 #endif /* HIPL_HIPFW_FIREWALL_DEFINES_H */

=== modified file 'hipfw/main.c'
--- hipfw/main.c        2011-11-25 13:52:20 +0000
+++ hipfw/main.c        2012-03-09 16:18:06 +0000
@@ -37,14 +37,15 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 #include <sys/types.h>
 
 #include "lib/core/filemanip.h"
 #include "lib/core/debug.h"
 #include "lib/core/util.h"
+#include "conntrack.h"
 #include "hipfw.h"
-#include "conntrack.h"
 #include "midauth.h"
 
 

=== removed file 'hipfw/pisa_cert.c'
--- hipfw/pisa_cert.c   2011-08-15 14:11:56 +0000
+++ hipfw/pisa_cert.c   1970-01-01 00:00:00 +0000
@@ -1,205 +0,0 @@
-/*
- * Copyright (c) 2010 Aalto University and RWTH Aachen University.
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use,
- * copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following
- * conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * @file
- * This file deals with the PISA specific handling of SPKI certificates. The
- * certificate is parsed and split into small chunks.
- *
- * @brief PISA handling for SPKI certificates
- */
-
-#define _BSD_SOURCE
-
-#include <string.h>
-#include <time.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <sys/types.h>
-
-#include "pisa_cert.h"
-
-
-/**
- * Extract parts of a SPKI certificate.
- *
- * @param cert pointer to the certificate text or part of a certificate text
- * @param name pointer to the pattern we are looking for
- * @param r pointer to a buffer that the search result will be copied to
- * @return 0 on success
- */
-static char *pisa_cert_get_part(char *cert, const char *name, char *r)
-{
-    int   level = 0, len = 0;
-    char *p     = cert, *start = NULL;
-
-    if (!r) {
-        return NULL;
-    }
-
-    if (!cert) {
-        goto out_err;
-    }
-
-    if (!name) {
-        goto out_err;
-    }
-
-    len = strlen(name);
-    if (len == 0) {
-        goto out_err;
-    }
-
-    while (*p) {
-        if (*p == '(') {
-            level++;
-            if (level == 2 && !strncmp(p + 1, name, len)) {
-                if (*(p + len + 1) == ' ') {
-                    start = p++;
-                    break;
-                }
-            }
-        }
-        if (*p == ')') {
-            level--;
-        }
-        if (level == 0) {
-            break;
-        }
-        p++;
-    }
-
-    if (!start) {
-        goto out_err;
-    }
-
-    len = 0;
-
-    while (*p) {
-        if (*p == '(') {
-            level++;
-        }
-        if (*p == ')') {
-            level--;
-            if (level == 1) {
-                len = p - start + 1;
-                break;
-            }
-        }
-        if (level == 0) {
-            break;
-        }
-        p++;
-    }
-
-    strncpy(r, start, len);
-    r[len] = '\0';
-
-    return r;
-
-out_err:
-    r[0] = '\0';
-    return NULL;
-}
-
-/**
- * Get the content from a SPKI certificate part.
- *
- * @param cert pointer to the certificate text or part of a certificate text
- * @param name pointer to the pattern we are looking for
- * @param r pointer to a buffer that the search result will be copied to
- * @return 0 on success
- */
-static void pisa_cert_get_content(char *cert, const char *name, char *r)
-{
-    char *start = cert;
-    int   len   = 0;
-
-    if (!r) {
-        return;
-    }
-
-    if (!cert || !name || !*name == '(') {
-        goto out_err;
-    }
-
-    if (strlen(name) + 3 > strlen(cert)) {
-        goto out_err;
-    }
-
-    if (strncmp(name, cert + 1, strlen(name))) {
-        goto out_err;
-    }
-    start = cert + strlen(name) + 2;
-
-    if (*start == '\0') {
-        goto out_err;
-    }
-
-    len = strlen(start) - 1;
-    if (*(start + len) != ')') {
-        goto out_err;
-    }
-    strncpy(r, start, len);
-
-out_err:
-    r[len] = '\0';
-}
-
-/**
- * Splits a certificate into semantic chunks and converts these to
- * sensible binary representations.
- *
- * @param cert    the original certificate
- * @param pc internal representation of the certificate
- */
-void pisa_split_cert(char *cert, struct pisa_cert *pc)
-{
-    struct tm       t;
-    char            buffer1[224], buffer2[224];
-    struct in6_addr addr;
-
-    pisa_cert_get_part(cert, "not-before", buffer1);
-    pisa_cert_get_content(buffer1, "not-before", buffer2);
-    strptime(buffer2, "\"%Y-%m-%d_%H:%M:%S\"", &t);
-    pc->not_before = mktime(&t);
-
-    pisa_cert_get_part(cert, "not-after", buffer1);
-    pisa_cert_get_content(buffer1, "not-after", buffer2);
-    strptime(buffer2, "\"%Y-%m-%d_%H:%M:%S\"", &t);
-    pc->not_after = mktime(&t);
-
-    pisa_cert_get_part(cert, "issuer", buffer1);
-    pisa_cert_get_part(buffer1, "hash hit", buffer2);
-    pisa_cert_get_content(buffer2, "hash hit", buffer1);
-    inet_pton(AF_INET6, buffer1, &addr);
-    memcpy(&pc->hit_issuer, &addr, sizeof(struct in6_addr));
-
-    pisa_cert_get_part(cert, "subject", buffer1);
-    pisa_cert_get_part(buffer1, "hash hit", buffer2);
-    pisa_cert_get_content(buffer2, "hash hit", buffer1);
-    inet_pton(AF_INET6, buffer1, &addr);
-    memcpy(&pc->hit_subject, &addr, sizeof(struct in6_addr));
-}

=== removed file 'hipfw/pisa_cert.h'
--- hipfw/pisa_cert.h   2011-11-25 13:52:20 +0000
+++ hipfw/pisa_cert.h   1970-01-01 00:00:00 +0000
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2010 Aalto University and RWTH Aachen University.
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use,
- * copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following
- * conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#ifndef HIPL_HIPFW_PISA_CERT_H
-#define HIPL_HIPFW_PISA_CERT_H
-
-#include <time.h>
-#include <netinet/in.h>
-
-struct pisa_cert {
-    struct in6_addr hit_issuer;
-    struct in6_addr hit_subject;
-    time_t          not_before;
-    time_t          not_after;
-};
-
-/**
- * Split the hip_cert_spki_info.cert part into small chunks
- *
- * @param cert the hip_cert_spki_info.cert part of the certificate
- * @param pc   datastructure that will contain the chunks
- */
-void pisa_split_cert(char *cert, struct pisa_cert *pc);
-
-#endif /* HIPL_HIPFW_PISA_CERT_H */

=== modified file 'hipfw/rule_management.c'
--- hipfw/rule_management.c     2011-12-15 13:53:03 +0000
+++ hipfw/rule_management.c     2012-03-09 16:18:06 +0000
@@ -68,6 +68,7 @@
 #define IN_IF_STR "-i"
 #define OUT_IF_STR "-o"
 #define STATE_STR "-state"
+#define CERT_STR "-cert"
 #define SRC_HI_STR "--hi"
 #define VERIFY_RESPONDER_STR "--verify_responder"
 #define ACCEPT_MOBILE_STR "--accept_mobile"
@@ -97,6 +98,7 @@
     STATE_OPTION,
     IN_IF_OPTION,
     OUT_IF_OPTION,
+    CERT_OPTION,
     HOOK
 };
 
@@ -248,6 +250,7 @@
     rule->state   = NULL;
     rule->in_if   = NULL;
     rule->out_if  = NULL;
+    rule->cert    = NULL;
     rule->hook    = -1;
     rule->accept  = -1;
     return rule;
@@ -283,6 +286,7 @@
         free(rule->state);
         free_string_option(rule->in_if);
         free_string_option(rule->out_if);
+        free_string_option(rule->cert);
         free(rule);
     }
 }
@@ -682,6 +686,15 @@
                     return NULL;
                 }
                 option_found = STATE_OPTION;
+            } else if (!strcmp(token, CERT_STR)) {
+                /* option already defined */
+                /* rule only applicable to forward hook */
+                if (rule->cert != NULL || rule->hook != NF_IP6_FORWARD) {
+                    HIP_DEBUG("error parsing rule: cert option \n");
+                    free_rule(rule);
+                    return NULL;
+                }
+                option_found = CERT_OPTION;
             } else if (!strcmp(token, VERIFY_RESPONDER_STR)) {
                 /* related state option must be defined */
                 if (rule->state == NULL) {
@@ -794,6 +807,16 @@
                     return NULL;
                 }
                 option_found = NO_OPTION;
+            } else if (option_found == CERT_OPTION) {
+                rule->cert          = malloc(sizeof(struct string_option));
+                rule->cert->value   = strdup(token);
+                rule->cert->boolean = 0;
+                if (rule->cert == NULL || rule->cert->value == NULL) {
+                    HIP_DEBUG("error parsing rule: cert value \n");
+                    free_rule(rule);
+                    return NULL;
+                }
+                option_found = NO_OPTION;
             } else if (option_found == IN_IF_OPTION) {
                 rule->in_if = parse_if(token);
                 if (rule->in_if == NULL) {

=== modified file 'hipfw/rule_management.h'
--- hipfw/rule_management.h     2011-11-25 13:52:20 +0000
+++ hipfw/rule_management.h     2012-03-09 16:18:06 +0000
@@ -76,6 +76,7 @@
     struct hip_host_id   *src_hi;
     struct int_option    *type;
     struct state_option  *state;
+    struct string_option *cert;
     struct string_option *in_if;
     struct string_option *out_if;
     unsigned int          hook;

=== modified file 'lib/core/builder.c'
--- lib/core/builder.c  2012-03-08 13:39:18 +0000
+++ lib/core/builder.c  2012-03-09 16:18:06 +0000
@@ -1118,6 +1118,10 @@
     case HIP_MSG_REINIT_FULLRELAY:   return "HIP_MSG_REINIT_FULLRELAY";
     case HIP_MSG_FIREWALL_START:     return "HIP_MSG_FIREWALL_START";
     case HIP_MSG_MANUAL_UPDATE_PACKET: return "HIP_MSG_MANUAL_UPDATE_PACKET";
+    case HIP_MSG_CERT_SPKI_SIGN:      return "HIP_MSG_CERT_SPKI_SIGN";
+    case HIP_MSG_CERT_SPKI_VERIFY:    return "HIP_MSG_CERT_SPKI_VERIFY";
+    case HIP_MSG_CERT_X509V3_SIGN:    return "HIP_MSG_CERT_X509V3_SIGN";
+    case HIP_MSG_CERT_X509V3_VERIFY:  return "HIP_MSG_CERT_X509V3_VERIFY";
     default:
         return lmod_get_packet_identifier(msg_type);
     }
@@ -1137,6 +1141,8 @@
     switch (param_type) {
     case HIP_PARAM_ACK:             return "HIP_PARAM_ACK";
     case HIP_PARAM_CERT:            return "HIP_PARAM_CERT";
+    case HIP_PARAM_CERT_X509_REQ:   return "HIP_PARAM_CERT_X509_REQ";
+    case HIP_PARAM_CERT_X509_RESP:  return "HIP_PARAM_CERT_X509_RESP";
     case HIP_PARAM_DH_SHARED_KEY:   return "HIP_PARAM_DH_SHARED_KEY";
     case HIP_PARAM_DIFFIE_HELLMAN:  return "HIP_PARAM_DIFFIE_HELLMAN";
     case HIP_PARAM_DSA_SIGN_DATA:   return "HIP_PARAM_DSA_SIGN_DATA";
@@ -3265,7 +3271,8 @@
  * @return zero on success or negative on failure
  */
 int hip_build_param_cert(struct hip_common *msg, uint8_t group, uint8_t count,
-                         uint8_t id, uint8_t type, void *data, size_t size)
+                         uint8_t id, enum hip_cert_type type, void *data,
+                         size_t size)
 {
     struct hip_cert cert;
 
@@ -3352,7 +3359,7 @@
 }
 
 /**
- * Build and append a X509 certiticate request parameter into a HIP control
+ * Build and append a X509 certificate request parameter into a HIP control
  * message (on-the-wire)
  *
  * @param msg a pointer to the message where the parameter will be
@@ -3361,7 +3368,7 @@
  * @return zero on success, or negative on failure
  * @see <a 
href="http://tools.ietf.org/html/draft-ietf-hip-cert";>draft-ietf-hip-cert</a>
  */
-int hip_build_param_cert_x509_req(struct hip_common *msg, struct in6_addr 
*addr)
+int hip_build_param_cert_x509_req(struct hip_common *msg, hip_hit_t *addr)
 {
     struct hip_cert_x509_req subj;
 
@@ -3399,7 +3406,7 @@
  * @return zero on success, or negative on failure
  * @see <a 
href="http://tools.ietf.org/html/draft-ietf-hip-cert";>draft-ietf-hip-cert</a>
  */
-int hip_build_param_cert_x509_resp(struct hip_common *msg, char *der, int len)
+int hip_build_param_cert_x509_resp(struct hip_common *msg, char *der, unsigned 
len)
 {
     return build_param_cert_x509(msg, der, len, HIP_PARAM_CERT_X509_RESP);
 }
@@ -3415,7 +3422,7 @@
  * @return zero on success, or negative on failure
  * @see <a 
href="http://tools.ietf.org/html/draft-ietf-hip-cert";>draft-ietf-hip-cert</a>
  */
-int hip_build_param_cert_x509_ver(struct hip_common *msg, char *der, int len)
+int hip_build_param_cert_x509_ver(struct hip_common *msg, char *der, unsigned 
len)
 {
     return build_param_cert_x509(msg, der, len, HIP_PARAM_CERT_X509_REQ);
 }

=== modified file 'lib/core/builder.h'
--- lib/core/builder.h  2012-02-23 10:43:16 +0000
+++ lib/core/builder.h  2012-03-09 16:18:06 +0000
@@ -115,13 +115,9 @@
                              uint32_t,
                              uint16_t,
                              struct hip_crypto_key *);
-int hip_build_param_cert(struct hip_common *,
-                         uint8_t,
-                         uint8_t,
-                         uint8_t,
-                         uint8_t,
-                         void *,
-                         size_t);
+int hip_build_param_cert(struct hip_common *msg, uint8_t group, uint8_t count,
+                         uint8_t id, enum hip_cert_type type, void *data,
+                         size_t size);
 int hip_build_param_puzzle(struct hip_common *const msg,
                            const uint8_t val_K,
                            const uint8_t lifetime,
@@ -159,8 +155,10 @@
 int hip_build_param_cert_spki_info(struct hip_common *msg,
                                    struct hip_cert_spki_info *cert_info);
 int hip_build_param_cert_x509_req(struct hip_common *, struct in6_addr *);
-int hip_build_param_cert_x509_resp(struct hip_common *, char *, int);
-int hip_build_param_cert_x509_ver(struct hip_common *, char *, int);
+int hip_build_param_cert_x509_resp(struct hip_common *msg, char *der,
+                                   unsigned len);
+int hip_build_param_cert_x509_ver(struct hip_common *msg, char *der,
+                                  unsigned len);
 
 int hip_build_param_hit_to_ip_set(struct hip_common *, const char *);
 int hip_build_user_hdr(struct hip_common *, hip_hdr, hip_hdr_err);

=== added file 'lib/core/cert.c'
--- lib/core/cert.c     1970-01-01 00:00:00 +0000
+++ lib/core/cert.c     2012-03-09 16:18:06 +0000
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2010-2012 Aalto University and RWTH Aachen University.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file
+ * @brief functionality for handling X509 certificates
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+
+#include "builder.h"
+#include "debug.h"
+#include "ife.h"
+#include "common.h"
+#include "cert.h"
+
+/**
+ * This function encodes the given certificate to its DER encoding for
+ * transmission over the wire. The encoded certificate is written to @p buf.
+ *
+ * @param cert      the certificate to encode
+ * @param buf       the output is written here
+ *
+ * @return          the length of the encoded data
+ *
+ * @note: The encoded data is in binary form and may contain embedded zeroes.
+ *        Functions such as strlen() will not return the correct length of the
+ *        encoded structure. Therefore the length value returned by this
+ *        function should always be used.
+ */
+int cert_X509_to_DER(X509 *const cert, unsigned char **buf)
+{
+    int len;
+
+    if (!cert) {
+        HIP_ERROR("Cannot encode NULL-certificate\n");
+        return -1;
+    }
+    if (!buf) {
+        HIP_ERROR("Cannot create output buffer at NULL-pointer.\n");
+        return -1;
+    }
+
+    *buf = NULL;
+    len  = i2d_X509(cert, buf);
+
+    if (len < 0) {
+        HIP_ERROR("Could not DER-encode the given certificate.\n");
+        return -1;
+    }
+    return len;
+}
+
+/**
+ * Function to decode a DER-encoded certificate to the internal OpenSSL X509
+ * structure.
+ *
+ * @param buf   the buffer from which the DER-encoded certificate is read
+ * @param len   the length of the DER-encoded certificate
+ *              (NOTE: strlen() and similar functions fail, since DER is
+ *              basically binary data that can contain 0-bytes).
+ *
+ * @return      the OpenSSL X509 structure corresponding the DER-encoded
+ *              certificate, NULL if errors occured
+ */
+X509 *cert_DER_to_X509(const unsigned char *buf, const int len)
+{
+    if (!buf) {
+        HIP_ERROR("Cannot decode from NULL-buffer\n");
+        return NULL;
+    }
+    if (len <= 0) {
+        HIP_ERROR("Cannot decode certificate of length <= 0\n");
+        return NULL;
+    }
+    return d2i_X509(NULL, &buf, len);
+}
+
+/**
+ * Load a X509 certificate from @p file. If @p file contains more
+ * than one certificate, the certificate at the top of the file is
+ * returned.
+ *
+ * @param   file  the file to load the certficate from
+ * @param   fmt   the input format of the certificate
+ *
+ * @return  a pointer to an X.509 certificate on success, NULL on error
+ */
+X509 *cert_load_x509_certificate(const char *const file,
+                                 enum encoding_format fmt)
+{
+    FILE *fp   = NULL;
+    X509 *cert = NULL;
+
+    if (!file) {
+        HIP_ERROR("Cannot read certificate from NULL-filename.\n");
+        return NULL;
+    }
+
+    fp = fopen(file, "rb");
+    if (!fp) {
+        HIP_ERROR("Could not open file for reading: %s\n", file);
+        return NULL;
+    }
+
+    if (fmt == ENCODING_FORMAT_PEM) {
+        cert = PEM_read_X509(fp, NULL, NULL, NULL);
+    } else if (fmt == ENCODING_FORMAT_DER) {
+        cert = d2i_X509_fp(fp, NULL);
+    } else {
+        HIP_ERROR("Invalid encoding format %i \n", fmt);
+        return NULL;
+    }
+
+    if (fclose(fp)) {
+        HIP_ERROR("Error closing file: %s\n", file);
+        X509_free(cert);
+        return NULL;
+    } else if (!cert) {
+        HIP_ERROR("Could not decode certificate from file.\n");
+        return NULL;
+    }
+
+    return cert;
+}
+
+/**
+ * Search for hip_cert parameter in @p msg and try to decode the data in
+ * the first certificate parameter of a X509 certificate.
+ *
+ * @param msg   the message to extract the certificate from
+ *
+ * @return      the first X509 certificate found in the message on success,
+ *              NULL on error and if no certificates were found
+ */
+X509 *cert_get_X509_from_msg(const struct hip_common *const msg)
+{
+    const struct hip_cert *param_cert = NULL;
+
+    if (!(param_cert = hip_get_param(msg, HIP_PARAM_CERT))) {
+        HIP_ERROR("Message contains no certificate.\n");
+        return NULL;
+    }
+
+    /* The contents of the certificate begin after the header of the
+     * hip_cert parameter. */
+    return cert_DER_to_X509((const unsigned char *) (param_cert + 1),
+                            ntohs(param_cert->length) -
+                            sizeof(struct hip_cert) +
+                            sizeof(struct hip_tlv_common));
+}
+
+/**
+ * Compare a given public key @p pkey with the public key
+ * contained in @p cert.
+ *
+ * @param cert  the X509 certificate
+ * @param pkey  the public key to match
+ *
+ * @return 1 if match, 0 otherwise
+ */
+int cert_match_public_key(X509 *cert, const EVP_PKEY *pkey)
+{
+    EVP_PKEY *pkey2 = NULL;
+
+    if (!cert || !pkey) {
+        return 0;
+    }
+    pkey2 = X509_get_pubkey(cert);
+    return EVP_PKEY_cmp(pkey2, pkey);
+}
+
+/**
+ * Build and verify a certificate chain.
+ *
+ * @param leaf_cert             the certificate to verify
+ * @param trusted_lookup_dir    certificates in this directory are used as
+ *                              root certificates
+ * @param trusted_chain         a certificate stack that can contain additional
+ *                              trusted certificates
+ * @param untrusted_chain       a chain of untrusted certificates that can be
+ *                              used to build a complete certificate chain
+ *
+ * @return                      0 if a certificate chain could be built and
+ *                              verified, a non-zero error code otherwise
+ */
+int cert_verify_chain(X509 *leaf_cert,
+                      const char *trusted_lookup_dir,
+                      STACK_OF(X509) *trusted_chain,
+                      STACK_OF(X509) *untrusted_chain)
+{
+    int             err              = 0;
+    X509_LOOKUP    *lookup           = NULL;
+    X509_STORE     *verify_ctx_store = NULL;
+    X509_STORE_CTX *verify_ctx       = NULL;
+
+    if (!leaf_cert) {
+        HIP_ERROR("Cannot verify NULL-certificate.\n");
+        return -1;
+    }
+
+    if (!trusted_lookup_dir && !trusted_chain) {
+        HIP_ERROR("Need trusted dir and trusted chain.\n");
+        return -1;
+    }
+
+    /* Build the verify context */
+    if (!(verify_ctx_store = X509_STORE_new())) {
+        HIP_ERROR("Failed to init certificate store.\n");
+        return -1;
+    }
+    if (!(lookup = X509_STORE_add_lookup(verify_ctx_store, 
X509_LOOKUP_hash_dir()))) {
+        HIP_ERROR("Failed to init lookup directory.\n");
+        return -1;
+    }
+    if (trusted_lookup_dir) {
+        if (!X509_LOOKUP_add_dir(lookup, trusted_lookup_dir,
+                                 X509_FILETYPE_PEM)) {
+            HIP_ERROR("Failed to add directory %s to trusted lookup 
resources.\n",
+                      trusted_lookup_dir);
+            return -1;
+        }
+    } else {
+        X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT);
+    }
+
+    if (!(verify_ctx = X509_STORE_CTX_new())) {
+        HIP_ERROR("Failed to allocate new verify context.\n");
+        return -ENOMEM;
+    }
+    if (!X509_STORE_CTX_init(verify_ctx, verify_ctx_store, leaf_cert,
+                             untrusted_chain)) {
+        HIP_ERROR("Failed to setup verify context.\n");
+        X509_STORE_CTX_free(verify_ctx);
+        return -1;
+    }
+    if (trusted_chain) {
+        X509_STORE_CTX_trusted_stack(verify_ctx, trusted_chain);
+    }
+
+    /* Finally do the verification and output some info on error */
+    OpenSSL_add_all_algorithms();
+    err = X509_verify_cert(verify_ctx);
+
+    if (err != 1) {
+        err = X509_STORE_CTX_get_error(verify_ctx);
+        HIP_DEBUG("X509 verify cert error: %d \n", err);
+        HIP_DEBUG("at depth: %d \n", 
X509_STORE_CTX_get_error_depth(verify_ctx));
+        HIP_DEBUG("reason: %s\n", X509_verify_cert_error_string(err));
+        HIP_DEBUG("certificate:\n");
+        X509_print_fp(stderr, X509_STORE_CTX_get_current_cert(verify_ctx));
+    } else {
+        err = 0;
+    }
+
+    X509_STORE_CTX_free(verify_ctx);
+    return err;
+}

=== added file 'lib/core/cert.h'
--- lib/core/cert.h     1970-01-01 00:00:00 +0000
+++ lib/core/cert.h     2012-03-09 16:18:06 +0000
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2010-2011 Aalto University and RWTH Aachen University.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef HIPL_LIB_CORE_CERT_H
+#define HIPL_LIB_CORE_CERT_H
+
+#include <openssl/x509.h>
+
+#include "lib/core/protodefs.h"
+
+enum encoding_format {
+    ENCODING_FORMAT_PEM,
+    ENCODING_FORMAT_DER
+};
+
+int cert_X509_to_DER(X509 *const cert, unsigned char **buf);
+X509 *cert_DER_to_X509(const unsigned char *const buf, const int len);
+
+X509 *cert_load_x509_certificate(const char *const file,
+                                 enum encoding_format fmt);
+X509 *cert_get_X509_from_msg(const struct hip_common *const msg);
+
+int cert_match_public_key(X509 *cert, const EVP_PKEY *pkey);
+int cert_verify_chain(X509 *leaf_cert,
+                      const char *trusted_lookup_dir,
+                      STACK_OF(X509) *trusted_chain,
+                      STACK_OF(X509) *untrusted_chain);
+
+#endif /* HIPL_LIB_CORE_CERT_H */

=== modified file 'lib/core/certtools.c'
--- lib/core/certtools.c        2012-01-14 15:29:47 +0000
+++ lib/core/certtools.c        2012-03-09 16:18:06 +0000
@@ -710,8 +710,8 @@
     /* get the struct from the message sent back by the daemon */
     HIP_IFEL(!(p = hip_get_param(msg, HIP_PARAM_CERT_X509_RESP)), -1,
              "No name x509 struct found\n");
-    memcpy(certificate, p->der, p->der_len);
-    err = p->der_len;
+    memcpy(certificate, p->der, ntohl(p->der_len));
+    err = ntohl(p->der_len);
 
 out_err:
     free(msg);
@@ -797,18 +797,18 @@
 }
 
 /**
- * Load a configuration file from HIP_CERT_CONF_PATH.
+ * Load the indicated configuration file.
  *
  * @return CONF pointer if OK, NULL on error
  */
 CONF *hip_open_conf(const char *filename)
 {
-    long  err;
     CONF *conf;
 
     conf = NCONF_new(NCONF_default());
-    if (!NCONF_load(conf, filename, &err)) {
+    if (!NCONF_load(conf, filename, NULL)) {
         HIP_ERROR("Error opening the configuration file");
+        NCONF_free(conf);
         return NULL;
     }
     return conf;

=== modified file 'lib/core/conf.c'
--- lib/core/conf.c     2012-01-13 16:25:15 +0000
+++ lib/core/conf.c     2012-03-09 16:18:06 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2011 Aalto University and RWTH Aachen University.
+ * Copyright (c) 2010-2012 Aalto University and RWTH Aachen University.
  *
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation
@@ -59,10 +59,12 @@
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <sys/types.h>
+#include <openssl/pem.h>
 
-#include "common.h"
 #include "config.h"
 #include "builder.h"
+#include "cert.h"
+#include "common.h"
 #include "crypto.h"
 #include "debug.h"
 #include "hostid.h"
@@ -126,7 +128,8 @@
 /* unused, was ACTION_HANDOVER 39 */
 #define ACTION_MANUAL_UPDATE 40
 #define ACTION_BROADCAST 41
-#define ACTION_MAX 42 /* exclusive */
+#define ACTION_ACQUIRE 42
+#define ACTION_MAX 43 /* exclusive */
 
 /**
  * TYPE_ constant list, as an index for each action_handler function.
@@ -176,7 +179,8 @@
 /* unused, was TYPE_HANDOVER 42 */
 #define TYPE_MANUAL_UPDATE 43
 #define TYPE_BROADCAST     44
-#define TYPE_MAX           45 /* exclusive */
+#define TYPE_CERTIFICATE   45
+#define TYPE_MAX           46 /* exclusive */
 
 /* #define TYPE_RELAY         22 */
 
@@ -230,6 +234,7 @@
     "shotgun on|off\n"
     "id-to-addr hit|lsi\n"
     "broadcast on|off\n"
+    "acquire certificate <hit> [valid-till_timestamp]\n"
 ;
 
 /**
@@ -648,6 +653,8 @@
         }
     } else if (!strcmp("broadcast", argv[2])) {
         ret = ACTION_BROADCAST;
+    } else if (!strcmp("acquire", argv[2])) {
+        ret = ACTION_ACQUIRE;
     }
 
     return ret;
@@ -698,6 +705,7 @@
     case ACTION_TRANSORDER:
     case ACTION_NAT_LOCAL_PORT:
     case ACTION_NAT_PEER_PORT:
+    case ACTION_ACQUIRE:
         count = 2;
         break;
     default:
@@ -750,6 +758,8 @@
         } else {
             ret = TYPE_NAT;
         }
+    } else if (!strcmp("certificate", text)) {
+        ret = TYPE_CERTIFICATE;
     } else if (strcmp("locator", argv[2]) == 0) {
         ret = TYPE_LOCATOR;
     } else if (!strcmp("debug", text)) {
@@ -819,6 +829,7 @@
     case ACTION_HIT_TO_IP:
     case ACTION_HIT_TO_IP_SET:
     case ACTION_BROADCAST:
+    case ACTION_ACQUIRE:
         type_arg = 3;
         break;
     case ACTION_MANUAL_UPDATE:
@@ -2424,6 +2435,122 @@
 }
 
 /**
+ * Utility function which compactly checks whether a string represents
+ * a positive natural number, since scanf() is too lenient.
+ *
+ * @param string NULL-terminated string to be checked
+ *
+ * @return       1 if the only characters in the string are digits,
+ *                optionally with one leading '+' sign; 0 otherwise
+ */
+static int is_pos_natural_number(const char *string)
+{
+    if (string) {
+        size_t len;
+
+        // allow one leading '+'
+        if (string[0] == '+') {
+            string++;
+        }
+
+        if ((len = strlen(string)) > 0) {
+            for (size_t i = 0; i < len; i++) {
+                if (string[i] < '0' || string[i] > '9') {
+                    return 0;
+                }
+            }
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static int conf_handle_certificate(struct hip_common *msg,
+                                   int action,
+                                   const char *opt[],
+                                   int optc,
+                                   UNUSED int send_only)
+{
+    hip_hit_t                        subject_hit;
+    uint32_t                         valid_until_h = 0, valid_until_n = 0;
+    int                              scanf_res     = 0, err = 0;
+    X509                            *cert          = NULL;
+    const struct hip_cert_x509_resp *p             = NULL;
+
+    /* Convert the parameter strings input by the user into the
+     * appropriate binary formats for further processing. */
+    const int pton_res = inet_pton(AF_INET6, opt[0], &subject_hit);
+
+    if (optc == 2 && is_pos_natural_number(opt[1])) {
+        /* Need to use sscanf() here: strtol() won't do since we want the 
result
+         * of the conversion to fit into an uint32_t, whereas strtol() and
+         * relatives would write to a variable of platform-dependent size. */
+        scanf_res = sscanf(opt[1], "%" SCNu32, &valid_until_h);
+    }
+
+    /* The second parameter after "acquire certificate" is optional, so we
+     * accept optc == 1 as well as optc == 2 (the latter is implied if
+     * scanf_res is 1). */
+    if (pton_res == 1 && action == ACTION_ACQUIRE &&
+        (optc == 1 || scanf_res == 1)) {
+        HIP_DEBUG_HIT("Requesting certificate for subject", &subject_hit);
+
+        if (hip_build_user_hdr(msg, HIP_MSG_CERT_X509V3_SIGN, 0)) {
+            HIP_ERROR("Failed to build user message header.\n");
+            return -1;
+        }
+
+        /* If the user provides a second parameter (following the HIT), it is
+         * meant to indicate the point in time when validity of the issued
+         * certificate ends; expressed in "number of seconds since the epoch";
+         * we use a uint32_t for this, so we're creating a year-2106-problem
+         * here (be scared). */
+        if (scanf_res == 1) {
+            valid_until_n = htonl(valid_until_h);
+            if (hip_build_param_contents(msg, &valid_until_n,
+                                         HIP_PARAM_UINT, sizeof(uint32_t))) {
+                HIP_ERROR("Failed to build validity parameter.\n");
+                return -1;
+            }
+        }
+
+        if (hip_build_param_cert_x509_req(msg, &subject_hit)) {
+            HIP_ERROR("Failed to build cert_x509_req parameter.\n");
+            return -1;
+        }
+    } else {
+        err = -1;
+        HIP_ERROR("Invalid arguments.\n");
+    }
+
+    /* Send the message to the daemon. The daemon fills the message. */
+    if (hip_send_recv_daemon_info(msg, send_only, 0)) {
+        return -ECOMM;
+    }
+
+    /* Handle the answer */
+    if (!(p = hip_get_param(msg, HIP_PARAM_CERT_X509_RESP))) {
+        HIP_ERROR("No name x509 struct found\n");
+        return -1;
+    }
+    const uint32_t der_len_h = ntohl(p->der_len);
+    if (!(cert = cert_DER_to_X509(p->der, der_len_h))) {
+        HIP_ERROR("Could not get X509 certificate from DER encoding\n.");
+        return -1;
+    }
+    if (fwrite(p->der, der_len_h, 1, stdout) != 1) {
+        HIP_ERROR("Couldn't output certificate.\n");
+        return -1;
+    }
+
+    /* Clear the msg (and in particular its message type field)
+     * to prevent hip_do_hipconf() from sending it again. */
+    hip_msg_init(msg);
+
+    return err;
+}
+
+/**
  * Function pointer array containing pointers to handler functions.
  * Add a handler function for your new action in the action_handler[] array.
  * If you added a handler function here, do not forget to define that function
@@ -2492,6 +2619,7 @@
     NULL,                               /* 42: unused, was TYPE_HANDOVER */
     conf_handle_manual_update,          /* 43: TYPE_MANUAL_UPDATE */
     conf_handle_broadcast,              /* 44: TYPE_BROADCAST */
+    conf_handle_certificate,            /* 45: TYPE_CERTIFICATE */
     NULL     /* TYPE_MAX, the end. */
 };
 

=== modified file 'lib/core/protodefs.h'
--- lib/core/protodefs.h        2012-03-08 18:50:52 +0000
+++ lib/core/protodefs.h        2012-03-09 16:18:06 +0000
@@ -375,6 +375,20 @@
 #define HIP_VER_RES                 0x01     /* Version 1, reserved 0 */
 #define HIP_USER_VER_RES            0xF0       /* Internal messages */
 
+
+/* HIP certificate types
+ * (according to RFC 6253) */
+enum hip_cert_type {
+    HIP_CERT_X509V3,
+    HIP_CERT_SPKI,
+    HIP_CERT_X509V3_HASH_URL,
+    HIP_CERT_SPKI_HASH_URL,
+    HIP_CERT_X509V3_LDAP_URL,
+    HIP_CERT_SPKI_LDAP_URL,
+    HIP_CERT_X509V3_DN,
+    HIP_CERT_SPKI_DN,
+};
+
 /**
  * @defgroup hip_ha_controls HIP host association controls
  *

=== added directory 'modules/cert'
=== added directory 'modules/cert/hipd'
=== renamed file 'hipd/pisa.c' => 'modules/cert/hipd/cert.c'
--- hipd/pisa.c 2011-10-25 21:14:16 +0000
+++ modules/cert/hipd/cert.c    2012-03-09 16:18:06 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Aalto University and RWTH Aachen University.
+ * Copyright (c) 2010-2012 Aalto University and RWTH Aachen University.
  *
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation
@@ -25,59 +25,179 @@
 
 /**
  * @file
- * This file contains functions that are specific to PISA. They deal with the
- * certificate loading.
- *
- * @brief Functions for certificate loading
+ * @brief functions to add certificates to R2 and U2 messages
  */
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include "config.h"
+#include "hipd/hipd.h"
+#include "hipd/pkt_handling.h"
+#include "lib/core/builder.h"
+#include "lib/core/cert.h"
 #include "lib/core/debug.h"
-#include "hipd.h"
-#include "pisa.h"
-
-#define CERT_MAX_SIZE 1024
-
-static char *midauth_cert = NULL;
-
-/**
- * Load a certificate from the file HIPL_SYSCONFDIR/cert and store it in memory
- *
- * @return 0 on success
- */
-static int pisa_load_certificate(void)
-{
-    FILE *f = NULL;
-
-    free(midauth_cert);
-    midauth_cert = calloc(1, CERT_MAX_SIZE);
-
-    if (!(f = fopen(HIPL_SYSCONFDIR "/cert", "r"))) {
-        HIP_ERROR("Could not open certificate file.\n");
-        return -1;
-    }
-
-    if (fread(midauth_cert, CERT_MAX_SIZE - 1, 1, f) == 0) {
-        perror("fread returned 0");
-    }
-    fclose(f);
-    return 0;
-}
-
-/**
- * Load a certificate from disk and return a pointer to the global
- * variable containing it.
- *
- * @see pisa_load_certificate*
- *
- * @return pointer to midauth_cert
- */
-char *hip_pisa_get_certificate(void)
-{
-    pisa_load_certificate();
-    return midauth_cert;
+#include "lib/core/ife.h"
+#include "lib/core/protodefs.h"
+#include "modules/midauth/hipd/midauth.h"
+#include "modules/update/hipd/update.h"
+#include "cert.h"
+
+static X509 *host_cert = NULL;
+
+/**
+ *  Handler that adds the certificate to an R2 message.
+ *
+ *  @param msg          the message where to add the certificate
+ *  @param certificate  the certificate to add to the message
+ *
+ *  @return             0 on success, negative on error
+ */
+static int hip_add_certificate(struct hip_common *msg, X509 *certificate)
+{
+    unsigned char *buf;
+    int            len = 0;
+
+    /* Sanity checks */
+    if (!msg) {
+        HIP_ERROR("Message is NULL\n");
+        return -1;
+    }
+    if (!certificate) {
+        HIP_ERROR("Certificate is NULL\n");
+        return -1;
+    }
+
+    /* Encode the certificate to DER and build the certificate parameter. */
+    if ((len = cert_X509_to_DER(certificate, &buf)) < 0) {
+        HIP_ERROR("Encoding error\n");
+        return -1;
+    }
+    if (hip_build_param_cert(msg, 0, 1, 1, HIP_CERT_X509V3, buf, len)) {
+        HIP_ERROR("Building of certificate parameter failed.\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+/**
+ *  Handler that adds the certificate to an R2 message.
+ *
+ * @param packet_type unused
+ * @param ha_state    unused
+ * @param ctx         the packet context
+ *
+ * @return 0 on success, negative on failure
+ *
+ * @note:  The certificate is regarded non-critical thus the function does
+ *         not fail even if no certificate is available.
+ */
+static int hip_add_certificate_r2(UNUSED const uint8_t packet_type,
+                                  UNUSED const uint32_t ha_state,
+                                  struct hip_packet_context *ctx)
+{
+    if (hip_add_certificate(ctx->output_msg, host_cert)) {
+        HIP_DEBUG("Sending R2 without certificate.\n");
+    }
+    return 0;
+}
+
+/**
+ * Handler that adds the certificate to the second or third update message.
+ * A certificate should only be included if the previous
+ * update packet contained a middlebox challenge.
+ *
+ * @param packet_type unused
+ * @param ha_state    unused
+ * @param ctx         the packet context
+ *
+ * @return 0 on success, negative on failure
+ *
+ * @note:  The certificate is regarded non-critical thus the function does
+ *          not fail even if no certificate is available.
+ */
+static int hip_add_certificate_update(UNUSED const uint8_t packet_type,
+                                      UNUSED const uint32_t ha_state,
+                                      struct hip_packet_context *ctx)
+{
+    if (!host_cert) {
+        HIP_DEBUG("No certificate available.\n");
+        return 0;
+    }
+
+    /* Include a certificate in the U2 or U3, if available. */
+    if (hip_classify_update_type(ctx->input_msg) == FIRST_UPDATE_PACKET ||
+        hip_classify_update_type(ctx->input_msg) == SECOND_UPDATE_PACKET) {
+        if (hip_get_param_contents(ctx->input_msg, 
HIP_PARAM_CHALLENGE_REQUEST)) {
+            if (hip_add_certificate(ctx->output_msg, host_cert)) {
+                HIP_ERROR("Failed to add certificate to update message.\n");
+                return -1;
+            }
+        } else {
+            HIP_DEBUG("No middlebox found in previous update, omitting 
certificate.\n");
+        }
+    }
+
+    return 0;
+}
+
+/**
+ * Initialize certificate functionality in the hipd.
+ * Registers handlers to add the trust point certificate in R2 and U2 messages.
+ *
+ * @return 0 on success, negative on error
+ */
+int hip_cert_init(void)
+{
+    if (hip_register_handle_function(HIP_I2, HIP_STATE_NONE,
+                                     &hip_add_certificate_r2, 40500)) {
+        HIP_ERROR("Error on registering certificate handle function.\n");
+        return -1;
+    }
+    if (hip_register_handle_function(HIP_I2, HIP_STATE_UNASSOCIATED,
+                                     &hip_add_certificate_r2, 40500)) {
+        HIP_ERROR("Error on registering certificate handle function.\n");
+        return -1;
+    }
+    if (hip_register_handle_function(HIP_I2, HIP_STATE_I1_SENT,
+                                     &hip_add_certificate_r2, 40500)) {
+        HIP_ERROR("Error on registering certificate handle function.\n");
+        return -1;
+    }
+    if (hip_register_handle_function(HIP_I2, HIP_STATE_I2_SENT,
+                                     &hip_add_certificate_r2, 40500)) {
+        HIP_ERROR("Error on registering certificate handle function.\n");
+        return -1;
+    }
+    if (hip_register_handle_function(HIP_I2, HIP_STATE_R2_SENT,
+                                     &hip_add_certificate_r2, 40500)) {
+        HIP_ERROR("Error on registering certificate handle function.\n");
+        return -1;
+    }
+    if (hip_register_handle_function(HIP_I2, HIP_STATE_ESTABLISHED,
+                                     &hip_add_certificate_r2, 40500)) {
+        HIP_ERROR("Error on registering certificate handle function.\n");
+        return -1;
+    }
+    if (hip_register_handle_function(HIP_UPDATE, HIP_STATE_ESTABLISHED,
+                                     &hip_add_certificate_update, 20752)) {
+        HIP_ERROR("Error on registering certificate handle function.\n");
+        return -1;
+    }
+    if (hip_register_handle_function(HIP_UPDATE, HIP_STATE_R2_SENT,
+                                     &hip_add_certificate_update, 20752)) {
+        HIP_ERROR("Error on registering certificate handle function.\n");
+        return -1;
+    }
+
+    if (!(host_cert = cert_load_x509_certificate(HIPL_SYSCONFDIR 
"/host-cert.der",
+                                                 ENCODING_FORMAT_DER))) {
+        HIP_DEBUG("Could not load certificate.\n");
+    }
+
+    HIP_DEBUG("certificates initialized\n");
+
+    return 0;
 }

=== renamed file 'hipd/pisa.h' => 'modules/cert/hipd/cert.h'
--- hipd/pisa.h 2011-11-25 17:56:24 +0000
+++ modules/cert/hipd/cert.h    2012-03-09 16:18:06 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Aalto University and RWTH Aachen University.
+ * Copyright (c) 2010-2011 Aalto University and RWTH Aachen University.
  *
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation
@@ -23,22 +23,9 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 
-/**
- * @file
- * This file contains function declarations  specific to PISA. They deal with 
the
- * certificate loading.
- *
- * @brief Functions declarations for certificate loading
- */
-
-#ifndef HIPL_HIPD_PISA_H
-#define HIPL_HIPD_PISA_H
-
-/**
- * Get the certificate text that will be appended to R2 and U2 packets
- *
- * @return pointer to the certificate text
- */
-char *hip_pisa_get_certificate(void);
-
-#endif /* HIPL_HIPD_PISA_H */
+#ifndef HIPL_MODULES_CERT_HIPD_CERT_H
+#define HIPL_MODULES_CERT_HIPD_CERT_H
+
+int hip_cert_init(void);
+
+#endif /* HIPL_MODULES_CERT_HIPD_CERT_H */

=== added file 'modules/cert/module_info.xml'
--- modules/cert/module_info.xml        1970-01-01 00:00:00 +0000
+++ modules/cert/module_info.xml        2012-03-09 16:18:06 +0000
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- Mandatory: name, version -->
+<module
+    name="cert"
+    version="0.0.1"
+    description="certificate exchange for the HIP daemon."
+    developer=""
+    bugaddress="hipl-users@xxxxxxxxxxxxx"
+    webpage="http://infrahip.hiit.fi/";>
+
+    <requires>
+        <module name="update" minversion="0.0.1" />
+        <module name="midauth" minversion="0.0.1" />
+    </requires>
+
+    <!-- Mandatory: name, header_file, init_function -->
+    <application
+        name="hipd"
+        header_file="modules/cert/hipd/cert.h"
+        init_function="hip_cert_init" />
+</module>
+

=== modified file 'modules/update/hipd/update.c' (properties changed: -x to +x)
=== modified file 'test/check_lib_core.c'
--- test/check_lib_core.c       2012-03-01 14:06:24 +0000
+++ test/check_lib_core.c       2012-03-09 16:18:06 +0000
@@ -37,6 +37,7 @@
 {
     int      number_failed;
     SRunner *sr = srunner_create(lib_core_hit());
+    srunner_add_suite(sr, lib_core_cert());
     srunner_add_suite(sr, lib_core_hostid());
     srunner_add_suite(sr, lib_core_solve());
     srunner_add_suite(sr, lib_core_straddr());

=== added file 'test/lib/core/cert.c'
--- test/lib/core/cert.c        1970-01-01 00:00:00 +0000
+++ test/lib/core/cert.c        2012-03-09 16:18:06 +0000
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2011 Aalto University and RWTH Aachen University.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <check.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "lib/core/cert.h"
+#include "lib/core/crypto.h"
+#include "lib/core/ife.h"
+#include "lib/core/protodefs.h"
+#include "config.h"
+#include "test_suites.h"
+
+#define TEST_CERT HIPL_SOURCEDIR "/test/lib/core/test_cert.pem"
+#define TEST_KEY  HIPL_SOURCEDIR "/test/lib/core/test_key.pem"
+
+START_TEST(test_cert_load_x509_certificate)
+{
+    X509 *cert = NULL;
+
+    HIP_DEBUG("Test loading of X509 certificates.\n");
+
+    fail_unless((cert = cert_load_x509_certificate(TEST_CERT,
+                                                   ENCODING_FORMAT_PEM)) != 
NULL,
+                NULL);
+    fail_unless((cert = cert_load_x509_certificate("non_existing_cert.pem",
+                                                   ENCODING_FORMAT_PEM)) == 
NULL,
+                NULL);
+    fail_unless((cert = cert_load_x509_certificate(NULL,
+                                                   ENCODING_FORMAT_PEM)) == 
NULL,
+                NULL);
+
+    X509_free(cert);
+    HIP_DEBUG("Successfully passed tests for loading X509 certificates.\n");
+}
+END_TEST
+
+START_TEST(test_cert_DER_encoding)
+{
+    int            len          = 0;
+    X509          *cert         = NULL;
+    X509          *cert_decoded = NULL;
+    unsigned char *buf          = NULL;
+
+    HIP_DEBUG("Test DER en/decoding of X509 certificates.\n");
+
+    fail_unless((cert = cert_load_x509_certificate(TEST_CERT,
+                                                   ENCODING_FORMAT_PEM)) != 
NULL,
+                NULL);
+    fail_unless((len = cert_X509_to_DER(cert, &buf)) > 0, NULL);
+    fail_unless((cert_decoded = cert_DER_to_X509(buf, len)) != NULL, NULL);
+    fail_unless(X509_cmp(cert, cert_decoded) == 0, NULL);
+
+    fail_unless((len = cert_X509_to_DER(NULL, &buf)) < 0, NULL);
+    fail_unless((len = cert_X509_to_DER(cert, NULL)) < 0, NULL);
+    fail_unless((len = cert_X509_to_DER(NULL, NULL)) < 0, NULL);
+
+    fail_unless((cert_decoded = cert_DER_to_X509(NULL, len)) == NULL, NULL);
+    fail_unless((cert_decoded = cert_DER_to_X509(buf, len - 1)) == NULL, NULL);
+    fail_unless((cert_decoded = cert_DER_to_X509(buf, len + 1)) == NULL, NULL);
+    fail_unless((cert_decoded = cert_DER_to_X509(buf, 0)) == NULL, NULL);
+
+    X509_free(cert);
+    X509_free(cert_decoded);
+
+    HIP_DEBUG("Successfully passed tests for DER en/decoding of X509 
certificates.\n");
+}
+
+END_TEST
+
+START_TEST(test_cert_match_public_key)
+{
+    int       err  = 0;
+    RSA      *rsa  = NULL;
+    X509     *cert = NULL;
+    EVP_PKEY *pkey = NULL;
+
+    HIP_DEBUG("Test matching of public keys.\n");
+
+    fail_unless((err = load_rsa_private_key(TEST_KEY, &rsa)) == 0, NULL);
+    fail_unless((cert = cert_load_x509_certificate(TEST_CERT,
+                                                   ENCODING_FORMAT_PEM)) != 
NULL,
+                NULL);
+    pkey = EVP_PKEY_new();
+    EVP_PKEY_assign_RSA(pkey, rsa);
+    fail_unless((err = cert_match_public_key(cert, pkey)) == 1, NULL);
+
+    fail_unless((err = cert_match_public_key(NULL, pkey)) == 0, NULL);
+    fail_unless((err = cert_match_public_key(cert, NULL)) == 0, NULL);
+    fail_unless((err = cert_match_public_key(NULL, NULL)) == 0, NULL);
+
+    EVP_PKEY_free(pkey);
+    X509_free(cert);
+
+    HIP_DEBUG("Successfully passed test for matching of public keys.\n");
+}
+
+END_TEST
+
+START_TEST(test_cert_verify_chain)
+{
+    int             err   = 0;
+    X509           *cert  = NULL;
+    STACK_OF(X509) *chain = NULL;
+
+    HIP_DEBUG("Test verification of certificate chains.\n");
+
+    fail_unless((cert = cert_load_x509_certificate(TEST_CERT,
+                                                   ENCODING_FORMAT_PEM)) != 
NULL,
+                NULL);
+    fail_unless((chain = sk_X509_new_null()) != NULL, NULL);
+    sk_X509_push(chain, cert);
+    fail_unless((err = cert_verify_chain(cert, NULL, chain, NULL)) == 0, NULL);
+
+    fail_unless((err = cert_verify_chain(NULL, NULL, chain, NULL)) != 0, NULL);
+    fail_unless((err = cert_verify_chain(cert, NULL, NULL, NULL)) != 0, NULL);
+
+    HIP_DEBUG("Successfully passed test for verification of certificate 
chains.\n");
+}
+
+END_TEST
+
+START_TEST(test_cert_get_X509_from_msg)
+{
+    int                len  = 0;
+    X509              *cert = NULL, *cert2 = NULL;
+    struct hip_common *msg  = NULL;
+    unsigned char     *buf  = NULL;
+
+    HIP_DEBUG("Test certificate extraction functionality.\n");
+
+    fail_unless((cert = cert_load_x509_certificate(TEST_CERT,
+                                                   ENCODING_FORMAT_PEM)) != 
NULL,
+                NULL);
+    msg = hip_msg_alloc();
+    hip_build_network_hdr(msg, HIP_UPDATE, 0, &in6addr_any, &in6addr_any);
+    fail_unless((len = cert_X509_to_DER(cert, &buf)) > 0, NULL);
+    fail_unless(hip_build_param_cert(msg, 0, 1, 1, HIP_CERT_X509V3, buf, len) 
== 0, NULL);
+    fail_unless((cert2 = cert_get_X509_from_msg(msg)) != NULL, NULL);
+    fail_unless(X509_cmp(cert, cert2) == 0, NULL);
+
+    X509_free(cert);
+    X509_free(cert2);
+
+    HIP_DEBUG("Successfully passed test for certificate extraction 
functionality.\n");
+}
+
+END_TEST
+
+
+Suite *lib_core_cert(void)
+{
+    Suite *s = suite_create("lib/core/cert");
+
+    TCase *tc_core = tcase_create("Core");
+    tcase_add_test(tc_core, test_cert_load_x509_certificate);
+    tcase_add_test(tc_core, test_cert_DER_encoding);
+    tcase_add_test(tc_core, test_cert_match_public_key);
+    tcase_add_test(tc_core, test_cert_verify_chain);
+    tcase_add_test(tc_core, test_cert_get_X509_from_msg);
+
+    suite_add_tcase(s, tc_core);
+
+    return s;
+}

=== added file 'test/lib/core/test_cert.pem'
--- test/lib/core/test_cert.pem 1970-01-01 00:00:00 +0000
+++ test/lib/core/test_cert.pem 2012-03-09 16:18:06 +0000
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICWTCCAcKgAwIBAgIJAPRDK58Gc992MA0GCSqGSIb3DQEBBQUAMCgxCzAJBgNV
+BAYTAkRFMRkwFwYDVQQDExBUZXN0IENlcnRpZmljYXRlMB4XDTExMTExNTA4NDYx
+MloXDTE0MDgxMTA4NDYxMlowKDELMAkGA1UEBhMCREUxGTAXBgNVBAMTEFRlc3Qg
+Q2VydGlmaWNhdGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMn5azBSwPlu
+DIzEhd6fGdo1+ze9uS+i+AbifvjHKYaDwDZktANnUmTuLNAXoeVtFi5GH/5aczUx
+rFaW+XT33oO1OjotZOHvoQd5cVAvXTtzuJj9PnBtA0lkrQ36f765p65Id0+Xme3o
+sXfqLsJy12C23RjisPgAo0hsLUFXt+FZAgMBAAGjgYowgYcwHQYDVR0OBBYEFGrj
+JefuwL7xAFj9NZoDVksjz1JBMFgGA1UdIwRRME+AFGrjJefuwL7xAFj9NZoDVksj
+z1JBoSykKjAoMQswCQYDVQQGEwJERTEZMBcGA1UEAxMQVGVzdCBDZXJ0aWZpY2F0
+ZYIJAPRDK58Gc992MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAKX5Q
+0di8aNk1Js5Sk6QstSWwoVT9DUNZ8wKKRZVHy4kSL7dGMNGRPyNydzJmKeacbZJ0
+wM64rMMC1E8Wnyo+7eS1k9NKgaR5S1K6SVTfgP0HYIeJquD5Im/KW3aMz/q5CWdV
+IZtpTC2/1YsK+dVlvvcYRxnSTpIEd/pmu574lis=
+-----END CERTIFICATE-----

=== added file 'test/lib/core/test_key.pem'
--- test/lib/core/test_key.pem  1970-01-01 00:00:00 +0000
+++ test/lib/core/test_key.pem  2012-03-09 16:18:06 +0000
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQDJ+WswUsD5bgyMxIXenxnaNfs3vbkvovgG4n74xymGg8A2ZLQD
+Z1Jk7izQF6HlbRYuRh/+WnM1MaxWlvl0996DtTo6LWTh76EHeXFQL107c7iY/T5w
+bQNJZK0N+n++uaeuSHdPl5nt6LF36i7Cctdgtt0Y4rD4AKNIbC1BV7fhWQIDAQAB
+AoGAT1OS8evOtyit7SvSmFlMwhOpk38EmN0dJTcYP4WZnadpevOacCvIhLO3DhP6
+Fi3+JDaOokvMK/xSf7/UQkiIL+dwY5FtWtG6K+T1WI4+DR7ULShr82jh4KemhYv3
+Xz6PvEBIUrf64VfsNsAzoWvbwum/Ev1XzFn5YS4/EW3ApnECQQD2YW6tTjzyq3y7
+sgil9/VtUrXpPi5Ekm8l/bFW2Ijwin03g6J+YvkDNIq5Wwyka7lBOLwpdSpzT2qB
+70Ne1nlfAkEA0dwlgou4xOVVmbtTb40FxIFgd2gDQO8bUFEa+TdPWLLxz9yxHQ7D
+YROYh5Gdi0u4lz0KNex/6zyaP7E+utbIRwJAexNc2FH2/DpSCuj6jP36qevhV2xq
+bHLB9zZtujZc4dwshOjK6VvDjKhYjBNBk3kEh+IxjHwtAoEvcUz2WI/G/QJAcMr5
+/ihKrsj0MSRVu+b36p3+0y68UPIypABzlu77XpkPDsF3ED8XE94MZREGtA+GrwLH
+siPivPRdk04YgSNfkQJBAMhHvxL5xsb31bu8h7kxoYHj/XuqJxyToTcqksr7M1RO
+z33Bid+znwnB7n8CLFpV3iqF14xbRKiPlc//wVNWtZ8=
+-----END RSA PRIVATE KEY-----

=== modified file 'test/lib/core/test_suites.h'
--- test/lib/core/test_suites.h 2012-03-01 14:06:24 +0000
+++ test/lib/core/test_suites.h 2012-03-09 16:18:06 +0000
@@ -28,6 +28,7 @@
 
 #include <check.h>
 
+Suite *lib_core_cert(void);
 Suite *lib_core_crypto(void);
 Suite *lib_core_hit(void);
 Suite *lib_core_hostid(void);

=== modified file 'tools/hipl_autobuild.sh'
--- tools/hipl_autobuild.sh     2012-02-28 16:54:46 +0000
+++ tools/hipl_autobuild.sh     2012-03-09 16:18:06 +0000
@@ -169,7 +169,7 @@
 run_program "make $MAKEOPTS check"
 
 # minimal configuration
-compile --enable-firewall --disable-rvs --disable-profiling --disable-debug 
--disable-performance --with-nomodules=heartbeat,update,heartbeat_update,midauth
+compile --enable-firewall --disable-rvs --disable-profiling --disable-debug 
--disable-performance 
--with-nomodules=heartbeat,update,heartbeat_update,midauth,cert
 
 # Max compile coverage configuration
 FEATURES_ALL="--enable-firewall --enable-rvs --enable-profiling 
--disable-debug --enable-performance"
@@ -185,9 +185,6 @@
 # FIXME: Disabled until the tree compiles with this optimization level.
 #compile $FEATURES_ALL CFLAGS="-O3"
 
-# Without modules
-compile --with-nomodules=heartbeat,update,heartbeat_update,midauth
-
 # test binary distribution packages
 # This is run as the last test because it can have sideeffects on the
 # other standard configurations.

Other related posts: