added X.509 trust chain verification

This commit is contained in:
Andreas Steffen 2006-06-27 08:48:28 +00:00
parent c01d911201
commit 6f74bfd6ac
15 changed files with 902 additions and 102 deletions

View File

@ -91,6 +91,16 @@ struct credential_store_t {
*/
bool (*has_rsa_private_key) (credential_store_t *this, rsa_public_key_t *pubkey);
/**
* @brief Verify an X.509 certificate up to trust anchor including revocation checks
*
* @param this calling object
* @param cert certificate to be verified
* @param until time until which the cert can be trusted
* @return TRUE if trusted
*/
bool (*verify) (credential_store_t *this, const x509_t *cert, time_t *until);
/**
* @brief If an end certificate does not already exists in the credential store then add it.
*
@ -108,7 +118,7 @@ struct credential_store_t {
* @return pointer to the added or already existing certificate
*/
x509_t* (*add_ca_certificate) (credential_store_t *this, x509_t *cert);
/**
* @brief Lists all certificates kept in the local credential store.
*

View File

@ -25,15 +25,18 @@
#include <string.h>
#include <pthread.h>
#include "local_credential_store.h"
#include <utils/lexparser.h>
#include <utils/linked_list.h>
#include <utils/logger_manager.h>
#include <crypto/certinfo.h>
#include <crypto/rsa/rsa_public_key.h>
#include <crypto/x509.h>
#include <crypto/crl.h>
#define PATH_BUF 256
#include "local_credential_store.h"
#define PATH_BUF 256
#define MAX_CA_PATH_LEN 7
typedef struct private_local_credential_store_t private_local_credential_store_t;
@ -165,6 +168,236 @@ static bool has_rsa_private_key(private_local_credential_store_t *this, rsa_publ
return found;
}
/**
* Implementation of credential_store_t.get_issuer_certificate.
*/
static x509_t* get_issuer_certificate(private_local_credential_store_t *this, const x509_t *cert)
{
x509_t *issuer_cert = NULL;
iterator_t *iterator = this->ca_certs->create_iterator(this->ca_certs, TRUE);
while (iterator->has_next(iterator))
{
x509_t *current_cert;
iterator->current(iterator, (void**)&current_cert);
if (cert->is_issuer(cert, current_cert))
{
issuer_cert = current_cert;
break;
}
}
iterator->destroy(iterator);
return issuer_cert;
}
/**
* Implementation of credential_store_t.get_crl.
*/
static crl_t* get_crl(private_local_credential_store_t *this, const x509_t *issuer)
{
crl_t *crl = NULL;
iterator_t *iterator = this->crls->create_iterator(this->crls, TRUE);
while (iterator->has_next(iterator))
{
crl_t *current_crl;
iterator->current(iterator, (void**)&current_crl);
if (current_crl->is_issuer(current_crl, issuer))
{
crl = current_crl;
break;
}
}
iterator->destroy(iterator);
return crl;
}
/**
* Verify the certificate status using CRLs
*/
static cert_status_t verify_by_crl(private_local_credential_store_t* this, const x509_t *cert,
const x509_t *issuer_cert, certinfo_t *certinfo)
{
crl_t *crl;
bool valid_signature;
rsa_public_key_t *issuer_public_key;
pthread_mutex_lock(&(this->crls_mutex));
crl = get_crl(this, issuer_cert);
if (crl == NULL)
{
this->logger->log(this->logger, ERROR, "crl not found");
goto err;
}
this->logger->log(this->logger, CONTROL|LEVEL1, "crl found");
issuer_public_key = issuer_cert->get_public_key(issuer_cert);
valid_signature = crl->verify(crl, issuer_public_key);
issuer_public_key->destroy(issuer_public_key);
if (!valid_signature)
{
this->logger->log(this->logger, ERROR, "crl signature is invalid");
goto err;
}
this->logger->log(this->logger, CONTROL|LEVEL1, "crl signature is valid");
crl->get_status(crl, certinfo);
err:
pthread_mutex_unlock(&(this->crls_mutex));
return certinfo->get_status(certinfo);
}
/**
* Verify the certificate status using OCSP
*/
static cert_status_t verify_by_ocsp(private_local_credential_store_t* this,
const x509_t *cert, certinfo_t *certinfo)
{
/* TODO implement function */
return CERT_UNDEFINED;
}
/**
* Remove a public key for the linked list
*/
static void remove_public_key(private_local_credential_store_t *this, const x509_t *cert)
{
/* TODO implement function */
}
/**
* Implementation of credential_store_t.verify.
*/
static bool verify(private_local_credential_store_t *this, const x509_t *cert, time_t *until)
{
int pathlen;
*until = UNDEFINED_TIME;
for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++)
{
err_t ugh = NULL;
x509_t *issuer_cert;
rsa_public_key_t *issuer_public_key;
bool valid_signature;
identification_t *subject = cert->get_subject(cert);
identification_t *issuer = cert->get_issuer(cert);
this->logger->log(this->logger, CONTROL|LEVEL1, "subject: '%s'", subject->get_string(subject));
this->logger->log(this->logger, CONTROL|LEVEL1, "issuer: '%s'", issuer->get_string(issuer));
ugh = cert->is_valid(cert, until);
if (ugh != NULL)
{
this->logger->log(this->logger, ERROR, "certificate %s", ugh);
return FALSE;
}
this->logger->log(this->logger, CONTROL|LEVEL1, "certificate is valid");
issuer_cert = get_issuer_certificate(this, cert);
if (issuer_cert == NULL)
{
this->logger->log(this->logger, ERROR, "issuer certificate not found");
return FALSE;
}
this->logger->log(this->logger, CONTROL|LEVEL1, "issuer certificate found");
issuer_public_key = issuer_cert->get_public_key(issuer_cert);
valid_signature = cert->verify(cert, issuer_public_key);
issuer_public_key->destroy(issuer_public_key);
if (!valid_signature)
{
this->logger->log(this->logger, ERROR, "certificate signature is invalid");
return FALSE;
}
this->logger->log(this->logger, CONTROL|LEVEL1, "certificate signature is valid");
/* check if cert is a self-signed root ca */
if (pathlen > 0 && cert->is_self_signed(cert))
{
this->logger->log(this->logger, CONTROL|LEVEL1, "reached self-signed root ca");
return TRUE;
}
else
{
time_t nextUpdate;
cert_status_t status;
certinfo_t *certinfo = certinfo_create(cert->get_serialNumber(cert));
certinfo->set_nextUpdate(certinfo, *until);
/* first check certificate revocation using ocsp */
status = verify_by_ocsp(this, cert, certinfo);
/* if ocsp service is not available then fall back to crl */
if ((status == CERT_UNDEFINED) || (status == CERT_UNKNOWN && this->strict))
{
status = verify_by_crl(this, cert, issuer_cert, certinfo);
}
nextUpdate = certinfo->get_nextUpdate(certinfo);
switch (status)
{
case CERT_GOOD:
/* if status information is stale */
if (this->strict && nextUpdate < time(NULL))
{
this->logger->log(this->logger, CONTROL|LEVEL1, "certificate is good but status is stale");
remove_public_key(this, cert);
return FALSE;
}
this->logger->log(this->logger, CONTROL|LEVEL1, "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 (this->strict && nextUpdate < *until)
*until = nextUpdate;
break;
case CERT_REVOKED:
{
u_char buf[TIMETOA_BUF];
time_t revocationTime = certinfo->get_revocationTime(certinfo);
timetoa(buf, TIMETOA_BUF, &revocationTime, TRUE);
this->logger->log(this->logger, ERROR, "certificate was revoked on %s, reason: %s",
buf, certinfo->get_revocationReason(certinfo));
remove_public_key(this, cert);
return FALSE;
}
case CERT_UNKNOWN:
case CERT_UNDEFINED:
default:
this->logger->log(this->logger, CONTROL|LEVEL1, "certificate status unknown");
if (this->strict)
{
remove_public_key(this, cert);
return FALSE;
}
break;
}
certinfo->destroy(certinfo);
}
/* go up one step in the trust chain */
cert = issuer_cert;
}
this->logger->log(this->logger, ERROR, "maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN);
return FALSE;
}
/**
* Add a unique certificate to a linked list
*/
@ -600,6 +833,7 @@ local_credential_store_t * local_credential_store_create(bool strict)
this->public.credential_store.get_rsa_private_key = (rsa_private_key_t*(*)(credential_store_t*,rsa_public_key_t*))get_rsa_private_key;
this->public.credential_store.has_rsa_private_key = (bool(*)(credential_store_t*,rsa_public_key_t*))has_rsa_private_key;
this->public.credential_store.get_rsa_public_key = (rsa_public_key_t*(*)(credential_store_t*,identification_t*))get_rsa_public_key;
this->public.credential_store.verify = (bool(*)(credential_store_t*,const x509_t*,time_t*))verify;
this->public.credential_store.add_end_certificate = (x509_t*(*)(credential_store_t*,x509_t*))add_end_certificate;
this->public.credential_store.add_ca_certificate = (x509_t*(*)(credential_store_t*,x509_t*))add_ca_certificate;
this->public.credential_store.log_certificates = (void(*)(credential_store_t*,logger_t*,bool))log_certificates;

View File

@ -136,6 +136,7 @@ static x509_t* load_end_certificate(const char *filename, identification_t **idp
{
identification_t *id = *idp;
identification_t *subject = cert->get_subject(cert);
time_t until;
err_t ugh = cert->is_valid(cert, NULL);
@ -149,6 +150,20 @@ static x509_t* load_end_certificate(const char *filename, identification_t **idp
id = subject;
*idp = id->clone(id);
}
/* test output */
if (charon->credentials->verify(charon->credentials, cert, &until))
{
char buf[TIMETOA_BUF];
timetoa(buf, TIMETOA_BUF, &until, TRUE);
logger->log(logger, CONTROL, " end entity certificate is trusted until %s", buf);
cert->set_until(cert, until);
}
else
{
logger->log(logger, ERROR, " end entity certificate is not trusted");
}
/* end of test output */
return charon->credentials->add_end_certificate(charon->credentials, cert);
}
return NULL;
@ -305,7 +320,7 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
}
if (msg->add_conn.me.cert)
{
x509_t *cert = load_end_certificate(msg->add_conn.me.cert, &my_id, this->stroke_logger);
x509_t *cert = load_end_certificate(msg->add_conn.me.cert, &my_id, this->logger);
if (my_ca == NULL && !my_ca_same && cert)
{
@ -316,7 +331,7 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
}
if (msg->add_conn.other.cert)
{
x509_t *cert = load_end_certificate(msg->add_conn.other.cert, &other_id, this->stroke_logger);
x509_t *cert = load_end_certificate(msg->add_conn.other.cert, &other_id, this->logger);
if (other_ca == NULL && !other_ca_same && cert)
{

View File

@ -21,6 +21,7 @@ crypto/hashers/sha1_hasher.c crypto/hashers/sha1_hasher.h \
crypto/hashers/md5_hasher.c crypto/hashers/md5_hasher.h \
crypto/prf_plus.h crypto/prf_plus.c \
crypto/hmac.c crypto/hmac.h \
crypto/certinfo.c crypto/certinfo.h \
crypto/x509.c crypto/x509.h \
crypto/crl.c crypto/crl.h \
crypto/diffie_hellman.c crypto/diffie_hellman.h \

View File

@ -0,0 +1,198 @@
/**
* @file certinfo.c
*
* @brief Implementation of certinfo_t.
*
*/
/*
* Copyright (C) 2006 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 <time.h>
#include <types.h>
#include <definitions.h>
#include "certinfo.h"
typedef struct private_certinfo_t private_certinfo_t;
/**
* Private data of a certinfo_t object.
*/
struct private_certinfo_t {
/**
* Public interface for this certificate status information object.
*/
certinfo_t public;
/**
* Serial number of the certificate
*/
chunk_t serialNumber;
/**
* Certificate status
*/
cert_status_t status;
/**
* Time when the certificate status info was generated
*/
time_t thisUpdate;
/**
* Time when an updated certifcate status info will be available
*/
time_t nextUpdate;
/**
* Time of certificate revocation
*/
time_t revocationTime;
/**
* Reason of certificate revocation
*/
crl_reason_t revocationReason;
};
/**
* RFC 2459 CRL reason codes
*/
static const char *const crl_reason_name[] = {
"unspecified",
"key compromise",
"ca compromise",
"affiliation changed",
"superseded",
"cessation of operation",
"certificate hold",
"reason #7",
"remove from crl"
};
enum_names crl_reason_names =
{ REASON_UNSPECIFIED, REASON_REMOVE_FROM_CRL, crl_reason_name, NULL};
/**
* Implements certinfo_t.get_serialNumber
*/
static chunk_t get_serialNumber(const private_certinfo_t *this)
{
return this->serialNumber;
}
/**
* Implements certinfo_t.set_status
*/
static void set_status(private_certinfo_t *this, cert_status_t status)
{
this->status = status;
}
/**
* Implements certinfo_t.get_status
*/
static cert_status_t get_status(const private_certinfo_t *this)
{
return this->status;
}
/**
* Implements certinfo_t.set_nextUpdate
*/
static void set_nextUpdate(private_certinfo_t *this, time_t nextUpdate)
{
this->nextUpdate = nextUpdate;
}
/**
* Implements certinfo_t.get_nextUpdate
*/
static time_t get_nextUpdate(const private_certinfo_t *this)
{
return this->nextUpdate;
}
/**
* Implements certinfo_t.set_revocationTime
*/
static void set_revocationTime(private_certinfo_t *this, time_t revocationTime)
{
this->revocationTime = revocationTime;
}
/**
* Implements certinfo_t.get_revocationTime
*/
static time_t get_revocationTime(const private_certinfo_t *this)
{
return this->revocationTime;
}
/**
* Implements certinfo_t.set_revocationReason
*/
static void set_revocationReason(private_certinfo_t *this, crl_reason_t reason)
{
this->revocationReason = reason;
}
/**
* Implements certinfo_t.get_revocationReason
*/
static const char *get_revocationReason(const private_certinfo_t *this)
{
return enum_name(&crl_reason_names, this->revocationReason);
}
/**
* Implements certinfo_t.destroy
*/
static void destroy(private_certinfo_t *this)
{
free(this->serialNumber.ptr);
free(this);
}
/*
* Described in header.
*/
certinfo_t *certinfo_create(chunk_t serial)
{
private_certinfo_t *this = malloc_thing(private_certinfo_t);
/* initialize */
this->serialNumber = chunk_clone(serial);
this->status = CERT_UNDEFINED;
this->nextUpdate = UNDEFINED_TIME;
this->revocationTime = UNDEFINED_TIME;
this->revocationReason = REASON_UNSPECIFIED;
/* public functions */
this->public.get_serialNumber = (chunk_t (*) (const certinfo_t*))get_serialNumber;
this->public.set_status = (void (*) (certinfo_t*,cert_status_t))set_status;
this->public.get_status = (cert_status_t (*) (const certinfo_t*))get_status;
this->public.set_nextUpdate = (void (*) (certinfo_t*,time_t))set_nextUpdate;
this->public.get_nextUpdate = (time_t (*) (const certinfo_t*))get_nextUpdate;
this->public.set_revocationTime = (void (*) (certinfo_t*,time_t))set_revocationTime;
this->public.get_revocationTime = (time_t (*) (const certinfo_t*))get_revocationTime;
this->public.set_revocationReason = (void (*) (certinfo_t*, crl_reason_t))set_revocationReason;
this->public.get_revocationReason = (const char *(*) (const certinfo_t*))get_revocationReason;
this->public.destroy = (void (*) (certinfo_t*))destroy;
return &this->public;
}

View File

@ -0,0 +1,166 @@
/**
* @file certinfo.h
*
* @brief Interface of certinfo_t.
*
*/
/*
* Copyright (C) 2006 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.
*/
#ifndef CERTINFO_H_
#define CERTINFO_H_
#include <types.h>
#include <definitions.h>
/**
* RFC 2560 OCSP - certificate status
*/
typedef enum {
CERT_GOOD = 0,
CERT_REVOKED = 1,
CERT_UNKNOWN = 2,
CERT_UNDEFINED = 3
} cert_status_t;
/**
* RFC 2459 CRL reason codes
*/
extern enum_names crl_reason_names;
typedef enum {
REASON_UNSPECIFIED = 0,
REASON_KEY_COMPROMISE = 1,
REASON_CA_COMPROMISE = 2,
REASON_AFFILIATION_CHANGED = 3,
REASON_SUPERSEDED = 4,
REASON_CESSATION_OF_OPERATON = 5,
REASON_CERTIFICATE_HOLD = 6,
REASON_REMOVE_FROM_CRL = 8
} crl_reason_t;
typedef struct certinfo_t certinfo_t;
/**
* @brief X.509 certificate status information
*
*
* @ingroup transforms
*/
struct certinfo_t {
/**
* @brief Get serial number
*
*
* @param this calling object
* @return serialNumber
*/
chunk_t (*get_serialNumber) (const certinfo_t *this);
/**
* @brief Set certificate status
*
*
* @param this calling object
* @param status status
*/
void (*set_status) (certinfo_t *this, cert_status_t status);
/**
* @brief Get certificate status
*
*
* @param this calling object
* @return status
*/
cert_status_t (*get_status) (const certinfo_t *this);
/**
* @brief Set nextUpdate
*
*
* @param this calling object
* @return nextUpdate
*/
void (*set_nextUpdate) (certinfo_t *this, time_t nextUpdate);
/**
* @brief Get nextUpdate
*
*
* @param this calling object
* @return nextUpdate
*/
time_t (*get_nextUpdate) (const certinfo_t *this);
/**
* @brief Set revocationTime
*
*
* @param this calling object
* @param revocationTime revocationTime
*/
void (*set_revocationTime) (certinfo_t *this, time_t revocationTime);
/**
* @brief Get revocationTime
*
*
* @param this calling object
* @return revocationTime
*/
time_t (*get_revocationTime) (const certinfo_t *this);
/**
* @brief Set revocationReason
*
*
* @param this calling object
* @param reason revocationReason
*/
void (*set_revocationReason) (certinfo_t *this, crl_reason_t reason);
/**
* @brief Get revocationReason
*
*
* @param this calling object
* @return revocationReason
*/
const char *(*get_revocationReason) (const certinfo_t *this);
/**
* @brief Destroys the certinfo_t object.
*
* @param this crl to destroy
*/
void (*destroy) (certinfo_t *this);
};
/**
* @brief Create a certinfo_t object.
*
* @param serial chunk serial number of the certificate
* @return created certinfo_t object
*
* @ingroup transforms
*/
certinfo_t *certinfo_create(chunk_t serial);
#endif /* CERTINFO_H_ */

View File

@ -33,8 +33,9 @@
#include <utils/linked_list.h>
#include <utils/identification.h>
#include "crl.h"
#include "certinfo.h"
#include "x509.h"
#include "crl.h"
#define CRL_WARNING_INTERVAL 7 /* days */
@ -132,8 +133,9 @@ struct private_crl_t {
chunk_t signature;
};
/* ASN.1 definition of an X.509 certificate revocation list */
/**
* ASN.1 definition of an X.509 certificate revocation list
*/
static const asn1Object_t crlObjects[] = {
{ 0, "certificateList", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
{ 1, "tbsCertList", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
@ -201,7 +203,8 @@ static crl_reason_t parse_crl_reasonCode(chunk_t object)
{
reason = *object.ptr;
}
/* TODO logger->log(logger, CONTROL|LEVEL2, " '%s'", enum_name(&crl_reason_names, reason)) */
logger->log(logger, CONTROL|LEVEL2, " '%s'", enum_name(&crl_reason_names, reason));
return reason;
}
@ -331,14 +334,6 @@ static err_t is_valid(const private_crl_t *this, time_t *until, bool strict)
return NULL;
}
/**
* Implements crl_t.is_newer
*/
static bool is_newer(const private_crl_t *this, const private_crl_t *other)
{
return (this->nextUpdate > other->nextUpdate);
}
/**
* Implements crl_t.get_issuer
*/
@ -359,7 +354,61 @@ static bool equals_issuer(const private_crl_t *this, const private_crl_t *other)
}
/**
* destroy
* Implements crl_t.is_issuer
*/
static bool is_issuer(const private_crl_t *this, const x509_t *issuer)
{
return (this->authKeyID.ptr)
? chunk_equals(this->authKeyID, issuer->get_subjectKeyID(issuer))
: (this->issuer->equals(this->issuer, issuer->get_subject(issuer))
&& chunk_equals_or_null(this->authKeySerialNumber, issuer->get_serialNumber(issuer)));
}
/**
* Implements crl_t.is_newer
*/
static bool is_newer(const private_crl_t *this, const private_crl_t *other)
{
return (this->nextUpdate > other->nextUpdate);
}
/**
* Implements crl_t.verify
*/
static bool verify(const private_crl_t *this, const rsa_public_key_t *signer)
{
return signer->verify_emsa_pkcs1_signature(signer, this->tbsCertList, this->signature);
}
/**
* Implements crl_t.get_status
*/
static void get_status(const private_crl_t *this, certinfo_t *certinfo)
{
chunk_t serialNumber = certinfo->get_serialNumber(certinfo);
iterator_t *iterator = this->revokedCertificates->create_iterator(this->revokedCertificates, TRUE);
certinfo->set_nextUpdate(certinfo, this->nextUpdate);
certinfo->set_status(certinfo, CERT_GOOD);
while (iterator->has_next(iterator))
{
revokedCert_t *revokedCert;
iterator->current(iterator, (void**)&revokedCert);
if (chunk_equals(serialNumber, revokedCert->userCertificate))
{
certinfo->set_status(certinfo, CERT_REVOKED);
certinfo->set_revocationTime(certinfo, revokedCert->revocationDate);
certinfo->set_revocationReason(certinfo, revokedCert->revocationReason);
break;
}
}
iterator->destroy(iterator);
}
/**
* Implements crl_t.destroy
*/
static void destroy(private_crl_t *this)
{
@ -440,12 +489,15 @@ crl_t *crl_create_from_chunk(chunk_t chunk)
this->authKeySerialNumber = CHUNK_INITIALIZER;
/* public functions */
this->public.is_valid = (err_t (*) (const crl_t*,time_t*))is_valid;
this->public.destroy = (void (*) (crl_t*))destroy;
this->public.get_issuer = (identification_t* (*) (const crl_t*))get_issuer;
this->public.equals_issuer = (bool (*) (const crl_t*,const crl_t*))equals_issuer;
this->public.is_issuer = (bool (*) (const crl_t*,const x509_t*))is_issuer;
this->public.is_valid = (err_t (*) (const crl_t*,time_t*,bool))is_valid;
this->public.is_newer = (bool (*) (const crl_t*,const crl_t*))is_newer;
this->public.verify = (bool (*) (const crl_t*,const rsa_public_key_t*))verify;
this->public.get_status = (void (*) (const crl_t*,certinfo_t*))get_status;
this->public.log_crl = (void (*) (const crl_t*,logger_t*,bool,bool))log_crl;
this->public.destroy = (void (*) (crl_t*))destroy;
/* we do not use a per-instance logger right now, since its not always accessible */
logger = logger_manager->get_logger(logger_manager, ASN1);

View File

@ -26,11 +26,11 @@
#include <types.h>
#include <definitions.h>
#include <crypto/rsa/rsa_public_key.h>
#include <crypto/certinfo.h>
#include <utils/identification.h>
#include <utils/iterator.h>
#include <utils/logger.h>
typedef struct crl_t crl_t;
/**
@ -54,7 +54,7 @@ struct crl_t {
* @return issuers ID
*/
identification_t *(*get_issuer) (const crl_t *this);
/**
* @brief Check if both crls have the same issuer.
*
@ -65,15 +65,14 @@ struct crl_t {
bool (*equals_issuer) (const crl_t *this, const crl_t *other);
/**
* @brief Check if a crl is trustworthy
* @brief Check if ia candidate cert is the issuer of the crl
*
* Use the issuer's public key to verify
* the trustworthiness of a crl.
*
* @todo implement!
* @param this calling object
* @param issuer candidate issuer of the crl
* @return TRUE if issuer
*/
bool (*verify) (const crl_t *this, rsa_public_key_t *signer);
bool (*is_issuer) (const crl_t *this, const x509_t *issuer);
/**
* @brief Checks the validity interval of the crl
*
@ -94,13 +93,21 @@ struct crl_t {
bool (*is_newer) (const crl_t *this, const crl_t *other);
/**
* @brief Check if a certificate has been revoked.
*
* This function uses the certificate's serialNumber
* to get the revocation status.
* @brief Check if a crl is trustworthy.
*
* @param this calling object
* @param signer signer's RSA public key
* @return TRUE if crl is trustworthy
*/
bool (*get_status) (const crl_t *this, chunk_t serial);
bool (*verify) (const crl_t *this, const rsa_public_key_t *signer);
/**
* @brief Get the certificate status
*
* @param this calling object
* @param certinfo certinfo is updated
*/
void (*get_status) (const crl_t *this, certinfo_t *certinfo);
/**
* @brief Destroys the crl.

View File

@ -141,7 +141,7 @@ struct private_rsa_public_key_t {
* @param data data to process
* @return processed data
*/
chunk_t (*rsaep) (private_rsa_public_key_t *this, chunk_t data);
chunk_t (*rsaep) (const private_rsa_public_key_t *this, chunk_t data);
/**
* @brief Implements the RSASVP1 algorithm specified in PKCS#1.
@ -150,7 +150,7 @@ struct private_rsa_public_key_t {
* @param data data to process
* @return processed data
*/
chunk_t (*rsavp1) (private_rsa_public_key_t *this, chunk_t data);
chunk_t (*rsavp1) (const private_rsa_public_key_t *this, chunk_t data);
};
private_rsa_public_key_t *rsa_public_key_create_empty(void);
@ -158,7 +158,7 @@ private_rsa_public_key_t *rsa_public_key_create_empty(void);
/**
* Implementation of private_rsa_public_key_t.rsaep and private_rsa_public_key_t.rsavp1
*/
static chunk_t rsaep(private_rsa_public_key_t *this, chunk_t data)
static chunk_t rsaep(const private_rsa_public_key_t *this, chunk_t data)
{
mpz_t m, c;
chunk_t encrypted;
@ -182,7 +182,7 @@ static chunk_t rsaep(private_rsa_public_key_t *this, chunk_t data)
/**
* Implementation of rsa_public_key.verify_emsa_pkcs1_signature.
*/
static status_t verify_emsa_pkcs1_signature(private_rsa_public_key_t *this, chunk_t data, chunk_t signature)
static status_t verify_emsa_pkcs1_signature(const private_rsa_public_key_t *this, chunk_t data, chunk_t signature)
{
hasher_t *hasher = NULL;
chunk_t hash;
@ -291,7 +291,7 @@ end:
/**
* Implementation of rsa_public_key.get_key.
*/
static status_t get_key(private_rsa_public_key_t *this, chunk_t *key)
static status_t get_key(const private_rsa_public_key_t *this, chunk_t *key)
{
chunk_t n, e;
@ -313,7 +313,7 @@ static status_t get_key(private_rsa_public_key_t *this, chunk_t *key)
/**
* Implementation of rsa_public_key.save_key.
*/
static status_t save_key(private_rsa_public_key_t *this, char *file)
static status_t save_key(const private_rsa_public_key_t *this, char *file)
{
return NOT_SUPPORTED;
}
@ -321,7 +321,7 @@ static status_t save_key(private_rsa_public_key_t *this, char *file)
/**
* Implementation of rsa_public_key.get_modulus.
*/
static mpz_t *get_modulus(private_rsa_public_key_t *this)
static mpz_t *get_modulus(const private_rsa_public_key_t *this)
{
return &this->n;
}
@ -329,7 +329,7 @@ static mpz_t *get_modulus(private_rsa_public_key_t *this)
/**
* Implementation of rsa_public_key.get_keysize.
*/
static size_t get_keysize(private_rsa_public_key_t *this)
static size_t get_keysize(const private_rsa_public_key_t *this)
{
return this->k;
}
@ -337,7 +337,7 @@ static size_t get_keysize(private_rsa_public_key_t *this)
/**
* Implementation of rsa_public_key.get_keyid.
*/
static chunk_t get_keyid(private_rsa_public_key_t *this)
static chunk_t get_keyid(const private_rsa_public_key_t *this)
{
return this->keyid;
}
@ -345,7 +345,7 @@ static chunk_t get_keyid(private_rsa_public_key_t *this)
/**
* Implementation of rsa_public_key.clone.
*/
static rsa_public_key_t* _clone(private_rsa_public_key_t *this)
static rsa_public_key_t* _clone(const private_rsa_public_key_t *this)
{
private_rsa_public_key_t *clone = rsa_public_key_create_empty();
@ -376,13 +376,13 @@ private_rsa_public_key_t *rsa_public_key_create_empty(void)
private_rsa_public_key_t *this = malloc_thing(private_rsa_public_key_t);
/* public functions */
this->public.verify_emsa_pkcs1_signature = (status_t (*) (rsa_public_key_t*,chunk_t,chunk_t))verify_emsa_pkcs1_signature;
this->public.get_key = (status_t (*) (rsa_public_key_t*,chunk_t*))get_key;
this->public.save_key = (status_t (*) (rsa_public_key_t*,char*))save_key;
this->public.get_modulus = (mpz_t *(*) (rsa_public_key_t*))get_modulus;
this->public.get_keysize = (size_t (*) (rsa_public_key_t*))get_keysize;
this->public.get_keyid = (chunk_t (*) (rsa_public_key_t*))get_keyid;
this->public.clone = (rsa_public_key_t* (*) (rsa_public_key_t*))_clone;
this->public.verify_emsa_pkcs1_signature = (status_t (*) (const rsa_public_key_t*,chunk_t,chunk_t))verify_emsa_pkcs1_signature;
this->public.get_key = (status_t (*) (const rsa_public_key_t*,chunk_t*))get_key;
this->public.save_key = (status_t (*) (const rsa_public_key_t*,char*))save_key;
this->public.get_modulus = (mpz_t *(*) (const rsa_public_key_t*))get_modulus;
this->public.get_keysize = (size_t (*) (const rsa_public_key_t*))get_keysize;
this->public.get_keyid = (chunk_t (*) (const rsa_public_key_t*))get_keyid;
this->public.clone = (rsa_public_key_t* (*) (const rsa_public_key_t*))_clone;
this->public.destroy = (void (*) (rsa_public_key_t*))destroy;
/* private functions */

View File

@ -67,7 +67,7 @@ struct rsa_public_key_t {
* - INVALID_ARG, if signature is not a signature
* - FAILED if signature invalid or unable to verify
*/
status_t (*verify_emsa_pkcs1_signature) (rsa_public_key_t *this, chunk_t data, chunk_t signature);
status_t (*verify_emsa_pkcs1_signature) (const rsa_public_key_t *this, chunk_t data, chunk_t signature);
/**
* @brief Gets the key.
@ -83,7 +83,7 @@ struct rsa_public_key_t {
* - SUCCESS
* - INVALID_STATE, if key not set
*/
status_t (*get_key) (rsa_public_key_t *this, chunk_t *key);
status_t (*get_key) (const rsa_public_key_t *this, chunk_t *key);
/**
* @brief Saves a key to a file.
@ -94,7 +94,7 @@ struct rsa_public_key_t {
* @param file file to which the key should be written.
* @return NOT_SUPPORTED
*/
status_t (*save_key) (rsa_public_key_t *this, char *file);
status_t (*save_key) (const rsa_public_key_t *this, char *file);
/**
* @brief Get the modulus of the key.
@ -102,7 +102,7 @@ struct rsa_public_key_t {
* @param this calling object
* @return modulus (n) of the key
*/
mpz_t *(*get_modulus) (rsa_public_key_t *this);
mpz_t *(*get_modulus) (const rsa_public_key_t *this);
/**
* @brief Get the size of the modulus in bytes.
@ -110,7 +110,7 @@ struct rsa_public_key_t {
* @param this calling object
* @return size of the modulus (n) in bytes
*/
size_t (*get_keysize) (rsa_public_key_t *this);
size_t (*get_keysize) (const rsa_public_key_t *this);
/**
* @brief Get the keyid formed as the SHA-1 hash of a publicKeyInfo object.
@ -118,7 +118,7 @@ struct rsa_public_key_t {
* @param this calling object
* @return keyid in the form of a SHA-1 hash
*/
chunk_t (*get_keyid) (rsa_public_key_t *this);
chunk_t (*get_keyid) (const rsa_public_key_t *this);
/**
* @brief Clone the public key.
@ -126,7 +126,7 @@ struct rsa_public_key_t {
* @param this public key to clone
* @return clone of this
*/
rsa_public_key_t *(*clone) (rsa_public_key_t *this);
rsa_public_key_t *(*clone) (const rsa_public_key_t *this);
/**
* @brief Destroys the public key.

View File

@ -73,6 +73,11 @@ struct private_x509_t {
*/
time_t installed;
/**
* Time until certificate can be trusted
*/
time_t until;
/**
* X.509 Certificate in DER format
*/
@ -909,6 +914,14 @@ static bool is_ca(const private_x509_t *this)
return this->isCA;
}
/**
* Implements x509_t.is_self_signed
*/
static bool is_self_signed(const private_x509_t *this)
{
return this->subject->equals(this->subject, this->issuer);
}
/**
* Implements x509_t.equals_subjectAltName
*/
@ -932,6 +945,17 @@ static bool equals_subjectAltName(const private_x509_t *this, identification_t *
return found;
}
/**
* Implements x509_t.is_issuer
*/
static bool is_issuer(const private_x509_t *this, const private_x509_t *issuer)
{
return (this->authKeyID.ptr)
? chunk_equals(this->authKeyID, issuer->subjectKeyID)
: (this->issuer->equals(this->issuer, issuer->subject)
&& chunk_equals_or_null(this->authKeySerialNumber, issuer->serialNumber));
}
/**
* Implements x509_t.get_public_key
*/
@ -940,6 +964,30 @@ static rsa_public_key_t *get_public_key(const private_x509_t *this)
return this->public_key->clone(this->public_key);
}
/**
* Implements x509_t.get_serialNumber
*/
static chunk_t get_serialNumber(const private_x509_t *this)
{
return this->serialNumber;
}
/**
* Implements x509_t.get_subjectKeyID
*/
static chunk_t get_subjectKeyID(const private_x509_t *this)
{
return this->subjectKeyID;
}
/**
* Implements x509_t.get_issuer
*/
static identification_t *get_issuer(const private_x509_t *this)
{
return this->issuer;
}
/**
* Implements x509_t.get_subject
*/
@ -949,11 +997,19 @@ static identification_t *get_subject(const private_x509_t *this)
}
/**
* Implements x509_t.get_issuer
* Implements x509_t.set_until
*/
static identification_t *get_issuer(const private_x509_t *this)
static void set_until(private_x509_t *this, time_t until)
{
return this->issuer;
this->until = until;
}
/**
* Implements x509_t.verify
*/
static bool verify(const private_x509_t *this, const rsa_public_key_t *signer)
{
return signer->verify_emsa_pkcs1_signature(signer, this->tbsCertificate, this->signature);
}
/**
@ -1060,8 +1116,11 @@ static void log_certificate(const private_x509_t *this, logger_t *logger, bool u
logger->log(logger, CONTROL, " not after %s %s", buf,
check_expiry(this->notAfter, CERT_WARNING_INTERVAL, TRUE));
logger->log(logger, CONTROL, " pubkey: RSA %d bits%s",
BITS_PER_BYTE * pubkey->get_keysize(pubkey), has_key? ", has private key":"");
timetoa(buf, BUF_LEN, &this->until, utc);
logger->log(logger, CONTROL, " pubkey: RSA %d bits%s, until %s",
BITS_PER_BYTE * pubkey->get_keysize(pubkey),
has_key? ", has private key":"", buf);
chunk_to_hex(buf, BUF_LEN, pubkey->get_keyid(pubkey));
logger->log(logger, CONTROL, " keyid: %s", buf);
@ -1103,12 +1162,18 @@ x509_t *x509_create_from_chunk(chunk_t chunk)
/* public functions */
this->public.equals = (bool (*) (const x509_t*,const x509_t*))equals;
this->public.equals_subjectAltName = (bool (*) (const x509_t*,identification_t*))equals_subjectAltName;
this->public.is_issuer = (bool (*) (const x509_t*,const x509_t*))is_issuer;
this->public.is_valid = (err_t (*) (const x509_t*,time_t*))is_valid;
this->public.is_ca = (bool (*) (const x509_t*))is_ca;
this->public.destroy = (void (*) (x509_t*))destroy;
this->public.is_self_signed = (bool (*) (const x509_t*))is_self_signed;
this->public.get_public_key = (rsa_public_key_t* (*) (const x509_t*))get_public_key;
this->public.get_subject = (identification_t* (*) (const x509_t*))get_subject;
this->public.get_serialNumber = (chunk_t (*) (const x509_t*))get_serialNumber;
this->public.get_subjectKeyID = (chunk_t (*) (const x509_t*))get_subjectKeyID;
this->public.get_issuer = (identification_t* (*) (const x509_t*))get_issuer;
this->public.get_subject = (identification_t* (*) (const x509_t*))get_subject;
this->public.set_until = (void (*) (x509_t*,time_t))set_until;
this->public.verify = (bool (*) (const x509_t*,const rsa_public_key_t*))verify;
this->public.destroy = (void (*) (x509_t*))destroy;
this->public.log_certificate = (void (*) (const x509_t*,logger_t*,bool,bool))log_certificate;
/* we do not use a per-instance logger right now, since its not always accessible */
@ -1127,7 +1192,8 @@ x509_t *x509_create_from_chunk(chunk_t chunk)
destroy(this);
return NULL;
}
/* set trusted lifetime of public key to notAfter */
this->until = this->notAfter;
return &this->public;
}

View File

@ -48,6 +48,14 @@ typedef struct x509_t x509_t;
*/
struct x509_t {
/**
* @brief Set trusted public key life.
*
* @param this calling object
* @param until time until public key is trusted
*/
void (*set_until) (x509_t *this, time_t until);
/**
* @brief Get the RSA public key from the certificate.
*
@ -55,9 +63,25 @@ struct x509_t {
* @return public_key
*/
rsa_public_key_t *(*get_public_key) (const x509_t *this);
/**
* @brief Get serial number from the certificate.
*
* @param this calling object
* @return serialNumber
*/
chunk_t (*get_serialNumber) (const x509_t *this);
/**
* @brief Get the certificate issuers ID.
* @brief Get serial number from the certificate.
*
* @param this calling object
* @return subjectKeyID
*/
chunk_t (*get_subjectKeyID) (const x509_t *this);
/**
* @brief Get the certificate issuer's ID.
*
* The resulting ID is always a identification_t
* of type ID_DER_ASN1_DN.
@ -81,19 +105,10 @@ struct x509_t {
/**
* @brief Check if a certificate is trustworthy
*
* Use the issuer's public key to verify
* the trustworthiness of a certificate.
*
* @todo implement!
* @param this calling object
* @param signer signer's RSA public key
*/
bool (*verify) (const x509_t *this, rsa_public_key_t *signer);
/**
* @brief Get the key identifier of the public key.
*
* @todo implement!
*/
chunk_t (*get_subject_key_identifier) (const x509_t *this);
bool (*verify) (const x509_t *this, const rsa_public_key_t *signer);
/**
* @brief Compare two certificates.
@ -102,7 +117,7 @@ struct x509_t {
*
* @param this first cert for compare
* @param other second cert for compare
* @return TRUE if signature is equal
* @return TRUE if signature is equal
*/
bool (*equals) (const x509_t *this, const x509_t *that);
@ -111,16 +126,25 @@ struct x509_t {
*
* @param this certificate being examined
* @param id id which is being compared to the subjectAltNames
* @return TRUE if a match is found
* @return TRUE if a match is found
*/
bool (*equals_subjectAltName) (const x509_t *this, identification_t *id);
/**
* @brief Checks if the subject of the other cert is the issuer of this cert.
*
* @param this certificate
* @param issuer potential issuer certificate
* @return TRUE if issuer is found
*/
bool (*is_issuer) (const x509_t *this, const x509_t *issuer);
/**
* @brief Checks the validity interval of the certificate
*
* @param this certificate being examined
* @param until until = min(until, notAfter)
* @return NULL if the certificate is valid
* @return NULL if the certificate is valid
*/
err_t (*is_valid) (const x509_t *this, time_t *until);
@ -128,10 +152,18 @@ struct x509_t {
* @brief Returns the CA basic constraints flag
*
* @param this certificate being examined
* @return TRUE if the CA flag is set
* @return TRUE if the CA flag is set
*/
bool (*is_ca) (const x509_t *this);
/**
* @brief Checks if the certificate is self-signed (subject equals issuer)
*
* @param this certificate being examined
* @return TRUE if self-signed
*/
bool (*is_self_signed) (const x509_t *this);
/**
* @brief Destroys the certificate.
*
@ -154,7 +186,7 @@ struct x509_t {
* @brief Read a x509 certificate from a DER encoded blob.
*
* @param chunk chunk containing DER encoded data
* @return created x509_t certificate, or NULL if invalid.
* @return created x509_t certificate, or NULL if invlid.
*
* @ingroup transforms
*/

View File

@ -20,6 +20,8 @@
* for more details.
*/
#include <stdlib.h>
#include "definitions.h"
/*
@ -38,3 +40,19 @@ char *mapping_find(mapping_t * maps, int value)
}
return "INVALID MAPPING";
}
/*
* Described in header
*/
const char *enum_name(enum_names *ed, unsigned long val)
{
enum_names *p;
for (p = ed; p != NULL; p = p->en_next_range)
{
if (p->en_first <= val && val <= p->en_last)
return p->en_names[val - p->en_first];
}
return NULL;
}

View File

@ -135,4 +135,22 @@ struct mapping_t
*/
char *mapping_find(mapping_t *mappings, int value);
/**
* @brief Describes an enumeration
* enum_name() returns the name of an enum value, or NULL if invalid.
*/
typedef const struct enum_names enum_names;
struct enum_names {
unsigned long en_first; /* first value in range */
unsigned long en_last; /* last value in range (inclusive) */
const char *const *en_names;
enum_names *en_next_range; /* descriptor of next range */
};
/**
* @brief Returns the name of an enum value, or NULL if invalid
*/
const char *enum_name(enum_names *ed, unsigned long val);
#endif /*DEFINITIONS_H_*/

View File

@ -109,23 +109,6 @@ enum status_t {
CREATED,
};
/**
* RFC 2459 CRL reason codes
*/
/* TODO extern enum_names crl_reason_names; */
typedef enum {
REASON_UNSPECIFIED = 0,
REASON_KEY_COMPROMISE = 1,
REASON_CA_COMPROMISE = 2,
REASON_AFFILIATION_CHANGED = 3,
REASON_SUPERSEDED = 4,
REASON_CESSATION_OF_OPERATON = 5,
REASON_CERTIFICATE_HOLD = 6,
REASON_REMOVE_FROM_CRL = 8
} crl_reason_t;
/**
* String mappings for type status_t.
*/