- import of strongswan-2.7.0
- applied patch for charon
This commit is contained in:
@@ -0,0 +1,763 @@
|
||||
/* Support of X.509 certificate revocation lists (CRLs)
|
||||
* Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* RCSID $Id: crl.c,v 1.12 2005/12/06 22:49:57 as Exp $
|
||||
*/
|
||||
|
||||
#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 <freeswan/ipsec_policy.h>
|
||||
|
||||
#include "constants.h"
|
||||
#include "defs.h"
|
||||
#include "log.h"
|
||||
#include "asn1.h"
|
||||
#include "oid.h"
|
||||
#include "x509.h"
|
||||
#include "crl.h"
|
||||
#include "ca.h"
|
||||
#include "certs.h"
|
||||
#include "keys.h"
|
||||
#include "whack.h"
|
||||
#include "fetch.h"
|
||||
#include "sha1.h"
|
||||
|
||||
/* chained lists of X.509 crls */
|
||||
|
||||
static x509crl_t *x509crls = NULL;
|
||||
|
||||
/* ASN.1 definition of an X.509 certificate list */
|
||||
|
||||
static const asn1Object_t crlObjects[] = {
|
||||
{ 0, "certificateList", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
|
||||
{ 1, "tbsCertList", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
|
||||
{ 2, "version", ASN1_INTEGER, ASN1_OPT |
|
||||
ASN1_BODY }, /* 2 */
|
||||
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
|
||||
{ 2, "signature", ASN1_EOC, ASN1_RAW }, /* 4 */
|
||||
{ 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
|
||||
{ 2, "thisUpdate", ASN1_EOC, ASN1_RAW }, /* 6 */
|
||||
{ 2, "nextUpdate", ASN1_EOC, ASN1_RAW }, /* 7 */
|
||||
{ 2, "revokedCertificates", ASN1_SEQUENCE, ASN1_OPT |
|
||||
ASN1_LOOP }, /* 8 */
|
||||
{ 3, "certList", ASN1_SEQUENCE, ASN1_NONE }, /* 9 */
|
||||
{ 4, "userCertificate", ASN1_INTEGER, ASN1_BODY }, /* 10 */
|
||||
{ 4, "revocationDate", ASN1_EOC, ASN1_RAW }, /* 11 */
|
||||
{ 4, "crlEntryExtensions", ASN1_SEQUENCE, ASN1_OPT |
|
||||
ASN1_LOOP }, /* 12 */
|
||||
{ 5, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */
|
||||
{ 6, "extnID", ASN1_OID, ASN1_BODY }, /* 14 */
|
||||
{ 6, "critical", ASN1_BOOLEAN, ASN1_DEF |
|
||||
ASN1_BODY }, /* 15 */
|
||||
{ 6, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 16 */
|
||||
{ 4, "end opt or loop", ASN1_EOC, ASN1_END }, /* 17 */
|
||||
{ 2, "end opt or loop", ASN1_EOC, ASN1_END }, /* 18 */
|
||||
{ 2, "optional extensions", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 19 */
|
||||
{ 3, "crlExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */
|
||||
{ 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */
|
||||
{ 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */
|
||||
{ 5, "critical", ASN1_BOOLEAN, ASN1_DEF |
|
||||
ASN1_BODY }, /* 23 */
|
||||
{ 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */
|
||||
{ 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
|
||||
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */
|
||||
{ 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */
|
||||
{ 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 28 */
|
||||
};
|
||||
|
||||
#define CRL_OBJ_CERTIFICATE_LIST 0
|
||||
#define CRL_OBJ_TBS_CERT_LIST 1
|
||||
#define CRL_OBJ_VERSION 2
|
||||
#define CRL_OBJ_SIG_ALG 4
|
||||
#define CRL_OBJ_ISSUER 5
|
||||
#define CRL_OBJ_THIS_UPDATE 6
|
||||
#define CRL_OBJ_NEXT_UPDATE 7
|
||||
#define CRL_OBJ_USER_CERTIFICATE 10
|
||||
#define CRL_OBJ_REVOCATION_DATE 11
|
||||
#define CRL_OBJ_CRL_ENTRY_EXTN_ID 14
|
||||
#define CRL_OBJ_CRL_ENTRY_CRITICAL 15
|
||||
#define CRL_OBJ_CRL_ENTRY_EXTN_VALUE 16
|
||||
#define CRL_OBJ_EXTN_ID 22
|
||||
#define CRL_OBJ_CRITICAL 23
|
||||
#define CRL_OBJ_EXTN_VALUE 24
|
||||
#define CRL_OBJ_ALGORITHM 27
|
||||
#define CRL_OBJ_SIGNATURE 28
|
||||
#define CRL_OBJ_ROOF 29
|
||||
|
||||
|
||||
const x509crl_t empty_x509crl = {
|
||||
NULL , /* *next */
|
||||
UNDEFINED_TIME, /* installed */
|
||||
NULL , /* distributionPoints */
|
||||
{ NULL, 0 } , /* certificateList */
|
||||
{ NULL, 0 } , /* tbsCertList */
|
||||
1 , /* version */
|
||||
OID_UNKNOWN , /* sigAlg */
|
||||
{ NULL, 0 } , /* issuer */
|
||||
UNDEFINED_TIME, /* thisUpdate */
|
||||
UNDEFINED_TIME, /* nextUpdate */
|
||||
NULL , /* revokedCertificates */
|
||||
/* crlExtensions */
|
||||
/* extension */
|
||||
/* extnID */
|
||||
/* critical */
|
||||
/* extnValue */
|
||||
{ NULL, 0 } , /* authKeyID */
|
||||
{ NULL, 0 } , /* authKeySerialNumber */
|
||||
OID_UNKNOWN , /* algorithm */
|
||||
{ NULL, 0 } /* signature */
|
||||
};
|
||||
|
||||
/*
|
||||
* get the X.509 CRL with a given issuer
|
||||
*/
|
||||
static x509crl_t*
|
||||
get_x509crl(chunk_t issuer, chunk_t serial, chunk_t keyid)
|
||||
{
|
||||
x509crl_t *crl = x509crls;
|
||||
x509crl_t *prev_crl = NULL;
|
||||
|
||||
while (crl != NULL)
|
||||
{
|
||||
if ((keyid.ptr != NULL && crl->authKeyID.ptr != NULL)
|
||||
? same_keyid(keyid, crl->authKeyID)
|
||||
: (same_dn(crl->issuer, issuer) && same_serial(serial, crl->authKeySerialNumber)))
|
||||
{
|
||||
if (crl != x509crls)
|
||||
{
|
||||
/* bring the CRL up front */
|
||||
prev_crl->next = crl->next;
|
||||
crl->next = x509crls;
|
||||
x509crls = crl;
|
||||
}
|
||||
return crl;
|
||||
}
|
||||
prev_crl = crl;
|
||||
crl = crl->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* free the dynamic memory used to store revoked certificates
|
||||
*/
|
||||
static void
|
||||
free_revoked_certs(revokedCert_t* revokedCerts)
|
||||
{
|
||||
while (revokedCerts != NULL)
|
||||
{
|
||||
revokedCert_t * revokedCert = revokedCerts;
|
||||
revokedCerts = revokedCert->next;
|
||||
pfree(revokedCert);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* free the dynamic memory used to store CRLs
|
||||
*/
|
||||
void
|
||||
free_crl(x509crl_t *crl)
|
||||
{
|
||||
free_revoked_certs(crl->revokedCertificates);
|
||||
free_generalNames(crl->distributionPoints, TRUE);
|
||||
pfree(crl->certificateList.ptr);
|
||||
pfree(crl);
|
||||
}
|
||||
|
||||
static void
|
||||
free_first_crl(void)
|
||||
{
|
||||
x509crl_t *crl = x509crls;
|
||||
|
||||
x509crls = crl->next;
|
||||
free_crl(crl);
|
||||
}
|
||||
|
||||
void
|
||||
free_crls(void)
|
||||
{
|
||||
lock_crl_list("free_crls");
|
||||
|
||||
while (x509crls != NULL)
|
||||
free_first_crl();
|
||||
|
||||
unlock_crl_list("free_crls");
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert X.509 CRL into chained list
|
||||
*/
|
||||
bool
|
||||
insert_crl(chunk_t blob, chunk_t crl_uri, bool cache_crl)
|
||||
{
|
||||
x509crl_t *crl = alloc_thing(x509crl_t, "x509crl");
|
||||
|
||||
*crl = empty_x509crl;
|
||||
|
||||
if (parse_x509crl(blob, 0, crl))
|
||||
{
|
||||
x509cert_t *issuer_cert;
|
||||
x509crl_t *oldcrl;
|
||||
bool valid_sig;
|
||||
generalName_t *gn;
|
||||
|
||||
/* add distribution point */
|
||||
gn = alloc_thing(generalName_t, "generalName");
|
||||
gn->kind = GN_URI;
|
||||
gn->name = crl_uri;
|
||||
gn->next = crl->distributionPoints;
|
||||
crl->distributionPoints = gn;
|
||||
|
||||
lock_authcert_list("insert_crl");
|
||||
/* get the issuer cacert */
|
||||
issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber,
|
||||
crl->authKeyID, AUTH_CA);
|
||||
if (issuer_cert == NULL)
|
||||
{
|
||||
plog("crl issuer cacert not found");
|
||||
free_crl(crl);
|
||||
unlock_authcert_list("insert_crl");
|
||||
return FALSE;
|
||||
}
|
||||
DBG(DBG_CONTROL,
|
||||
DBG_log("crl issuer cacert found")
|
||||
)
|
||||
|
||||
/* check the issuer's signature of the crl */
|
||||
valid_sig = check_signature(crl->tbsCertList, crl->signature
|
||||
, crl->algorithm, crl->algorithm, issuer_cert);
|
||||
unlock_authcert_list("insert_crl");
|
||||
|
||||
if (!valid_sig)
|
||||
{
|
||||
free_crl(crl);
|
||||
return FALSE;
|
||||
}
|
||||
DBG(DBG_CONTROL,
|
||||
DBG_log("crl signature is valid")
|
||||
)
|
||||
|
||||
lock_crl_list("insert_crl");
|
||||
oldcrl = get_x509crl(crl->issuer, crl->authKeySerialNumber
|
||||
, crl->authKeyID);
|
||||
|
||||
if (oldcrl != NULL)
|
||||
{
|
||||
if (crl->thisUpdate > oldcrl->thisUpdate)
|
||||
{
|
||||
/* keep any known CRL distribution points */
|
||||
add_distribution_points(oldcrl->distributionPoints
|
||||
, &crl->distributionPoints);
|
||||
|
||||
/* now delete the old CRL */
|
||||
free_first_crl();
|
||||
DBG(DBG_CONTROL,
|
||||
DBG_log("thisUpdate is newer - existing crl deleted")
|
||||
)
|
||||
}
|
||||
else
|
||||
{
|
||||
unlock_crl_list("insert_crls");
|
||||
DBG(DBG_CONTROL,
|
||||
DBG_log("thisUpdate is not newer - existing crl not replaced");
|
||||
)
|
||||
free_crl(crl);
|
||||
return oldcrl->nextUpdate - time(NULL) > 2*crl_check_interval;
|
||||
}
|
||||
}
|
||||
|
||||
/* insert new CRL */
|
||||
crl->next = x509crls;
|
||||
x509crls = crl;
|
||||
|
||||
unlock_crl_list("insert_crl");
|
||||
|
||||
/* If crl caching is enabled then the crl is saved locally.
|
||||
* Only http or ldap URIs are cached but not local file URIs.
|
||||
* The issuer's subjectKeyID is used as a unique filename
|
||||
*/
|
||||
if (cache_crl && strncasecmp(crl_uri.ptr, "file", 4) != 0)
|
||||
{
|
||||
char path[BUF_LEN];
|
||||
char buf[BUF_LEN];
|
||||
char digest_buf[SHA1_DIGEST_SIZE];
|
||||
chunk_t subjectKeyID = { digest_buf, SHA1_DIGEST_SIZE };
|
||||
|
||||
if (issuer_cert->subjectKeyID.ptr == NULL)
|
||||
compute_subjectKeyID(issuer_cert, subjectKeyID);
|
||||
else
|
||||
subjectKeyID = issuer_cert->subjectKeyID;
|
||||
|
||||
datatot(subjectKeyID.ptr, subjectKeyID.len, 16, buf, BUF_LEN);
|
||||
snprintf(path, BUF_LEN, "%s/%s.crl", CRL_PATH, buf);
|
||||
write_chunk(path, "crl", crl->certificateList, 0022, TRUE);
|
||||
}
|
||||
|
||||
/* is the fetched crl valid? */
|
||||
return crl->nextUpdate - time(NULL) > 2*crl_check_interval;
|
||||
}
|
||||
else
|
||||
{
|
||||
plog(" error in X.509 crl");
|
||||
free_crl(crl);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads CRLs
|
||||
*/
|
||||
void
|
||||
load_crls(void)
|
||||
{
|
||||
struct dirent **filelist;
|
||||
u_char buf[BUF_LEN];
|
||||
u_char *save_dir;
|
||||
int n;
|
||||
|
||||
/* change directory to specified path */
|
||||
save_dir = getcwd(buf, BUF_LEN);
|
||||
if (chdir(CRL_PATH))
|
||||
{
|
||||
plog("Could not change to directory '%s'", CRL_PATH);
|
||||
}
|
||||
else
|
||||
{
|
||||
plog("Changing to directory '%s'", CRL_PATH);
|
||||
n = scandir(CRL_PATH, &filelist, file_select, alphasort);
|
||||
|
||||
if (n < 0)
|
||||
plog(" scandir() error");
|
||||
else
|
||||
{
|
||||
while (n--)
|
||||
{
|
||||
bool pgp = FALSE;
|
||||
chunk_t blob = empty_chunk;
|
||||
char *filename = filelist[n]->d_name;
|
||||
|
||||
if (load_coded_file(filename, NULL, "crl", &blob, &pgp))
|
||||
{
|
||||
chunk_t crl_uri;
|
||||
|
||||
crl_uri.len = 7 + sizeof(CRL_PATH) + strlen(filename);
|
||||
crl_uri.ptr = alloc_bytes(crl_uri.len + 1, "crl uri");
|
||||
|
||||
/* build CRL file URI */
|
||||
snprintf(crl_uri.ptr, crl_uri.len + 1, "file://%s/%s"
|
||||
, CRL_PATH, filename);
|
||||
|
||||
insert_crl(blob, crl_uri, FALSE);
|
||||
}
|
||||
free(filelist[n]);
|
||||
}
|
||||
free(filelist);
|
||||
}
|
||||
}
|
||||
/* restore directory path */
|
||||
chdir(save_dir);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses a CRL revocation reason code
|
||||
*/
|
||||
static crl_reason_t
|
||||
parse_crl_reasonCode(chunk_t object)
|
||||
{
|
||||
crl_reason_t reason = REASON_UNSPECIFIED;
|
||||
|
||||
if (*object.ptr == ASN1_ENUMERATED
|
||||
&& asn1_length(&object) == 1)
|
||||
{
|
||||
reason = *object.ptr;
|
||||
}
|
||||
|
||||
DBG(DBG_PARSING,
|
||||
DBG_log(" '%s'", enum_name(&crl_reason_names, reason))
|
||||
)
|
||||
return reason;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses an X.509 CRL
|
||||
*/
|
||||
bool
|
||||
parse_x509crl(chunk_t blob, u_int level0, x509crl_t *crl)
|
||||
{
|
||||
u_char buf[BUF_LEN];
|
||||
asn1_ctx_t ctx;
|
||||
bool critical;
|
||||
chunk_t extnID;
|
||||
chunk_t userCertificate;
|
||||
chunk_t object;
|
||||
u_int level;
|
||||
int objectID = 0;
|
||||
|
||||
asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
|
||||
|
||||
while (objectID < CRL_OBJ_ROOF)
|
||||
{
|
||||
if (!extract_object(crlObjects, &objectID, &object, &level, &ctx))
|
||||
return FALSE;
|
||||
|
||||
/* those objects which will parsed further need the next higher level */
|
||||
level++;
|
||||
|
||||
switch (objectID) {
|
||||
case CRL_OBJ_CERTIFICATE_LIST:
|
||||
crl->certificateList = object;
|
||||
break;
|
||||
case CRL_OBJ_TBS_CERT_LIST:
|
||||
crl->tbsCertList = object;
|
||||
break;
|
||||
case CRL_OBJ_VERSION:
|
||||
crl->version = (object.len) ? (1+(u_int)*object.ptr) : 1;
|
||||
DBG(DBG_PARSING,
|
||||
DBG_log(" v%d", crl->version);
|
||||
)
|
||||
break;
|
||||
case CRL_OBJ_SIG_ALG:
|
||||
crl->sigAlg = parse_algorithmIdentifier(object, level, NULL);
|
||||
break;
|
||||
case CRL_OBJ_ISSUER:
|
||||
crl->issuer = object;
|
||||
DBG(DBG_PARSING,
|
||||
dntoa(buf, BUF_LEN, object);
|
||||
DBG_log(" '%s'",buf)
|
||||
)
|
||||
break;
|
||||
case CRL_OBJ_THIS_UPDATE:
|
||||
crl->thisUpdate = parse_time(object, level);
|
||||
break;
|
||||
case CRL_OBJ_NEXT_UPDATE:
|
||||
crl->nextUpdate = parse_time(object, level);
|
||||
break;
|
||||
case CRL_OBJ_USER_CERTIFICATE:
|
||||
userCertificate = object;
|
||||
break;
|
||||
case CRL_OBJ_REVOCATION_DATE:
|
||||
{
|
||||
/* put all the serial numbers and the revocation date in a chained list
|
||||
with revocedCertificates pointing to the first revoked certificate */
|
||||
|
||||
revokedCert_t *revokedCert = alloc_thing(revokedCert_t, "revokedCert");
|
||||
revokedCert->userCertificate = userCertificate;
|
||||
revokedCert->revocationDate = parse_time(object, level);
|
||||
revokedCert->revocationReason = REASON_UNSPECIFIED;
|
||||
revokedCert->next = crl->revokedCertificates;
|
||||
crl->revokedCertificates = revokedCert;
|
||||
}
|
||||
break;
|
||||
case CRL_OBJ_CRL_ENTRY_EXTN_ID:
|
||||
case CRL_OBJ_EXTN_ID:
|
||||
extnID = object;
|
||||
break;
|
||||
case CRL_OBJ_CRL_ENTRY_CRITICAL:
|
||||
case CRL_OBJ_CRITICAL:
|
||||
critical = object.len && *object.ptr;
|
||||
DBG(DBG_PARSING,
|
||||
DBG_log(" %s",(critical)?"TRUE":"FALSE");
|
||||
)
|
||||
break;
|
||||
case CRL_OBJ_CRL_ENTRY_EXTN_VALUE:
|
||||
case CRL_OBJ_EXTN_VALUE:
|
||||
{
|
||||
u_int extn_oid = known_oid(extnID);
|
||||
|
||||
if (extn_oid == OID_CRL_REASON_CODE)
|
||||
{
|
||||
crl->revokedCertificates->revocationReason =
|
||||
parse_crl_reasonCode(object);
|
||||
}
|
||||
else if (extn_oid == OID_AUTHORITY_KEY_ID)
|
||||
{
|
||||
parse_authorityKeyIdentifier(object, level
|
||||
, &crl->authKeyID, &crl->authKeySerialNumber);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CRL_OBJ_ALGORITHM:
|
||||
crl->algorithm = parse_algorithmIdentifier(object, level, NULL);
|
||||
break;
|
||||
case CRL_OBJ_SIGNATURE:
|
||||
crl->signature = object;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
time(&crl->installed);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Checks if the current certificate is revoked. It goes through the
|
||||
* list of revoked certificates of the corresponding crl. Either the
|
||||
* status CERT_GOOD or CERT_REVOKED is returned
|
||||
*/
|
||||
static cert_status_t
|
||||
check_revocation(const x509crl_t *crl, chunk_t serial
|
||||
, time_t *revocationDate, crl_reason_t * revocationReason)
|
||||
{
|
||||
revokedCert_t *revokedCert = crl->revokedCertificates;
|
||||
|
||||
*revocationDate = UNDEFINED_TIME;
|
||||
*revocationReason = REASON_UNSPECIFIED;
|
||||
|
||||
DBG(DBG_CONTROL,
|
||||
DBG_dump_chunk("serial number:", serial)
|
||||
)
|
||||
|
||||
while(revokedCert != NULL)
|
||||
{
|
||||
/* compare serial numbers */
|
||||
if (revokedCert->userCertificate.len == serial.len &&
|
||||
memcmp(revokedCert->userCertificate.ptr, serial.ptr, serial.len) == 0)
|
||||
{
|
||||
*revocationDate = revokedCert->revocationDate;
|
||||
*revocationReason = revokedCert->revocationReason;
|
||||
return CERT_REVOKED;
|
||||
}
|
||||
revokedCert = revokedCert->next;
|
||||
}
|
||||
return CERT_GOOD;
|
||||
}
|
||||
|
||||
/*
|
||||
* check if any crls are about to expire
|
||||
*/
|
||||
void
|
||||
check_crls(void)
|
||||
{
|
||||
x509crl_t *crl;
|
||||
|
||||
lock_crl_list("check_crls");
|
||||
crl = x509crls;
|
||||
|
||||
while (crl != NULL)
|
||||
{
|
||||
time_t time_left = crl->nextUpdate - time(NULL);
|
||||
u_char buf[BUF_LEN];
|
||||
|
||||
DBG(DBG_CONTROL,
|
||||
dntoa(buf, BUF_LEN, crl->issuer);
|
||||
DBG_log("issuer: '%s'",buf);
|
||||
if (crl->authKeyID.ptr != NULL)
|
||||
{
|
||||
datatot(crl->authKeyID.ptr, crl->authKeyID.len, ':'
|
||||
, buf, BUF_LEN);
|
||||
DBG_log("authkey: %s", buf);
|
||||
}
|
||||
DBG_log("%ld seconds left", time_left)
|
||||
)
|
||||
if (time_left < 2*crl_check_interval)
|
||||
{
|
||||
fetch_req_t *req = build_crl_fetch_request(crl->issuer
|
||||
, crl->authKeySerialNumber
|
||||
, crl->authKeyID, crl->distributionPoints);
|
||||
add_crl_fetch_request(req);
|
||||
}
|
||||
crl = crl->next;
|
||||
}
|
||||
unlock_crl_list("check_crls");
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
, crl_reason_t *revocationReason)
|
||||
{
|
||||
x509crl_t *crl;
|
||||
|
||||
ca_info_t *ca = get_ca_info(cert->issuer, cert->authKeySerialNumber
|
||||
, cert->authKeyID);
|
||||
|
||||
generalName_t *crluri = (ca == NULL)? NULL : ca->crluri;
|
||||
|
||||
*revocationDate = UNDEFINED_TIME;
|
||||
*revocationReason = REASON_UNSPECIFIED;
|
||||
|
||||
lock_crl_list("verify_by_crl");
|
||||
crl = get_x509crl(cert->issuer, cert->authKeySerialNumber, cert->authKeyID);
|
||||
|
||||
if (crl == NULL)
|
||||
{
|
||||
unlock_crl_list("verify_by_crl");
|
||||
plog("crl not found");
|
||||
|
||||
if (cert->crlDistributionPoints != NULL)
|
||||
{
|
||||
fetch_req_t *req = build_crl_fetch_request(cert->issuer
|
||||
, cert->authKeySerialNumber
|
||||
, cert->authKeyID, cert->crlDistributionPoints);
|
||||
add_crl_fetch_request(req);
|
||||
}
|
||||
|
||||
if (crluri != NULL)
|
||||
{
|
||||
fetch_req_t *req = build_crl_fetch_request(cert->issuer
|
||||
, cert->authKeySerialNumber
|
||||
, cert->authKeyID, crluri);
|
||||
add_crl_fetch_request(req);
|
||||
}
|
||||
|
||||
if (cert->crlDistributionPoints != 0 || crluri != NULL)
|
||||
{
|
||||
wake_fetch_thread("verify_by_crl");
|
||||
return CERT_UNKNOWN;
|
||||
}
|
||||
else
|
||||
return CERT_UNDEFINED;
|
||||
}
|
||||
else
|
||||
{
|
||||
x509cert_t *issuer_cert;
|
||||
bool valid;
|
||||
|
||||
DBG(DBG_CONTROL,
|
||||
DBG_log("crl found")
|
||||
)
|
||||
|
||||
add_distribution_points(cert->crlDistributionPoints
|
||||
, &crl->distributionPoints);
|
||||
|
||||
add_distribution_points(crluri
|
||||
, &crl->distributionPoints);
|
||||
|
||||
lock_authcert_list("verify_by_crl");
|
||||
|
||||
issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber
|
||||
, crl->authKeyID, AUTH_CA);
|
||||
valid = check_signature(crl->tbsCertList, crl->signature
|
||||
, crl->algorithm, crl->algorithm, issuer_cert);
|
||||
|
||||
unlock_authcert_list("verify_by_crl");
|
||||
|
||||
if (valid)
|
||||
{
|
||||
cert_status_t status;
|
||||
|
||||
DBG(DBG_CONTROL,
|
||||
DBG_log("crl signature is valid")
|
||||
)
|
||||
/* return the expiration date */
|
||||
*until = crl->nextUpdate;
|
||||
|
||||
/* has the certificate been revoked? */
|
||||
status = check_revocation(crl, cert->serialNumber, revocationDate
|
||||
, revocationReason);
|
||||
|
||||
if (*until < time(NULL))
|
||||
{
|
||||
fetch_req_t *req;
|
||||
|
||||
plog("crl update is overdue since %s"
|
||||
, timetoa(until, TRUE));
|
||||
|
||||
/* try to fetch a crl update */
|
||||
req = build_crl_fetch_request(crl->issuer
|
||||
, crl->authKeySerialNumber
|
||||
, crl->authKeyID, crl->distributionPoints);
|
||||
unlock_crl_list("verify_by_crl");
|
||||
|
||||
add_crl_fetch_request(req);
|
||||
wake_fetch_thread("verify_by_crl");
|
||||
}
|
||||
else
|
||||
{
|
||||
unlock_crl_list("verify_by_crl");
|
||||
DBG(DBG_CONTROL,
|
||||
DBG_log("crl is valid")
|
||||
)
|
||||
}
|
||||
return status;
|
||||
}
|
||||
else
|
||||
{
|
||||
unlock_crl_list("verify_by_crl");
|
||||
plog("crl signature is invalid");
|
||||
return CERT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* list all X.509 crls in the chained list
|
||||
*/
|
||||
void
|
||||
list_crls(bool utc, bool strict)
|
||||
{
|
||||
x509crl_t *crl;
|
||||
|
||||
lock_crl_list("list_crls");
|
||||
crl = x509crls;
|
||||
|
||||
if (crl != NULL)
|
||||
{
|
||||
whack_log(RC_COMMENT, " ");
|
||||
whack_log(RC_COMMENT, "List of X.509 CRLs:");
|
||||
whack_log(RC_COMMENT, " ");
|
||||
}
|
||||
|
||||
while (crl != NULL)
|
||||
{
|
||||
u_char buf[BUF_LEN];
|
||||
u_int revoked = 0;
|
||||
revokedCert_t *revokedCert = crl->revokedCertificates;
|
||||
|
||||
/* count number of revoked certificates in CRL */
|
||||
while (revokedCert != NULL)
|
||||
{
|
||||
revoked++;
|
||||
revokedCert = revokedCert->next;
|
||||
}
|
||||
|
||||
whack_log(RC_COMMENT, "%s, revoked certs: %d",
|
||||
timetoa(&crl->installed, utc), revoked);
|
||||
dntoa(buf, BUF_LEN, crl->issuer);
|
||||
whack_log(RC_COMMENT, " issuer: '%s'", buf);
|
||||
|
||||
list_distribution_points(crl->distributionPoints);
|
||||
|
||||
whack_log(RC_COMMENT, " updates: this %s",
|
||||
timetoa(&crl->thisUpdate, utc));
|
||||
whack_log(RC_COMMENT, " next %s %s",
|
||||
timetoa(&crl->nextUpdate, utc),
|
||||
check_expiry(crl->nextUpdate, CRL_WARNING_INTERVAL, strict));
|
||||
if (crl->authKeyID.ptr != NULL)
|
||||
{
|
||||
datatot(crl->authKeyID.ptr, crl->authKeyID.len, ':'
|
||||
, buf, BUF_LEN);
|
||||
whack_log(RC_COMMENT, " authkey: %s", buf);
|
||||
}
|
||||
if (crl->authKeySerialNumber.ptr != NULL)
|
||||
{
|
||||
datatot(crl->authKeySerialNumber.ptr, crl->authKeySerialNumber.len, ':'
|
||||
, buf, BUF_LEN);
|
||||
whack_log(RC_COMMENT, " aserial: %s", buf);
|
||||
}
|
||||
|
||||
crl = crl->next;
|
||||
}
|
||||
unlock_crl_list("list_crls");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user