1 /* $NetBSD: revoke.c,v 1.3 2014/04/24 13:45:34 pettai Exp $ */
4 * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * @page page_revoke Revocation methods
39 * There are two revocation method for PKIX/X.509: CRL and OCSP.
40 * Revocation is needed if the private key is lost and
41 * stolen. Depending on how picky you are, you might want to make
42 * revocation for destroyed private keys too (smartcard broken), but
43 * that should not be a problem.
45 * CRL is a list of certifiates that have expired.
47 * OCSP is an online checking method where the requestor sends a list
48 * of certificates to the OCSP server to return a signed reply if they
49 * are valid or not. Some services sends a OCSP reply as part of the
50 * hand-shake to make the revoktion decision simpler/faster for the
59 CRLCertificateList crl
;
67 OCSPBasicOCSPResponse ocsp
;
73 struct hx509_revoke_ctx_data
{
76 struct revoke_crl
*val
;
80 struct revoke_ocsp
*val
;
86 * Allocate a revokation context. Free with hx509_revoke_free().
88 * @param context A hx509 context.
89 * @param ctx returns a newly allocated revokation context.
91 * @return An hx509 error code, see hx509_get_error_string().
93 * @ingroup hx509_revoke
97 hx509_revoke_init(hx509_context context
, hx509_revoke_ctx
*ctx
)
99 *ctx
= calloc(1, sizeof(**ctx
));
104 (*ctx
)->crls
.len
= 0;
105 (*ctx
)->crls
.val
= NULL
;
106 (*ctx
)->ocsps
.len
= 0;
107 (*ctx
)->ocsps
.val
= NULL
;
113 _hx509_revoke_ref(hx509_revoke_ctx ctx
)
118 _hx509_abort("revoke ctx refcount == 0 on ref");
120 if (ctx
->ref
== UINT_MAX
)
121 _hx509_abort("revoke ctx refcount == UINT_MAX on ref");
126 free_ocsp(struct revoke_ocsp
*ocsp
)
129 free_OCSPBasicOCSPResponse(&ocsp
->ocsp
);
130 hx509_certs_free(&ocsp
->certs
);
131 hx509_cert_free(ocsp
->signer
);
135 * Free a hx509 revokation context.
137 * @param ctx context to be freed
139 * @ingroup hx509_revoke
143 hx509_revoke_free(hx509_revoke_ctx
*ctx
)
147 if (ctx
== NULL
|| *ctx
== NULL
)
150 if ((*ctx
)->ref
== 0)
151 _hx509_abort("revoke ctx refcount == 0 on free");
152 if (--(*ctx
)->ref
> 0)
155 for (i
= 0; i
< (*ctx
)->crls
.len
; i
++) {
156 free((*ctx
)->crls
.val
[i
].path
);
157 free_CRLCertificateList(&(*ctx
)->crls
.val
[i
].crl
);
160 for (i
= 0; i
< (*ctx
)->ocsps
.len
; i
++)
161 free_ocsp(&(*ctx
)->ocsps
.val
[i
]);
162 free((*ctx
)->ocsps
.val
);
164 free((*ctx
)->crls
.val
);
166 memset(*ctx
, 0, sizeof(**ctx
));
172 verify_ocsp(hx509_context context
,
173 struct revoke_ocsp
*ocsp
,
178 hx509_cert signer
= NULL
;
182 _hx509_query_clear(&q
);
185 * Need to match on issuer too in case there are two CA that have
186 * issued the same name to a certificate. One example of this is
187 * the www.openvalidation.org test's ocsp validator.
190 q
.match
= HX509_QUERY_MATCH_ISSUER_NAME
;
191 q
.issuer_name
= &_hx509_get_cert(parent
)->tbsCertificate
.issuer
;
193 switch(ocsp
->ocsp
.tbsResponseData
.responderID
.element
) {
194 case choice_OCSPResponderID_byName
:
195 q
.match
|= HX509_QUERY_MATCH_SUBJECT_NAME
;
196 q
.subject_name
= &ocsp
->ocsp
.tbsResponseData
.responderID
.u
.byName
;
198 case choice_OCSPResponderID_byKey
:
199 q
.match
|= HX509_QUERY_MATCH_KEY_HASH_SHA1
;
200 q
.keyhash_sha1
= &ocsp
->ocsp
.tbsResponseData
.responderID
.u
.byKey
;
204 ret
= hx509_certs_find(context
, certs
, &q
, &signer
);
205 if (ret
&& ocsp
->certs
)
206 ret
= hx509_certs_find(context
, ocsp
->certs
, &q
, &signer
);
211 * If signer certificate isn't the CA certificate, lets check the
212 * it is the CA that signed the signer certificate and the OCSP EKU
215 if (hx509_cert_cmp(signer
, parent
) != 0) {
216 Certificate
*p
= _hx509_get_cert(parent
);
217 Certificate
*s
= _hx509_get_cert(signer
);
219 ret
= _hx509_cert_is_parent_cmp(s
, p
, 0);
221 ret
= HX509_PARENT_NOT_CA
;
222 hx509_set_error_string(context
, 0, ret
, "Revoke OCSP signer is "
223 "doesn't have CA as signer certificate");
227 ret
= _hx509_verify_signature_bitstring(context
,
229 &s
->signatureAlgorithm
,
230 &s
->tbsCertificate
._save
,
233 hx509_set_error_string(context
, HX509_ERROR_APPEND
, ret
,
234 "OCSP signer signature invalid");
238 ret
= hx509_cert_check_eku(context
, signer
,
239 &asn1_oid_id_pkix_kp_OCSPSigning
, 0);
244 ret
= _hx509_verify_signature_bitstring(context
,
246 &ocsp
->ocsp
.signatureAlgorithm
,
247 &ocsp
->ocsp
.tbsResponseData
._save
,
248 &ocsp
->ocsp
.signature
);
250 hx509_set_error_string(context
, HX509_ERROR_APPEND
, ret
,
251 "OCSP signature invalid");
255 ocsp
->signer
= signer
;
259 hx509_cert_free(signer
);
269 parse_ocsp_basic(const void *data
, size_t length
, OCSPBasicOCSPResponse
*basic
)
275 memset(basic
, 0, sizeof(*basic
));
277 ret
= decode_OCSPResponse(data
, length
, &resp
, &size
);
280 if (length
!= size
) {
281 free_OCSPResponse(&resp
);
282 return ASN1_EXTRA_DATA
;
285 switch (resp
.responseStatus
) {
289 free_OCSPResponse(&resp
);
290 return HX509_REVOKE_WRONG_DATA
;
293 if (resp
.responseBytes
== NULL
) {
294 free_OCSPResponse(&resp
);
298 ret
= der_heim_oid_cmp(&resp
.responseBytes
->responseType
,
299 &asn1_oid_id_pkix_ocsp_basic
);
301 free_OCSPResponse(&resp
);
302 return HX509_REVOKE_WRONG_DATA
;
305 ret
= decode_OCSPBasicOCSPResponse(resp
.responseBytes
->response
.data
,
306 resp
.responseBytes
->response
.length
,
310 free_OCSPResponse(&resp
);
313 if (size
!= resp
.responseBytes
->response
.length
) {
314 free_OCSPResponse(&resp
);
315 free_OCSPBasicOCSPResponse(basic
);
316 return ASN1_EXTRA_DATA
;
318 free_OCSPResponse(&resp
);
328 load_ocsp(hx509_context context
, struct revoke_ocsp
*ocsp
)
330 OCSPBasicOCSPResponse basic
;
331 hx509_certs certs
= NULL
;
337 ret
= rk_undumpdata(ocsp
->path
, &data
, &length
);
341 ret
= stat(ocsp
->path
, &sb
);
345 ret
= parse_ocsp_basic(data
, length
, &basic
);
348 hx509_set_error_string(context
, 0, ret
,
349 "Failed to parse OCSP response");
356 ret
= hx509_certs_init(context
, "MEMORY:ocsp-certs", 0,
359 free_OCSPBasicOCSPResponse(&basic
);
363 for (i
= 0; i
< basic
.certs
->len
; i
++) {
366 ret
= hx509_cert_init(context
, &basic
.certs
->val
[i
], &c
);
370 ret
= hx509_certs_add(context
, certs
, c
);
377 ocsp
->last_modfied
= sb
.st_mtime
;
379 free_OCSPBasicOCSPResponse(&ocsp
->ocsp
);
380 hx509_certs_free(&ocsp
->certs
);
381 hx509_cert_free(ocsp
->signer
);
391 * Add a OCSP file to the revokation context.
393 * @param context hx509 context
394 * @param ctx hx509 revokation context
395 * @param path path to file that is going to be added to the context.
397 * @return An hx509 error code, see hx509_get_error_string().
399 * @ingroup hx509_revoke
403 hx509_revoke_add_ocsp(hx509_context context
,
404 hx509_revoke_ctx ctx
,
411 if (strncmp(path
, "FILE:", 5) != 0) {
412 hx509_set_error_string(context
, 0, HX509_UNSUPPORTED_OPERATION
,
413 "unsupport type in %s", path
);
414 return HX509_UNSUPPORTED_OPERATION
;
419 for (i
= 0; i
< ctx
->ocsps
.len
; i
++) {
420 if (strcmp(ctx
->ocsps
.val
[0].path
, path
) == 0)
424 data
= realloc(ctx
->ocsps
.val
,
425 (ctx
->ocsps
.len
+ 1) * sizeof(ctx
->ocsps
.val
[0]));
427 hx509_clear_error_string(context
);
431 ctx
->ocsps
.val
= data
;
433 memset(&ctx
->ocsps
.val
[ctx
->ocsps
.len
], 0,
434 sizeof(ctx
->ocsps
.val
[0]));
436 ctx
->ocsps
.val
[ctx
->ocsps
.len
].path
= strdup(path
);
437 if (ctx
->ocsps
.val
[ctx
->ocsps
.len
].path
== NULL
) {
438 hx509_clear_error_string(context
);
442 ret
= load_ocsp(context
, &ctx
->ocsps
.val
[ctx
->ocsps
.len
]);
444 free(ctx
->ocsps
.val
[ctx
->ocsps
.len
].path
);
457 verify_crl(hx509_context context
,
458 hx509_revoke_ctx ctx
,
459 CRLCertificateList
*crl
,
469 t
= _hx509_Time2time_t(&crl
->tbsCertList
.thisUpdate
);
471 hx509_set_error_string(context
, 0, HX509_CRL_USED_BEFORE_TIME
,
472 "CRL used before time");
473 return HX509_CRL_USED_BEFORE_TIME
;
476 if (crl
->tbsCertList
.nextUpdate
== NULL
) {
477 hx509_set_error_string(context
, 0, HX509_CRL_INVALID_FORMAT
,
478 "CRL missing nextUpdate");
479 return HX509_CRL_INVALID_FORMAT
;
482 t
= _hx509_Time2time_t(crl
->tbsCertList
.nextUpdate
);
484 hx509_set_error_string(context
, 0, HX509_CRL_USED_AFTER_TIME
,
485 "CRL used after time");
486 return HX509_CRL_USED_AFTER_TIME
;
489 _hx509_query_clear(&q
);
492 * If it's the signer have CRLSIGN bit set, use that as the signer
493 * cert for the certificate, otherwise, search for a certificate.
495 if (_hx509_check_key_usage(context
, parent
, 1 << 6, FALSE
) == 0) {
496 signer
= hx509_cert_ref(parent
);
498 q
.match
= HX509_QUERY_MATCH_SUBJECT_NAME
;
499 q
.match
|= HX509_QUERY_KU_CRLSIGN
;
500 q
.subject_name
= &crl
->tbsCertList
.issuer
;
502 ret
= hx509_certs_find(context
, certs
, &q
, &signer
);
504 hx509_set_error_string(context
, HX509_ERROR_APPEND
, ret
,
505 "Failed to find certificate for CRL");
510 ret
= _hx509_verify_signature_bitstring(context
,
512 &crl
->signatureAlgorithm
,
513 &crl
->tbsCertList
._save
,
514 &crl
->signatureValue
);
516 hx509_set_error_string(context
, HX509_ERROR_APPEND
, ret
,
517 "CRL signature invalid");
522 * If signer is not CA cert, need to check revoke status of this
523 * CRL signing cert too, this include all parent CRL signer cert
524 * up to the root *sigh*, assume root at least hve CERTSIGN flag
527 while (_hx509_check_key_usage(context
, signer
, 1 << 5, TRUE
)) {
528 hx509_cert crl_parent
;
530 _hx509_query_clear(&q
);
532 q
.match
= HX509_QUERY_MATCH_SUBJECT_NAME
;
533 q
.match
|= HX509_QUERY_KU_CRLSIGN
;
534 q
.subject_name
= &_hx509_get_cert(signer
)->tbsCertificate
.issuer
;
536 ret
= hx509_certs_find(context
, certs
, &q
, &crl_parent
);
538 hx509_set_error_string(context
, HX509_ERROR_APPEND
, ret
,
539 "Failed to find parent of CRL signer");
543 ret
= hx509_revoke_verify(context
,
549 hx509_cert_free(signer
);
552 hx509_set_error_string(context
, HX509_ERROR_APPEND
, ret
,
553 "Failed to verify revoke "
554 "status of CRL signer");
560 hx509_cert_free(signer
);
566 load_crl(const char *path
, time_t *t
, CRLCertificateList
*crl
)
573 memset(crl
, 0, sizeof(*crl
));
575 ret
= rk_undumpdata(path
, &data
, &length
);
579 ret
= stat(path
, &sb
);
585 ret
= decode_CRLCertificateList(data
, length
, crl
, &size
);
590 /* check signature is aligned */
591 if (crl
->signatureValue
.length
& 7) {
592 free_CRLCertificateList(crl
);
593 return HX509_CRYPTO_SIG_INVALID_FORMAT
;
599 * Add a CRL file to the revokation context.
601 * @param context hx509 context
602 * @param ctx hx509 revokation context
603 * @param path path to file that is going to be added to the context.
605 * @return An hx509 error code, see hx509_get_error_string().
607 * @ingroup hx509_revoke
611 hx509_revoke_add_crl(hx509_context context
,
612 hx509_revoke_ctx ctx
,
619 if (strncmp(path
, "FILE:", 5) != 0) {
620 hx509_set_error_string(context
, 0, HX509_UNSUPPORTED_OPERATION
,
621 "unsupport type in %s", path
);
622 return HX509_UNSUPPORTED_OPERATION
;
628 for (i
= 0; i
< ctx
->crls
.len
; i
++) {
629 if (strcmp(ctx
->crls
.val
[i
].path
, path
) == 0)
633 data
= realloc(ctx
->crls
.val
,
634 (ctx
->crls
.len
+ 1) * sizeof(ctx
->crls
.val
[0]));
636 hx509_clear_error_string(context
);
639 ctx
->crls
.val
= data
;
641 memset(&ctx
->crls
.val
[ctx
->crls
.len
], 0, sizeof(ctx
->crls
.val
[0]));
643 ctx
->crls
.val
[ctx
->crls
.len
].path
= strdup(path
);
644 if (ctx
->crls
.val
[ctx
->crls
.len
].path
== NULL
) {
645 hx509_clear_error_string(context
);
650 &ctx
->crls
.val
[ctx
->crls
.len
].last_modfied
,
651 &ctx
->crls
.val
[ctx
->crls
.len
].crl
);
653 free(ctx
->crls
.val
[ctx
->crls
.len
].path
);
663 * Check that a certificate is not expired according to a revokation
664 * context. Also need the parent certificte to the check OCSP
667 * @param context hx509 context
668 * @param ctx hx509 revokation context
674 * @return An hx509 error code, see hx509_get_error_string().
676 * @ingroup hx509_revoke
681 hx509_revoke_verify(hx509_context context
,
682 hx509_revoke_ctx ctx
,
686 hx509_cert parent_cert
)
688 const Certificate
*c
= _hx509_get_cert(cert
);
689 const Certificate
*p
= _hx509_get_cert(parent_cert
);
690 unsigned long i
, j
, k
;
693 hx509_clear_error_string(context
);
695 for (i
= 0; i
< ctx
->ocsps
.len
; i
++) {
696 struct revoke_ocsp
*ocsp
= &ctx
->ocsps
.val
[i
];
699 /* check this ocsp apply to this cert */
701 /* check if there is a newer version of the file */
702 ret
= stat(ocsp
->path
, &sb
);
703 if (ret
== 0 && ocsp
->last_modfied
!= sb
.st_mtime
) {
704 ret
= load_ocsp(context
, ocsp
);
709 /* verify signature in ocsp if not already done */
710 if (ocsp
->signer
== NULL
) {
711 ret
= verify_ocsp(context
, ocsp
, now
, certs
, parent_cert
);
716 for (j
= 0; j
< ocsp
->ocsp
.tbsResponseData
.responses
.len
; j
++) {
717 heim_octet_string os
;
719 ret
= der_heim_integer_cmp(&ocsp
->ocsp
.tbsResponseData
.responses
.val
[j
].certID
.serialNumber
,
720 &c
->tbsCertificate
.serialNumber
);
724 /* verify issuer hashes hash */
725 ret
= _hx509_verify_signature(context
,
727 &ocsp
->ocsp
.tbsResponseData
.responses
.val
[i
].certID
.hashAlgorithm
,
728 &c
->tbsCertificate
.issuer
._save
,
729 &ocsp
->ocsp
.tbsResponseData
.responses
.val
[i
].certID
.issuerNameHash
);
733 os
.data
= p
->tbsCertificate
.subjectPublicKeyInfo
.subjectPublicKey
.data
;
734 os
.length
= p
->tbsCertificate
.subjectPublicKeyInfo
.subjectPublicKey
.length
/ 8;
736 ret
= _hx509_verify_signature(context
,
738 &ocsp
->ocsp
.tbsResponseData
.responses
.val
[j
].certID
.hashAlgorithm
,
740 &ocsp
->ocsp
.tbsResponseData
.responses
.val
[j
].certID
.issuerKeyHash
);
744 switch (ocsp
->ocsp
.tbsResponseData
.responses
.val
[j
].certStatus
.element
) {
745 case choice_OCSPCertStatus_good
:
747 case choice_OCSPCertStatus_revoked
:
748 hx509_set_error_string(context
, 0,
750 "Certificate revoked by issuer in OCSP");
751 return HX509_CERT_REVOKED
;
752 case choice_OCSPCertStatus_unknown
:
756 /* don't allow the update to be in the future */
757 if (ocsp
->ocsp
.tbsResponseData
.responses
.val
[j
].thisUpdate
>
758 now
+ context
->ocsp_time_diff
)
761 /* don't allow the next update to be in the past */
762 if (ocsp
->ocsp
.tbsResponseData
.responses
.val
[j
].nextUpdate
) {
763 if (*ocsp
->ocsp
.tbsResponseData
.responses
.val
[j
].nextUpdate
< now
)
765 } /* else should force a refetch, but can we ? */
771 for (i
= 0; i
< ctx
->crls
.len
; i
++) {
772 struct revoke_crl
*crl
= &ctx
->crls
.val
[i
];
776 /* check if cert.issuer == crls.val[i].crl.issuer */
777 ret
= _hx509_name_cmp(&c
->tbsCertificate
.issuer
,
778 &crl
->crl
.tbsCertList
.issuer
, &diff
);
782 ret
= stat(crl
->path
, &sb
);
783 if (ret
== 0 && crl
->last_modfied
!= sb
.st_mtime
) {
784 CRLCertificateList cl
;
786 ret
= load_crl(crl
->path
, &crl
->last_modfied
, &cl
);
788 free_CRLCertificateList(&crl
->crl
);
791 crl
->failed_verify
= 0;
794 if (crl
->failed_verify
)
797 /* verify signature in crl if not already done */
798 if (crl
->verified
== 0) {
799 ret
= verify_crl(context
, ctx
, &crl
->crl
, now
, certs
, parent_cert
);
801 crl
->failed_verify
= 1;
807 if (crl
->crl
.tbsCertList
.crlExtensions
) {
808 for (j
= 0; j
< crl
->crl
.tbsCertList
.crlExtensions
->len
; j
++) {
809 if (crl
->crl
.tbsCertList
.crlExtensions
->val
[j
].critical
) {
810 hx509_set_error_string(context
, 0,
811 HX509_CRL_UNKNOWN_EXTENSION
,
812 "Unknown CRL extension");
813 return HX509_CRL_UNKNOWN_EXTENSION
;
818 if (crl
->crl
.tbsCertList
.revokedCertificates
== NULL
)
821 /* check if cert is in crl */
822 for (j
= 0; j
< crl
->crl
.tbsCertList
.revokedCertificates
->len
; j
++) {
825 ret
= der_heim_integer_cmp(&crl
->crl
.tbsCertList
.revokedCertificates
->val
[j
].userCertificate
,
826 &c
->tbsCertificate
.serialNumber
);
830 t
= _hx509_Time2time_t(&crl
->crl
.tbsCertList
.revokedCertificates
->val
[j
].revocationDate
);
834 if (crl
->crl
.tbsCertList
.revokedCertificates
->val
[j
].crlEntryExtensions
)
835 for (k
= 0; k
< crl
->crl
.tbsCertList
.revokedCertificates
->val
[j
].crlEntryExtensions
->len
; k
++)
836 if (crl
->crl
.tbsCertList
.revokedCertificates
->val
[j
].crlEntryExtensions
->val
[k
].critical
)
837 return HX509_CRL_UNKNOWN_EXTENSION
;
839 hx509_set_error_string(context
, 0,
841 "Certificate revoked by issuer in CRL");
842 return HX509_CERT_REVOKED
;
849 if (context
->flags
& HX509_CTX_VERIFY_MISSING_OK
)
851 hx509_set_error_string(context
, HX509_ERROR_APPEND
,
852 HX509_REVOKE_STATUS_MISSING
,
853 "No revoke status found for "
855 return HX509_REVOKE_STATUS_MISSING
;
858 struct ocsp_add_ctx
{
861 const AlgorithmIdentifier
*digest
;
866 add_to_req(hx509_context context
, void *ptr
, hx509_cert cert
)
868 struct ocsp_add_ctx
*ctx
= ptr
;
869 OCSPInnerRequest
*one
;
870 hx509_cert parent
= NULL
;
871 Certificate
*p
, *c
= _hx509_get_cert(cert
);
872 heim_octet_string os
;
877 d
= realloc(ctx
->req
->requestList
.val
,
878 sizeof(ctx
->req
->requestList
.val
[0]) *
879 (ctx
->req
->requestList
.len
+ 1));
882 ctx
->req
->requestList
.val
= d
;
884 one
= &ctx
->req
->requestList
.val
[ctx
->req
->requestList
.len
];
885 memset(one
, 0, sizeof(*one
));
887 _hx509_query_clear(&q
);
889 q
.match
|= HX509_QUERY_FIND_ISSUER_CERT
;
892 ret
= hx509_certs_find(context
, ctx
->certs
, &q
, &parent
);
897 if (hx509_cert_cmp(ctx
->parent
, parent
) != 0) {
898 ret
= HX509_REVOKE_NOT_SAME_PARENT
;
899 hx509_set_error_string(context
, 0, ret
,
900 "Not same parent certifate as "
901 "last certificate in request");
905 ctx
->parent
= hx509_cert_ref(parent
);
907 p
= _hx509_get_cert(parent
);
909 ret
= copy_AlgorithmIdentifier(ctx
->digest
, &one
->reqCert
.hashAlgorithm
);
913 ret
= _hx509_create_signature(context
,
915 &one
->reqCert
.hashAlgorithm
,
916 &c
->tbsCertificate
.issuer
._save
,
918 &one
->reqCert
.issuerNameHash
);
922 os
.data
= p
->tbsCertificate
.subjectPublicKeyInfo
.subjectPublicKey
.data
;
924 p
->tbsCertificate
.subjectPublicKeyInfo
.subjectPublicKey
.length
/ 8;
926 ret
= _hx509_create_signature(context
,
928 &one
->reqCert
.hashAlgorithm
,
931 &one
->reqCert
.issuerKeyHash
);
935 ret
= copy_CertificateSerialNumber(&c
->tbsCertificate
.serialNumber
,
936 &one
->reqCert
.serialNumber
);
940 ctx
->req
->requestList
.len
++;
942 hx509_cert_free(parent
);
944 free_OCSPInnerRequest(one
);
945 memset(one
, 0, sizeof(*one
));
952 * Create an OCSP request for a set of certificates.
954 * @param context a hx509 context
955 * @param reqcerts list of certificates to request ocsp data for
956 * @param pool certificate pool to use when signing
957 * @param signer certificate to use to sign the request
958 * @param digest the signing algorithm in the request, if NULL use the
959 * default signature algorithm,
960 * @param request the encoded request, free with free_heim_octet_string().
961 * @param nonce nonce in the request, free with free_heim_octet_string().
963 * @return An hx509 error code, see hx509_get_error_string().
965 * @ingroup hx509_revoke
969 hx509_ocsp_request(hx509_context context
,
970 hx509_certs reqcerts
,
973 const AlgorithmIdentifier
*digest
,
974 heim_octet_string
*request
,
975 heim_octet_string
*nonce
)
980 struct ocsp_add_ctx ctx
;
983 memset(&req
, 0, sizeof(req
));
986 digest
= _hx509_crypto_default_digest_alg
;
988 ctx
.req
= &req
.tbsRequest
;
993 ret
= hx509_certs_iter_f(context
, reqcerts
, add_to_req
, &ctx
);
994 hx509_cert_free(ctx
.parent
);
999 req
.tbsRequest
.requestExtensions
=
1000 calloc(1, sizeof(*req
.tbsRequest
.requestExtensions
));
1001 if (req
.tbsRequest
.requestExtensions
== NULL
) {
1006 es
= req
.tbsRequest
.requestExtensions
;
1008 es
->val
= calloc(es
->len
, sizeof(es
->val
[0]));
1009 if (es
->val
== NULL
) {
1014 ret
= der_copy_oid(&asn1_oid_id_pkix_ocsp_nonce
, &es
->val
[0].extnID
);
1016 free_OCSPRequest(&req
);
1020 es
->val
[0].extnValue
.data
= malloc(10);
1021 if (es
->val
[0].extnValue
.data
== NULL
) {
1025 es
->val
[0].extnValue
.length
= 10;
1027 ret
= RAND_bytes(es
->val
[0].extnValue
.data
,
1028 es
->val
[0].extnValue
.length
);
1030 ret
= HX509_CRYPTO_INTERNAL_ERROR
;
1033 ret
= der_copy_octet_string(nonce
, &es
->val
[0].extnValue
);
1040 ASN1_MALLOC_ENCODE(OCSPRequest
, request
->data
, request
->length
,
1042 free_OCSPRequest(&req
);
1045 if (size
!= request
->length
)
1046 _hx509_abort("internal ASN.1 encoder error");
1051 free_OCSPRequest(&req
);
1056 printable_time(time_t t
)
1060 if ((p
= ctime(&t
)) == NULL
)
1061 strlcpy(s
, "?", sizeof(s
));
1063 strlcpy(s
, p
+ 4, sizeof(s
));
1070 * Print the OCSP reply stored in a file.
1072 * @param context a hx509 context
1073 * @param path path to a file with a OCSP reply
1074 * @param out the out FILE descriptor to print the reply on
1076 * @return An hx509 error code, see hx509_get_error_string().
1078 * @ingroup hx509_revoke
1082 hx509_revoke_ocsp_print(hx509_context context
, const char *path
, FILE *out
)
1084 struct revoke_ocsp ocsp
;
1091 memset(&ocsp
, 0, sizeof(ocsp
));
1093 ocsp
.path
= strdup(path
);
1094 if (ocsp
.path
== NULL
)
1097 ret
= load_ocsp(context
, &ocsp
);
1103 fprintf(out
, "signer: ");
1105 switch(ocsp
.ocsp
.tbsResponseData
.responderID
.element
) {
1106 case choice_OCSPResponderID_byName
: {
1109 _hx509_name_from_Name(&ocsp
.ocsp
.tbsResponseData
.responderID
.u
.byName
, &n
);
1110 hx509_name_to_string(n
, &s
);
1111 hx509_name_free(&n
);
1112 fprintf(out
, " byName: %s\n", s
);
1116 case choice_OCSPResponderID_byKey
: {
1118 hex_encode(ocsp
.ocsp
.tbsResponseData
.responderID
.u
.byKey
.data
,
1119 ocsp
.ocsp
.tbsResponseData
.responderID
.u
.byKey
.length
,
1121 fprintf(out
, " byKey: %s\n", s
);
1126 _hx509_abort("choice_OCSPResponderID unknown");
1130 fprintf(out
, "producedAt: %s\n",
1131 printable_time(ocsp
.ocsp
.tbsResponseData
.producedAt
));
1133 fprintf(out
, "replies: %d\n", ocsp
.ocsp
.tbsResponseData
.responses
.len
);
1135 for (i
= 0; i
< ocsp
.ocsp
.tbsResponseData
.responses
.len
; i
++) {
1137 switch (ocsp
.ocsp
.tbsResponseData
.responses
.val
[i
].certStatus
.element
) {
1138 case choice_OCSPCertStatus_good
:
1141 case choice_OCSPCertStatus_revoked
:
1144 case choice_OCSPCertStatus_unknown
:
1148 status
= "element unknown";
1151 fprintf(out
, "\t%zu. status: %s\n", i
, status
);
1153 fprintf(out
, "\tthisUpdate: %s\n",
1154 printable_time(ocsp
.ocsp
.tbsResponseData
.responses
.val
[i
].thisUpdate
));
1155 if (ocsp
.ocsp
.tbsResponseData
.responses
.val
[i
].nextUpdate
)
1156 fprintf(out
, "\tproducedAt: %s\n",
1157 printable_time(ocsp
.ocsp
.tbsResponseData
.responses
.val
[i
].thisUpdate
));
1161 fprintf(out
, "appended certs:\n");
1163 ret
= hx509_certs_iter_f(context
, ocsp
.certs
, hx509_ci_print_names
, out
);
1170 * Verify that the certificate is part of the OCSP reply and it's not
1171 * expired. Doesn't verify signature the OCSP reply or it's done by a
1172 * authorized sender, that is assumed to be already done.
1174 * @param context a hx509 context
1175 * @param now the time right now, if 0, use the current time.
1176 * @param cert the certificate to verify
1177 * @param flags flags control the behavior
1178 * @param data pointer to the encode ocsp reply
1179 * @param length the length of the encode ocsp reply
1180 * @param expiration return the time the OCSP will expire and need to
1183 * @return An hx509 error code, see hx509_get_error_string().
1185 * @ingroup hx509_verify
1189 hx509_ocsp_verify(hx509_context context
,
1193 const void *data
, size_t length
,
1196 const Certificate
*c
= _hx509_get_cert(cert
);
1197 OCSPBasicOCSPResponse basic
;
1206 ret
= parse_ocsp_basic(data
, length
, &basic
);
1208 hx509_set_error_string(context
, 0, ret
,
1209 "Failed to parse OCSP response");
1213 for (i
= 0; i
< basic
.tbsResponseData
.responses
.len
; i
++) {
1215 ret
= der_heim_integer_cmp(&basic
.tbsResponseData
.responses
.val
[i
].certID
.serialNumber
,
1216 &c
->tbsCertificate
.serialNumber
);
1220 /* verify issuer hashes hash */
1221 ret
= _hx509_verify_signature(context
,
1223 &basic
.tbsResponseData
.responses
.val
[i
].certID
.hashAlgorithm
,
1224 &c
->tbsCertificate
.issuer
._save
,
1225 &basic
.tbsResponseData
.responses
.val
[i
].certID
.issuerNameHash
);
1229 switch (basic
.tbsResponseData
.responses
.val
[i
].certStatus
.element
) {
1230 case choice_OCSPCertStatus_good
:
1232 case choice_OCSPCertStatus_revoked
:
1233 case choice_OCSPCertStatus_unknown
:
1237 /* don't allow the update to be in the future */
1238 if (basic
.tbsResponseData
.responses
.val
[i
].thisUpdate
>
1239 now
+ context
->ocsp_time_diff
)
1242 /* don't allow the next update to be in the past */
1243 if (basic
.tbsResponseData
.responses
.val
[i
].nextUpdate
) {
1244 if (*basic
.tbsResponseData
.responses
.val
[i
].nextUpdate
< now
)
1246 *expiration
= *basic
.tbsResponseData
.responses
.val
[i
].nextUpdate
;
1250 free_OCSPBasicOCSPResponse(&basic
);
1254 free_OCSPBasicOCSPResponse(&basic
);
1260 ret
= hx509_cert_get_subject(cert
, &name
);
1262 hx509_clear_error_string(context
);
1265 ret
= hx509_name_to_string(name
, &subject
);
1266 hx509_name_free(&name
);
1268 hx509_clear_error_string(context
);
1271 hx509_set_error_string(context
, 0, HX509_CERT_NOT_IN_OCSP
,
1272 "Certificate %s not in OCSP response "
1278 return HX509_CERT_NOT_IN_OCSP
;
1282 hx509_certs revoked
;
1287 * Create a CRL context. Use hx509_crl_free() to free the CRL context.
1289 * @param context a hx509 context.
1290 * @param crl return pointer to a newly allocated CRL context.
1292 * @return An hx509 error code, see hx509_get_error_string().
1294 * @ingroup hx509_verify
1298 hx509_crl_alloc(hx509_context context
, hx509_crl
*crl
)
1302 *crl
= calloc(1, sizeof(**crl
));
1304 hx509_set_error_string(context
, 0, ENOMEM
, "out of memory");
1308 ret
= hx509_certs_init(context
, "MEMORY:crl", 0, NULL
, &(*crl
)->revoked
);
1319 * Add revoked certificate to an CRL context.
1321 * @param context a hx509 context.
1322 * @param crl the CRL to add the revoked certificate to.
1323 * @param certs keyset of certificate to revoke.
1325 * @return An hx509 error code, see hx509_get_error_string().
1327 * @ingroup hx509_verify
1331 hx509_crl_add_revoked_certs(hx509_context context
,
1335 return hx509_certs_merge(context
, crl
->revoked
, certs
);
1339 * Set the lifetime of a CRL context.
1341 * @param context a hx509 context.
1342 * @param crl a CRL context
1343 * @param delta delta time the certificate is valid, library adds the
1344 * current time to this.
1346 * @return An hx509 error code, see hx509_get_error_string().
1348 * @ingroup hx509_verify
1352 hx509_crl_lifetime(hx509_context context
, hx509_crl crl
, int delta
)
1354 crl
->expire
= time(NULL
) + delta
;
1359 * Free a CRL context.
1361 * @param context a hx509 context.
1362 * @param crl a CRL context to free.
1364 * @ingroup hx509_verify
1368 hx509_crl_free(hx509_context context
, hx509_crl
*crl
)
1372 hx509_certs_free(&(*crl
)->revoked
);
1373 memset(*crl
, 0, sizeof(**crl
));
1379 add_revoked(hx509_context context
, void *ctx
, hx509_cert cert
)
1381 TBSCRLCertList
*c
= ctx
;
1386 num
= c
->revokedCertificates
->len
;
1387 ptr
= realloc(c
->revokedCertificates
->val
,
1388 (num
+ 1) * sizeof(c
->revokedCertificates
->val
[0]));
1390 hx509_clear_error_string(context
);
1393 c
->revokedCertificates
->val
= ptr
;
1395 ret
= hx509_cert_get_serialnumber(cert
,
1396 &c
->revokedCertificates
->val
[num
].userCertificate
);
1398 hx509_clear_error_string(context
);
1401 c
->revokedCertificates
->val
[num
].revocationDate
.element
=
1402 choice_Time_generalTime
;
1403 c
->revokedCertificates
->val
[num
].revocationDate
.u
.generalTime
=
1404 time(NULL
) - 3600 * 24;
1405 c
->revokedCertificates
->val
[num
].crlEntryExtensions
= NULL
;
1407 c
->revokedCertificates
->len
++;
1413 * Sign a CRL and return an encode certificate.
1415 * @param context a hx509 context.
1416 * @param signer certificate to sign the CRL with
1417 * @param crl the CRL to sign
1418 * @param os return the signed and encoded CRL, free with
1419 * free_heim_octet_string()
1421 * @return An hx509 error code, see hx509_get_error_string().
1423 * @ingroup hx509_verify
1427 hx509_crl_sign(hx509_context context
,
1430 heim_octet_string
*os
)
1432 const AlgorithmIdentifier
*sigalg
= _hx509_crypto_default_sig_alg
;
1433 CRLCertificateList c
;
1436 hx509_private_key signerkey
;
1438 memset(&c
, 0, sizeof(c
));
1440 signerkey
= _hx509_cert_private_key(signer
);
1441 if (signerkey
== NULL
) {
1442 ret
= HX509_PRIVATE_KEY_MISSING
;
1443 hx509_set_error_string(context
, 0, ret
,
1444 "Private key missing for CRL signing");
1448 c
.tbsCertList
.version
= malloc(sizeof(*c
.tbsCertList
.version
));
1449 if (c
.tbsCertList
.version
== NULL
) {
1450 hx509_set_error_string(context
, 0, ENOMEM
, "out of memory");
1454 *c
.tbsCertList
.version
= 1;
1456 ret
= copy_AlgorithmIdentifier(sigalg
, &c
.tbsCertList
.signature
);
1458 hx509_clear_error_string(context
);
1462 ret
= copy_Name(&_hx509_get_cert(signer
)->tbsCertificate
.issuer
,
1463 &c
.tbsCertList
.issuer
);
1465 hx509_clear_error_string(context
);
1469 c
.tbsCertList
.thisUpdate
.element
= choice_Time_generalTime
;
1470 c
.tbsCertList
.thisUpdate
.u
.generalTime
= time(NULL
) - 24 * 3600;
1472 c
.tbsCertList
.nextUpdate
= malloc(sizeof(*c
.tbsCertList
.nextUpdate
));
1473 if (c
.tbsCertList
.nextUpdate
== NULL
) {
1474 hx509_set_error_string(context
, 0, ENOMEM
, "out of memory");
1480 time_t next
= crl
->expire
;
1482 next
= time(NULL
) + 24 * 3600 * 365;
1484 c
.tbsCertList
.nextUpdate
->element
= choice_Time_generalTime
;
1485 c
.tbsCertList
.nextUpdate
->u
.generalTime
= next
;
1488 c
.tbsCertList
.revokedCertificates
=
1489 calloc(1, sizeof(*c
.tbsCertList
.revokedCertificates
));
1490 if (c
.tbsCertList
.revokedCertificates
== NULL
) {
1491 hx509_set_error_string(context
, 0, ENOMEM
, "out of memory");
1495 c
.tbsCertList
.crlExtensions
= NULL
;
1497 ret
= hx509_certs_iter_f(context
, crl
->revoked
, add_revoked
, &c
.tbsCertList
);
1501 /* if not revoked certs, remove OPTIONAL entry */
1502 if (c
.tbsCertList
.revokedCertificates
->len
== 0) {
1503 free(c
.tbsCertList
.revokedCertificates
);
1504 c
.tbsCertList
.revokedCertificates
= NULL
;
1507 ASN1_MALLOC_ENCODE(TBSCRLCertList
, os
->data
, os
->length
,
1508 &c
.tbsCertList
, &size
, ret
);
1510 hx509_set_error_string(context
, 0, ret
, "failed to encode tbsCRL");
1513 if (size
!= os
->length
)
1514 _hx509_abort("internal ASN.1 encoder error");
1517 ret
= _hx509_create_signature_bitstring(context
,
1521 &c
.signatureAlgorithm
,
1525 hx509_set_error_string(context
, 0, ret
, "Failed to sign CRL");
1529 ASN1_MALLOC_ENCODE(CRLCertificateList
, os
->data
, os
->length
,
1532 hx509_set_error_string(context
, 0, ret
, "failed to encode CRL");
1535 if (size
!= os
->length
)
1536 _hx509_abort("internal ASN.1 encoder error");
1538 free_CRLCertificateList(&c
);
1543 free_CRLCertificateList(&c
);