diff options
author | Andreas Steffen <andreas.steffen@strongswan.org> | 2009-09-27 23:09:30 +0200 |
---|---|---|
committer | Andreas Steffen <andreas.steffen@strongswan.org> | 2009-09-27 23:09:30 +0200 |
commit | 0eff9f65398c1b2ecf8b478302b6f4e3cc717e80 (patch) | |
tree | 0495c9ad699d0aa67bbba26e1b4bcc958881859b /src/pluto | |
parent | 727b0f11e234acd31885a04025d0caf1b7c92f77 (diff) | |
download | strongswan-0eff9f65398c1b2ecf8b478302b6f4e3cc717e80.tar.bz2 strongswan-0eff9f65398c1b2ecf8b478302b6f4e3cc717e80.tar.xz |
pluto and scepclient now use the x509 plugin for certificates
Diffstat (limited to 'src/pluto')
-rw-r--r-- | src/pluto/ac.c | 9 | ||||
-rw-r--r-- | src/pluto/builder.c | 12 | ||||
-rw-r--r-- | src/pluto/ca.c | 319 | ||||
-rw-r--r-- | src/pluto/ca.h | 11 | ||||
-rw-r--r-- | src/pluto/certs.c | 18 | ||||
-rw-r--r-- | src/pluto/connections.c | 329 | ||||
-rw-r--r-- | src/pluto/crl.c | 148 | ||||
-rw-r--r-- | src/pluto/crl.h | 5 | ||||
-rw-r--r-- | src/pluto/fetch.c | 211 | ||||
-rw-r--r-- | src/pluto/fetch.h | 19 | ||||
-rw-r--r-- | src/pluto/id.c | 82 | ||||
-rw-r--r-- | src/pluto/id.h | 9 | ||||
-rw-r--r-- | src/pluto/ipsec_doi.c | 30 | ||||
-rw-r--r-- | src/pluto/keys.c | 56 | ||||
-rw-r--r-- | src/pluto/ocsp.c | 151 | ||||
-rw-r--r-- | src/pluto/ocsp.h | 3 | ||||
-rw-r--r-- | src/pluto/pkcs7.c | 78 | ||||
-rw-r--r-- | src/pluto/pkcs7.h | 17 | ||||
-rw-r--r-- | src/pluto/smartcard.c | 121 | ||||
-rw-r--r-- | src/pluto/x509.c | 794 | ||||
-rw-r--r-- | src/pluto/x509.h | 63 |
21 files changed, 979 insertions, 1506 deletions
diff --git a/src/pluto/ac.c b/src/pluto/ac.c index 5594569a4..96cc9b274 100644 --- a/src/pluto/ac.c +++ b/src/pluto/ac.c @@ -669,8 +669,8 @@ x509acert_t* get_x509acert(chunk_t issuer, chunk_t serial) while (ac != NULL) { - if (same_dn(issuer, ac->holderIssuer) - && same_serial(serial, ac->holderSerial)) + if (same_dn(issuer, ac->holderIssuer) && + chunk_equals(serial, ac->holderSerial)) { if (ac!= x509acerts) { @@ -772,8 +772,7 @@ bool verify_x509acert(x509acert_t *ac, bool strict) ) lock_authcert_list("verify_x509acert"); - aacert = get_authcert(ac->issuerName, ac->authKeySerialNumber - , ac->authKeyID, AUTH_AA); + aacert = get_authcert(ac->issuerName, ac->authKeyID, AUTH_AA); unlock_authcert_list("verify_x509acert"); if (aacert == NULL) @@ -786,7 +785,7 @@ bool verify_x509acert(x509acert_t *ac, bool strict) ) if (!x509_check_signature(ac->certificateInfo, ac->signature, ac->algorithm, - aacert)) + aacert->cert)) { plog("attribute certificate signature is invalid"); return FALSE; diff --git a/src/pluto/builder.c b/src/pluto/builder.c index fac393e7e..acaff0d4d 100644 --- a/src/pluto/builder.c +++ b/src/pluto/builder.c @@ -20,6 +20,7 @@ #include <stdio.h> #include <string.h> #include <unistd.h> +#include <time.h> #include <freeswan.h> @@ -79,13 +80,20 @@ static cert_t *builder_load_cert(certificate_type_t type, va_list args) else { x509cert_t *x509cert = malloc_thing(x509cert_t); + *x509cert = empty_x509cert; - if (parse_x509cert(chunk_clone(blob), 0, x509cert)) + x509cert->cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, blob, + BUILD_END); + if (x509cert->cert) { cert_t *cert = malloc_thing(cert_t); + *cert = cert_empty; cert->type = CERT_X509_SIGNATURE; cert->u.x509 = x509cert; + time(&x509cert->installed); return cert; } plog(" error in X.509 certificate"); @@ -158,6 +166,8 @@ static x509crl_t *builder_load_crl(certificate_type_t type, va_list args) { crl = malloc_thing(x509crl_t); *crl = empty_x509crl; + crl->distributionPoints = linked_list_create(); + if (parse_x509crl(chunk_clone(blob), 0, crl)) { return crl; diff --git a/src/pluto/ca.c b/src/pluto/ca.c index 77374b6f8..bc6bfe9ad 100644 --- a/src/pluto/ca.c +++ b/src/pluto/ca.c @@ -20,6 +20,8 @@ #include <time.h> #include <sys/types.h> +#include <utils/identification.h> + #include <freeswan.h> #include "constants.h" @@ -36,20 +38,6 @@ static x509cert_t *x509authcerts = NULL; -const ca_info_t empty_ca_info = { - NULL , /* next */ - NULL , /* name */ - UNDEFINED_TIME, - { NULL, 0 } , /* authName */ - { NULL, 0 } , /* authKeyID */ - { NULL, 0 } , /* authKey SerialNumber */ - NULL , /* ldaphost */ - NULL , /* ldapbase */ - NULL , /* ocspori */ - NULL , /* crluri */ - FALSE /* strictcrlpolicy */ -}; - /* chained list of X.509 certification authority information records */ static ca_info_t *ca_infos = NULL; @@ -57,8 +45,7 @@ static ca_info_t *ca_infos = NULL; /* * Checks if CA a is trusted by CA b */ -bool -trusted_ca(chunk_t a, chunk_t b, int *pathlen) +bool trusted_ca(chunk_t a, chunk_t b, int *pathlen) { bool match = FALSE; @@ -80,28 +67,49 @@ trusted_ca(chunk_t a, chunk_t b, int *pathlen) /* CA a equals CA b -> we have a match */ if (same_dn(a, b)) + { return TRUE; + } /* CA a might be a subordinate CA of b */ lock_authcert_list("trusted_ca"); while ((*pathlen)++ < MAX_CA_PATH_LEN) { - x509cert_t *cacert = get_authcert(a, chunk_empty, chunk_empty, AUTH_CA); + certificate_t *certificate; + identification_t *issuer; + chunk_t issuer_dn; + x509cert_t *cacert; - /* cacert not found or self-signed root cacert-> exit */ - if (cacert == NULL || same_dn(cacert->issuer, a)) + cacert = get_authcert(a, chunk_empty, AUTH_CA); + if (cacert == NULL) + { break; + } + certificate = cacert->cert; + + /* is the certificate self-signed? */ + { + x509_t *x509 = (x509_t*)certificate; + + if (x509->get_flags(x509) & X509_SELF_SIGNED) + { + break; + } + } /* does the issuer of CA a match CA b? */ - match = same_dn(cacert->issuer, b); + issuer = certificate->get_issuer(certificate); + issuer_dn = issuer->get_encoding(issuer); + match = same_dn(issuer_dn, b); /* we have a match and exit the loop */ if (match) + { break; - + } /* go one level up in the CA chain */ - a = cacert->issuer; + a = issuer_dn; } unlock_authcert_list("trusted_ca"); @@ -111,8 +119,8 @@ trusted_ca(chunk_t a, chunk_t b, int *pathlen) /* * does our CA match one of the requested CAs? */ -bool -match_requested_ca(generalName_t *requested_ca, chunk_t our_ca, int *our_pathlen) +bool match_requested_ca(generalName_t *requested_ca, chunk_t our_ca, + int *our_pathlen) { /* if no ca is requested than any ca will match */ if (requested_ca == NULL) @@ -149,8 +157,7 @@ match_requested_ca(generalName_t *requested_ca, chunk_t our_ca, int *our_pathlen /* * free the first authority certificate in the chain */ -static void -free_first_authcert(void) +static void free_first_authcert(void) { x509cert_t *first = x509authcerts; x509authcerts = first->next; @@ -160,8 +167,7 @@ free_first_authcert(void) /* * free all CA certificates */ -void -free_authcerts(void) +void free_authcerts(void) { lock_authcert_list("free_authcerts"); @@ -174,30 +180,58 @@ free_authcerts(void) /* * get a X.509 authority certificate with a given subject or keyid */ -x509cert_t* -get_authcert(chunk_t subject, chunk_t serial, chunk_t keyid, u_char auth_flags) +x509cert_t* get_authcert(chunk_t subject, chunk_t keyid, u_char auth_flags) { - x509cert_t *cert = x509authcerts; - x509cert_t *prev_cert = NULL; + x509cert_t *cert, *prev_cert = NULL; + + /* the authority certificate list is empty */ + if (x509authcerts == NULL) + { + return NULL; + } - while (cert != NULL) + for (cert = x509authcerts; cert != NULL; prev_cert = cert, cert = cert->next) { - if (cert->authority_flags & auth_flags - && ((keyid.ptr != NULL) ? same_keyid(keyid, cert->subjectKeyID) - : (same_dn(subject, cert->subject) - && same_serial(serial, cert->serialNumber)))) + certificate_t *certificate = cert->cert; + identification_t *cert_subject; + chunk_t cert_subject_dn; + + /* skip non-matching types of authority certificates */ + if (!(cert->authority_flags & auth_flags)) + { + continue; + } + + /* compare the keyid with the certificate's subjectKeyIdentifier */ + if (keyid.ptr) { - if (cert != x509authcerts) + x509_t *x509 = (x509_t*)certificate; + chunk_t subjectKeyId; + + subjectKeyId = x509->get_subjectKeyIdentifier(x509); + if (subjectKeyId.ptr && !chunk_equals(keyid, subjectKeyId)) { - /* bring the certificate up front */ - prev_cert->next = cert->next; - cert->next = x509authcerts; - x509authcerts = cert; + continue; } - return cert; } - prev_cert = cert; - cert = cert->next; + + /* compare the subjectDistinguishedNames */ + cert_subject = certificate->get_subject(certificate); + cert_subject_dn = cert_subject->get_encoding(cert_subject); + if (!same_dn(subject, cert_subject_dn)) + { + continue; + } + + /* found the authcert */ + if (cert != x509authcerts) + { + /* bring the certificate up front */ + prev_cert->next = cert->next; + cert->next = x509authcerts; + x509authcerts = cert; + } + return cert; } return NULL; } @@ -205,9 +239,12 @@ get_authcert(chunk_t subject, chunk_t serial, chunk_t keyid, u_char auth_flags) /* * add an authority certificate to the chained list */ -x509cert_t* -add_authcert(x509cert_t *cert, u_char auth_flags) +x509cert_t* add_authcert(x509cert_t *cert, u_char auth_flags) { + certificate_t *certificate = cert->cert; + x509_t *x509 = (x509_t*)certificate; + identification_t *cert_subject = certificate->get_subject(certificate); + chunk_t cert_subject_dn = cert_subject->get_encoding(cert_subject); x509cert_t *old_cert; /* set authority flags */ @@ -215,12 +252,12 @@ add_authcert(x509cert_t *cert, u_char auth_flags) lock_authcert_list("add_authcert"); - old_cert = get_authcert(cert->subject, cert->serialNumber - , cert->subjectKeyID, auth_flags); - + old_cert = get_authcert(cert_subject_dn, + x509->get_subjectKeyIdentifier(x509), + auth_flags); if (old_cert != NULL) { - if (same_x509cert(cert, old_cert)) + if (certificate->equals(certificate, old_cert->cert)) { /* cert is already present, just add additional authority flags */ old_cert->authority_flags |= cert->authority_flags; @@ -256,8 +293,7 @@ add_authcert(x509cert_t *cert, u_char auth_flags) /* * Loads authority certificates */ -void -load_authcerts(const char *type, const char *path, u_char auth_flags) +void load_authcerts(const char *type, const char *path, u_char auth_flags) { struct dirent **filelist; u_char buf[BUF_LEN]; @@ -299,8 +335,7 @@ load_authcerts(const char *type, const char *path, u_char auth_flags) /* * list all X.509 authcerts with given auth flags in a chained list */ -void -list_authcerts(const char *caption, u_char auth_flags, bool utc) +void list_authcerts(const char *caption, u_char auth_flags, bool utc) { lock_authcert_list("list_authcerts"); list_x509cert_chain(caption, x509authcerts, auth_flags, utc); @@ -310,19 +345,43 @@ list_authcerts(const char *caption, u_char auth_flags, bool utc) /* * get a cacert with a given subject or keyid from an alternative list */ -static const x509cert_t* -get_alt_cacert(chunk_t subject, chunk_t serial, chunk_t keyid - , const x509cert_t *cert) +static const x509cert_t* get_alt_cacert(chunk_t subject, chunk_t keyid, + const x509cert_t *cert) { - while (cert != NULL) + if (cert == NULL) + { + return NULL; + } + + for (; cert != NULL; cert = cert->next) { - if ((keyid.ptr != NULL) ? same_keyid(keyid, cert->subjectKeyID) - : (same_dn(subject, cert->subject) - && same_serial(serial, cert->serialNumber))) + certificate_t *certificate = cert->cert; + identification_t *cert_subject; + chunk_t cert_subject_dn; + + /* compare the keyid with the certificate's subjectKeyIdentifier */ + if (keyid.ptr) + { + x509_t *x509 = (x509_t*)certificate; + chunk_t subjectKeyId; + + subjectKeyId = x509->get_subjectKeyIdentifier(x509); + if (subjectKeyId.ptr && !chunk_equals(keyid, subjectKeyId)) + { + continue; + } + } + + /* compare the subjectDistinguishedNames */ + cert_subject = certificate->get_subject(certificate); + cert_subject_dn = cert_subject->get_encoding(cert_subject); + if (!same_dn(subject, cert_subject_dn)) { - return cert; + continue; } - cert = cert->next; + + /* we found the cacert */ + return cert; } return NULL; } @@ -330,8 +389,7 @@ get_alt_cacert(chunk_t subject, chunk_t serial, chunk_t keyid /* establish trust into a candidate authcert by going up the trust chain. * validity and revocation status are not checked. */ -bool -trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chain) +bool trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chain) { int pathlen; @@ -339,25 +397,25 @@ trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chain) for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++) { + certificate_t *certificate = cert->cert; + x509_t *x509 = (x509_t*)certificate; + identification_t *subject = certificate->get_subject(certificate); + identification_t *issuer = certificate->get_issuer(certificate); + chunk_t issuer_dn = issuer->get_encoding(issuer); + chunk_t authKeyID = x509->get_authKeyIdentifier(x509); const x509cert_t *authcert = NULL; - u_char buf[BUF_LEN]; DBG(DBG_CONTROL, - dntoa(buf, BUF_LEN, cert->subject); - DBG_log("subject: '%s'",buf); - dntoa(buf, BUF_LEN, cert->issuer); - DBG_log("issuer: '%s'",buf); - if (cert->authKeyID.ptr != NULL) + DBG_log("subject: '%Y'", subject); + DBG_log("issuer: '%Y'", issuer); + if (authKeyID.ptr != NULL) { - datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':' - , buf, BUF_LEN); - DBG_log("authkey: %s", buf); + DBG_log("authkey: %#B", &authKeyID); } ) /* search in alternative chain first */ - authcert = get_alt_cacert(cert->issuer, cert->authKeySerialNumber - , cert->authKeyID, alt_chain); + authcert = get_alt_cacert(issuer_dn, authKeyID, alt_chain); if (authcert != NULL) { @@ -368,8 +426,7 @@ trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chain) else { /* search in trusted chain */ - authcert = get_authcert(cert->issuer, cert->authKeySerialNumber - , cert->authKeyID, AUTH_CA); + authcert = get_authcert(issuer_dn, authKeyID, AUTH_CA); if (authcert != NULL) { @@ -385,8 +442,7 @@ trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chain) } } - if (!x509_check_signature(cert->tbsCertificate, cert->signature, - cert->algorithm, authcert)) + if (!certificate->issued_by(certificate, authcert->cert)) { plog("certificate signature is invalid"); unlock_authcert_list("trust_authcert_candidate"); @@ -397,7 +453,7 @@ trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chain) ) /* check if cert is a self-signed root ca */ - if (pathlen > 0 && same_dn(cert->issuer, cert->subject)) + if (pathlen > 0 && (x509->get_flags(x509) & X509_SELF_SIGNED)) { DBG(DBG_CONTROL, DBG_log("reached self-signed root ca") @@ -417,16 +473,14 @@ trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chain) /* * get a CA info record with a given authName or authKeyID */ -ca_info_t* -get_ca_info(chunk_t authname, chunk_t serial, chunk_t keyid) +ca_info_t* get_ca_info(chunk_t authname, chunk_t keyid) { ca_info_t *ca= ca_infos; while (ca!= NULL) { if ((keyid.ptr != NULL) ? same_keyid(keyid, ca->authKeyID) - : (same_dn(authname, ca->authName) - && same_serial(serial, ca->authKeySerialNumber))) + : same_dn(authname, ca->authName)) { return ca; } @@ -443,24 +497,23 @@ static void free_ca_info(ca_info_t* ca_info) { if (ca_info == NULL) + { return; - + } + ca_info->crluris->destroy_function(ca_info->crluris, free); free(ca_info->name); free(ca_info->ldaphost); free(ca_info->ldapbase); free(ca_info->ocspuri); free(ca_info->authName.ptr); free(ca_info->authKeyID.ptr); - free(ca_info->authKeySerialNumber.ptr); - free_generalNames(ca_info->crluri, TRUE); free(ca_info); } /* * free all CA certificates */ -void -free_ca_infos(void) +void free_ca_infos(void) { while (ca_infos != NULL) { @@ -474,8 +527,7 @@ free_ca_infos(void) /* * find a CA information record by name and optionally delete it */ -bool -find_ca_info_by_name(const char *name, bool delete) +bool find_ca_info_by_name(const char *name, bool delete) { ca_info_t **ca_p = &ca_infos; ca_info_t *ca = *ca_p; @@ -501,12 +553,23 @@ find_ca_info_by_name(const char *name, bool delete) return FALSE; } +/* + * Create an empty ca_info_t record + */ +ca_info_t* create_ca_info(void) +{ + ca_info_t *ca_info = malloc_thing(ca_info_t); + + memset(ca_info, 0, sizeof(ca_info_t)); + ca_info->crluris = linked_list_create(); + + return ca_info; +} - /* - * adds a CA description to a chained list +/** + * Adds a CA description to a chained list */ -void -add_ca_info(const whack_message_t *msg) +void add_ca_info(const whack_message_t *msg) { smartcard_t *sc = NULL; cert_t cert; @@ -532,13 +595,16 @@ add_ca_info(const whack_message_t *msg) if (valid_cert) { - char buf[BUF_LEN]; x509cert_t *cacert = cert.u.x509; + certificate_t *certificate = cacert->cert; + x509_t *x509 = (x509_t*)certificate; + identification_t *subject = certificate->get_subject(certificate); + chunk_t subject_dn = subject->get_encoding(subject); + chunk_t subjectKeyID = x509->get_subjectKeyIdentifier(x509); ca_info_t *ca = NULL; /* does the authname already exist? */ - ca = get_ca_info(cacert->subject, cacert->serialNumber - , cacert->subjectKeyID); + ca = get_ca_info(subject_dn, subjectKeyID); if (ca != NULL) { @@ -552,30 +618,23 @@ add_ca_info(const whack_message_t *msg) plog("added ca description \"%s\"", msg->name); /* create and initialize new ca_info record */ - ca = malloc_thing(ca_info_t); - *ca = empty_ca_info; + ca = create_ca_info(); /* name */ ca->name = clone_str(msg->name); /* authName */ - ca->authName = chunk_clone(cacert->subject); - dntoa(buf, BUF_LEN, ca->authName); + ca->authName = chunk_clone(subject_dn); DBG(DBG_CONTROL, - DBG_log("authname: '%s'", buf) + DBG_log("authname: '%Y'", subject) ) - /* authSerialNumber */ - ca->authKeySerialNumber = chunk_clone(cacert->serialNumber); - /* authKeyID */ - if (cacert->subjectKeyID.ptr != NULL) + if (subjectKeyID.ptr) { - ca->authKeyID = chunk_clone(cacert->subjectKeyID); - datatot(cacert->subjectKeyID.ptr, cacert->subjectKeyID.len, ':' - , buf, BUF_LEN); + ca->authKeyID = chunk_clone(subjectKeyID); DBG(DBG_CONTROL | DBG_PARSING , - DBG_log("authkey: %s", buf) + DBG_log("authkey: %#B", &subjectKeyID) ) } @@ -594,23 +653,9 @@ add_ca_info(const whack_message_t *msg) plog(" ignoring ocspuri with unkown protocol"); } - /* crluri2*/ - if (msg->crluri2 != NULL) - { - generalName_t gn = - { NULL, GN_URI, {msg->crluri2, strlen(msg->crluri2)} }; - - add_distribution_points(&gn, &ca->crluri); - } - - /* crluri */ - if (msg->crluri != NULL) - { - generalName_t gn = - { NULL, GN_URI, {msg->crluri, strlen(msg->crluri)} }; - - add_distribution_points(&gn, &ca->crluri); - } + /* add crl uris */ + add_distribution_point(ca->crluris, msg->crluri); + add_distribution_point(ca->crluris, msg->crluri2); /* strictrlpolicy */ ca->strictcrlpolicy = msg->whack_strict; @@ -625,11 +670,12 @@ add_ca_info(const whack_message_t *msg) unlock_ca_info_list("add_ca_info"); /* add cacert to list of authcerts */ + cacert = add_authcert(cacert, AUTH_CA); if (!cached_cert && sc != NULL) { if (sc->last_cert.type == CERT_X509_SIGNATURE) sc->last_cert.u.x509->count--; - sc->last_cert.u.x509 = add_authcert(cacert, AUTH_CA); + sc->last_cert.u.x509 = cacert; share_cert(sc->last_cert); } if (sc != NULL) @@ -640,8 +686,7 @@ add_ca_info(const whack_message_t *msg) /* * list all ca_info records in the chained list */ -void -list_ca_infos(bool utc) +void list_ca_infos(bool utc) { ca_info_t *ca = ca_infos; @@ -672,7 +717,7 @@ list_ca_infos(bool utc) if (ca->ocspuri != NULL) whack_log(RC_COMMENT, " ocspuri: '%s'", ca->ocspuri); - list_distribution_points(ca->crluri); + list_distribution_points(ca->crluris); if (ca->authKeyID.ptr != NULL) { @@ -680,12 +725,6 @@ list_ca_infos(bool utc) , buf, BUF_LEN); whack_log(RC_COMMENT, " authkey: %s", buf); } - if (ca->authKeySerialNumber.ptr != NULL) - { - datatot(ca->authKeySerialNumber.ptr, ca->authKeySerialNumber.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " aserial: %s", buf); - } ca = ca->next; } } diff --git a/src/pluto/ca.h b/src/pluto/ca.h index 44d079b4c..eadb96dba 100644 --- a/src/pluto/ca.h +++ b/src/pluto/ca.h @@ -15,6 +15,8 @@ #ifndef _CA_H #define _CA_H +#include <utils/linked_list.h> + #include "x509.h" #include "whack.h" @@ -37,19 +39,18 @@ struct ca_info { time_t installed; chunk_t authName; chunk_t authKeyID; - chunk_t authKeySerialNumber; char *ldaphost; char *ldapbase; char *ocspuri; - generalName_t *crluri; + linked_list_t *crluris; bool strictcrlpolicy; }; extern bool trusted_ca(chunk_t a, chunk_t b, int *pathlen); extern bool match_requested_ca(generalName_t *requested_ca , chunk_t our_ca, int *our_pathlen); -extern x509cert_t* get_authcert(chunk_t subject, chunk_t serial, chunk_t keyid - , u_char auth_flags); +extern x509cert_t* get_authcert(chunk_t subject, chunk_t keyid, + u_char auth_flags); extern void load_authcerts(const char *type, const char *path , u_char auth_flags); extern x509cert_t* add_authcert(x509cert_t *cert, u_char auth_flags); @@ -57,7 +58,7 @@ extern void free_authcerts(void); extern void list_authcerts(const char *caption, u_char auth_flags, bool utc); extern bool trust_authcert_candidate(const x509cert_t *cert , const x509cert_t *alt_chain); -extern ca_info_t* get_ca_info(chunk_t name, chunk_t serial, chunk_t keyid); +extern ca_info_t* get_ca_info(chunk_t name, chunk_t keyid); extern bool find_ca_info_by_name(const char *name, bool delete); extern void add_ca_info(const whack_message_t *msg); extern void delete_ca_info(const char *name); diff --git a/src/pluto/certs.c b/src/pluto/certs.c index 5c6aa568e..cdf567e90 100644 --- a/src/pluto/certs.c +++ b/src/pluto/certs.c @@ -46,9 +46,9 @@ chunk_t cert_get_encoding(cert_t cert) switch (cert.type) { case CERT_PGP: - return cert.u.pgp->certificate; + return chunk_clone(cert.u.pgp->certificate); case CERT_X509_SIGNATURE: - return cert.u.x509->certificate; + return cert.u.x509->cert->get_encoding(cert.u.x509->cert); default: return chunk_empty; } @@ -59,11 +59,17 @@ public_key_t* cert_get_public_key(const cert_t cert) switch (cert.type) { case CERT_PGP: - return cert.u.pgp->public_key; - break; + { + public_key_t *public_key = cert.u.pgp->public_key; + + return public_key->get_ref(public_key); + } case CERT_X509_SIGNATURE: - return cert.u.x509->public_key; - break; + { + certificate_t *certificate = cert.u.x509->cert; + + return certificate->get_public_key(certificate); + } default: return NULL; } diff --git a/src/pluto/connections.c b/src/pluto/connections.c index 1eb2d332d..5cd74d7d9 100644 --- a/src/pluto/connections.c +++ b/src/pluto/connections.c @@ -92,17 +92,17 @@ static struct host_pair *host_pairs = NULL; static struct connection *unoriented_connections = NULL; /* check to see that Ids of peers match */ -bool -same_peer_ids(const struct connection *c, const struct connection *d -, const struct id *his_id) +bool same_peer_ids(const struct connection *c, const struct connection *d, + const struct id *his_id) { return same_id(&c->spd.this.id, &d->spd.this.id) && same_id(his_id == NULL? &c->spd.that.id : his_id, &d->spd.that.id); } -static struct host_pair * -find_host_pair(const ip_address *myaddr, u_int16_t myport -, const ip_address *hisaddr, u_int16_t hisport) +static struct host_pair *find_host_pair(const ip_address *myaddr, + u_int16_t myport, + const ip_address *hisaddr, + u_int16_t hisport) { struct host_pair *p, *prev; @@ -138,9 +138,10 @@ find_host_pair(const ip_address *myaddr, u_int16_t myport } /* find head of list of connections with this pair of hosts */ -static struct connection * -find_host_pair_connections(const ip_address *myaddr, u_int16_t myport -, const ip_address *hisaddr, u_int16_t hisport) +static struct connection *find_host_pair_connections(const ip_address *myaddr, + u_int16_t myport, + const ip_address *hisaddr, + u_int16_t hisport) { struct host_pair *hp = find_host_pair(myaddr, myport, hisaddr, hisport); @@ -158,8 +159,7 @@ find_host_pair_connections(const ip_address *myaddr, u_int16_t myport return hp == NULL? NULL : hp->connections; } -static void -connect_to_host_pair(struct connection *c) +static void connect_to_host_pair(struct connection *c) { if (oriented(*c)) { @@ -206,8 +206,7 @@ connect_to_host_pair(struct connection *c) * Move the winner (if any) to the front. * If none is found, and strict, a diagnostic is logged to whack. */ -struct connection * -con_by_name(const char *nm, bool strict) +struct connection *con_by_name(const char *nm, bool strict) { struct connection *p, *prev; @@ -235,8 +234,7 @@ con_by_name(const char *nm, bool strict) return p; } -void -release_connection(struct connection *c, bool relations) +void release_connection(struct connection *c, bool relations) { if (c->kind == CK_INSTANCE) { @@ -264,8 +262,7 @@ release_connection(struct connection *c, bool relations) } -void -delete_connection(struct connection *c, bool relations) +void delete_connection(struct connection *c, bool relations) { struct connection *old_cur_connection = cur_connection == c? NULL : cur_connection; @@ -361,8 +358,7 @@ delete_connection(struct connection *c, bool relations) } /* Delete connections with the specified name */ -void -delete_connections_by_name(const char *name, bool strict) +void delete_connections_by_name(const char *name, bool strict) { struct connection *c = con_by_name(name, strict); @@ -370,15 +366,13 @@ delete_connections_by_name(const char *name, bool strict) delete_connection(c, FALSE); } -void -delete_every_connection(void) +void delete_every_connection(void) { while (connections != NULL) delete_connection(connections, TRUE); } -void -release_dead_interfaces(void) +void release_dead_interfaces(void) { struct host_pair *hp; @@ -427,8 +421,7 @@ release_dead_interfaces(void) } /* adjust orientations of connections to reflect newly added interfaces */ -void -check_orientations(void) +void check_orientations(void) { /* try to orient all the unoriented connections */ { @@ -491,8 +484,7 @@ check_orientations(void) } } -static err_t -default_end(struct end *e, ip_address *dflt_nexthop) +static err_t default_end(struct end *e, ip_address *dflt_nexthop) { err_t ugh = NULL; const struct af_info *afi = aftoinfo(addrtypeof(&e->host_addr)); @@ -527,13 +519,8 @@ default_end(struct end *e, ip_address *dflt_nexthop) * Note: if that==NULL, skip nexthop * Returns strlen of formated result (length excludes NUL at end). */ -size_t -format_end(char *buf -, size_t buf_len -, const struct end *this -, const struct end *that -, bool is_left -, lset_t policy) +size_t format_end(char *buf, size_t buf_len, const struct end *this, + const struct end *that, bool is_left, lset_t policy) { char client[SUBNETTOT_BUF]; const char *client_sep = ""; @@ -668,10 +655,9 @@ format_end(char *buf */ #define CONNECTION_BUF (2 * (END_BUF - 1) + 4) -static size_t -format_connection(char *buf, size_t buf_len - , const struct connection *c - , struct spd_route *sr) +static size_t format_connection(char *buf, size_t buf_len, + const struct connection *c, + struct spd_route *sr) { size_t w = format_end(buf, buf_len, &sr->this, &sr->that, TRUE, LEMPTY); @@ -679,8 +665,7 @@ format_connection(char *buf, size_t buf_len return w + format_end(buf + w, buf_len - w, &sr->that, &sr->this, FALSE, c->policy); } -static void -unshare_connection_strings(struct connection *c) +static void unshare_connection_strings(struct connection *c) { c->name = clone_str(c->name); @@ -755,8 +740,9 @@ static void load_end_certificate(char *filename, struct end *dst) dst->cert = cert; else { + time_t valid_until = 0; + /* check validity of cert */ - valid_until = cert.u.x509->notAfter; ugh = check_validity(cert.u.x509, &valid_until); if (ugh != NULL) { @@ -772,9 +758,15 @@ static void load_end_certificate(char *filename, struct end *dst) dst->cert.type = cert.type; dst->cert.u.x509 = add_x509cert(cert.u.x509); } + /* if no CA is defined, use issuer as default */ if (dst->ca.ptr == NULL) - dst->ca = dst->cert.u.x509->issuer; + { + certificate_t *certificate = dst->cert.u.x509->cert; + identification_t *issuer = certificate->get_issuer(certificate); + + dst->ca = issuer->get_encoding(issuer); + } break; default: break; @@ -796,8 +788,8 @@ static void load_end_certificate(char *filename, struct end *dst) } } -static bool -extract_end(struct end *dst, const whack_end_t *src, const char *which) +static bool extract_end(struct end *dst, const whack_end_t *src, + const char *which) { bool same_ca = FALSE; @@ -884,9 +876,9 @@ extract_end(struct end *dst, const whack_end_t *src, const char *which) return same_ca; } -static bool -check_connection_end(const whack_end_t *this, const whack_end_t *that -, const whack_message_t *wm) +static bool check_connection_end(const whack_end_t *this, + const whack_end_t *that, + const whack_message_t *wm) { if (wm->addr_family != addrtypeof(&this->host_addr) || wm->addr_family != addrtypeof(&this->host_nexthop) @@ -921,8 +913,7 @@ check_connection_end(const whack_end_t *this, const whack_end_t *that return TRUE; /* happy */ } -struct connection * -find_connection_by_reqid(uint32_t reqid) +struct connection *find_connection_by_reqid(uint32_t reqid) { struct connection *c; @@ -936,8 +927,7 @@ find_connection_by_reqid(uint32_t reqid) return NULL; } -static uint32_t -gen_reqid(void) +static uint32_t gen_reqid(void) { uint32_t start; static uint32_t reqid = IPSEC_MANUAL_REQID_MAX & ~3; @@ -955,8 +945,7 @@ gen_reqid(void) return 0; /* never reached ... */ } -void -add_connection(const whack_message_t *wm) +void add_connection(const whack_message_t *wm) { if (con_by_name(wm->name, FALSE) != NULL) { @@ -1172,8 +1161,7 @@ add_connection(const whack_message_t *wm) * Returns name of new connection. May be NULL. * Caller is responsible for freeing. */ -char * -add_group_instance(struct connection *group, const ip_subnet *target) +char *add_group_instance(struct connection *group, const ip_subnet *target) { char namebuf[100] , targetbuf[SUBNETTOT_BUF]; @@ -1234,9 +1222,8 @@ add_group_instance(struct connection *group, const ip_subnet *target) } /* an old target has disappeared for a group: delete instance */ -void -remove_group_instance(const struct connection *group USED_BY_DEBUG -, const char *name) +void remove_group_instance(const struct connection *group USED_BY_DEBUG, + const char *name) { passert(group->kind == CK_GROUP); passert(oriented(*group)); @@ -1254,10 +1241,9 @@ remove_group_instance(const struct connection *group USED_BY_DEBUG * * Note that instantiate can only deal with a single SPD/eroute. */ -static struct connection * -instantiate(struct connection *c, const ip_address *him -, u_int16_t his_port -, const struct id *his_id) +static struct connection *instantiate(struct connection *c, + const ip_address *him, u_int16_t his_port, + const struct id *his_id) { struct connection *d; int wildcards; @@ -1318,9 +1304,9 @@ instantiate(struct connection *c, const ip_address *him } } -struct connection * -rw_instantiate(struct connection *c, const ip_address *him, u_int16_t his_port -, const ip_subnet *his_net, const struct id *his_id) +struct connection *rw_instantiate(struct connection *c, const ip_address *him, + u_int16_t his_port, const ip_subnet *his_net, + const struct id *his_id) { struct connection *d = instantiate(c, him, his_port, his_id); @@ -1345,13 +1331,10 @@ rw_instantiate(struct connection *c, const ip_address *him, u_int16_t his_port return d; } -struct connection * -oppo_instantiate(struct connection *c -, const ip_address *him -, const struct id *his_id -, struct gw_info *gw -, const ip_address *our_client USED_BY_DEBUG -, const ip_address *peer_client) +struct connection *oppo_instantiate(struct connection *c, const ip_address *him, + const struct id *his_id, struct gw_info *gw, + const ip_address *our_client USED_BY_DEBUG, + const ip_address *peer_client) { struct connection *d = instantiate(c, him, 0, his_id); @@ -1416,8 +1399,7 @@ oppo_instantiate(struct connection *c } /* priority formatting */ -void -fmt_policy_prio(policy_prio_t pp, char buf[POLICY_PRIO_BUF]) +void fmt_policy_prio(policy_prio_t pp, char buf[POLICY_PRIO_BUF]) { if (pp == BOTTOM_PRIO) snprintf(buf, POLICY_PRIO_BUF, "0"); @@ -1431,8 +1413,8 @@ fmt_policy_prio(policy_prio_t pp, char buf[POLICY_PRIO_BUF]) * Road Warrior: peer's IP address * Opportunistic: [" " myclient "==="] " ..." peer ["===" hisclient] '\0' */ -static size_t -fmt_client(const ip_subnet *client, const ip_address *gw, const char *prefix, char buf[ADDRTOT_BUF]) +static size_t fmt_client(const ip_subnet *client, const ip_address *gw, + const char *prefix, char buf[ADDRTOT_BUF]) { if (subnetisaddr(client, gw)) { @@ -1452,8 +1434,7 @@ fmt_client(const ip_subnet *client, const ip_address *gw, const char *prefix, ch return strlen(buf); } -void -fmt_conn_instance(const struct connection *c, char buf[CONN_INST_BUF]) +void fmt_conn_instance(const struct connection *c, char buf[CONN_INST_BUF]) { char *p = buf; @@ -1510,11 +1491,10 @@ fmt_conn_instance(const struct connection *c, char buf[CONN_INST_BUF]) * * See also build_outgoing_opportunistic_connection. */ -struct connection * -find_connection_for_clients(struct spd_route **srp, - const ip_address *our_client, - const ip_address *peer_client, - int transport_proto) +struct connection *find_connection_for_clients(struct spd_route **srp, + const ip_address *our_client, + const ip_address *peer_client, + int transport_proto) { struct connection *c = connections, *best = NULL; policy_prio_t best_prio = BOTTOM_PRIO; @@ -1654,10 +1634,9 @@ find_connection_for_clients(struct spd_route **srp, * find_connection_for_clients. In this case, we know the gateways * that we need to instantiate an opportunistic connection. */ -struct connection * -build_outgoing_opportunistic_connection(struct gw_info *gw - ,const ip_address *our_client - ,const ip_address *peer_client) +struct connection *build_outgoing_opportunistic_connection(struct gw_info *gw, + const ip_address *our_client, + const ip_address *peer_client) { struct iface *p; struct connection *best = NULL; @@ -1733,8 +1712,7 @@ build_outgoing_opportunistic_connection(struct gw_info *gw , our_client, peer_client); } -bool -orient(struct connection *c) +bool orient(struct connection *c) { struct spd_route *sr; @@ -1796,8 +1774,7 @@ orient(struct connection *c) return oriented(*c); } -void -initiate_connection(const char *name, int whackfd) +void initiate_connection(const char *name, int whackfd) { struct connection *c = con_by_name(name, TRUE); @@ -1928,10 +1905,8 @@ struct find_oppo_continuation { struct find_oppo_bundle b; }; -static void -cannot_oppo(struct connection *c - , struct find_oppo_bundle *b - , err_t ugh) +static void cannot_oppo(struct connection *c, struct find_oppo_bundle *b, + err_t ugh) { char pcb[ADDRTOT_BUF]; char ocb[ADDRTOT_BUF]; @@ -2048,12 +2023,9 @@ cannot_oppo(struct connection *c static void initiate_opportunistic_body(struct find_oppo_bundle *b , struct adns_continuation *ac, err_t ac_ugh); /* forward */ -void -initiate_opportunistic(const ip_address *our_client -, const ip_address *peer_client -, int transport_proto -, bool held -, int whackfd) +void initiate_opportunistic(const ip_address *our_client, + const ip_address *peer_client, int transport_proto, + bool held, int whackfd) { struct find_oppo_bundle b; @@ -2070,8 +2042,7 @@ initiate_opportunistic(const ip_address *our_client initiate_opportunistic_body(&b, NULL, NULL); } -static void -continue_oppo(struct adns_continuation *acr, err_t ugh) +static void continue_oppo(struct adns_continuation *acr, err_t ugh) { struct find_oppo_continuation *cr = (void *)acr; /* inherit, damn you! */ struct connection *c; @@ -2145,10 +2116,9 @@ continue_oppo(struct adns_continuation *acr, err_t ugh) } #ifdef USE_KEYRR -static err_t -check_key_recs(enum myid_state try_state -, const struct connection *c -, struct adns_continuation *ac) +static err_t check_key_recs(enum myid_state try_state, + const struct connection *c, + struct adns_continuation *ac) { /* Check if KEY lookup yielded good results. * Looking up based on our ID. Used if @@ -2260,10 +2230,9 @@ static err_t check_txt_recs(enum myid_state try_state, /* note: gateways_from_dns must be NULL iff this is the first call */ -static void -initiate_opportunistic_body(struct find_oppo_bundle *b -, struct adns_continuation *ac -, err_t ac_ugh) +static void initiate_opportunistic_body(struct find_oppo_bundle *b, + struct adns_continuation *ac, + err_t ac_ugh) { struct connection *c; struct spd_route *sr; @@ -2964,8 +2933,7 @@ initiate_opportunistic_body(struct find_oppo_bundle *b close_any(b->whackfd); } -void -terminate_connection(const char *nm) +void terminate_connection(const char *nm) { /* Loop because more than one may match (master and instances) * But at least one is required (enforced by con_by_name). @@ -3002,8 +2970,7 @@ terminate_connection(const char *nm) */ bool uniqueIDs = FALSE; /* --uniqueids? */ -void -ISAKMP_SA_established(struct connection *c, so_serial_t serial) +void ISAKMP_SA_established(struct connection *c, so_serial_t serial) { c->newest_isakmp_sa = serial; @@ -3047,11 +3014,8 @@ ISAKMP_SA_established(struct connection *c, so_serial_t serial) * The return value is used to find other connections sharing a route. * *erop is used to find other connections sharing an eroute. */ -struct connection * -route_owner(struct connection *c - , struct spd_route **srp - , struct connection **erop - , struct spd_route **esrp) +struct connection *route_owner(struct connection *c, struct spd_route **srp, + struct connection **erop, struct spd_route **esrp) { struct connection *d , *best_ro = c @@ -3157,8 +3121,7 @@ route_owner(struct connection *c * There ought to be only one. * This might get to be a bottleneck -- try hashing if it does. */ -struct connection * -shunt_owner(const ip_subnet *ours, const ip_subnet *his) +struct connection *shunt_owner(const ip_subnet *ours, const ip_subnet *his) { struct connection *c; struct spd_route *sr; @@ -3180,9 +3143,9 @@ shunt_owner(const ip_subnet *ours, const ip_subnet *his) * We don't know enough to chose amongst those available. * ??? no longer usefully different from find_host_pair_connections */ -struct connection * -find_host_connection(const ip_address *me, u_int16_t my_port -, const ip_address *him, u_int16_t his_port, lset_t policy) +struct connection *find_host_connection(const ip_address *me, u_int16_t my_port, + const ip_address *him, u_int16_t his_port, + lset_t policy) { struct connection *c = find_host_pair_connections(me, my_port, him, his_port); @@ -3266,9 +3229,9 @@ find_host_connection(const ip_address *me, u_int16_t my_port */ #define PRIO_NO_MATCH_FOUND 2048 -struct connection * -refine_host_connection(const struct state *st, const struct id *peer_id -, chunk_t peer_ca) +struct connection *refine_host_connection(const struct state *st, + const struct id *peer_id, + chunk_t peer_ca) { struct connection *c = st->st_connection; struct connection *d; @@ -3456,8 +3419,8 @@ refine_host_connection(const struct state *st, const struct id *peer_id * With virtual addressing, we must not allow someone to use an already * used (by another id) addr/net. */ -static bool -is_virtual_net_used(const ip_subnet *peer_net, const struct id *peer_id) +static bool is_virtual_net_used(const ip_subnet *peer_net, + const struct id *peer_id) { struct connection *d; @@ -3520,18 +3483,17 @@ is_virtual_net_used(const ip_subnet *peer_net, const struct id *peer_id) #define PRIO_WEIGHT (MAX_WILDCARDS+1)*WILD_WEIGHT /* fc_try: a helper function for find_client_connection */ -static struct connection * -fc_try(const struct connection *c -, struct host_pair *hp -, const struct id *peer_id -, const ip_subnet *our_net -, const ip_subnet *peer_net -, const u_int8_t our_protocol -, const u_int16_t our_port -, const u_int8_t peer_protocol -, const u_int16_t peer_port -, chunk_t peer_ca -, const ietfAttrList_t *peer_list) +static struct connection *fc_try(const struct connection *c, + struct host_pair *hp, + const struct id *peer_id, + const ip_subnet *our_net, + const ip_subnet *peer_net, + const u_int8_t our_protocol, + const u_int16_t our_port, + const u_int8_t peer_protocol, + const u_int16_t peer_port, + chunk_t peer_ca, + const ietfAttrList_t *peer_list) { struct connection *d; struct connection *best = NULL; @@ -3650,17 +3612,16 @@ fc_try(const struct connection *c return best; } -static struct connection * -fc_try_oppo(const struct connection *c -, struct host_pair *hp -, const ip_subnet *our_net -, const ip_subnet *peer_net -, const u_int8_t our_protocol -, const u_int16_t our_port -, const u_int8_t peer_protocol -, const u_int16_t peer_port -, chunk_t peer_ca -, const ietfAttrList_t *peer_list) +static struct connection *fc_try_oppo(const struct connection *c, + struct host_pair *hp, + const ip_subnet *our_net, + const ip_subnet *peer_net, + const u_int8_t our_protocol, + const u_int16_t our_port, + const u_int8_t peer_protocol, + const u_int16_t peer_port, + chunk_t peer_ca, + const ietfAttrList_t *peer_list) { struct connection *d; struct connection *best = NULL; @@ -3754,8 +3715,8 @@ fc_try_oppo(const struct connection *c /* * get the peer's CA and group attributes */ -chunk_t -get_peer_ca_and_groups(struct connection *c, const ietfAttrList_t **peer_list) +chunk_t get_peer_ca_and_groups(struct connection *c, + const ietfAttrList_t **peer_list) { struct state *p1st = find_phase1_state(c, ISAKMP_SA_ESTABLISHED_STATES); @@ -3781,11 +3742,13 @@ get_peer_ca_and_groups(struct connection *c, const ietfAttrList_t **peer_list) return chunk_empty; } -struct connection * -find_client_connection(struct connection *c -, const ip_subnet *our_net, const ip_subnet *peer_net -, const u_int8_t our_protocol, const u_int16_t our_port -, const u_int8_t peer_protocol, const u_int16_t peer_port) +struct connection *find_client_connection(struct connection *c, + const ip_subnet *our_net, + const ip_subnet *peer_net, + const u_int8_t our_protocol, + const u_int16_t our_port, + const u_int8_t peer_protocol, + const u_int16_t peer_port) { struct connection *d; struct spd_route *sr; @@ -3919,9 +3882,7 @@ find_client_connection(struct connection *c return d; } -int -connection_compare(const struct connection *ca -, const struct connection *cb) +int connection_compare(const struct connection *ca, const struct connection *cb) { int ret; @@ -3950,15 +3911,13 @@ connection_compare(const struct connection *ca } } -static int -connection_compare_qsort(const void *a, const void *b) +static int connection_compare_qsort(const void *a, const void *b) { return connection_compare(*(const struct connection *const *)a , *(const struct connection *const *)b); } -void -show_connections_status(bool all, const char *name) +void show_connections_status(bool all, const char *name) { struct connection *c; int count, i; @@ -4125,13 +4084,8 @@ struct pending { }; /* queue a Quick Mode negotiation pending completion of a suitable Main Mode */ -void -add_pending(int whack_sock -, struct state *isakmp_sa -, struct connection *c -, lset_t policy -, unsigned long try -, so_serial_t replacing) +void add_pending(int whack_sock, struct state *isakmp_sa, struct connection *c, + lset_t policy, unsigned long try, so_serial_t replacing) { bool already_queued = FALSE; struct pending *p = c->host_pair->pending; @@ -4169,8 +4123,7 @@ add_pending(int whack_sock * This is accomplished by closing all the whack socket file descriptors. * We go to a lot of trouble to tell each whack, but to not tell it twice. */ -void -release_pending_whacks(struct state *st, err_t story) +void release_pending_whacks(struct state *st, err_t story) { struct pending *p; struct stat stst; @@ -4202,8 +4155,7 @@ release_pending_whacks(struct state *st, err_t story) } } -static void -delete_pending(struct pending **pp) +static void delete_pending(struct pending **pp) { struct pending *p = *pp; @@ -4214,8 +4166,7 @@ delete_pending(struct pending **pp) free(p); } -void -unpend(struct state *st) +void unpend(struct state *st) { struct pending **pp , *p; @@ -4241,8 +4192,7 @@ unpend(struct state *st) } /* a Main Mode negotiation has been replaced; update any pending */ -void -update_pending(struct state *os, struct state *ns) +void update_pending(struct state *os, struct state *ns) { struct pending *p; @@ -4259,8 +4209,7 @@ update_pending(struct state *os, struct state *ns) } /* a Main Mode negotiation has failed; discard any pending */ -void -flush_pending_by_state(struct state *st) +void flush_pending_by_state(struct state *st) { struct host_pair *hp = st->st_connection->host_pair; @@ -4280,8 +4229,7 @@ flush_pending_by_state(struct state *st) } /* a connection has been deleted; discard any related pending */ -static void -flush_pending_by_connection(struct connection *c) +static void flush_pending_by_connection(struct connection *c) { if (c->host_pair != NULL) { @@ -4303,8 +4251,7 @@ flush_pending_by_connection(struct connection *c) } } -void -show_pending_phase2(const struct host_pair *hp, const struct state *st) +void show_pending_phase2(const struct host_pair *hp, const struct state *st) { const struct pending *p; @@ -4329,8 +4276,7 @@ show_pending_phase2(const struct host_pair *hp, const struct state *st) * We must be careful to avoid circularity: * we don't touch it if it is CK_GOING_AWAY. */ -void -connection_discard(struct connection *c) +void connection_discard(struct connection *c) { if (c->kind == CK_INSTANCE) { @@ -4354,8 +4300,7 @@ connection_discard(struct connection *c) long eclipse_count = 0; -struct connection * -eclipsed(struct connection *c, struct spd_route **esrp) +struct connection *eclipsed(struct connection *c, struct spd_route **esrp) { struct connection *ue; struct spd_route *sr1 = &c->spd; diff --git a/src/pluto/crl.c b/src/pluto/crl.c index 52f46e701..291ceb3c2 100644 --- a/src/pluto/crl.c +++ b/src/pluto/crl.c @@ -133,7 +133,7 @@ const x509crl_t empty_x509crl = { /** * Get the X.509 CRL with a given issuer */ -static x509crl_t* get_x509crl(chunk_t issuer, chunk_t serial, chunk_t keyid) +static x509crl_t* get_x509crl(chunk_t issuer, chunk_t keyid) { x509crl_t *crl = x509crls; x509crl_t *prev_crl = NULL; @@ -142,7 +142,7 @@ static x509crl_t* get_x509crl(chunk_t issuer, chunk_t serial, chunk_t keyid) { if ((keyid.ptr != NULL && crl->authKeyID.ptr != NULL) ? same_keyid(keyid, crl->authKeyID) - : (same_dn(crl->issuer, issuer) && same_serial(serial, crl->authKeySerialNumber))) + : (same_dn(crl->issuer, issuer))) { if (crl != x509crls) { @@ -177,8 +177,8 @@ static void free_revoked_certs(revokedCert_t* revokedCerts) */ void free_crl(x509crl_t *crl) { + crl->distributionPoints->destroy_function(crl->distributionPoints, free); free_revoked_certs(crl->revokedCertificates); - free_generalNames(crl->distributionPoints, TRUE); free(crl->certificateList.ptr); free(crl); } @@ -204,24 +204,19 @@ void free_crls(void) /** * Insert X.509 CRL into chained list */ -bool insert_crl(x509crl_t *crl, chunk_t crl_uri, bool cache_crl) +bool insert_crl(x509crl_t *crl, char *crl_uri, bool cache_crl) { x509cert_t *issuer_cert; x509crl_t *oldcrl; bool valid_sig; - generalName_t *gn; /* add distribution point */ - gn = malloc_thing(generalName_t); - gn->kind = GN_URI; - gn->name = crl_uri; - gn->next = crl->distributionPoints; - crl->distributionPoints = gn; + add_distribution_point(crl->distributionPoints, crl_uri); lock_authcert_list("insert_crl"); + /* get the issuer cacert */ - issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber, - crl->authKeyID, AUTH_CA); + issuer_cert = get_authcert(crl->issuer, crl->authKeyID, AUTH_CA); if (issuer_cert == NULL) { plog("crl issuer cacert not found"); @@ -235,7 +230,7 @@ bool insert_crl(x509crl_t *crl, chunk_t crl_uri, bool cache_crl) /* check the issuer's signature of the crl */ valid_sig = x509_check_signature(crl->tbsCertList, crl->signature, - crl->algorithm, issuer_cert); + crl->algorithm, issuer_cert->cert); unlock_authcert_list("insert_crl"); if (!valid_sig) @@ -248,16 +243,15 @@ bool insert_crl(x509crl_t *crl, chunk_t crl_uri, bool cache_crl) ) lock_crl_list("insert_crl"); - oldcrl = get_x509crl(crl->issuer, crl->authKeySerialNumber - , crl->authKeyID); + oldcrl = get_x509crl(crl->issuer, crl->authKeyID); if (oldcrl != NULL) { if (crl->thisUpdate > oldcrl->thisUpdate) { /* keep any known CRL distribution points */ - add_distribution_points(oldcrl->distributionPoints - , &crl->distributionPoints); + add_distribution_points(crl->distributionPoints, + oldcrl->distributionPoints); /* now delete the old CRL */ free_first_crl(); @@ -286,23 +280,15 @@ bool insert_crl(x509crl_t *crl, chunk_t crl_uri, bool cache_crl) * Only http or ldap URIs are cached but not local file URIs. * The issuer's subjectKeyID is used as a unique filename */ - if (cache_crl && strncasecmp(crl_uri.ptr, "file", 4) != 0) + if (cache_crl && strncasecmp(crl_uri, "file", 4) != 0) { char path[BUF_LEN], buf[BUF_LEN]; - char digest_buf[HASH_SIZE_SHA1]; - chunk_t subjectKeyID = chunk_create(digest_buf, sizeof(digest_buf)); - bool has_keyID; + certificate_t *certificate = issuer_cert->cert; + x509_t *x509 = (x509_t*)certificate; + chunk_t subjectKeyID; - if (issuer_cert->subjectKeyID.ptr == NULL) - { - has_keyID = compute_subjectKeyID(issuer_cert, subjectKeyID); - } - else - { - subjectKeyID = issuer_cert->subjectKeyID; - has_keyID = TRUE; - } - if (has_keyID) + subjectKeyID = x509->get_subjectKeyIdentifier(x509); + if (subjectKeyID.ptr) { datatot(subjectKeyID.ptr, subjectKeyID.len, 16, buf, BUF_LEN); snprintf(path, BUF_LEN, "%s/%s.crl", CRL_PATH, buf); @@ -348,16 +334,10 @@ void load_crls(void) CERT_PLUTO_CRL, BUILD_FROM_FILE, filename, BUILD_END); if (crl) { - chunk_t crl_uri; + char crl_uri[BUF_LEN]; plog(" loaded crl from '%s'", filename); - crl_uri.len = 7 + sizeof(CRL_PATH) + strlen(filename); - crl_uri.ptr = malloc(crl_uri.len + 1); - - /* build CRL file URI */ - snprintf(crl_uri.ptr, crl_uri.len + 1, "file://%s/%s" - , CRL_PATH, filename); - + snprintf(crl_uri, BUF_LEN, "file://%s/%s", CRL_PATH, filename); insert_crl(crl, crl_uri, FALSE); } free(filelist[n]); @@ -543,8 +523,7 @@ check_revocation(const x509crl_t *crl, chunk_t serial /* * check if any crls are about to expire */ -void -check_crls(void) +void check_crls(void) { x509crl_t *crl; @@ -569,9 +548,9 @@ check_crls(void) ) if (time_left < 2*crl_check_interval) { - fetch_req_t *req = build_crl_fetch_request(crl->issuer - , crl->authKeySerialNumber - , crl->authKeyID, crl->distributionPoints); + fetch_req_t *req = build_crl_fetch_request(crl->issuer, + crl->authKeyID, + crl->distributionPoints); add_crl_fetch_request(req); } crl = crl->next; @@ -582,51 +561,63 @@ check_crls(void) /* * verify if a cert hasn't been revoked by a crl */ -cert_status_t -verify_by_crl(const x509cert_t *cert, time_t *until, time_t *revocationDate -, crl_reason_t *revocationReason) +cert_status_t verify_by_crl(const x509cert_t *cert, time_t *until, + time_t *revocationDate, + crl_reason_t *revocationReason) { + certificate_t *certificate = cert->cert; + x509_t *x509 = (x509_t*)certificate; + identification_t *issuer = certificate->get_issuer(certificate); + chunk_t issuer_dn = issuer->get_encoding(issuer); + chunk_t authKeyID = x509->get_authKeyIdentifier(x509); x509crl_t *crl; + ca_info_t *ca; + enumerator_t *enumerator; + char *point; - ca_info_t *ca = get_ca_info(cert->issuer, cert->authKeySerialNumber - , cert->authKeyID); - - generalName_t *crluri = (ca == NULL)? NULL : ca->crluri; - + ca = get_ca_info(issuer_dn, authKeyID); + *revocationDate = UNDEFINED_TIME; *revocationReason = CRL_REASON_UNSPECIFIED; lock_crl_list("verify_by_crl"); - crl = get_x509crl(cert->issuer, cert->authKeySerialNumber, cert->authKeyID); + crl = get_x509crl(issuer_dn, authKeyID); if (crl == NULL) { + linked_list_t *crluris; + unlock_crl_list("verify_by_crl"); plog("crl not found"); - if (cert->crlDistributionPoints != NULL) + crluris = linked_list_create(); + if (ca) { - fetch_req_t *req = build_crl_fetch_request(cert->issuer - , cert->authKeySerialNumber - , cert->authKeyID, cert->crlDistributionPoints); - add_crl_fetch_request(req); + add_distribution_points(crluris, ca->crluris); } - if (crluri != NULL) + enumerator = x509->create_crl_uri_enumerator(x509); + while (enumerator->enumerate(enumerator, &point)) { - fetch_req_t *req = build_crl_fetch_request(cert->issuer - , cert->authKeySerialNumber - , cert->authKeyID, crluri); - add_crl_fetch_request(req); + add_distribution_point(crluris, point); } + enumerator->destroy(enumerator); - if (cert->crlDistributionPoints != 0 || crluri != NULL) + if (crluris->get_count(crluris) > 0) { + fetch_req_t *req; + + req = build_crl_fetch_request(issuer_dn, authKeyID, crluris); + crluris->destroy_function(crluris, free); + add_crl_fetch_request(req); wake_fetch_thread("verify_by_crl"); return CERT_UNKNOWN; } else + { + crluris->destroy(crluris); return CERT_UNDEFINED; + } } else { @@ -637,18 +628,23 @@ verify_by_crl(const x509cert_t *cert, time_t *until, time_t *revocationDate DBG_log("crl found") ) - add_distribution_points(cert->crlDistributionPoints - , &crl->distributionPoints); + if (ca) + { + add_distribution_points(crl->distributionPoints, ca->crluris); + } - add_distribution_points(crluri - , &crl->distributionPoints); + enumerator = x509->create_crl_uri_enumerator(x509); + while (enumerator->enumerate(enumerator, &point)) + { + add_distribution_point(crl->distributionPoints, point); + } + enumerator->destroy(enumerator); lock_authcert_list("verify_by_crl"); - issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber - , crl->authKeyID, AUTH_CA); + issuer_cert = get_authcert(crl->issuer, crl->authKeyID, AUTH_CA); valid = x509_check_signature(crl->tbsCertList, crl->signature, - crl->algorithm, issuer_cert); + crl->algorithm, issuer_cert->cert); unlock_authcert_list("verify_by_crl"); @@ -663,7 +659,7 @@ verify_by_crl(const x509cert_t *cert, time_t *until, time_t *revocationDate *until = crl->nextUpdate; /* has the certificate been revoked? */ - status = check_revocation(crl, cert->serialNumber, revocationDate + status = check_revocation(crl, x509->get_serial(x509), revocationDate , revocationReason); if (*until < time(NULL)) @@ -673,9 +669,8 @@ verify_by_crl(const x509cert_t *cert, time_t *until, time_t *revocationDate plog("crl update is overdue since %T", until, TRUE); /* try to fetch a crl update */ - req = build_crl_fetch_request(crl->issuer - , crl->authKeySerialNumber - , crl->authKeyID, crl->distributionPoints); + req = build_crl_fetch_request(crl->issuer, crl->authKeyID, + crl->distributionPoints); unlock_crl_list("verify_by_crl"); add_crl_fetch_request(req); @@ -702,8 +697,7 @@ verify_by_crl(const x509cert_t *cert, time_t *until, time_t *revocationDate /* * list all X.509 crls in the chained list */ -void -list_crls(bool utc, bool strict) +void list_crls(bool utc, bool strict) { x509crl_t *crl; diff --git a/src/pluto/crl.h b/src/pluto/crl.h index db3080c2a..765608fbf 100644 --- a/src/pluto/crl.h +++ b/src/pluto/crl.h @@ -14,6 +14,7 @@ #include "constants.h" +#include <utils/linked_list.h> #include <credentials/certificates/crl.h> /* access structure for a revoked serial number */ @@ -34,7 +35,7 @@ typedef struct x509crl x509crl_t; struct x509crl { x509crl_t *next; time_t installed; - generalName_t *distributionPoints; + linked_list_t *distributionPoints; chunk_t certificateList; chunk_t tbsCertList; u_int version; @@ -80,7 +81,7 @@ extern const x509crl_t empty_x509crl; extern bool parse_x509crl(chunk_t blob, u_int level0, x509crl_t *crl); extern void load_crls(void); extern void check_crls(void); -extern bool insert_crl(x509crl_t *crl, chunk_t crl_uri, bool cache_crl); +extern bool insert_crl(x509crl_t *crl, char *crl_uri, bool cache_crl); extern cert_status_t verify_by_crl(const x509cert_t *cert, time_t *until , time_t *revocationDate, crl_reason_t *revocationReason); extern void list_crls(bool utc, bool strict); diff --git a/src/pluto/fetch.c b/src/pluto/fetch.c index b8804fb07..4217cd1d2 100644 --- a/src/pluto/fetch.c +++ b/src/pluto/fetch.c @@ -48,7 +48,6 @@ fetch_req_t empty_fetch_req = { 0 , /* trials */ { NULL, 0}, /* issuer */ { NULL, 0}, /* authKeyID */ - { NULL, 0}, /* authKeySerialNumber */ NULL /* distributionPoints */ }; @@ -251,10 +250,9 @@ void wake_fetch_thread(const char *who) */ static void free_fetch_request(fetch_req_t *req) { + req->distributionPoints->destroy_function(req->distributionPoints, free); free(req->issuer.ptr); - free(req->authKeySerialNumber.ptr); free(req->authKeyID.ptr); - free_generalNames(req->distributionPoints, TRUE); free(req); } @@ -286,47 +284,39 @@ x509crl_t* fetch_crl(char *url) /** * Complete a distributionPoint URI with ca information */ -static char* complete_uri(chunk_t distPoint, const char *ldaphost) +static char* complete_uri(char *distPoint, const char *ldaphost) { - char *uri; - char *ptr = distPoint.ptr; - size_t len = distPoint.len; + char *symbol = strchr(distPoint, ':'); - char *symbol = memchr(ptr, ':', len); - - if (symbol != NULL) + if (symbol) { - size_t type_len = symbol - ptr; + int type_len = symbol - distPoint; - if (type_len >= 4 && strncasecmp(ptr, "ldap", 4) == 0) + if (type_len >= 4 && strncasecmp(distPoint, "ldap", 4) == 0) { - ptr = symbol + 1; - len -= (type_len + 1); + char *ptr = symbol + 1; + int len = strlen(distPoint) - (type_len + 1); if (len > 2 && *ptr++ == '/' && *ptr++ == '/') { len -= 2; - symbol = memchr(ptr, '/', len); + symbol = strchr(ptr, '/'); - if (symbol != NULL && symbol - ptr == 0 && ldaphost != NULL) + if (symbol && symbol - ptr == 0 && ldaphost) { - uri = malloc(distPoint.len + strlen(ldaphost) + 1); + char uri[BUF_LEN]; /* insert the ldaphost into the uri */ - sprintf(uri, "%.*s%s%.*s" - , (int)(distPoint.len - len), distPoint.ptr - , ldaphost - , (int)len, symbol); - return uri; + snprintf(uri, BUF_LEN, "%.*s%s%.*s", strlen(distPoint)-len, + distPoint, ldaphost, len, symbol); + return strdup(uri); } } } } /* default action: copy distributionPoint without change */ - uri = malloc(distPoint.len + 1); - sprintf(uri, "%.*s", (int)distPoint.len, distPoint.ptr); - return uri; + return strdup(distPoint); } /** @@ -343,40 +333,40 @@ static void fetch_crls(bool cache_crls) while (req != NULL) { + enumerator_t *enumerator; + char *point; bool valid_crl = FALSE; - generalName_t *gn = req->distributionPoints; const char *ldaphost; ca_info_t *ca; lock_ca_info_list("fetch_crls"); - ca = get_ca_info(req->issuer, req->authKeySerialNumber, req->authKeyID); + ca = get_ca_info(req->issuer, req->authKeyID); ldaphost = (ca == NULL)? NULL : ca->ldaphost; - while (gn != NULL) + enumerator = req->distributionPoints->create_enumerator(req->distributionPoints); + while (enumerator->enumerate(enumerator, &point)) { - char *uri = complete_uri(gn->name, ldaphost); x509crl_t *crl; + char *uri; + uri = complete_uri(point, ldaphost); crl = fetch_crl(uri); + free(uri); + if (crl) { - chunk_t crl_uri = chunk_clone(gn->name); - - if (insert_crl(crl, crl_uri, cache_crls)) + if (insert_crl(crl, point, cache_crls)) { DBG(DBG_CONTROL, DBG_log("we have a valid crl") ) valid_crl = TRUE; - free(uri); break; } } - free(uri); - gn = gn->next; } - + enumerator->destroy(enumerator); unlock_ca_info_list("fetch_crls"); if (valid_crl) @@ -401,19 +391,11 @@ static void fetch_crls(bool cache_crls) static void fetch_ocsp_status(ocsp_location_t* location) { - chunk_t request, response; - char *uri; + chunk_t request = build_ocsp_request(location); + chunk_t response = chunk_empty; - request = build_ocsp_request(location); - response = chunk_empty; - - /* we need a null terminated string for curl */ - uri = malloc(location->uri.len + 1); - memcpy(uri, location->uri.ptr, location->uri.len); - *(uri + location->uri.len) = '\0'; - - DBG1(" requesting ocsp status from '%s' ...", uri); - if (lib->fetcher->fetch(lib->fetcher, uri, &response, + DBG1(" requesting ocsp status from '%s' ...", location->uri); + if (lib->fetcher->fetch(lib->fetcher, location->uri, &response, FETCH_REQUEST_DATA, request, FETCH_REQUEST_TYPE, "application/ocsp-request", FETCH_END) == SUCCESS) @@ -422,10 +404,9 @@ static void fetch_ocsp_status(ocsp_location_t* location) } else { - DBG1("ocsp request to %s failed", uri); + DBG1("ocsp request to %s failed", location->uri); } - free(uri); free(request.ptr); chunk_free(&location->nonce); @@ -554,62 +535,95 @@ void free_ocsp_fetch(void) /** - * Add additional distribution points + * Add an additional distribution point */ -void add_distribution_points(const generalName_t *newPoints ,generalName_t **distributionPoints) +void add_distribution_point(linked_list_t *points, char *new_point) { - while (newPoints != NULL) + char *point; + bool add = TRUE; + enumerator_t *enumerator; + + if (new_point == NULL || *new_point == '\0') { - /* skip empty distribution point */ - if (newPoints->name.len > 0) + return; + } + + enumerator = points->create_enumerator(points); + while (enumerator->enumerate(enumerator, &point)) + { + if (streq(point, new_point)) { - bool add = TRUE; - generalName_t *gn = *distributionPoints; + add = FALSE; + break; + } + } + enumerator->destroy(enumerator); - while (gn != NULL) - { - if (gn->kind == newPoints->kind - && gn->name.len == newPoints->name.len - && memeq(gn->name.ptr, newPoints->name.ptr, gn->name.len)) - { - /* skip if the distribution point is already present */ - add = FALSE; - break; - } - gn = gn->next; - } + if (add) + { + points->insert_last(points, strdup(new_point)); + } +} - if (add) - { - /* clone additional distribution point */ - gn = clone_thing(*newPoints); - gn->name = chunk_clone(newPoints->name); +/** + * Add additional distribution points + */ +void add_distribution_points(linked_list_t *points, linked_list_t *new_points) +{ + char *new_point; + enumerator_t *enumerator; - /* insert additional CRL distribution point */ - gn->next = *distributionPoints; - *distributionPoints = gn; + enumerator = new_points->create_enumerator(new_points); + while (enumerator->enumerate(enumerator, &new_point)) + { + bool add = TRUE; + char *point; + enumerator_t *enumerator; + + enumerator = points->create_enumerator(points); + while (enumerator->enumerate(enumerator, &point)) + { + if (streq(point, new_point)) + { + add = FALSE; + break; } } - newPoints = newPoints->next; + enumerator->destroy(enumerator); + + if (add) + { + points->insert_last(points, strdup(new_point)); + } } + enumerator->destroy(enumerator); } -fetch_req_t* build_crl_fetch_request(chunk_t issuer, chunk_t authKeySerialNumber, - chunk_t authKeyID, const generalName_t *gn) +fetch_req_t* build_crl_fetch_request(chunk_t issuer, chunk_t authKeyID, + linked_list_t *distributionPoints) { + char *point; + enumerator_t *enumerator; fetch_req_t *req = malloc_thing(fetch_req_t); - *req = empty_fetch_req; + + memset(req, 0, sizeof(fetch_req_t)); + req->distributionPoints = linked_list_create(); /* note current time */ req->installed = time(NULL); /* clone fields */ req->issuer = chunk_clone(issuer); - req->authKeySerialNumber = chunk_clone(authKeySerialNumber); req->authKeyID = chunk_clone(authKeyID); /* copy distribution points */ - add_distribution_points(gn, &req->distributionPoints); + enumerator = distributionPoints->create_enumerator(distributionPoints); + while (enumerator->enumerate(enumerator, &point)) + { + req->distributionPoints->insert_last(req->distributionPoints, + strdup(point)); + } + enumerator->destroy(enumerator); return req; } @@ -626,9 +640,8 @@ void add_crl_fetch_request(fetch_req_t *req) while (r != NULL) { - if ((req->authKeyID.ptr != NULL)? same_keyid(req->authKeyID, r->authKeyID) - : (same_dn(req->issuer, r->issuer) - && same_serial(req->authKeySerialNumber, r->authKeySerialNumber))) + if (req->authKeyID.ptr ? same_keyid(req->authKeyID, r->authKeyID) : + same_dn(req->issuer, r->issuer)) { /* there is already a fetch request */ DBG(DBG_CONTROL, @@ -636,7 +649,8 @@ void add_crl_fetch_request(fetch_req_t *req) ) /* there might be new distribution points */ - add_distribution_points(req->distributionPoints, &r->distributionPoints); + add_distribution_points(r->distributionPoints, + req->distributionPoints); unlock_crl_fetch_list("add_crl_fetch_request"); free_fetch_request(req); @@ -672,17 +686,20 @@ void add_ocsp_fetch_request(ocsp_location_t *location, chunk_t serialNumber) /** * List all distribution points */ -void list_distribution_points(const generalName_t *gn) +void list_distribution_points(linked_list_t *distributionPoints) { - bool first_gn = TRUE; + char *point; + bool first_point = TRUE; + enumerator_t *enumerator; - while (gn != NULL) + enumerator = distributionPoints->create_enumerator(distributionPoints); + while (enumerator->enumerate(enumerator, &point)) { - whack_log(RC_COMMENT, " %s '%.*s'", (first_gn)? "distPts: " - :" ", (int)gn->name.len, gn->name.ptr); - first_gn = FALSE; - gn = gn->next; + whack_log(RC_COMMENT, " %s '%s'", + (first_point)? "distPts: " : " ", point); + first_point = FALSE; } + enumerator->destroy(enumerator); } /** @@ -716,12 +733,6 @@ void list_crl_fetch_requests(bool utc) , buf, BUF_LEN); whack_log(RC_COMMENT, " authkey: %s", buf); } - if (req->authKeySerialNumber.ptr != NULL) - { - datatot(req->authKeySerialNumber.ptr, req->authKeySerialNumber.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " aserial: %s", buf); - } list_distribution_points(req->distributionPoints); req = req->next; } diff --git a/src/pluto/fetch.h b/src/pluto/fetch.h index f7b4eb074..a12e86a0b 100644 --- a/src/pluto/fetch.h +++ b/src/pluto/fetch.h @@ -13,6 +13,8 @@ * for more details. */ +#include <utils/linked_list.h> + #include "x509.h" #define FETCH_CMD_TIMEOUT 10 /* seconds */ @@ -32,8 +34,7 @@ struct fetch_req { int trials; chunk_t issuer; chunk_t authKeyID; - chunk_t authKeySerialNumber; - generalName_t *distributionPoints; + linked_list_t *distributionPoints; }; #ifdef THREADS @@ -64,13 +65,15 @@ extern void wake_fetch_thread(const char *who); extern void init_fetch(void); extern void free_crl_fetch(void); extern void free_ocsp_fetch(void); -extern void add_distribution_points(const generalName_t *newPoints - , generalName_t **distributionPoints); -extern fetch_req_t* build_crl_fetch_request(chunk_t issuer, chunk_t authKeySerialNumber - , chunk_t authKeyID, const generalName_t *gn); +extern void add_distribution_point(linked_list_t *points, char* new_point); +extern void add_distribution_points(linked_list_t *points, + linked_list_t *new_points); +extern fetch_req_t* build_crl_fetch_request(chunk_t issuer, chunk_t authKeyID, + linked_list_t *distributionPoints); extern void add_crl_fetch_request(fetch_req_t *req); -extern void add_ocsp_fetch_request(struct ocsp_location *location, chunk_t serialNumber); -extern void list_distribution_points(const generalName_t *gn); +extern void add_ocsp_fetch_request(struct ocsp_location *location, + chunk_t serialNumber); +extern void list_distribution_points(linked_list_t *distributionPoints); extern void list_crl_fetch_requests(bool utc); extern void list_ocsp_fetch_requests(bool utc); extern size_t write_buffer(void *ptr, size_t size, size_t nmemb, void *data); diff --git a/src/pluto/id.c b/src/pluto/id.c index f34775e68..cd5b35075 100644 --- a/src/pluto/id.c +++ b/src/pluto/id.c @@ -44,8 +44,7 @@ char *myid_str[MYID_SPECIFIED+1]; /* string form of IDs */ /* initialize id module * Fills in myid from environment variable IPSECmyid or defaultrouteaddr */ -void -init_id(void) +void init_id(void) { passert(empty_id.kind == ID_ANY); myid_state = MYID_UNKNOWN; @@ -66,8 +65,7 @@ init_id(void) /* * free id module */ -void -free_id(void) +void free_id(void) { enum myid_state s; @@ -78,8 +76,7 @@ free_id(void) } } -static void -calc_myid_str(enum myid_state s) +static void calc_myid_str(enum myid_state s) { /* preformat the ID name */ char buf[BUF_LEN]; @@ -89,8 +86,7 @@ calc_myid_str(enum myid_state s) } -void -set_myid(enum myid_state s, char *idstr) +void set_myid(enum myid_state s, char *idstr) { if (idstr != NULL) { @@ -114,8 +110,7 @@ set_myid(enum myid_state s, char *idstr) } } -void -set_myFQDN(void) +void set_myFQDN(void) { char FQDN[HOST_NAME_MAX + 1]; int r = gethostname(FQDN, sizeof(FQDN)); @@ -151,8 +146,7 @@ set_myFQDN(void) } } -void -show_myid_status(void) +void show_myid_status(void) { char idstr[BUF_LEN]; @@ -163,8 +157,7 @@ show_myid_status(void) /* Convert textual form of id into a (temporary) struct id. * Note that if the id is to be kept, unshare_id_content will be necessary. */ -err_t -atoid(char *src, struct id *id, bool myid_ok) +err_t atoid(char *src, struct id *id, bool myid_ok) { err_t ugh = NULL; @@ -252,15 +245,13 @@ atoid(char *src, struct id *id, bool myid_ok) /* * Converts a binary key ID into hexadecimal format */ -int -keyidtoa(char *dst, size_t dstlen, chunk_t keyid) +int keyidtoa(char *dst, size_t dstlen, chunk_t keyid) { int n = datatot(keyid.ptr, keyid.len, 'x', dst, dstlen); return (((size_t)n < dstlen)? n : dstlen) - 1; } -void -iptoid(const ip_address *ip, struct id *id) +void iptoid(const ip_address *ip, struct id *id) { *id = empty_id; @@ -278,8 +269,7 @@ iptoid(const ip_address *ip, struct id *id) id->ip_addr = *ip; } -int -idtoa(const struct id *id, char *dst, size_t dstlen) +int idtoa(const struct id *id, char *dst, size_t dstlen) { int n; @@ -326,8 +316,7 @@ idtoa(const struct id *id, char *dst, size_t dstlen) /* Replace the shell metacharacters ', \, ", `, and $ in a character string * by escape sequences consisting of their octal values */ -void -escape_metachar(const char *src, char *dst, size_t dstlen) +void escape_metachar(const char *src, char *dst, size_t dstlen) { while (*src != '\0' && dstlen > 4) { @@ -355,8 +344,7 @@ escape_metachar(const char *src, char *dst, size_t dstlen) /* Make private copy of string in struct id. * This is needed if the result of atoid is to be kept. */ -void -unshare_id_content(struct id *id) +void unshare_id_content(struct id *id) { switch (id->kind) { @@ -376,8 +364,7 @@ unshare_id_content(struct id *id) } } -void -free_id_content(struct id *id) +void free_id_content(struct id *id) { switch (id->kind) { @@ -398,8 +385,7 @@ free_id_content(struct id *id) } /* compare two struct id values */ -bool -same_id(const struct id *a, const struct id *b) +bool same_id(const struct id *a, const struct id *b) { a = resolve_myid(a); b = resolve_myid(b); @@ -446,8 +432,7 @@ same_id(const struct id *a, const struct id *b) } /* compare two struct id values, DNs can contain wildcards */ -bool -match_id(const struct id *a, const struct id *b, int *wildcards) +bool match_id(const struct id *a, const struct id *b, int *wildcards) { if (b->kind == ID_ANY) { @@ -466,8 +451,7 @@ match_id(const struct id *a, const struct id *b, int *wildcards) } /* count the numer of wildcards in an id */ -int -id_count_wildcards(const struct id *id) +int id_count_wildcards(const struct id *id) { switch (id->kind) { @@ -485,8 +469,7 @@ id_count_wildcards(const struct id *id) * We assume it will end up being a pointer into a sufficiently * stable datastructure. It only needs to last a short time. */ -void -build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl, struct end *end) +void build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl, struct end *end) { const struct id *id = resolve_myid(&end->id); @@ -515,6 +498,37 @@ build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl, struct end *end) } } +/** + * Converts libstrongswan's identification_t type into pluto's struct id + */ +void id_from_identification(struct id *id, identification_t *identification) +{ + chunk_t encoding; + + encoding = identification->get_encoding(identification); + id->kind = identification->get_type(identification); + + switch (id->kind) + { + case ID_FQDN: + case ID_USER_FQDN: + case ID_DER_ASN1_DN: + case ID_KEY_ID: + id->name = encoding; + break; + case ID_IPV4_ADDR: + case ID_IPV6_ADDR: + initaddr(encoding.ptr, encoding.len, + (id->kind == ID_IPV4_ADDR) ? AF_INET : AF_INET6, + &id->ip_addr); + break; + case ID_ANY: + default: + id->kind = ID_ANY; + id->name = chunk_empty; + } +} + /* * Local Variables: * c-basic-offset:4 diff --git a/src/pluto/id.h b/src/pluto/id.h index dc2dcdfa6..8fe1a1f46 100644 --- a/src/pluto/id.h +++ b/src/pluto/id.h @@ -15,6 +15,8 @@ #ifndef _ID_H #define _ID_H +#include <utils/identification.h> + #include "defs.h" struct id { @@ -26,7 +28,7 @@ struct id { extern void init_id(void); extern void free_id(void); -extern const struct id empty_id; /* ID_NONE */ +extern const struct id empty_id; /* ID_ANY */ enum myid_state { MYID_UNKNOWN, /* not yet figured out */ @@ -59,7 +61,8 @@ extern int id_count_wildcards(const struct id *id); #define id_is_ipaddr(id) ((id)->kind == ID_IPV4_ADDR || (id)->kind == ID_IPV6_ADDR) struct isakmp_ipsec_id; /* forward declaration of tag (defined in packet.h) */ -extern void - build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl, struct end *end); +extern void build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl, + struct end *end); +extern void id_from_identification(struct id *id, identification_t *identification); #endif /* _ID_H */ diff --git a/src/pluto/ipsec_doi.c b/src/pluto/ipsec_doi.c index 78eaaa018..43c01a8db 100644 --- a/src/pluto/ipsec_doi.c +++ b/src/pluto/ipsec_doi.c @@ -2149,8 +2149,14 @@ static void decode_cert(struct msg_digest *md) if (cert->isacert_type == CERT_X509_SIGNATURE) { x509cert_t cert = empty_x509cert; - if (parse_x509cert(blob, 0, &cert)) + + cert.cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, blob, + BUILD_END); + if (cert.cert) { + time(&cert.installed); if (verify_x509cert(&cert, strict_crl_policy, &valid_until)) { DBG(DBG_PARSING, @@ -2162,9 +2168,7 @@ static void decode_cert(struct msg_digest *md) { plog("X.509 certificate rejected"); } - DESTROY_IF(cert.public_key); - free_generalNames(cert.subjectAltName, FALSE); - free_generalNames(cert.crlDistributionPoints, FALSE); + DESTROY_IF(cert.cert); } else { @@ -3556,6 +3560,8 @@ stf_status main_inR2_outI3(struct msg_digest *md) } if (send_cert) { + bool success; + chunk_t cert_encoding; pb_stream cert_pbs; struct isakmp_cert cert_hd; @@ -3566,7 +3572,10 @@ stf_status main_inR2_outI3(struct msg_digest *md) { return STF_INTERNAL_ERROR; } - if (!out_chunk(cert_get_encoding(mycert), &cert_pbs, "CERT")) + cert_encoding = cert_get_encoding(mycert); + success = out_chunk(cert_encoding, &cert_pbs, "CERT"); + free(cert_encoding.ptr); + if (!success) { return STF_INTERNAL_ERROR; } @@ -3996,9 +4005,11 @@ main_inI3_outR3_tail(struct msg_digest *md } if (send_cert) { + bool success; + chunk_t cert_encoding; pb_stream cert_pbs; - struct isakmp_cert cert_hd; + cert_hd.isacert_np = ISAKMP_NEXT_SIG; cert_hd.isacert_type = mycert.type; @@ -4006,8 +4017,11 @@ main_inI3_outR3_tail(struct msg_digest *md { return STF_INTERNAL_ERROR; } - if (!out_chunk(cert_get_encoding(mycert), &cert_pbs, "CERT")) - { + cert_encoding = cert_get_encoding(mycert); + success = out_chunk(cert_encoding, &cert_pbs, "CERT"); + free(cert_encoding.ptr); + if (!success) + { return STF_INTERNAL_ERROR; } close_output_pbs(&cert_pbs); diff --git a/src/pluto/keys.c b/src/pluto/keys.c index 4035495c6..d1ea88f68 100644 --- a/src/pluto/keys.c +++ b/src/pluto/keys.c @@ -127,6 +127,7 @@ static const secret_t* get_secret(const struct connection *c, break; /* we have found the private key - no sense in searching further */ } } + pub_key->destroy(pub_key); return best; } @@ -277,6 +278,7 @@ bool has_private_key(cert_t cert) break; } } + pub_key->destroy(pub_key); return has_key; } @@ -285,17 +287,22 @@ bool has_private_key(cert_t cert) */ private_key_t* get_x509_private_key(const x509cert_t *cert) { + public_key_t *public_key = cert->cert->get_public_key(cert->cert); + private_key_t *private_key = NULL; secret_t *s; for (s = secrets; s != NULL; s = s->next) { + if (s->kind == PPK_PUBKEY && - s->u.private_key->belongs_to(s->u.private_key, cert->public_key)) + s->u.private_key->belongs_to(s->u.private_key, public_key)) { - return s->u.private_key; + private_key = s->u.private_key; + break; } } - return NULL; + public_key->destroy(public_key); + return private_key; } /* find the appropriate private key (see get_secret). @@ -1231,7 +1238,7 @@ void delete_public_keys(const struct id *id, key_type_t type, if (same_id(id, &pk->id) && pk_type == type && (issuer.ptr == NULL || pk->issuer.ptr == NULL || same_dn(issuer, pk->issuer)) - && same_serial(serial, pk->serial)) + && (serial.ptr == NULL || chunk_equals(serial, pk->serial))) { *pp = free_public_keyentry(p); } @@ -1317,46 +1324,50 @@ bool add_public_key(const struct id *id, enum dns_auth_level dns_auth_level, void add_x509_public_key(x509cert_t *cert , time_t until, enum dns_auth_level dns_auth_level) { - generalName_t *gn; + certificate_t *certificate = cert->cert; + x509_t *x509 = (x509_t*)certificate; + identification_t *subject = certificate->get_subject(certificate); + identification_t *issuer = certificate->get_issuer(certificate); + identification_t *id; + chunk_t issuer_dn = issuer->get_encoding(issuer); + chunk_t serialNumber = x509->get_serial(x509); pubkey_t *pk; key_type_t pk_type; + enumerator_t *enumerator; /* ID type: ID_DER_ASN1_DN (X.509 subject field) */ pk = malloc_thing(pubkey_t); zero(pk); - pk->public_key = cert->public_key->get_ref(cert->public_key); + pk->public_key = cert->cert->get_public_key(cert->cert); pk->id.kind = ID_DER_ASN1_DN; - pk->id.name = cert->subject; + pk->id.name = subject->get_encoding(subject); pk->dns_auth_level = dns_auth_level; pk->until_time = until; - pk->issuer = cert->issuer; - pk->serial = cert->serialNumber; + pk->issuer = issuer_dn; + pk->serial = serialNumber; pk_type = pk->public_key->get_type(pk->public_key); delete_public_keys(&pk->id, pk_type, pk->issuer, pk->serial); install_public_key(pk, &pubkeys); - gn = cert->subjectAltName; - - while (gn != NULL) /* insert all subjectAltNames */ + /* insert all subjectAltNames */ + enumerator = x509->create_subjectAltName_enumerator(x509); + while (enumerator->enumerate(enumerator, &id)) { - struct id id = empty_id; - - gntoid(&id, gn); - if (id.kind != ID_ANY) + if (id->get_type(id) != ID_ANY) { pk = malloc_thing(pubkey_t); zero(pk); - pk->public_key = cert->public_key->get_ref(cert->public_key); - pk->id = id; + id_from_identification(&pk->id, id); + pk->public_key = cert->cert->get_public_key(cert->cert); pk->dns_auth_level = dns_auth_level; pk->until_time = until; - pk->issuer = cert->issuer; - pk->serial = cert->serialNumber; + pk->issuer = issuer_dn; + pk->serial = serialNumber; delete_public_keys(&pk->id, pk_type, pk->issuer, pk->serial); install_public_key(pk, &pubkeys); } - gn = gn->next; } + enumerator->destroy(enumerator); } /* extract id and public key from OpenPGP certificate and @@ -1385,7 +1396,7 @@ void add_pgp_public_key(pgpcert_t *cert , time_t until, */ void remove_x509_public_key(const x509cert_t *cert) { - public_key_t *revoked_key = cert->public_key; + public_key_t *revoked_key = cert->cert->get_public_key(cert->cert); pubkey_list_t *p, **pp; p = pubkeys; @@ -1405,6 +1416,7 @@ void remove_x509_public_key(const x509cert_t *cert) } p =*pp; } + revoked_key->destroy(revoked_key); } /* diff --git a/src/pluto/ocsp.c b/src/pluto/ocsp.c index da81ce2d8..510667e67 100644 --- a/src/pluto/ocsp.c +++ b/src/pluto/ocsp.c @@ -283,18 +283,29 @@ static const asn1Object_t singleResponseObjects[] = { */ static bool build_ocsp_location(const x509cert_t *cert, ocsp_location_t *location) { + certificate_t *certificate = cert->cert; + identification_t *issuer = certificate->get_issuer(certificate); + x509_t *x509 = (x509_t*)certificate; + chunk_t issuer_dn = issuer->get_encoding(issuer); + chunk_t authKeyID = x509->get_authKeyIdentifier(x509); hasher_t *hasher; static u_char digest[HASH_SIZE_SHA1]; /* temporary storage */ - location->uri = cert->accessLocation; + enumerator_t *enumerator = x509->create_ocsp_uri_enumerator(x509); - if (location->uri.ptr == NULL) + location->uri = NULL; + while (enumerator->enumerate(enumerator, &location->uri)) { - ca_info_t *ca = get_ca_info(cert->issuer, cert->authKeySerialNumber - , cert->authKeyID); + break; + } + enumerator->destroy(enumerator); + + if (location->uri == NULL) + { + ca_info_t *ca = get_ca_info(issuer_dn, authKeyID); if (ca != NULL && ca->ocspuri != NULL) { - location->uri = chunk_create(ca->ocspuri, strlen(ca->ocspuri)); + location->uri = ca->ocspuri; } else { /* abort if no ocsp location uri is defined */ @@ -309,23 +320,22 @@ static bool build_ocsp_location(const x509cert_t *cert, ocsp_location_t *locatio { return FALSE; } - hasher->get_hash(hasher, cert->issuer, digest); + hasher->get_hash(hasher, issuer_dn, digest); hasher->destroy(hasher); location->next = NULL; - location->issuer = cert->issuer; - location->authKeyID = cert->authKeyID; - location->authKeySerialNumber = cert->authKeySerialNumber; + location->issuer = issuer_dn; + location->authKeyID = authKeyID; - if (cert->authKeyID.ptr == NULL) + if (authKeyID.ptr == NULL) { - x509cert_t *authcert = get_authcert(cert->issuer - , cert->authKeySerialNumber, cert->authKeyID, AUTH_CA); + x509cert_t *authcert = get_authcert(issuer_dn, authKeyID, AUTH_CA); if (authcert != NULL) { - location->authKeyID = authcert->subjectKeyID; - location->authKeySerialNumber = authcert->serialNumber; + x509_t *x509 = (x509_t*)authcert->cert; + + location->authKeyID = x509->get_subjectKeyIdentifier(x509); } } @@ -342,9 +352,8 @@ static bool same_ocsp_location(const ocsp_location_t *a, const ocsp_location_t * { return ((a->authKeyID.ptr != NULL) ? same_keyid(a->authKeyID, b->authKeyID) - : (same_dn(a->issuer, b->issuer) - && same_serial(a->authKeySerialNumber, b->authKeySerialNumber))) - && chunk_equals(a->uri, b->uri); + : same_dn(a->issuer, b->issuer)) + && streq(a->uri, b->uri); } /** @@ -411,6 +420,8 @@ cert_status_t verify_by_ocsp(const x509cert_t *cert, time_t *until, time_t *revocationDate, crl_reason_t *revocationReason) { + x509_t *x509 = (x509_t*)cert->cert; + chunk_t serialNumber = x509->get_serial(x509); cert_status_t status; ocsp_location_t location; time_t nextUpdate = 0; @@ -420,17 +431,19 @@ cert_status_t verify_by_ocsp(const x509cert_t *cert, time_t *until, /* is an ocsp location defined? */ if (!build_ocsp_location(cert, &location)) + { return CERT_UNDEFINED; + } lock_ocsp_cache("verify_by_ocsp"); - status = get_ocsp_status(&location, cert->serialNumber, &nextUpdate + status = get_ocsp_status(&location, serialNumber, &nextUpdate , revocationDate, revocationReason); unlock_ocsp_cache("verify_by_ocsp"); if (status == CERT_UNDEFINED || nextUpdate < time(NULL)) { plog("ocsp status is stale or not in cache"); - add_ocsp_fetch_request(&location, cert->serialNumber); + add_ocsp_fetch_request(&location, serialNumber); /* inititate fetching of ocsp status */ wake_fetch_thread("verify_by_ocsp"); @@ -521,8 +534,7 @@ static void free_ocsp_location(ocsp_location_t* location) free(location->issuer.ptr); free(location->authNameID.ptr); free(location->authKeyID.ptr); - free(location->authKeySerialNumber.ptr); - free(location->uri.ptr); + free(location->uri); free_certinfos(location->certinfo); free(location); } @@ -588,8 +600,7 @@ void list_ocsp_locations(ocsp_location_t *location, bool requests, dntoa(buf, BUF_LEN, location->issuer); whack_log(RC_COMMENT, " issuer: '%s'", buf); } - whack_log(RC_COMMENT, " uri: '%.*s'", (int)location->uri.len - , location->uri.ptr); + whack_log(RC_COMMENT, " uri: '%s'", location->uri); if (location->authNameID.ptr != NULL) { datatot(location->authNameID.ptr, location->authNameID.len, ':' @@ -602,12 +613,6 @@ void list_ocsp_locations(ocsp_location_t *location, bool requests, , buf, BUF_LEN); whack_log(RC_COMMENT, " authkey: %s", buf); } - if (location->authKeySerialNumber.ptr != NULL) - { - datatot(location->authKeySerialNumber.ptr - , location->authKeySerialNumber.len, ':', buf, BUF_LEN); - whack_log(RC_COMMENT, " aserial: %s", buf); - } while (certinfo != NULL) { char thisUpdate[BUF_LEN]; @@ -662,17 +667,17 @@ static bool get_ocsp_requestor_cert(ocsp_location_t *location) for (;;) { - char buf[BUF_LEN]; + certificate_t *certificate; /* looking for a certificate from the same issuer */ - cert = get_x509cert(location->issuer, location->authKeySerialNumber - ,location->authKeyID, cert); + cert = get_x509cert(location->issuer, location->authKeyID, cert); if (cert == NULL) + { break; - + } + certificate = cert->cert; DBG(DBG_CONTROL, - dntoa(buf, BUF_LEN, cert->subject); - DBG_log("candidate: '%s'", buf); + DBG_log("candidate: '%Y'", certificate->get_subject(certificate)); ) if (cert->smartcard) @@ -774,7 +779,7 @@ static chunk_t sc_build_sha1_signature(chunk_t tbs, smartcard_t *sc) */ static chunk_t build_signature(chunk_t tbsRequest) { - chunk_t sigdata, certs; + chunk_t sigdata, cert, certs; if (ocsp_requestor_sc != NULL) { @@ -793,11 +798,9 @@ static chunk_t build_signature(chunk_t tbsRequest) } /* include our certificate */ - certs = asn1_wrap(ASN1_CONTEXT_C_0, "m" - , asn1_simple_object(ASN1_SEQUENCE - , ocsp_requestor_cert->certificate - ) - ); + cert = ocsp_requestor_cert->cert->get_encoding(ocsp_requestor_cert->cert); + certs = asn1_wrap(ASN1_CONTEXT_C_0, "m", + asn1_wrap(ASN1_SEQUENCE, "m", cert)); /* build signature comprising algorithm, signature and cert */ return asn1_wrap(ASN1_CONTEXT_C_0, "m" @@ -872,9 +875,12 @@ static chunk_t build_request_list(ocsp_location_t *location) */ static chunk_t build_requestor_name(void) { + certificate_t *certificate = ocsp_requestor_cert->cert; + identification_t *subject = certificate->get_subject(certificate); + return asn1_wrap(ASN1_CONTEXT_C_1, "m" , asn1_simple_object(ASN1_CONTEXT_C_4 - , ocsp_requestor_cert->subject)); + , subject->get_encoding(subject))); } /** @@ -976,9 +982,8 @@ static bool valid_ocsp_response(response_t *res) lock_authcert_list("valid_ocsp_response"); - authcert = get_authcert(res->responder_id_name, chunk_empty - , res->responder_id_key, AUTH_OCSP | AUTH_CA); - + authcert = get_authcert(res->responder_id_name, res->responder_id_key, + AUTH_OCSP | AUTH_CA); if (authcert == NULL) { plog("no matching ocsp signer cert found"); @@ -989,7 +994,8 @@ static bool valid_ocsp_response(response_t *res) DBG_log("ocsp signer cert found") ) - if (!x509_check_signature(res->tbs, res->signature, res->algorithm, authcert)) + if (!x509_check_signature(res->tbs, res->signature, res->algorithm, + authcert->cert)) { plog("signature of ocsp response is invalid"); unlock_authcert_list("valid_ocsp_response"); @@ -1002,22 +1008,22 @@ static bool valid_ocsp_response(response_t *res) for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++) { - u_char buf[BUF_LEN]; err_t ugh = NULL; time_t until; x509cert_t *cert = authcert; + certificate_t *certificate = cert->cert; + x509_t *x509 = (x509_t*)certificate; + identification_t *subject = certificate->get_subject(certificate); + identification_t *issuer = certificate->get_issuer(certificate); + chunk_t authKeyID = x509->get_authKeyIdentifier(x509); DBG(DBG_CONTROL, - dntoa(buf, BUF_LEN, cert->subject); - DBG_log("subject: '%s'",buf); - dntoa(buf, BUF_LEN, cert->issuer); - DBG_log("issuer: '%s'",buf); - if (cert->authKeyID.ptr != NULL) + DBG_log("subject: '%Y'", subject); + DBG_log("issuer: '%Y'", issuer); + if (authKeyID.ptr != NULL) { - datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':' - , buf, BUF_LEN); - DBG_log("authkey: %s", buf); + DBG_log("authkey: %#B", &authKeyID); } ) @@ -1034,9 +1040,7 @@ static bool valid_ocsp_response(response_t *res) DBG_log("certificate is valid") ) - authcert = get_authcert(cert->issuer, cert->authKeySerialNumber - , cert->authKeyID, AUTH_CA); - + authcert = get_authcert(issuer->get_encoding(issuer), authKeyID, AUTH_CA); if (authcert == NULL) { plog("issuer cacert not found"); @@ -1047,8 +1051,7 @@ static bool valid_ocsp_response(response_t *res) DBG_log("issuer cacert found") ) - if (!x509_check_signature(cert->tbsCertificate, cert->signature, - cert->algorithm, authcert)) + if (!certificate->issued_by(certificate, authcert->cert)) { plog("certificate signature is invalid"); unlock_authcert_list("valid_ocsp_response"); @@ -1059,7 +1062,7 @@ static bool valid_ocsp_response(response_t *res) ) /* check if cert is self-signed */ - if (same_dn(cert->issuer, cert->subject)) + if (x509->get_flags(x509) & X509_SELF_SIGNED) { DBG(DBG_CONTROL, DBG_log("reached self-signed root ca") @@ -1143,14 +1146,27 @@ static bool parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res) break; case BASIC_RESPONSE_CERTIFICATE: { - chunk_t blob = chunk_clone(object); x509cert_t *cert = malloc_thing(x509cert_t); + x509_t *x509; *cert = empty_x509cert; - - if (parse_x509cert(blob, parser->get_level(parser)+1, cert) - && cert->isOcspSigner - && trust_authcert_candidate(cert, NULL)) + cert->cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, object, + BUILD_END); + if (cert->cert == NULL) + { + DBG(DBG_CONTROL | DBG_PARSING, + DBG_log("parsing of embedded ocsp certificate failed") + ) + free_x509cert(cert); + break; + } + time(&cert->installed); + x509 = (x509_t*)cert->cert; + + if ((x509->get_flags(x509) & X509_OCSP_SIGNER) && + trust_authcert_candidate(cert, NULL)) { add_authcert(cert, AUTH_OCSP); } @@ -1322,8 +1338,7 @@ ocsp_location_t* add_ocsp_location(const ocsp_location_t *loc, location->issuer = chunk_clone(loc->issuer); location->authNameID = chunk_clone(loc->authNameID); location->authKeyID = chunk_clone(loc->authKeyID); - location->authKeySerialNumber = chunk_clone(loc->authKeySerialNumber); - location->uri = chunk_clone(loc->uri); + location->uri = strdup(loc->uri); location->certinfo = NULL; /* insert new ocsp location in front of chain */ diff --git a/src/pluto/ocsp.h b/src/pluto/ocsp.h index 4615e6f76..dd3854fbf 100644 --- a/src/pluto/ocsp.h +++ b/src/pluto/ocsp.h @@ -57,9 +57,8 @@ struct ocsp_location { chunk_t issuer; chunk_t authNameID; chunk_t authKeyID; - chunk_t authKeySerialNumber; - chunk_t uri; chunk_t nonce; + char *uri; ocsp_certinfo_t *certinfo; }; diff --git a/src/pluto/pkcs7.c b/src/pluto/pkcs7.c index 61d375113..dcfc9e88c 100644 --- a/src/pluto/pkcs7.c +++ b/src/pluto/pkcs7.c @@ -17,6 +17,7 @@ #include <stdlib.h> #include <string.h> +#include <time.h> #include <freeswan.h> @@ -202,7 +203,7 @@ end: * Parse a PKCS#7 signedData object */ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert, - chunk_t *attributes, const x509cert_t *cacert) + chunk_t *attributes, certificate_t *cacert) { u_char buf[BUF_LEN]; asn1_parser_t *parser; @@ -252,14 +253,17 @@ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert case PKCS7_SIGNED_CERT: if (cert != NULL) { - chunk_t cert_blob = chunk_clone(object); x509cert_t *newcert = malloc_thing(x509cert_t); - *newcert = empty_x509cert; - DBG2(" parsing pkcs7-wrapped certificate"); - if (parse_x509cert(cert_blob, level+1, newcert)) + *newcert = empty_x509cert; + newcert->cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, object, + BUILD_END); + if (newcert->cert) { + time(&newcert->installed); newcert->next = *cert; *cert = newcert; } @@ -308,9 +312,15 @@ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert /* check the signature only if a cacert is available */ if (cacert != NULL) { - public_key_t *key = cacert->public_key; - signature_scheme_t scheme = SIGN_RSA_EMSA_PKCS1_SHA1; + public_key_t *key; + signature_scheme_t scheme; + scheme = signature_scheme_from_oid(digest_alg); + if (scheme == SIGN_UNKNOWN) + { + DBG1("unsupported signature scheme"); + return FALSE; + } if (signerInfos == 0) { DBG1("no signerInfo object found"); @@ -332,11 +342,11 @@ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert return FALSE; } - /* determine signature scheme */ - scheme = signature_scheme_from_oid(digest_alg); - - if (scheme == SIGN_UNKNOWN) + /* verify the signature */ + key = cacert->get_public_key(cacert); + if (key == NULL) { + DBG1("no public key found in CA certificate"); return FALSE; } if (key->verify(key, scheme, *attributes, encrypted_digest)) @@ -346,10 +356,11 @@ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert else { DBG1("invalid signature"); - return FALSE; + success = FALSE; } + key->destroy(key); } - return TRUE; + return success; } /** @@ -629,18 +640,21 @@ static chunk_t pkcs7_build_contentInfo(contentInfo_t *cInfo) /** * build issuerAndSerialNumber object */ -chunk_t pkcs7_build_issuerAndSerialNumber(const x509cert_t *cert) +chunk_t pkcs7_build_issuerAndSerialNumber(certificate_t *cert) { - return asn1_wrap(ASN1_SEQUENCE, "cm" - , cert->issuer - , asn1_integer("c", cert->serialNumber)); + identification_t *issuer = cert->get_issuer(cert); + x509_t *x509 = (x509_t*)cert; + + return asn1_wrap(ASN1_SEQUENCE, "cm", + issuer->get_encoding(issuer), + asn1_integer("c", x509->get_serial(x509))); } /** * create a signed pkcs7 contentInfo object */ chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes, - const x509cert_t *cert, int digest_alg, + certificate_t *cert, int digest_alg, private_key_t *key) { contentInfo_t pkcs7Data, signedData; @@ -677,7 +691,7 @@ chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes, , ASN1_INTEGER_1 , asn1_wrap(ASN1_SET, "m", asn1_algorithmIdentifier(digest_alg)) , pkcs7_build_contentInfo(&pkcs7Data) - , asn1_simple_object(ASN1_CONTEXT_C_0, cert->certificate) + , asn1_wrap(ASN1_CONTEXT_C_0, "m", cert->get_encoding(cert)) , asn1_wrap(ASN1_SET, "m", signerInfo)); cInfo = pkcs7_build_contentInfo(&signedData); @@ -691,7 +705,7 @@ chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes, /** * create a symmetrically encrypted pkcs7 contentInfo object */ -chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int enc_alg) +chunk_t pkcs7_build_envelopedData(chunk_t data, certificate_t *cert, int enc_alg) { encryption_algorithm_t alg; size_t alg_key_size; @@ -744,9 +758,24 @@ chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int enc_ crypter->set_key(crypter, symmetricKey); crypter->encrypt(crypter, in, iv, &out); crypter->destroy(crypter); + chunk_clear(&in); DBG3("encrypted data %B", &out); - cert->public_key->encrypt(cert->public_key, symmetricKey, &protectedKey); + /* protect symmetric key by public key encryption */ + { + public_key_t *key = cert->get_public_key(cert); + + if (key == NULL) + { + DBG1("public key not found in encryption certificate"); + chunk_clear(&symmetricKey); + chunk_free(&iv); + chunk_free(&out); + return chunk_empty; + } + key->encrypt(key, symmetricKey, &protectedKey); + key->destroy(key); + } /* build pkcs7 enveloped data object */ { @@ -781,10 +810,9 @@ chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int enc_ cInfo = pkcs7_build_contentInfo(&envelopedData); DBG3("envelopedData %B", &cInfo); - free(envelopedData.content.ptr); - free(symmetricKey.ptr); - free(in.ptr); - free(iv.ptr); + chunk_free(&envelopedData.content); + chunk_free(&iv); + chunk_clear(&symmetricKey); return cInfo; } } diff --git a/src/pluto/pkcs7.h b/src/pluto/pkcs7.h index 028822dfe..4122c196b 100644 --- a/src/pluto/pkcs7.h +++ b/src/pluto/pkcs7.h @@ -20,6 +20,7 @@ #include <crypto/crypters/crypter.h> #include <credentials/keys/private_key.h> +#include <credentials/certificates/certificate.h> #include "defs.h" #include "x509.h" @@ -35,17 +36,19 @@ struct contentInfo { extern const contentInfo_t empty_contentInfo; extern bool pkcs7_parse_contentInfo(chunk_t blob, u_int level0, - contentInfo_t *cInfo); + contentInfo_t *cInfo); extern bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, - x509cert_t **cert, chunk_t *attributes, const x509cert_t *cacert); + x509cert_t **cert, chunk_t *attributes, + certificate_t *cacert); extern bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data, - chunk_t serialNumber, private_key_t *key); + chunk_t serialNumber, private_key_t *key); extern chunk_t pkcs7_contentType_attribute(void); extern chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_alg); -extern chunk_t pkcs7_build_issuerAndSerialNumber(const x509cert_t *cert); +extern chunk_t pkcs7_build_issuerAndSerialNumber(certificate_t *cert); extern chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes, - const x509cert_t *cert, int digest_alg, private_key_t *key); -extern chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, - int enc_alg); + certificate_t *cert, int digest_alg, + private_key_t *key); +extern chunk_t pkcs7_build_envelopedData(chunk_t data, certificate_t *cert, + int enc_alg); #endif /* _PKCS7_H */ diff --git a/src/pluto/smartcard.c b/src/pluto/smartcard.c index 8b479009f..97074f52e 100644 --- a/src/pluto/smartcard.c +++ b/src/pluto/smartcard.c @@ -386,8 +386,7 @@ static enum_names pkcs11_return_names = * The calling application is responsible for cleaning up * and calling C_Finalize() */ -static CK_RV -scx_unload_pkcs11_module(scx_pkcs11_module_t *mod) +static CK_RV scx_unload_pkcs11_module(scx_pkcs11_module_t *mod) { if (!mod || mod->_magic != SCX_MAGIC) return CKR_ARGUMENTS_BAD; @@ -400,8 +399,8 @@ scx_unload_pkcs11_module(scx_pkcs11_module_t *mod) return CKR_OK; } -static scx_pkcs11_module_t* -scx_load_pkcs11_module(const char *name, CK_FUNCTION_LIST_PTR_PTR funcs) +static scx_pkcs11_module_t* scx_load_pkcs11_module(const char *name, + CK_FUNCTION_LIST_PTR_PTR funcs) { CK_RV (*c_get_function_list)(CK_FUNCTION_LIST_PTR_PTR); scx_pkcs11_module_t *mod; @@ -437,9 +436,9 @@ failed: scx_unload_pkcs11_module(mod); /* * retrieve a certificate object */ -static bool -scx_find_cert_object(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object -, smartcard_t *sc, cert_t *cert) +static bool scx_find_cert_object(CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE object, + smartcard_t *sc, cert_t *cert) { size_t hex_len, label_len; u_char *hex_id = NULL; @@ -518,8 +517,7 @@ scx_find_cert_object(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object /* * search a given slot for PKCS#11 certificate objects */ -static void -scx_find_cert_objects(CK_SLOT_ID slot, CK_SESSION_HANDLE session) +static void scx_find_cert_objects(CK_SLOT_ID slot, CK_SESSION_HANDLE session) { CK_RV rv; CK_OBJECT_CLASS class = CKO_CERTIFICATE; @@ -616,8 +614,7 @@ scx_find_cert_objects(CK_SLOT_ID slot, CK_SESSION_HANDLE session) /* * search all slots for PKCS#11 certificate objects */ -static void -scx_find_all_cert_objects(void) +static void scx_find_all_cert_objects(void) { CK_RV rv; CK_SLOT_ID_PTR slots = NULL_PTR; @@ -696,8 +693,7 @@ scx_find_all_cert_objects(void) * init_args should be unused when we have a PKCS#11 compliant module, * but NSS softoken breaks that API. */ -void -scx_init(const char* module, const char *init_args) +void scx_init(const char* module, const char *init_args) { #ifdef SMARTCARD CK_C_INITIALIZE_ARGS args = { .pReserved = (char *)init_args, }; @@ -752,8 +748,7 @@ scx_init(const char* module, const char *init_args) /* * finalize and unload PKCS#11 cryptoki module */ -void -scx_finalize(void) +void scx_finalize(void) { #ifdef SMARTCARD while (smartcards != NULL) @@ -783,8 +778,7 @@ scx_finalize(void) /* * does a filename contain the token %smartcard? */ -bool -scx_on_smartcard(const char *filename) +bool scx_on_smartcard(const char *filename) { return strneq(filename, SCX_TOKEN, strlen(SCX_TOKEN)); } @@ -793,11 +787,9 @@ scx_on_smartcard(const char *filename) /* * find a specific object on the smartcard */ -static bool -scx_pkcs11_find_object( CK_SESSION_HANDLE session, - CK_OBJECT_HANDLE_PTR object, - CK_OBJECT_CLASS class, - const char* id) +static bool scx_pkcs11_find_object(CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE_PTR object, + CK_OBJECT_CLASS class, const char* id) { size_t len; char buf[BUF_LEN]; @@ -848,8 +840,7 @@ scx_pkcs11_find_object( CK_SESSION_HANDLE session, /* * check if a given certificate object id is found in a slot */ -static bool -scx_find_cert_id_in_slot(smartcard_t *sc, CK_SLOT_ID slot) +static bool scx_find_cert_id_in_slot(smartcard_t *sc, CK_SLOT_ID slot) { CK_SESSION_HANDLE session; CK_OBJECT_HANDLE object; @@ -905,8 +896,7 @@ scx_find_cert_id_in_slot(smartcard_t *sc, CK_SLOT_ID slot) /* * Connect to the smart card in the reader and select the correct slot */ -bool -scx_establish_context(smartcard_t *sc) +bool scx_establish_context(smartcard_t *sc) { #ifdef SMARTCARD bool id_found = FALSE; @@ -983,8 +973,7 @@ scx_establish_context(smartcard_t *sc) /* * log in to a session */ -bool -scx_login(smartcard_t *sc) +bool scx_login(smartcard_t *sc) { #ifdef SMARTCARD CK_RV rv; @@ -1031,8 +1020,7 @@ scx_login(smartcard_t *sc) /* * logout from a session */ -static void -scx_logout(smartcard_t *sc) +static void scx_logout(smartcard_t *sc) { CK_RV rv; @@ -1052,8 +1040,7 @@ scx_logout(smartcard_t *sc) /* * Release context and disconnect from card */ -void -scx_release_context(smartcard_t *sc) +void scx_release_context(smartcard_t *sc) { #ifdef SMARTCARD CK_RV rv; @@ -1083,9 +1070,8 @@ scx_release_context(smartcard_t *sc) /* * Load host certificate from smartcard */ -bool -scx_load_cert(const char *filename, smartcard_t **scp, cert_t *cert -, bool *cached) +bool scx_load_cert(const char *filename, smartcard_t **scp, cert_t *cert, + bool *cached) { #ifdef SMARTCARD /* compile with smartcard support */ CK_OBJECT_HANDLE object; @@ -1158,8 +1144,7 @@ scx_load_cert(const char *filename, smartcard_t **scp, cert_t *cert * %smartcard:45 - - 45 * %smartcard0:45 - 0 45 */ -smartcard_t* -scx_parse_number_slot_id(const char *number_slot_id) +smartcard_t* scx_parse_number_slot_id(const char *number_slot_id) { int len = strlen(number_slot_id); smartcard_t *sc = malloc_thing(smartcard_t); @@ -1218,8 +1203,7 @@ scx_parse_number_slot_id(const char *number_slot_id) /* * Verify pin on card */ -bool -scx_verify_pin(smartcard_t *sc) +bool scx_verify_pin(smartcard_t *sc) { #ifdef SMARTCARD CK_RV rv; @@ -1270,9 +1254,8 @@ scx_verify_pin(smartcard_t *sc) /* * Sign hash on smartcard */ -bool -scx_sign_hash(smartcard_t *sc, const u_char *in, size_t inlen -, u_char *out, size_t outlen) +bool scx_sign_hash(smartcard_t *sc, const u_char *in, size_t inlen, u_char *out, + size_t outlen) { #ifdef SMARTCARD CK_RV rv; @@ -1380,9 +1363,8 @@ scx_sign_hash(smartcard_t *sc, const u_char *in, size_t inlen /* * encrypt data block with an RSA public key */ -bool -scx_encrypt(smartcard_t *sc, const u_char *in, size_t inlen -, u_char *out, size_t *outlen) +bool scx_encrypt(smartcard_t *sc, const u_char *in, size_t inlen, u_char *out, + size_t *outlen) { #ifdef SMARTCARD CK_RV rv; @@ -1530,9 +1512,8 @@ scx_encrypt(smartcard_t *sc, const u_char *in, size_t inlen /* * decrypt a data block with an RSA private key */ -bool -scx_decrypt(smartcard_t *sc, const u_char *in, size_t inlen -, u_char *out, size_t *outlen) +bool scx_decrypt(smartcard_t *sc, const u_char *in, size_t inlen, u_char *out, + size_t *outlen) { #ifdef SMARTCARD CK_RV rv; @@ -1606,9 +1587,8 @@ scx_decrypt(smartcard_t *sc, const u_char *in, size_t inlen * decrypt it using a private RSA key and * return the decrypted data block via whack */ -bool -scx_op_via_whack(const char* msg, int inbase, int outbase, sc_op_t op -, const char* keyid, int whackfd) +bool scx_op_via_whack(const char* msg, int inbase, int outbase, sc_op_t op, + const char* keyid, int whackfd) { char inbuf[RSA_MAX_OCTETS]; char outbuf[2*RSA_MAX_OCTETS + 1]; @@ -1701,8 +1681,7 @@ scx_op_via_whack(const char* msg, int inbase, int outbase, sc_op_t op /* * get length of RSA key in bytes */ -size_t -scx_get_keylength(smartcard_t *sc) +size_t scx_get_keylength(smartcard_t *sc) { #ifdef SMARTCARD CK_RV rv; @@ -1737,8 +1716,7 @@ scx_get_keylength(smartcard_t *sc) /* * prompt for pin and verify it */ -bool -scx_get_pin(smartcard_t *sc, int whackfd) +bool scx_get_pin(smartcard_t *sc, int whackfd) { #ifdef SMARTCARD char pin[BUF_LEN]; @@ -1796,8 +1774,7 @@ scx_get_pin(smartcard_t *sc, int whackfd) /* * free the pin code */ -void -scx_free_pin(chunk_t *pin) +void scx_free_pin(chunk_t *pin) { if (pin->ptr != NULL) { @@ -1811,8 +1788,7 @@ scx_free_pin(chunk_t *pin) /* * frees a smartcard record */ -void -scx_free(smartcard_t *sc) +void scx_free(smartcard_t *sc) { if (sc != NULL) { @@ -1827,8 +1803,7 @@ scx_free(smartcard_t *sc) /* release of a smartcard record decreases the count by one " the record is freed when the counter reaches zero */ -void -scx_release(smartcard_t *sc) +void scx_release(smartcard_t *sc) { if (sc != NULL && --sc->count == 0) { @@ -1844,8 +1819,7 @@ scx_release(smartcard_t *sc) /* * compare two smartcard records by comparing their slots and ids */ -static bool -scx_same(smartcard_t *a, smartcard_t *b) +static bool scx_same(smartcard_t *a, smartcard_t *b) { if (a->number && b->number) { @@ -1863,8 +1837,7 @@ scx_same(smartcard_t *a, smartcard_t *b) /* for each link pointing to the smartcard record " increase the count by one */ -void -scx_share(smartcard_t *sc) +void scx_share(smartcard_t *sc) { if (sc != NULL) sc->count++; @@ -1873,8 +1846,7 @@ scx_share(smartcard_t *sc) /* * adds a smartcard record to the chained list */ -smartcard_t* -scx_add(smartcard_t *smartcard) +smartcard_t* scx_add(smartcard_t *smartcard) { smartcard_t *sc = smartcards; smartcard_t **psc = &smartcards; @@ -1903,8 +1875,7 @@ scx_add(smartcard_t *smartcard) /* * get the smartcard that belongs to an X.509 certificate */ -smartcard_t* -scx_get(x509cert_t *cert) +smartcard_t* scx_get(x509cert_t *cert) { smartcard_t *sc = smartcards; @@ -1920,8 +1891,7 @@ scx_get(x509cert_t *cert) /* * prints either the slot number or 'any slot' */ -char * -scx_print_slot(smartcard_t *sc, const char *whitespace) +char *scx_print_slot(smartcard_t *sc, const char *whitespace) { char *buf = temporary_cyclic_buffer(); @@ -1935,8 +1905,7 @@ scx_print_slot(smartcard_t *sc, const char *whitespace) /* * list all smartcard info records in a chained list */ -void -scx_list(bool utc) +void scx_list(bool utc) { smartcard_t *sc = smartcards; @@ -1966,10 +1935,10 @@ scx_list(bool utc) whack_log(RC_COMMENT, " label: '%s'", sc->label); if (sc->last_cert.type == CERT_X509_SIGNATURE) { - char buf[BUF_LEN]; + certificate_t *certificate = sc->last_cert.u.x509->cert; - dntoa(buf, BUF_LEN, sc->last_cert.u.x509->subject); - whack_log(RC_COMMENT, " subject: '%s'", buf); + whack_log(RC_COMMENT, " subject: '%Y'", + certificate->get_subject(certificate)); } sc = sc->next; } diff --git a/src/pluto/x509.c b/src/pluto/x509.c index f1d079560..d0a57b39a 100644 --- a/src/pluto/x509.c +++ b/src/pluto/x509.c @@ -49,18 +49,6 @@ static x509cert_t *x509certs = NULL; /** - * ASN.1 definition of a basicConstraints extension - */ -static const asn1Object_t basicConstraintsObjects[] = { - { 0, "basicConstraints", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "CA", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 1 */ - { 1, "pathLenConstraint", ASN1_INTEGER, ASN1_OPT|ASN1_BODY }, /* 2 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define BASIC_CONSTRAINTS_CA 1 - -/** * ASN.1 definition of a authorityKeyIdentifier extension */ static const asn1Object_t authKeyIdentifierObjects[] = { @@ -78,31 +66,6 @@ static const asn1Object_t authKeyIdentifierObjects[] = { #define AUTH_KEY_ID_CERT_SERIAL 5 /** - * ASN.1 definition of a authorityInfoAccess extension - */ -static const asn1Object_t authInfoAccessObjects[] = { - { 0, "authorityInfoAccess", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ - { 1, "accessDescription", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ - { 2, "accessMethod", ASN1_OID, ASN1_BODY }, /* 2 */ - { 2, "accessLocation", ASN1_EOC, ASN1_RAW }, /* 3 */ - { 0, "end loop", ASN1_EOC, ASN1_END }, /* 4 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define AUTH_INFO_ACCESS_METHOD 2 -#define AUTH_INFO_ACCESS_LOCATION 3 - -/** - * ASN.1 definition of a extendedKeyUsage extension - */ -static const asn1Object_t extendedKeyUsageObjects[] = { - { 0, "extendedKeyUsage", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ - { 1, "keyPurposeID", ASN1_OID, ASN1_BODY }, /* 1 */ - { 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define EXT_KEY_USAGE_PURPOSE_ID 1 - -/** * ASN.1 definition of generalNames */ static const asn1Object_t generalNamesObjects[] = { @@ -158,109 +121,13 @@ static const asn1Object_t otherNameObjects[] = { #define ON_OBJ_ID_TYPE 0 #define ON_OBJ_VALUE 1 -/** - * ASN.1 definition of crlDistributionPoints - */ -static const asn1Object_t crlDistributionPointsObjects[] = { - { 0, "crlDistributionPoints", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ - { 1, "DistributionPoint", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ - { 2, "distributionPoint", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_LOOP }, /* 2 */ - { 3, "fullName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_OBJ }, /* 3 */ - { 3, "end choice", ASN1_EOC, ASN1_END }, /* 4 */ - { 3, "nameRelToCRLIssuer",ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY }, /* 5 */ - { 3, "end choice", ASN1_EOC, ASN1_END }, /* 6 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 7 */ - { 2, "reasons", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY }, /* 8 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 9 */ - { 2, "crlIssuer", ASN1_CONTEXT_C_2, ASN1_OPT|ASN1_BODY }, /* 10 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 11 */ - { 0, "end loop", ASN1_EOC, ASN1_END }, /* 12 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define CRL_DIST_POINTS_FULLNAME 3 - -/** - * ASN.1 definition of an X.509v3 x509_cert - */ -static const asn1Object_t certObjects[] = { - { 0, "x509", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ - { 1, "tbsCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ - { 2, "DEFAULT v1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 2 */ - { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */ - { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 4 */ - { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 5 */ - { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */ - { 2, "validity", ASN1_SEQUENCE, ASN1_NONE }, /* 7 */ - { 3, "notBefore", ASN1_EOC, ASN1_RAW }, /* 8 */ - { 3, "notAfter", ASN1_EOC, ASN1_RAW }, /* 9 */ - { 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */ - { 2, "subjectPublicKeyInfo",ASN1_SEQUENCE, ASN1_RAW }, /* 11 */ - { 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 13 */ - { 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 14 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 15 */ - { 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 16 */ - { 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 17 */ - { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 18 */ - { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 19 */ - { 5, "critical", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 20 */ - { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 21 */ - { 3, "end loop", ASN1_EOC, ASN1_END }, /* 22 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 23 */ - { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 24 */ - { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 25 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define X509_OBJ_CERTIFICATE 0 -#define X509_OBJ_TBS_CERTIFICATE 1 -#define X509_OBJ_VERSION 3 -#define X509_OBJ_SERIAL_NUMBER 4 -#define X509_OBJ_SIG_ALG 5 -#define X509_OBJ_ISSUER 6 -#define X509_OBJ_NOT_BEFORE 8 -#define X509_OBJ_NOT_AFTER 9 -#define X509_OBJ_SUBJECT 10 -#define X509_OBJ_SUBJECT_PUBLIC_KEY_INFO 11 -#define X509_OBJ_EXTN_ID 19 -#define X509_OBJ_CRITICAL 20 -#define X509_OBJ_EXTN_VALUE 21 -#define X509_OBJ_ALGORITHM 24 -#define X509_OBJ_SIGNATURE 25 - const x509cert_t empty_x509cert = { + NULL , /* cert */ NULL , /* *next */ UNDEFINED_TIME, /* installed */ 0 , /* count */ FALSE , /* smartcard */ AUTH_NONE , /* authority_flags */ - { NULL, 0 } , /* certificate */ - { NULL, 0 } , /* tbsCertificate */ - 1 , /* version */ - { NULL, 0 } , /* serialNumber */ - OID_UNKNOWN , /* sigAlg */ - { NULL, 0 } , /* issuer */ - /* validity */ - 0 , /* notBefore */ - 0 , /* notAfter */ - { NULL, 0 } , /* subject */ - NULL , /* public_key */ - /* issuerUniqueID */ - /* subjectUniqueID */ - /* extensions */ - /* extension */ - /* extnID */ - /* critical */ - /* extnValue */ - FALSE , /* isCA */ - FALSE , /* isOcspSigner */ - { NULL, 0 } , /* subjectKeyID */ - { NULL, 0 } , /* authKeyID */ - { NULL, 0 } , /* authKeySerialNumber */ - { NULL, 0 } , /* accessLocation */ - NULL , /* subjectAltName */ - NULL , /* crlDistributionPoints */ - OID_UNKNOWN , /* algorithm */ - { NULL, 0 } /* signature */ }; /* coding of X.501 distinguished name */ @@ -333,10 +200,6 @@ static const x501rdn_t x501rdns[] = { #define X501_RDN_ROOF 26 -static chunk_t ASN1_subjectAltName_oid = chunk_from_chars( - 0x06, 0x03, 0x55, 0x1D, 0x11 -); - static void update_chunk(chunk_t *ch, int n) { n = (n > -1 && n < (int)ch->len)? n : (int)ch->len-1; @@ -947,14 +810,6 @@ bool match_dn(chunk_t a, chunk_t b, int *wildcards) } /** - * Compare two X.509 certificates by comparing their signatures - */ -bool same_x509cert(const x509cert_t *a, const x509cert_t *b) -{ - return chunk_equals(a->signature, b->signature); -} - -/** * For each link pointing to the certificate increase the count by one */ void share_x509cert(x509cert_t *cert) @@ -970,11 +825,12 @@ void share_x509cert(x509cert_t *cert) */ x509cert_t* add_x509cert(x509cert_t *cert) { + certificate_t *certificate = cert->cert; x509cert_t *c = x509certs; while (c != NULL) { - if (same_x509cert(c, cert)) /* already in chain, free cert */ + if (certificate->equals(certificate, c->cert)) /* already in chain, free cert */ { free_x509cert(cert); return c; @@ -998,39 +854,47 @@ x509cert_t* add_x509cert(x509cert_t *cert) */ void select_x509cert_id(x509cert_t *cert, struct id *end_id) { + certificate_t *certificate = cert->cert; + x509_t *x509 = (x509_t*)certificate; + identification_t *subjectAltName; + bool copy_subject_dn = TRUE; /* ID is subject DN */ if (end_id->kind != ID_ANY) /* check for matching subjectAltName */ { - generalName_t *gn = cert->subjectAltName; + enumerator_t *enumerator; - while (gn != NULL) + enumerator = x509->create_subjectAltName_enumerator(x509); + while (enumerator->enumerate(enumerator, &subjectAltName)) { struct id id = empty_id; - gntoid(&id, gn); + id_from_identification(&id, subjectAltName); if (same_id(&id, end_id)) { copy_subject_dn = FALSE; /* take subjectAltName instead */ break; } - gn = gn->next; } + enumerator->destroy(enumerator); } if (copy_subject_dn) { + identification_t *subject = certificate->get_subject(certificate); + chunk_t subject_dn = subject->get_encoding(subject); + if (end_id->kind != ID_ANY && end_id->kind != ID_DER_ASN1_DN) { - char buf[BUF_LEN]; + char buf[BUF_LEN]; - idtoa(end_id, buf, BUF_LEN); - plog(" no subjectAltName matches ID '%s', replaced by subject DN", buf); + idtoa(end_id, buf, BUF_LEN); + plog(" no subjectAltName matches ID '%s', replaced by subject DN", buf); } end_id->kind = ID_DER_ASN1_DN; - end_id->name.len = cert->subject.len; + end_id->name.len = subject_dn.len; end_id->name.ptr = temporary_cyclic_buffer(); - memcpy(end_id->name.ptr, cert->subject.ptr, cert->subject.len); + memcpy(end_id->name.ptr, subject_dn.ptr, subject_dn.len); } } @@ -1047,31 +911,22 @@ bool same_keyid(chunk_t a, chunk_t b) } /** - * Check for equality between two serial numbers - */ -bool same_serial(chunk_t a, chunk_t b) -{ - /* do not compare serial numbers if one of them is not defined */ - if (a.ptr == NULL || b.ptr == NULL) - { - return TRUE; - } - return chunk_equals(a, b); -} - -/** * Get a X.509 certificate with a given issuer found at a certain position */ -x509cert_t* get_x509cert(chunk_t issuer, chunk_t serial, chunk_t keyid, - x509cert_t *chain) +x509cert_t* get_x509cert(chunk_t issuer, chunk_t keyid, x509cert_t *chain) { x509cert_t *cert = (chain != NULL)? chain->next : x509certs; while (cert != NULL) { - if ((keyid.ptr != NULL) ? same_keyid(keyid, cert->authKeyID) - : (same_dn(issuer, cert->issuer) - && same_serial(serial, cert->authKeySerialNumber))) + certificate_t *certificate = cert->cert; + x509_t *x509 = (x509_t*)certificate; + identification_t *cert_issuer = certificate->get_issuer(certificate); + chunk_t cert_issuer_dn = cert_issuer->get_encoding(cert_issuer); + chunk_t authKeyID = x509->get_authKeyIdentifier(x509); + + if ((keyid.ptr != NULL) ? same_keyid(keyid, authKeyID) + : same_dn(issuer, cert_issuer_dn)) { return cert; } @@ -1081,92 +936,6 @@ x509cert_t* get_x509cert(chunk_t issuer, chunk_t serial, chunk_t keyid, } /** - * Encode a linked list of subjectAltNames - */ -chunk_t build_subjectAltNames(generalName_t *subjectAltNames) -{ - u_char *pos; - chunk_t names; - size_t len = 0; - generalName_t *gn = subjectAltNames; - - /* compute the total size of the ASN.1 attributes object */ - while (gn != NULL) - { - len += gn->name.len; - gn = gn->next; - } - - pos = asn1_build_object(&names, ASN1_SEQUENCE, len); - - gn = subjectAltNames; - while (gn != NULL) - { - chunkcpy(pos, gn->name); - gn = gn->next; - } - - return asn1_wrap(ASN1_SEQUENCE, "cm" - , ASN1_subjectAltName_oid - , asn1_wrap(ASN1_OCTET_STRING, "m", names)); -} - -/** - * Build a to-be-signed X.509 certificate body - */ -static chunk_t build_tbs_x509cert(x509cert_t *cert, public_key_t *rsa) -{ - /* version is always X.509v3 */ - chunk_t version = asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2); - chunk_t key = chunk_empty; - chunk_t extensions = chunk_empty; - - rsa->get_encoding(rsa, KEY_PUB_ASN1_DER, &key); - - chunk_t keyInfo = asn1_wrap(ASN1_SEQUENCE, "mm", - asn1_algorithmIdentifier(OID_RSA_ENCRYPTION), - asn1_bitstring("m", key)); - - if (cert->subjectAltName != NULL) - { - extensions = asn1_wrap(ASN1_CONTEXT_C_3, "m" - , asn1_wrap(ASN1_SEQUENCE, "m" - , build_subjectAltNames(cert->subjectAltName))); - } - - return asn1_wrap(ASN1_SEQUENCE, "mmmcmcmm" - , version - , asn1_integer("c", cert->serialNumber) - , asn1_algorithmIdentifier(cert->sigAlg) - , cert->issuer - , asn1_wrap(ASN1_SEQUENCE, "mm" - , asn1_from_time(&cert->notBefore, ASN1_UTCTIME) - , asn1_from_time(&cert->notAfter, ASN1_UTCTIME) - ) - , cert->subject - , keyInfo - , extensions - ); -} - -/** - * Build a DER-encoded X.509 certificate - */ -void build_x509cert(x509cert_t *cert, public_key_t *cert_key, - private_key_t *signer_key) -{ - chunk_t tbs_cert = build_tbs_x509cert(cert, cert_key); - - chunk_t signature = x509_build_signature(tbs_cert, cert->sigAlg - , signer_key, TRUE); - - cert->certificate = asn1_wrap(ASN1_SEQUENCE, "mmm" - , tbs_cert - , asn1_algorithmIdentifier(cert->sigAlg) - , signature); -} - -/** * Free the dynamic memory used to store generalNames */ void free_generalNames(generalName_t* gn, bool free_name) @@ -1190,10 +959,12 @@ void free_x509cert(x509cert_t *cert) { if (cert != NULL) { - DESTROY_IF(cert->public_key); - free_generalNames(cert->subjectAltName, FALSE); - free_generalNames(cert->crlDistributionPoints, FALSE); - free(cert->certificate.ptr); + certificate_t *certificate = cert->cert; + + if (certificate) + { + certificate->destroy(certificate); + } free(cert); cert = NULL; } @@ -1230,13 +1001,16 @@ void store_x509certs(x509cert_t **firstcert, bool strict) while (*pp != NULL) { x509cert_t *cert = *pp; + certificate_t *certificate = cert->cert; + x509_t *x509 = (x509_t*)certificate; + x509_flag_t flags = x509->get_flags(x509); - if (cert->isCA) + if (flags & X509_CA) { *pp = cert->next; /* we don't accept self-signed CA certs */ - if (same_dn(cert->issuer, cert->subject)) + if (flags & X509_SELF_SIGNED) { plog("self-signed cacert rejected"); free_x509cert(cert); @@ -1302,16 +1076,27 @@ void store_x509certs(x509cert_t **firstcert, bool strict) * Check if a signature over binary blob is genuine */ bool x509_check_signature(chunk_t tbs, chunk_t sig, int algorithm, - const x509cert_t *issuer_cert) + certificate_t *issuer_cert) { - public_key_t *key = issuer_cert->public_key; - signature_scheme_t scheme = signature_scheme_from_oid(algorithm); + bool success; + public_key_t *key; + signature_scheme_t scheme; + scheme = signature_scheme_from_oid(algorithm); if (scheme == SIGN_UNKNOWN) { return FALSE; } - return key->verify(key, scheme, tbs, sig); + + key = issuer_cert->get_public_key(issuer_cert); + if (key == NULL) + { + return FALSE; + } + success = key->verify(key, scheme, tbs, sig); + key->destroy(key); + + return success; } /** @@ -1332,82 +1117,6 @@ chunk_t x509_build_signature(chunk_t tbs, int algorithm, private_key_t *key, } /** - * Extracts the basicConstraints extension - */ -static bool parse_basicConstraints(chunk_t blob, int level0) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - bool isCA = FALSE; - - parser = asn1_parser_create(basicConstraintsObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - if (objectID == BASIC_CONSTRAINTS_CA) - { - isCA = object.len && *object.ptr; - DBG(DBG_PARSING, - DBG_log(" %s",(isCA)?"TRUE":"FALSE"); - ) - } - } - parser->destroy(parser); - - return isCA; -} - -/** - * Converts a X.500 generalName into an ID - */ -void gntoid(struct id *id, const generalName_t *gn) -{ - switch(gn->kind) - { - case GN_DNS_NAME: /* ID type: ID_FQDN */ - id->kind = ID_FQDN; - id->name = gn->name; - break; - case GN_IP_ADDRESS: /* ID type: ID_IPV4_ADDR */ - { - const struct af_info *afi = &af_inet4_info; - err_t ugh = NULL; - - id->kind = afi->id_addr; - ugh = initaddr(gn->name.ptr, gn->name.len, afi->af, &id->ip_addr); - } - break; - case GN_RFC822_NAME: /* ID type: ID_USER_FQDN */ - id->kind = ID_USER_FQDN; - id->name = gn->name; - break; - default: - id->kind = ID_ANY; - id->name = chunk_empty; - } -} - -/** - * Compute the subjectKeyIdentifier according to section 4.2.1.2 of RFC 3280 - * as the 160 bit SHA-1 hash of the public key - */ -bool compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID) -{ - chunk_t fingerprint; - - if (!cert->public_key->get_fingerprint(cert->public_key, KEY_ID_PUBKEY_SHA1, - &fingerprint)) - { - plog(" unable to compute subjectKeyID"); - return FALSE; - } - memcpy(subjectKeyID.ptr, fingerprint.ptr, subjectKeyID.len); - return TRUE; -} - -/** * Extracts an otherName */ static bool parse_otherName(chunk_t blob, int level0) @@ -1608,294 +1317,31 @@ void parse_authorityKeyIdentifier(chunk_t blob, int level0, } /** - * Extracts an authorityInfoAcess location - */ -static void parse_authorityInfoAccess(chunk_t blob, int level0, - chunk_t *accessLocation) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - int accessMethod = OID_UNKNOWN; - - parser = asn1_parser_create(authInfoAccessObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - switch (objectID) - { - case AUTH_INFO_ACCESS_METHOD: - accessMethod = asn1_known_oid(object); - break; - case AUTH_INFO_ACCESS_LOCATION: - { - switch (accessMethod) - { - case OID_OCSP: - if (*object.ptr == ASN1_CONTEXT_S_6) - { - if (asn1_length(&object) == ASN1_INVALID_LENGTH) - { - goto end; - } - DBG(DBG_PARSING, - DBG_log(" '%.*s'",(int)object.len, object.ptr) - ) - - /* only HTTP(S) URIs accepted */ - if (strncasecmp(object.ptr, "http", 4) == 0) - { - *accessLocation = object; - goto end; - } - } - plog("warning: ignoring OCSP InfoAccessLocation with unkown protocol"); - break; - default: - /* unkown accessMethod, ignoring */ - break; - } - } - break; - default: - break; - } - } - -end: - parser->destroy(parser); -} - -/** - * Extracts extendedKeyUsage OIDs - */ -static bool parse_extendedKeyUsage(chunk_t blob, int level0) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - bool ocsp_signing = FALSE; - - parser = asn1_parser_create(extendedKeyUsageObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - if (objectID == EXT_KEY_USAGE_PURPOSE_ID - && asn1_known_oid(object) == OID_OCSP_SIGNING) - { - ocsp_signing = TRUE; - } - } - parser->destroy(parser); - - return ocsp_signing; -} - -/** - * Extracts one or several crlDistributionPoints - * and puts them into a chained list - */ -static generalName_t* parse_crlDistributionPoints(chunk_t blob, int level0) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - - generalName_t *top_gn = NULL; /* top of the chained list */ - generalName_t **tail_gn = &top_gn; /* tail of the chained list */ - - parser = asn1_parser_create(crlDistributionPointsObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - if (objectID == CRL_DIST_POINTS_FULLNAME) - { - generalName_t *gn; - - gn = parse_generalNames(object, parser->get_level(parser)+1, TRUE); - /* append extracted generalNames to existing chained list */ - *tail_gn = gn; - /* find new tail of the chained list */ - while (gn != NULL) - { - tail_gn = &gn->next; gn = gn->next; - } - } - } - parser->destroy(parser); - - return top_gn; -} - -/** - * Parses an X.509v3 certificate - */ -bool parse_x509cert(chunk_t blob, u_int level0, x509cert_t *cert) -{ - u_char buf[BUF_LEN]; - asn1_parser_t *parser; - chunk_t object; - int objectID; - int extn_oid = OID_UNKNOWN; - bool critical; - bool success = FALSE; - - parser = asn1_parser_create(certObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - u_int level = parser->get_level(parser) + 1; - - switch (objectID) { - case X509_OBJ_CERTIFICATE: - cert->certificate = object; - break; - case X509_OBJ_TBS_CERTIFICATE: - cert->tbsCertificate = object; - break; - case X509_OBJ_VERSION: - cert->version = (object.len) ? (1+(u_int)*object.ptr) : 1; - DBG(DBG_PARSING, - DBG_log(" v%d", cert->version); - ) - break; - case X509_OBJ_SERIAL_NUMBER: - cert->serialNumber = object; - break; - case X509_OBJ_SIG_ALG: - cert->sigAlg = asn1_parse_algorithmIdentifier(object, level, NULL); - break; - case X509_OBJ_ISSUER: - cert->issuer = object; - DBG(DBG_PARSING, - dntoa(buf, BUF_LEN, object); - DBG_log(" '%s'",buf) - ) - break; - case X509_OBJ_NOT_BEFORE: - cert->notBefore = asn1_parse_time(object, level); - break; - case X509_OBJ_NOT_AFTER: - cert->notAfter = asn1_parse_time(object, level); - break; - case X509_OBJ_SUBJECT: - cert->subject = object; - DBG(DBG_PARSING, - dntoa(buf, BUF_LEN, object); - DBG_log(" '%s'",buf) - ) - break; - case X509_OBJ_SUBJECT_PUBLIC_KEY_INFO: - cert->public_key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, - KEY_ANY, BUILD_BLOB_ASN1_DER, object, BUILD_END); - if (cert->public_key == NULL) - { - goto end; - } - break; - case X509_OBJ_EXTN_ID: - extn_oid = asn1_known_oid(object); - break; - case X509_OBJ_CRITICAL: - critical = object.len && *object.ptr; - DBG(DBG_PARSING, - DBG_log(" %s",(critical)?"TRUE":"FALSE"); - ) - break; - case X509_OBJ_EXTN_VALUE: - { - switch (extn_oid) { - case OID_SUBJECT_KEY_ID: - if (!asn1_parse_simple_object(&object, ASN1_OCTET_STRING, - level, "keyIdentifier")) - { - goto end; - } - cert->subjectKeyID = object; - break; - case OID_SUBJECT_ALT_NAME: - cert->subjectAltName = - parse_generalNames(object, level, FALSE); - break; - case OID_BASIC_CONSTRAINTS: - cert->isCA = - parse_basicConstraints(object, level); - break; - case OID_CRL_DISTRIBUTION_POINTS: - cert->crlDistributionPoints = - parse_crlDistributionPoints(object, level); - break; - case OID_AUTHORITY_KEY_ID: - parse_authorityKeyIdentifier(object, level - , &cert->authKeyID, &cert->authKeySerialNumber); - break; - case OID_AUTHORITY_INFO_ACCESS: - parse_authorityInfoAccess(object, level, &cert->accessLocation); - break; - case OID_EXTENDED_KEY_USAGE: - cert->isOcspSigner = parse_extendedKeyUsage(object, level); - break; - case OID_NS_REVOCATION_URL: - case OID_NS_CA_REVOCATION_URL: - case OID_NS_CA_POLICY_URL: - case OID_NS_COMMENT: - if (!asn1_parse_simple_object(&object, ASN1_IA5STRING - , level, oid_names[extn_oid].name)) - { - goto end; - } - break; - default: - break; - } - } - break; - case X509_OBJ_ALGORITHM: - cert->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL); - break; - case X509_OBJ_SIGNATURE: - cert->signature = object; - break; - default: - break; - } - } - success = parser->success(parser); - time(&cert->installed); - -end: - parser->destroy(parser); - return success; -} - -/** * Verify the validity of a certificate by * checking the notBefore and notAfter dates */ err_t check_validity(const x509cert_t *cert, time_t *until) { - time_t current_time; - + time_t current_time, notBefore, notAfter; + certificate_t *certificate = cert->cert; + time(¤t_time); + certificate->get_validity(certificate, ¤t_time, ¬Before, ¬After); DBG(DBG_CONTROL | DBG_PARSING , - DBG_log(" not before : %T", &cert->notBefore, TRUE); + DBG_log(" not before : %T", ¬Before, TRUE); DBG_log(" current time: %T", ¤t_time, TRUE); - DBG_log(" not after : %T", &cert->notAfter, TRUE); + DBG_log(" not after : %T", ¬After, TRUE); ) - if (cert->notAfter < *until) + if (*until == 0 || notAfter < *until) { - *until = cert->notAfter; + *until = notAfter; } - if (current_time < cert->notBefore) + if (current_time < notBefore) { return "certificate is not valid yet"; } - if (current_time > cert->notAfter) + if (current_time > notAfter) { return "certificate has expired"; } @@ -1912,24 +1358,24 @@ bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until) { int pathlen; - *until = cert->notAfter; + *until = 0; for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++) { + certificate_t *certificate = cert->cert; + identification_t *subject = certificate->get_subject(certificate); + identification_t *issuer = certificate->get_issuer(certificate); + x509_t *x509 = (x509_t*)certificate; + chunk_t authKeyID = x509->get_authKeyIdentifier(x509); x509cert_t *issuer_cert; - u_char buf[BUF_LEN]; err_t ugh = NULL; DBG(DBG_CONTROL, - dntoa(buf, BUF_LEN, cert->subject); - DBG_log("subject: '%s'",buf); - dntoa(buf, BUF_LEN, cert->issuer); - DBG_log("issuer: '%s'",buf); - if (cert->authKeyID.ptr != NULL) + DBG_log("subject: '%Y'", subject); + DBG_log("issuer: '%Y'", issuer); + if (authKeyID.ptr != NULL) { - datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':' - , buf, BUF_LEN); - DBG_log("authkey: %s", buf); + DBG_log("authkey: %#B", &authKeyID); } ) @@ -1946,9 +1392,8 @@ bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until) ) lock_authcert_list("verify_x509cert"); - issuer_cert = get_authcert(cert->issuer, cert->authKeySerialNumber - , cert->authKeyID, AUTH_CA); - + issuer_cert = get_authcert(issuer->get_encoding(issuer), + authKeyID, AUTH_CA); if (issuer_cert == NULL) { plog("issuer cacert not found"); @@ -1959,8 +1404,7 @@ bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until) DBG_log("issuer cacert found") ) - if (!x509_check_signature(cert->tbsCertificate, cert->signature, - cert->algorithm, issuer_cert)) + if (!certificate->issued_by(certificate, issuer_cert->cert)) { plog("certificate signature is invalid"); unlock_authcert_list("verify_x509cert"); @@ -1972,7 +1416,7 @@ bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until) unlock_authcert_list("verify_x509cert"); /* check if cert is a self-signed root ca */ - if (pathlen > 0 && same_dn(cert->issuer, cert->subject)) + if (pathlen > 0 && (x509->get_flags(x509) & X509_SELF_SIGNED)) { DBG(DBG_CONTROL, DBG_log("reached self-signed root ca") @@ -2063,11 +1507,13 @@ void list_x509cert_chain(const char *caption, x509cert_t* cert, { if (auth_flags == AUTH_NONE || (auth_flags & cert->authority_flags)) { - u_char buf[BUF_LEN]; - public_key_t *key = cert->public_key; - chunk_t keyid; + time_t notBefore, notAfter; + public_key_t *key; + chunk_t serial, keyid, subjkey, authkey; cert_t c; - + certificate_t *certificate = cert->cert; + x509_t *x509 = (x509_t*)certificate; + c.type = CERT_X509_SIGNATURE; c.u.x509 = cert; @@ -2081,45 +1527,47 @@ void list_x509cert_chain(const char *caption, x509cert_t* cert, whack_log(RC_COMMENT, "%T, count: %d", &cert->installed, utc, cert->count); - dntoa(buf, BUF_LEN, cert->subject); - whack_log(RC_COMMENT, " subject: '%s'", buf); - dntoa(buf, BUF_LEN, cert->issuer); - whack_log(RC_COMMENT, " issuer: '%s'", buf); - datatot(cert->serialNumber.ptr, cert->serialNumber.len, ':', - buf, BUF_LEN); - whack_log(RC_COMMENT, " serial: %s", buf); + whack_log(RC_COMMENT, " subject: '%Y'", + certificate->get_subject(certificate)); + whack_log(RC_COMMENT, " issuer: '%Y'", + certificate->get_issuer(certificate)); + serial = x509->get_serial(x509); + whack_log(RC_COMMENT, " serial: %#B", &serial); + + /* list validity */ + certificate->get_validity(certificate, &now, ¬Before, ¬After); whack_log(RC_COMMENT, " validity: not before %T %s", - &cert->notBefore, utc, - (cert->notBefore < now)?"ok":"fatal (not valid yet)"); + ¬Before, utc, + (notBefore < now)?"ok":"fatal (not valid yet)"); whack_log(RC_COMMENT, " not after %T %s", - &cert->notAfter, utc, - check_expiry(cert->notAfter, CA_CERT_WARNING_INTERVAL, TRUE)); - whack_log(RC_COMMENT, " pubkey: %N %4d bits%s", - key_type_names, key->get_type(key), - key->get_keysize(key) * BITS_PER_BYTE, - cert->smartcard ? ", on smartcard" : - (has_private_key(c)? ", has private key" : "")); - if (key->get_fingerprint(key, KEY_ID_PUBKEY_INFO_SHA1, &keyid)) - { - whack_log(RC_COMMENT, " keyid: %#B", &keyid); - } - if (cert->subjectKeyID.ptr != NULL) - { - datatot(cert->subjectKeyID.ptr, cert->subjectKeyID.len, ':', - buf, BUF_LEN); - whack_log(RC_COMMENT, " subjkey: %s", buf); - } - if (cert->authKeyID.ptr != NULL) + ¬After, utc, + check_expiry(notAfter, CA_CERT_WARNING_INTERVAL, TRUE)); + + key = certificate->get_public_key(certificate); + if (key); { - datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':', - buf, BUF_LEN); - whack_log(RC_COMMENT, " authkey: %s", buf); + whack_log(RC_COMMENT, " pubkey: %N %4d bits%s", + key_type_names, key->get_type(key), + key->get_keysize(key) * BITS_PER_BYTE, + cert->smartcard ? ", on smartcard" : + (has_private_key(c)? ", has private key" : "")); + + if (key->get_fingerprint(key, KEY_ID_PUBKEY_INFO_SHA1, &keyid)) + { + whack_log(RC_COMMENT, " keyid: %#B", &keyid); + } + if (key->get_fingerprint(key, KEY_ID_PUBKEY_SHA1, &subjkey)) + { + whack_log(RC_COMMENT, " subjkey: %#B", &subjkey); + } + key->destroy(key); } - if (cert->authKeySerialNumber.ptr != NULL) + + /* list optional authorityKeyIdentifier */ + authkey = x509->get_authKeyIdentifier(x509); + if (authkey.ptr) { - datatot(cert->authKeySerialNumber.ptr, - cert->authKeySerialNumber.len, ':', buf, BUF_LEN); - whack_log(RC_COMMENT, " aserial: %s", buf); + whack_log(RC_COMMENT, " authkey: %#B", &authkey); } } cert = cert->next; diff --git a/src/pluto/x509.h b/src/pluto/x509.h index 6c1b4a6ca..490ffc370 100644 --- a/src/pluto/x509.h +++ b/src/pluto/x509.h @@ -20,7 +20,7 @@ #include <credentials/keys/public_key.h> #include <credentials/keys/private_key.h> - +#include <credentials/certificates/x509.h> #include "constants.h" #include "id.h" @@ -53,80 +53,39 @@ struct generalName { typedef struct x509cert x509cert_t; struct x509cert { + certificate_t *cert; x509cert_t *next; - time_t installed; - int count; - bool smartcard; - u_char authority_flags; - chunk_t certificate; - chunk_t tbsCertificate; - u_int version; - chunk_t serialNumber; - /* signature */ - int sigAlg; - chunk_t issuer; - /* validity */ - time_t notBefore; - time_t notAfter; - chunk_t subject; - public_key_t *public_key; - /* issuerUniqueID */ - /* subjectUniqueID */ - /* v3 extensions */ - /* extension */ - /* extension */ - /* extnID */ - /* critical */ - /* extnValue */ - bool isCA; - bool isOcspSigner; /* ocsp */ - chunk_t subjectKeyID; - chunk_t authKeyID; - chunk_t authKeySerialNumber; - chunk_t accessLocation; /* ocsp */ - generalName_t *subjectAltName; - generalName_t *crlDistributionPoints; - /* signatureAlgorithm */ - int algorithm; - chunk_t signature; + time_t installed; + int count; + bool smartcard; + u_char authority_flags; }; /* used for initialization */ extern const x509cert_t empty_x509cert; -extern bool same_serial(chunk_t a, chunk_t b); extern bool same_keyid(chunk_t a, chunk_t b); extern bool same_dn(chunk_t a, chunk_t b); extern bool match_dn(chunk_t a, chunk_t b, int *wildcards); -extern bool same_x509cert(const x509cert_t *a, const x509cert_t *b); extern void hex_str(chunk_t bin, chunk_t *str); extern int dn_count_wildcards(chunk_t dn); extern int dntoa(char *dst, size_t dstlen, chunk_t dn); extern int dntoa_or_null(char *dst, size_t dstlen, chunk_t dn, const char* null_dn); extern err_t atodn(char *src, chunk_t *dn); -extern void gntoid(struct id *id, const generalName_t *gn); -extern bool compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID); extern void select_x509cert_id(x509cert_t *cert, struct id *end_id); -extern bool parse_x509cert(chunk_t blob, u_int level0, x509cert_t *cert); -extern time_t parse_time(chunk_t blob, int level0); -extern void parse_authorityKeyIdentifier(chunk_t blob, int level0 - , chunk_t *authKeyID, chunk_t *authKeySerialNumber); +extern void parse_authorityKeyIdentifier(chunk_t blob, int level0, + chunk_t *authKeyID, + chunk_t *authKeySerialNumber); extern chunk_t get_directoryName(chunk_t blob, int level, bool implicit); extern err_t check_validity(const x509cert_t *cert, time_t *until); - extern bool x509_check_signature(chunk_t tbs, chunk_t sig, int algorithm, - const x509cert_t *issuer_cert); + certificate_t *issuer_cert); extern chunk_t x509_build_signature(chunk_t tbs, int algorithm, private_key_t *key, bool bit_string); - extern bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until); extern x509cert_t* add_x509cert(x509cert_t *cert); -extern x509cert_t* get_x509cert(chunk_t issuer, chunk_t serial, chunk_t keyid, - x509cert_t* chain); -extern void build_x509cert(x509cert_t *cert, public_key_t *cert_key, - private_key_t *signer_key); -extern chunk_t build_subjectAltNames(generalName_t *subjectAltNames); +extern x509cert_t* get_x509cert(chunk_t issuer, chunk_t keyid, x509cert_t* chain); extern void share_x509cert(x509cert_t *cert); extern void release_x509cert(x509cert_t *cert); extern void free_x509cert(x509cert_t *cert); |