/* * NAME: * crl - check for revoked x509 certs * * DESCRIPTION: * SSL Verify callbacks can call crl_check(ctx,xs), which will * indicate which of the following cases is true. * * 1 we cannot find a CRL for issuer, return 0 * 2 we have a CRL which revokes xs, return -2 * 3 we have an expired CRL for issuer which does not revoke xs, * return -1 * 4 we have a valid CRL for issuer which does not revoke xs, * return 1 * * SEE ALSO: * sslfd(3) * * AUTHOR: * Simon J. Gerraty */ /* * @(#)Copyright (c) 1996 Simon J. Gerraty. * * This is free software. It comes with NO WARRANTY. * Permission to use, modify and distribute this source code * is granted subject to the following conditions. * 1/ that the above copyright notice and this notice * are preserved in all copies and that due credit be given * to the author. * 2/ that any changes to this code are clearly commented * as such so that the author does not get blamed for bugs * other than his own. * * Please send copies of changes and bug-fixes to: * sjg@quick.com.au */ #ifndef lint static char RCSid[] = "$Id: crl.c,v 1.8 1998/11/12 04:00:35 sjg Exp $"; #endif #include #include #include #include #include #include #include #include #ifndef R_OK #include #endif #include "buffer.h" #include "x509.h" #include "pem.h" #include "ssl.h" #ifdef libsslfd #include "sslfd.h" #else /* * Make this more stand alone so folk can use it with Apache */ # ifndef SSLEAY_VERSION_NUMBER # include "crypto.h" # endif # if SSLEAY_VERSION_NUMBER >= 0x0800 # define SSLEAY8 # define X509_cert_verify_error_string X509_verify_cert_error_string # define X509_NAME_ONELINE(x) (char *)X509_NAME_oneline((x), 0, 0) # endif #endif #ifdef SSLEAY8 # include "x509_vfy.h" #endif #ifndef SSLEAY8 /* * This stuff has been added to libcrypto - see crl-*.patch */ /* * The BIO stuff is derrived from apps/crl.c */ static X509_CRL * load_crl(issuer, infile) X509_NAME *issuer; char *infile; { X509_CRL *crl = NULL; BIO *in = NULL; in=BIO_new(BIO_s_file()); if (in == NULL) { syslog(LOG_ERR, "cannot create BIO for %s", infile); goto end; } if (BIO_read_filename(in,infile) <= 0) { syslog(LOG_ERR, "%s: %m", infile); goto end; } /* * assume PEM, and if that fails, try DER */ if ((crl = PEM_read_bio_X509_CRL(in,NULL,NULL)) == NULL && (crl = d2i_X509_CRL_bio(in,NULL)) == NULL) { syslog(LOG_ERR, "unable to load CRL %s", infile); goto end; } /* * we have loaded a CRL, check that issuer is correct */ if (X509_name_cmp(issuer, crl->crl->issuer) != 0) { syslog(LOG_DEBUG, "loaded wrong CRL"); X509_CRL_free(crl); crl = NULL; } end: if (in != NULL) BIO_free(in); return(crl); } #endif X509_CRL * find_crl(ctx, xs) #ifdef SSLEAY8 X509_STORE_CTX *ctx; #else CERTIFICATE_CTX *ctx; #endif X509 *xs; { #ifdef SSLEAY8 X509_OBJECT obj; #endif X509_NAME *issuer; X509_CRL *crl = 0; u_long h; int i, k; char buf[256]; if (!ctx) return 0; /* should/can not happen */ issuer = X509_get_issuer_name(xs); /* * REVISIT: is there any point checking a CRL for a * self-signed cert? In any case we need to do this for 0.9 * so that we do get the CRL ok for the subject cert. */ if (X509_NAME_cmp(X509_get_subject_name(xs),issuer) == 0) return 0; #ifdef SSLEAY8 memset((char *) &obj, 0, sizeof (obj)); /* initialize it! */ if (X509_STORE_get_by_subject(ctx,X509_LU_CRL,issuer,&obj) > 0) return (obj.data.crl); X509_OBJECT_free_contents(&obj); #else /* * The search logic is lifted from eay's * crypto/x509/x509_crt.c I've just made it look for crl's */ h = X509_issuer_name_hash(xs); for (i = 0; i < ctx->num_dirs; i++) { sprintf(buf, "%.200s/%08lx.crl", ctx->dirs[i], h); if (access(buf, R_OK) == 0) crl = load_crl(issuer, buf); if (crl) /* could have been the wrong one */ return crl; for (k = 0; k < 8; k++) { sprintf(buf, "%.200s/%08lx.%d.crl", ctx->dirs[i], h, k); if (access(buf, R_OK) == 0) crl = load_crl(issuer, buf); if (crl) /* still the wrong one? */ return crl; } } #endif return 0; } int asn1cmp(a, b) ASN1_INTEGER *a, *b; { int ret; if ((ret = a->length - b->length) == 0) { if ((ret = memcmp(a->data, b->data, a->length)) == 0) { ret = a->type - b->type; } } return ret; } /* * The possible cases are: * 1 we cannot find a CRL for issuer, return 0 * 2 we have a CRL which revokes xs, return -2 * 3 we have an expired CRL for issuer which does not revoke xs, * return -1 * 4 we have a valid CRL for issuer which does not revoke xs, * return 1 */ int check_crl(ctx, xs) #ifdef SSLEAY8 X509_STORE_CTX *ctx; #else CERTIFICATE_CTX *ctx; #endif X509 *xs; { X509_CRL *crl = find_crl(ctx, xs); X509_REVOKED *r; ASN1_UTCTIME *utc; int ret = 1; /* OK */ if (!crl) return 0; /* no CRL */ while (ret > 0 && (r = (X509_REVOKED *) sk_pop(crl->crl->revoked)) != NULL) { if (asn1cmp(xs->cert_info->serialNumber, r->serialNumber) == 0) ret = -2; /* revoked */ } /* * not revoked, need to check if crl has expired */ if (ret > 0 && crl->crl->nextUpdate != 0 && /* its optional */ X509_cmp_current_time(crl->crl->nextUpdate) < 0) ret = -1; /* expired */ #if SSLEAY_VERSION_NUMBER < 0x0900 X509_CRL_free(crl); #endif return ret; } .