From f565d0c575f9d7e4a53e10ee447871fea21cb2e3 Mon Sep 17 00:00:00 2001 From: Andreas Steffen Date: Tue, 10 Nov 2009 23:54:04 +0100 Subject: [PATCH] merged pluto's PGP certificate parsing with charon's --- src/pluto/Makefile.am | 1 - src/pluto/ac.c | 2 +- src/pluto/builder.c | 50 ++--- src/pluto/ca.c | 65 +++--- src/pluto/ca.h | 9 +- src/pluto/certs.c | 207 ++++++++++++------ src/pluto/certs.h | 45 ++-- src/pluto/connections.c | 110 ++++------ src/pluto/connections.h | 2 +- src/pluto/crl.c | 7 +- src/pluto/crl.h | 3 +- src/pluto/ike_alg.c | 5 +- src/pluto/ipsec_doi.c | 43 ++-- src/pluto/keys.c | 112 +++++----- src/pluto/keys.h | 12 +- src/pluto/ocsp.c | 22 +- src/pluto/ocsp.h | 4 +- src/pluto/pgpcert.c | 472 ---------------------------------------- src/pluto/pgpcert.h | 34 --- src/pluto/rcv_whack.c | 2 +- src/pluto/smartcard.c | 139 ++++++------ src/pluto/smartcard.h | 7 +- src/pluto/x509.c | 174 ++------------- src/pluto/x509.h | 30 +-- src/whack/whack.h | 1 + 25 files changed, 471 insertions(+), 1087 deletions(-) diff --git a/src/pluto/Makefile.am b/src/pluto/Makefile.am index e966299c0..14a13a52b 100644 --- a/src/pluto/Makefile.am +++ b/src/pluto/Makefile.am @@ -36,7 +36,6 @@ modecfg.c modecfg.h \ nat_traversal.c nat_traversal.h \ ocsp.c ocsp.h \ packet.c packet.h \ -pgpcert.c pgpcert.h \ pkcs7.c pkcs7.h \ plutomain.c \ rcv_whack.c rcv_whack.h \ diff --git a/src/pluto/ac.c b/src/pluto/ac.c index f2d81a5b8..d8b16112f 100644 --- a/src/pluto/ac.c +++ b/src/pluto/ac.c @@ -85,7 +85,7 @@ bool ac_verify_cert(certificate_t *cert, bool strict) identification_t *subject = cert->get_subject(cert); identification_t *issuer = cert->get_issuer(cert); chunk_t authKeyID = ac->get_authKeyIdentifier(ac); - x509cert_t *aacert; + cert_t *aacert; time_t notBefore, valid_until; DBG1("holder: '%Y'", subject); diff --git a/src/pluto/builder.c b/src/pluto/builder.c index 6c7cde547..0cba32bcf 100644 --- a/src/pluto/builder.c +++ b/src/pluto/builder.c @@ -64,43 +64,31 @@ static cert_t *builder_load_cert(certificate_type_t type, va_list args) } if (blob.ptr) { + cert_t *cert = malloc_thing(cert_t); + + *cert = cert_empty; + if (pgp) { - pgpcert_t *pgpcert = malloc_thing(pgpcert_t); - *pgpcert = pgpcert_empty; - if (parse_pgp(chunk_clone(blob), pgpcert)) - { - cert_t *cert = malloc_thing(cert_t); - *cert = cert_empty; - cert->type = CERT_PGP; - cert->u.pgp = pgpcert; - return cert; - } - plog(" error in OpenPGP certificate"); - free_pgpcert(pgpcert); + cert->cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_GPG, + BUILD_BLOB_PGP, blob, + BUILD_END); } else { - x509cert_t *x509cert = malloc_thing(x509cert_t); - - *x509cert = empty_x509cert; - x509cert->cert = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_X509, - BUILD_BLOB_ASN1_DER, blob, - BUILD_X509_FLAG, flags, - BUILD_END); - if (x509cert->cert) - { - cert_t *cert = malloc_thing(cert_t); - - *cert = cert_empty; - cert->type = CERT_X509_SIGNATURE; - cert->u.x509 = x509cert; - return cert; - } - plog(" error in X.509 certificate"); - free_x509cert(x509cert); + cert->cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, blob, + BUILD_X509_FLAG, flags, + BUILD_END); } + if (cert->cert) + { + return cert; + } + plog(" error in X.509 certificate"); + cert_free(cert); } return NULL; } diff --git a/src/pluto/ca.c b/src/pluto/ca.c index 583ef8b90..e25e7f6f5 100644 --- a/src/pluto/ca.c +++ b/src/pluto/ca.c @@ -37,7 +37,7 @@ /* chained list of X.509 authority certificates (ca, aa, and ocsp) */ -static x509cert_t *x509authcerts = NULL; +static cert_t *x509authcerts = NULL; /* chained list of X.509 certification authority information records */ @@ -79,7 +79,7 @@ bool trusted_ca(identification_t *a, identification_t *b, int *pathlen) { certificate_t *certificate; identification_t *issuer; - x509cert_t *cacert; + cert_t *cacert; cacert = get_authcert(a, chunk_empty, X509_CA); if (cacert == NULL) @@ -161,9 +161,10 @@ bool match_requested_ca(linked_list_t *requested_ca, identification_t *our_ca, */ static void free_first_authcert(void) { - x509cert_t *first = x509authcerts; + cert_t *first = x509authcerts; + x509authcerts = first->next; - free_x509cert(first); + cert_free(first); } /* @@ -174,18 +175,19 @@ void free_authcerts(void) lock_authcert_list("free_authcerts"); while (x509authcerts != NULL) + { free_first_authcert(); - + } unlock_authcert_list("free_authcerts"); } /* * get a X.509 authority certificate with a given subject or keyid */ -x509cert_t* get_authcert(identification_t *subject, chunk_t keyid, +cert_t* get_authcert(identification_t *subject, chunk_t keyid, x509_flag_t auth_flags) { - x509cert_t *cert, *prev_cert = NULL; + cert_t *cert, *prev_cert = NULL; /* the authority certificate list is empty */ if (x509authcerts == NULL) @@ -238,11 +240,11 @@ x509cert_t* get_authcert(identification_t *subject, chunk_t keyid, /* * add an authority certificate to the chained list */ -x509cert_t* add_authcert(x509cert_t *cert, x509_flag_t auth_flags) +cert_t* add_authcert(cert_t *cert, x509_flag_t auth_flags) { certificate_t *certificate = cert->cert; x509_t *x509 = (x509_t*)certificate; - x509cert_t *old_cert; + cert_t *old_cert; lock_authcert_list("add_authcert"); @@ -258,7 +260,7 @@ x509cert_t* add_authcert(x509cert_t *cert, x509_flag_t auth_flags) ) unlock_authcert_list("add_authcert"); - free_x509cert(cert); + cert_free(cert); return old_cert; } else @@ -274,7 +276,7 @@ x509cert_t* add_authcert(x509cert_t *cert, x509_flag_t auth_flags) /* add new authcert to chained list */ cert->next = x509authcerts; x509authcerts = cert; - share_x509cert(cert); /* set count to one */ + cert_share(cert); /* set count to one */ DBG(DBG_CONTROL | DBG_PARSING, DBG_log(" authcert inserted") ) @@ -302,16 +304,17 @@ void load_authcerts(char *type, char *path, x509_flag_t auth_flags) while (enumerator->enumerate(enumerator, NULL, &file, &st)) { - cert_t cert; + cert_t *cert; if (!S_ISREG(st.st_mode)) { /* skip special file */ continue; } - if (load_cert(file, type, auth_flags, &cert)) + cert = load_cert(file, type, auth_flags); + if (cert) { - add_authcert(cert.u.x509, auth_flags); + add_authcert(cert, auth_flags); } } enumerator->destroy(enumerator); @@ -330,8 +333,8 @@ void list_authcerts(const char *caption, x509_flag_t auth_flags, bool utc) /* * get a cacert with a given subject or keyid from an alternative list */ -static const x509cert_t* get_alt_cacert(identification_t *subject, chunk_t keyid, - const x509cert_t *cert) +static const cert_t* get_alt_cacert(identification_t *subject, chunk_t keyid, + const cert_t *cert) { if (cert == NULL) { @@ -369,7 +372,7 @@ static const x509cert_t* get_alt_cacert(identification_t *subject, 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 cert_t *cert, const cert_t *alt_chain) { int pathlen; @@ -382,7 +385,7 @@ bool trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chai identification_t *subject = certificate->get_subject(certificate); identification_t *issuer = certificate->get_issuer(certificate); chunk_t authKeyID = x509->get_authKeyIdentifier(x509); - const x509cert_t *authcert = NULL; + const cert_t *authcert = NULL; DBG(DBG_CONTROL, DBG_log("subject: '%Y'", subject); @@ -551,8 +554,7 @@ ca_info_t* create_ca_info(void) void add_ca_info(const whack_message_t *msg) { smartcard_t *sc = NULL; - cert_t cert; - bool valid_cert = FALSE; + cert_t *cert = NULL; bool cached_cert = FALSE; if (find_ca_info_by_name(msg->name, FALSE)) @@ -564,18 +566,17 @@ void add_ca_info(const whack_message_t *msg) if (scx_on_smartcard(msg->cacert)) { /* load CA cert from smartcard */ - valid_cert = scx_load_cert(msg->cacert, &sc, &cert, &cached_cert); + cert = scx_load_cert(msg->cacert, &sc, &cached_cert); } else { /* load CA cert from file */ - valid_cert = load_ca_cert(msg->cacert, &cert); + cert = load_ca_cert(msg->cacert); } - if (valid_cert) + if (cert) { - x509cert_t *cacert = cert.u.x509; - certificate_t *certificate = cacert->cert; + certificate_t *certificate = cert->cert; x509_t *x509 = (x509_t*)certificate; identification_t *subject = certificate->get_subject(certificate); chunk_t subjectKeyID = x509->get_subjectKeyIdentifier(x509); @@ -589,7 +590,7 @@ void add_ca_info(const whack_message_t *msg) /* ca_info is already present */ loglog(RC_DUPNAME, " duplicate ca information in record \"%s\" found," "ignoring \"%s\"", ca->name, msg->name); - free_x509cert(cacert); + cert_free(cert); return; } @@ -647,13 +648,15 @@ void 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, X509_CA); + cert = add_authcert(cert, X509_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 = cacert; - share_cert(sc->last_cert); + if (sc->last_cert != NULL) + { + sc->last_cert->count--; + } + sc->last_cert = cert; + cert_share(sc->last_cert); } if (sc != NULL) time(&sc->last_load); diff --git a/src/pluto/ca.h b/src/pluto/ca.h index 7b016f943..d964a694a 100644 --- a/src/pluto/ca.h +++ b/src/pluto/ca.h @@ -18,7 +18,7 @@ #include #include -#include "x509.h" +#include "certs.h" #include "whack.h" /* CA info structures */ @@ -40,14 +40,13 @@ struct ca_info { extern bool trusted_ca(identification_t *a, identification_t *b, int *pathlen); extern bool match_requested_ca(linked_list_t *requested_ca, identification_t *our_ca, int *our_pathlen); -extern x509cert_t* get_authcert(identification_t *subject, chunk_t keyid, +extern cert_t* get_authcert(identification_t *subject, chunk_t keyid, x509_flag_t auth_flags); extern void load_authcerts(char *type, char *path, x509_flag_t auth_flags); -extern x509cert_t* add_authcert(x509cert_t *cert, x509_flag_t auth_flags); +extern cert_t* add_authcert(cert_t *cert, x509_flag_t auth_flags); extern void free_authcerts(void); extern void list_authcerts(const char *caption, x509_flag_t auth_flags, bool utc); -extern bool trust_authcert_candidate(const x509cert_t *cert, - const x509cert_t *alt_chain); +extern bool trust_authcert_candidate(const cert_t *cert, const cert_t *alt_chain); extern ca_info_t* get_ca_info(identification_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); diff --git a/src/pluto/certs.c b/src/pluto/certs.c index 89e289b6c..644f65766 100644 --- a/src/pluto/certs.c +++ b/src/pluto/certs.c @@ -18,60 +18,83 @@ #include #include #include +#include #include -#include "library.h" -#include "asn1/asn1.h" -#include "credentials/certificates/certificate.h" +#include +#include +#include +#include #include "constants.h" #include "defs.h" #include "log.h" #include "certs.h" #include "whack.h" +#include "fetch.h" +#include "keys.h" #include "builder.h" /** - * used for initializatin of certs + * Initialization */ -const cert_t cert_empty = {CERT_NONE, {NULL}}; +const cert_t cert_empty = { + NULL , /* cert */ + NULL , /* *next */ + 0 , /* count */ + FALSE /* smartcard */ +}; /** - * extracts the certificate to be sent to the peer + * Chained lists of X.509 and PGP end entity certificates */ -chunk_t cert_get_encoding(cert_t cert) +static cert_t *certs = NULL; + +/** + * Free a pluto certificate + */ +void cert_free(cert_t *cert) { - switch (cert.type) + if (cert) { - case CERT_PGP: - return chunk_clone(cert.u.pgp->certificate); - case CERT_X509_SIGNATURE: - return cert.u.x509->cert->get_encoding(cert.u.x509->cert); - default: - return chunk_empty; + certificate_t *certificate = cert->cert; + + if (certificate) + { + certificate->destroy(certificate); + } + free(cert); } } -public_key_t* cert_get_public_key(const cert_t cert) +/** + * Add a pluto end entity certificate to the chained list + */ +cert_t* cert_add(cert_t *cert) { - switch (cert.type) + certificate_t *certificate = cert->cert; + cert_t *c = certs; + + while (c != NULL) { - case CERT_PGP: + if (certificate->equals(certificate, c->cert)) /* already in chain, free cert */ { - public_key_t *public_key = cert.u.pgp->public_key; - - return public_key->get_ref(public_key); + cert_free(cert); + return c; } - case CERT_X509_SIGNATURE: - { - certificate_t *certificate = cert.u.x509->cert; - - return certificate->get_public_key(certificate); - } - default: - return NULL; + c = c->next; } + + /* insert new cert at the root of the chain */ + lock_certs_and_keys("cert_add"); + cert->next = certs; + certs = cert; + DBG(DBG_CONTROL | DBG_PARSING, + DBG_log(" cert inserted") + ) + unlock_certs_and_keys("cert_add"); + return cert; } /** @@ -161,7 +184,7 @@ private_key_t* load_private_key(char* filename, prompt_pass_t *pass, /** * Loads a X.509 or OpenPGP certificate */ -bool load_cert(char *filename, const char *label, x509_flag_t flags, cert_t *out) +cert_t* load_cert(char *filename, const char *label, x509_flag_t flags) { cert_t *cert; @@ -171,83 +194,133 @@ bool load_cert(char *filename, const char *label, x509_flag_t flags, cert_t *out BUILD_END); if (cert) { - /* the API passes an empty cert_t, we move over and free the built one */ plog(" loaded %s certificate from '%s'", label, filename); - *out = *cert; - free(cert); - return TRUE; } - return FALSE; + return cert; } /** * Loads a host certificate */ -bool load_host_cert(char *filename, cert_t *cert) +cert_t* load_host_cert(char *filename) { char *path = concatenate_paths(HOST_CERT_PATH, filename); - return load_cert(path, "host", X509_NONE, cert); + return load_cert(path, "host", X509_NONE); } /** * Loads a CA certificate */ -bool load_ca_cert(char *filename, cert_t *cert) +cert_t* load_ca_cert(char *filename) { char *path = concatenate_paths(CA_CERT_PATH, filename); - return load_cert(path, "CA", X509_NONE, cert); -} - -/** - * establish equality of two certificates - */ -bool same_cert(const cert_t *a, const cert_t *b) -{ - return a->type == b->type && a->u.x509 == b->u.x509; + return load_cert(path, "CA", X509_NONE); } /** * for each link pointing to the certificate increase the count by one */ -void share_cert(cert_t cert) +void cert_share(cert_t *cert) { - switch (cert.type) + if (cert != NULL) { - case CERT_PGP: - share_pgpcert(cert.u.pgp); - break; - case CERT_X509_SIGNATURE: - share_x509cert(cert.u.x509); - break; - default: - break; + cert->count++; } } /* release of a certificate decreases the count by one * the certificate is freed when the counter reaches zero */ -void release_cert(cert_t cert) +void cert_release(cert_t *cert) { - switch (cert.type) + if (cert && --cert->count == 0) { - case CERT_PGP: - release_pgpcert(cert.u.pgp); - break; - case CERT_X509_SIGNATURE: - release_x509cert(cert.u.x509); - break; - default: - break; + cert_t **pp = &certs; + while (*pp != cert) + { + pp = &(*pp)->next; + } + *pp = cert->next; + cert_free(cert); } } +/** + * List all PGP end certificates in a chained list + */ +void list_pgp_end_certs(bool utc) +{ + cert_t *cert = certs; + time_t now = time(NULL); + bool first = TRUE; + + + while (cert != NULL) + { + certificate_t *certificate = cert->cert; + + if (certificate->get_type(certificate) == CERT_GPG) + { + time_t created, until; + public_key_t *key; + identification_t *userid = certificate->get_subject(certificate); + pgp_certificate_t *pgp_cert = (pgp_certificate_t*)certificate; + chunk_t fingerprint = pgp_cert->get_fingerprint(pgp_cert); + + if (first) + { + whack_log(RC_COMMENT, " "); + whack_log(RC_COMMENT, "List of PGP End Entity Certificates:"); + first = false; + } + whack_log(RC_COMMENT, " "); + whack_log(RC_COMMENT, " userid: '%Y'", userid); + whack_log(RC_COMMENT, " digest: %#B", &fingerprint); + + /* list validity */ + certificate->get_validity(certificate, &now, &created, &until); + whack_log(RC_COMMENT, " created: %T", &created, utc); + whack_log(RC_COMMENT, " until: %T %s%s", &until, utc, + check_expiry(until, CA_CERT_WARNING_INTERVAL, TRUE), + (until == TIME_32_BIT_SIGNED_MAX) ? " (expires never)":""); + + key = certificate->get_public_key(certificate); + if (key) + { + chunk_t keyid; + + whack_log(RC_COMMENT, " pubkey: %N %4d bits%s", + key_type_names, key->get_type(key), + key->get_keysize(key) * BITS_PER_BYTE, + has_private_key(cert)? ", 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, &keyid)) + { + whack_log(RC_COMMENT, " subjkey: %#B", &keyid); + } + } + } + cert = cert->next; + } +} + +/** + * List all X.509 end certificates in a chained list + */ +void list_x509_end_certs(bool utc) +{ + list_x509cert_chain("End Entity", certs, X509_NONE, utc); +} + /** * list all X.509 and OpenPGP end certificates */ -void list_certs(bool utc) +void cert_list(bool utc) { list_x509_end_certs(utc); list_pgp_end_certs(utc); diff --git a/src/pluto/certs.h b/src/pluto/certs.h index faf820dae..b2b11eb37 100644 --- a/src/pluto/certs.h +++ b/src/pluto/certs.h @@ -18,9 +18,12 @@ #define _CERTS_H #include +#include +#include -#include "x509.h" -#include "pgpcert.h" +#include + +#include "defs.h" /* path definitions for private keys, end certs, * cacerts, attribute certs and crls @@ -43,16 +46,16 @@ #define CRL_WARNING_INTERVAL 7 /* days */ #define ACERT_WARNING_INTERVAL 1 /* day */ -/* certificate access structure - * currently X.509 and OpenPGP certificates are supported - */ -typedef struct { - u_char type; - union { - x509cert_t *x509; - pgpcert_t *pgp; - } u; -} cert_t; +/* access structure for a pluto certificate */ + +typedef struct cert_t cert_t; + +struct cert_t { + certificate_t *cert; + cert_t *next; + int count; + bool smartcard; +}; /* used for initialization */ extern const cert_t cert_empty; @@ -62,18 +65,16 @@ extern const cert_t cert_empty; */ extern bool no_cr_send; -extern public_key_t* cert_get_public_key(const cert_t cert); -extern chunk_t cert_get_encoding(cert_t cert); extern private_key_t* load_private_key(char* filename, prompt_pass_t *pass, key_type_t type); -extern bool load_cert(char *filename, const char *label, x509_flag_t flags, - cert_t *cert); -extern bool load_host_cert(char *filename, cert_t *cert); -extern bool load_ca_cert(char *filename, cert_t *cert); -extern bool same_cert(const cert_t *a, const cert_t *b); -extern void share_cert(cert_t cert); -extern void release_cert(cert_t cert); -extern void list_certs(bool utc); +extern cert_t* load_cert(char *filename, const char *label, x509_flag_t flags); +extern cert_t* load_host_cert(char *filename); +extern cert_t* load_ca_cert(char *filename); +extern cert_t* cert_add(cert_t *cert); +extern void cert_free(cert_t *cert); +extern void cert_share(cert_t *cert); +extern void cert_release(cert_t *cert); +extern void cert_list(bool utc); #endif /* _CERTS_H */ diff --git a/src/pluto/connections.c b/src/pluto/connections.c index 45d88a350..e571f6a13 100644 --- a/src/pluto/connections.c +++ b/src/pluto/connections.c @@ -39,7 +39,6 @@ #include "x509.h" #include "ca.h" #include "crl.h" -#include "pgpcert.h" #include "certs.h" #include "ac.h" #include "smartcard.h" @@ -398,9 +397,9 @@ void delete_connection(connection_t *c, bool relations) gw_delref(&c->gw_info); lock_certs_and_keys("delete_connection"); - release_cert(c->spd.this.cert); + cert_release(c->spd.this.cert); scx_release(c->spd.this.sc); - release_cert(c->spd.that.cert); + cert_release(c->spd.that.cert); scx_release(c->spd.that.sc); unlock_certs_and_keys("delete_connection"); @@ -736,7 +735,7 @@ static void unshare_connection_strings(connection_t *c) c->spd.this.pool = clone_str(c->spd.this.pool); c->spd.this.updown = clone_str(c->spd.this.updown); scx_share(c->spd.this.sc); - share_cert(c->spd.this.cert); + cert_share(c->spd.this.cert); if (c->spd.this.ca) { c->spd.this.ca = c->spd.this.ca->clone(c->spd.this.ca); @@ -749,7 +748,7 @@ static void unshare_connection_strings(connection_t *c) c->spd.that.pool = clone_str(c->spd.that.pool); c->spd.that.updown = clone_str(c->spd.that.updown); scx_share(c->spd.that.sc); - share_cert(c->spd.that.cert); + cert_share(c->spd.that.cert); if (c->spd.that.ca) { c->spd.that.ca = c->spd.that.ca->clone(c->spd.that.ca); @@ -767,13 +766,12 @@ static void unshare_connection_strings(connection_t *c) static void load_end_certificate(char *filename, struct end *dst) { time_t valid_until; - cert_t cert; - bool valid_cert = FALSE; + cert_t *cert = NULL; + certificate_t *certificate; bool cached_cert = FALSE; - + /* initialize end certificate */ - dst->cert.type = CERT_NONE; - dst->cert.u.x509 = NULL; + dst->cert = NULL; /* initialize smartcard info record */ dst->sc = NULL; @@ -783,87 +781,73 @@ static void load_end_certificate(char *filename, struct end *dst) if (scx_on_smartcard(filename)) { /* load cert from smartcard */ - valid_cert = scx_load_cert(filename, &dst->sc, &cert, &cached_cert); + cert = scx_load_cert(filename, &dst->sc, &cached_cert); } else { /* load cert from file */ - valid_cert = load_host_cert(filename, &cert); + cert = load_host_cert(filename); } } - if (valid_cert) + if (cert) { - switch (cert.type) + certificate = cert->cert; + + if (dst->id->get_type(dst->id) == ID_ANY || + !certificate->has_subject(certificate, dst->id)) { - case CERT_PGP: - dst->id = select_pgpcert_id(cert.u.pgp, dst->id); + plog( " id '%Y' not confirmed by certificate, defaulting to '%Y'", + dst->id, certificate->get_subject(certificate)); + dst->id->destroy(dst->id); + dst->id = certificate->get_subject(certificate); + dst->id = dst->id->clone(dst->id); + } - if (cached_cert) + if (cached_cert) + { + dst->cert = cert; + } + else + { + if (!certificate->get_validity(certificate, NULL, NULL, &valid_until)) { - dst->cert = cert; + cert_free(cert); + return; } - else - { - valid_until = cert.u.pgp->until; - add_pgp_public_key(cert.u.pgp, cert.u.pgp->until, DAL_LOCAL); - dst->cert.type = cert.type; - dst->cert.u.pgp = add_pgpcert(cert.u.pgp); - } - break; - case CERT_X509_SIGNATURE: - dst->id = select_x509cert_id(cert.u.x509, dst->id); + DBG(DBG_CONTROL, + DBG_log("certificate is valid") + ) + add_public_key_from_cert(cert, valid_until, DAL_LOCAL); + dst->cert = cert_add(cert); + } + certificate = dst->cert->cert; - if (cached_cert) - { - dst->cert = cert; - } - else - { - certificate_t *certificate = cert.u.x509->cert; - - if (!certificate->get_validity(certificate, NULL, NULL, &valid_until)) - { - free_x509cert(cert.u.x509); - break; - } - DBG(DBG_CONTROL, - DBG_log("certificate is valid") - ) - add_x509_public_key(cert.u.x509, valid_until, DAL_LOCAL); - 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 == NULL && certificate->get_type(certificate) == CERT_X509) + { + identification_t *issuer; - /* if no CA is defined, use issuer as default */ - if (dst->ca == NULL) - { - certificate_t *certificate = dst->cert.u.x509->cert; - identification_t *issuer = certificate->get_issuer(certificate); - - dst->ca = issuer->clone(issuer); - } - break; - default: - break; + issuer = certificate->get_issuer(certificate); + dst->ca = issuer->clone(issuer); } /* cache the certificate that was last retrieved from the smartcard */ if (dst->sc) { - if (!same_cert(&dst->sc->last_cert, &dst->cert)) + if (!certificate->equals(certificate, dst->sc->last_cert->cert)) { lock_certs_and_keys("load_end_certificates"); - release_cert(dst->sc->last_cert); + cert_release(dst->sc->last_cert); dst->sc->last_cert = dst->cert; - share_cert(dst->cert); + cert_share(dst->cert); unlock_certs_and_keys("load_end_certificates"); } time(&dst->sc->last_load); } } scx_share(dst->sc); - share_cert(dst->cert); + cert_share(dst->cert); } static bool extract_end(struct end *dst, const whack_end_t *src, diff --git a/src/pluto/connections.h b/src/pluto/connections.h index 5a1281210..ee2e00da6 100644 --- a/src/pluto/connections.h +++ b/src/pluto/connections.h @@ -147,7 +147,7 @@ struct end { u_int16_t host_port; /* host order */ u_int16_t port; /* host order */ u_int8_t protocol; - cert_t cert; /* end certificate */ + cert_t *cert; /* end certificate */ identification_t *ca; /* CA distinguished name */ ietf_attributes_t *groups; /* access control groups */ smartcard_t *sc; /* smartcard reader and key info */ diff --git a/src/pluto/crl.c b/src/pluto/crl.c index f80c7955b..84fe77554 100644 --- a/src/pluto/crl.c +++ b/src/pluto/crl.c @@ -113,7 +113,7 @@ bool insert_crl(x509crl_t *x509crl, char *crl_uri, bool cache_crl) crl_t *crl = (crl_t*)cert_crl; identification_t *issuer = cert_crl->get_issuer(cert_crl); chunk_t authKeyID = crl->get_authKeyIdentifier(crl); - x509cert_t *issuer_cert; + cert_t *issuer_cert; x509crl_t *oldcrl; time_t now, nextUpdate; bool valid_sig; @@ -340,8 +340,7 @@ void 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, +cert_status_t verify_by_crl(cert_t *cert, time_t *until, time_t *revocationDate, crl_reason_t *revocationReason) { certificate_t *certificate = cert->cert; @@ -402,7 +401,7 @@ cert_status_t verify_by_crl(const x509cert_t *cert, time_t *until, certificate_t *cert_crl = x509crl->crl; crl_t *crl = (crl_t*)cert_crl; chunk_t authKeyID = crl->get_authKeyIdentifier(crl); - x509cert_t *issuer_cert; + cert_t *issuer_cert; bool trusted, valid; DBG(DBG_CONTROL, diff --git a/src/pluto/crl.h b/src/pluto/crl.h index bac0717a0..43bafe145 100644 --- a/src/pluto/crl.h +++ b/src/pluto/crl.h @@ -26,7 +26,6 @@ struct x509crl { certificate_t *crl; x509crl_t *next; linked_list_t *distributionPoints; - chunk_t signature; }; /* apply a strict CRL policy @@ -46,7 +45,7 @@ extern long crl_check_interval; extern void load_crls(void); extern void check_crls(void); 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, +extern cert_status_t verify_by_crl(cert_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/ike_alg.c b/src/pluto/ike_alg.c index 3528a62ef..7521dd33b 100644 --- a/src/pluto/ike_alg.c +++ b/src/pluto/ike_alg.c @@ -199,9 +199,10 @@ struct db_context *ike_alg_db_new(connection_t *c, lset_t policy) key_type_t key_type = KEY_ANY; - if (c->spd.this.cert.type != CERT_NONE) + if (c->spd.this.cert) { - public_key_t *key = cert_get_public_key(c->spd.this.cert); + certificate_t *certificate = c->spd.this.cert->cert; + public_key_t *key = certificate->get_public_key(certificate); if (key == NULL) { diff --git a/src/pluto/ipsec_doi.c b/src/pluto/ipsec_doi.c index b7f5fcea1..1f8917d79 100644 --- a/src/pluto/ipsec_doi.c +++ b/src/pluto/ipsec_doi.c @@ -905,7 +905,6 @@ main_outI1(int whack_sock, connection_t *c, struct state *predecessor struct state *st = new_state(); pb_stream reply; /* not actually a reply, but you know what I mean */ pb_stream rbody; - int vids_to_send = 0; /* set up new state */ @@ -925,7 +924,8 @@ main_outI1(int whack_sock, connection_t *c, struct state *predecessor { vids_to_send++; } - if (c->spd.this.cert.type == CERT_PGP) + if (c->spd.this.cert && + c->spd.this.cert->cert->get_type(c->spd.this.cert->cert) == CERT_GPG) { vids_to_send++; } @@ -1022,7 +1022,8 @@ main_outI1(int whack_sock, connection_t *c, struct state *predecessor /* if we have an OpenPGP certificate we assume an * OpenPGP peer and have to send the Vendor ID */ - if (c->spd.this.cert.type == CERT_PGP) + if (c->spd.this.cert && + c->spd.this.cert->cert->get_type(c->spd.this.cert->cert) == CERT_GPG) { if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE , &rbody, VID_OPENPGP)) @@ -2166,12 +2167,12 @@ static void decode_cert(struct msg_digest *md) blob.len = pbs_left(&p->pbs); if (cert->isacert_type == CERT_X509_SIGNATURE) { - x509cert_t x509cert = empty_x509cert; + cert_t x509cert = cert_empty; x509cert.cert = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_X509, - BUILD_BLOB_ASN1_DER, blob, - BUILD_END); + CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, blob, + BUILD_END); if (x509cert.cert) { if (verify_x509cert(&x509cert, strict_crl_policy, &valid_until)) @@ -2179,7 +2180,7 @@ static void decode_cert(struct msg_digest *md) DBG(DBG_PARSING, DBG_log("Public key validated") ) - add_x509_public_key(&x509cert, valid_until, DAL_SIGNED); + add_public_key_from_cert(&x509cert, valid_until, DAL_SIGNED); } else { @@ -3518,7 +3519,7 @@ stf_status main_inR2_outI3(struct msg_digest *md) connection_t *c = st->st_connection; certpolicy_t cert_policy = c->spd.this.sendcert; - cert_t mycert = c->spd.this.cert; + cert_t *mycert = c->spd.this.cert; bool requested, send_cert, send_cr; bool pubkey_auth = uses_pubkey_auth(st->st_oakley.auth); @@ -3548,8 +3549,9 @@ stf_status main_inR2_outI3(struct msg_digest *md) * or are requested to send it */ requested = cert_policy == CERT_SEND_IF_ASKED && c->got_certrequest; - send_cert = pubkey_auth && mycert.type != CERT_NONE - && (cert_policy == CERT_ALWAYS_SEND || requested); + send_cert = pubkey_auth && mycert && + mycert->cert->get_type(mycert->cert) == CERT_X509 && + (cert_policy == CERT_ALWAYS_SEND || requested); /* send certificate request if we don't have a preloaded RSA public key */ send_cr = !no_cr_send && send_cert && !has_preloaded_public_key(st); @@ -3599,7 +3601,7 @@ stf_status main_inR2_outI3(struct msg_digest *md) DBG(DBG_CONTROL, DBG_log("our certificate policy is %N", cert_policy_names, cert_policy) ) - if (mycert.type != CERT_NONE) + if (mycert && mycert->cert->get_type(mycert->cert) == CERT_X509) { const char *request_text = ""; @@ -3623,13 +3625,13 @@ stf_status main_inR2_outI3(struct msg_digest *md) struct isakmp_cert cert_hd; cert_hd.isacert_np = (send_cr)? ISAKMP_NEXT_CR : ISAKMP_NEXT_SIG; - cert_hd.isacert_type = mycert.type; + cert_hd.isacert_type = CERT_X509_SIGNATURE; if (!out_struct(&cert_hd, &isakmp_ipsec_certificate_desc, &md->rbody, &cert_pbs)) { return STF_INTERNAL_ERROR; } - cert_encoding = cert_get_encoding(mycert); + cert_encoding = mycert->cert->get_encoding(mycert->cert); success = out_chunk(cert_encoding, &cert_pbs, "CERT"); free(cert_encoding.ptr); if (!success) @@ -3645,7 +3647,7 @@ stf_status main_inR2_outI3(struct msg_digest *md) identification_t *ca = st->st_connection->spd.that.ca; chunk_t cr = (ca) ? ca->get_encoding(ca) : chunk_empty; - if (!build_and_ship_CR(mycert.type, cr, &md->rbody, ISAKMP_NEXT_SIG)) + if (!build_and_ship_CR(CERT_X509_SIGNATURE, cr, &md->rbody, ISAKMP_NEXT_SIG)) { return STF_INTERNAL_ERROR; } @@ -3971,7 +3973,7 @@ main_inI3_outR3_tail(struct msg_digest *md u_int8_t auth_payload; pb_stream r_id_pbs; /* ID Payload; also used for hash calculation */ certpolicy_t cert_policy; - cert_t mycert; + cert_t *mycert; bool pubkey_auth, send_cert, requested; /* ID and HASH_I or SIG_I in @@ -3996,7 +3998,8 @@ main_inI3_outR3_tail(struct msg_digest *md requested = cert_policy == CERT_SEND_IF_ASKED && st->st_connection->got_certrequest; pubkey_auth = uses_pubkey_auth(st->st_oakley.auth); - send_cert = pubkey_auth && mycert.type != CERT_NONE && + send_cert = pubkey_auth && mycert && + mycert->cert->get_type(mycert->cert) == CERT_X509 && (cert_policy == CERT_ALWAYS_SEND || requested); /*************** build output packet HDR*;IDir;HASH/SIG_R ***************/ @@ -4039,7 +4042,7 @@ main_inI3_outR3_tail(struct msg_digest *md DBG(DBG_CONTROL, DBG_log("our certificate policy is %N", cert_policy_names, cert_policy) ) - if (mycert.type != CERT_NONE) + if (mycert && mycert->cert->get_type(mycert->cert) == CERT_X509) { const char *request_text = ""; @@ -4063,13 +4066,13 @@ main_inI3_outR3_tail(struct msg_digest *md struct isakmp_cert cert_hd; cert_hd.isacert_np = ISAKMP_NEXT_SIG; - cert_hd.isacert_type = mycert.type; + cert_hd.isacert_type = CERT_X509_SIGNATURE; if (!out_struct(&cert_hd, &isakmp_ipsec_certificate_desc, &md->rbody, &cert_pbs)) { return STF_INTERNAL_ERROR; } - cert_encoding = cert_get_encoding(mycert); + cert_encoding = mycert->cert->get_encoding(mycert->cert); success = out_chunk(cert_encoding, &cert_pbs, "CERT"); free(cert_encoding.ptr); if (!success) diff --git a/src/pluto/keys.c b/src/pluto/keys.c index f054a6bd9..8cf28ace1 100644 --- a/src/pluto/keys.c +++ b/src/pluto/keys.c @@ -36,11 +36,11 @@ #include #include +#include #include "constants.h" #include "defs.h" #include "x509.h" -#include "pgpcert.h" #include "certs.h" #include "smartcard.h" #include "connections.h" @@ -111,9 +111,11 @@ static const secret_t* get_secret(const connection_t *c, identification_t *my_id, *his_id; /* is there a certificate assigned to this connection? */ - if (kind == PPK_PUBKEY && c->spd.this.cert.type != CERT_NONE) + if (kind == PPK_PUBKEY && c->spd.this.cert) { - public_key_t *pub_key = cert_get_public_key(c->spd.this.cert); + certificate_t *certificate = c->spd.this.cert->cert; + + public_key_t *pub_key = certificate->get_public_key(certificate); for (s = secrets; s != NULL; s = s->next) { @@ -262,11 +264,11 @@ const chunk_t* get_preshared_secret(const connection_t *c) /* check the existence of a private key matching a public key contained * in an X.509 or OpenPGP certificate */ -bool has_private_key(cert_t cert) +bool has_private_key(cert_t *cert) { secret_t *s; bool has_key = FALSE; - public_key_t *pub_key = cert_get_public_key(cert); + public_key_t *pub_key = cert->cert->get_public_key(cert->cert); for (s = secrets; s != NULL; s = s->next) { @@ -284,7 +286,7 @@ bool has_private_key(cert_t cert) /* * get the matching private key belonging to a given X.509 certificate */ -private_key_t* get_x509_private_key(const x509cert_t *cert) +private_key_t* get_x509_private_key(const cert_t *cert) { public_key_t *public_key = cert->cert->get_public_key(cert->cert); private_key_t *private_key = NULL; @@ -1272,80 +1274,86 @@ bool add_public_key(identification_t *id, enum dns_auth_level dns_auth_level, return TRUE; } -/* extract id and public key from x.509 certificate and - * insert it into a pubkeyrec +/** + * Extract id and public key a certificate and insert it into a pubkeyrec */ -void add_x509_public_key(x509cert_t *cert , time_t until, - enum dns_auth_level dns_auth_level) +void add_public_key_from_cert(cert_t *cert , time_t until, + enum dns_auth_level dns_auth_level) { 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 *issuer = NULL; identification_t *id; - chunk_t serialNumber = x509->get_serial(x509); + chunk_t serialNumber = chunk_empty; 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 = certificate->get_public_key(certificate); + pk_type = pk->public_key->get_type(pk->public_key); pk->id = subject->clone(subject); pk->dns_auth_level = dns_auth_level; pk->until_time = until; - pk->issuer = issuer->clone(issuer); - pk->serial = chunk_clone(serialNumber); - pk_type = pk->public_key->get_type(pk->public_key); + if (certificate->get_type(certificate) == CERT_X509) + { + x509_t *x509 = (x509_t*)certificate; + + issuer = certificate->get_issuer(certificate); + serialNumber = x509->get_serial(x509); + pk->issuer = issuer->clone(issuer); + pk->serial = chunk_clone(serialNumber); + } delete_public_keys(pk->id, pk_type, pk->issuer, pk->serial); install_public_key(pk, &pubkeys); - /* insert all subjectAltNames */ - enumerator = x509->create_subjectAltName_enumerator(x509); - while (enumerator->enumerate(enumerator, &id)) + if (certificate->get_type(certificate) == CERT_X509) { - if (id->get_type(id) != ID_ANY) + x509_t *x509 = (x509_t*)certificate; + enumerator_t *enumerator; + + /* insert all subjectAltNames from X.509 certificates */ + enumerator = x509->create_subjectAltName_enumerator(x509); + while (enumerator->enumerate(enumerator, &id)) { - pk = malloc_thing(pubkey_t); - zero(pk); - pk->id = id->clone(id); - pk->public_key = certificate->get_public_key(certificate); - pk->dns_auth_level = dns_auth_level; - pk->until_time = until; - pk->issuer = issuer->clone(issuer); - pk->serial = chunk_clone(serialNumber); - delete_public_keys(pk->id, pk_type, pk->issuer, pk->serial); - install_public_key(pk, &pubkeys); + if (id->get_type(id) != ID_ANY) + { + pk = malloc_thing(pubkey_t); + zero(pk); + pk->id = id->clone(id); + pk->public_key = certificate->get_public_key(certificate); + pk->dns_auth_level = dns_auth_level; + pk->until_time = until; + pk->issuer = issuer->clone(issuer); + pk->serial = chunk_clone(serialNumber); + delete_public_keys(pk->id, pk_type, pk->issuer, pk->serial); + install_public_key(pk, &pubkeys); + } } + enumerator->destroy(enumerator); } - enumerator->destroy(enumerator); -} + else + { + pgp_certificate_t *pgp_cert = (pgp_certificate_t*)certificate; + chunk_t fingerprint = pgp_cert->get_fingerprint(pgp_cert); -/* extract id and public key from OpenPGP certificate and - * insert it into a pubkeyrec - */ -void add_pgp_public_key(pgpcert_t *cert , time_t until, - enum dns_auth_level dns_auth_level) -{ - pubkey_t *pk; - key_type_t pk_type; - - pk = malloc_thing(pubkey_t); - zero(pk); - pk->public_key = cert->public_key->get_ref(cert->public_key); - pk->id = cert->fingerprint->clone(cert->fingerprint); - pk->dns_auth_level = dns_auth_level; - pk->until_time = until; - pk_type = pk->public_key->get_type(pk->public_key); - delete_public_keys(pk->id, pk_type, NULL, chunk_empty); - install_public_key(pk, &pubkeys); + /* add v3 or v4 PGP fingerprint */ + pk = malloc_thing(pubkey_t); + zero(pk); + pk->id = identification_create_from_encoding(ID_KEY_ID, fingerprint); + pk->public_key = certificate->get_public_key(certificate); + pk->dns_auth_level = dns_auth_level; + pk->until_time = until; + delete_public_keys(pk->id, pk_type, pk->issuer, pk->serial); + install_public_key(pk, &pubkeys); + } } /* when a X.509 certificate gets revoked, all instances of * the corresponding public key must be removed */ -void remove_x509_public_key(const x509cert_t *cert) +void remove_x509_public_key(const cert_t *cert) { public_key_t *revoked_key = cert->cert->get_public_key(cert->cert); pubkey_list_t *p, **pp; diff --git a/src/pluto/keys.h b/src/pluto/keys.h index 558a44f1b..d856c0009 100644 --- a/src/pluto/keys.h +++ b/src/pluto/keys.h @@ -45,7 +45,7 @@ struct connection; extern const chunk_t *get_preshared_secret(const struct connection *c); extern private_key_t *get_private_key(const struct connection *c); -extern private_key_t *get_x509_private_key(const x509cert_t *cert); +extern private_key_t *get_x509_private_key(const cert_t *cert); /* public key machinery */ @@ -84,12 +84,10 @@ extern bool add_public_key(identification_t *id, enum pubkey_alg alg, chunk_t rfc3110_key, pubkey_list_t **head); -extern bool has_private_key(cert_t cert); -extern void add_x509_public_key(x509cert_t *cert, time_t until - , enum dns_auth_level dns_auth_level); -extern void add_pgp_public_key(pgpcert_t *cert, time_t until - , enum dns_auth_level dns_auth_level); -extern void remove_x509_public_key(const x509cert_t *cert); +extern bool has_private_key(cert_t *cert); +extern void add_public_key_from_cert(cert_t *cert, time_t until, + enum dns_auth_level dns_auth_level); +extern void remove_x509_public_key(const cert_t *cert); extern void list_public_keys(bool utc); struct gw_info; /* forward declaration of tag (defined in dnskey.h) */ diff --git a/src/pluto/ocsp.c b/src/pluto/ocsp.c index 2674aa2ab..d1533cc5a 100644 --- a/src/pluto/ocsp.c +++ b/src/pluto/ocsp.c @@ -145,7 +145,7 @@ static chunk_t ocsp_default_uri; static ocsp_location_t *ocsp_cache = NULL; /* static temporary storage for ocsp requestor information */ -static x509cert_t *ocsp_requestor_cert = NULL; +static cert_t *ocsp_requestor_cert = NULL; static smartcard_t *ocsp_requestor_sc = NULL; @@ -281,7 +281,7 @@ static const asn1Object_t singleResponseObjects[] = { * Build an ocsp location from certificate information * without unsharing its contents */ -static bool build_ocsp_location(const x509cert_t *cert, ocsp_location_t *location) +static bool build_ocsp_location(const cert_t *cert, ocsp_location_t *location) { certificate_t *certificate = cert->cert; identification_t *issuer = certificate->get_issuer(certificate); @@ -329,7 +329,7 @@ static bool build_ocsp_location(const x509cert_t *cert, ocsp_location_t *locatio if (authKeyID.ptr == NULL) { - x509cert_t *authcert = get_authcert(issuer, authKeyID, X509_CA); + cert_t *authcert = get_authcert(issuer, authKeyID, X509_CA); if (authcert) { @@ -416,7 +416,7 @@ static cert_status_t get_ocsp_status(const ocsp_location_t *loc, /** * Verify the ocsp status of a certificate */ -cert_status_t verify_by_ocsp(const x509cert_t *cert, time_t *until, +cert_status_t verify_by_ocsp(const cert_t *cert, time_t *until, time_t *revocationDate, crl_reason_t *revocationReason) { @@ -646,7 +646,7 @@ void list_ocsp_cache(bool utc, bool strict) static bool get_ocsp_requestor_cert(ocsp_location_t *location) { - x509cert_t *cert = NULL; + cert_t *cert = NULL; /* initialize temporary static storage */ ocsp_requestor_cert = NULL; @@ -962,7 +962,7 @@ chunk_t build_ocsp_request(ocsp_location_t *location) static bool valid_ocsp_response(response_t *res) { int pathlen, pathlen_constraint; - x509cert_t *authcert; + cert_t *authcert; lock_authcert_list("valid_ocsp_response"); @@ -992,7 +992,7 @@ static bool valid_ocsp_response(response_t *res) for (pathlen = -1; pathlen <= X509_MAX_PATH_LEN; pathlen++) { - x509cert_t *cert = authcert; + cert_t *cert = authcert; certificate_t *certificate = cert->cert; x509_t *x509 = (x509_t*)certificate; identification_t *subject = certificate->get_subject(certificate); @@ -1133,10 +1133,10 @@ static bool parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res) break; case BASIC_RESPONSE_CERTIFICATE: { - x509cert_t *cert = malloc_thing(x509cert_t); + cert_t *cert = malloc_thing(cert_t); x509_t *x509; - *cert = empty_x509cert; + *cert = cert_empty; cert->cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_BLOB_ASN1_DER, object, @@ -1146,7 +1146,7 @@ static bool parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res) DBG(DBG_CONTROL | DBG_PARSING, DBG_log("parsing of embedded ocsp certificate failed") ) - free_x509cert(cert); + cert_free(cert); break; } x509 = (x509_t*)cert->cert; @@ -1161,7 +1161,7 @@ static bool parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res) DBG(DBG_CONTROL | DBG_PARSING, DBG_log("embedded ocsp certificate rejected") ) - free_x509cert(cert); + cert_free(cert); } } break; diff --git a/src/pluto/ocsp.h b/src/pluto/ocsp.h index a3ba6c0a3..977cca3c8 100644 --- a/src/pluto/ocsp.h +++ b/src/pluto/ocsp.h @@ -69,11 +69,11 @@ extern ocsp_location_t* add_ocsp_location(const ocsp_location_t *loc extern void add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info , ocsp_location_t **chain, bool request); extern void check_ocsp(void); -extern cert_status_t verify_by_ocsp(const x509cert_t *cert, time_t *until +extern cert_status_t verify_by_ocsp(const cert_t *cert, time_t *until , time_t *revocationTime, crl_reason_t *revocationReason); extern bool ocsp_set_request_cert(char* path); extern void ocsp_set_default_uri(char* uri); -extern void ocsp_cache_add_cert(const x509cert_t* cert); +extern void ocsp_cache_add_cert(const cert_t* cert); extern chunk_t build_ocsp_request(ocsp_location_t* location); extern void parse_ocsp(ocsp_location_t* location, chunk_t blob); extern void list_ocsp_locations(ocsp_location_t *location, bool requests diff --git a/src/pluto/pgpcert.c b/src/pluto/pgpcert.c index 3e9831ef8..380186cfd 100644 --- a/src/pluto/pgpcert.c +++ b/src/pluto/pgpcert.c @@ -32,476 +32,4 @@ #include "whack.h" #include "keys.h" -typedef enum pgp_packet_tag_t pgp_packet_tag_t; - -/** - * OpenPGP packet tags as defined in section 4.3 of RFC 4880 - */ -enum pgp_packet_tag_t { - PGP_PKT_RESERVED = 0, - PGP_PKT_PUBKEY_ENC_SESSION_KEY = 1, - PGP_PKT_SIGNATURE = 2, - PGP_PKT_SYMKEY_ENC_SESSION_KEY = 3, - PGP_PKT_ONE_PASS_SIGNATURE_PKT = 4, - PGP_PKT_SECRET_KEY = 5, - PGP_PKT_PUBLIC_KEY = 6, - PGP_PKT_SECRET_SUBKEY = 7, - PGP_PKT_COMPRESSED_DATA = 8, - PGP_PKT_SYMKEY_ENC_DATA = 9, - PGP_PKT_MARKER = 10, - PGP_PKT_LITERAL_DATA = 11, - PGP_PKT_TRUST = 12, - PGP_PKT_USER_ID = 13, - PGP_PKT_PUBLIC_SUBKEY = 14, - PGP_PKT_USER_ATTRIBUTE = 17, - PGP_PKT_SYM_ENC_INT_PROT_DATA = 18, - PGP_PKT_MOD_DETECT_CODE = 19 -}; - -ENUM_BEGIN(pgp_packet_tag_names, PGP_PKT_RESERVED, PGP_PKT_PUBLIC_SUBKEY, - "Reserved", - "Public-Key Encrypted Session Key Packet", - "Signature Packet", - "Symmetric-Key Encrypted Session Key Packet", - "One-Pass Signature Packet", - "Secret Key Packet", - "Public Key Packet", - "Secret Subkey Packet", - "Compressed Data Packet", - "Symmetrically Encrypted Data Packet", - "Marker Packet", - "Literal Data Packet", - "Trust Packet", - "User ID Packet", - "Public Subkey Packet" -); -ENUM_NEXT(pgp_packet_tag_names, PGP_PKT_USER_ATTRIBUTE, PGP_PKT_MOD_DETECT_CODE, PGP_PKT_PUBLIC_SUBKEY, - "User Attribute Packet", - "Sym. Encrypted and Integrity Protected Data Packet", - "Modification Detection Code Packet" -); -ENUM_END(pgp_packet_tag_names, PGP_PKT_MOD_DETECT_CODE); - -/** - * Chained list of OpenPGP end certificates - */ -static pgpcert_t *pgpcerts = NULL; - -/** - * Size of PGP Key ID - */ -#define PGP_KEYID_SIZE 8 - -const pgpcert_t pgpcert_empty = { - NULL , /* next */ - 0 , /* version */ - 0 , /* count */ - { NULL, 0 }, /* certificate */ - 0 , /* created */ - 0 , /* until */ - NULL , /* public key */ - NULL /* fingerprint */ -}; - -#define PGP_INVALID_LENGTH 0xffffffff - -/** - * Returns the length of an OpenPGP (RFC 4880) packet - * The blob pointer is advanced past the length field. - */ -static size_t pgp_length(chunk_t *blob, size_t len) -{ - size_t size = 0; - - if (len > blob->len) - { - return PGP_INVALID_LENGTH; - } - blob->len -= len; - - while (len-- > 0) - { - size = 256*size + *blob->ptr++; - } - return size; -} - -/** - * Extracts the length of a PGP packet - */ -static size_t pgp_old_packet_length(chunk_t *blob) -{ - /* bits 0 and 1 define the packet length type */ - int len_type = 0x03 & *blob->ptr++; - - blob->len--; - - /* len_type: 0 -> 1 byte, 1 -> 2 bytes, 2 -> 4 bytes */ - return pgp_length(blob, (len_type == 0)? 1: len_type << 1); -} - -/** - * Extracts PGP packet version (V3 or V4) - */ -static u_char pgp_version(chunk_t *blob) -{ - u_char version = *blob->ptr++; - blob->len--; - DBG(DBG_PARSING, - DBG_log("L3 - version:"); - DBG_log(" V%d", version) - ) - return version; -} - -/** - * Parse OpenPGP signature packet defined in section 5.2.2 of RFC 4880 - */ -static bool parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert) -{ - time_t created; - chunk_t keyid; - u_char sig_type; - u_char version = pgp_version(packet); - - /* we parse only V3 signature packets */ - if (version != 3) - { - return TRUE; - } - - /* size byte must have the value 5 */ - if (pgp_length(packet, 1) != 5) - { - plog(" size must be 5"); - return FALSE; - } - - /* signature type - 1 byte */ - sig_type = (u_char)pgp_length(packet, 1); - DBG(DBG_PARSING, - DBG_log("L3 - signature type: 0x%2x", sig_type) - ) - - /* creation date - 4 bytes */ - created = (time_t)pgp_length(packet, 4); - DBG(DBG_PARSING, - DBG_log("L3 - created:"); - DBG_log(" %T", &cert->created, TRUE) - ) - - /* key ID of signer - 8 bytes */ - keyid.ptr = packet->ptr; - keyid.len = PGP_KEYID_SIZE; - DBG_cond_dump_chunk(DBG_PARSING, "L3 - key ID of signer", keyid); - - return TRUE; -} - -/** - * Parses the version and validity of an OpenPGP public key packet - */ -static bool parse_pgp_pubkey_version_validity(chunk_t *packet, pgpcert_t *cert) -{ - cert->version = pgp_version(packet); - - if (cert->version < 3 || cert->version > 4) - { - plog("OpenPGP packet version V%d not supported", cert->version); - return FALSE; - } - - /* creation date - 4 bytes */ - cert->created = (time_t)pgp_length(packet, 4); - DBG(DBG_PARSING, - DBG_log("L3 - created:"); - DBG_log(" %T", &cert->created, TRUE) - ) - - if (cert->version == 3) - { - /* validity in days - 2 bytes */ - cert->until = (time_t)pgp_length(packet, 2); - - /* validity of 0 days means that the key never expires */ - if (cert->until > 0) - { - cert->until = cert->created + 24*3600*cert->until; - } - DBG(DBG_PARSING, - DBG_log("L3 - until:"); - DBG_log(" %T", &cert->until, TRUE); - ) - } - return TRUE; -} - -/** - * Parse OpenPGP public key packet defined in section 5.5.2 of RFC 4880 - */ -static bool parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert) -{ - chunk_t pubkey_packet = *packet; - - if (!parse_pgp_pubkey_version_validity(packet, cert)) - { - return FALSE; - } - - cert->public_key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY, - BUILD_BLOB_PGP, *packet, BUILD_END); - if (cert->public_key == NULL) - { - return FALSE; - } - - /* compute V4 or V3 fingerprint according to section 12.2 of RFC 4880 */ - if (cert->version == 4) - { - chunk_t pubkey_packet_header = chunk_from_chars( - 0x99, pubkey_packet.len / 256, pubkey_packet.len % 256 - ); - chunk_t hash; - hasher_t *hasher; - - hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (hasher == NULL) - { - plog("no SHA-1 hasher available"); - return FALSE; - } - hasher->allocate_hash(hasher, pubkey_packet_header, NULL); - hasher->allocate_hash(hasher, pubkey_packet, &hash); - hasher->destroy(hasher); - cert->fingerprint = identification_create_from_encoding(ID_KEY_ID, hash); - free(hash.ptr); - } - else - { - chunk_t fp; - - /* V3 fingerprint is computed by public_key_t class */ - if (!cert->public_key->get_fingerprint(cert->public_key, KEY_ID_PGPV3, - &fp)) - { - return FALSE; - } - cert->fingerprint = identification_create_from_encoding(ID_KEY_ID, fp); - } - return TRUE; -} - -bool parse_pgp(chunk_t blob, pgpcert_t *cert) -{ - DBG(DBG_PARSING, - DBG_log("L0 - PGP file:") - ) - DBG_cond_dump_chunk(DBG_RAW, "", blob); - - if (cert == NULL) - { - /* should not occur, nothing to parse */ - return FALSE; - } - - /* parse a PGP certificate file */ - cert->certificate = blob; - - while (blob.len > 0) - { - chunk_t packet = chunk_empty; - u_char packet_tag = *blob.ptr; - - DBG(DBG_PARSING, - DBG_log("L1 - PGP packet: tag= 0x%2x", packet_tag) - ) - - /* bit 7 must be set */ - if (!(packet_tag & 0x80)) - { - plog(" incorrect Packet Tag"); - return FALSE; - } - - /* bit 6 set defines new packet format */ - if (packet_tag & 0x40) - { - plog(" new PGP packet format not supported"); - return FALSE; - } - else - { - int packet_type = (packet_tag & 0x3C) >> 2; - - packet.len = pgp_old_packet_length(&blob); - packet.ptr = blob.ptr; - blob.ptr += packet.len; - blob.len -= packet.len; - DBG(DBG_PARSING, - DBG_log(" %N (%d), old format, %u bytes", - pgp_packet_tag_names, packet_type, - packet_type, packet.len); - DBG_log("L2 - body:") - ) - DBG_cond_dump_chunk(DBG_RAW, "", packet); - - /* parse a PGP certificate */ - switch (packet_type) - { - case PGP_PKT_PUBLIC_KEY: - if (!parse_pgp_pubkey_packet(&packet, cert)) - { - return FALSE; - } - break; - case PGP_PKT_SIGNATURE: - if (!parse_pgp_signature_packet(&packet, cert)) - { - return FALSE; - } - break; - case PGP_PKT_USER_ID: - DBG(DBG_PARSING, - DBG_log("L3 - user ID:"); - DBG_log(" '%.*s'", (int)packet.len, packet.ptr) - ) - break; - default: - break; - } - } - } - return TRUE; -} - -/** - * Compare two OpenPGP certificates - */ -static bool same_pgpcert(pgpcert_t *a, pgpcert_t *b) -{ - return a->certificate.len == b->certificate.len && - memeq(a->certificate.ptr, b->certificate.ptr, b->certificate.len); -} - -/** - * For each link pointing to the certificate increase the count by one - */ -void share_pgpcert(pgpcert_t *cert) -{ - if (cert != NULL) - { - cert->count++; - } -} - -/** - * Select the OpenPGP keyid as ID - */ -identification_t* select_pgpcert_id(pgpcert_t *cert, identification_t *id) -{ - id->destroy(id); - - return cert->fingerprint->clone(cert->fingerprint); -} - -/** - * Add an OpenPGP user/host certificate to the chained list - */ -pgpcert_t* add_pgpcert(pgpcert_t *cert) -{ - pgpcert_t *c = pgpcerts; - - while (c != NULL) - { - if (same_pgpcert(c, cert)) /* already in chain, free cert */ - { - free_pgpcert(cert); - return c; - } - c = c->next; - } - - /* insert new cert at the root of the chain */ - cert->next = pgpcerts; - pgpcerts = cert; - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log(" pgp cert inserted") - ) - return cert; -} - -/** - * Release of a certificate decreases the count by one. - * The certificate is freed when the counter reaches zero - */ -void release_pgpcert(pgpcert_t *cert) -{ - if (cert != NULL && --cert->count == 0) - { - pgpcert_t **pp = &pgpcerts; - while (*pp != cert) - { - pp = &(*pp)->next; - } - *pp = cert->next; - free_pgpcert(cert); - } -} - -/** - * Free a PGP certificate - */ -void free_pgpcert(pgpcert_t *cert) -{ - if (cert != NULL) - { - DESTROY_IF(cert->public_key); - DESTROY_IF(cert->fingerprint); - free(cert->certificate.ptr); - free(cert); - } -} - -/** - * List all PGP end certificates in a chained list - */ -void list_pgp_end_certs(bool utc) -{ - pgpcert_t *cert = pgpcerts; - time_t now; - - /* determine the current time */ - time(&now); - - if (cert != NULL) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of PGP End Entity Certificates:"); - } - - while (cert != NULL) - { - public_key_t *key = cert->public_key; - chunk_t keyid; - cert_t c; - - c.type = CERT_PGP; - c.u.pgp = cert; - - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, " digest: %Y", cert->fingerprint); - whack_log(RC_COMMENT, " created: %T", &cert->created, utc); - whack_log(RC_COMMENT, " until: %T %s", &cert->until, utc, - check_expiry(cert->until, 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, - 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); - } - cert = cert->next; - } -} diff --git a/src/pluto/pgpcert.h b/src/pluto/pgpcert.h index 27c1605cf..fa589829f 100644 --- a/src/pluto/pgpcert.h +++ b/src/pluto/pgpcert.h @@ -17,40 +17,6 @@ #ifndef _PGPCERT_H #define _PGPCERT_H -#include -#include -#include -#include - -/* - * Length of PGP V3 fingerprint - */ -#define PGP_FINGERPRINT_SIZE HASH_SIZE_MD5 - -typedef char fingerprint_t[PGP_FINGERPRINT_SIZE]; - -/* access structure for an OpenPGP certificate */ - -typedef struct pgpcert pgpcert_t; - -struct pgpcert { - pgpcert_t *next; - int version; - int count; - chunk_t certificate; - time_t created; - time_t until; - public_key_t *public_key; - identification_t *fingerprint; -}; - -extern const pgpcert_t pgpcert_empty; -extern bool parse_pgp(chunk_t blob, pgpcert_t *cert); -extern void share_pgpcert(pgpcert_t *cert); -extern identification_t* select_pgpcert_id(pgpcert_t *cert, identification_t *id); -extern pgpcert_t* add_pgpcert(pgpcert_t *cert); extern void list_pgp_end_certs(bool utc); -extern void release_pgpcert(pgpcert_t *cert); -extern void free_pgpcert(pgpcert_t *cert); #endif /* _PGPCERT_H */ diff --git a/src/pluto/rcv_whack.c b/src/pluto/rcv_whack.c index 79e63d27a..826a1aa6e 100644 --- a/src/pluto/rcv_whack.c +++ b/src/pluto/rcv_whack.c @@ -476,7 +476,7 @@ void whack_handle(int whackctlfd) if (msg.whack_list & LIST_CERTS) { - list_certs(msg.whack_utc); + cert_list(msg.whack_utc); } if (msg.whack_list & LIST_CACERTS) diff --git a/src/pluto/smartcard.c b/src/pluto/smartcard.c index 1c96615bc..f1a3932a6 100644 --- a/src/pluto/smartcard.c +++ b/src/pluto/smartcard.c @@ -59,21 +59,21 @@ static smartcard_t *smartcards = NULL; static int sc_number = 0; const smartcard_t empty_sc = { - NULL , /* next */ - 0 , /* last_load */ - { CERT_NONE, {NULL} }, /* last_cert */ - 0 , /* count */ - 0 , /* number */ - 999999 , /* slot */ - NULL , /* id */ - NULL , /* label */ - { NULL, 0 } , /* pin */ - FALSE , /* pinpad */ - FALSE , /* valid */ - FALSE , /* session_opened */ - FALSE , /* logged_in */ - TRUE , /* any_slot */ - 0L , /* session */ + NULL , /* next */ + 0 , /* last_load */ + NULL , /* last_cert */ + 0 , /* count */ + 0 , /* number */ + 999999 , /* slot */ + NULL , /* id */ + NULL , /* label */ + { NULL, 0 } , /* pin */ + FALSE , /* pinpad */ + FALSE , /* valid */ + FALSE , /* session_opened */ + FALSE , /* logged_in */ + TRUE , /* any_slot */ + 0L , /* session */ }; #ifdef SMARTCARD /* compile with smartcard support */ @@ -437,14 +437,13 @@ 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 cert_t* scx_find_cert_object(CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE object, smartcard_t *sc) { size_t hex_len, label_len; u_char *hex_id = NULL; + cert_t *cert; chunk_t blob; - x509cert_t *x509cert; CK_ATTRIBUTE attr[] = { { CKA_ID, NULL_PTR, 0L }, @@ -452,16 +451,13 @@ static bool scx_find_cert_object(CK_SESSION_HANDLE session, { CKA_VALUE, NULL_PTR, 0L } }; - /* initialize the return argument */ - *cert = cert_empty; - /* get the length of the attributes first */ CK_RV rv = pkcs11_functions->C_GetAttributeValue(session, object, attr, 3); if (rv != CKR_OK) { plog("couldn't read the attribute sizes: %s" , enum_show(&pkcs11_return_names, rv)); - return FALSE; + return NULL; } free(sc->label); @@ -486,7 +482,7 @@ static bool scx_find_cert_object(CK_SESSION_HANDLE session, free(hex_id); free(sc->label); free(blob.ptr); - return FALSE; + return NULL; } free(sc->id); @@ -500,22 +496,23 @@ static bool scx_find_cert_object(CK_SESSION_HANDLE session, sc->label[label_len] = '\0'; /* parse the retrieved cert */ - x509cert = malloc_thing(x509cert_t); - *x509cert = empty_x509cert; - x509cert->smartcard = TRUE; - x509cert->cert = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_X509, - BUILD_BLOB_ASN1_DER, blob, - BUILD_END); - if (x509cert->cert) + + /* initialize the return argument */ + cert = malloc_thing(cert_t); + *cert = cert_empty; + cert->smartcard = TRUE; + cert->cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, blob, + BUILD_END); + if (cert->cert) { - cert->type = CERT_X509_SIGNATURE; - cert->u.x509 = x509cert; - return TRUE; + return cert; } + plog("failed to load cert from smartcard, error in X.509 certificate"); - free_x509cert(x509cert); - return FALSE; + cert_free(cert); + return NULL; } @@ -542,7 +539,7 @@ static void scx_find_cert_objects(CK_SLOT_ID slot, CK_SESSION_HANDLE session) CK_ULONG obj_count = 0; time_t valid_until; smartcard_t *sc; - x509cert_t *cert; + certificate_t *certificate; x509_t *x509; rv = pkcs11_functions->C_FindObjects(session, &object, 1, &obj_count); @@ -562,8 +559,8 @@ static void scx_find_cert_objects(CK_SLOT_ID slot, CK_SESSION_HANDLE session) *sc = empty_sc; sc->any_slot = FALSE; sc->slot = slot; - - if (!scx_find_cert_object(session, object, sc, &sc->last_cert)) + sc->last_cert = scx_find_cert_object(session, object, sc); + if (sc->last_cert == NULL) { scx_free(sc); continue; @@ -574,10 +571,9 @@ static void scx_find_cert_objects(CK_SLOT_ID slot, CK_SESSION_HANDLE session) ) /* check validity of certificate */ - cert = sc->last_cert.u.x509; - if (!cert->cert->get_validity(cert->cert, NULL, NULL, &valid_until)) + certificate = sc->last_cert->cert; + if (!certificate->get_validity(certificate, NULL, NULL, &valid_until)) { - free_x509cert(cert); scx_free(sc); continue; } @@ -586,20 +582,20 @@ static void scx_find_cert_objects(CK_SLOT_ID slot, CK_SESSION_HANDLE session) ) sc = scx_add(sc); - x509 = (x509_t*)cert->cert; + x509 = (x509_t*)certificate; /* put end entity and ca certificates into different chains */ if (x509->get_flags(x509) & X509_CA) { - sc->last_cert.u.x509 = add_authcert(cert, X509_CA); + sc->last_cert = add_authcert(sc->last_cert, X509_CA); } else { - add_x509_public_key(cert, valid_until, DAL_LOCAL); - sc->last_cert.u.x509 = add_x509cert(cert); + add_public_key_from_cert(sc->last_cert, valid_until, DAL_LOCAL); + sc->last_cert = cert_add(sc->last_cert); } - share_cert(sc->last_cert); + cert_share(sc->last_cert); time(&sc->last_load); } @@ -1070,67 +1066,66 @@ void 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) +cert_t* scx_load_cert(const char *filename, smartcard_t **scp, bool *cached) { #ifdef SMARTCARD /* compile with smartcard support */ - CK_OBJECT_HANDLE object; - const char *number_slot_id = filename + strlen(SCX_TOKEN); - - smartcard_t *sc = scx_add(scx_parse_number_slot_id(number_slot_id)); + CK_OBJECT_HANDLE object; + smartcard_t *sc; + cert_t *cert = NULL; /* return the smartcard object */ - *scp = sc; + *scp = sc = scx_add(scx_parse_number_slot_id(number_slot_id)); /* is there a cached smartcard certificate? */ - *cached = sc->last_cert.type != CERT_NONE - && (time(NULL) - sc->last_load) < SCX_CERT_CACHE_INTERVAL; + *cached = sc->last_cert && + (time(NULL) - sc->last_load) < SCX_CERT_CACHE_INTERVAL; if (*cached) { - *cert = sc->last_cert; plog(" using cached cert from smartcard #%d (%s, id: %s, label: '%s')" , sc->number , scx_print_slot(sc, "") , sc->id , sc->label); - return TRUE; + return sc->last_cert; } if (!scx_establish_context(sc)) { scx_release_context(sc); - return FALSE; + return NULL; } /* find the certificate object */ if (!scx_pkcs11_find_object(sc->session, &object, CKO_CERTIFICATE, sc->id)) { scx_release_context(sc); - return FALSE; + return NULL; } /* retrieve the certificate object */ - if (!scx_find_cert_object(sc->session, object, sc, cert)) + cert = scx_find_cert_object(sc->session, object, sc); + if (cert == NULL) { scx_release_context(sc); - return FALSE; + return NULL; } if (!pkcs11_keep_state) + { scx_release_context(sc); - + } plog(" loaded cert from smartcard #%d (%s, id: %s, label: '%s')" , sc->number , scx_print_slot(sc, "") , sc->id , sc->label); - return TRUE; + return cert; #else plog(" warning: SMARTCARD support is deactivated in pluto/Makefile!"); - return FALSE; + return NULL; #endif } @@ -1793,6 +1788,7 @@ void scx_free(smartcard_t *sc) if (sc != NULL) { scx_release_context(sc); + cert_release(sc->last_cert); free(sc->id); free(sc->label); scx_free_pin(&sc->pin); @@ -1811,7 +1807,6 @@ void scx_release(smartcard_t *sc) while (*pp != sc) pp = &(*pp)->next; *pp = sc->next; - release_cert(sc->last_cert); scx_free(sc); } } @@ -1875,14 +1870,16 @@ smartcard_t* 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(cert_t *cert) { smartcard_t *sc = smartcards; while (sc != NULL) { - if (sc->last_cert.u.x509 == cert) + if (sc->last_cert == cert) + { return sc; + } sc = sc->next; } return NULL; @@ -1929,9 +1926,9 @@ void scx_list(bool utc) whack_log(RC_COMMENT, " id: %s", sc->id); if (sc->label != NULL) whack_log(RC_COMMENT, " label: '%s'", sc->label); - if (sc->last_cert.type == CERT_X509_SIGNATURE) + if (sc->last_cert) { - certificate_t *certificate = sc->last_cert.u.x509->cert; + certificate_t *certificate = sc->last_cert->cert; whack_log(RC_COMMENT, " subject: '%Y'", certificate->get_subject(certificate)); diff --git a/src/pluto/smartcard.h b/src/pluto/smartcard.h index 60a0fccfc..7a2229794 100644 --- a/src/pluto/smartcard.h +++ b/src/pluto/smartcard.h @@ -42,7 +42,7 @@ typedef struct smartcard smartcard_t; struct smartcard { smartcard_t *next; time_t last_load; - cert_t last_cert; + cert_t *last_cert; int count; int number; unsigned long slot; @@ -75,8 +75,7 @@ extern void scx_finalize(void); extern bool scx_establish_context(smartcard_t *sc); extern bool scx_login(smartcard_t *sc); extern bool scx_on_smartcard(const char *filename); -extern bool scx_load_cert(const char *filename, smartcard_t **scp - , cert_t *cert, bool *cached); +extern cert_t* scx_load_cert(const char *filename, smartcard_t **scp, bool *cached); extern bool scx_verify_pin(smartcard_t *sc); extern void scx_share(smartcard_t *sc); extern bool scx_sign_hash(smartcard_t *sc, const u_char *in, size_t inlen @@ -90,7 +89,7 @@ extern bool scx_op_via_whack(const char* msg, int inbase, int outbase extern bool scx_get_pin(smartcard_t *sc, int whackfd); extern size_t scx_get_keylength(smartcard_t *sc); extern smartcard_t* scx_add(smartcard_t *sc); -extern smartcard_t* scx_get(x509cert_t *cert); +extern smartcard_t* scx_get(cert_t *cert); extern void scx_release(smartcard_t *sc); extern void scx_release_context(smartcard_t *sc); extern void scx_free_pin(chunk_t *pin); diff --git a/src/pluto/x509.c b/src/pluto/x509.c index a612a70ed..705ff2c57 100644 --- a/src/pluto/x509.c +++ b/src/pluto/x509.c @@ -42,100 +42,6 @@ #include "fetch.h" #include "ocsp.h" -/** - * Chained lists of X.509 end certificates - */ -static x509cert_t *x509certs = NULL; - -const x509cert_t empty_x509cert = { - NULL , /* cert */ - NULL , /* *next */ - 0 , /* count */ - FALSE /* smartcard */ -}; - -/* coding of X.501 distinguished name */ - -/** - * For each link pointing to the certificate increase the count by one - */ -void share_x509cert(x509cert_t *cert) -{ - if (cert != NULL) - { - cert->count++; - } -} - -/** - * Add a X.509 user/host certificate to the chained list - */ -x509cert_t* add_x509cert(x509cert_t *cert) -{ - certificate_t *certificate = cert->cert; - x509cert_t *c = x509certs; - - while (c != NULL) - { - if (certificate->equals(certificate, c->cert)) /* already in chain, free cert */ - { - free_x509cert(cert); - return c; - } - c = c->next; - } - - /* insert new cert at the root of the chain */ - lock_certs_and_keys("add_x509cert"); - cert->next = x509certs; - x509certs = cert; - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log(" x509 cert inserted") - ) - unlock_certs_and_keys("add_x509cert"); - return cert; -} - -/** - * Choose either subject DN or a subjectAltName as connection end ID - */ -identification_t* select_x509cert_id(x509cert_t *cert, identification_t *id) -{ - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; - identification_t *subject, *subjectAltName; - - bool copy_subject_dn = TRUE; /* ID is subject DN */ - - if (id->get_type(id) != ID_ANY) /* check for a matching subjectAltName */ - { - enumerator_t *enumerator; - - enumerator = x509->create_subjectAltName_enumerator(x509); - while (enumerator->enumerate(enumerator, &subjectAltName)) - { - if (id->equals(id, subjectAltName)) - { - copy_subject_dn = FALSE; /* take subjectAltName instead */ - break; - } - } - enumerator->destroy(enumerator); - } - if (copy_subject_dn) - { - id->destroy(id); - subject = certificate->get_subject(certificate); - plog(" no subjectAltName matches ID '%Y', replaced by subject DN", id); - - return subject->clone(subject); - } - else - { - return id; - } -} - /** * Check for equality between two key identifiers */ @@ -151,9 +57,9 @@ bool same_keyid(chunk_t a, chunk_t b) /** * Get a X.509 certificate with a given issuer found at a certain position */ -x509cert_t* get_x509cert(identification_t *issuer, chunk_t keyid, x509cert_t *chain) +cert_t* get_x509cert(identification_t *issuer, chunk_t keyid, cert_t *chain) { - x509cert_t *cert = chain ? chain->next : x509certs; + cert_t *cert = chain->next; while (cert) { @@ -171,48 +77,12 @@ x509cert_t* get_x509cert(identification_t *issuer, chunk_t keyid, x509cert_t *ch return NULL; } -/** - * Free a X.509 certificate - */ -void free_x509cert(x509cert_t *cert) -{ - if (cert) - { - certificate_t *certificate = cert->cert; - - if (certificate) - { - certificate->destroy(certificate); - } - free(cert); - cert = NULL; - } -} - -/** - * Release of a certificate decreases the count by one - * the certificate is freed when the counter reaches zero - */ -void release_x509cert(x509cert_t *cert) -{ - if (cert && --cert->count == 0) - { - x509cert_t **pp = &x509certs; - while (*pp != cert) - { - pp = &(*pp)->next; - } - *pp = cert->next; - free_x509cert(cert); - } -} - /** * Stores a chained list of end certs and CA certs */ void store_x509certs(linked_list_t *certs, bool strict) { - x509cert_t *x509cert, *cacerts = NULL; + cert_t *x509cert, *cacerts = NULL; certificate_t *cert; enumerator_t *enumerator; @@ -235,8 +105,8 @@ void store_x509certs(linked_list_t *certs, bool strict) else { /* insertion into temporary chain of candidate CA certs */ - x509cert = malloc_thing(x509cert_t); - *x509cert = empty_x509cert; + x509cert = malloc_thing(cert_t); + *x509cert = cert_empty; x509cert->cert = cert->get_ref(cert); x509cert->next = cacerts; cacerts = x509cert; @@ -249,7 +119,7 @@ void store_x509certs(linked_list_t *certs, bool strict) while (cacerts) { - x509cert_t *cert = cacerts; + cert_t *cert = cacerts; cacerts = cacerts->next; @@ -260,7 +130,7 @@ void store_x509certs(linked_list_t *certs, bool strict) else { plog("intermediate cacert rejected"); - free_x509cert(cert); + cert_free(cert); } } @@ -274,8 +144,8 @@ void store_x509certs(linked_list_t *certs, bool strict) if (!(x509->get_flags(x509) & X509_CA)) { - x509cert = malloc_thing(x509cert_t); - *x509cert = empty_x509cert; + x509cert = malloc_thing(cert_t); + *x509cert = cert_empty; x509cert->cert = cert->get_ref(cert); if (verify_x509cert(x509cert, strict, &valid_until)) @@ -283,12 +153,12 @@ void store_x509certs(linked_list_t *certs, bool strict) DBG(DBG_CONTROL | DBG_PARSING, DBG_log("public key validated") ) - add_x509_public_key(x509cert, valid_until, DAL_SIGNED); + add_public_key_from_cert(x509cert, valid_until, DAL_SIGNED); } else { plog("X.509 certificate rejected"); - free_x509cert(x509cert); + cert_free(x509cert); } } } @@ -342,7 +212,7 @@ chunk_t x509_build_signature(chunk_t tbs, int algorithm, private_key_t *key, /** * Verifies a X.509 certificate */ -bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until) +bool verify_x509cert(cert_t *cert, bool strict, time_t *until) { int pathlen, pathlen_constraint; @@ -355,7 +225,7 @@ bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until) identification_t *issuer = certificate->get_issuer(certificate); x509_t *x509 = (x509_t*)certificate; chunk_t authKeyID = x509->get_authKeyIdentifier(x509); - x509cert_t *issuer_cert; + cert_t *issuer_cert; time_t notBefore, notAfter; bool valid; @@ -497,7 +367,7 @@ bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until) /** * List all X.509 certs in a chained list */ -void list_x509cert_chain(const char *caption, x509cert_t* cert, +void list_x509cert_chain(const char *caption, cert_t* cert, x509_flag_t flags, bool utc) { bool first = TRUE; @@ -511,7 +381,8 @@ void list_x509cert_chain(const char *caption, x509cert_t* cert, certificate_t *certificate = cert->cert; x509_t *x509 = (x509_t*)certificate; - if (flags == X509_NONE || (flags & x509->get_flags(x509))) + if (certificate->get_type(certificate) == CERT_X509 && + (flags == X509_NONE || (flags & x509->get_flags(x509)))) { enumerator_t *enumerator; char buf[BUF_LEN]; @@ -522,10 +393,6 @@ void list_x509cert_chain(const char *caption, x509cert_t* cert, time_t notBefore, notAfter; public_key_t *key; chunk_t serial, keyid, subjkey, authkey; - cert_t c; - - c.type = CERT_X509_SIGNATURE; - c.u.x509 = cert; if (first) { @@ -581,7 +448,7 @@ void list_x509cert_chain(const char *caption, x509cert_t* cert, 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" : "")); + (has_private_key(cert)? ", has private key" : "")); if (key->get_fingerprint(key, KEY_ID_PUBKEY_INFO_SHA1, &keyid)) { @@ -613,10 +480,3 @@ void list_x509cert_chain(const char *caption, x509cert_t* cert, } } -/** - * List all X.509 end certificates in a chained list - */ -void list_x509_end_certs(bool utc) -{ - list_x509cert_chain("End Entity", x509certs, X509_NONE, utc); -} diff --git a/src/pluto/x509.h b/src/pluto/x509.h index 40e7e7e5d..615b2ab57 100644 --- a/src/pluto/x509.h +++ b/src/pluto/x509.h @@ -20,43 +20,21 @@ #include #include -#include #include #include #include "constants.h" - -/* access structure for an X.509v3 certificate */ - -typedef struct x509cert x509cert_t; - -struct x509cert { - certificate_t *cert; - x509cert_t *next; - int count; - bool smartcard; -}; - -/* used for initialization */ -extern const x509cert_t empty_x509cert; +#include "certs.h" extern bool same_keyid(chunk_t a, chunk_t b); -extern identification_t* select_x509cert_id(x509cert_t *cert, identification_t *id); -extern void parse_authorityKeyIdentifier(chunk_t blob, int level0, - chunk_t *authKeyID, - chunk_t *authKeySerialNumber); extern bool x509_check_signature(chunk_t tbs, chunk_t sig, int algorithm, 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(identification_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); +extern bool verify_x509cert(cert_t *cert, bool strict, time_t *until); +extern cert_t* get_x509cert(identification_t *issuer, chunk_t keyid, cert_t* chain); extern void store_x509certs(linked_list_t *certs, bool strict); -extern void list_x509cert_chain(const char *caption, x509cert_t* cert, +extern void list_x509cert_chain(const char *caption, cert_t* cert, x509_flag_t flags, bool utc); extern void list_x509_end_certs(bool utc); diff --git a/src/whack/whack.h b/src/whack/whack.h index 6d5f0fb4f..3f66a7b4f 100644 --- a/src/whack/whack.h +++ b/src/whack/whack.h @@ -18,6 +18,7 @@ #include #include +#include /* copy of smartcard operations, defined in smartcard.h */ #ifndef SC_OP_T