2 * Copyright (c) 2004 - 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
36 #include "crypto-headers.h"
39 struct hx509_verify_ctx_data
{
40 hx509_certs trust_anchors
;
42 #define HX509_VERIFY_CTX_F_TIME_SET 1
43 #define HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE 2
44 #define HX509_VERIFY_CTX_F_REQUIRE_RFC3280 4
45 #define HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS 8
46 #define HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS 16
48 unsigned int max_depth
;
49 #define HX509_VERIFY_MAX_DEPTH 30
50 hx509_revoke_ctx revoke_ctx
;
53 #define REQUIRE_RFC3280(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_REQUIRE_RFC3280)
54 #define CHECK_TA(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS)
55 #define ALLOW_DEF_TA(ctx) (((ctx)->flags & HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS) == 0)
57 struct _hx509_cert_attrs
{
59 hx509_cert_attribute
*val
;
62 struct hx509_cert_data
{
66 hx509_private_key private_key
;
67 struct _hx509_cert_attrs attrs
;
69 _hx509_cert_release_func release
;
73 typedef struct hx509_name_constraints
{
76 } hx509_name_constraints
;
78 #define GeneralSubtrees_SET(g,var) \
79 (g)->len = (var)->len, (g)->val = (var)->val;
82 * Creates a hx509 context that most functions in the library
83 * uses. The context is only allowed to be used by one thread at each
84 * moment. Free the context with hx509_context_free().
86 * @param context Returns a pointer to new hx509 context.
88 * @return Returns an hx509 error code.
94 hx509_context_init(hx509_context
*context
)
96 *context
= calloc(1, sizeof(**context
));
100 _hx509_ks_null_register(*context
);
101 _hx509_ks_mem_register(*context
);
102 _hx509_ks_file_register(*context
);
103 _hx509_ks_pkcs12_register(*context
);
104 _hx509_ks_pkcs11_register(*context
);
105 _hx509_ks_dir_register(*context
);
106 _hx509_ks_keychain_register(*context
);
108 ENGINE_add_conf_module();
109 OpenSSL_add_all_algorithms();
111 (*context
)->ocsp_time_diff
= HX509_DEFAULT_OCSP_TIME_DIFF
;
113 initialize_hx_error_table_r(&(*context
)->et_list
);
114 initialize_asn1_error_table_r(&(*context
)->et_list
);
116 #ifdef HX509_DEFAULT_ANCHORS
117 (void)hx509_certs_init(*context
, HX509_DEFAULT_ANCHORS
, 0,
118 NULL
, &(*context
)->default_trust_anchors
);
125 * Selects if the hx509_revoke_verify() function is going to require
126 * the existans of a revokation method (OSCP, CRL) or not. Note that
127 * hx509_verify_path(), hx509_cms_verify_signed(), and other function
128 * call hx509_revoke_verify().
130 * @param context hx509 context to change the flag for.
131 * @param flag zero, revokation method required, non zero missing
132 * revokation method ok
134 * @ingroup hx509_verify
138 hx509_context_set_missing_revoke(hx509_context context
, int flag
)
141 context
->flags
|= HX509_CTX_VERIFY_MISSING_OK
;
143 context
->flags
&= ~HX509_CTX_VERIFY_MISSING_OK
;
147 * Free the context allocated by hx509_context_init().
149 * @param context context to be freed.
155 hx509_context_free(hx509_context
*context
)
157 hx509_clear_error_string(*context
);
158 if ((*context
)->ks_ops
) {
159 free((*context
)->ks_ops
);
160 (*context
)->ks_ops
= NULL
;
162 (*context
)->ks_num_ops
= 0;
163 free_error_table ((*context
)->et_list
);
164 if ((*context
)->querystat
)
165 free((*context
)->querystat
);
166 memset(*context
, 0, sizeof(**context
));
176 _hx509_get_cert(hx509_cert cert
)
187 _hx509_print_cert_subject(hx509_cert cert
)
193 ret
= hx509_cert_get_subject(cert
, &name
);
197 ret
= hx509_name_to_string(name
, &subject_name
);
198 hx509_name_free(&name
);
202 printf("name: %s\n", subject_name
);
213 _hx509_cert_get_version(const Certificate
*t
)
215 return t
->tbsCertificate
.version
? *t
->tbsCertificate
.version
+ 1 : 1;
219 * Allocate and init an hx509 certificate object from the decoded
222 * @param context A hx509 context.
226 * @return Returns an hx509 error code.
228 * @ingroup hx509_cert
232 hx509_cert_init(hx509_context context
, const Certificate
*c
, hx509_cert
*cert
)
236 *cert
= malloc(sizeof(**cert
));
240 (*cert
)->friendlyname
= NULL
;
241 (*cert
)->attrs
.len
= 0;
242 (*cert
)->attrs
.val
= NULL
;
243 (*cert
)->private_key
= NULL
;
244 (*cert
)->basename
= NULL
;
245 (*cert
)->release
= NULL
;
248 (*cert
)->data
= calloc(1, sizeof(*(*cert
)->data
));
249 if ((*cert
)->data
== NULL
) {
253 ret
= copy_Certificate(c
, (*cert
)->data
);
263 * Just like hx509_cert_init(), but instead of a decode certificate
264 * takes an pointer and length to a memory region that contains a
265 * DER/BER encoded certificate.
267 * If the memory region doesn't contain just the certificate and
268 * nothing more the function will fail with
269 * HX509_EXTRA_DATA_AFTER_STRUCTURE.
271 * @param context A hx509 context.
272 * @param ptr pointer to memory region containing encoded certificate.
273 * @param len length of memory region.
274 * @param cert a return pointer to a hx509 certificate object, will
275 * contain NULL on error.
277 * @return An hx509 error code, see hx509_get_error_string().
279 * @ingroup hx509_cert
283 hx509_cert_init_data(hx509_context context
,
292 ret
= decode_Certificate(ptr
, len
, &t
, &size
);
294 hx509_set_error_string(context
, 0, ret
, "Failed to decode certificate");
298 hx509_set_error_string(context
, 0, HX509_EXTRA_DATA_AFTER_STRUCTURE
,
299 "Extra data after certificate");
300 return HX509_EXTRA_DATA_AFTER_STRUCTURE
;
303 ret
= hx509_cert_init(context
, &t
, cert
);
304 free_Certificate(&t
);
309 _hx509_cert_set_release(hx509_cert cert
,
310 _hx509_cert_release_func release
,
313 cert
->release
= release
;
318 /* Doesn't make a copy of `private_key'. */
321 _hx509_cert_assign_key(hx509_cert cert
, hx509_private_key private_key
)
323 if (cert
->private_key
)
324 _hx509_private_key_free(&cert
->private_key
);
325 cert
->private_key
= _hx509_private_key_ref(private_key
);
330 * Free reference to the hx509 certificate object, if the refcounter
331 * reaches 0, the object if freed. Its allowed to pass in NULL.
333 * @param cert the cert to free.
335 * @ingroup hx509_cert
339 hx509_cert_free(hx509_cert cert
)
347 _hx509_abort("cert refcount <= 0 on free");
352 (cert
->release
)(cert
, cert
->ctx
);
354 if (cert
->private_key
)
355 _hx509_private_key_free(&cert
->private_key
);
357 free_Certificate(cert
->data
);
360 for (i
= 0; i
< cert
->attrs
.len
; i
++) {
361 der_free_octet_string(&cert
->attrs
.val
[i
]->data
);
362 der_free_oid(&cert
->attrs
.val
[i
]->oid
);
363 free(cert
->attrs
.val
[i
]);
365 free(cert
->attrs
.val
);
366 free(cert
->friendlyname
);
368 hx509_name_free(&cert
->basename
);
369 memset(cert
, 0, sizeof(cert
));
374 * Add a reference to a hx509 certificate object.
376 * @param cert a pointer to an hx509 certificate object.
378 * @return the same object as is passed in.
380 * @ingroup hx509_cert
384 hx509_cert_ref(hx509_cert cert
)
387 _hx509_abort("cert refcount <= 0");
390 _hx509_abort("cert refcount == 0");
395 * Allocate an verification context that is used fo control the
396 * verification process.
398 * @param context A hx509 context.
399 * @param ctx returns a pointer to a hx509_verify_ctx object.
401 * @return An hx509 error code, see hx509_get_error_string().
403 * @ingroup hx509_verify
407 hx509_verify_init_ctx(hx509_context context
, hx509_verify_ctx
*ctx
)
411 c
= calloc(1, sizeof(*c
));
415 c
->max_depth
= HX509_VERIFY_MAX_DEPTH
;
423 * Free an hx509 verification context.
425 * @param ctx the context to be freed.
427 * @ingroup hx509_verify
431 hx509_verify_destroy_ctx(hx509_verify_ctx ctx
)
434 hx509_certs_free(&ctx
->trust_anchors
);
435 hx509_revoke_free(&ctx
->revoke_ctx
);
436 memset(ctx
, 0, sizeof(*ctx
));
442 * Set the trust anchors in the verification context, makes an
443 * reference to the keyset, so the consumer can free the keyset
444 * independent of the destruction of the verification context (ctx).
446 * @param ctx a verification context
447 * @param set a keyset containing the trust anchors.
449 * @ingroup hx509_verify
453 hx509_verify_attach_anchors(hx509_verify_ctx ctx
, hx509_certs set
)
455 ctx
->trust_anchors
= _hx509_certs_ref(set
);
459 * Attach an revocation context to the verfication context, , makes an
460 * reference to the revoke context, so the consumer can free the
461 * revoke context independent of the destruction of the verification
462 * context. If there is no revoke context, the verification process is
463 * NOT going to check any verification status.
465 * @param ctx a verification context.
466 * @param revoke_ctx a revoke context.
468 * @ingroup hx509_verify
472 hx509_verify_attach_revoke(hx509_verify_ctx ctx
, hx509_revoke_ctx revoke_ctx
)
474 ctx
->revoke_ctx
= _hx509_revoke_ref(revoke_ctx
);
478 * Set the clock time the the verification process is going to
479 * use. Used to check certificate in the past and future time. If not
480 * set the current time will be used.
482 * @param ctx a verification context.
483 * @param t the time the verifiation is using.
486 * @ingroup hx509_verify
490 hx509_verify_set_time(hx509_verify_ctx ctx
, time_t t
)
492 ctx
->flags
|= HX509_VERIFY_CTX_F_TIME_SET
;
497 * Set the maximum depth of the certificate chain that the path
498 * builder is going to try.
500 * @param ctx a verification context
501 * @param max_depth maxium depth of the certificate chain, include
504 * @ingroup hx509_verify
508 hx509_verify_set_max_depth(hx509_verify_ctx ctx
, unsigned int max_depth
)
510 ctx
->max_depth
= max_depth
;
514 * Allow or deny the use of proxy certificates
516 * @param ctx a verification context
517 * @param boolean if non zero, allow proxy certificates.
519 * @ingroup hx509_verify
523 hx509_verify_set_proxy_certificate(hx509_verify_ctx ctx
, int boolean
)
526 ctx
->flags
|= HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE
;
528 ctx
->flags
&= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE
;
532 * Select strict RFC3280 verification of certificiates. This means
533 * checking key usage on CA certificates, this will make version 1
534 * certificiates unuseable.
536 * @param ctx a verification context
537 * @param boolean if non zero, use strict verification.
539 * @ingroup hx509_verify
543 hx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx
, int boolean
)
546 ctx
->flags
|= HX509_VERIFY_CTX_F_REQUIRE_RFC3280
;
548 ctx
->flags
&= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280
;
552 * Allow using the operating system builtin trust anchors if no other
553 * trust anchors are configured.
555 * @param ctx a verification context
556 * @param boolean if non zero, useing the operating systems builtin
560 * @return An hx509 error code, see hx509_get_error_string().
562 * @ingroup hx509_cert
566 hx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx
, int boolean
)
569 ctx
->flags
&= ~HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS
;
571 ctx
->flags
|= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS
;
574 static const Extension
*
575 find_extension(const Certificate
*cert
, const heim_oid
*oid
, int *idx
)
577 const TBSCertificate
*c
= &cert
->tbsCertificate
;
579 if (c
->version
== NULL
|| *c
->version
< 2 || c
->extensions
== NULL
)
582 for (;*idx
< c
->extensions
->len
; (*idx
)++) {
583 if (der_heim_oid_cmp(&c
->extensions
->val
[*idx
].extnID
, oid
) == 0)
584 return &c
->extensions
->val
[(*idx
)++];
590 find_extension_auth_key_id(const Certificate
*subject
,
591 AuthorityKeyIdentifier
*ai
)
597 memset(ai
, 0, sizeof(*ai
));
599 e
= find_extension(subject
, oid_id_x509_ce_authorityKeyIdentifier(), &i
);
601 return HX509_EXTENSION_NOT_FOUND
;
603 return decode_AuthorityKeyIdentifier(e
->extnValue
.data
,
609 _hx509_find_extension_subject_key_id(const Certificate
*issuer
,
610 SubjectKeyIdentifier
*si
)
616 memset(si
, 0, sizeof(*si
));
618 e
= find_extension(issuer
, oid_id_x509_ce_subjectKeyIdentifier(), &i
);
620 return HX509_EXTENSION_NOT_FOUND
;
622 return decode_SubjectKeyIdentifier(e
->extnValue
.data
,
628 find_extension_name_constraints(const Certificate
*subject
,
635 memset(nc
, 0, sizeof(*nc
));
637 e
= find_extension(subject
, oid_id_x509_ce_nameConstraints(), &i
);
639 return HX509_EXTENSION_NOT_FOUND
;
641 return decode_NameConstraints(e
->extnValue
.data
,
647 find_extension_subject_alt_name(const Certificate
*cert
, int *i
,
653 memset(sa
, 0, sizeof(*sa
));
655 e
= find_extension(cert
, oid_id_x509_ce_subjectAltName(), i
);
657 return HX509_EXTENSION_NOT_FOUND
;
659 return decode_GeneralNames(e
->extnValue
.data
,
665 find_extension_eku(const Certificate
*cert
, ExtKeyUsage
*eku
)
671 memset(eku
, 0, sizeof(*eku
));
673 e
= find_extension(cert
, oid_id_x509_ce_extKeyUsage(), &i
);
675 return HX509_EXTENSION_NOT_FOUND
;
677 return decode_ExtKeyUsage(e
->extnValue
.data
,
683 add_to_list(hx509_octet_string_list
*list
, const heim_octet_string
*entry
)
688 p
= realloc(list
->val
, (list
->len
+ 1) * sizeof(list
->val
[0]));
692 ret
= der_copy_octet_string(entry
, &list
->val
[list
->len
]);
700 * Free a list of octet strings returned by another hx509 library
703 * @param list list to be freed.
705 * @ingroup hx509_misc
709 hx509_free_octet_string_list(hx509_octet_string_list
*list
)
712 for (i
= 0; i
< list
->len
; i
++)
713 der_free_octet_string(&list
->val
[i
]);
720 * Return a list of subjectAltNames specified by oid in the
721 * certificate. On error the
723 * The returned list of octet string should be freed with
724 * hx509_free_octet_string_list().
726 * @param context A hx509 context.
727 * @param cert a hx509 certificate object.
728 * @param oid an oid to for SubjectAltName.
729 * @param list list of matching SubjectAltName.
731 * @return An hx509 error code, see hx509_get_error_string().
733 * @ingroup hx509_cert
737 hx509_cert_find_subjectAltName_otherName(hx509_context context
,
740 hx509_octet_string_list
*list
)
750 ret
= find_extension_subject_alt_name(_hx509_get_cert(cert
), &i
, &sa
);
752 if (ret
== HX509_EXTENSION_NOT_FOUND
) {
755 } else if (ret
!= 0) {
756 hx509_set_error_string(context
, 0, ret
, "Error searching for SAN");
757 hx509_free_octet_string_list(list
);
761 for (j
= 0; j
< sa
.len
; j
++) {
762 if (sa
.val
[j
].element
== choice_GeneralName_otherName
&&
763 der_heim_oid_cmp(&sa
.val
[j
].u
.otherName
.type_id
, oid
) == 0)
765 ret
= add_to_list(list
, &sa
.val
[j
].u
.otherName
.value
);
767 hx509_set_error_string(context
, 0, ret
,
768 "Error adding an exra SAN to "
770 hx509_free_octet_string_list(list
);
771 free_GeneralNames(&sa
);
776 free_GeneralNames(&sa
);
783 check_key_usage(hx509_context context
, const Certificate
*cert
,
784 unsigned flags
, int req_present
)
792 if (_hx509_cert_get_version(cert
) < 3)
795 e
= find_extension(cert
, oid_id_x509_ce_keyUsage(), &i
);
798 hx509_set_error_string(context
, 0, HX509_KU_CERT_MISSING
,
799 "Required extension key "
800 "usage missing from certifiate");
801 return HX509_KU_CERT_MISSING
;
806 ret
= decode_KeyUsage(e
->extnValue
.data
, e
->extnValue
.length
, &ku
, &size
);
809 ku_flags
= KeyUsage2int(ku
);
810 if ((ku_flags
& flags
) != flags
) {
811 unsigned missing
= (~ku_flags
) & flags
;
812 char buf
[256], *name
;
814 unparse_flags(missing
, asn1_KeyUsage_units(), buf
, sizeof(buf
));
815 _hx509_unparse_Name(&cert
->tbsCertificate
.subject
, &name
);
816 hx509_set_error_string(context
, 0, HX509_KU_CERT_MISSING
,
817 "Key usage %s required but missing "
818 "from certifiate %s", buf
, name
);
820 return HX509_KU_CERT_MISSING
;
826 * Return 0 on matching key usage 'flags' for 'cert', otherwise return
827 * an error code. If 'req_present' the existance is required of the
828 * KeyUsage extension.
832 _hx509_check_key_usage(hx509_context context
, hx509_cert cert
,
833 unsigned flags
, int req_present
)
835 return check_key_usage(context
, _hx509_get_cert(cert
), flags
, req_present
);
838 enum certtype
{ PROXY_CERT
, EE_CERT
, CA_CERT
};
841 check_basic_constraints(hx509_context context
, const Certificate
*cert
,
842 enum certtype type
, int depth
)
849 if (_hx509_cert_get_version(cert
) < 3)
852 e
= find_extension(cert
, oid_id_x509_ce_basicConstraints(), &i
);
860 ret
= _hx509_unparse_Name(&cert
->tbsCertificate
.subject
, &name
);
862 hx509_set_error_string(context
, 0, HX509_EXTENSION_NOT_FOUND
,
863 "basicConstraints missing from "
864 "CA certifiacte %s", name
);
866 return HX509_EXTENSION_NOT_FOUND
;
871 ret
= decode_BasicConstraints(e
->extnValue
.data
,
872 e
->extnValue
.length
, &bc
,
878 if (bc
.cA
!= NULL
&& *bc
.cA
)
879 ret
= HX509_PARENT_IS_CA
;
885 if (bc
.cA
== NULL
|| !*bc
.cA
)
886 ret
= HX509_PARENT_NOT_CA
;
887 else if (bc
.pathLenConstraint
)
888 if (depth
- 1 > *bc
.pathLenConstraint
)
889 ret
= HX509_CA_PATH_TOO_DEEP
;
892 free_BasicConstraints(&bc
);
897 _hx509_cert_is_parent_cmp(const Certificate
*subject
,
898 const Certificate
*issuer
,
899 int allow_self_signed
)
902 AuthorityKeyIdentifier ai
;
903 SubjectKeyIdentifier si
;
906 diff
= _hx509_name_cmp(&issuer
->tbsCertificate
.subject
,
907 &subject
->tbsCertificate
.issuer
);
911 memset(&ai
, 0, sizeof(ai
));
912 memset(&si
, 0, sizeof(si
));
915 * Try to find AuthorityKeyIdentifier, if it's not present in the
916 * subject certificate nor the parent.
919 ret_ai
= find_extension_auth_key_id(subject
, &ai
);
920 if (ret_ai
&& ret_ai
!= HX509_EXTENSION_NOT_FOUND
)
922 ret_si
= _hx509_find_extension_subject_key_id(issuer
, &si
);
923 if (ret_si
&& ret_si
!= HX509_EXTENSION_NOT_FOUND
)
926 if (ret_si
&& ret_ai
)
931 if (allow_self_signed
) {
934 } else if (ai
.keyIdentifier
) {
940 if (ai
.keyIdentifier
== NULL
) {
943 if (ai
.authorityCertIssuer
== NULL
)
945 if (ai
.authorityCertSerialNumber
== NULL
)
948 diff
= der_heim_integer_cmp(ai
.authorityCertSerialNumber
,
949 &issuer
->tbsCertificate
.serialNumber
);
952 if (ai
.authorityCertIssuer
->len
!= 1)
954 if (ai
.authorityCertIssuer
->val
[0].element
!= choice_GeneralName_directoryName
)
958 ai
.authorityCertIssuer
->val
[0].u
.directoryName
.element
;
960 ai
.authorityCertIssuer
->val
[0].u
.directoryName
.u
.rdnSequence
;
962 diff
= _hx509_name_cmp(&issuer
->tbsCertificate
.subject
,
968 diff
= der_heim_octet_string_cmp(ai
.keyIdentifier
, &si
);
973 free_AuthorityKeyIdentifier(&ai
);
974 free_SubjectKeyIdentifier(&si
);
979 certificate_is_anchor(hx509_context context
,
980 hx509_certs trust_anchors
,
981 const hx509_cert cert
)
987 if (trust_anchors
== NULL
)
990 _hx509_query_clear(&q
);
992 q
.match
= HX509_QUERY_MATCH_CERTIFICATE
;
993 q
.certificate
= _hx509_get_cert(cert
);
995 ret
= hx509_certs_find(context
, trust_anchors
, &q
, &c
);
1002 certificate_is_self_signed(const Certificate
*cert
)
1004 return _hx509_name_cmp(&cert
->tbsCertificate
.subject
,
1005 &cert
->tbsCertificate
.issuer
) == 0;
1009 * The subjectName is "null" when it's empty set of relative DBs.
1013 subject_null_p(const Certificate
*c
)
1015 return c
->tbsCertificate
.subject
.u
.rdnSequence
.len
== 0;
1020 find_parent(hx509_context context
,
1022 hx509_certs trust_anchors
,
1028 AuthorityKeyIdentifier ai
;
1033 memset(&ai
, 0, sizeof(ai
));
1035 _hx509_query_clear(&q
);
1037 if (!subject_null_p(current
->data
)) {
1038 q
.match
|= HX509_QUERY_FIND_ISSUER_CERT
;
1039 q
.subject
= _hx509_get_cert(current
);
1041 ret
= find_extension_auth_key_id(current
->data
, &ai
);
1043 hx509_set_error_string(context
, 0, HX509_CERTIFICATE_MALFORMED
,
1044 "Subjectless certificate missing AuthKeyID");
1045 return HX509_CERTIFICATE_MALFORMED
;
1048 if (ai
.keyIdentifier
== NULL
) {
1049 free_AuthorityKeyIdentifier(&ai
);
1050 hx509_set_error_string(context
, 0, HX509_CERTIFICATE_MALFORMED
,
1051 "Subjectless certificate missing keyIdentifier "
1052 "inside AuthKeyID");
1053 return HX509_CERTIFICATE_MALFORMED
;
1056 q
.subject_id
= ai
.keyIdentifier
;
1057 q
.match
= HX509_QUERY_MATCH_SUBJECT_KEY_ID
;
1061 q
.match
|= HX509_QUERY_NO_MATCH_PATH
;
1064 q
.timenow
= time_now
;
1065 q
.match
|= HX509_QUERY_MATCH_TIME
;
1067 ret
= hx509_certs_find(context
, pool
, &q
, parent
);
1069 free_AuthorityKeyIdentifier(&ai
);
1072 q
.match
&= ~HX509_QUERY_MATCH_TIME
;
1075 if (trust_anchors
) {
1076 ret
= hx509_certs_find(context
, trust_anchors
, &q
, parent
);
1078 free_AuthorityKeyIdentifier(&ai
);
1082 free_AuthorityKeyIdentifier(&ai
);
1088 ret
= hx509_cert_get_subject(current
, &name
);
1090 hx509_clear_error_string(context
);
1091 return HX509_ISSUER_NOT_FOUND
;
1093 ret
= hx509_name_to_string(name
, &str
);
1094 hx509_name_free(&name
);
1096 hx509_clear_error_string(context
);
1097 return HX509_ISSUER_NOT_FOUND
;
1100 hx509_set_error_string(context
, 0, HX509_ISSUER_NOT_FOUND
,
1101 "Failed to find issuer for "
1102 "certificate with subject: '%s'", str
);
1105 return HX509_ISSUER_NOT_FOUND
;
1113 is_proxy_cert(hx509_context context
,
1114 const Certificate
*cert
,
1115 ProxyCertInfo
*rinfo
)
1123 memset(rinfo
, 0, sizeof(*rinfo
));
1125 e
= find_extension(cert
, oid_id_pkix_pe_proxyCertInfo(), &i
);
1127 hx509_clear_error_string(context
);
1128 return HX509_EXTENSION_NOT_FOUND
;
1131 ret
= decode_ProxyCertInfo(e
->extnValue
.data
,
1132 e
->extnValue
.length
,
1136 hx509_clear_error_string(context
);
1139 if (size
!= e
->extnValue
.length
) {
1140 free_ProxyCertInfo(&info
);
1141 hx509_clear_error_string(context
);
1142 return HX509_EXTRA_DATA_AFTER_STRUCTURE
;
1145 free_ProxyCertInfo(&info
);
1153 * Path operations are like MEMORY based keyset, but with exposed
1154 * internal so we can do easy searches.
1158 _hx509_path_append(hx509_context context
, hx509_path
*path
, hx509_cert cert
)
1161 val
= realloc(path
->val
, (path
->len
+ 1) * sizeof(path
->val
[0]));
1163 hx509_set_error_string(context
, 0, ENOMEM
, "out of memory");
1168 path
->val
[path
->len
] = hx509_cert_ref(cert
);
1175 _hx509_path_free(hx509_path
*path
)
1179 for (i
= 0; i
< path
->len
; i
++)
1180 hx509_cert_free(path
->val
[i
]);
1187 * Find path by looking up issuer for the top certificate and continue
1188 * until an anchor certificate is found or max limit is found. A
1189 * certificate never included twice in the path.
1191 * If the trust anchors are not given, calculate optimistic path, just
1192 * follow the chain upward until we no longer find a parent or we hit
1193 * the max path limit. In this case, a failure will always be returned
1194 * depending on what error condition is hit first.
1196 * The path includes a path from the top certificate to the anchor
1199 * The caller needs to free `path´ both on successful built path and
1204 _hx509_calculate_path(hx509_context context
,
1207 hx509_certs anchors
,
1208 unsigned int max_depth
,
1213 hx509_cert parent
, current
;
1217 max_depth
= HX509_VERIFY_MAX_DEPTH
;
1219 ret
= _hx509_path_append(context
, path
, cert
);
1223 current
= hx509_cert_ref(cert
);
1225 while (!certificate_is_anchor(context
, anchors
, current
)) {
1227 ret
= find_parent(context
, time_now
, anchors
, path
,
1228 pool
, current
, &parent
);
1229 hx509_cert_free(current
);
1233 ret
= _hx509_path_append(context
, path
, parent
);
1238 if (path
->len
> max_depth
) {
1239 hx509_cert_free(current
);
1240 hx509_set_error_string(context
, 0, HX509_PATH_TOO_LONG
,
1241 "Path too long while bulding "
1242 "certificate chain");
1243 return HX509_PATH_TOO_LONG
;
1247 if ((flags
& HX509_CALCULATE_PATH_NO_ANCHOR
) &&
1249 certificate_is_anchor(context
, anchors
, path
->val
[path
->len
- 1]))
1251 hx509_cert_free(path
->val
[path
->len
- 1]);
1255 hx509_cert_free(current
);
1260 AlgorithmIdentifier_cmp(const AlgorithmIdentifier
*p
,
1261 const AlgorithmIdentifier
*q
)
1264 diff
= der_heim_oid_cmp(&p
->algorithm
, &q
->algorithm
);
1267 if (p
->parameters
) {
1269 return heim_any_cmp(p
->parameters
,
1282 _hx509_Certificate_cmp(const Certificate
*p
, const Certificate
*q
)
1285 diff
= der_heim_bit_string_cmp(&p
->signatureValue
, &q
->signatureValue
);
1288 diff
= AlgorithmIdentifier_cmp(&p
->signatureAlgorithm
,
1289 &q
->signatureAlgorithm
);
1292 diff
= der_heim_octet_string_cmp(&p
->tbsCertificate
._save
,
1293 &q
->tbsCertificate
._save
);
1298 * Compare to hx509 certificate object, useful for sorting.
1300 * @param p a hx509 certificate object.
1301 * @param q a hx509 certificate object.
1303 * @return 0 the objects are the same, returns > 0 is p is "larger"
1304 * then q, < 0 if p is "smaller" then q.
1306 * @ingroup hx509_cert
1310 hx509_cert_cmp(hx509_cert p
, hx509_cert q
)
1312 return _hx509_Certificate_cmp(p
->data
, q
->data
);
1316 * Return the name of the issuer of the hx509 certificate.
1318 * @param p a hx509 certificate object.
1319 * @param name a pointer to a hx509 name, should be freed by
1320 * hx509_name_free().
1322 * @return An hx509 error code, see hx509_get_error_string().
1324 * @ingroup hx509_cert
1328 hx509_cert_get_issuer(hx509_cert p
, hx509_name
*name
)
1330 return _hx509_name_from_Name(&p
->data
->tbsCertificate
.issuer
, name
);
1334 * Return the name of the subject of the hx509 certificate.
1336 * @param p a hx509 certificate object.
1337 * @param name a pointer to a hx509 name, should be freed by
1338 * hx509_name_free(). See also hx509_cert_get_base_subject().
1340 * @return An hx509 error code, see hx509_get_error_string().
1342 * @ingroup hx509_cert
1346 hx509_cert_get_subject(hx509_cert p
, hx509_name
*name
)
1348 return _hx509_name_from_Name(&p
->data
->tbsCertificate
.subject
, name
);
1352 * Return the name of the base subject of the hx509 certificate. If
1353 * the certiicate is a verified proxy certificate, the this function
1354 * return the base certificate (root of the proxy chain). If the proxy
1355 * certificate is not verified with the base certificate
1356 * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned.
1358 * @param context a hx509 context.
1359 * @param c a hx509 certificate object.
1360 * @param name a pointer to a hx509 name, should be freed by
1361 * hx509_name_free(). See also hx509_cert_get_subject().
1363 * @return An hx509 error code, see hx509_get_error_string().
1365 * @ingroup hx509_cert
1369 hx509_cert_get_base_subject(hx509_context context
, hx509_cert c
,
1373 return hx509_name_copy(context
, c
->basename
, name
);
1374 if (is_proxy_cert(context
, c
->data
, NULL
) == 0) {
1375 int ret
= HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED
;
1376 hx509_set_error_string(context
, 0, ret
,
1377 "Proxy certificate have not been "
1378 "canonicalize yet, no base name");
1381 return _hx509_name_from_Name(&c
->data
->tbsCertificate
.subject
, name
);
1385 * Get serial number of the certificate.
1387 * @param p a hx509 certificate object.
1388 * @param i serial number, should be freed ith der_free_heim_integer().
1390 * @return An hx509 error code, see hx509_get_error_string().
1392 * @ingroup hx509_cert
1396 hx509_cert_get_serialnumber(hx509_cert p
, heim_integer
*i
)
1398 return der_copy_heim_integer(&p
->data
->tbsCertificate
.serialNumber
, i
);
1402 * Get notBefore time of the certificate.
1404 * @param p a hx509 certificate object.
1406 * @return return not before time
1408 * @ingroup hx509_cert
1412 hx509_cert_get_notBefore(hx509_cert p
)
1414 return _hx509_Time2time_t(&p
->data
->tbsCertificate
.validity
.notBefore
);
1418 * Get notAfter time of the certificate.
1420 * @param p a hx509 certificate object.
1422 * @return return not after time.
1424 * @ingroup hx509_cert
1428 hx509_cert_get_notAfter(hx509_cert p
)
1430 return _hx509_Time2time_t(&p
->data
->tbsCertificate
.validity
.notAfter
);
1434 * Get the SubjectPublicKeyInfo structure from the hx509 certificate.
1436 * @param p a hx509 certificate object.
1437 * @param spki SubjectPublicKeyInfo, should be freed with
1438 * free_SubjectPublicKeyInfo().
1440 * @return An hx509 error code, see hx509_get_error_string().
1442 * @ingroup hx509_cert
1446 hx509_cert_get_SPKI(hx509_cert p
, SubjectPublicKeyInfo
*spki
)
1448 return copy_SubjectPublicKeyInfo(&p
->data
->tbsCertificate
.subjectPublicKeyInfo
,
1453 _hx509_cert_private_key(hx509_cert p
)
1455 return p
->private_key
;
1459 _hx509_cert_private_key_exportable(hx509_cert p
)
1461 if (p
->private_key
== NULL
)
1463 return _hx509_private_key_exportable(p
->private_key
);
1467 _hx509_cert_private_decrypt(hx509_context context
,
1468 const heim_octet_string
*ciphertext
,
1469 const heim_oid
*encryption_oid
,
1471 heim_octet_string
*cleartext
)
1473 cleartext
->data
= NULL
;
1474 cleartext
->length
= 0;
1476 if (p
->private_key
== NULL
) {
1477 hx509_set_error_string(context
, 0, HX509_PRIVATE_KEY_MISSING
,
1478 "Private key missing");
1479 return HX509_PRIVATE_KEY_MISSING
;
1482 return _hx509_private_key_private_decrypt(context
,
1490 _hx509_cert_public_encrypt(hx509_context context
,
1491 const heim_octet_string
*cleartext
,
1493 heim_oid
*encryption_oid
,
1494 heim_octet_string
*ciphertext
)
1496 return _hx509_public_encrypt(context
,
1498 encryption_oid
, ciphertext
);
1506 _hx509_Time2time_t(const Time
*t
)
1508 switch(t
->element
) {
1509 case choice_Time_utcTime
:
1510 return t
->u
.utcTime
;
1511 case choice_Time_generalTime
:
1512 return t
->u
.generalTime
;
1522 init_name_constraints(hx509_name_constraints
*nc
)
1524 memset(nc
, 0, sizeof(*nc
));
1529 add_name_constraints(hx509_context context
, const Certificate
*c
, int not_ca
,
1530 hx509_name_constraints
*nc
)
1532 NameConstraints tnc
;
1535 ret
= find_extension_name_constraints(c
, &tnc
);
1536 if (ret
== HX509_EXTENSION_NOT_FOUND
)
1539 hx509_set_error_string(context
, 0, ret
, "Failed getting NameConstraints");
1541 } else if (not_ca
) {
1542 ret
= HX509_VERIFY_CONSTRAINTS
;
1543 hx509_set_error_string(context
, 0, ret
, "Not a CA and "
1544 "have NameConstraints");
1546 NameConstraints
*val
;
1547 val
= realloc(nc
->val
, sizeof(nc
->val
[0]) * (nc
->len
+ 1));
1549 hx509_clear_error_string(context
);
1554 ret
= copy_NameConstraints(&tnc
, &nc
->val
[nc
->len
]);
1556 hx509_clear_error_string(context
);
1562 free_NameConstraints(&tnc
);
1567 match_RDN(const RelativeDistinguishedName
*c
,
1568 const RelativeDistinguishedName
*n
)
1572 if (c
->len
!= n
->len
)
1573 return HX509_NAME_CONSTRAINT_ERROR
;
1575 for (i
= 0; i
< n
->len
; i
++) {
1576 if (der_heim_oid_cmp(&c
->val
[i
].type
, &n
->val
[i
].type
) != 0)
1577 return HX509_NAME_CONSTRAINT_ERROR
;
1578 if (_hx509_name_ds_cmp(&c
->val
[i
].value
, &n
->val
[i
].value
) != 0)
1579 return HX509_NAME_CONSTRAINT_ERROR
;
1585 match_X501Name(const Name
*c
, const Name
*n
)
1589 if (c
->element
!= choice_Name_rdnSequence
1590 || n
->element
!= choice_Name_rdnSequence
)
1592 if (c
->u
.rdnSequence
.len
> n
->u
.rdnSequence
.len
)
1593 return HX509_NAME_CONSTRAINT_ERROR
;
1594 for (i
= 0; i
< c
->u
.rdnSequence
.len
; i
++) {
1595 ret
= match_RDN(&c
->u
.rdnSequence
.val
[i
], &n
->u
.rdnSequence
.val
[i
]);
1604 match_general_name(const GeneralName
*c
, const GeneralName
*n
, int *match
)
1607 * Name constraints only apply to the same name type, see RFC3280,
1610 assert(c
->element
== n
->element
);
1612 switch(c
->element
) {
1613 case choice_GeneralName_otherName
:
1614 if (der_heim_oid_cmp(&c
->u
.otherName
.type_id
,
1615 &n
->u
.otherName
.type_id
) != 0)
1616 return HX509_NAME_CONSTRAINT_ERROR
;
1617 if (heim_any_cmp(&c
->u
.otherName
.value
,
1618 &n
->u
.otherName
.value
) != 0)
1619 return HX509_NAME_CONSTRAINT_ERROR
;
1622 case choice_GeneralName_rfc822Name
: {
1625 s
= strchr(c
->u
.rfc822Name
, '@');
1627 if (strcasecmp(c
->u
.rfc822Name
, n
->u
.rfc822Name
) != 0)
1628 return HX509_NAME_CONSTRAINT_ERROR
;
1630 s
= strchr(n
->u
.rfc822Name
, '@');
1632 return HX509_NAME_CONSTRAINT_ERROR
;
1633 len1
= strlen(c
->u
.rfc822Name
);
1634 len2
= strlen(s
+ 1);
1636 return HX509_NAME_CONSTRAINT_ERROR
;
1637 if (strcasecmp(s
+ 1 + len2
- len1
, c
->u
.rfc822Name
) != 0)
1638 return HX509_NAME_CONSTRAINT_ERROR
;
1639 if (len1
< len2
&& s
[len2
- len1
+ 1] != '.')
1640 return HX509_NAME_CONSTRAINT_ERROR
;
1645 case choice_GeneralName_dNSName
: {
1648 lenc
= strlen(c
->u
.dNSName
);
1649 lenn
= strlen(n
->u
.dNSName
);
1651 return HX509_NAME_CONSTRAINT_ERROR
;
1652 if (strcasecmp(&n
->u
.dNSName
[lenn
- lenc
], c
->u
.dNSName
) != 0)
1653 return HX509_NAME_CONSTRAINT_ERROR
;
1654 if (lenc
!= lenn
&& n
->u
.dNSName
[lenn
- lenc
- 1] != '.')
1655 return HX509_NAME_CONSTRAINT_ERROR
;
1659 case choice_GeneralName_directoryName
: {
1660 Name c_name
, n_name
;
1663 c_name
._save
.data
= NULL
;
1664 c_name
._save
.length
= 0;
1665 c_name
.element
= c
->u
.directoryName
.element
;
1666 c_name
.u
.rdnSequence
= c
->u
.directoryName
.u
.rdnSequence
;
1668 n_name
._save
.data
= NULL
;
1669 n_name
._save
.length
= 0;
1670 n_name
.element
= n
->u
.directoryName
.element
;
1671 n_name
.u
.rdnSequence
= n
->u
.directoryName
.u
.rdnSequence
;
1673 ret
= match_X501Name(&c_name
, &n_name
);
1678 case choice_GeneralName_uniformResourceIdentifier
:
1679 case choice_GeneralName_iPAddress
:
1680 case choice_GeneralName_registeredID
:
1682 return HX509_NAME_CONSTRAINT_ERROR
;
1687 match_alt_name(const GeneralName
*n
, const Certificate
*c
,
1688 int *same
, int *match
)
1695 ret
= find_extension_subject_alt_name(c
, &i
, &sa
);
1696 if (ret
== HX509_EXTENSION_NOT_FOUND
) {
1699 } else if (ret
!= 0)
1702 for (j
= 0; j
< sa
.len
; j
++) {
1703 if (n
->element
== sa
.val
[j
].element
) {
1705 ret
= match_general_name(n
, &sa
.val
[j
], match
);
1708 free_GeneralNames(&sa
);
1715 match_tree(const GeneralSubtrees
*t
, const Certificate
*c
, int *match
)
1717 int name
, alt_name
, same
;
1721 name
= alt_name
= same
= *match
= 0;
1722 for (i
= 0; i
< t
->len
; i
++) {
1723 if (t
->val
[i
].minimum
&& t
->val
[i
].maximum
)
1727 * If the constraint apply to directoryNames, test is with
1728 * subjectName of the certificate if the certificate have a
1729 * non-null (empty) subjectName.
1732 if (t
->val
[i
].base
.element
== choice_GeneralName_directoryName
1733 && !subject_null_p(c
))
1735 GeneralName certname
;
1737 memset(&certname
, 0, sizeof(certname
));
1738 certname
.element
= choice_GeneralName_directoryName
;
1739 certname
.u
.directoryName
.element
=
1740 c
->tbsCertificate
.subject
.element
;
1741 certname
.u
.directoryName
.u
.rdnSequence
=
1742 c
->tbsCertificate
.subject
.u
.rdnSequence
;
1744 ret
= match_general_name(&t
->val
[i
].base
, &certname
, &name
);
1747 /* Handle subjectAltNames, this is icky since they
1748 * restrictions only apply if the subjectAltName is of the
1749 * same type. So if there have been a match of type, require
1750 * altname to be set.
1752 ret
= match_alt_name(&t
->val
[i
].base
, c
, &same
, &alt_name
);
1754 if (name
&& (!same
|| alt_name
))
1760 check_name_constraints(hx509_context context
,
1761 const hx509_name_constraints
*nc
,
1762 const Certificate
*c
)
1767 for (i
= 0 ; i
< nc
->len
; i
++) {
1770 if (nc
->val
[i
].permittedSubtrees
) {
1771 GeneralSubtrees_SET(&gs
, nc
->val
[i
].permittedSubtrees
);
1772 ret
= match_tree(&gs
, c
, &match
);
1774 hx509_clear_error_string(context
);
1777 /* allow null subjectNames, they wont matches anything */
1778 if (match
== 0 && !subject_null_p(c
)) {
1779 hx509_set_error_string(context
, 0, HX509_VERIFY_CONSTRAINTS
,
1780 "Error verify constraints, "
1781 "certificate didn't match any "
1782 "permitted subtree");
1783 return HX509_VERIFY_CONSTRAINTS
;
1786 if (nc
->val
[i
].excludedSubtrees
) {
1787 GeneralSubtrees_SET(&gs
, nc
->val
[i
].excludedSubtrees
);
1788 ret
= match_tree(&gs
, c
, &match
);
1790 hx509_clear_error_string(context
);
1794 hx509_set_error_string(context
, 0, HX509_VERIFY_CONSTRAINTS
,
1795 "Error verify constraints, "
1796 "certificate included in excluded "
1798 return HX509_VERIFY_CONSTRAINTS
;
1806 free_name_constraints(hx509_name_constraints
*nc
)
1810 for (i
= 0 ; i
< nc
->len
; i
++)
1811 free_NameConstraints(&nc
->val
[i
]);
1816 * Build and verify the path for the certificate to the trust anchor
1817 * specified in the verify context. The path is constructed from the
1818 * certificate, the pool and the trust anchors.
1820 * @param context A hx509 context.
1821 * @param ctx A hx509 verification context.
1822 * @param cert the certificate to build the path from.
1823 * @param pool A keyset of certificates to build the chain from.
1825 * @return An hx509 error code, see hx509_get_error_string().
1827 * @ingroup hx509_verify
1831 hx509_verify_path(hx509_context context
,
1832 hx509_verify_ctx ctx
,
1836 hx509_name_constraints nc
;
1839 const AlgorithmIdentifier
*alg_id
;
1841 int ret
, i
, proxy_cert_depth
, selfsigned_depth
;
1844 hx509_certs anchors
= NULL
;
1846 memset(&proxy_issuer
, 0, sizeof(proxy_issuer
));
1848 ret
= init_name_constraints(&nc
);
1855 if ((ctx
->flags
& HX509_VERIFY_CTX_F_TIME_SET
) == 0)
1856 ctx
->time_now
= time(NULL
);
1861 if (ctx
->trust_anchors
)
1862 anchors
= _hx509_certs_ref(ctx
->trust_anchors
);
1863 else if (context
->default_trust_anchors
&& ALLOW_DEF_TA(ctx
))
1864 anchors
= _hx509_certs_ref(context
->default_trust_anchors
);
1866 ret
= hx509_certs_init(context
, "MEMORY:no-TA", 0, NULL
, &anchors
);
1872 * Calculate the path from the certificate user presented to the
1875 ret
= _hx509_calculate_path(context
, 0, ctx
->time_now
,
1876 anchors
, ctx
->max_depth
,
1882 alg_id
= path
.val
[path
->len
- 1]->data
->tbsCertificate
.signature
;
1886 * Check CA and proxy certificate chain from the top of the
1887 * certificate chain. Also check certificate is valid with respect
1888 * to the current time.
1892 proxy_cert_depth
= 0;
1893 selfsigned_depth
= 0;
1895 if (ctx
->flags
& HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE
)
1900 for (i
= 0; i
< path
.len
; i
++) {
1904 c
= _hx509_get_cert(path
.val
[i
]);
1907 * Lets do some basic check on issuer like
1908 * keyUsage.keyCertSign and basicConstraints.cA bit depending
1909 * on what type of certificate this is.
1914 /* XXX make constants for keyusage */
1915 ret
= check_key_usage(context
, c
, 1 << 5,
1916 REQUIRE_RFC3280(ctx
) ? TRUE
: FALSE
);
1918 hx509_set_error_string(context
, HX509_ERROR_APPEND
, ret
,
1919 "Key usage missing from CA certificate");
1923 if (i
+ 1 != path
.len
&& certificate_is_self_signed(c
))
1930 if (is_proxy_cert(context
, c
, &info
) == 0) {
1933 if (info
.pCPathLenConstraint
!= NULL
&&
1934 *info
.pCPathLenConstraint
< i
)
1936 free_ProxyCertInfo(&info
);
1937 ret
= HX509_PATH_TOO_LONG
;
1938 hx509_set_error_string(context
, 0, ret
,
1939 "Proxy certificate chain "
1940 "longer then allowed");
1943 /* XXX MUST check info.proxyPolicy */
1944 free_ProxyCertInfo(&info
);
1947 if (find_extension(c
, oid_id_x509_ce_subjectAltName(), &j
)) {
1948 ret
= HX509_PROXY_CERT_INVALID
;
1949 hx509_set_error_string(context
, 0, ret
,
1950 "Proxy certificate have explicity "
1951 "forbidden subjectAltName");
1956 if (find_extension(c
, oid_id_x509_ce_issuerAltName(), &j
)) {
1957 ret
= HX509_PROXY_CERT_INVALID
;
1958 hx509_set_error_string(context
, 0, ret
,
1959 "Proxy certificate have explicity "
1960 "forbidden issuerAltName");
1965 * The subject name of the proxy certificate should be
1966 * CN=XXX,<proxy issuer>, prune of CN and check if its
1967 * the same over the whole chain of proxy certs and
1968 * then check with the EE cert when we get to it.
1971 if (proxy_cert_depth
) {
1972 ret
= _hx509_name_cmp(&proxy_issuer
, &c
->tbsCertificate
.subject
);
1974 ret
= HX509_PROXY_CERT_NAME_WRONG
;
1975 hx509_set_error_string(context
, 0, ret
,
1976 "Base proxy name not right");
1981 free_Name(&proxy_issuer
);
1983 ret
= copy_Name(&c
->tbsCertificate
.subject
, &proxy_issuer
);
1985 hx509_clear_error_string(context
);
1989 j
= proxy_issuer
.u
.rdnSequence
.len
;
1990 if (proxy_issuer
.u
.rdnSequence
.len
< 2
1991 || proxy_issuer
.u
.rdnSequence
.val
[j
- 1].len
> 1
1992 || der_heim_oid_cmp(&proxy_issuer
.u
.rdnSequence
.val
[j
- 1].val
[0].type
,
1993 oid_id_at_commonName()))
1995 ret
= HX509_PROXY_CERT_NAME_WRONG
;
1996 hx509_set_error_string(context
, 0, ret
,
1997 "Proxy name too short or "
1998 "does not have Common name "
2003 free_RelativeDistinguishedName(&proxy_issuer
.u
.rdnSequence
.val
[j
- 1]);
2004 proxy_issuer
.u
.rdnSequence
.len
-= 1;
2006 ret
= _hx509_name_cmp(&proxy_issuer
, &c
->tbsCertificate
.issuer
);
2008 ret
= HX509_PROXY_CERT_NAME_WRONG
;
2009 hx509_set_error_string(context
, 0, ret
,
2010 "Proxy issuer name not as expected");
2017 * Now we are done with the proxy certificates, this
2018 * cert was an EE cert and we we will fall though to
2019 * EE checking below.
2027 * If there where any proxy certificates in the chain
2028 * (proxy_cert_depth > 0), check that the proxy issuer
2029 * matched proxy certificates "base" subject.
2031 if (proxy_cert_depth
) {
2033 ret
= _hx509_name_cmp(&proxy_issuer
,
2034 &c
->tbsCertificate
.subject
);
2036 ret
= HX509_PROXY_CERT_NAME_WRONG
;
2037 hx509_clear_error_string(context
);
2041 hx509_name_free(&cert
->basename
);
2043 ret
= _hx509_name_from_Name(&proxy_issuer
, &cert
->basename
);
2045 hx509_clear_error_string(context
);
2053 ret
= check_basic_constraints(context
, c
, type
,
2054 i
- proxy_cert_depth
- selfsigned_depth
);
2059 * Don't check the trust anchors expiration time since they
2060 * are transported out of band, from RFC3820.
2062 if (i
+ 1 != path
.len
|| CHECK_TA(ctx
)) {
2064 t
= _hx509_Time2time_t(&c
->tbsCertificate
.validity
.notBefore
);
2065 if (t
> ctx
->time_now
) {
2066 ret
= HX509_CERT_USED_BEFORE_TIME
;
2067 hx509_clear_error_string(context
);
2070 t
= _hx509_Time2time_t(&c
->tbsCertificate
.validity
.notAfter
);
2071 if (t
< ctx
->time_now
) {
2072 ret
= HX509_CERT_USED_AFTER_TIME
;
2073 hx509_clear_error_string(context
);
2078 if (type
== EE_CERT
)
2080 else if (type
== PROXY_CERT
)
2085 * Verify constraints, do this backward so path constraints are
2086 * checked in the right order.
2089 for (ret
= 0, i
= path
.len
- 1; i
>= 0; i
--) {
2092 c
= _hx509_get_cert(path
.val
[i
]);
2094 /* verify name constraints, not for selfsigned and anchor */
2095 if (!certificate_is_self_signed(c
) || i
+ 1 != path
.len
) {
2096 ret
= check_name_constraints(context
, &nc
, c
);
2101 ret
= add_name_constraints(context
, c
, i
== 0, &nc
);
2105 /* XXX verify all other silly constraints */
2110 * Verify that no certificates has been revoked.
2113 if (ctx
->revoke_ctx
) {
2116 ret
= hx509_certs_init(context
, "MEMORY:revoke-certs", 0,
2121 for (i
= 0; i
< path
.len
; i
++) {
2122 ret
= hx509_certs_add(context
, certs
, path
.val
[i
]);
2124 hx509_certs_free(&certs
);
2128 ret
= hx509_certs_merge(context
, certs
, pool
);
2130 hx509_certs_free(&certs
);
2134 for (i
= 0; i
< path
.len
- 1; i
++) {
2135 int parent
= (i
< path
.len
- 1) ? i
+ 1 : i
;
2137 ret
= hx509_revoke_verify(context
,
2144 hx509_certs_free(&certs
);
2148 hx509_certs_free(&certs
);
2152 for (i
= path
.len
- 1; i
>= 0; i
--) {
2153 _hx509_print_cert_subject(path
.val
[i
]);
2158 * Verify signatures, do this backward so public key working
2159 * parameter is passed up from the anchor up though the chain.
2162 for (i
= path
.len
- 1; i
>= 0; i
--) {
2163 Certificate
*signer
, *c
;
2165 c
= _hx509_get_cert(path
.val
[i
]);
2167 /* is last in chain (trust anchor) */
2168 if (i
+ 1 == path
.len
) {
2169 signer
= path
.val
[i
]->data
;
2171 /* if trust anchor is not self signed, don't check sig */
2172 if (!certificate_is_self_signed(signer
))
2175 /* take next certificate in chain */
2176 signer
= path
.val
[i
+ 1]->data
;
2179 /* verify signatureValue */
2180 ret
= _hx509_verify_signature_bitstring(context
,
2182 &c
->signatureAlgorithm
,
2183 &c
->tbsCertificate
._save
,
2184 &c
->signatureValue
);
2186 hx509_set_error_string(context
, HX509_ERROR_APPEND
, ret
,
2187 "Failed to verify signature of certificate");
2193 hx509_certs_free(&anchors
);
2194 free_Name(&proxy_issuer
);
2195 free_name_constraints(&nc
);
2196 _hx509_path_free(&path
);
2202 * Verify a signature made using the private key of an certificate.
2204 * @param context A hx509 context.
2205 * @param signer the certificate that made the signature.
2206 * @param alg algorthm that was used to sign the data.
2207 * @param data the data that was signed.
2208 * @param sig the sigature to verify.
2210 * @return An hx509 error code, see hx509_get_error_string().
2212 * @ingroup hx509_crypto
2216 hx509_verify_signature(hx509_context context
,
2217 const hx509_cert signer
,
2218 const AlgorithmIdentifier
*alg
,
2219 const heim_octet_string
*data
,
2220 const heim_octet_string
*sig
)
2222 return _hx509_verify_signature(context
, signer
->data
, alg
, data
, sig
);
2227 * Verify that the certificate is allowed to be used for the hostname
2230 * @param context A hx509 context.
2231 * @param cert the certificate to match with
2232 * @param flags undocumented flags, use 0
2234 * @param type type of hostname: HX509_HN_HOSTNAME for plain hostname,
2235 * HX509_HN_DNSSRV for DNS SRV names.
2236 * @param hostname the hostname to check
2237 * @param sa address of the host
2238 * @param sa_size length of address
2240 * @return An hx509 error code, see hx509_get_error_string().
2242 * @ingroup hx509_cert
2246 hx509_verify_hostname(hx509_context context
,
2247 const hx509_cert cert
,
2249 hx509_hostname_type type
,
2250 const char *hostname
,
2251 const struct sockaddr
*sa
,
2252 /* XXX krb5_socklen_t */ int sa_size
)
2257 if (sa
&& sa_size
<= 0)
2260 memset(&san
, 0, sizeof(san
));
2264 ret
= find_extension_subject_alt_name(cert
->data
, &i
, &san
);
2265 if (ret
== HX509_EXTENSION_NOT_FOUND
) {
2268 } else if (ret
!= 0)
2271 for (j
= 0; j
< san
.len
; j
++) {
2272 switch (san
.val
[j
].element
) {
2273 case choice_GeneralName_dNSName
:
2274 if (strcasecmp(san
.val
[j
].u
.dNSName
, hostname
) == 0) {
2275 free_GeneralNames(&san
);
2283 free_GeneralNames(&san
);
2287 Name
*name
= &cert
->data
->tbsCertificate
.subject
;
2289 /* match if first component is a CN= */
2290 if (name
->u
.rdnSequence
.len
> 0
2291 && name
->u
.rdnSequence
.val
[0].len
== 1
2292 && der_heim_oid_cmp(&name
->u
.rdnSequence
.val
[0].val
[0].type
,
2293 oid_id_at_commonName()) == 0)
2295 DirectoryString
*ds
= &name
->u
.rdnSequence
.val
[0].val
[0].value
;
2297 switch (ds
->element
) {
2298 case choice_DirectoryString_printableString
:
2299 if (strcasecmp(ds
->u
.printableString
, hostname
) == 0)
2302 case choice_DirectoryString_ia5String
:
2303 if (strcasecmp(ds
->u
.ia5String
, hostname
) == 0)
2306 case choice_DirectoryString_utf8String
:
2307 if (strcasecmp(ds
->u
.utf8String
, hostname
) == 0)
2315 if ((flags
& HX509_VHN_F_ALLOW_NO_MATCH
) == 0)
2316 ret
= HX509_NAME_CONSTRAINT_ERROR
;
2322 _hx509_set_cert_attribute(hx509_context context
,
2324 const heim_oid
*oid
,
2325 const heim_octet_string
*attr
)
2327 hx509_cert_attribute a
;
2330 if (hx509_cert_get_attribute(cert
, oid
) != NULL
)
2333 d
= realloc(cert
->attrs
.val
,
2334 sizeof(cert
->attrs
.val
[0]) * (cert
->attrs
.len
+ 1));
2336 hx509_clear_error_string(context
);
2339 cert
->attrs
.val
= d
;
2341 a
= malloc(sizeof(*a
));
2345 der_copy_octet_string(attr
, &a
->data
);
2346 der_copy_oid(oid
, &a
->oid
);
2348 cert
->attrs
.val
[cert
->attrs
.len
] = a
;
2355 * Get an external attribute for the certificate, examples are
2356 * friendly name and id.
2358 * @param cert hx509 certificate object to search
2359 * @param oid an oid to search for.
2361 * @return an hx509_cert_attribute, only valid as long as the
2362 * certificate is referenced.
2364 * @ingroup hx509_cert
2367 hx509_cert_attribute
2368 hx509_cert_get_attribute(hx509_cert cert
, const heim_oid
*oid
)
2371 for (i
= 0; i
< cert
->attrs
.len
; i
++)
2372 if (der_heim_oid_cmp(oid
, &cert
->attrs
.val
[i
]->oid
) == 0)
2373 return cert
->attrs
.val
[i
];
2378 * Set the friendly name on the certificate.
2380 * @param cert The certificate to set the friendly name on
2381 * @param name Friendly name.
2383 * @return An hx509 error code, see hx509_get_error_string().
2385 * @ingroup hx509_cert
2389 hx509_cert_set_friendly_name(hx509_cert cert
, const char *name
)
2391 if (cert
->friendlyname
)
2392 free(cert
->friendlyname
);
2393 cert
->friendlyname
= strdup(name
);
2394 if (cert
->friendlyname
== NULL
)
2400 * Get friendly name of the certificate.
2402 * @param cert cert to get the friendly name from.
2404 * @return an friendly name or NULL if there is. The friendly name is
2405 * only valid as long as the certificate is referenced.
2407 * @ingroup hx509_cert
2411 hx509_cert_get_friendly_name(hx509_cert cert
)
2413 hx509_cert_attribute a
;
2414 PKCS9_friendlyName n
;
2418 if (cert
->friendlyname
)
2419 return cert
->friendlyname
;
2421 a
= hx509_cert_get_attribute(cert
, oid_id_pkcs_9_at_friendlyName());
2423 /* XXX use subject name ? */
2427 ret
= decode_PKCS9_friendlyName(a
->data
.data
, a
->data
.length
, &n
, &sz
);
2432 free_PKCS9_friendlyName(&n
);
2436 cert
->friendlyname
= malloc(n
.val
[0].length
+ 1);
2437 if (cert
->friendlyname
== NULL
) {
2438 free_PKCS9_friendlyName(&n
);
2442 for (i
= 0; i
< n
.val
[0].length
; i
++) {
2443 if (n
.val
[0].data
[i
] <= 0xff)
2444 cert
->friendlyname
[i
] = n
.val
[0].data
[i
] & 0xff;
2446 cert
->friendlyname
[i
] = 'X';
2448 cert
->friendlyname
[i
] = '\0';
2449 free_PKCS9_friendlyName(&n
);
2451 return cert
->friendlyname
;
2455 _hx509_query_clear(hx509_query
*q
)
2457 memset(q
, 0, sizeof(*q
));
2461 * Allocate an query controller. Free using hx509_query_free().
2463 * @param context A hx509 context.
2464 * @param q return pointer to a hx509_query.
2466 * @return An hx509 error code, see hx509_get_error_string().
2468 * @ingroup hx509_cert
2472 hx509_query_alloc(hx509_context context
, hx509_query
**q
)
2474 *q
= calloc(1, sizeof(**q
));
2481 * Set match options for the hx509 query controller.
2483 * @param q query controller.
2484 * @param option options to control the query controller.
2486 * @return An hx509 error code, see hx509_get_error_string().
2488 * @ingroup hx509_cert
2492 hx509_query_match_option(hx509_query
*q
, hx509_query_option option
)
2495 case HX509_QUERY_OPTION_PRIVATE_KEY
:
2496 q
->match
|= HX509_QUERY_PRIVATE_KEY
;
2498 case HX509_QUERY_OPTION_KU_ENCIPHERMENT
:
2499 q
->match
|= HX509_QUERY_KU_ENCIPHERMENT
;
2501 case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE
:
2502 q
->match
|= HX509_QUERY_KU_DIGITALSIGNATURE
;
2504 case HX509_QUERY_OPTION_KU_KEYCERTSIGN
:
2505 q
->match
|= HX509_QUERY_KU_KEYCERTSIGN
;
2507 case HX509_QUERY_OPTION_END
:
2514 * Set the issuer and serial number of match in the query
2515 * controller. The function make copies of the isser and serial number.
2517 * @param q a hx509 query controller
2518 * @param issuer issuer to search for
2519 * @param serialNumber the serialNumber of the issuer.
2521 * @return An hx509 error code, see hx509_get_error_string().
2523 * @ingroup hx509_cert
2527 hx509_query_match_issuer_serial(hx509_query
*q
,
2529 const heim_integer
*serialNumber
)
2533 der_free_heim_integer(q
->serial
);
2536 q
->serial
= malloc(sizeof(*q
->serial
));
2537 if (q
->serial
== NULL
)
2539 ret
= der_copy_heim_integer(serialNumber
, q
->serial
);
2545 if (q
->issuer_name
) {
2546 free_Name(q
->issuer_name
);
2547 free(q
->issuer_name
);
2549 q
->issuer_name
= malloc(sizeof(*q
->issuer_name
));
2550 if (q
->issuer_name
== NULL
)
2552 ret
= copy_Name(issuer
, q
->issuer_name
);
2554 free(q
->issuer_name
);
2555 q
->issuer_name
= NULL
;
2558 q
->match
|= HX509_QUERY_MATCH_SERIALNUMBER
|HX509_QUERY_MATCH_ISSUER_NAME
;
2563 * Set the query controller to match on a friendly name
2565 * @param q a hx509 query controller.
2566 * @param name a friendly name to match on
2568 * @return An hx509 error code, see hx509_get_error_string().
2570 * @ingroup hx509_cert
2574 hx509_query_match_friendly_name(hx509_query
*q
, const char *name
)
2576 if (q
->friendlyname
)
2577 free(q
->friendlyname
);
2578 q
->friendlyname
= strdup(name
);
2579 if (q
->friendlyname
== NULL
)
2581 q
->match
|= HX509_QUERY_MATCH_FRIENDLY_NAME
;
2586 * Set the query controller to match using a specific match function.
2588 * @param q a hx509 query controller.
2589 * @param func function to use for matching, if the argument is NULL,
2590 * the match function is removed.
2591 * @param ctx context passed to the function.
2593 * @return An hx509 error code, see hx509_get_error_string().
2595 * @ingroup hx509_cert
2599 hx509_query_match_cmp_func(hx509_query
*q
,
2600 int (*func
)(void *, hx509_cert
),
2604 q
->match
|= HX509_QUERY_MATCH_FUNCTION
;
2606 q
->match
&= ~HX509_QUERY_MATCH_FUNCTION
;
2608 q
->cmp_func_ctx
= ctx
;
2613 * Free the query controller.
2615 * @param context A hx509 context.
2616 * @param q a pointer to the query controller.
2618 * @ingroup hx509_cert
2622 hx509_query_free(hx509_context context
, hx509_query
*q
)
2625 der_free_heim_integer(q
->serial
);
2629 if (q
->issuer_name
) {
2630 free_Name(q
->issuer_name
);
2631 free(q
->issuer_name
);
2632 q
->issuer_name
= NULL
;
2635 free(q
->friendlyname
);
2636 memset(q
, 0, sizeof(*q
));
2642 _hx509_query_match_cert(hx509_context context
, const hx509_query
*q
, hx509_cert cert
)
2644 Certificate
*c
= _hx509_get_cert(cert
);
2646 _hx509_query_statistic(context
, 1, q
);
2648 if ((q
->match
& HX509_QUERY_FIND_ISSUER_CERT
) &&
2649 _hx509_cert_is_parent_cmp(q
->subject
, c
, 0) != 0)
2652 if ((q
->match
& HX509_QUERY_MATCH_CERTIFICATE
) &&
2653 _hx509_Certificate_cmp(q
->certificate
, c
) != 0)
2656 if ((q
->match
& HX509_QUERY_MATCH_SERIALNUMBER
)
2657 && der_heim_integer_cmp(&c
->tbsCertificate
.serialNumber
, q
->serial
) != 0)
2660 if ((q
->match
& HX509_QUERY_MATCH_ISSUER_NAME
)
2661 && _hx509_name_cmp(&c
->tbsCertificate
.issuer
, q
->issuer_name
) != 0)
2664 if ((q
->match
& HX509_QUERY_MATCH_SUBJECT_NAME
)
2665 && _hx509_name_cmp(&c
->tbsCertificate
.subject
, q
->subject_name
) != 0)
2668 if (q
->match
& HX509_QUERY_MATCH_SUBJECT_KEY_ID
) {
2669 SubjectKeyIdentifier si
;
2672 ret
= _hx509_find_extension_subject_key_id(c
, &si
);
2674 if (der_heim_octet_string_cmp(&si
, q
->subject_id
) != 0)
2676 free_SubjectKeyIdentifier(&si
);
2681 if ((q
->match
& HX509_QUERY_MATCH_ISSUER_ID
))
2683 if ((q
->match
& HX509_QUERY_PRIVATE_KEY
) &&
2684 _hx509_cert_private_key(cert
) == NULL
)
2689 if (q
->match
& HX509_QUERY_KU_DIGITALSIGNATURE
)
2691 if (q
->match
& HX509_QUERY_KU_NONREPUDIATION
)
2693 if (q
->match
& HX509_QUERY_KU_ENCIPHERMENT
)
2695 if (q
->match
& HX509_QUERY_KU_DATAENCIPHERMENT
)
2697 if (q
->match
& HX509_QUERY_KU_KEYAGREEMENT
)
2699 if (q
->match
& HX509_QUERY_KU_KEYCERTSIGN
)
2701 if (q
->match
& HX509_QUERY_KU_CRLSIGN
)
2703 if (ku
&& check_key_usage(context
, c
, ku
, TRUE
))
2706 if ((q
->match
& HX509_QUERY_ANCHOR
))
2709 if (q
->match
& HX509_QUERY_MATCH_LOCAL_KEY_ID
) {
2710 hx509_cert_attribute a
;
2712 a
= hx509_cert_get_attribute(cert
, oid_id_pkcs_9_at_localKeyId());
2715 if (der_heim_octet_string_cmp(&a
->data
, q
->local_key_id
) != 0)
2719 if (q
->match
& HX509_QUERY_NO_MATCH_PATH
) {
2722 for (i
= 0; i
< q
->path
->len
; i
++)
2723 if (hx509_cert_cmp(q
->path
->val
[i
], cert
) == 0)
2726 if (q
->match
& HX509_QUERY_MATCH_FRIENDLY_NAME
) {
2727 const char *name
= hx509_cert_get_friendly_name(cert
);
2730 if (strcasecmp(q
->friendlyname
, name
) != 0)
2733 if (q
->match
& HX509_QUERY_MATCH_FUNCTION
) {
2734 int ret
= (*q
->cmp_func
)(q
->cmp_func_ctx
, cert
);
2739 if (q
->match
& HX509_QUERY_MATCH_KEY_HASH_SHA1
) {
2740 heim_octet_string os
;
2743 os
.data
= c
->tbsCertificate
.subjectPublicKeyInfo
.subjectPublicKey
.data
;
2745 c
->tbsCertificate
.subjectPublicKeyInfo
.subjectPublicKey
.length
/ 8;
2747 ret
= _hx509_verify_signature(context
,
2749 hx509_signature_sha1(),
2756 if (q
->match
& HX509_QUERY_MATCH_TIME
) {
2758 t
= _hx509_Time2time_t(&c
->tbsCertificate
.validity
.notBefore
);
2761 t
= _hx509_Time2time_t(&c
->tbsCertificate
.validity
.notAfter
);
2766 if (q
->match
& ~HX509_QUERY_MASK
)
2773 * Set a statistic file for the query statistics.
2775 * @param context A hx509 context.
2776 * @param fn statistics file name
2778 * @ingroup hx509_cert
2782 hx509_query_statistic_file(hx509_context context
, const char *fn
)
2784 if (context
->querystat
)
2785 free(context
->querystat
);
2786 context
->querystat
= strdup(fn
);
2790 _hx509_query_statistic(hx509_context context
, int type
, const hx509_query
*q
)
2793 if (context
->querystat
== NULL
)
2795 f
= fopen(context
->querystat
, "a");
2798 fprintf(f
, "%d %d\n", type
, q
->match
);
2802 static const char *statname
[] = {
2804 "match serialnumber",
2805 "match issuer name",
2806 "match subject name",
2807 "match subject key id",
2811 "ku digitalsignature",
2814 "ku nonrepudiation",
2816 "ku dataencipherment",
2818 "match certificate",
2819 "match local key id",
2821 "match friendly name",
2823 "match key hash sha1",
2828 unsigned long stats
;
2834 stat_sort(const void *a
, const void *b
)
2836 const struct stat_el
*ae
= a
;
2837 const struct stat_el
*be
= b
;
2838 return be
->stats
- ae
->stats
;
2842 * Unparse the statistics file and print the result on a FILE descriptor.
2844 * @param context A hx509 context.
2845 * @param printtype tyep to print
2846 * @param out the FILE to write the data on.
2848 * @ingroup hx509_cert
2852 hx509_query_unparse_stats(hx509_context context
, int printtype
, FILE *out
)
2856 int type
, mask
, i
, num
;
2857 unsigned long multiqueries
= 0, totalqueries
= 0;
2858 struct stat_el stats
[32];
2860 if (context
->querystat
== NULL
)
2862 f
= fopen(context
->querystat
, "r");
2864 fprintf(out
, "No statistic file %s: %s.\n",
2865 context
->querystat
, strerror(errno
));
2869 for (i
= 0; i
< sizeof(stats
)/sizeof(stats
[0]); i
++) {
2874 while (fscanf(f
, "%d %d\n", &type
, &mask
) == 2) {
2875 if (type
!= printtype
)
2878 while (mask
&& i
< sizeof(stats
)/sizeof(stats
[0])) {
2892 qsort(stats
, sizeof(stats
)/sizeof(stats
[0]), sizeof(stats
[0]), stat_sort
);
2896 errx(1, "out of memory");
2898 rtbl_set_separator (t
, " ");
2900 rtbl_add_column_by_id (t
, 0, "Name", 0);
2901 rtbl_add_column_by_id (t
, 1, "Counter", 0);
2904 for (i
= 0; i
< sizeof(stats
)/sizeof(stats
[0]); i
++) {
2907 if (stats
[i
].index
< sizeof(statname
)/sizeof(statname
[0]))
2908 rtbl_add_column_entry_by_id (t
, 0, statname
[stats
[i
].index
]);
2910 snprintf(str
, sizeof(str
), "%d", stats
[i
].index
);
2911 rtbl_add_column_entry_by_id (t
, 0, str
);
2913 snprintf(str
, sizeof(str
), "%lu", stats
[i
].stats
);
2914 rtbl_add_column_entry_by_id (t
, 1, str
);
2917 rtbl_format(t
, out
);
2920 fprintf(out
, "\nQueries: multi %lu total %lu\n",
2921 multiqueries
, totalqueries
);
2925 * Check the extended key usage on the hx509 certificate.
2927 * @param context A hx509 context.
2928 * @param cert A hx509 context.
2929 * @param eku the EKU to check for
2930 * @param allow_any_eku if the any EKU is set, allow that to be a
2933 * @return An hx509 error code, see hx509_get_error_string().
2935 * @ingroup hx509_cert
2939 hx509_cert_check_eku(hx509_context context
, hx509_cert cert
,
2940 const heim_oid
*eku
, int allow_any_eku
)
2945 ret
= find_extension_eku(_hx509_get_cert(cert
), &e
);
2947 hx509_clear_error_string(context
);
2951 for (i
= 0; i
< e
.len
; i
++) {
2952 if (der_heim_oid_cmp(eku
, &e
.val
[i
]) == 0) {
2953 free_ExtKeyUsage(&e
);
2956 if (allow_any_eku
) {
2958 if (der_heim_oid_cmp(id_any_eku
, &e
.val
[i
]) == 0) {
2959 free_ExtKeyUsage(&e
);
2965 free_ExtKeyUsage(&e
);
2966 hx509_clear_error_string(context
);
2967 return HX509_CERTIFICATE_MISSING_EKU
;
2971 _hx509_cert_get_keyusage(hx509_context context
,
2980 memset(ku
, 0, sizeof(*ku
));
2982 cert
= _hx509_get_cert(c
);
2984 if (_hx509_cert_get_version(cert
) < 3)
2987 e
= find_extension(cert
, oid_id_x509_ce_keyUsage(), &i
);
2989 return HX509_KU_CERT_MISSING
;
2991 ret
= decode_KeyUsage(e
->extnValue
.data
, e
->extnValue
.length
, ku
, &size
);
2998 _hx509_cert_get_eku(hx509_context context
,
3004 memset(e
, 0, sizeof(*e
));
3006 ret
= find_extension_eku(_hx509_get_cert(cert
), e
);
3007 if (ret
&& ret
!= HX509_EXTENSION_NOT_FOUND
) {
3008 hx509_clear_error_string(context
);
3015 * Encodes the hx509 certificate as a DER encode binary.
3017 * @param context A hx509 context.
3018 * @param c the certificate to encode.
3019 * @param os the encode certificate, set to NULL, 0 on case of error.
3021 * @return An hx509 error code, see hx509_get_error_string().
3023 * @ingroup hx509_cert
3027 hx509_cert_binary(hx509_context context
, hx509_cert c
, heim_octet_string
*os
)
3035 ASN1_MALLOC_ENCODE(Certificate
, os
->data
, os
->length
,
3036 _hx509_get_cert(c
), &size
, ret
);
3042 if (os
->length
!= size
)
3043 _hx509_abort("internal ASN.1 encoder error");
3049 * Last to avoid lost __attribute__s due to #undef.
3052 #undef __attribute__
3053 #define __attribute__(X)
3056 _hx509_abort(const char *fmt
, ...)
3057 __attribute__ ((noreturn
, format (printf
, 1, 2)))