📄 revoke.c
字号:
/* * Copyright (c) 2006 - 2007 Kungliga Tekniska H鰃skolan * (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 22583 2008-02-11 20:46:21Z 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 */inthx509_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 voidfree_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 */voidhx509_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 intverify_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 intparse_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 intload_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 */inthx509_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 intverify_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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -