2 * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * @page page_revoke Revocation methods
37 * There are two revocation method for PKIX/X.509: CRL and OCSP.
38 * Revocation is needed if the private key is lost and
39 * stolen. Depending on how picky you are, you might want to make
40 * revocation for destroyed private keys too (smartcard broken), but
41 * that should not be a problem.
43 * CRL is a list of certifiates that have expired.
45 * OCSP is an online checking method where the requestor sends a list
46 * of certificates to the OCSP server to return a signed reply if they
47 * are valid or not. Some services sends a OCSP reply as part of the
48 * hand-shake to make the revoktion decision simpler/faster for the
57 CRLCertificateList crl;
65 OCSPBasicOCSPResponse ocsp;
71 struct hx509_revoke_ctx_data {
74 struct revoke_crl *val;
78 struct revoke_ocsp *val;
84 * Allocate a revokation context. Free with hx509_revoke_free().
86 * @param context A hx509 context.
87 * @param ctx returns a newly allocated revokation context.
89 * @return An hx509 error code, see hx509_get_error_string().
91 * @ingroup hx509_revoke
95 hx509_revoke_init(hx509_context context, hx509_revoke_ctx *ctx)
97 *ctx = calloc(1, sizeof(**ctx));
102 (*ctx)->crls.len = 0;
103 (*ctx)->crls.val = NULL;
104 (*ctx)->ocsps.len = 0;
105 (*ctx)->ocsps.val = NULL;
111 _hx509_revoke_ref(hx509_revoke_ctx ctx)
116 _hx509_abort("revoke ctx refcount == 0 on ref");
118 if (ctx->ref == UINT_MAX)
119 _hx509_abort("revoke ctx refcount == UINT_MAX on ref");
124 free_ocsp(struct revoke_ocsp *ocsp)
127 free_OCSPBasicOCSPResponse(&ocsp->ocsp);
128 hx509_certs_free(&ocsp->certs);
129 hx509_cert_free(ocsp->signer);
133 * Free a hx509 revokation context.
135 * @param ctx context to be freed
137 * @ingroup hx509_revoke
141 hx509_revoke_free(hx509_revoke_ctx *ctx)
145 if (ctx == NULL || *ctx == NULL)
148 if ((*ctx)->ref == 0)
149 _hx509_abort("revoke ctx refcount == 0 on free");
150 if (--(*ctx)->ref > 0)
153 for (i = 0; i < (*ctx)->crls.len; i++) {
154 free((*ctx)->crls.val[i].path);
155 free_CRLCertificateList(&(*ctx)->crls.val[i].crl);
158 for (i = 0; i < (*ctx)->ocsps.len; i++)
159 free_ocsp(&(*ctx)->ocsps.val[i]);
160 free((*ctx)->ocsps.val);
162 free((*ctx)->crls.val);
164 memset(*ctx, 0, sizeof(**ctx));
170 verify_ocsp(hx509_context context,
171 struct revoke_ocsp *ocsp,
176 hx509_cert signer = NULL;
180 _hx509_query_clear(&q);
183 * Need to match on issuer too in case there are two CA that have
184 * issued the same name to a certificate. One example of this is
185 * the www.openvalidation.org test's ocsp validator.
188 q.match = HX509_QUERY_MATCH_ISSUER_NAME;
189 q.issuer_name = &_hx509_get_cert(parent)->tbsCertificate.issuer;
191 switch(ocsp->ocsp.tbsResponseData.responderID.element) {
192 case choice_OCSPResponderID_byName:
193 q.match |= HX509_QUERY_MATCH_SUBJECT_NAME;
194 q.subject_name = &ocsp->ocsp.tbsResponseData.responderID.u.byName;
196 case choice_OCSPResponderID_byKey:
197 q.match |= HX509_QUERY_MATCH_KEY_HASH_SHA1;
198 q.keyhash_sha1 = &ocsp->ocsp.tbsResponseData.responderID.u.byKey;
202 ret = hx509_certs_find(context, certs, &q, &signer);
203 if (ret && ocsp->certs)
204 ret = hx509_certs_find(context, ocsp->certs, &q, &signer);
209 * If signer certificate isn't the CA certificate, lets check the
210 * it is the CA that signed the signer certificate and the OCSP EKU
213 if (hx509_cert_cmp(signer, parent) != 0) {
214 Certificate *p = _hx509_get_cert(parent);
215 Certificate *s = _hx509_get_cert(signer);
217 ret = _hx509_cert_is_parent_cmp(s, p, 0);
219 ret = HX509_PARENT_NOT_CA;
220 hx509_set_error_string(context, 0, ret, "Revoke OCSP signer is "
221 "doesn't have CA as signer certificate");
225 ret = _hx509_verify_signature_bitstring(context,
227 &s->signatureAlgorithm,
228 &s->tbsCertificate._save,
231 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
232 "OCSP signer signature invalid");
236 ret = hx509_cert_check_eku(context, signer,
237 &asn1_oid_id_pkix_kp_OCSPSigning, 0);
242 ret = _hx509_verify_signature_bitstring(context,
243 _hx509_get_cert(signer),
244 &ocsp->ocsp.signatureAlgorithm,
245 &ocsp->ocsp.tbsResponseData._save,
246 &ocsp->ocsp.signature);
248 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
249 "OCSP signature invalid");
253 ocsp->signer = signer;
257 hx509_cert_free(signer);
267 parse_ocsp_basic(const void *data, size_t length, OCSPBasicOCSPResponse *basic)
273 memset(basic, 0, sizeof(*basic));
275 ret = decode_OCSPResponse(data, length, &resp, &size);
278 if (length != size) {
279 free_OCSPResponse(&resp);
280 return ASN1_EXTRA_DATA;
283 switch (resp.responseStatus) {
287 free_OCSPResponse(&resp);
288 return HX509_REVOKE_WRONG_DATA;
291 if (resp.responseBytes == NULL) {
292 free_OCSPResponse(&resp);
296 ret = der_heim_oid_cmp(&resp.responseBytes->responseType,
297 &asn1_oid_id_pkix_ocsp_basic);
299 free_OCSPResponse(&resp);
300 return HX509_REVOKE_WRONG_DATA;
303 ret = decode_OCSPBasicOCSPResponse(resp.responseBytes->response.data,
304 resp.responseBytes->response.length,
308 free_OCSPResponse(&resp);
311 if (size != resp.responseBytes->response.length) {
312 free_OCSPResponse(&resp);
313 free_OCSPBasicOCSPResponse(basic);
314 return ASN1_EXTRA_DATA;
316 free_OCSPResponse(&resp);
326 load_ocsp(hx509_context context, struct revoke_ocsp *ocsp)
328 OCSPBasicOCSPResponse basic;
329 hx509_certs certs = NULL;
335 ret = rk_undumpdata(ocsp->path, &data, &length);
339 ret = stat(ocsp->path, &sb);
343 ret = parse_ocsp_basic(data, length, &basic);
346 hx509_set_error_string(context, 0, ret,
347 "Failed to parse OCSP response");
354 ret = hx509_certs_init(context, "MEMORY:ocsp-certs", 0,
357 free_OCSPBasicOCSPResponse(&basic);
361 for (i = 0; i < basic.certs->len; i++) {
364 ret = hx509_cert_init(context, &basic.certs->val[i], &c);
368 ret = hx509_certs_add(context, certs, c);
375 ocsp->last_modfied = sb.st_mtime;
377 free_OCSPBasicOCSPResponse(&ocsp->ocsp);
378 hx509_certs_free(&ocsp->certs);
379 hx509_cert_free(ocsp->signer);
389 * Add a OCSP file to the revokation context.
391 * @param context hx509 context
392 * @param ctx hx509 revokation context
393 * @param path path to file that is going to be added to the context.
395 * @return An hx509 error code, see hx509_get_error_string().
397 * @ingroup hx509_revoke
401 hx509_revoke_add_ocsp(hx509_context context,
402 hx509_revoke_ctx ctx,
409 if (strncmp(path, "FILE:", 5) != 0) {
410 hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
411 "unsupport type in %s", path);
412 return HX509_UNSUPPORTED_OPERATION;
417 for (i = 0; i < ctx->ocsps.len; i++) {
418 if (strcmp(ctx->ocsps.val[0].path, path) == 0)
422 data = realloc(ctx->ocsps.val,
423 (ctx->ocsps.len + 1) * sizeof(ctx->ocsps.val[0]));
425 hx509_clear_error_string(context);
429 ctx->ocsps.val = data;
431 memset(&ctx->ocsps.val[ctx->ocsps.len], 0,
432 sizeof(ctx->ocsps.val[0]));
434 ctx->ocsps.val[ctx->ocsps.len].path = strdup(path);
435 if (ctx->ocsps.val[ctx->ocsps.len].path == NULL) {
436 hx509_clear_error_string(context);
440 ret = load_ocsp(context, &ctx->ocsps.val[ctx->ocsps.len]);
442 free(ctx->ocsps.val[ctx->ocsps.len].path);
455 verify_crl(hx509_context context,
456 hx509_revoke_ctx ctx,
457 CRLCertificateList *crl,
467 t = _hx509_Time2time_t(&crl->tbsCertList.thisUpdate);
469 hx509_set_error_string(context, 0, HX509_CRL_USED_BEFORE_TIME,
470 "CRL used before time");
471 return HX509_CRL_USED_BEFORE_TIME;
474 if (crl->tbsCertList.nextUpdate == NULL) {
475 hx509_set_error_string(context, 0, HX509_CRL_INVALID_FORMAT,
476 "CRL missing nextUpdate");
477 return HX509_CRL_INVALID_FORMAT;
480 t = _hx509_Time2time_t(crl->tbsCertList.nextUpdate);
482 hx509_set_error_string(context, 0, HX509_CRL_USED_AFTER_TIME,
483 "CRL used after time");
484 return HX509_CRL_USED_AFTER_TIME;
487 _hx509_query_clear(&q);
490 * If it's the signer have CRLSIGN bit set, use that as the signer
491 * cert for the certificate, otherwise, search for a certificate.
493 if (_hx509_check_key_usage(context, parent, 1 << 6, FALSE) == 0) {
494 signer = hx509_cert_ref(parent);
496 q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
497 q.match |= HX509_QUERY_KU_CRLSIGN;
498 q.subject_name = &crl->tbsCertList.issuer;
500 ret = hx509_certs_find(context, certs, &q, &signer);
502 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
503 "Failed to find certificate for CRL");
508 ret = _hx509_verify_signature_bitstring(context,
509 _hx509_get_cert(signer),
510 &crl->signatureAlgorithm,
511 &crl->tbsCertList._save,
512 &crl->signatureValue);
514 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
515 "CRL signature invalid");
520 * If signer is not CA cert, need to check revoke status of this
521 * CRL signing cert too, this include all parent CRL signer cert
522 * up to the root *sigh*, assume root at least hve CERTSIGN flag
525 while (_hx509_check_key_usage(context, signer, 1 << 5, TRUE)) {
526 hx509_cert crl_parent;
528 _hx509_query_clear(&q);
530 q.match = HX509_QUERY_MATCH_SUBJECT_NAME;
531 q.match |= HX509_QUERY_KU_CRLSIGN;
532 q.subject_name = &_hx509_get_cert(signer)->tbsCertificate.issuer;
534 ret = hx509_certs_find(context, certs, &q, &crl_parent);
536 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
537 "Failed to find parent of CRL signer");
541 ret = hx509_revoke_verify(context,
547 hx509_cert_free(signer);
550 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
551 "Failed to verify revoke "
552 "status of CRL signer");
558 hx509_cert_free(signer);
564 load_crl(const char *path, time_t *t, CRLCertificateList *crl)
571 memset(crl, 0, sizeof(*crl));
573 ret = rk_undumpdata(path, &data, &length);
577 ret = stat(path, &sb);
583 ret = decode_CRLCertificateList(data, length, crl, &size);
588 /* check signature is aligned */
589 if (crl->signatureValue.length & 7) {
590 free_CRLCertificateList(crl);
591 return HX509_CRYPTO_SIG_INVALID_FORMAT;
597 * Add a CRL file to the revokation context.
599 * @param context hx509 context
600 * @param ctx hx509 revokation context
601 * @param path path to file that is going to be added to the context.
603 * @return An hx509 error code, see hx509_get_error_string().
605 * @ingroup hx509_revoke
609 hx509_revoke_add_crl(hx509_context context,
610 hx509_revoke_ctx ctx,
617 if (strncmp(path, "FILE:", 5) != 0) {
618 hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
619 "unsupport type in %s", path);
620 return HX509_UNSUPPORTED_OPERATION;
626 for (i = 0; i < ctx->crls.len; i++) {
627 if (strcmp(ctx->crls.val[0].path, path) == 0)
631 data = realloc(ctx->crls.val,
632 (ctx->crls.len + 1) * sizeof(ctx->crls.val[0]));
634 hx509_clear_error_string(context);
637 ctx->crls.val = data;
639 memset(&ctx->crls.val[ctx->crls.len], 0, sizeof(ctx->crls.val[0]));
641 ctx->crls.val[ctx->crls.len].path = strdup(path);
642 if (ctx->crls.val[ctx->crls.len].path == NULL) {
643 hx509_clear_error_string(context);
648 &ctx->crls.val[ctx->crls.len].last_modfied,
649 &ctx->crls.val[ctx->crls.len].crl);
651 free(ctx->crls.val[ctx->crls.len].path);
661 * Check that a certificate is not expired according to a revokation
662 * context. Also need the parent certificte to the check OCSP
665 * @param context hx509 context
666 * @param ctx hx509 revokation context
672 * @return An hx509 error code, see hx509_get_error_string().
674 * @ingroup hx509_revoke
679 hx509_revoke_verify(hx509_context context,
680 hx509_revoke_ctx ctx,
684 hx509_cert parent_cert)
686 const Certificate *c = _hx509_get_cert(cert);
687 const Certificate *p = _hx509_get_cert(parent_cert);
688 unsigned long i, j, k;
691 hx509_clear_error_string(context);
693 for (i = 0; i < ctx->ocsps.len; i++) {
694 struct revoke_ocsp *ocsp = &ctx->ocsps.val[i];
697 /* check this ocsp apply to this cert */
699 /* check if there is a newer version of the file */
700 ret = stat(ocsp->path, &sb);
701 if (ret == 0 && ocsp->last_modfied != sb.st_mtime) {
702 ret = load_ocsp(context, ocsp);
707 /* verify signature in ocsp if not already done */
708 if (ocsp->signer == NULL) {
709 ret = verify_ocsp(context, ocsp, now, certs, parent_cert);
714 for (j = 0; j < ocsp->ocsp.tbsResponseData.responses.len; j++) {
715 heim_octet_string os;
717 ret = der_heim_integer_cmp(&ocsp->ocsp.tbsResponseData.responses.val[j].certID.serialNumber,
718 &c->tbsCertificate.serialNumber);
722 /* verify issuer hashes hash */
723 ret = _hx509_verify_signature(context,
725 &ocsp->ocsp.tbsResponseData.responses.val[i].certID.hashAlgorithm,
726 &c->tbsCertificate.issuer._save,
727 &ocsp->ocsp.tbsResponseData.responses.val[i].certID.issuerNameHash);
731 os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
732 os.length = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
734 ret = _hx509_verify_signature(context,
736 &ocsp->ocsp.tbsResponseData.responses.val[j].certID.hashAlgorithm,
738 &ocsp->ocsp.tbsResponseData.responses.val[j].certID.issuerKeyHash);
742 switch (ocsp->ocsp.tbsResponseData.responses.val[j].certStatus.element) {
743 case choice_OCSPCertStatus_good:
745 case choice_OCSPCertStatus_revoked:
746 hx509_set_error_string(context, 0,
748 "Certificate revoked by issuer in OCSP");
749 return HX509_CERT_REVOKED;
750 case choice_OCSPCertStatus_unknown:
754 /* don't allow the update to be in the future */
755 if (ocsp->ocsp.tbsResponseData.responses.val[j].thisUpdate >
756 now + context->ocsp_time_diff)
759 /* don't allow the next update to be in the past */
760 if (ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate) {
761 if (*ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate < now)
764 /* Should force a refetch, but can we ? */;
770 for (i = 0; i < ctx->crls.len; i++) {
771 struct revoke_crl *crl = &ctx->crls.val[i];
775 /* check if cert.issuer == crls.val[i].crl.issuer */
776 ret = _hx509_name_cmp(&c->tbsCertificate.issuer,
777 &crl->crl.tbsCertList.issuer, &diff);
781 ret = stat(crl->path, &sb);
782 if (ret == 0 && crl->last_modfied != sb.st_mtime) {
783 CRLCertificateList cl;
785 ret = load_crl(crl->path, &crl->last_modfied, &cl);
787 free_CRLCertificateList(&crl->crl);
790 crl->failed_verify = 0;
793 if (crl->failed_verify)
796 /* verify signature in crl if not already done */
797 if (crl->verified == 0) {
798 ret = verify_crl(context, ctx, &crl->crl, now, certs, parent_cert);
800 crl->failed_verify = 1;
806 if (crl->crl.tbsCertList.crlExtensions) {
807 for (j = 0; j < crl->crl.tbsCertList.crlExtensions->len; j++) {
808 if (crl->crl.tbsCertList.crlExtensions->val[j].critical) {
809 hx509_set_error_string(context, 0,
810 HX509_CRL_UNKNOWN_EXTENSION,
811 "Unknown CRL extension");
812 return HX509_CRL_UNKNOWN_EXTENSION;
817 if (crl->crl.tbsCertList.revokedCertificates == NULL)
820 /* check if cert is in crl */
821 for (j = 0; j < crl->crl.tbsCertList.revokedCertificates->len; j++) {
824 ret = der_heim_integer_cmp(&crl->crl.tbsCertList.revokedCertificates->val[j].userCertificate,
825 &c->tbsCertificate.serialNumber);
829 t = _hx509_Time2time_t(&crl->crl.tbsCertList.revokedCertificates->val[j].revocationDate);
833 if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions)
834 for (k = 0; k < crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->len; k++)
835 if (crl->crl.tbsCertList.revokedCertificates->val[j].crlEntryExtensions->val[k].critical)
836 return HX509_CRL_UNKNOWN_EXTENSION;
838 hx509_set_error_string(context, 0,
840 "Certificate revoked by issuer in CRL");
841 return HX509_CERT_REVOKED;
848 if (context->flags & HX509_CTX_VERIFY_MISSING_OK)
850 hx509_set_error_string(context, HX509_ERROR_APPEND,
851 HX509_REVOKE_STATUS_MISSING,
852 "No revoke status found for "
854 return HX509_REVOKE_STATUS_MISSING;
857 struct ocsp_add_ctx {
860 const AlgorithmIdentifier *digest;
865 add_to_req(hx509_context context, void *ptr, hx509_cert cert)
867 struct ocsp_add_ctx *ctx = ptr;
868 OCSPInnerRequest *one;
869 hx509_cert parent = NULL;
870 Certificate *p, *c = _hx509_get_cert(cert);
871 heim_octet_string os;
876 d = realloc(ctx->req->requestList.val,
877 sizeof(ctx->req->requestList.val[0]) *
878 (ctx->req->requestList.len + 1));
881 ctx->req->requestList.val = d;
883 one = &ctx->req->requestList.val[ctx->req->requestList.len];
884 memset(one, 0, sizeof(*one));
886 _hx509_query_clear(&q);
888 q.match |= HX509_QUERY_FIND_ISSUER_CERT;
891 ret = hx509_certs_find(context, ctx->certs, &q, &parent);
896 if (hx509_cert_cmp(ctx->parent, parent) != 0) {
897 ret = HX509_REVOKE_NOT_SAME_PARENT;
898 hx509_set_error_string(context, 0, ret,
899 "Not same parent certifate as "
900 "last certificate in request");
904 ctx->parent = hx509_cert_ref(parent);
906 p = _hx509_get_cert(parent);
908 ret = copy_AlgorithmIdentifier(ctx->digest, &one->reqCert.hashAlgorithm);
912 ret = _hx509_create_signature(context,
914 &one->reqCert.hashAlgorithm,
915 &c->tbsCertificate.issuer._save,
917 &one->reqCert.issuerNameHash);
921 os.data = p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
923 p->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
925 ret = _hx509_create_signature(context,
927 &one->reqCert.hashAlgorithm,
930 &one->reqCert.issuerKeyHash);
934 ret = copy_CertificateSerialNumber(&c->tbsCertificate.serialNumber,
935 &one->reqCert.serialNumber);
939 ctx->req->requestList.len++;
941 hx509_cert_free(parent);
943 free_OCSPInnerRequest(one);
944 memset(one, 0, sizeof(*one));
951 * Create an OCSP request for a set of certificates.
953 * @param context a hx509 context
954 * @param reqcerts list of certificates to request ocsp data for
955 * @param pool certificate pool to use when signing
956 * @param signer certificate to use to sign the request
957 * @param digest the signing algorithm in the request, if NULL use the
958 * default signature algorithm,
959 * @param request the encoded request, free with free_heim_octet_string().
960 * @param nonce nonce in the request, free with free_heim_octet_string().
962 * @return An hx509 error code, see hx509_get_error_string().
964 * @ingroup hx509_revoke
968 hx509_ocsp_request(hx509_context context,
969 hx509_certs reqcerts,
972 const AlgorithmIdentifier *digest,
973 heim_octet_string *request,
974 heim_octet_string *nonce)
979 struct ocsp_add_ctx ctx;
982 memset(&req, 0, sizeof(req));
985 digest = _hx509_crypto_default_digest_alg;
987 ctx.req = &req.tbsRequest;
992 ret = hx509_certs_iter(context, reqcerts, add_to_req, &ctx);
993 hx509_cert_free(ctx.parent);
998 req.tbsRequest.requestExtensions =
999 calloc(1, sizeof(*req.tbsRequest.requestExtensions));
1000 if (req.tbsRequest.requestExtensions == NULL) {
1005 es = req.tbsRequest.requestExtensions;
1007 es->val = calloc(es->len, sizeof(es->val[0]));
1008 if (es->val == NULL) {
1013 ret = der_copy_oid(&asn1_oid_id_pkix_ocsp_nonce, &es->val[0].extnID);
1015 free_OCSPRequest(&req);
1019 es->val[0].extnValue.data = malloc(10);
1020 if (es->val[0].extnValue.data == NULL) {
1024 es->val[0].extnValue.length = 10;
1026 ret = RAND_bytes(es->val[0].extnValue.data,
1027 es->val[0].extnValue.length);
1029 ret = HX509_CRYPTO_INTERNAL_ERROR;
1032 ret = der_copy_octet_string(nonce, &es->val[0].extnValue);
1039 ASN1_MALLOC_ENCODE(OCSPRequest, request->data, request->length,
1041 free_OCSPRequest(&req);
1044 if (size != request->length)
1045 _hx509_abort("internal ASN.1 encoder error");
1050 free_OCSPRequest(&req);
1055 printable_time(time_t t)
1058 strlcpy(s, ctime(&t)+ 4, sizeof(s));
1064 * Print the OCSP reply stored in a file.
1066 * @param context a hx509 context
1067 * @param path path to a file with a OCSP reply
1068 * @param out the out FILE descriptor to print the reply on
1070 * @return An hx509 error code, see hx509_get_error_string().
1072 * @ingroup hx509_revoke
1076 hx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out)
1078 struct revoke_ocsp ocsp;
1084 memset(&ocsp, 0, sizeof(ocsp));
1086 ocsp.path = strdup(path);
1087 if (ocsp.path == NULL)
1090 ret = load_ocsp(context, &ocsp);
1096 fprintf(out, "signer: ");
1098 switch(ocsp.ocsp.tbsResponseData.responderID.element) {
1099 case choice_OCSPResponderID_byName: {
1102 _hx509_name_from_Name(&ocsp.ocsp.tbsResponseData.responderID.u.byName, &n);
1103 hx509_name_to_string(n, &s);
1104 hx509_name_free(&n);
1105 fprintf(out, " byName: %s\n", s);
1109 case choice_OCSPResponderID_byKey: {
1111 hex_encode(ocsp.ocsp.tbsResponseData.responderID.u.byKey.data,
1112 ocsp.ocsp.tbsResponseData.responderID.u.byKey.length,
1114 fprintf(out, " byKey: %s\n", s);
1119 _hx509_abort("choice_OCSPResponderID unknown");
1123 fprintf(out, "producedAt: %s\n",
1124 printable_time(ocsp.ocsp.tbsResponseData.producedAt));
1126 fprintf(out, "replies: %d\n", ocsp.ocsp.tbsResponseData.responses.len);
1128 for (i = 0; i < ocsp.ocsp.tbsResponseData.responses.len; i++) {
1130 switch (ocsp.ocsp.tbsResponseData.responses.val[i].certStatus.element) {
1131 case choice_OCSPCertStatus_good:
1134 case choice_OCSPCertStatus_revoked:
1137 case choice_OCSPCertStatus_unknown:
1141 status = "element unknown";
1144 fprintf(out, "\t%d. status: %s\n", i, status);
1146 fprintf(out, "\tthisUpdate: %s\n",
1147 printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate));
1148 if (ocsp.ocsp.tbsResponseData.responses.val[i].nextUpdate)
1149 fprintf(out, "\tproducedAt: %s\n",
1150 printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate));
1154 fprintf(out, "appended certs:\n");
1156 ret = hx509_certs_iter(context, ocsp.certs, hx509_ci_print_names, out);
1163 * Verify that the certificate is part of the OCSP reply and it's not
1164 * expired. Doesn't verify signature the OCSP reply or it's done by a
1165 * authorized sender, that is assumed to be already done.
1167 * @param context a hx509 context
1168 * @param now the time right now, if 0, use the current time.
1169 * @param cert the certificate to verify
1170 * @param flags flags control the behavior
1171 * @param data pointer to the encode ocsp reply
1172 * @param length the length of the encode ocsp reply
1173 * @param expiration return the time the OCSP will expire and need to
1176 * @return An hx509 error code, see hx509_get_error_string().
1178 * @ingroup hx509_verify
1182 hx509_ocsp_verify(hx509_context context,
1186 const void *data, size_t length,
1189 const Certificate *c = _hx509_get_cert(cert);
1190 OCSPBasicOCSPResponse basic;
1198 ret = parse_ocsp_basic(data, length, &basic);
1200 hx509_set_error_string(context, 0, ret,
1201 "Failed to parse OCSP response");
1205 for (i = 0; i < basic.tbsResponseData.responses.len; i++) {
1207 ret = der_heim_integer_cmp(&basic.tbsResponseData.responses.val[i].certID.serialNumber,
1208 &c->tbsCertificate.serialNumber);
1212 /* verify issuer hashes hash */
1213 ret = _hx509_verify_signature(context,
1215 &basic.tbsResponseData.responses.val[i].certID.hashAlgorithm,
1216 &c->tbsCertificate.issuer._save,
1217 &basic.tbsResponseData.responses.val[i].certID.issuerNameHash);
1221 switch (basic.tbsResponseData.responses.val[i].certStatus.element) {
1222 case choice_OCSPCertStatus_good:
1224 case choice_OCSPCertStatus_revoked:
1225 case choice_OCSPCertStatus_unknown:
1229 /* don't allow the update to be in the future */
1230 if (basic.tbsResponseData.responses.val[i].thisUpdate >
1231 now + context->ocsp_time_diff)
1234 /* don't allow the next update to be in the past */
1235 if (basic.tbsResponseData.responses.val[i].nextUpdate) {
1236 if (*basic.tbsResponseData.responses.val[i].nextUpdate < now)
1238 *expiration = *basic.tbsResponseData.responses.val[i].nextUpdate;
1242 free_OCSPBasicOCSPResponse(&basic);
1246 free_OCSPBasicOCSPResponse(&basic);
1252 ret = hx509_cert_get_subject(cert, &name);
1254 hx509_clear_error_string(context);
1257 ret = hx509_name_to_string(name, &subject);
1258 hx509_name_free(&name);
1260 hx509_clear_error_string(context);
1263 hx509_set_error_string(context, 0, HX509_CERT_NOT_IN_OCSP,
1264 "Certificate %s not in OCSP response "
1270 return HX509_CERT_NOT_IN_OCSP;
1274 hx509_certs revoked;
1279 * Create a CRL context. Use hx509_crl_free() to free the CRL context.
1281 * @param context a hx509 context.
1282 * @param crl return pointer to a newly allocated CRL context.
1284 * @return An hx509 error code, see hx509_get_error_string().
1286 * @ingroup hx509_verify
1290 hx509_crl_alloc(hx509_context context, hx509_crl *crl)
1294 *crl = calloc(1, sizeof(**crl));
1296 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1300 ret = hx509_certs_init(context, "MEMORY:crl", 0, NULL, &(*crl)->revoked);
1311 * Add revoked certificate to an CRL context.
1313 * @param context a hx509 context.
1314 * @param crl the CRL to add the revoked certificate to.
1315 * @param certs keyset of certificate to revoke.
1317 * @return An hx509 error code, see hx509_get_error_string().
1319 * @ingroup hx509_verify
1323 hx509_crl_add_revoked_certs(hx509_context context,
1327 return hx509_certs_merge(context, crl->revoked, certs);
1331 * Set the lifetime of a CRL context.
1333 * @param context a hx509 context.
1334 * @param crl a CRL context
1335 * @param delta delta time the certificate is valid, library adds the
1336 * current time to this.
1338 * @return An hx509 error code, see hx509_get_error_string().
1340 * @ingroup hx509_verify
1344 hx509_crl_lifetime(hx509_context context, hx509_crl crl, int delta)
1346 crl->expire = time(NULL) + delta;
1351 * Free a CRL context.
1353 * @param context a hx509 context.
1354 * @param crl a CRL context to free.
1356 * @ingroup hx509_verify
1360 hx509_crl_free(hx509_context context, hx509_crl *crl)
1364 hx509_certs_free(&(*crl)->revoked);
1365 memset(*crl, 0, sizeof(**crl));
1371 add_revoked(hx509_context context, void *ctx, hx509_cert cert)
1373 TBSCRLCertList *c = ctx;
1378 num = c->revokedCertificates->len;
1379 ptr = realloc(c->revokedCertificates->val,
1380 (num + 1) * sizeof(c->revokedCertificates->val[0]));
1382 hx509_clear_error_string(context);
1385 c->revokedCertificates->val = ptr;
1387 ret = hx509_cert_get_serialnumber(cert,
1388 &c->revokedCertificates->val[num].userCertificate);
1390 hx509_clear_error_string(context);
1393 c->revokedCertificates->val[num].revocationDate.element =
1394 choice_Time_generalTime;
1395 c->revokedCertificates->val[num].revocationDate.u.generalTime =
1396 time(NULL) - 3600 * 24;
1397 c->revokedCertificates->val[num].crlEntryExtensions = NULL;
1399 c->revokedCertificates->len++;
1405 * Sign a CRL and return an encode certificate.
1407 * @param context a hx509 context.
1408 * @param signer certificate to sign the CRL with
1409 * @param crl the CRL to sign
1410 * @param os return the signed and encoded CRL, free with
1411 * free_heim_octet_string()
1413 * @return An hx509 error code, see hx509_get_error_string().
1415 * @ingroup hx509_verify
1419 hx509_crl_sign(hx509_context context,
1422 heim_octet_string *os)
1424 const AlgorithmIdentifier *sigalg = _hx509_crypto_default_sig_alg;
1425 CRLCertificateList c;
1428 hx509_private_key signerkey;
1430 memset(&c, 0, sizeof(c));
1432 signerkey = _hx509_cert_private_key(signer);
1433 if (signerkey == NULL) {
1434 ret = HX509_PRIVATE_KEY_MISSING;
1435 hx509_set_error_string(context, 0, ret,
1436 "Private key missing for CRL signing");
1440 c.tbsCertList.version = malloc(sizeof(*c.tbsCertList.version));
1441 if (c.tbsCertList.version == NULL) {
1442 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1446 *c.tbsCertList.version = 1;
1448 ret = copy_AlgorithmIdentifier(sigalg, &c.tbsCertList.signature);
1450 hx509_clear_error_string(context);
1454 ret = copy_Name(&_hx509_get_cert(signer)->tbsCertificate.issuer,
1455 &c.tbsCertList.issuer);
1457 hx509_clear_error_string(context);
1461 c.tbsCertList.thisUpdate.element = choice_Time_generalTime;
1462 c.tbsCertList.thisUpdate.u.generalTime = time(NULL) - 24 * 3600;
1464 c.tbsCertList.nextUpdate = malloc(sizeof(*c.tbsCertList.nextUpdate));
1465 if (c.tbsCertList.nextUpdate == NULL) {
1466 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1472 time_t next = crl->expire;
1474 next = time(NULL) + 24 * 3600 * 365;
1476 c.tbsCertList.nextUpdate->element = choice_Time_generalTime;
1477 c.tbsCertList.nextUpdate->u.generalTime = next;
1480 c.tbsCertList.revokedCertificates =
1481 calloc(1, sizeof(*c.tbsCertList.revokedCertificates));
1482 if (c.tbsCertList.revokedCertificates == NULL) {
1483 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1487 c.tbsCertList.crlExtensions = NULL;
1489 ret = hx509_certs_iter(context, crl->revoked, add_revoked, &c.tbsCertList);
1493 /* if not revoked certs, remove OPTIONAL entry */
1494 if (c.tbsCertList.revokedCertificates->len == 0) {
1495 free(c.tbsCertList.revokedCertificates);
1496 c.tbsCertList.revokedCertificates = NULL;
1499 ASN1_MALLOC_ENCODE(TBSCRLCertList, os->data, os->length,
1500 &c.tbsCertList, &size, ret);
1502 hx509_set_error_string(context, 0, ret, "failed to encode tbsCRL");
1505 if (size != os->length)
1506 _hx509_abort("internal ASN.1 encoder error");
1509 ret = _hx509_create_signature_bitstring(context,
1513 &c.signatureAlgorithm,
1517 hx509_set_error_string(context, 0, ret, "Failed to sign CRL");
1521 ASN1_MALLOC_ENCODE(CRLCertificateList, os->data, os->length,
1524 hx509_set_error_string(context, 0, ret, "failed to encode CRL");
1527 if (size != os->length)
1528 _hx509_abort("internal ASN.1 encoder error");
1530 free_CRLCertificateList(&c);
1535 free_CRLCertificateList(&c);