summaryrefslogtreecommitdiff
path: root/src/pluto/crl.c
diff options
context:
space:
mode:
authorRene Mayrhofer <rene@mayrhofer.eu.org>2009-06-23 11:25:24 +0000
committerRene Mayrhofer <rene@mayrhofer.eu.org>2009-06-23 11:25:24 +0000
commit41787e147279ff0695e9d759487266a60b80867b (patch)
tree8f28566c8fd7106c80d2536d2df540dbb4499cc5 /src/pluto/crl.c
parentc3e7f611ea8273c6b3909cb006ade4903a74aad0 (diff)
downloadvyos-strongswan-41787e147279ff0695e9d759487266a60b80867b.tar.gz
vyos-strongswan-41787e147279ff0695e9d759487266a60b80867b.zip
[svn-upgrade] Integrating new upstream version, strongswan (4.3.2)
Diffstat (limited to 'src/pluto/crl.c')
-rw-r--r--src/pluto/crl.c1197
1 files changed, 599 insertions, 598 deletions
diff --git a/src/pluto/crl.c b/src/pluto/crl.c
index c891d19e6..c800f2acc 100644
--- a/src/pluto/crl.c
+++ b/src/pluto/crl.c
@@ -1,5 +1,7 @@
/* Support of X.509 certificate revocation lists (CRLs)
- * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ * Copyright (C) 2000-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
@@ -10,8 +12,6 @@
* 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 4632 2008-11-11 18:37:19Z martin $
*/
#include <stdlib.h>
@@ -23,13 +23,15 @@
#include <sys/types.h>
#include <freeswan.h>
-#include <ipsec_policy.h>
+
+#include <asn1/asn1.h>
+#include <asn1/asn1_parser.h>
+#include <asn1/oid.h>
+#include <crypto/hashers/hasher.h>
#include "constants.h"
#include "defs.h"
#include "log.h"
-#include "asn1.h"
-#include <asn1/oid.h>
#include "x509.h"
#include "crl.h"
#include "ca.h"
@@ -37,482 +39,482 @@
#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 */
-
+/**
+ * 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 */
- { 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
+ { 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 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
+};
+
+#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_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
-
+#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
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 */
- { NULL, 0 } , /* crlNumber */
- OID_UNKNOWN , /* algorithm */
- { NULL, 0 } /* signature */
+ 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 */
+ { NULL, 0 } , /* crlNumber */
+ OID_UNKNOWN , /* algorithm */
+ { NULL, 0 } /* signature */
};
-/*
- * get the X.509 CRL with a given issuer
+/**
+ * Get the X.509 CRL with a given issuer
*/
-static x509crl_t*
-get_x509crl(chunk_t issuer, chunk_t serial, chunk_t keyid)
+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)))
+ x509crl_t *crl = x509crls;
+ x509crl_t *prev_crl = NULL;
+
+ while (crl != NULL)
{
- if (crl != x509crls)
- {
- /* bring the CRL up front */
- prev_crl->next = crl->next;
- crl->next = x509crls;
- x509crls = crl;
- }
- return crl;
+ 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;
}
- prev_crl = crl;
- crl = crl->next;
- }
- return NULL;
+ return NULL;
}
-/*
- * free the dynamic memory used to store revoked certificates
+/**
+ * Free the dynamic memory used to store revoked certificates
*/
-static void
-free_revoked_certs(revokedCert_t* revokedCerts)
+static void free_revoked_certs(revokedCert_t* revokedCerts)
{
- while (revokedCerts != NULL)
- {
- revokedCert_t * revokedCert = revokedCerts;
- revokedCerts = revokedCert->next;
- pfree(revokedCert);
- }
+ while (revokedCerts != NULL)
+ {
+ revokedCert_t * revokedCert = revokedCerts;
+ revokedCerts = revokedCert->next;
+ free(revokedCert);
+ }
}
-/*
- * free the dynamic memory used to store CRLs
+/**
+ * Free the dynamic memory used to store CRLs
*/
-void
-free_crl(x509crl_t *crl)
+void free_crl(x509crl_t *crl)
{
- free_revoked_certs(crl->revokedCertificates);
- free_generalNames(crl->distributionPoints, TRUE);
- pfree(crl->certificateList.ptr);
- pfree(crl);
+ free_revoked_certs(crl->revokedCertificates);
+ free_generalNames(crl->distributionPoints, TRUE);
+ free(crl->certificateList.ptr);
+ free(crl);
}
-static void
-free_first_crl(void)
+static void free_first_crl(void)
{
- x509crl_t *crl = x509crls;
+ x509crl_t *crl = x509crls;
- x509crls = crl->next;
- free_crl(crl);
+ x509crls = crl->next;
+ free_crl(crl);
}
-void
-free_crls(void)
+void free_crls(void)
{
- lock_crl_list("free_crls");
+ lock_crl_list("free_crls");
- while (x509crls != NULL)
- free_first_crl();
+ while (x509crls != NULL)
+ free_first_crl();
- unlock_crl_list("free_crls");
+ 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)
+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");
+ x509crl_t *crl = malloc_thing(x509crl_t);
- 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);
+ *crl = empty_x509crl;
- if (oldcrl != NULL)
+ if (parse_x509crl(blob, 0, crl))
{
- 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();
+ x509cert_t *issuer_cert;
+ x509crl_t *oldcrl;
+ bool valid_sig;
+ generalName_t *gn;
+
+ /* add distribution point */
+ gn = malloc_thing(generalName_t);
+ 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("thisUpdate is newer - existing crl deleted")
+ DBG_log("crl issuer cacert found")
)
- }
- else
- {
- unlock_crl_list("insert_crls");
+
+ /* check the issuer's signature of the crl */
+ valid_sig = x509_check_signature(crl->tbsCertList, crl->signature,
+ crl->algorithm, issuer_cert);
+ unlock_authcert_list("insert_crl");
+
+ if (!valid_sig)
+ {
+ free_crl(crl);
+ return FALSE;
+ }
DBG(DBG_CONTROL,
- DBG_log("thisUpdate is not newer - existing crl not replaced");
+ DBG_log("crl signature is valid")
)
- free_crl(crl);
- return oldcrl->nextUpdate - time(NULL) > 2*crl_check_interval;
- }
- }
- /* insert new CRL */
- crl->next = x509crls;
- x509crls = crl;
+ lock_crl_list("insert_crl");
+ oldcrl = get_x509crl(crl->issuer, crl->authKeySerialNumber
+ , crl->authKeyID);
- unlock_crl_list("insert_crl");
+ 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;
+ }
+ }
- /* 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)
+ /* 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], buf[BUF_LEN];
+ char digest_buf[HASH_SIZE_SHA1];
+ chunk_t subjectKeyID = chunk_from_buf(digest_buf);
+ bool has_keyID;
+
+ if (issuer_cert->subjectKeyID.ptr == NULL)
+ {
+ has_keyID = compute_subjectKeyID(issuer_cert, subjectKeyID);
+ }
+ else
+ {
+ subjectKeyID = issuer_cert->subjectKeyID;
+ has_keyID = TRUE;
+ }
+ if (has_keyID)
+ {
+ datatot(subjectKeyID.ptr, subjectKeyID.len, 16, buf, BUF_LEN);
+ snprintf(path, BUF_LEN, "%s/%s.crl", CRL_PATH, buf);
+ chunk_write(crl->certificateList, path, "crl", 0022, TRUE);
+ }
+ }
+
+ /* is the fetched crl valid? */
+ return crl->nextUpdate - time(NULL) > 2*crl_check_interval;
+ }
+ else
{
- 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);
+ plog(" error in X.509 crl");
+ free_crl(crl);
+ return FALSE;
}
-
- /* 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)
+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");
+ 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
{
- while (n--)
- {
- bool pgp = FALSE;
- chunk_t blob = empty_chunk;
- char *filename = filelist[n]->d_name;
+ plog("Changing to directory '%s'", CRL_PATH);
+ n = scandir(CRL_PATH, &filelist, file_select, alphasort);
- if (load_coded_file(filename, NULL, "crl", &blob, &pgp))
+ if (n < 0)
+ plog(" scandir() error");
+ else
{
- 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);
+ while (n--)
+ {
+ bool pgp = FALSE;
+ chunk_t blob = chunk_empty;
+ 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 = malloc(crl_uri.len + 1);
+
+ /* 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);
}
- free(filelist[n]);
- }
- free(filelist);
}
- }
- /* restore directory path */
- ignore_result(chdir(save_dir));
+ /* restore directory path */
+ ignore_result(chdir(save_dir));
}
-/*
+/**
* Parses a CRL revocation reason code
*/
-static crl_reason_t
-parse_crl_reasonCode(chunk_t object)
+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;
+ crl_reason_t reason = REASON_UNSPECIFIED;
+
+ if (*object.ptr == ASN1_ENUMERATED
+ && asn1_length(&object) == 1)
+ {
+ reason = *object.ptr;
+ }
+
+ DBG(DBG_PARSING,
+ DBG_log(" '%N'", crl_reason_names, reason)
+ )
+ return reason;
}
/*
* Parses an X.509 CRL
*/
-bool
-parse_x509crl(chunk_t blob, u_int level0, x509crl_t *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 = empty_chunk;
- 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);
- }
- else if (extn_oid == OID_CRL_NUMBER)
- {
- if (!parse_asn1_simple_object(&object, ASN1_INTEGER, level, "crlNumber"))
- return FALSE;
- crl->crlNumber = object;
+ u_char buf[BUF_LEN];
+ asn1_parser_t *parser;
+ chunk_t extnID;
+ chunk_t userCertificate = chunk_empty;
+ chunk_t object;
+ int objectID;
+ bool success = FALSE;
+ bool critical;
+
+ parser = asn1_parser_create(crlObjects, blob);
+
+ while (parser->iterate(parser, &objectID, &object))
+ {
+ u_int level = parser->get_level(parser)+1;
+
+ 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 = asn1_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 = asn1_parse_time(object, level);
+ break;
+ case CRL_OBJ_NEXT_UPDATE:
+ crl->nextUpdate = asn1_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 = malloc_thing(revokedCert_t);
+ revokedCert->userCertificate = userCertificate;
+ revokedCert->revocationDate = asn1_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 = asn1_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);
+ }
+ else if (extn_oid == OID_CRL_NUMBER)
+ {
+ if (!asn1_parse_simple_object(&object, ASN1_INTEGER,
+ level, "crlNumber"))
+ {
+ goto end;
+ }
+ crl->crlNumber = object;
+ }
+ }
+ break;
+ case CRL_OBJ_ALGORITHM:
+ crl->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL);
+ break;
+ case CRL_OBJ_SIGNATURE:
+ crl->signature = object;
+ break;
+ default:
+ break;
}
- }
- 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;
+ success = parser->success(parser);
+ time(&crl->installed);
+
+end:
+ parser->destroy(parser);
+ return success;
}
/* Checks if the current certificate is revoked. It goes through the
@@ -523,28 +525,28 @@ 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)
+ revokedCert_t *revokedCert = crl->revokedCertificates;
+
+ *revocationDate = UNDEFINED_TIME;
+ *revocationReason = REASON_UNSPECIFIED;
+
+ DBG(DBG_CONTROL,
+ DBG_dump_chunk("serial number:", serial)
+ )
+
+ while(revokedCert != NULL)
{
- *revocationDate = revokedCert->revocationDate;
- *revocationReason = revokedCert->revocationReason;
- return CERT_REVOKED;
+ /* compare serial numbers */
+ if (revokedCert->userCertificate.len == serial.len &&
+ memeq(revokedCert->userCertificate.ptr, serial.ptr, serial.len))
+ {
+ *revocationDate = revokedCert->revocationDate;
+ *revocationReason = revokedCert->revocationReason;
+ return CERT_REVOKED;
+ }
+ revokedCert = revokedCert->next;
}
- revokedCert = revokedCert->next;
- }
- return CERT_GOOD;
+ return CERT_GOOD;
}
/*
@@ -553,37 +555,37 @@ check_revocation(const x509crl_t *crl, chunk_t serial
void
check_crls(void)
{
- x509crl_t *crl;
+ 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];
+ lock_crl_list("check_crls");
+ crl = x509crls;
- 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)
+ while (crl != NULL)
{
- fetch_req_t *req = build_crl_fetch_request(crl->issuer
- , crl->authKeySerialNumber
- , crl->authKeyID, crl->distributionPoints);
- add_crl_fetch_request(req);
+ 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;
}
- crl = crl->next;
- }
- unlock_crl_list("check_crls");
+ unlock_crl_list("check_crls");
}
/*
@@ -593,118 +595,117 @@ 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);
+ x509crl_t *crl;
- generalName_t *crluri = (ca == NULL)? NULL : ca->crluri;
+ ca_info_t *ca = get_ca_info(cert->issuer, cert->authKeySerialNumber
+ , cert->authKeyID);
- *revocationDate = UNDEFINED_TIME;
- *revocationReason = REASON_UNSPECIFIED;
+ generalName_t *crluri = (ca == NULL)? NULL : ca->crluri;
- lock_crl_list("verify_by_crl");
- crl = get_x509crl(cert->issuer, cert->authKeySerialNumber, cert->authKeyID);
+ *revocationDate = UNDEFINED_TIME;
+ *revocationReason = REASON_UNSPECIFIED;
- if (crl == NULL)
- {
- unlock_crl_list("verify_by_crl");
- plog("crl not found");
+ lock_crl_list("verify_by_crl");
+ crl = get_x509crl(cert->issuer, cert->authKeySerialNumber, cert->authKeyID);
- if (cert->crlDistributionPoints != NULL)
+ if (crl == NULL)
{
- fetch_req_t *req = build_crl_fetch_request(cert->issuer
- , cert->authKeySerialNumber
- , cert->authKeyID, cert->crlDistributionPoints);
- add_crl_fetch_request(req);
- }
+ unlock_crl_list("verify_by_crl");
+ plog("crl not found");
- 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 != NULL)
+ {
+ fetch_req_t *req = build_crl_fetch_request(cert->issuer
+ , cert->authKeySerialNumber
+ , cert->authKeyID, cert->crlDistributionPoints);
+ add_crl_fetch_request(req);
+ }
- if (cert->crlDistributionPoints != 0 || crluri != NULL)
- {
- wake_fetch_thread("verify_by_crl");
- return CERT_UNKNOWN;
+ 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
- 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;
+ x509cert_t *issuer_cert;
+ bool valid;
- DBG(DBG_CONTROL,
- DBG_log("crl signature is valid")
- )
- /* return the expiration date */
- *until = crl->nextUpdate;
+ DBG(DBG_CONTROL,
+ DBG_log("crl found")
+ )
- /* has the certificate been revoked? */
- status = check_revocation(crl, cert->serialNumber, revocationDate
- , revocationReason);
+ add_distribution_points(cert->crlDistributionPoints
+ , &crl->distributionPoints);
- if (*until < time(NULL))
- {
- fetch_req_t *req;
+ add_distribution_points(crluri
+ , &crl->distributionPoints);
- plog("crl update is overdue since %s"
- , timetoa(until, TRUE));
+ lock_authcert_list("verify_by_crl");
- /* 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");
+ issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber
+ , crl->authKeyID, AUTH_CA);
+ valid = x509_check_signature(crl->tbsCertList, crl->signature,
+ crl->algorithm, issuer_cert);
+
+ unlock_authcert_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;
+ 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 %T", 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;
+ }
}
- }
}
/*
@@ -713,63 +714,63 @@ verify_by_crl(const x509cert_t *cert, time_t *until, time_t *revocationDate
void
list_crls(bool utc, bool strict)
{
- x509crl_t *crl;
+ x509crl_t *crl;
- lock_crl_list("list_crls");
- crl = x509crls;
+ 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);
- if (crl->crlNumber.ptr != NULL)
+ if (crl != NULL)
{
- datatot(crl->crlNumber.ptr, crl->crlNumber.len, ':'
- , buf, BUF_LEN);
- whack_log(RC_COMMENT, " crlnumber: %s", buf);
+ whack_log(RC_COMMENT, " ");
+ whack_log(RC_COMMENT, "List of X.509 CRLs:");
+ whack_log(RC_COMMENT, " ");
}
- 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)
+
+ while (crl != NULL)
{
- datatot(crl->authKeySerialNumber.ptr, crl->authKeySerialNumber.len, ':'
- , buf, BUF_LEN);
- whack_log(RC_COMMENT, " aserial: %s", buf);
- }
+ 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, "%T, revoked certs: %d",
+ &crl->installed, utc, revoked);
+ dntoa(buf, BUF_LEN, crl->issuer);
+ whack_log(RC_COMMENT, " issuer: '%s'", buf);
+ if (crl->crlNumber.ptr != NULL)
+ {
+ datatot(crl->crlNumber.ptr, crl->crlNumber.len, ':'
+ , buf, BUF_LEN);
+ whack_log(RC_COMMENT, " crlnumber: %s", buf);
+ }
+ list_distribution_points(crl->distributionPoints);
+
+ whack_log(RC_COMMENT, " updates: this %T",
+ &crl->thisUpdate, utc);
+ whack_log(RC_COMMENT, " next %T %s",
+ &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");
+ crl = crl->next;
+ }
+ unlock_crl_list("list_crls");
}