summaryrefslogtreecommitdiffstats
path: root/crypto/heimdal/lib/hx509/revoke.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/heimdal/lib/hx509/revoke.c')
-rw-r--r--crypto/heimdal/lib/hx509/revoke.c1525
1 files changed, 0 insertions, 1525 deletions
diff --git a/crypto/heimdal/lib/hx509/revoke.c b/crypto/heimdal/lib/hx509/revoke.c
deleted file mode 100644
index cfde439..0000000
--- a/crypto/heimdal/lib/hx509/revoke.c
+++ /dev/null
@@ -1,1525 +0,0 @@
-/*
- * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
- * (Royal Institute of Technology, Stockholm, Sweden).
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * 3. Neither the name of the Institute nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/**
- * @page page_revoke Revocation methods
- *
- * There are two revocation method for PKIX/X.509: CRL and OCSP.
- * Revocation is needed if the private key is lost and
- * stolen. Depending on how picky you are, you might want to make
- * revocation for destroyed private keys too (smartcard broken), but
- * that should not be a problem.
- *
- * CRL is a list of certifiates that have expired.
- *
- * OCSP is an online checking method where the requestor sends a list
- * of certificates to the OCSP server to return a signed reply if they
- * are valid or not. Some services sends a OCSP reply as part of the
- * hand-shake to make the revoktion decision simpler/faster for the
- * client.
- */
-
-#include "hx_locl.h"
-RCSID("$Id: revoke.c 22275 2007-12-11 11:02:11Z lha $");
-
-struct revoke_crl {
- char *path;
- time_t last_modfied;
- CRLCertificateList crl;
- int verified;
- int failed_verify;
-};
-
-struct revoke_ocsp {
- char *path;
- time_t last_modfied;
- OCSPBasicOCSPResponse ocsp;
- hx509_certs certs;
- hx509_cert signer;
-};
-
-
-struct hx509_revoke_ctx_data {
- unsigned ref;
- struct {
- struct revoke_crl *val;
- size_t len;
- } crls;
- struct {
- struct revoke_ocsp *val;
- size_t len;
- } ocsps;
-};
-
-/**
- * Allocate a revokation context. Free with hx509_revoke_free().
- *
- * @param context A hx509 context.
- * @param ctx returns a newly allocated revokation context.
- *
- * @return An hx509 error code, see hx509_get_error_string().
- *
- * @ingroup hx509_revoke
- */
-
-int
-hx509_revoke_init(hx509_context context, hx509_revoke_ctx *ctx)
-{
- *ctx = calloc(1, sizeof(**ctx));
- if (*ctx == NULL)
- return ENOMEM;
-
- (*ctx)->ref = 1;
- (*ctx)->crls.len = 0;
- (*ctx)->crls.val = NULL;
- (*ctx)->ocsps.len = 0;
- (*ctx)->ocsps.val = NULL;
-
- return 0;
-}
-
-hx509_revoke_ctx
-_hx509_revoke_ref(hx509_revoke_ctx ctx)
-{
- if (ctx == NULL)
- return NULL;
- if (ctx->ref <= 0)
- _hx509_abort("revoke ctx refcount <= 0");
- ctx->ref++;
- if (ctx->ref == 0)
- _hx509_abort("revoke ctx refcount == 0");
- return ctx;
-}
-
-static void
-free_ocsp(struct revoke_ocsp *ocsp)
-{
- free(ocsp->path);
- free_OCSPBasicOCSPResponse(&ocsp->ocsp);
- hx509_certs_free(&ocsp->certs);
- hx509_cert_free(ocsp->signer);
-}
-
-/**
- * Free a hx509 revokation context.
- *
- * @param ctx context to be freed
- *
- * @ingroup hx509_revoke
- */
-
-void
-hx509_revoke_free(hx509_revoke_ctx *ctx)
-{
- size_t i ;
-
- if (ctx == NULL || *ctx == NULL)
- return;
-
- if ((*ctx)->ref <= 0)
- _hx509_abort("revoke ctx refcount <= 0 on free");
- if (--(*ctx)->ref > 0)
- return;
-
- for (i = 0; i < (*ctx)->crls.len; i++) {
- free((*ctx)->crls.val[i].path);
- free_CRLCertificateList(&(*ctx)->crls.val[i].crl);
- }
-
- for (i = 0; i < (*ctx)->ocsps.len; i++)
- free_ocsp(&(*ctx)->ocsps.val[i]);
- free((*ctx)->ocsps.val);
-
- free((*ctx)->crls.val);
-
- memset(*ctx, 0, sizeof(**ctx));
- free(*ctx);
- *ctx = NULL;
-}
-
-static int
-verify_ocsp(hx509_context context,
- struct revoke_ocsp *ocsp,
- time_t time_now,
- hx509_certs certs,
- hx509_cert parent)
-{
- hx509_cert signer = NULL;
- hx509_query q;
- int ret;
-
- _hx509_query_clear(&q);
-
- /*
- * Need to match on issuer too in case there are two CA that have
- * issued the same name to a certificate. One example of this is
- * the www.openvalidation.org test's ocsp validator.
- */
-
- q.match = HX509_QUERY_MATCH_ISSUER_NAME;
- q.issuer_name = &_hx509_get_cert(parent)->tbsCertificate.issuer;
-
- switch(ocsp->ocsp.tbsResponseData.responderID.element) {
- case choice_OCSPResponderID_byName:
- q.match |= HX509_QUERY_MATCH_SUBJECT_NAME;
- q.subject_name = &ocsp->ocsp.tbsResponseData.responderID.u.byName;
- break;
- case choice_OCSPResponderID_byKey:
- q.match |= HX509_QUERY_MATCH_KEY_HASH_SHA1;
- q.keyhash_sha1 = &ocsp->ocsp.tbsResponseData.responderID.u.byKey;
- break;
- }
-
- ret = hx509_certs_find(context, certs, &q, &signer);
- if (ret && ocsp->certs)
- ret = hx509_certs_find(context, ocsp->certs, &q, &signer);
- if (ret)
- goto out;
-
- /*
- * If signer certificate isn't the CA certificate, lets check the
- * it is the CA that signed the signer certificate and the OCSP EKU
- * is set.
- */
- if (hx509_cert_cmp(signer, parent) != 0) {
- Certificate *p = _hx509_get_cert(parent);
- Certificate *s = _hx509_get_cert(signer);
-
- ret = _hx509_cert_is_parent_cmp(s, p, 0);
- if (ret != 0) {
- ret = HX509_PARENT_NOT_CA;
- hx509_set_error_string(context, 0, ret, "Revoke OSCP signer is "
- "doesn't have CA as signer certificate");
- goto out;
- }
-
- ret = _hx509_verify_signature_bitstring(context,
- p,
- &s->signatureAlgorithm,
- &s->tbsCertificate._save,
- &s->signatureValue);
- if (ret) {
- hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
- "OSCP signer signature invalid");
- goto out;
- }
-
- ret = hx509_cert_check_eku(context, signer,
- oid_id_pkix_kp_OCSPSigning(), 0);
- if (ret)
- goto out;
- }
-
- ret = _hx509_verify_signature_bitstring(context,
- _hx509_get_cert(signer),
- &ocsp->ocsp.signatureAlgorithm,
- &ocsp->ocsp.tbsResponseData._save,
- &ocsp->ocsp.signature);
- if (ret) {
- hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
- "OSCP signature invalid");
- goto out;
- }
-
- ocsp->signer = signer;
- signer = NULL;
-out:
- if (signer)
- hx509_cert_free(signer);
-
- return ret;
-}
-
-/*
- *
- */
-
-static int
-parse_ocsp_basic(const void *data, size_t length, OCSPBasicOCSPResponse *basic)
-{
- OCSPResponse resp;
- size_t size;
- int ret;
-
- memset(basic, 0, sizeof(*basic));
-
- ret = decode_OCSPResponse(data, length, &resp, &size);
- if (ret)
- return ret;
- if (length != size) {
- free_OCSPResponse(&resp);
- return ASN1_EXTRA_DATA;
- }
-
- switch (resp.responseStatus) {
- case successful:
- break;
- default:
- free_OCSPResponse(&resp);
- return HX509_REVOKE_WRONG_DATA;
- }
-
- if (resp.responseBytes == NULL) {
- free_OCSPResponse(&resp);
- return EINVAL;
- }
-
- ret = der_heim_oid_cmp(&resp.responseBytes->responseType,
- oid_id_pkix_ocsp_basic());
- if (ret != 0) {
- free_OCSPResponse(&resp);
- return HX509_REVOKE_WRONG_DATA;
- }
-
- ret = decode_OCSPBasicOCSPResponse(resp.responseBytes->response.data,
- resp.responseBytes->response.length,
- basic,
- &size);
- if (ret) {
- free_OCSPResponse(&resp);
- return ret;
- }
- if (size != resp.responseBytes->response.length) {
- free_OCSPResponse(&resp);
- free_OCSPBasicOCSPResponse(basic);
- return ASN1_EXTRA_DATA;
- }
- free_OCSPResponse(&resp);
-
- return 0;
-}
-
-/*
- *
- */
-
-static int
-load_ocsp(hx509_context context, struct revoke_ocsp *ocsp)
-{
- OCSPBasicOCSPResponse basic;
- hx509_certs certs = NULL;
- size_t length;
- struct stat sb;
- void *data;
- int ret;
-
- ret = _hx509_map_file(ocsp->path, &data, &length, &sb);
- if (ret)
- return ret;
-
- ret = parse_ocsp_basic(data, length, &basic);
- _hx509_unmap_file(data, length);
- if (ret) {
- hx509_set_error_string(context, 0, ret,
- "Failed to parse OCSP response");
- return ret;
- }
-
- if (basic.certs) {
- int i;
-
- ret = hx509_certs_init(context, "MEMORY:ocsp-certs", 0,
- NULL, &certs);
- if (ret) {
- free_OCSPBasicOCSPResponse(&basic);
- return ret;
- }
-
- for (i = 0; i < basic.certs->len; i++) {
- hx509_cert c;
-
- ret = hx509_cert_init(context, &basic.certs->val[i], &c);
- if (ret)
- continue;
-
- ret = hx509_certs_add(context, certs, c);
- hx509_cert_free(c);
- if (ret)
- continue;
- }
- }
-
- ocsp->last_modfied = sb.st_mtime;
-
- free_OCSPBasicOCSPResponse(&ocsp->ocsp);
- hx509_certs_free(&ocsp->certs);
- hx509_cert_free(ocsp->signer);
-
- ocsp->ocsp = basic;
- ocsp->certs = certs;
- ocsp->signer = NULL;
-
- return 0;
-}
-
-/**
- * Add a OCSP file to the revokation context.
- *
- * @param context hx509 context
- * @param ctx hx509 revokation context
- * @param path path to file that is going to be added to the context.
- *
- * @return An hx509 error code, see hx509_get_error_string().
- *
- * @ingroup hx509_revoke
- */
-
-int
-hx509_revoke_add_ocsp(hx509_context context,
- hx509_revoke_ctx ctx,
- const char *path)
-{
- void *data;
- int ret;
- size_t i;
-
- if (strncmp(path, "FILE:", 5) != 0) {
- hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
- "unsupport type in %s", path);
- return HX509_UNSUPPORTED_OPERATION;
- }
-
- path += 5;
-
- for (i = 0; i < ctx->ocsps.len; i++) {
- if (strcmp(ctx->ocsps.val[0].path, path) == 0)
- return 0;
- }
-
- data = realloc(ctx->ocsps.val,
- (ctx->ocsps.len + 1) * sizeof(ctx->ocsps.val[0]));
- if (data == NULL) {
- hx509_clear_error_string(context);
- return ENOMEM;
- }
-
- ctx->ocsps.val = data;
-
- memset(&ctx->ocsps.val[ctx->ocsps.len], 0,
- sizeof(ctx->ocsps.val[0]));
-
- ctx->ocsps.val[ctx->ocsps.len].path = strdup(path);
- if (ctx->ocsps.val[ctx->ocsps.len].path == NULL) {
- hx509_clear_error_string(context);
- return ENOMEM;
- }
-
- ret = load_ocsp(context, &ctx->ocsps.val[ctx->ocsps.len]);
- if (ret) {
- free(ctx->ocsps.val[ctx->ocsps.len].path);
- return ret;
- }
- ctx->ocsps.len++;
-
- return ret;
-}
-
-/*
- *
- */
-
-static int
-verify_crl(hx509_context context,
- hx509_revoke_ctx ctx,
- CRLCertificateList *crl,
- time_t time_now,
- hx509_certs certs,
- hx509_cert parent)
-{
- hx509_cert signer;
- hx509_query q;
- time_t t;
- int ret;
-
- t = _hx509_Time2time_t(&crl->tbsCertList.thisUpdate);
- if (t > time_now) {
- hx509_set_error_string(context, 0, HX509_CRL_USED_BEFORE_TIME,
- "CRL used before time");
- return HX509_CRL_USED_BEFORE_TIME;
- }
-
- if (crl->tbsCertList.nextUpdate == NULL) {
- hx509_set_error_string(context, 0, HX509_CRL_INVALID_FORMAT,
- "CRL missing nextUpdate");
- return HX509_CRL_INVALID_FORMAT;
- }
-
- t = _hx509_Time2time_t(crl->tbsCertList.nextUpdate);
- if (t < time_now) {
- hx509_set_error_string(context, 0, HX509_CRL_USED_AFTER_TIME,
- "CRL used after time");
- return HX509_CRL_USED_AFTER_TIME;
- }
-
- _hx509_query_clear(&q);
-
- /*
- * If it's the signer have CRLSIGN bit set, use that as the signer
- * cert for the certificate, otherwise, search for a certificate.
- */
- if (_hx509_check_key_usage(context, parent, 1 << 6, FALSE) == 0) {
- signer = hx509_cert_ref(parent);
- } else {
- q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
- q.match |= HX509_QUERY_KU_CRLSIGN;
- q.subject_name = &crl->tbsCertList.issuer;
-
- ret = hx509_certs_find(context, certs, &q, &signer);
- if (ret) {
- hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
- "Failed to find certificate for CRL");
- return ret;
- }
- }
-
- ret = _hx509_verify_signature_bitstring(context,
- _hx509_get_cert(signer),
- &crl->signatureAlgorithm,
- &crl->tbsCertList._save,
- &crl->signatureValue);
- if (ret) {
- hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
- "CRL signature invalid");
- goto out;
- }
-
- /*
- * If signer is not CA cert, need to check revoke status of this
- * CRL signing cert too, this include all parent CRL signer cert
- * up to the root *sigh*, assume root at least hve CERTSIGN flag
- * set.
- */
- while (_hx509_check_key_usage(context, signer, 1 << 5, TRUE)) {
- hx509_cert crl_parent;
-
- _hx509_query_clear(&q);
-
- q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
- q.match |= HX509_QUERY_KU_CRLSIGN;
- q.subject_name = &_hx509_get_cert(signer)->tbsCertificate.issuer;
-
- ret = hx509_certs_find(context, certs, &q, &crl_parent);
- if (ret) {
- hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
- "Failed to find parent of CRL signer");
- goto out;
- }
-
- ret = hx509_revoke_verify(context,
- ctx,
- certs,
- time_now,
- signer,
- crl_parent);
- hx509_cert_free(signer);
- signer = crl_parent;
- if (ret) {
- hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
- "Failed to verify revoke "
- "status of CRL signer");
- goto out;
- }
- }
-
-out:
- hx509_cert_free(signer);
-
- return ret;
-}
-
-static int
-load_crl(const char *path, time_t *t, CRLCertificateList *crl)
-{
- size_t length, size;
- struct stat sb;
- void *data;
- int ret;
-
- memset(crl, 0, sizeof(*crl));
-
- ret = _hx509_map_file(path, &data, &length, &sb);
- if (ret)
- return ret;
-
- *t = sb.st_mtime;
-
- ret = decode_CRLCertificateList(data, length, crl, &size);
- _hx509_unmap_file(data, length);
- if (ret)
- return ret;
-
- /* check signature is aligned */
- if (crl->signatureValue.length & 7) {
- free_CRLCertificateList(crl);
- return HX509_CRYPTO_SIG_INVALID_FORMAT;
- }
- return 0;
-}
-
-/**
- * Add a CRL file to the revokation context.
- *
- * @param context hx509 context
- * @param ctx hx509 revokation context
- * @param path path to file that is going to be added to the context.
- *
- * @return An hx509 error code, see hx509_get_error_string().
- *
- * @ingroup hx509_revoke
- */
-
-int
-hx509_revoke_add_crl(hx509_context context,
- hx509_revoke_ctx ctx,
- const char *path)
-{
- void *data;
- size_t i;
- int ret;
-
- if (strncmp(path, "FILE:", 5) != 0) {
- hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
- "unsupport type in %s", path);
- return HX509_UNSUPPORTED_OPERATION;
- }
-
-
- path += 5;
-
- for (i = 0; i < ctx->crls.len; i++) {
- if (strcmp(ctx->crls.val[0].path, path) == 0)
- return 0;
- }
-
- data = realloc(ctx->crls.val,
- (ctx->crls.len + 1) * sizeof(ctx->crls.val[0]));
- if (data == NULL) {
- hx509_clear_error_string(context);
- return ENOMEM;
- }
- ctx->crls.val = data;
-
- memset(&ctx->crls.val[ctx->crls.len], 0, sizeof(ctx->crls.val[0]));
-
- ctx->crls.val[ctx->crls.len].path = strdup(path);
- if (ctx->crls.val[ctx->crls.len].path == NULL) {
- hx509_clear_error_string(context);
- return ENOMEM;
- }
-
- ret = load_crl(path,
- &ctx->crls.val[ctx->crls.len].last_modfied,
- &ctx->crls.val[ctx->crls.len].crl);
- if (ret) {
- free(ctx->crls.val[ctx->crls.len].path);
- return ret;
- }
-
- ctx->crls.len++;
-
- return ret;
-}
-
-/**
- * Check that a certificate is not expired according to a revokation
- * context. Also need the parent certificte to the check OCSP
- * parent identifier.
- *
- * @param context hx509 context
- * @param ctx hx509 revokation context
- * @param certs
- * @param now
- * @param cert
- * @param parent_cert
- *
- * @return An hx509 error code, see hx509_get_error_string().
- *
- * @ingroup hx509_revoke
- */
-
-
-int
-hx509_revoke_verify(hx509_context context,
- hx509_revoke_ctx ctx,
- hx509_certs certs,
- time_t now,
- hx509_cert cert,
- hx509_cert parent_cert)
-{
- const Certificate *c = _hx509_get_cert(cert);
- const Certificate *p = _hx509_get_cert(parent_cert);
- unsigned long i, j, k;
- int ret;
-
- hx509_clear_error_string(context);
-
- for (i = 0; i < ctx->ocsps.len; i++) {
- struct revoke_ocsp *ocsp = &ctx->ocsps.val[i];
- struct stat sb;
-
- /* check this ocsp apply to this cert */
-
- /* check if there is a newer version of the file */
- ret = stat(ocsp->path, &sb);
- if (ret == 0 && ocsp->last_modfied != sb.st_mtime) {
- ret = load_ocsp(context, ocsp);
- if (ret)
- continue;
- }
-
- /* verify signature in ocsp if not already done */
- if (ocsp->signer == NULL) {
- ret = verify_ocsp(context, ocsp, now, certs, parent_cert);
- if (ret)
- continue;
- }
-
- for (j = 0; j < ocsp->ocsp.tbsResponseData.responses.len; j++) {
- heim_octet_string os;
-
- ret = der_heim_integer_cmp(&ocsp->ocsp.tbsResponseData.responses.val[j].certID.serialNumber,
- &c->tbsCertificate.serialNumber);
- if (ret != 0)
- continue;
-
- /* verify issuer hashes hash */
- ret = _hx509_verify_signature(context,
- NULL,
- &ocsp->ocsp.tbsResponseData.responses.val[i].certID.hashAlgorithm,
- &c->tbsCertificate.issuer._save,
- &ocsp->ocsp.tbsResponseData.responses.val[i].certID.issuerNameHash);
- if (ret != 0)
- continue;
-
- os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
- os.length = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
-
- ret = _hx509_verify_signature(context,
- NULL,
- &ocsp->ocsp.tbsResponseData.responses.val[j].certID.hashAlgorithm,
- &os,
- &ocsp->ocsp.tbsResponseData.responses.val[j].certID.issuerKeyHash);
- if (ret != 0)
- continue;
-
- switch (ocsp->ocsp.tbsResponseData.responses.val[j].certStatus.element) {
- case choice_OCSPCertStatus_good:
- break;
- case choice_OCSPCertStatus_revoked:
- hx509_set_error_string(context, 0,
- HX509_CERT_REVOKED,
- "Certificate revoked by issuer in OCSP");
- return HX509_CERT_REVOKED;
- case choice_OCSPCertStatus_unknown:
- continue;
- }
-
- /* don't allow the update to be in the future */
- if (ocsp->ocsp.tbsResponseData.responses.val[j].thisUpdate >
- now + context->ocsp_time_diff)
- continue;
-
- /* don't allow the next update to be in the past */
- if (ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate) {
- if (*ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate < now)
- continue;
- } else
- /* Should force a refetch, but can we ? */;
-
- return 0;
- }
- }
-
- for (i = 0; i < ctx->crls.len; i++) {
- struct revoke_crl *crl = &ctx->crls.val[i];
- struct stat sb;
-
- /* check if cert.issuer == crls.val[i].crl.issuer */
- ret = _hx509_name_cmp(&c->tbsCertificate.issuer,
- &crl->crl.tbsCertList.issuer);
- if (ret)
- continue;
-
- ret = stat(crl->path, &sb);
- if (ret == 0 && crl->last_modfied != sb.st_mtime) {
- CRLCertificateList cl;
-
- ret = load_crl(crl->path, &crl->last_modfied, &cl);
- if (ret == 0) {
- free_CRLCertificateList(&crl->crl);
- crl->crl = cl;
- crl->verified = 0;
- crl->failed_verify = 0;
- }
- }
- if (crl->failed_verify)
- continue;
-
- /* verify signature in crl if not already done */
- if (crl->verified == 0) {
- ret = verify_crl(context, ctx, &crl->crl, now, certs, parent_cert);
- if (ret) {
- crl->failed_verify = 1;
- continue;
- }
- crl->verified = 1;
- }
-
- if (crl->crl.tbsCertList.crlExtensions) {
- for (j = 0; j < crl->crl.tbsCertList.crlExtensions->len; j++) {
- if (crl->crl.tbsCertList.crlExtensions->val[j].critical) {
- hx509_set_error_string(context, 0,
- HX509_CRL_UNKNOWN_EXTENSION,
- "Unknown CRL extension");
- return HX509_CRL_UNKNOWN_EXTENSION;
- }
- }
- }
-
- if (crl->crl.tbsCertList.revokedCertificates == NULL)
- return 0;
-
- /* check if cert is in crl */
- for (j = 0; j < crl->crl.tbsCertList.revokedCertificates->len; j++) {
- time_t t;
-
- ret = der_heim_integer_cmp(&crl->crl.tbsCertList.revokedCertificates->val[j].userCertificate,
- &c->tbsCertificate.serialNumber);
- if (ret != 0)
- continue;
-
- t = _hx509_Time2time_t(&crl->crl.tbsCertList.revokedCertificates->val[j].revocationDate);
- if (t > now)
- continue;
-
- if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions)
- for (k = 0; k < crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->len; k++)
- if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->val[k].critical)
- return HX509_CRL_UNKNOWN_EXTENSION;
-
- hx509_set_error_string(context, 0,
- HX509_CERT_REVOKED,
- "Certificate revoked by issuer in CRL");
- return HX509_CERT_REVOKED;
- }
-
- return 0;
- }
-
-
- if (context->flags & HX509_CTX_VERIFY_MISSING_OK)
- return 0;
- hx509_set_error_string(context, HX509_ERROR_APPEND,
- HX509_REVOKE_STATUS_MISSING,
- "No revoke status found for "
- "certificates");
- return HX509_REVOKE_STATUS_MISSING;
-}
-
-struct ocsp_add_ctx {
- OCSPTBSRequest *req;
- hx509_certs certs;
- const AlgorithmIdentifier *digest;
- hx509_cert parent;
-};
-
-static int
-add_to_req(hx509_context context, void *ptr, hx509_cert cert)
-{
- struct ocsp_add_ctx *ctx = ptr;
- OCSPInnerRequest *one;
- hx509_cert parent = NULL;
- Certificate *p, *c = _hx509_get_cert(cert);
- heim_octet_string os;
- int ret;
- hx509_query q;
- void *d;
-
- d = realloc(ctx->req->requestList.val,
- sizeof(ctx->req->requestList.val[0]) *
- (ctx->req->requestList.len + 1));
- if (d == NULL)
- return ENOMEM;
- ctx->req->requestList.val = d;
-
- one = &ctx->req->requestList.val[ctx->req->requestList.len];
- memset(one, 0, sizeof(*one));
-
- _hx509_query_clear(&q);
-
- q.match |= HX509_QUERY_FIND_ISSUER_CERT;
- q.subject = c;
-
- ret = hx509_certs_find(context, ctx->certs, &q, &parent);
- if (ret)
- goto out;
-
- if (ctx->parent) {
- if (hx509_cert_cmp(ctx->parent, parent) != 0) {
- ret = HX509_REVOKE_NOT_SAME_PARENT;
- hx509_set_error_string(context, 0, ret,
- "Not same parent certifate as "
- "last certificate in request");
- goto out;
- }
- } else
- ctx->parent = hx509_cert_ref(parent);
-
- p = _hx509_get_cert(parent);
-
- ret = copy_AlgorithmIdentifier(ctx->digest, &one->reqCert.hashAlgorithm);
- if (ret)
- goto out;
-
- ret = _hx509_create_signature(context,
- NULL,
- &one->reqCert.hashAlgorithm,
- &c->tbsCertificate.issuer._save,
- NULL,
- &one->reqCert.issuerNameHash);
- if (ret)
- goto out;
-
- os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
- os.length =
- p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
-
- ret = _hx509_create_signature(context,
- NULL,
- &one->reqCert.hashAlgorithm,
- &os,
- NULL,
- &one->reqCert.issuerKeyHash);
- if (ret)
- goto out;
-
- ret = copy_CertificateSerialNumber(&c->tbsCertificate.serialNumber,
- &one->reqCert.serialNumber);
- if (ret)
- goto out;
-
- ctx->req->requestList.len++;
-out:
- hx509_cert_free(parent);
- if (ret) {
- free_OCSPInnerRequest(one);
- memset(one, 0, sizeof(*one));
- }
-
- return ret;
-}
-
-/**
- * Create an OCSP request for a set of certificates.
- *
- * @param context a hx509 context
- * @param reqcerts list of certificates to request ocsp data for
- * @param pool certificate pool to use when signing
- * @param signer certificate to use to sign the request
- * @param digest the signing algorithm in the request, if NULL use the
- * default signature algorithm,
- * @param request the encoded request, free with free_heim_octet_string().
- * @param nonce nonce in the request, free with free_heim_octet_string().
- *
- * @return An hx509 error code, see hx509_get_error_string().
- *
- * @ingroup hx509_revoke
- */
-
-int
-hx509_ocsp_request(hx509_context context,
- hx509_certs reqcerts,
- hx509_certs pool,
- hx509_cert signer,
- const AlgorithmIdentifier *digest,
- heim_octet_string *request,
- heim_octet_string *nonce)
-{
- OCSPRequest req;
- size_t size;
- int ret;
- struct ocsp_add_ctx ctx;
- Extensions *es;
-
- memset(&req, 0, sizeof(req));
-
- if (digest == NULL)
- digest = _hx509_crypto_default_digest_alg;
-
- ctx.req = &req.tbsRequest;
- ctx.certs = pool;
- ctx.digest = digest;
- ctx.parent = NULL;
-
- ret = hx509_certs_iter(context, reqcerts, add_to_req, &ctx);
- hx509_cert_free(ctx.parent);
- if (ret)
- goto out;
-
- if (nonce) {
- req.tbsRequest.requestExtensions =
- calloc(1, sizeof(*req.tbsRequest.requestExtensions));
- if (req.tbsRequest.requestExtensions == NULL) {
- ret = ENOMEM;
- goto out;
- }
-
- es = req.tbsRequest.requestExtensions;
-
- es->val = calloc(es->len, sizeof(es->val[0]));
- if (es->val == NULL) {
- ret = ENOMEM;
- goto out;
- }
- es->len = 1;
-
- ret = der_copy_oid(oid_id_pkix_ocsp_nonce(), &es->val[0].extnID);
- if (ret) {
- free_OCSPRequest(&req);
- return ret;
- }
-
- es->val[0].extnValue.data = malloc(10);
- if (es->val[0].extnValue.data == NULL) {
- ret = ENOMEM;
- goto out;
- }
- es->val[0].extnValue.length = 10;
-
- ret = RAND_bytes(es->val[0].extnValue.data,
- es->val[0].extnValue.length);
- if (ret != 1) {
- ret = HX509_CRYPTO_INTERNAL_ERROR;
- goto out;
- }
- ret = der_copy_octet_string(nonce, &es->val[0].extnValue);
- if (ret) {
- ret = ENOMEM;
- goto out;
- }
- }
-
- ASN1_MALLOC_ENCODE(OCSPRequest, request->data, request->length,
- &req, &size, ret);
- free_OCSPRequest(&req);
- if (ret)
- goto out;
- if (size != request->length)
- _hx509_abort("internal ASN.1 encoder error");
-
- return 0;
-
-out:
- free_OCSPRequest(&req);
- return ret;
-}
-
-static char *
-printable_time(time_t t)
-{
- static char s[128];
- strlcpy(s, ctime(&t)+ 4, sizeof(s));
- s[20] = 0;
- return s;
-}
-
-/**
- * Print the OCSP reply stored in a file.
- *
- * @param context a hx509 context
- * @param path path to a file with a OCSP reply
- * @param out the out FILE descriptor to print the reply on
- *
- * @return An hx509 error code, see hx509_get_error_string().
- *
- * @ingroup hx509_revoke
- */
-
-int
-hx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out)
-{
- struct revoke_ocsp ocsp;
- int ret, i;
-
- if (out == NULL)
- out = stdout;
-
- memset(&ocsp, 0, sizeof(ocsp));
-
- ocsp.path = strdup(path);
- if (ocsp.path == NULL)
- return ENOMEM;
-
- ret = load_ocsp(context, &ocsp);
- if (ret) {
- free_ocsp(&ocsp);
- return ret;
- }
-
- fprintf(out, "signer: ");
-
- switch(ocsp.ocsp.tbsResponseData.responderID.element) {
- case choice_OCSPResponderID_byName: {
- hx509_name n;
- char *s;
- _hx509_name_from_Name(&ocsp.ocsp.tbsResponseData.responderID.u.byName, &n);
- hx509_name_to_string(n, &s);
- hx509_name_free(&n);
- fprintf(out, " byName: %s\n", s);
- free(s);
- break;
- }
- case choice_OCSPResponderID_byKey: {
- char *s;
- hex_encode(ocsp.ocsp.tbsResponseData.responderID.u.byKey.data,
- ocsp.ocsp.tbsResponseData.responderID.u.byKey.length,
- &s);
- fprintf(out, " byKey: %s\n", s);
- free(s);
- break;
- }
- default:
- _hx509_abort("choice_OCSPResponderID unknown");
- break;
- }
-
- fprintf(out, "producedAt: %s\n",
- printable_time(ocsp.ocsp.tbsResponseData.producedAt));
-
- fprintf(out, "replies: %d\n", ocsp.ocsp.tbsResponseData.responses.len);
-
- for (i = 0; i < ocsp.ocsp.tbsResponseData.responses.len; i++) {
- const char *status;
- switch (ocsp.ocsp.tbsResponseData.responses.val[i].certStatus.element) {
- case choice_OCSPCertStatus_good:
- status = "good";
- break;
- case choice_OCSPCertStatus_revoked:
- status = "revoked";
- break;
- case choice_OCSPCertStatus_unknown:
- status = "unknown";
- break;
- default:
- status = "element unknown";
- }
-
- fprintf(out, "\t%d. status: %s\n", i, status);
-
- fprintf(out, "\tthisUpdate: %s\n",
- printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate));
- if (ocsp.ocsp.tbsResponseData.responses.val[i].nextUpdate)
- fprintf(out, "\tproducedAt: %s\n",
- printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate));
-
- }
-
- fprintf(out, "appended certs:\n");
- if (ocsp.certs)
- ret = hx509_certs_iter(context, ocsp.certs, hx509_ci_print_names, out);
-
- free_ocsp(&ocsp);
- return ret;
-}
-
-/**
- * Verify that the certificate is part of the OCSP reply and it's not
- * expired. Doesn't verify signature the OCSP reply or it's done by a
- * authorized sender, that is assumed to be already done.
- *
- * @param context a hx509 context
- * @param now the time right now, if 0, use the current time.
- * @param cert the certificate to verify
- * @param flags flags control the behavior
- * @param data pointer to the encode ocsp reply
- * @param length the length of the encode ocsp reply
- * @param expiration return the time the OCSP will expire and need to
- * be rechecked.
- *
- * @return An hx509 error code, see hx509_get_error_string().
- *
- * @ingroup hx509_verify
- */
-
-int
-hx509_ocsp_verify(hx509_context context,
- time_t now,
- hx509_cert cert,
- int flags,
- const void *data, size_t length,
- time_t *expiration)
-{
- const Certificate *c = _hx509_get_cert(cert);
- OCSPBasicOCSPResponse basic;
- int ret, i;
-
- if (now == 0)
- now = time(NULL);
-
- *expiration = 0;
-
- ret = parse_ocsp_basic(data, length, &basic);
- if (ret) {
- hx509_set_error_string(context, 0, ret,
- "Failed to parse OCSP response");
- return ret;
- }
-
- for (i = 0; i < basic.tbsResponseData.responses.len; i++) {
-
- ret = der_heim_integer_cmp(&basic.tbsResponseData.responses.val[i].certID.serialNumber,
- &c->tbsCertificate.serialNumber);
- if (ret != 0)
- continue;
-
- /* verify issuer hashes hash */
- ret = _hx509_verify_signature(context,
- NULL,
- &basic.tbsResponseData.responses.val[i].certID.hashAlgorithm,
- &c->tbsCertificate.issuer._save,
- &basic.tbsResponseData.responses.val[i].certID.issuerNameHash);
- if (ret != 0)
- continue;
-
- switch (basic.tbsResponseData.responses.val[i].certStatus.element) {
- case choice_OCSPCertStatus_good:
- break;
- case choice_OCSPCertStatus_revoked:
- case choice_OCSPCertStatus_unknown:
- continue;
- }
-
- /* don't allow the update to be in the future */
- if (basic.tbsResponseData.responses.val[i].thisUpdate >
- now + context->ocsp_time_diff)
- continue;
-
- /* don't allow the next update to be in the past */
- if (basic.tbsResponseData.responses.val[i].nextUpdate) {
- if (*basic.tbsResponseData.responses.val[i].nextUpdate < now)
- continue;
- *expiration = *basic.tbsResponseData.responses.val[i].nextUpdate;
- } else
- *expiration = now;
-
- free_OCSPBasicOCSPResponse(&basic);
- return 0;
- }
-
- free_OCSPBasicOCSPResponse(&basic);
-
- {
- hx509_name name;
- char *subject;
-
- ret = hx509_cert_get_subject(cert, &name);
- if (ret) {
- hx509_clear_error_string(context);
- goto out;
- }
- ret = hx509_name_to_string(name, &subject);
- hx509_name_free(&name);
- if (ret) {
- hx509_clear_error_string(context);
- goto out;
- }
- hx509_set_error_string(context, 0, HX509_CERT_NOT_IN_OCSP,
- "Certificate %s not in OCSP response "
- "or not good",
- subject);
- free(subject);
- }
-out:
- return HX509_CERT_NOT_IN_OCSP;
-}
-
-struct hx509_crl {
- hx509_certs revoked;
- time_t expire;
-};
-
-/**
- * Create a CRL context. Use hx509_crl_free() to free the CRL context.
- *
- * @param context a hx509 context.
- * @param crl return pointer to a newly allocated CRL context.
- *
- * @return An hx509 error code, see hx509_get_error_string().
- *
- * @ingroup hx509_verify
- */
-
-int
-hx509_crl_alloc(hx509_context context, hx509_crl *crl)
-{
- int ret;
-
- *crl = calloc(1, sizeof(**crl));
- if (*crl == NULL) {
- hx509_set_error_string(context, 0, ENOMEM, "out of memory");
- return ENOMEM;
- }
-
- ret = hx509_certs_init(context, "MEMORY:crl", 0, NULL, &(*crl)->revoked);
- if (ret) {
- free(*crl);
- *crl = NULL;
- return ret;
- }
- (*crl)->expire = 0;
- return ret;
-}
-
-/**
- * Add revoked certificate to an CRL context.
- *
- * @param context a hx509 context.
- * @param crl the CRL to add the revoked certificate to.
- * @param certs keyset of certificate to revoke.
- *
- * @return An hx509 error code, see hx509_get_error_string().
- *
- * @ingroup hx509_verify
- */
-
-int
-hx509_crl_add_revoked_certs(hx509_context context,
- hx509_crl crl,
- hx509_certs certs)
-{
- return hx509_certs_merge(context, crl->revoked, certs);
-}
-
-/**
- * Set the lifetime of a CRL context.
- *
- * @param context a hx509 context.
- * @param crl a CRL context
- * @param delta delta time the certificate is valid, library adds the
- * current time to this.
- *
- * @return An hx509 error code, see hx509_get_error_string().
- *
- * @ingroup hx509_verify
- */
-
-int
-hx509_crl_lifetime(hx509_context context, hx509_crl crl, int delta)
-{
- crl->expire = time(NULL) + delta;
- return 0;
-}
-
-/**
- * Free a CRL context.
- *
- * @param context a hx509 context.
- * @param crl a CRL context to free.
- *
- * @ingroup hx509_verify
- */
-
-void
-hx509_crl_free(hx509_context context, hx509_crl *crl)
-{
- if (*crl == NULL)
- return;
- hx509_certs_free(&(*crl)->revoked);
- memset(*crl, 0, sizeof(**crl));
- free(*crl);
- *crl = NULL;
-}
-
-static int
-add_revoked(hx509_context context, void *ctx, hx509_cert cert)
-{
- TBSCRLCertList *c = ctx;
- unsigned int num;
- void *ptr;
- int ret;
-
- num = c->revokedCertificates->len;
- ptr = realloc(c->revokedCertificates->val,
- (num + 1) * sizeof(c->revokedCertificates->val[0]));
- if (ptr == NULL) {
- hx509_clear_error_string(context);
- return ENOMEM;
- }
- c->revokedCertificates->val = ptr;
-
- ret = hx509_cert_get_serialnumber(cert,
- &c->revokedCertificates->val[num].userCertificate);
- if (ret) {
- hx509_clear_error_string(context);
- return ret;
- }
- c->revokedCertificates->val[num].revocationDate.element =
- choice_Time_generalTime;
- c->revokedCertificates->val[num].revocationDate.u.generalTime =
- time(NULL) - 3600 * 24;
- c->revokedCertificates->val[num].crlEntryExtensions = NULL;
-
- c->revokedCertificates->len++;
-
- return 0;
-}
-
-/**
- * Sign a CRL and return an encode certificate.
- *
- * @param context a hx509 context.
- * @param signer certificate to sign the CRL with
- * @param crl the CRL to sign
- * @param os return the signed and encoded CRL, free with
- * free_heim_octet_string()
- *
- * @return An hx509 error code, see hx509_get_error_string().
- *
- * @ingroup hx509_verify
- */
-
-int
-hx509_crl_sign(hx509_context context,
- hx509_cert signer,
- hx509_crl crl,
- heim_octet_string *os)
-{
- const AlgorithmIdentifier *sigalg = _hx509_crypto_default_sig_alg;
- CRLCertificateList c;
- size_t size;
- int ret;
- hx509_private_key signerkey;
-
- memset(&c, 0, sizeof(c));
-
- signerkey = _hx509_cert_private_key(signer);
- if (signerkey == NULL) {
- ret = HX509_PRIVATE_KEY_MISSING;
- hx509_set_error_string(context, 0, ret,
- "Private key missing for CRL signing");
- return ret;
- }
-
- c.tbsCertList.version = malloc(sizeof(*c.tbsCertList.version));
- if (c.tbsCertList.version == NULL) {
- hx509_set_error_string(context, 0, ENOMEM, "out of memory");
- return ENOMEM;
- }
-
- *c.tbsCertList.version = 1;
-
- ret = copy_AlgorithmIdentifier(sigalg, &c.tbsCertList.signature);
- if (ret) {
- hx509_clear_error_string(context);
- goto out;
- }
-
- ret = copy_Name(&_hx509_get_cert(signer)->tbsCertificate.issuer,
- &c.tbsCertList.issuer);
- if (ret) {
- hx509_clear_error_string(context);
- goto out;
- }
-
- c.tbsCertList.thisUpdate.element = choice_Time_generalTime;
- c.tbsCertList.thisUpdate.u.generalTime = time(NULL) - 24 * 3600;
-
- c.tbsCertList.nextUpdate = malloc(sizeof(*c.tbsCertList.nextUpdate));
- if (c.tbsCertList.nextUpdate == NULL) {
- hx509_set_error_string(context, 0, ENOMEM, "out of memory");
- ret = ENOMEM;
- goto out;
- }
-
- {
- time_t next = crl->expire;
- if (next == 0)
- next = time(NULL) + 24 * 3600 * 365;
-
- c.tbsCertList.nextUpdate->element = choice_Time_generalTime;
- c.tbsCertList.nextUpdate->u.generalTime = next;
- }
-
- c.tbsCertList.revokedCertificates =
- calloc(1, sizeof(*c.tbsCertList.revokedCertificates));
- if (c.tbsCertList.revokedCertificates == NULL) {
- hx509_set_error_string(context, 0, ENOMEM, "out of memory");
- ret = ENOMEM;
- goto out;
- }
- c.tbsCertList.crlExtensions = NULL;
-
- ret = hx509_certs_iter(context, crl->revoked, add_revoked, &c.tbsCertList);
- if (ret)
- goto out;
-
- /* if not revoked certs, remove OPTIONAL entry */
- if (c.tbsCertList.revokedCertificates->len == 0) {
- free(c.tbsCertList.revokedCertificates);
- c.tbsCertList.revokedCertificates = NULL;
- }
-
- ASN1_MALLOC_ENCODE(TBSCRLCertList, os->data, os->length,
- &c.tbsCertList, &size, ret);
- if (ret) {
- hx509_set_error_string(context, 0, ret, "failed to encode tbsCRL");
- goto out;
- }
- if (size != os->length)
- _hx509_abort("internal ASN.1 encoder error");
-
-
- ret = _hx509_create_signature_bitstring(context,
- signerkey,
- sigalg,
- os,
- &c.signatureAlgorithm,
- &c.signatureValue);
- free(os->data);
-
- ASN1_MALLOC_ENCODE(CRLCertificateList, os->data, os->length,
- &c, &size, ret);
- free_CRLCertificateList(&c);
- if (ret) {
- hx509_set_error_string(context, 0, ret, "failed to encode CRL");
- goto out;
- }
- if (size != os->length)
- _hx509_abort("internal ASN.1 encoder error");
-
- return 0;
-
-out:
- free_CRLCertificateList(&c);
- return ret;
-}
OpenPOWER on IntegriCloud