📄 revoke.c
字号:
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 intload_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 */inthx509_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 */inthx509_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; int diff; /* check if cert.issuer == crls.val[i].crl.issuer */ ret = _hx509_name_cmp(&c->tbsCertificate.issuer, &crl->crl.tbsCertList.issuer, &diff); if (ret || diff) 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 intadd_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 */inthx509_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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -