269 lines
5.8 KiB
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);
|
|
}
|
|
|