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"
40 * @page page_cert The basic certificate
42 * The basic hx509 cerificate object in hx509 is hx509_cert. The
43 * hx509_cert object is representing one X509/PKIX certificate and
44 * associated attributes; like private key, friendly name, etc.
46 * A hx509_cert object is usully found via the keyset interfaces (@ref
47 * page_keyset), but its also possible to create a certificate
48 * directly from a parsed object with hx509_cert_init() and
49 * hx509_cert_init_data().
51 * See the library functions here: @ref hx509_cert
54 struct hx509_verify_ctx_data
{
55 hx509_certs trust_anchors
;
57 #define HX509_VERIFY_CTX_F_TIME_SET 1
58 #define HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE 2
59 #define HX509_VERIFY_CTX_F_REQUIRE_RFC3280 4
60 #define HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS 8
61 #define HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS 16
63 unsigned int max_depth
;
64 #define HX509_VERIFY_MAX_DEPTH 30
65 hx509_revoke_ctx revoke_ctx
;
68 #define REQUIRE_RFC3280(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_REQUIRE_RFC3280)
69 #define CHECK_TA(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS)
70 #define ALLOW_DEF_TA(ctx) (((ctx)->flags & HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS) == 0)
72 struct _hx509_cert_attrs
{
74 hx509_cert_attribute
*val
;
77 struct hx509_cert_data
{
81 hx509_private_key private_key
;
82 struct _hx509_cert_attrs attrs
;
84 _hx509_cert_release_func release
;
88 typedef struct hx509_name_constraints
{
91 } hx509_name_constraints
;
93 #define GeneralSubtrees_SET(g,var) \
94 (g)->len = (var)->len, (g)->val = (var)->val;
97 * Creates a hx509 context that most functions in the library
98 * uses. The context is only allowed to be used by one thread at each
99 * moment. Free the context with hx509_context_free().
101 * @param context Returns a pointer to new hx509 context.
103 * @return Returns an hx509 error code.
109 hx509_context_init(hx509_context
*context
)
111 *context
= calloc(1, sizeof(**context
));
112 if (*context
== NULL
)
115 _hx509_ks_null_register(*context
);
116 _hx509_ks_mem_register(*context
);
117 _hx509_ks_file_register(*context
);
118 _hx509_ks_pkcs12_register(*context
);
119 _hx509_ks_pkcs11_register(*context
);
120 _hx509_ks_dir_register(*context
);
121 _hx509_ks_keychain_register(*context
);
123 ENGINE_add_conf_module();
124 OpenSSL_add_all_algorithms();
126 (*context
)->ocsp_time_diff
= HX509_DEFAULT_OCSP_TIME_DIFF
;
128 initialize_hx_error_table_r(&(*context
)->et_list
);
129 initialize_asn1_error_table_r(&(*context
)->et_list
);
131 #ifdef HX509_DEFAULT_ANCHORS
132 (void)hx509_certs_init(*context
, HX509_DEFAULT_ANCHORS
, 0,
133 NULL
, &(*context
)->default_trust_anchors
);
140 * Selects if the hx509_revoke_verify() function is going to require
141 * the existans of a revokation method (OSCP, CRL) or not. Note that
142 * hx509_verify_path(), hx509_cms_verify_signed(), and other function
143 * call hx509_revoke_verify().
145 * @param context hx509 context to change the flag for.
146 * @param flag zero, revokation method required, non zero missing
147 * revokation method ok
149 * @ingroup hx509_verify
153 hx509_context_set_missing_revoke(hx509_context context
, int flag
)
156 context
->flags
|= HX509_CTX_VERIFY_MISSING_OK
;
158 context
->flags
&= ~HX509_CTX_VERIFY_MISSING_OK
;
162 * Free the context allocated by hx509_context_init().
164 * @param context context to be freed.
170 hx509_context_free(hx509_context
*context
)
172 hx509_clear_error_string(*context
);
173 if ((*context
)->ks_ops
) {
174 free((*context
)->ks_ops
);
175 (*context
)->ks_ops
= NULL
;
177 (*context
)->ks_num_ops
= 0;
178 free_error_table ((*context
)->et_list
);
179 if ((*context
)->querystat
)
180 free((*context
)->querystat
);
181 memset(*context
, 0, sizeof(**context
));
191 _hx509_get_cert(hx509_cert cert
)
201 _hx509_cert_get_version(const Certificate
*t
)
203 return t
->tbsCertificate
.version
? *t
->tbsCertificate
.version
+ 1 : 1;
207 * Allocate and init an hx509 certificate object from the decoded
210 * @param context A hx509 context.
214 * @return Returns an hx509 error code.
216 * @ingroup hx509_cert
220 hx509_cert_init(hx509_context context
, const Certificate
*c
, hx509_cert
*cert
)
224 *cert
= malloc(sizeof(**cert
));
228 (*cert
)->friendlyname
= NULL
;
229 (*cert
)->attrs
.len
= 0;
230 (*cert
)->attrs
.val
= NULL
;
231 (*cert
)->private_key
= NULL
;
232 (*cert
)->basename
= NULL
;
233 (*cert
)->release
= NULL
;
236 (*cert
)->data
= calloc(1, sizeof(*(*cert
)->data
));
237 if ((*cert
)->data
== NULL
) {
241 ret
= copy_Certificate(c
, (*cert
)->data
);
251 * Just like hx509_cert_init(), but instead of a decode certificate
252 * takes an pointer and length to a memory region that contains a
253 * DER/BER encoded certificate.
255 * If the memory region doesn't contain just the certificate and
256 * nothing more the function will fail with
257 * HX509_EXTRA_DATA_AFTER_STRUCTURE.
259 * @param context A hx509 context.
260 * @param ptr pointer to memory region containing encoded certificate.
261 * @param len length of memory region.
262 * @param cert a return pointer to a hx509 certificate object, will
263 * contain NULL on error.
265 * @return An hx509 error code, see hx509_get_error_string().
267 * @ingroup hx509_cert
271 hx509_cert_init_data(hx509_context context
,
280 ret
= decode_Certificate(ptr
, len
, &t
, &size
);
282 hx509_set_error_string(context
, 0, ret
, "Failed to decode certificate");
286 hx509_set_error_string(context
, 0, HX509_EXTRA_DATA_AFTER_STRUCTURE
,
287 "Extra data after certificate");
288 return HX509_EXTRA_DATA_AFTER_STRUCTURE
;
291 ret
= hx509_cert_init(context
, &t
, cert
);
292 free_Certificate(&t
);
297 _hx509_cert_set_release(hx509_cert cert
,
298 _hx509_cert_release_func release
,
301 cert
->release
= release
;
306 /* Doesn't make a copy of `private_key'. */
309 _hx509_cert_assign_key(hx509_cert cert
, hx509_private_key private_key
)
311 if (cert
->private_key
)
312 _hx509_private_key_free(&cert
->private_key
);
313 cert
->private_key
= _hx509_private_key_ref(private_key
);
318 * Free reference to the hx509 certificate object, if the refcounter
319 * reaches 0, the object if freed. Its allowed to pass in NULL.
321 * @param cert the cert to free.
323 * @ingroup hx509_cert
327 hx509_cert_free(hx509_cert cert
)
335 _hx509_abort("cert refcount <= 0 on free");
340 (cert
->release
)(cert
, cert
->ctx
);
342 if (cert
->private_key
)
343 _hx509_private_key_free(&cert
->private_key
);
345 free_Certificate(cert
->data
);
348 for (i
= 0; i
< cert
->attrs
.len
; i
++) {
349 der_free_octet_string(&cert
->attrs
.val
[i
]->data
);
350 der_free_oid(&cert
->attrs
.val
[i
]->oid
);
351 free(cert
->attrs
.val
[i
]);
353 free(cert
->attrs
.val
);
354 free(cert
->friendlyname
);
356 hx509_name_free(&cert
->basename
);
357 memset(cert
, 0, sizeof(cert
));
362 * Add a reference to a hx509 certificate object.
364 * @param cert a pointer to an hx509 certificate object.
366 * @return the same object as is passed in.
368 * @ingroup hx509_cert
372 hx509_cert_ref(hx509_cert cert
)
377 _hx509_abort("cert refcount <= 0");
380 _hx509_abort("cert refcount == 0");
385 * Allocate an verification context that is used fo control the
386 * verification process.
388 * @param context A hx509 context.
389 * @param ctx returns a pointer to a hx509_verify_ctx object.
391 * @return An hx509 error code, see hx509_get_error_string().
393 * @ingroup hx509_verify
397 hx509_verify_init_ctx(hx509_context context
, hx509_verify_ctx
*ctx
)
401 c
= calloc(1, sizeof(*c
));
405 c
->max_depth
= HX509_VERIFY_MAX_DEPTH
;
413 * Free an hx509 verification context.
415 * @param ctx the context to be freed.
417 * @ingroup hx509_verify
421 hx509_verify_destroy_ctx(hx509_verify_ctx ctx
)
424 hx509_certs_free(&ctx
->trust_anchors
);
425 hx509_revoke_free(&ctx
->revoke_ctx
);
426 memset(ctx
, 0, sizeof(*ctx
));
432 * Set the trust anchors in the verification context, makes an
433 * reference to the keyset, so the consumer can free the keyset
434 * independent of the destruction of the verification context (ctx).
436 * @param ctx a verification context
437 * @param set a keyset containing the trust anchors.
439 * @ingroup hx509_verify
443 hx509_verify_attach_anchors(hx509_verify_ctx ctx
, hx509_certs set
)
445 ctx
->trust_anchors
= _hx509_certs_ref(set
);
449 * Attach an revocation context to the verfication context, , makes an
450 * reference to the revoke context, so the consumer can free the
451 * revoke context independent of the destruction of the verification
452 * context. If there is no revoke context, the verification process is
453 * NOT going to check any verification status.
455 * @param ctx a verification context.
456 * @param revoke_ctx a revoke context.
458 * @ingroup hx509_verify
462 hx509_verify_attach_revoke(hx509_verify_ctx ctx
, hx509_revoke_ctx revoke_ctx
)
465 hx509_revoke_free(&ctx
->revoke_ctx
);
466 ctx
->revoke_ctx
= _hx509_revoke_ref(revoke_ctx
);
470 * Set the clock time the the verification process is going to
471 * use. Used to check certificate in the past and future time. If not
472 * set the current time will be used.
474 * @param ctx a verification context.
475 * @param t the time the verifiation is using.
478 * @ingroup hx509_verify
482 hx509_verify_set_time(hx509_verify_ctx ctx
, time_t t
)
484 ctx
->flags
|= HX509_VERIFY_CTX_F_TIME_SET
;
489 * Set the maximum depth of the certificate chain that the path
490 * builder is going to try.
492 * @param ctx a verification context
493 * @param max_depth maxium depth of the certificate chain, include
496 * @ingroup hx509_verify
500 hx509_verify_set_max_depth(hx509_verify_ctx ctx
, unsigned int max_depth
)
502 ctx
->max_depth
= max_depth
;
506 * Allow or deny the use of proxy certificates
508 * @param ctx a verification context
509 * @param boolean if non zero, allow proxy certificates.
511 * @ingroup hx509_verify
515 hx509_verify_set_proxy_certificate(hx509_verify_ctx ctx
, int boolean
)
518 ctx
->flags
|= HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE
;
520 ctx
->flags
&= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE
;
524 * Select strict RFC3280 verification of certificiates. This means
525 * checking key usage on CA certificates, this will make version 1
526 * certificiates unuseable.
528 * @param ctx a verification context
529 * @param boolean if non zero, use strict verification.
531 * @ingroup hx509_verify
535 hx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx
, int boolean
)
538 ctx
->flags
|= HX509_VERIFY_CTX_F_REQUIRE_RFC3280
;
540 ctx
->flags
&= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280
;
544 * Allow using the operating system builtin trust anchors if no other
545 * trust anchors are configured.
547 * @param ctx a verification context
548 * @param boolean if non zero, useing the operating systems builtin
552 * @return An hx509 error code, see hx509_get_error_string().
554 * @ingroup hx509_cert
558 hx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx
, int boolean
)
561 ctx
->flags
&= ~HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS
;
563 ctx
->flags
|= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS
;
566 static const Extension
*
567 find_extension(const Certificate
*cert
, const heim_oid
*oid
, int *idx
)
569 const TBSCertificate
*c
= &cert
->tbsCertificate
;
571 if (c
->version
== NULL
|| *c
->version
< 2 || c
->extensions
== NULL
)
574 for (;*idx
< c
->extensions
->len
; (*idx
)++) {
575 if (der_heim_oid_cmp(&c
->extensions
->val
[*idx
].extnID
, oid
) == 0)
576 return &c
->extensions
->val
[(*idx
)++];
582 find_extension_auth_key_id(const Certificate
*subject
,
583 AuthorityKeyIdentifier
*ai
)
589 memset(ai
, 0, sizeof(*ai
));
591 e
= find_extension(subject
, oid_id_x509_ce_authorityKeyIdentifier(), &i
);
593 return HX509_EXTENSION_NOT_FOUND
;
595 return decode_AuthorityKeyIdentifier(e
->extnValue
.data
,
601 _hx509_find_extension_subject_key_id(const Certificate
*issuer
,
602 SubjectKeyIdentifier
*si
)
608 memset(si
, 0, sizeof(*si
));
610 e
= find_extension(issuer
, oid_id_x509_ce_subjectKeyIdentifier(), &i
);
612 return HX509_EXTENSION_NOT_FOUND
;
614 return decode_SubjectKeyIdentifier(e
->extnValue
.data
,
620 find_extension_name_constraints(const Certificate
*subject
,
627 memset(nc
, 0, sizeof(*nc
));
629 e
= find_extension(subject
, oid_id_x509_ce_nameConstraints(), &i
);
631 return HX509_EXTENSION_NOT_FOUND
;
633 return decode_NameConstraints(e
->extnValue
.data
,
639 find_extension_subject_alt_name(const Certificate
*cert
, int *i
,
645 memset(sa
, 0, sizeof(*sa
));
647 e
= find_extension(cert
, oid_id_x509_ce_subjectAltName(), i
);
649 return HX509_EXTENSION_NOT_FOUND
;
651 return decode_GeneralNames(e
->extnValue
.data
,
657 find_extension_eku(const Certificate
*cert
, ExtKeyUsage
*eku
)
663 memset(eku
, 0, sizeof(*eku
));
665 e
= find_extension(cert
, oid_id_x509_ce_extKeyUsage(), &i
);
667 return HX509_EXTENSION_NOT_FOUND
;
669 return decode_ExtKeyUsage(e
->extnValue
.data
,
675 add_to_list(hx509_octet_string_list
*list
, const heim_octet_string
*entry
)
680 p
= realloc(list
->val
, (list
->len
+ 1) * sizeof(list
->val
[0]));
684 ret
= der_copy_octet_string(entry
, &list
->val
[list
->len
]);
692 * Free a list of octet strings returned by another hx509 library
695 * @param list list to be freed.
697 * @ingroup hx509_misc
701 hx509_free_octet_string_list(hx509_octet_string_list
*list
)
704 for (i
= 0; i
< list
->len
; i
++)
705 der_free_octet_string(&list
->val
[i
]);
712 * Return a list of subjectAltNames specified by oid in the
713 * certificate. On error the
715 * The returned list of octet string should be freed with
716 * hx509_free_octet_string_list().
718 * @param context A hx509 context.
719 * @param cert a hx509 certificate object.
720 * @param oid an oid to for SubjectAltName.
721 * @param list list of matching SubjectAltName.
723 * @return An hx509 error code, see hx509_get_error_string().
725 * @ingroup hx509_cert
729 hx509_cert_find_subjectAltName_otherName(hx509_context context
,
732 hx509_octet_string_list
*list
)
742 ret
= find_extension_subject_alt_name(_hx509_get_cert(cert
), &i
, &sa
);
744 if (ret
== HX509_EXTENSION_NOT_FOUND
) {
747 } else if (ret
!= 0) {
748 hx509_set_error_string(context
, 0, ret
, "Error searching for SAN");
749 hx509_free_octet_string_list(list
);
753 for (j
= 0; j
< sa
.len
; j
++) {
754 if (sa
.val
[j
].element
== choice_GeneralName_otherName
&&
755 der_heim_oid_cmp(&sa
.val
[j
].u
.otherName
.type_id
, oid
) == 0)
757 ret
= add_to_list(list
, &sa
.val
[j
].u
.otherName
.value
);
759 hx509_set_error_string(context
, 0, ret
,
760 "Error adding an exra SAN to "
762 hx509_free_octet_string_list(list
);
763 free_GeneralNames(&sa
);
768 free_GeneralNames(&sa
);
775 check_key_usage(hx509_context context
, const Certificate
*cert
,
776 unsigned flags
, int req_present
)
784 if (_hx509_cert_get_version(cert
) < 3)
787 e
= find_extension(cert
, oid_id_x509_ce_keyUsage(), &i
);
790 hx509_set_error_string(context
, 0, HX509_KU_CERT_MISSING
,
791 "Required extension key "
792 "usage missing from certifiate");
793 return HX509_KU_CERT_MISSING
;
798 ret
= decode_KeyUsage(e
->extnValue
.data
, e
->extnValue
.length
, &ku
, &size
);
801 ku_flags
= KeyUsage2int(ku
);
802 if ((ku_flags
& flags
) != flags
) {
803 unsigned missing
= (~ku_flags
) & flags
;
804 char buf
[256], *name
;
806 unparse_flags(missing
, asn1_KeyUsage_units(), buf
, sizeof(buf
));
807 _hx509_unparse_Name(&cert
->tbsCertificate
.subject
, &name
);
808 hx509_set_error_string(context
, 0, HX509_KU_CERT_MISSING
,
809 "Key usage %s required but missing "
810 "from certifiate %s", buf
, name
);
812 return HX509_KU_CERT_MISSING
;
818 * Return 0 on matching key usage 'flags' for 'cert', otherwise return
819 * an error code. If 'req_present' the existance is required of the
820 * KeyUsage extension.
824 _hx509_check_key_usage(hx509_context context
, hx509_cert cert
,
825 unsigned flags
, int req_present
)
827 return check_key_usage(context
, _hx509_get_cert(cert
), flags
, req_present
);
830 enum certtype
{ PROXY_CERT
, EE_CERT
, CA_CERT
};
833 check_basic_constraints(hx509_context context
, const Certificate
*cert
,
834 enum certtype type
, int depth
)
841 if (_hx509_cert_get_version(cert
) < 3)
844 e
= find_extension(cert
, oid_id_x509_ce_basicConstraints(), &i
);
852 ret
= _hx509_unparse_Name(&cert
->tbsCertificate
.subject
, &name
);
854 hx509_set_error_string(context
, 0, HX509_EXTENSION_NOT_FOUND
,
855 "basicConstraints missing from "
856 "CA certifiacte %s", name
);
858 return HX509_EXTENSION_NOT_FOUND
;
863 ret
= decode_BasicConstraints(e
->extnValue
.data
,
864 e
->extnValue
.length
, &bc
,
870 if (bc
.cA
!= NULL
&& *bc
.cA
)
871 ret
= HX509_PARENT_IS_CA
;
877 if (bc
.cA
== NULL
|| !*bc
.cA
)
878 ret
= HX509_PARENT_NOT_CA
;
879 else if (bc
.pathLenConstraint
)
880 if (depth
- 1 > *bc
.pathLenConstraint
)
881 ret
= HX509_CA_PATH_TOO_DEEP
;
884 free_BasicConstraints(&bc
);
889 _hx509_cert_is_parent_cmp(const Certificate
*subject
,
890 const Certificate
*issuer
,
891 int allow_self_signed
)
894 AuthorityKeyIdentifier ai
;
895 SubjectKeyIdentifier si
;
898 diff
= _hx509_name_cmp(&issuer
->tbsCertificate
.subject
,
899 &subject
->tbsCertificate
.issuer
);
903 memset(&ai
, 0, sizeof(ai
));
904 memset(&si
, 0, sizeof(si
));
907 * Try to find AuthorityKeyIdentifier, if it's not present in the
908 * subject certificate nor the parent.
911 ret_ai
= find_extension_auth_key_id(subject
, &ai
);
912 if (ret_ai
&& ret_ai
!= HX509_EXTENSION_NOT_FOUND
)
914 ret_si
= _hx509_find_extension_subject_key_id(issuer
, &si
);
915 if (ret_si
&& ret_si
!= HX509_EXTENSION_NOT_FOUND
)
918 if (ret_si
&& ret_ai
)
923 if (allow_self_signed
) {
926 } else if (ai
.keyIdentifier
) {
932 if (ai
.keyIdentifier
== NULL
) {
935 if (ai
.authorityCertIssuer
== NULL
)
937 if (ai
.authorityCertSerialNumber
== NULL
)
940 diff
= der_heim_integer_cmp(ai
.authorityCertSerialNumber
,
941 &issuer
->tbsCertificate
.serialNumber
);
944 if (ai
.authorityCertIssuer
->len
!= 1)
946 if (ai
.authorityCertIssuer
->val
[0].element
!= choice_GeneralName_directoryName
)
950 ai
.authorityCertIssuer
->val
[0].u
.directoryName
.element
;
952 ai
.authorityCertIssuer
->val
[0].u
.directoryName
.u
.rdnSequence
;
954 diff
= _hx509_name_cmp(&issuer
->tbsCertificate
.subject
,
960 diff
= der_heim_octet_string_cmp(ai
.keyIdentifier
, &si
);
965 free_AuthorityKeyIdentifier(&ai
);
966 free_SubjectKeyIdentifier(&si
);
971 certificate_is_anchor(hx509_context context
,
972 hx509_certs trust_anchors
,
973 const hx509_cert cert
)
979 if (trust_anchors
== NULL
)
982 _hx509_query_clear(&q
);
984 q
.match
= HX509_QUERY_MATCH_CERTIFICATE
;
985 q
.certificate
= _hx509_get_cert(cert
);
987 ret
= hx509_certs_find(context
, trust_anchors
, &q
, &c
);
994 certificate_is_self_signed(const Certificate
*cert
)
996 return _hx509_name_cmp(&cert
->tbsCertificate
.subject
,
997 &cert
->tbsCertificate
.issuer
) == 0;
1001 * The subjectName is "null" when it's empty set of relative DBs.
1005 subject_null_p(const Certificate
*c
)
1007 return c
->tbsCertificate
.subject
.u
.rdnSequence
.len
== 0;
1012 find_parent(hx509_context context
,
1014 hx509_certs trust_anchors
,
1020 AuthorityKeyIdentifier ai
;
1025 memset(&ai
, 0, sizeof(ai
));
1027 _hx509_query_clear(&q
);
1029 if (!subject_null_p(current
->data
)) {
1030 q
.match
|= HX509_QUERY_FIND_ISSUER_CERT
;
1031 q
.subject
= _hx509_get_cert(current
);
1033 ret
= find_extension_auth_key_id(current
->data
, &ai
);
1035 hx509_set_error_string(context
, 0, HX509_CERTIFICATE_MALFORMED
,
1036 "Subjectless certificate missing AuthKeyID");
1037 return HX509_CERTIFICATE_MALFORMED
;
1040 if (ai
.keyIdentifier
== NULL
) {
1041 free_AuthorityKeyIdentifier(&ai
);
1042 hx509_set_error_string(context
, 0, HX509_CERTIFICATE_MALFORMED
,
1043 "Subjectless certificate missing keyIdentifier "
1044 "inside AuthKeyID");
1045 return HX509_CERTIFICATE_MALFORMED
;
1048 q
.subject_id
= ai
.keyIdentifier
;
1049 q
.match
= HX509_QUERY_MATCH_SUBJECT_KEY_ID
;
1053 q
.match
|= HX509_QUERY_NO_MATCH_PATH
;
1056 q
.timenow
= time_now
;
1057 q
.match
|= HX509_QUERY_MATCH_TIME
;
1059 ret
= hx509_certs_find(context
, pool
, &q
, parent
);
1061 free_AuthorityKeyIdentifier(&ai
);
1064 q
.match
&= ~HX509_QUERY_MATCH_TIME
;
1067 if (trust_anchors
) {
1068 ret
= hx509_certs_find(context
, trust_anchors
, &q
, parent
);
1070 free_AuthorityKeyIdentifier(&ai
);
1074 free_AuthorityKeyIdentifier(&ai
);
1080 ret
= hx509_cert_get_subject(current
, &name
);
1082 hx509_clear_error_string(context
);
1083 return HX509_ISSUER_NOT_FOUND
;
1085 ret
= hx509_name_to_string(name
, &str
);
1086 hx509_name_free(&name
);
1088 hx509_clear_error_string(context
);
1089 return HX509_ISSUER_NOT_FOUND
;
1092 hx509_set_error_string(context
, 0, HX509_ISSUER_NOT_FOUND
,
1093 "Failed to find issuer for "
1094 "certificate with subject: '%s'", str
);
1097 return HX509_ISSUER_NOT_FOUND
;
1105 is_proxy_cert(hx509_context context
,
1106 const Certificate
*cert
,
1107 ProxyCertInfo
*rinfo
)
1115 memset(rinfo
, 0, sizeof(*rinfo
));
1117 e
= find_extension(cert
, oid_id_pkix_pe_proxyCertInfo(), &i
);
1119 hx509_clear_error_string(context
);
1120 return HX509_EXTENSION_NOT_FOUND
;
1123 ret
= decode_ProxyCertInfo(e
->extnValue
.data
,
1124 e
->extnValue
.length
,
1128 hx509_clear_error_string(context
);
1131 if (size
!= e
->extnValue
.length
) {
1132 free_ProxyCertInfo(&info
);
1133 hx509_clear_error_string(context
);
1134 return HX509_EXTRA_DATA_AFTER_STRUCTURE
;
1137 free_ProxyCertInfo(&info
);
1145 * Path operations are like MEMORY based keyset, but with exposed
1146 * internal so we can do easy searches.
1150 _hx509_path_append(hx509_context context
, hx509_path
*path
, hx509_cert cert
)
1153 val
= realloc(path
->val
, (path
->len
+ 1) * sizeof(path
->val
[0]));
1155 hx509_set_error_string(context
, 0, ENOMEM
, "out of memory");
1160 path
->val
[path
->len
] = hx509_cert_ref(cert
);
1167 _hx509_path_free(hx509_path
*path
)
1171 for (i
= 0; i
< path
->len
; i
++)
1172 hx509_cert_free(path
->val
[i
]);
1179 * Find path by looking up issuer for the top certificate and continue
1180 * until an anchor certificate is found or max limit is found. A
1181 * certificate never included twice in the path.
1183 * If the trust anchors are not given, calculate optimistic path, just
1184 * follow the chain upward until we no longer find a parent or we hit
1185 * the max path limit. In this case, a failure will always be returned
1186 * depending on what error condition is hit first.
1188 * The path includes a path from the top certificate to the anchor
1191 * The caller needs to free `path´ both on successful built path and
1196 _hx509_calculate_path(hx509_context context
,
1199 hx509_certs anchors
,
1200 unsigned int max_depth
,
1205 hx509_cert parent
, current
;
1209 max_depth
= HX509_VERIFY_MAX_DEPTH
;
1211 ret
= _hx509_path_append(context
, path
, cert
);
1215 current
= hx509_cert_ref(cert
);
1217 while (!certificate_is_anchor(context
, anchors
, current
)) {
1219 ret
= find_parent(context
, time_now
, anchors
, path
,
1220 pool
, current
, &parent
);
1221 hx509_cert_free(current
);
1225 ret
= _hx509_path_append(context
, path
, parent
);
1230 if (path
->len
> max_depth
) {
1231 hx509_cert_free(current
);
1232 hx509_set_error_string(context
, 0, HX509_PATH_TOO_LONG
,
1233 "Path too long while bulding "
1234 "certificate chain");
1235 return HX509_PATH_TOO_LONG
;
1239 if ((flags
& HX509_CALCULATE_PATH_NO_ANCHOR
) &&
1241 certificate_is_anchor(context
, anchors
, path
->val
[path
->len
- 1]))
1243 hx509_cert_free(path
->val
[path
->len
- 1]);
1247 hx509_cert_free(current
);
1252 _hx509_AlgorithmIdentifier_cmp(const AlgorithmIdentifier
*p
,
1253 const AlgorithmIdentifier
*q
)
1256 diff
= der_heim_oid_cmp(&p
->algorithm
, &q
->algorithm
);
1259 if (p
->parameters
) {
1261 return heim_any_cmp(p
->parameters
,
1274 _hx509_Certificate_cmp(const Certificate
*p
, const Certificate
*q
)
1277 diff
= der_heim_bit_string_cmp(&p
->signatureValue
, &q
->signatureValue
);
1280 diff
= _hx509_aAlgorithmIdentifier_cmp(&p
->signatureAlgorithm
,
1281 &q
->signatureAlgorithm
);
1284 diff
= der_heim_octet_string_cmp(&p
->tbsCertificate
._save
,
1285 &q
->tbsCertificate
._save
);
1290 * Compare to hx509 certificate object, useful for sorting.
1292 * @param p a hx509 certificate object.
1293 * @param q a hx509 certificate object.
1295 * @return 0 the objects are the same, returns > 0 is p is "larger"
1296 * then q, < 0 if p is "smaller" then q.
1298 * @ingroup hx509_cert
1302 hx509_cert_cmp(hx509_cert p
, hx509_cert q
)
1304 return _hx509_Certificate_cmp(p
->data
, q
->data
);
1308 * Return the name of the issuer of the hx509 certificate.
1310 * @param p a hx509 certificate object.
1311 * @param name a pointer to a hx509 name, should be freed by
1312 * hx509_name_free().
1314 * @return An hx509 error code, see hx509_get_error_string().
1316 * @ingroup hx509_cert
1320 hx509_cert_get_issuer(hx509_cert p
, hx509_name
*name
)
1322 return _hx509_name_from_Name(&p
->data
->tbsCertificate
.issuer
, name
);
1326 * Return the name of the subject of the hx509 certificate.
1328 * @param p a hx509 certificate object.
1329 * @param name a pointer to a hx509 name, should be freed by
1330 * hx509_name_free(). See also hx509_cert_get_base_subject().
1332 * @return An hx509 error code, see hx509_get_error_string().
1334 * @ingroup hx509_cert
1338 hx509_cert_get_subject(hx509_cert p
, hx509_name
*name
)
1340 return _hx509_name_from_Name(&p
->data
->tbsCertificate
.subject
, name
);
1344 * Return the name of the base subject of the hx509 certificate. If
1345 * the certiicate is a verified proxy certificate, the this function
1346 * return the base certificate (root of the proxy chain). If the proxy
1347 * certificate is not verified with the base certificate
1348 * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned.
1350 * @param context a hx509 context.
1351 * @param c a hx509 certificate object.
1352 * @param name a pointer to a hx509 name, should be freed by
1353 * hx509_name_free(). See also hx509_cert_get_subject().
1355 * @return An hx509 error code, see hx509_get_error_string().
1357 * @ingroup hx509_cert
1361 hx509_cert_get_base_subject(hx509_context context
, hx509_cert c
,
1365 return hx509_name_copy(context
, c
->basename
, name
);
1366 if (is_proxy_cert(context
, c
->data
, NULL
) == 0) {
1367 int ret
= HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED
;
1368 hx509_set_error_string(context
, 0, ret
,
1369 "Proxy certificate have not been "
1370 "canonicalize yet, no base name");
1373 return _hx509_name_from_Name(&c
->data
->tbsCertificate
.subject
, name
);
1377 * Get serial number of the certificate.
1379 * @param p a hx509 certificate object.
1380 * @param i serial number, should be freed ith der_free_heim_integer().
1382 * @return An hx509 error code, see hx509_get_error_string().
1384 * @ingroup hx509_cert
1388 hx509_cert_get_serialnumber(hx509_cert p
, heim_integer
*i
)
1390 return der_copy_heim_integer(&p
->data
->tbsCertificate
.serialNumber
, i
);
1394 * Get notBefore time of the certificate.
1396 * @param p a hx509 certificate object.
1398 * @return return not before time
1400 * @ingroup hx509_cert
1404 hx509_cert_get_notBefore(hx509_cert p
)
1406 return _hx509_Time2time_t(&p
->data
->tbsCertificate
.validity
.notBefore
);
1410 * Get notAfter time of the certificate.
1412 * @param p a hx509 certificate object.
1414 * @return return not after time.
1416 * @ingroup hx509_cert
1420 hx509_cert_get_notAfter(hx509_cert p
)
1422 return _hx509_Time2time_t(&p
->data
->tbsCertificate
.validity
.notAfter
);
1426 * Get the SubjectPublicKeyInfo structure from the hx509 certificate.
1428 * @param context a hx509 context.
1429 * @param p a hx509 certificate object.
1430 * @param spki SubjectPublicKeyInfo, should be freed with
1431 * free_SubjectPublicKeyInfo().
1433 * @return An hx509 error code, see hx509_get_error_string().
1435 * @ingroup hx509_cert
1439 hx509_cert_get_SPKI(hx509_context context
, hx509_cert p
, SubjectPublicKeyInfo
*spki
)
1443 ret
= copy_SubjectPublicKeyInfo(&p
->data
->tbsCertificate
.subjectPublicKeyInfo
, spki
);
1445 hx509_set_error_string(context
, 0, ret
, "Failed to copy SPKI");
1450 * Get the AlgorithmIdentifier from the hx509 certificate.
1452 * @param context a hx509 context.
1453 * @param p a hx509 certificate object.
1454 * @param alg AlgorithmIdentifier, should be freed with
1455 * free_AlgorithmIdentifier().
1457 * @return An hx509 error code, see hx509_get_error_string().
1459 * @ingroup hx509_cert
1463 hx509_cert_get_SPKI_AlgorithmIdentifier(hx509_context context
,
1465 AlgorithmIdentifier
*alg
)
1469 ret
= copy_AlgorithmIdentifier(&p
->data
->tbsCertificate
.subjectPublicKeyInfo
.algorithm
, alg
);
1471 hx509_set_error_string(context
, 0, ret
,
1472 "Failed to copy SPKI AlgorithmIdentifier");
1478 _hx509_cert_private_key(hx509_cert p
)
1480 return p
->private_key
;
1484 hx509_cert_have_private_key(hx509_cert p
)
1486 return p
->private_key
? 1 : 0;
1491 _hx509_cert_private_key_exportable(hx509_cert p
)
1493 if (p
->private_key
== NULL
)
1495 return _hx509_private_key_exportable(p
->private_key
);
1499 _hx509_cert_private_decrypt(hx509_context context
,
1500 const heim_octet_string
*ciphertext
,
1501 const heim_oid
*encryption_oid
,
1503 heim_octet_string
*cleartext
)
1505 cleartext
->data
= NULL
;
1506 cleartext
->length
= 0;
1508 if (p
->private_key
== NULL
) {
1509 hx509_set_error_string(context
, 0, HX509_PRIVATE_KEY_MISSING
,
1510 "Private key missing");
1511 return HX509_PRIVATE_KEY_MISSING
;
1514 return _hx509_private_key_private_decrypt(context
,
1522 _hx509_cert_public_encrypt(hx509_context context
,
1523 const heim_octet_string
*cleartext
,
1525 heim_oid
*encryption_oid
,
1526 heim_octet_string
*ciphertext
)
1528 return _hx509_public_encrypt(context
,
1530 encryption_oid
, ciphertext
);
1538 _hx509_Time2time_t(const Time
*t
)
1540 switch(t
->element
) {
1541 case choice_Time_utcTime
:
1542 return t
->u
.utcTime
;
1543 case choice_Time_generalTime
:
1544 return t
->u
.generalTime
;
1554 init_name_constraints(hx509_name_constraints
*nc
)
1556 memset(nc
, 0, sizeof(*nc
));
1561 add_name_constraints(hx509_context context
, const Certificate
*c
, int not_ca
,
1562 hx509_name_constraints
*nc
)
1564 NameConstraints tnc
;
1567 ret
= find_extension_name_constraints(c
, &tnc
);
1568 if (ret
== HX509_EXTENSION_NOT_FOUND
)
1571 hx509_set_error_string(context
, 0, ret
, "Failed getting NameConstraints");
1573 } else if (not_ca
) {
1574 ret
= HX509_VERIFY_CONSTRAINTS
;
1575 hx509_set_error_string(context
, 0, ret
, "Not a CA and "
1576 "have NameConstraints");
1578 NameConstraints
*val
;
1579 val
= realloc(nc
->val
, sizeof(nc
->val
[0]) * (nc
->len
+ 1));
1581 hx509_clear_error_string(context
);
1586 ret
= copy_NameConstraints(&tnc
, &nc
->val
[nc
->len
]);
1588 hx509_clear_error_string(context
);
1594 free_NameConstraints(&tnc
);
1599 match_RDN(const RelativeDistinguishedName
*c
,
1600 const RelativeDistinguishedName
*n
)
1604 if (c
->len
!= n
->len
)
1605 return HX509_NAME_CONSTRAINT_ERROR
;
1607 for (i
= 0; i
< n
->len
; i
++) {
1608 if (der_heim_oid_cmp(&c
->val
[i
].type
, &n
->val
[i
].type
) != 0)
1609 return HX509_NAME_CONSTRAINT_ERROR
;
1610 if (_hx509_name_ds_cmp(&c
->val
[i
].value
, &n
->val
[i
].value
) != 0)
1611 return HX509_NAME_CONSTRAINT_ERROR
;
1617 match_X501Name(const Name
*c
, const Name
*n
)
1621 if (c
->element
!= choice_Name_rdnSequence
1622 || n
->element
!= choice_Name_rdnSequence
)
1624 if (c
->u
.rdnSequence
.len
> n
->u
.rdnSequence
.len
)
1625 return HX509_NAME_CONSTRAINT_ERROR
;
1626 for (i
= 0; i
< c
->u
.rdnSequence
.len
; i
++) {
1627 ret
= match_RDN(&c
->u
.rdnSequence
.val
[i
], &n
->u
.rdnSequence
.val
[i
]);
1636 match_general_name(const GeneralName
*c
, const GeneralName
*n
, int *match
)
1639 * Name constraints only apply to the same name type, see RFC3280,
1642 assert(c
->element
== n
->element
);
1644 switch(c
->element
) {
1645 case choice_GeneralName_otherName
:
1646 if (der_heim_oid_cmp(&c
->u
.otherName
.type_id
,
1647 &n
->u
.otherName
.type_id
) != 0)
1648 return HX509_NAME_CONSTRAINT_ERROR
;
1649 if (heim_any_cmp(&c
->u
.otherName
.value
,
1650 &n
->u
.otherName
.value
) != 0)
1651 return HX509_NAME_CONSTRAINT_ERROR
;
1654 case choice_GeneralName_rfc822Name
: {
1657 s
= strchr(c
->u
.rfc822Name
, '@');
1659 if (strcasecmp(c
->u
.rfc822Name
, n
->u
.rfc822Name
) != 0)
1660 return HX509_NAME_CONSTRAINT_ERROR
;
1662 s
= strchr(n
->u
.rfc822Name
, '@');
1664 return HX509_NAME_CONSTRAINT_ERROR
;
1665 len1
= strlen(c
->u
.rfc822Name
);
1666 len2
= strlen(s
+ 1);
1668 return HX509_NAME_CONSTRAINT_ERROR
;
1669 if (strcasecmp(s
+ 1 + len2
- len1
, c
->u
.rfc822Name
) != 0)
1670 return HX509_NAME_CONSTRAINT_ERROR
;
1671 if (len1
< len2
&& s
[len2
- len1
+ 1] != '.')
1672 return HX509_NAME_CONSTRAINT_ERROR
;
1677 case choice_GeneralName_dNSName
: {
1680 lenc
= strlen(c
->u
.dNSName
);
1681 lenn
= strlen(n
->u
.dNSName
);
1683 return HX509_NAME_CONSTRAINT_ERROR
;
1684 if (strcasecmp(&n
->u
.dNSName
[lenn
- lenc
], c
->u
.dNSName
) != 0)
1685 return HX509_NAME_CONSTRAINT_ERROR
;
1686 if (lenc
!= lenn
&& n
->u
.dNSName
[lenn
- lenc
- 1] != '.')
1687 return HX509_NAME_CONSTRAINT_ERROR
;
1691 case choice_GeneralName_directoryName
: {
1692 Name c_name
, n_name
;
1695 c_name
._save
.data
= NULL
;
1696 c_name
._save
.length
= 0;
1697 c_name
.element
= c
->u
.directoryName
.element
;
1698 c_name
.u
.rdnSequence
= c
->u
.directoryName
.u
.rdnSequence
;
1700 n_name
._save
.data
= NULL
;
1701 n_name
._save
.length
= 0;
1702 n_name
.element
= n
->u
.directoryName
.element
;
1703 n_name
.u
.rdnSequence
= n
->u
.directoryName
.u
.rdnSequence
;
1705 ret
= match_X501Name(&c_name
, &n_name
);
1710 case choice_GeneralName_uniformResourceIdentifier
:
1711 case choice_GeneralName_iPAddress
:
1712 case choice_GeneralName_registeredID
:
1714 return HX509_NAME_CONSTRAINT_ERROR
;
1719 match_alt_name(const GeneralName
*n
, const Certificate
*c
,
1720 int *same
, int *match
)
1727 ret
= find_extension_subject_alt_name(c
, &i
, &sa
);
1728 if (ret
== HX509_EXTENSION_NOT_FOUND
) {
1731 } else if (ret
!= 0)
1734 for (j
= 0; j
< sa
.len
; j
++) {
1735 if (n
->element
== sa
.val
[j
].element
) {
1737 ret
= match_general_name(n
, &sa
.val
[j
], match
);
1740 free_GeneralNames(&sa
);
1747 match_tree(const GeneralSubtrees
*t
, const Certificate
*c
, int *match
)
1749 int name
, alt_name
, same
;
1753 name
= alt_name
= same
= *match
= 0;
1754 for (i
= 0; i
< t
->len
; i
++) {
1755 if (t
->val
[i
].minimum
&& t
->val
[i
].maximum
)
1759 * If the constraint apply to directoryNames, test is with
1760 * subjectName of the certificate if the certificate have a
1761 * non-null (empty) subjectName.
1764 if (t
->val
[i
].base
.element
== choice_GeneralName_directoryName
1765 && !subject_null_p(c
))
1767 GeneralName certname
;
1769 memset(&certname
, 0, sizeof(certname
));
1770 certname
.element
= choice_GeneralName_directoryName
;
1771 certname
.u
.directoryName
.element
=
1772 c
->tbsCertificate
.subject
.element
;
1773 certname
.u
.directoryName
.u
.rdnSequence
=
1774 c
->tbsCertificate
.subject
.u
.rdnSequence
;
1776 ret
= match_general_name(&t
->val
[i
].base
, &certname
, &name
);
1779 /* Handle subjectAltNames, this is icky since they
1780 * restrictions only apply if the subjectAltName is of the
1781 * same type. So if there have been a match of type, require
1782 * altname to be set.
1784 ret
= match_alt_name(&t
->val
[i
].base
, c
, &same
, &alt_name
);
1786 if (name
&& (!same
|| alt_name
))
1792 check_name_constraints(hx509_context context
,
1793 const hx509_name_constraints
*nc
,
1794 const Certificate
*c
)
1799 for (i
= 0 ; i
< nc
->len
; i
++) {
1802 if (nc
->val
[i
].permittedSubtrees
) {
1803 GeneralSubtrees_SET(&gs
, nc
->val
[i
].permittedSubtrees
);
1804 ret
= match_tree(&gs
, c
, &match
);
1806 hx509_clear_error_string(context
);
1809 /* allow null subjectNames, they wont matches anything */
1810 if (match
== 0 && !subject_null_p(c
)) {
1811 hx509_set_error_string(context
, 0, HX509_VERIFY_CONSTRAINTS
,
1812 "Error verify constraints, "
1813 "certificate didn't match any "
1814 "permitted subtree");
1815 return HX509_VERIFY_CONSTRAINTS
;
1818 if (nc
->val
[i
].excludedSubtrees
) {
1819 GeneralSubtrees_SET(&gs
, nc
->val
[i
].excludedSubtrees
);
1820 ret
= match_tree(&gs
, c
, &match
);
1822 hx509_clear_error_string(context
);
1826 hx509_set_error_string(context
, 0, HX509_VERIFY_CONSTRAINTS
,
1827 "Error verify constraints, "
1828 "certificate included in excluded "
1830 return HX509_VERIFY_CONSTRAINTS
;
1838 free_name_constraints(hx509_name_constraints
*nc
)
1842 for (i
= 0 ; i
< nc
->len
; i
++)
1843 free_NameConstraints(&nc
->val
[i
]);
1848 * Build and verify the path for the certificate to the trust anchor
1849 * specified in the verify context. The path is constructed from the
1850 * certificate, the pool and the trust anchors.
1852 * @param context A hx509 context.
1853 * @param ctx A hx509 verification context.
1854 * @param cert the certificate to build the path from.
1855 * @param pool A keyset of certificates to build the chain from.
1857 * @return An hx509 error code, see hx509_get_error_string().
1859 * @ingroup hx509_verify
1863 hx509_verify_path(hx509_context context
,
1864 hx509_verify_ctx ctx
,
1868 hx509_name_constraints nc
;
1871 const AlgorithmIdentifier
*alg_id
;
1873 int ret
, i
, proxy_cert_depth
, selfsigned_depth
;
1876 hx509_certs anchors
= NULL
;
1878 memset(&proxy_issuer
, 0, sizeof(proxy_issuer
));
1880 ret
= init_name_constraints(&nc
);
1887 if ((ctx
->flags
& HX509_VERIFY_CTX_F_TIME_SET
) == 0)
1888 ctx
->time_now
= time(NULL
);
1893 if (ctx
->trust_anchors
)
1894 anchors
= _hx509_certs_ref(ctx
->trust_anchors
);
1895 else if (context
->default_trust_anchors
&& ALLOW_DEF_TA(ctx
))
1896 anchors
= _hx509_certs_ref(context
->default_trust_anchors
);
1898 ret
= hx509_certs_init(context
, "MEMORY:no-TA", 0, NULL
, &anchors
);
1904 * Calculate the path from the certificate user presented to the
1907 ret
= _hx509_calculate_path(context
, 0, ctx
->time_now
,
1908 anchors
, ctx
->max_depth
,
1914 alg_id
= path
.val
[path
->len
- 1]->data
->tbsCertificate
.signature
;
1918 * Check CA and proxy certificate chain from the top of the
1919 * certificate chain. Also check certificate is valid with respect
1920 * to the current time.
1924 proxy_cert_depth
= 0;
1925 selfsigned_depth
= 0;
1927 if (ctx
->flags
& HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE
)
1932 for (i
= 0; i
< path
.len
; i
++) {
1936 c
= _hx509_get_cert(path
.val
[i
]);
1939 * Lets do some basic check on issuer like
1940 * keyUsage.keyCertSign and basicConstraints.cA bit depending
1941 * on what type of certificate this is.
1946 /* XXX make constants for keyusage */
1947 ret
= check_key_usage(context
, c
, 1 << 5,
1948 REQUIRE_RFC3280(ctx
) ? TRUE
: FALSE
);
1950 hx509_set_error_string(context
, HX509_ERROR_APPEND
, ret
,
1951 "Key usage missing from CA certificate");
1955 if (i
+ 1 != path
.len
&& certificate_is_self_signed(c
))
1962 if (is_proxy_cert(context
, c
, &info
) == 0) {
1965 if (info
.pCPathLenConstraint
!= NULL
&&
1966 *info
.pCPathLenConstraint
< i
)
1968 free_ProxyCertInfo(&info
);
1969 ret
= HX509_PATH_TOO_LONG
;
1970 hx509_set_error_string(context
, 0, ret
,
1971 "Proxy certificate chain "
1972 "longer then allowed");
1975 /* XXX MUST check info.proxyPolicy */
1976 free_ProxyCertInfo(&info
);
1979 if (find_extension(c
, oid_id_x509_ce_subjectAltName(), &j
)) {
1980 ret
= HX509_PROXY_CERT_INVALID
;
1981 hx509_set_error_string(context
, 0, ret
,
1982 "Proxy certificate have explicity "
1983 "forbidden subjectAltName");
1988 if (find_extension(c
, oid_id_x509_ce_issuerAltName(), &j
)) {
1989 ret
= HX509_PROXY_CERT_INVALID
;
1990 hx509_set_error_string(context
, 0, ret
,
1991 "Proxy certificate have explicity "
1992 "forbidden issuerAltName");
1997 * The subject name of the proxy certificate should be
1998 * CN=XXX,<proxy issuer>, prune of CN and check if its
1999 * the same over the whole chain of proxy certs and
2000 * then check with the EE cert when we get to it.
2003 if (proxy_cert_depth
) {
2004 ret
= _hx509_name_cmp(&proxy_issuer
, &c
->tbsCertificate
.subject
);
2006 ret
= HX509_PROXY_CERT_NAME_WRONG
;
2007 hx509_set_error_string(context
, 0, ret
,
2008 "Base proxy name not right");
2013 free_Name(&proxy_issuer
);
2015 ret
= copy_Name(&c
->tbsCertificate
.subject
, &proxy_issuer
);
2017 hx509_clear_error_string(context
);
2021 j
= proxy_issuer
.u
.rdnSequence
.len
;
2022 if (proxy_issuer
.u
.rdnSequence
.len
< 2
2023 || proxy_issuer
.u
.rdnSequence
.val
[j
- 1].len
> 1
2024 || der_heim_oid_cmp(&proxy_issuer
.u
.rdnSequence
.val
[j
- 1].val
[0].type
,
2025 oid_id_at_commonName()))
2027 ret
= HX509_PROXY_CERT_NAME_WRONG
;
2028 hx509_set_error_string(context
, 0, ret
,
2029 "Proxy name too short or "
2030 "does not have Common name "
2035 free_RelativeDistinguishedName(&proxy_issuer
.u
.rdnSequence
.val
[j
- 1]);
2036 proxy_issuer
.u
.rdnSequence
.len
-= 1;
2038 ret
= _hx509_name_cmp(&proxy_issuer
, &c
->tbsCertificate
.issuer
);
2040 ret
= HX509_PROXY_CERT_NAME_WRONG
;
2041 hx509_set_error_string(context
, 0, ret
,
2042 "Proxy issuer name not as expected");
2049 * Now we are done with the proxy certificates, this
2050 * cert was an EE cert and we we will fall though to
2051 * EE checking below.
2059 * If there where any proxy certificates in the chain
2060 * (proxy_cert_depth > 0), check that the proxy issuer
2061 * matched proxy certificates "base" subject.
2063 if (proxy_cert_depth
) {
2065 ret
= _hx509_name_cmp(&proxy_issuer
,
2066 &c
->tbsCertificate
.subject
);
2068 ret
= HX509_PROXY_CERT_NAME_WRONG
;
2069 hx509_clear_error_string(context
);
2073 hx509_name_free(&cert
->basename
);
2075 ret
= _hx509_name_from_Name(&proxy_issuer
, &cert
->basename
);
2077 hx509_clear_error_string(context
);
2085 ret
= check_basic_constraints(context
, c
, type
,
2086 i
- proxy_cert_depth
- selfsigned_depth
);
2091 * Don't check the trust anchors expiration time since they
2092 * are transported out of band, from RFC3820.
2094 if (i
+ 1 != path
.len
|| CHECK_TA(ctx
)) {
2096 t
= _hx509_Time2time_t(&c
->tbsCertificate
.validity
.notBefore
);
2097 if (t
> ctx
->time_now
) {
2098 ret
= HX509_CERT_USED_BEFORE_TIME
;
2099 hx509_clear_error_string(context
);
2102 t
= _hx509_Time2time_t(&c
->tbsCertificate
.validity
.notAfter
);
2103 if (t
< ctx
->time_now
) {
2104 ret
= HX509_CERT_USED_AFTER_TIME
;
2105 hx509_clear_error_string(context
);
2110 if (type
== EE_CERT
)
2112 else if (type
== PROXY_CERT
)
2117 * Verify constraints, do this backward so path constraints are
2118 * checked in the right order.
2121 for (ret
= 0, i
= path
.len
- 1; i
>= 0; i
--) {
2124 c
= _hx509_get_cert(path
.val
[i
]);
2126 /* verify name constraints, not for selfsigned and anchor */
2127 if (!certificate_is_self_signed(c
) || i
+ 1 != path
.len
) {
2128 ret
= check_name_constraints(context
, &nc
, c
);
2133 ret
= add_name_constraints(context
, c
, i
== 0, &nc
);
2137 /* XXX verify all other silly constraints */
2142 * Verify that no certificates has been revoked.
2145 if (ctx
->revoke_ctx
) {
2148 ret
= hx509_certs_init(context
, "MEMORY:revoke-certs", 0,
2153 for (i
= 0; i
< path
.len
; i
++) {
2154 ret
= hx509_certs_add(context
, certs
, path
.val
[i
]);
2156 hx509_certs_free(&certs
);
2160 ret
= hx509_certs_merge(context
, certs
, pool
);
2162 hx509_certs_free(&certs
);
2166 for (i
= 0; i
< path
.len
- 1; i
++) {
2167 int parent
= (i
< path
.len
- 1) ? i
+ 1 : i
;
2169 ret
= hx509_revoke_verify(context
,
2176 hx509_certs_free(&certs
);
2180 hx509_certs_free(&certs
);
2184 * Verify signatures, do this backward so public key working
2185 * parameter is passed up from the anchor up though the chain.
2188 for (i
= path
.len
- 1; i
>= 0; i
--) {
2189 Certificate
*signer
, *c
;
2191 c
= _hx509_get_cert(path
.val
[i
]);
2193 /* is last in chain (trust anchor) */
2194 if (i
+ 1 == path
.len
) {
2195 signer
= path
.val
[i
]->data
;
2197 /* if trust anchor is not self signed, don't check sig */
2198 if (!certificate_is_self_signed(signer
))
2201 /* take next certificate in chain */
2202 signer
= path
.val
[i
+ 1]->data
;
2205 /* verify signatureValue */
2206 ret
= _hx509_verify_signature_bitstring(context
,
2208 &c
->signatureAlgorithm
,
2209 &c
->tbsCertificate
._save
,
2210 &c
->signatureValue
);
2212 hx509_set_error_string(context
, HX509_ERROR_APPEND
, ret
,
2213 "Failed to verify signature of certificate");
2219 hx509_certs_free(&anchors
);
2220 free_Name(&proxy_issuer
);
2221 free_name_constraints(&nc
);
2222 _hx509_path_free(&path
);
2228 * Verify a signature made using the private key of an certificate.
2230 * @param context A hx509 context.
2231 * @param signer the certificate that made the signature.
2232 * @param alg algorthm that was used to sign the data.
2233 * @param data the data that was signed.
2234 * @param sig the sigature to verify.
2236 * @return An hx509 error code, see hx509_get_error_string().
2238 * @ingroup hx509_crypto
2242 hx509_verify_signature(hx509_context context
,
2243 const hx509_cert signer
,
2244 const AlgorithmIdentifier
*alg
,
2245 const heim_octet_string
*data
,
2246 const heim_octet_string
*sig
)
2248 return _hx509_verify_signature(context
, signer
->data
, alg
, data
, sig
);
2253 * Verify that the certificate is allowed to be used for the hostname
2256 * @param context A hx509 context.
2257 * @param cert the certificate to match with
2258 * @param flags Flags to modify the behavior:
2259 * - HX509_VHN_F_ALLOW_NO_MATCH no match is ok
2260 * @param type type of hostname:
2261 * - HX509_HN_HOSTNAME for plain hostname.
2262 * - HX509_HN_DNSSRV for DNS SRV names.
2263 * @param hostname the hostname to check
2264 * @param sa address of the host
2265 * @param sa_size length of address
2267 * @return An hx509 error code, see hx509_get_error_string().
2269 * @ingroup hx509_cert
2273 hx509_verify_hostname(hx509_context context
,
2274 const hx509_cert cert
,
2276 hx509_hostname_type type
,
2277 const char *hostname
,
2278 const struct sockaddr
*sa
,
2279 /* XXX krb5_socklen_t */ int sa_size
)
2284 if (sa
&& sa_size
<= 0)
2287 memset(&san
, 0, sizeof(san
));
2291 ret
= find_extension_subject_alt_name(cert
->data
, &i
, &san
);
2292 if (ret
== HX509_EXTENSION_NOT_FOUND
) {
2295 } else if (ret
!= 0)
2298 for (j
= 0; j
< san
.len
; j
++) {
2299 switch (san
.val
[j
].element
) {
2300 case choice_GeneralName_dNSName
:
2301 if (strcasecmp(san
.val
[j
].u
.dNSName
, hostname
) == 0) {
2302 free_GeneralNames(&san
);
2310 free_GeneralNames(&san
);
2314 Name
*name
= &cert
->data
->tbsCertificate
.subject
;
2316 /* match if first component is a CN= */
2317 if (name
->u
.rdnSequence
.len
> 0
2318 && name
->u
.rdnSequence
.val
[0].len
== 1
2319 && der_heim_oid_cmp(&name
->u
.rdnSequence
.val
[0].val
[0].type
,
2320 oid_id_at_commonName()) == 0)
2322 DirectoryString
*ds
= &name
->u
.rdnSequence
.val
[0].val
[0].value
;
2324 switch (ds
->element
) {
2325 case choice_DirectoryString_printableString
:
2326 if (strcasecmp(ds
->u
.printableString
, hostname
) == 0)
2329 case choice_DirectoryString_ia5String
:
2330 if (strcasecmp(ds
->u
.ia5String
, hostname
) == 0)
2333 case choice_DirectoryString_utf8String
:
2334 if (strcasecmp(ds
->u
.utf8String
, hostname
) == 0)
2342 if ((flags
& HX509_VHN_F_ALLOW_NO_MATCH
) == 0)
2343 ret
= HX509_NAME_CONSTRAINT_ERROR
;
2349 _hx509_set_cert_attribute(hx509_context context
,
2351 const heim_oid
*oid
,
2352 const heim_octet_string
*attr
)
2354 hx509_cert_attribute a
;
2357 if (hx509_cert_get_attribute(cert
, oid
) != NULL
)
2360 d
= realloc(cert
->attrs
.val
,
2361 sizeof(cert
->attrs
.val
[0]) * (cert
->attrs
.len
+ 1));
2363 hx509_clear_error_string(context
);
2366 cert
->attrs
.val
= d
;
2368 a
= malloc(sizeof(*a
));
2372 der_copy_octet_string(attr
, &a
->data
);
2373 der_copy_oid(oid
, &a
->oid
);
2375 cert
->attrs
.val
[cert
->attrs
.len
] = a
;
2382 * Get an external attribute for the certificate, examples are
2383 * friendly name and id.
2385 * @param cert hx509 certificate object to search
2386 * @param oid an oid to search for.
2388 * @return an hx509_cert_attribute, only valid as long as the
2389 * certificate is referenced.
2391 * @ingroup hx509_cert
2394 hx509_cert_attribute
2395 hx509_cert_get_attribute(hx509_cert cert
, const heim_oid
*oid
)
2398 for (i
= 0; i
< cert
->attrs
.len
; i
++)
2399 if (der_heim_oid_cmp(oid
, &cert
->attrs
.val
[i
]->oid
) == 0)
2400 return cert
->attrs
.val
[i
];
2405 * Set the friendly name on the certificate.
2407 * @param cert The certificate to set the friendly name on
2408 * @param name Friendly name.
2410 * @return An hx509 error code, see hx509_get_error_string().
2412 * @ingroup hx509_cert
2416 hx509_cert_set_friendly_name(hx509_cert cert
, const char *name
)
2418 if (cert
->friendlyname
)
2419 free(cert
->friendlyname
);
2420 cert
->friendlyname
= strdup(name
);
2421 if (cert
->friendlyname
== NULL
)
2427 * Get friendly name of the certificate.
2429 * @param cert cert to get the friendly name from.
2431 * @return an friendly name or NULL if there is. The friendly name is
2432 * only valid as long as the certificate is referenced.
2434 * @ingroup hx509_cert
2438 hx509_cert_get_friendly_name(hx509_cert cert
)
2440 hx509_cert_attribute a
;
2441 PKCS9_friendlyName n
;
2445 if (cert
->friendlyname
)
2446 return cert
->friendlyname
;
2448 a
= hx509_cert_get_attribute(cert
, oid_id_pkcs_9_at_friendlyName());
2450 /* XXX use subject name ? */
2454 ret
= decode_PKCS9_friendlyName(a
->data
.data
, a
->data
.length
, &n
, &sz
);
2459 free_PKCS9_friendlyName(&n
);
2463 cert
->friendlyname
= malloc(n
.val
[0].length
+ 1);
2464 if (cert
->friendlyname
== NULL
) {
2465 free_PKCS9_friendlyName(&n
);
2469 for (i
= 0; i
< n
.val
[0].length
; i
++) {
2470 if (n
.val
[0].data
[i
] <= 0xff)
2471 cert
->friendlyname
[i
] = n
.val
[0].data
[i
] & 0xff;
2473 cert
->friendlyname
[i
] = 'X';
2475 cert
->friendlyname
[i
] = '\0';
2476 free_PKCS9_friendlyName(&n
);
2478 return cert
->friendlyname
;
2482 _hx509_query_clear(hx509_query
*q
)
2484 memset(q
, 0, sizeof(*q
));
2488 * Allocate an query controller. Free using hx509_query_free().
2490 * @param context A hx509 context.
2491 * @param q return pointer to a hx509_query.
2493 * @return An hx509 error code, see hx509_get_error_string().
2495 * @ingroup hx509_cert
2499 hx509_query_alloc(hx509_context context
, hx509_query
**q
)
2501 *q
= calloc(1, sizeof(**q
));
2508 * Set match options for the hx509 query controller.
2510 * @param q query controller.
2511 * @param option options to control the query controller.
2513 * @return An hx509 error code, see hx509_get_error_string().
2515 * @ingroup hx509_cert
2519 hx509_query_match_option(hx509_query
*q
, hx509_query_option option
)
2522 case HX509_QUERY_OPTION_PRIVATE_KEY
:
2523 q
->match
|= HX509_QUERY_PRIVATE_KEY
;
2525 case HX509_QUERY_OPTION_KU_ENCIPHERMENT
:
2526 q
->match
|= HX509_QUERY_KU_ENCIPHERMENT
;
2528 case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE
:
2529 q
->match
|= HX509_QUERY_KU_DIGITALSIGNATURE
;
2531 case HX509_QUERY_OPTION_KU_KEYCERTSIGN
:
2532 q
->match
|= HX509_QUERY_KU_KEYCERTSIGN
;
2534 case HX509_QUERY_OPTION_END
:
2541 * Set the issuer and serial number of match in the query
2542 * controller. The function make copies of the isser and serial number.
2544 * @param q a hx509 query controller
2545 * @param issuer issuer to search for
2546 * @param serialNumber the serialNumber of the issuer.
2548 * @return An hx509 error code, see hx509_get_error_string().
2550 * @ingroup hx509_cert
2554 hx509_query_match_issuer_serial(hx509_query
*q
,
2556 const heim_integer
*serialNumber
)
2560 der_free_heim_integer(q
->serial
);
2563 q
->serial
= malloc(sizeof(*q
->serial
));
2564 if (q
->serial
== NULL
)
2566 ret
= der_copy_heim_integer(serialNumber
, q
->serial
);
2572 if (q
->issuer_name
) {
2573 free_Name(q
->issuer_name
);
2574 free(q
->issuer_name
);
2576 q
->issuer_name
= malloc(sizeof(*q
->issuer_name
));
2577 if (q
->issuer_name
== NULL
)
2579 ret
= copy_Name(issuer
, q
->issuer_name
);
2581 free(q
->issuer_name
);
2582 q
->issuer_name
= NULL
;
2585 q
->match
|= HX509_QUERY_MATCH_SERIALNUMBER
|HX509_QUERY_MATCH_ISSUER_NAME
;
2590 * Set the query controller to match on a friendly name
2592 * @param q a hx509 query controller.
2593 * @param name a friendly name to match on
2595 * @return An hx509 error code, see hx509_get_error_string().
2597 * @ingroup hx509_cert
2601 hx509_query_match_friendly_name(hx509_query
*q
, const char *name
)
2603 if (q
->friendlyname
)
2604 free(q
->friendlyname
);
2605 q
->friendlyname
= strdup(name
);
2606 if (q
->friendlyname
== NULL
)
2608 q
->match
|= HX509_QUERY_MATCH_FRIENDLY_NAME
;
2613 * Set the query controller to match using a specific match function.
2615 * @param q a hx509 query controller.
2616 * @param func function to use for matching, if the argument is NULL,
2617 * the match function is removed.
2618 * @param ctx context passed to the function.
2620 * @return An hx509 error code, see hx509_get_error_string().
2622 * @ingroup hx509_cert
2626 hx509_query_match_cmp_func(hx509_query
*q
,
2627 int (*func
)(void *, hx509_cert
),
2631 q
->match
|= HX509_QUERY_MATCH_FUNCTION
;
2633 q
->match
&= ~HX509_QUERY_MATCH_FUNCTION
;
2635 q
->cmp_func_ctx
= ctx
;
2640 * Free the query controller.
2642 * @param context A hx509 context.
2643 * @param q a pointer to the query controller.
2645 * @ingroup hx509_cert
2649 hx509_query_free(hx509_context context
, hx509_query
*q
)
2652 der_free_heim_integer(q
->serial
);
2656 if (q
->issuer_name
) {
2657 free_Name(q
->issuer_name
);
2658 free(q
->issuer_name
);
2659 q
->issuer_name
= NULL
;
2662 free(q
->friendlyname
);
2663 memset(q
, 0, sizeof(*q
));
2669 _hx509_query_match_cert(hx509_context context
, const hx509_query
*q
, hx509_cert cert
)
2671 Certificate
*c
= _hx509_get_cert(cert
);
2673 _hx509_query_statistic(context
, 1, q
);
2675 if ((q
->match
& HX509_QUERY_FIND_ISSUER_CERT
) &&
2676 _hx509_cert_is_parent_cmp(q
->subject
, c
, 0) != 0)
2679 if ((q
->match
& HX509_QUERY_MATCH_CERTIFICATE
) &&
2680 _hx509_Certificate_cmp(q
->certificate
, c
) != 0)
2683 if ((q
->match
& HX509_QUERY_MATCH_SERIALNUMBER
)
2684 && der_heim_integer_cmp(&c
->tbsCertificate
.serialNumber
, q
->serial
) != 0)
2687 if ((q
->match
& HX509_QUERY_MATCH_ISSUER_NAME
)
2688 && _hx509_name_cmp(&c
->tbsCertificate
.issuer
, q
->issuer_name
) != 0)
2691 if ((q
->match
& HX509_QUERY_MATCH_SUBJECT_NAME
)
2692 && _hx509_name_cmp(&c
->tbsCertificate
.subject
, q
->subject_name
) != 0)
2695 if (q
->match
& HX509_QUERY_MATCH_SUBJECT_KEY_ID
) {
2696 SubjectKeyIdentifier si
;
2699 ret
= _hx509_find_extension_subject_key_id(c
, &si
);
2701 if (der_heim_octet_string_cmp(&si
, q
->subject_id
) != 0)
2703 free_SubjectKeyIdentifier(&si
);
2708 if ((q
->match
& HX509_QUERY_MATCH_ISSUER_ID
))
2710 if ((q
->match
& HX509_QUERY_PRIVATE_KEY
) &&
2711 _hx509_cert_private_key(cert
) == NULL
)
2716 if (q
->match
& HX509_QUERY_KU_DIGITALSIGNATURE
)
2718 if (q
->match
& HX509_QUERY_KU_NONREPUDIATION
)
2720 if (q
->match
& HX509_QUERY_KU_ENCIPHERMENT
)
2722 if (q
->match
& HX509_QUERY_KU_DATAENCIPHERMENT
)
2724 if (q
->match
& HX509_QUERY_KU_KEYAGREEMENT
)
2726 if (q
->match
& HX509_QUERY_KU_KEYCERTSIGN
)
2728 if (q
->match
& HX509_QUERY_KU_CRLSIGN
)
2730 if (ku
&& check_key_usage(context
, c
, ku
, TRUE
))
2733 if ((q
->match
& HX509_QUERY_ANCHOR
))
2736 if (q
->match
& HX509_QUERY_MATCH_LOCAL_KEY_ID
) {
2737 hx509_cert_attribute a
;
2739 a
= hx509_cert_get_attribute(cert
, oid_id_pkcs_9_at_localKeyId());
2742 if (der_heim_octet_string_cmp(&a
->data
, q
->local_key_id
) != 0)
2746 if (q
->match
& HX509_QUERY_NO_MATCH_PATH
) {
2749 for (i
= 0; i
< q
->path
->len
; i
++)
2750 if (hx509_cert_cmp(q
->path
->val
[i
], cert
) == 0)
2753 if (q
->match
& HX509_QUERY_MATCH_FRIENDLY_NAME
) {
2754 const char *name
= hx509_cert_get_friendly_name(cert
);
2757 if (strcasecmp(q
->friendlyname
, name
) != 0)
2760 if (q
->match
& HX509_QUERY_MATCH_FUNCTION
) {
2761 int ret
= (*q
->cmp_func
)(q
->cmp_func_ctx
, cert
);
2766 if (q
->match
& HX509_QUERY_MATCH_KEY_HASH_SHA1
) {
2767 heim_octet_string os
;
2770 os
.data
= c
->tbsCertificate
.subjectPublicKeyInfo
.subjectPublicKey
.data
;
2772 c
->tbsCertificate
.subjectPublicKeyInfo
.subjectPublicKey
.length
/ 8;
2774 ret
= _hx509_verify_signature(context
,
2776 hx509_signature_sha1(),
2783 if (q
->match
& HX509_QUERY_MATCH_TIME
) {
2785 t
= _hx509_Time2time_t(&c
->tbsCertificate
.validity
.notBefore
);
2788 t
= _hx509_Time2time_t(&c
->tbsCertificate
.validity
.notAfter
);
2793 if (q
->match
& ~HX509_QUERY_MASK
)
2800 * Set a statistic file for the query statistics.
2802 * @param context A hx509 context.
2803 * @param fn statistics file name
2805 * @ingroup hx509_cert
2809 hx509_query_statistic_file(hx509_context context
, const char *fn
)
2811 if (context
->querystat
)
2812 free(context
->querystat
);
2813 context
->querystat
= strdup(fn
);
2817 _hx509_query_statistic(hx509_context context
, int type
, const hx509_query
*q
)
2820 if (context
->querystat
== NULL
)
2822 f
= fopen(context
->querystat
, "a");
2825 fprintf(f
, "%d %d\n", type
, q
->match
);
2829 static const char *statname
[] = {
2831 "match serialnumber",
2832 "match issuer name",
2833 "match subject name",
2834 "match subject key id",
2838 "ku digitalsignature",
2841 "ku nonrepudiation",
2843 "ku dataencipherment",
2845 "match certificate",
2846 "match local key id",
2848 "match friendly name",
2850 "match key hash sha1",
2855 unsigned long stats
;
2861 stat_sort(const void *a
, const void *b
)
2863 const struct stat_el
*ae
= a
;
2864 const struct stat_el
*be
= b
;
2865 return be
->stats
- ae
->stats
;
2869 * Unparse the statistics file and print the result on a FILE descriptor.
2871 * @param context A hx509 context.
2872 * @param printtype tyep to print
2873 * @param out the FILE to write the data on.
2875 * @ingroup hx509_cert
2879 hx509_query_unparse_stats(hx509_context context
, int printtype
, FILE *out
)
2883 int type
, mask
, i
, num
;
2884 unsigned long multiqueries
= 0, totalqueries
= 0;
2885 struct stat_el stats
[32];
2887 if (context
->querystat
== NULL
)
2889 f
= fopen(context
->querystat
, "r");
2891 fprintf(out
, "No statistic file %s: %s.\n",
2892 context
->querystat
, strerror(errno
));
2896 for (i
= 0; i
< sizeof(stats
)/sizeof(stats
[0]); i
++) {
2901 while (fscanf(f
, "%d %d\n", &type
, &mask
) == 2) {
2902 if (type
!= printtype
)
2905 while (mask
&& i
< sizeof(stats
)/sizeof(stats
[0])) {
2919 qsort(stats
, sizeof(stats
)/sizeof(stats
[0]), sizeof(stats
[0]), stat_sort
);
2923 errx(1, "out of memory");
2925 rtbl_set_separator (t
, " ");
2927 rtbl_add_column_by_id (t
, 0, "Name", 0);
2928 rtbl_add_column_by_id (t
, 1, "Counter", 0);
2931 for (i
= 0; i
< sizeof(stats
)/sizeof(stats
[0]); i
++) {
2934 if (stats
[i
].index
< sizeof(statname
)/sizeof(statname
[0]))
2935 rtbl_add_column_entry_by_id (t
, 0, statname
[stats
[i
].index
]);
2937 snprintf(str
, sizeof(str
), "%d", stats
[i
].index
);
2938 rtbl_add_column_entry_by_id (t
, 0, str
);
2940 snprintf(str
, sizeof(str
), "%lu", stats
[i
].stats
);
2941 rtbl_add_column_entry_by_id (t
, 1, str
);
2944 rtbl_format(t
, out
);
2947 fprintf(out
, "\nQueries: multi %lu total %lu\n",
2948 multiqueries
, totalqueries
);
2952 * Check the extended key usage on the hx509 certificate.
2954 * @param context A hx509 context.
2955 * @param cert A hx509 context.
2956 * @param eku the EKU to check for
2957 * @param allow_any_eku if the any EKU is set, allow that to be a
2960 * @return An hx509 error code, see hx509_get_error_string().
2962 * @ingroup hx509_cert
2966 hx509_cert_check_eku(hx509_context context
, hx509_cert cert
,
2967 const heim_oid
*eku
, int allow_any_eku
)
2972 ret
= find_extension_eku(_hx509_get_cert(cert
), &e
);
2974 hx509_clear_error_string(context
);
2978 for (i
= 0; i
< e
.len
; i
++) {
2979 if (der_heim_oid_cmp(eku
, &e
.val
[i
]) == 0) {
2980 free_ExtKeyUsage(&e
);
2983 if (allow_any_eku
) {
2985 if (der_heim_oid_cmp(id_any_eku
, &e
.val
[i
]) == 0) {
2986 free_ExtKeyUsage(&e
);
2992 free_ExtKeyUsage(&e
);
2993 hx509_clear_error_string(context
);
2994 return HX509_CERTIFICATE_MISSING_EKU
;
2998 _hx509_cert_get_keyusage(hx509_context context
,
3007 memset(ku
, 0, sizeof(*ku
));
3009 cert
= _hx509_get_cert(c
);
3011 if (_hx509_cert_get_version(cert
) < 3)
3014 e
= find_extension(cert
, oid_id_x509_ce_keyUsage(), &i
);
3016 return HX509_KU_CERT_MISSING
;
3018 ret
= decode_KeyUsage(e
->extnValue
.data
, e
->extnValue
.length
, ku
, &size
);
3025 _hx509_cert_get_eku(hx509_context context
,
3031 memset(e
, 0, sizeof(*e
));
3033 ret
= find_extension_eku(_hx509_get_cert(cert
), e
);
3034 if (ret
&& ret
!= HX509_EXTENSION_NOT_FOUND
) {
3035 hx509_clear_error_string(context
);
3042 * Encodes the hx509 certificate as a DER encode binary.
3044 * @param context A hx509 context.
3045 * @param c the certificate to encode.
3046 * @param os the encode certificate, set to NULL, 0 on case of
3047 * error. Free the returned structure with hx509_xfree().
3049 * @return An hx509 error code, see hx509_get_error_string().
3051 * @ingroup hx509_cert
3055 hx509_cert_binary(hx509_context context
, hx509_cert c
, heim_octet_string
*os
)
3063 ASN1_MALLOC_ENCODE(Certificate
, os
->data
, os
->length
,
3064 _hx509_get_cert(c
), &size
, ret
);
3070 if (os
->length
!= size
)
3071 _hx509_abort("internal ASN.1 encoder error");
3077 * Last to avoid lost __attribute__s due to #undef.
3080 #undef __attribute__
3081 #define __attribute__(X)
3084 _hx509_abort(const char *fmt
, ...)
3085 __attribute__ ((noreturn
, format (printf
, 1, 2)))
3097 * Free a data element allocated in the library.
3099 * @param ptr data to be freed.
3101 * @ingroup hx509_misc
3105 hx509_xfree(void *ptr
)