strongswan/src/pluto/certs.c

269 lines
5.8 KiB
C

/* Certificate support for IKE authentication
* Copyright (C) 2002-2009 Andreas Steffen
*
* HSR - 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 <time.h>
#include <freeswan.h>
#include <library.h>
#include <asn1/asn1.h>
#include <credentials/certificates/certificate.h>
#include <credentials/certificates/pgp_certificate.h>
#include "constants.h"
#include "defs.h"
#include "log.h"
#include "certs.h"
#include "whack.h"
#include "fetch.h"
#include "keys.h"
#include "builder.h"
/**
* Initialization
*/
const cert_t cert_empty = {
NULL , /* cert */
NULL , /* *next */
0 , /* count */
FALSE /* smartcard */
};
/**
* Chained lists of X.509 and PGP end entity certificates
*/
static cert_t *certs = NULL;
/**
* Free a pluto certificate
*/
void cert_free(cert_t *cert)
{
if (cert)
{
certificate_t *certificate = cert->cert;
if (certificate)
{
certificate->destroy(certificate);
}
free(cert);
}
}
/**
* Add a pluto end entity certificate to the chained list
*/
cert_t* cert_add(cert_t *cert)
{
certificate_t *certificate = cert->cert;
cert_t *c;
lock_certs_and_keys("cert_add");
for (c = certs; c != NULL; c = c->next)
{
if (certificate->equals(certificate, c->cert))
{ /* already in chain, free cert */
unlock_certs_and_keys("cert_add");
cert_free(cert);
return c;
}
}
/* insert new cert at the root of the chain */
cert->next = certs;
certs = cert;
DBG(DBG_CONTROL | DBG_PARSING,
DBG_log(" cert inserted")
)
unlock_certs_and_keys("cert_add");
return cert;
}
/**
* Loads a X.509 or OpenPGP certificate
*/
cert_t* load_cert(char *filename, const char *label, x509_flag_t flags)
{
cert_t *cert;
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CERT,
BUILD_FROM_FILE, filename,
BUILD_X509_FLAG, flags,
BUILD_END);
if (cert)
{
plog(" loaded %s certificate from '%s'", label, filename);
}
return cert;
}
/**
* Loads a host certificate
*/
cert_t* load_host_cert(char *filename)
{
char *path = concatenate_paths(HOST_CERT_PATH, filename);
return load_cert(path, "host", X509_NONE);
}
/**
* Loads a CA certificate
*/
cert_t* load_ca_cert(char *filename)
{
char *path = concatenate_paths(CA_CERT_PATH, filename);
return load_cert(path, "CA", X509_NONE);
}
/**
* for each link pointing to the certificate increase the count by one
*/
void cert_share(cert_t *cert)
{
if (cert != NULL)
{
cert->count++;
}
}
/* release of a certificate decreases the count by one
* the certificate is freed when the counter reaches zero
*/
void cert_release(cert_t *cert)
{
if (cert && --cert->count == 0)
{
cert_t **pp = &certs;
while (*pp != cert)
{
pp = &(*pp)->next;
}
*pp = cert->next;
cert_free(cert);
}
}
/**
* Get a X.509 certificate with a given issuer found at a certain position
*/
cert_t* get_x509cert(identification_t *issuer, chunk_t keyid, cert_t *chain)
{
cert_t *cert = chain ? chain->next : certs;
while (cert)
{
certificate_t *certificate = cert->cert;
x509_t *x509 = (x509_t*)certificate;
chunk_t authKeyID = x509->get_authKeyIdentifier(x509);
if (keyid.ptr ? same_keyid(keyid, authKeyID) :
certificate->has_issuer(certificate, issuer))
{
return cert;
}
cert = cert->next;
}
return NULL;
}
/**
* 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),
has_private_key(cert)? ", has private key" : "");
if (key->get_fingerprint(key, KEYID_PUBKEY_INFO_SHA1, &keyid))
{
whack_log(RC_COMMENT, " keyid: %#B", &keyid);
}
if (key->get_fingerprint(key, KEYID_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 cert_list(bool utc)
{
list_x509_end_certs(utc);
list_pgp_end_certs(utc);
}