diff options
Diffstat (limited to '.pc/snprintf-fix-4.4.0.patch/src/pluto/x509.c')
-rw-r--r-- | .pc/snprintf-fix-4.4.0.patch/src/pluto/x509.c | 459 |
1 files changed, 459 insertions, 0 deletions
diff --git a/.pc/snprintf-fix-4.4.0.patch/src/pluto/x509.c b/.pc/snprintf-fix-4.4.0.patch/src/pluto/x509.c new file mode 100644 index 000000000..0a29830ea --- /dev/null +++ b/.pc/snprintf-fix-4.4.0.patch/src/pluto/x509.c @@ -0,0 +1,459 @@ +/* Support of X.509 certificates + * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann + * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss + * Copyright (C) 2002 Mario Strasser + * Copyright (C) 2000-2009 Andreas Steffen - Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <dirent.h> +#include <time.h> +#include <sys/types.h> + +#include <freeswan.h> + +#include <asn1/asn1.h> +#include <crypto/hashers/hasher.h> +#include <utils/enumerator.h> +#include <utils/identification.h> + +#include "constants.h" +#include "defs.h" +#include "log.h" +#include "x509.h" +#include "crl.h" +#include "ca.h" +#include "certs.h" +#include "keys.h" +#include "whack.h" +#include "fetch.h" +#include "ocsp.h" + +/** + * Check for equality between two key identifiers + */ +bool same_keyid(chunk_t a, chunk_t b) +{ + if (a.ptr == NULL || b.ptr == NULL) + { + return FALSE; + } + return chunk_equals(a, b); +} + +/** + * Stores a chained list of end certs and CA certs + */ +void store_x509certs(linked_list_t *certs, bool strict) +{ + cert_t *x509cert, *cacerts = NULL; + certificate_t *cert; + enumerator_t *enumerator; + + /* first extract CA certs, ignoring self-signed root CA certs */ + + enumerator = certs->create_enumerator(certs); + while (enumerator->enumerate(enumerator, &cert)) + { + x509_t *x509 = (x509_t*)cert; + x509_flag_t flags; + + flags = x509->get_flags(x509); + if (flags & X509_CA) + { + /* we don't accept self-signed CA certs */ + if (flags & X509_SELF_SIGNED) + { + plog("self-signed cacert rejected"); + } + else + { + /* insertion into temporary chain of candidate CA certs */ + x509cert = malloc_thing(cert_t); + *x509cert = cert_empty; + x509cert->cert = cert->get_ref(cert); + x509cert->next = cacerts; + cacerts = x509cert; + } + } + } + enumerator->destroy(enumerator); + + /* now verify the candidate CA certs */ + + while (cacerts) + { + cert_t *cert = cacerts; + + cacerts = cacerts->next; + + if (trust_authcert_candidate(cert, cacerts)) + { + add_authcert(cert, X509_CA); + } + else + { + plog("intermediate cacert rejected"); + cert_free(cert); + } + } + + /* now verify the end certificates */ + + enumerator = certs->create_enumerator(certs); + while (enumerator->enumerate(enumerator, &cert)) + { + time_t valid_until; + x509_t *x509 = (x509_t*)cert; + + if (!(x509->get_flags(x509) & X509_CA)) + { + x509cert = malloc_thing(cert_t); + *x509cert = cert_empty; + x509cert->cert = cert->get_ref(cert); + + if (verify_x509cert(x509cert, strict, &valid_until)) + { + DBG(DBG_CONTROL | DBG_PARSING, + DBG_log("public key validated") + ) + add_public_key_from_cert(x509cert, valid_until, DAL_SIGNED); + } + else + { + plog("X.509 certificate rejected"); + cert_free(x509cert); + } + } + } + enumerator->destroy(enumerator); +} + +/** + * Check if a signature over binary blob is genuine + */ +bool x509_check_signature(chunk_t tbs, chunk_t sig, int algorithm, + certificate_t *issuer_cert) +{ + bool success; + public_key_t *key; + signature_scheme_t scheme; + + scheme = signature_scheme_from_oid(algorithm); + if (scheme == SIGN_UNKNOWN) + { + return FALSE; + } + + 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; +} + +/** + * Build an ASN.1 encoded PKCS#1 signature over a binary blob + */ +chunk_t x509_build_signature(chunk_t tbs, int algorithm, private_key_t *key, + bool bit_string) +{ + chunk_t signature; + signature_scheme_t scheme = signature_scheme_from_oid(algorithm); + + if (scheme == SIGN_UNKNOWN || !key->sign(key, scheme, tbs, &signature)) + { + return chunk_empty; + } + return (bit_string) ? asn1_bitstring("m", signature) + : asn1_wrap(ASN1_OCTET_STRING, "m", signature); +} + +/** + * Verifies a X.509 certificate + */ +bool verify_x509cert(cert_t *cert, bool strict, time_t *until) +{ + int pathlen, pathlen_constraint; + + *until = 0; + + for (pathlen = -1; pathlen <= X509_MAX_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); + cert_t *issuer_cert; + time_t notBefore, notAfter; + bool valid; + + DBG(DBG_CONTROL, + DBG_log("subject: '%Y'", subject); + DBG_log("issuer: '%Y'", issuer); + if (authKeyID.ptr) + { + DBG_log("authkey: %#B", &authKeyID); + } + ) + + valid = certificate->get_validity(certificate, NULL, + ¬Before, ¬After); + if (*until == UNDEFINED_TIME || notAfter < *until) + { + *until = notAfter; + } + if (!valid) + { + plog("certificate is invalid (valid from %T to %T)", + ¬Before, FALSE, ¬After, FALSE); + return FALSE; + } + DBG(DBG_CONTROL, + DBG_log("certificate is valid") + ) + + lock_authcert_list("verify_x509cert"); + issuer_cert = get_authcert(issuer, authKeyID, X509_CA); + if (issuer_cert == NULL) + { + plog("issuer cacert not found"); + unlock_authcert_list("verify_x509cert"); + return FALSE; + } + DBG(DBG_CONTROL, + DBG_log("issuer cacert found") + ) + + if (!certificate->issued_by(certificate, issuer_cert->cert)) + { + plog("certificate signature is invalid"); + unlock_authcert_list("verify_x509cert"); + return FALSE; + } + DBG(DBG_CONTROL, + DBG_log("certificate signature is valid") + ) + unlock_authcert_list("verify_x509cert"); + + /* check path length constraint */ + pathlen_constraint = x509->get_pathLenConstraint(x509); + if (pathlen_constraint != X509_NO_PATH_LEN_CONSTRAINT && + pathlen > pathlen_constraint) + { + plog("path length of %d violates constraint of %d", + pathlen, pathlen_constraint); + return FALSE; + } + + /* check if cert is a self-signed root ca */ + if (pathlen >= 0 && (x509->get_flags(x509) & X509_SELF_SIGNED)) + { + DBG(DBG_CONTROL, + DBG_log("reached self-signed root ca with a path length of %d", + pathlen) + ) + return TRUE; + } + else + { + time_t nextUpdate = *until; + time_t revocationDate = UNDEFINED_TIME; + crl_reason_t revocationReason = CRL_REASON_UNSPECIFIED; + + /* first check certificate revocation using ocsp */ + cert_status_t status = verify_by_ocsp(cert, &nextUpdate + , &revocationDate, &revocationReason); + + /* if ocsp service is not available then fall back to crl */ + if ((status == CERT_UNDEFINED) + || (status == CERT_UNKNOWN && strict)) + { + status = verify_by_crl(cert, &nextUpdate, &revocationDate + , &revocationReason); + } + + switch (status) + { + case CERT_GOOD: + /* if status information is stale */ + if (strict && nextUpdate < time(NULL)) + { + DBG(DBG_CONTROL, + DBG_log("certificate is good but status is stale") + ) + remove_x509_public_key(cert); + return FALSE; + } + DBG(DBG_CONTROL, + DBG_log("certificate is good") + ) + + /* with strict crl policy the public key must have the same + * lifetime as the validity of the ocsp status or crl lifetime + */ + if (strict && nextUpdate < *until) + { + *until = nextUpdate; + } + break; + case CERT_REVOKED: + plog("certificate was revoked on %T, reason: %N" + , &revocationDate, TRUE + , crl_reason_names, revocationReason); + remove_x509_public_key(cert); + return FALSE; + case CERT_UNKNOWN: + case CERT_UNDEFINED: + default: + plog("certificate status unknown"); + if (strict) + { + remove_x509_public_key(cert); + return FALSE; + } + break; + } + } + + /* go up one step in the trust chain */ + cert = issuer_cert; + } + plog("maximum path length of %d exceeded", X509_MAX_PATH_LEN); + return FALSE; +} + +/** + * List all X.509 certs in a chained list + */ +void list_x509cert_chain(const char *caption, cert_t* cert, + x509_flag_t flags, bool utc) +{ + bool first = TRUE; + time_t now; + + /* determine the current time */ + time(&now); + + while (cert) + { + certificate_t *certificate = cert->cert; + x509_t *x509 = (x509_t*)certificate; + + if (certificate->get_type(certificate) == CERT_X509 && + (flags == X509_NONE || (flags & x509->get_flags(x509)))) + { + enumerator_t *enumerator; + char buf[BUF_LEN]; + char *pos = buf; + int len = BUF_LEN, pathlen; + bool first_altName = TRUE; + identification_t *id; + time_t notBefore, notAfter; + public_key_t *key; + chunk_t serial, keyid, subjkey, authkey; + + if (first) + { + whack_log(RC_COMMENT, " "); + whack_log(RC_COMMENT, "List of X.509 %s Certificates:", caption); + first = FALSE; + } + whack_log(RC_COMMENT, " "); + + enumerator = x509->create_subjectAltName_enumerator(x509); + while (enumerator->enumerate(enumerator, &id)) + { + int written; + + if (first_altName) + { + written = snprintf(pos, len, "%Y", id); + first_altName = FALSE; + } + else + { + written = snprintf(pos, len, ", %Y", id); + } + pos += written; + len -= written; + } + enumerator->destroy(enumerator); + if (!first_altName) + { + whack_log(RC_COMMENT, " altNames: %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", + ¬Before, utc, + (notBefore < now)?"ok":"fatal (not valid yet)"); + whack_log(RC_COMMENT, " not after %T %s", + ¬After, utc, + check_expiry(notAfter, CA_CERT_WARNING_INTERVAL, TRUE)); + + key = certificate->get_public_key(certificate); + if (key) + { + 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(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, &subjkey)) + { + whack_log(RC_COMMENT, " subjkey: %#B", &subjkey); + } + key->destroy(key); + } + + /* list optional authorityKeyIdentifier */ + authkey = x509->get_authKeyIdentifier(x509); + if (authkey.ptr) + { + whack_log(RC_COMMENT, " authkey: %#B", &authkey); + } + + /* list optional pathLenConstraint */ + pathlen = x509->get_pathLenConstraint(x509); + if (pathlen != X509_NO_PATH_LEN_CONSTRAINT) + { + whack_log(RC_COMMENT, " pathlen: %d", pathlen); + } + + } + cert = cert->next; + } +} + |