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
35 __RCSID("$Heimdal: cert.c 22450 2008-01-15 19:39:14Z lha $"
37 #include "crypto-headers.h"
41 * @page page_cert The basic certificate
43 * The basic hx509 cerificate object in hx509 is hx509_cert. The
44 * hx509_cert object is representing one X509/PKIX certificate and
45 * associated attributes; like private key, friendly name, etc.
47 * A hx509_cert object is usully found via the keyset interfaces (@ref
48 * page_keyset), but its also possible to create a certificate
49 * directly from a parsed object with hx509_cert_init() and
50 * hx509_cert_init_data().
52 * See the library functions here: @ref hx509_cert
55 struct hx509_verify_ctx_data
{
56 hx509_certs trust_anchors
;
58 #define HX509_VERIFY_CTX_F_TIME_SET 1
59 #define HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE 2
60 #define HX509_VERIFY_CTX_F_REQUIRE_RFC3280 4
61 #define HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS 8
62 #define HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS 16
64 unsigned int max_depth
;
65 #define HX509_VERIFY_MAX_DEPTH 30
66 hx509_revoke_ctx revoke_ctx
;
69 #define REQUIRE_RFC3280(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_REQUIRE_RFC3280)
70 #define CHECK_TA(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS)
71 #define ALLOW_DEF_TA(ctx) (((ctx)->flags & HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS) == 0)
73 struct _hx509_cert_attrs
{
75 hx509_cert_attribute
*val
;
78 struct hx509_cert_data
{
82 hx509_private_key private_key
;
83 struct _hx509_cert_attrs attrs
;
85 _hx509_cert_release_func release
;
89 typedef struct hx509_name_constraints
{
92 } hx509_name_constraints
;
94 #define GeneralSubtrees_SET(g,var) \
95 (g)->len = (var)->len, (g)->val = (var)->val;
98 * Creates a hx509 context that most functions in the library
99 * uses. The context is only allowed to be used by one thread at each
100 * moment. Free the context with hx509_context_free().
102 * @param context Returns a pointer to new hx509 context.
104 * @return Returns an hx509 error code.
110 hx509_context_init(hx509_context
*context
)
112 *context
= calloc(1, sizeof(**context
));
113 if (*context
== NULL
)
116 _hx509_ks_null_register(*context
);
117 _hx509_ks_mem_register(*context
);
118 _hx509_ks_file_register(*context
);
119 _hx509_ks_pkcs12_register(*context
);
120 _hx509_ks_pkcs11_register(*context
);
121 _hx509_ks_dir_register(*context
);
122 _hx509_ks_keychain_register(*context
);
124 ENGINE_add_conf_module();
125 OpenSSL_add_all_algorithms();
127 (*context
)->ocsp_time_diff
= HX509_DEFAULT_OCSP_TIME_DIFF
;
129 initialize_hx_error_table_r(&(*context
)->et_list
);
130 initialize_asn1_error_table_r(&(*context
)->et_list
);
132 #ifdef HX509_DEFAULT_ANCHORS
133 (void)hx509_certs_init(*context
, HX509_DEFAULT_ANCHORS
, 0,
134 NULL
, &(*context
)->default_trust_anchors
);
141 * Selects if the hx509_revoke_verify() function is going to require
142 * the existans of a revokation method (OSCP, CRL) or not. Note that
143 * hx509_verify_path(), hx509_cms_verify_signed(), and other function
144 * call hx509_revoke_verify().
146 * @param context hx509 context to change the flag for.
147 * @param flag zero, revokation method required, non zero missing
148 * revokation method ok
150 * @ingroup hx509_verify
154 hx509_context_set_missing_revoke(hx509_context context
, int flag
)
157 context
->flags
|= HX509_CTX_VERIFY_MISSING_OK
;
159 context
->flags
&= ~HX509_CTX_VERIFY_MISSING_OK
;
163 * Free the context allocated by hx509_context_init().
165 * @param context context to be freed.
171 hx509_context_free(hx509_context
*context
)
173 hx509_clear_error_string(*context
);
174 if ((*context
)->ks_ops
) {
175 free((*context
)->ks_ops
);
176 (*context
)->ks_ops
= NULL
;
178 (*context
)->ks_num_ops
= 0;
179 free_error_table ((*context
)->et_list
);
180 if ((*context
)->querystat
)
181 free((*context
)->querystat
);
182 memset(*context
, 0, sizeof(**context
));
192 _hx509_get_cert(hx509_cert cert
)
202 _hx509_cert_get_version(const Certificate
*t
)
204 return t
->tbsCertificate
.version
? *t
->tbsCertificate
.version
+ 1 : 1;
208 * Allocate and init an hx509 certificate object from the decoded
211 * @param context A hx509 context.
215 * @return Returns an hx509 error code.
217 * @ingroup hx509_cert
221 hx509_cert_init(hx509_context context
, const Certificate
*c
, hx509_cert
*cert
)
225 *cert
= malloc(sizeof(**cert
));
229 (*cert
)->friendlyname
= NULL
;
230 (*cert
)->attrs
.len
= 0;
231 (*cert
)->attrs
.val
= NULL
;
232 (*cert
)->private_key
= NULL
;
233 (*cert
)->basename
= NULL
;
234 (*cert
)->release
= NULL
;
237 (*cert
)->data
= calloc(1, sizeof(*(*cert
)->data
));
238 if ((*cert
)->data
== NULL
) {
242 ret
= copy_Certificate(c
, (*cert
)->data
);
252 * Just like hx509_cert_init(), but instead of a decode certificate
253 * takes an pointer and length to a memory region that contains a
254 * DER/BER encoded certificate.
256 * If the memory region doesn't contain just the certificate and
257 * nothing more the function will fail with
258 * HX509_EXTRA_DATA_AFTER_STRUCTURE.
260 * @param context A hx509 context.
261 * @param ptr pointer to memory region containing encoded certificate.
262 * @param len length of memory region.
263 * @param cert a return pointer to a hx509 certificate object, will
264 * contain NULL on error.
266 * @return An hx509 error code, see hx509_get_error_string().
268 * @ingroup hx509_cert
272 hx509_cert_init_data(hx509_context context
,
281 ret
= decode_Certificate(ptr
, len
, &t
, &size
);
283 hx509_set_error_string(context
, 0, ret
, "Failed to decode certificate");
287 hx509_set_error_string(context
, 0, HX509_EXTRA_DATA_AFTER_STRUCTURE
,
288 "Extra data after certificate");
289 return HX509_EXTRA_DATA_AFTER_STRUCTURE
;
292 ret
= hx509_cert_init(context
, &t
, cert
);
293 free_Certificate(&t
);
298 _hx509_cert_set_release(hx509_cert cert
,
299 _hx509_cert_release_func release
,
302 cert
->release
= release
;
307 /* Doesn't make a copy of `private_key'. */
310 _hx509_cert_assign_key(hx509_cert cert
, hx509_private_key private_key
)
312 if (cert
->private_key
)
313 _hx509_private_key_free(&cert
->private_key
);
314 cert
->private_key
= _hx509_private_key_ref(private_key
);
319 * Free reference to the hx509 certificate object, if the refcounter
320 * reaches 0, the object if freed. Its allowed to pass in NULL.
322 * @param cert the cert to free.
324 * @ingroup hx509_cert
328 hx509_cert_free(hx509_cert cert
)
336 _hx509_abort("cert refcount <= 0 on free");
341 (cert
->release
)(cert
, cert
->ctx
);
343 if (cert
->private_key
)
344 _hx509_private_key_free(&cert
->private_key
);
346 free_Certificate(cert
->data
);
349 for (i
= 0; i
< cert
->attrs
.len
; i
++) {
350 der_free_octet_string(&cert
->attrs
.val
[i
]->data
);
351 der_free_oid(&cert
->attrs
.val
[i
]->oid
);
352 free(cert
->attrs
.val
[i
]);
354 free(cert
->attrs
.val
);
355 free(cert
->friendlyname
);
357 hx509_name_free(&cert
->basename
);
358 memset(cert
, 0, sizeof(cert
));
363 * Add a reference to a hx509 certificate object.
365 * @param cert a pointer to an hx509 certificate object.
367 * @return the same object as is passed in.
369 * @ingroup hx509_cert
373 hx509_cert_ref(hx509_cert cert
)
378 _hx509_abort("cert refcount <= 0");
381 _hx509_abort("cert refcount == 0");
386 * Allocate an verification context that is used fo control the
387 * verification process.
389 * @param context A hx509 context.
390 * @param ctx returns a pointer to a hx509_verify_ctx object.
392 * @return An hx509 error code, see hx509_get_error_string().
394 * @ingroup hx509_verify
398 hx509_verify_init_ctx(hx509_context context
, hx509_verify_ctx
*ctx
)
402 c
= calloc(1, sizeof(*c
));
406 c
->max_depth
= HX509_VERIFY_MAX_DEPTH
;
414 * Free an hx509 verification context.
416 * @param ctx the context to be freed.
418 * @ingroup hx509_verify
422 hx509_verify_destroy_ctx(hx509_verify_ctx ctx
)
425 hx509_certs_free(&ctx
->trust_anchors
);
426 hx509_revoke_free(&ctx
->revoke_ctx
);
427 memset(ctx
, 0, sizeof(*ctx
));
433 * Set the trust anchors in the verification context, makes an
434 * reference to the keyset, so the consumer can free the keyset
435 * independent of the destruction of the verification context (ctx).
437 * @param ctx a verification context
438 * @param set a keyset containing the trust anchors.
440 * @ingroup hx509_verify
444 hx509_verify_attach_anchors(hx509_verify_ctx ctx
, hx509_certs set
)
446 ctx
->trust_anchors
= _hx509_certs_ref(set
);
450 * Attach an revocation context to the verfication context, , makes an
451 * reference to the revoke context, so the consumer can free the
452 * revoke context independent of the destruction of the verification
453 * context. If there is no revoke context, the verification process is
454 * NOT going to check any verification status.
456 * @param ctx a verification context.
457 * @param revoke_ctx a revoke context.
459 * @ingroup hx509_verify
463 hx509_verify_attach_revoke(hx509_verify_ctx ctx
, hx509_revoke_ctx revoke_ctx
)
466 hx509_revoke_free(&ctx
->revoke_ctx
);
467 ctx
->revoke_ctx
= _hx509_revoke_ref(revoke_ctx
);
471 * Set the clock time the the verification process is going to
472 * use. Used to check certificate in the past and future time. If not
473 * set the current time will be used.
475 * @param ctx a verification context.
476 * @param t the time the verifiation is using.
479 * @ingroup hx509_verify
483 hx509_verify_set_time(hx509_verify_ctx ctx
, time_t t
)
485 ctx
->flags
|= HX509_VERIFY_CTX_F_TIME_SET
;
490 * Set the maximum depth of the certificate chain that the path
491 * builder is going to try.
493 * @param ctx a verification context
494 * @param max_depth maxium depth of the certificate chain, include
497 * @ingroup hx509_verify
501 hx509_verify_set_max_depth(hx509_verify_ctx ctx
, unsigned int max_depth
)
503 ctx
->max_depth
= max_depth
;
507 * Allow or deny the use of proxy certificates
509 * @param ctx a verification context
510 * @param boolean if non zero, allow proxy certificates.
512 * @ingroup hx509_verify
516 hx509_verify_set_proxy_certificate(hx509_verify_ctx ctx
, int boolean
)
519 ctx
->flags
|= HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE
;
521 ctx
->flags
&= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE
;
525 * Select strict RFC3280 verification of certificiates. This means
526 * checking key usage on CA certificates, this will make version 1
527 * certificiates unuseable.
529 * @param ctx a verification context
530 * @param boolean if non zero, use strict verification.
532 * @ingroup hx509_verify
536 hx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx
, int boolean
)
539 ctx
->flags
|= HX509_VERIFY_CTX_F_REQUIRE_RFC3280
;
541 ctx
->flags
&= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280
;
545 * Allow using the operating system builtin trust anchors if no other
546 * trust anchors are configured.
548 * @param ctx a verification context
549 * @param boolean if non zero, useing the operating systems builtin
553 * @return An hx509 error code, see hx509_get_error_string().
555 * @ingroup hx509_cert
559 hx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx
, int boolean
)
562 ctx
->flags
&= ~HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS
;
564 ctx
->flags
|= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS
;
567 static const Extension
*
568 find_extension(const Certificate
*cert
, const heim_oid
*oid
, int *idx
)
570 const TBSCertificate
*c
= &cert
->tbsCertificate
;
572 if (c
->version
== NULL
|| *c
->version
< 2 || c
->extensions
== NULL
)
575 for (;*idx
< c
->extensions
->len
; (*idx
)++) {
576 if (der_heim_oid_cmp(&c
->extensions
->val
[*idx
].extnID
, oid
) == 0)
577 return &c
->extensions
->val
[(*idx
)++];
583 find_extension_auth_key_id(const Certificate
*subject
,
584 AuthorityKeyIdentifier
*ai
)
590 memset(ai
, 0, sizeof(*ai
));
592 e
= find_extension(subject
, oid_id_x509_ce_authorityKeyIdentifier(), &i
);
594 return HX509_EXTENSION_NOT_FOUND
;
596 return decode_AuthorityKeyIdentifier(e
->extnValue
.data
,
602 _hx509_find_extension_subject_key_id(const Certificate
*issuer
,
603 SubjectKeyIdentifier
*si
)
609 memset(si
, 0, sizeof(*si
));
611 e
= find_extension(issuer
, oid_id_x509_ce_subjectKeyIdentifier(), &i
);
613 return HX509_EXTENSION_NOT_FOUND
;
615 return decode_SubjectKeyIdentifier(e
->extnValue
.data
,
621 find_extension_name_constraints(const Certificate
*subject
,
628 memset(nc
, 0, sizeof(*nc
));
630 e
= find_extension(subject
, oid_id_x509_ce_nameConstraints(), &i
);
632 return HX509_EXTENSION_NOT_FOUND
;
634 return decode_NameConstraints(e
->extnValue
.data
,
640 find_extension_subject_alt_name(const Certificate
*cert
, int *i
,
646 memset(sa
, 0, sizeof(*sa
));
648 e
= find_extension(cert
, oid_id_x509_ce_subjectAltName(), i
);
650 return HX509_EXTENSION_NOT_FOUND
;
652 return decode_GeneralNames(e
->extnValue
.data
,
658 find_extension_eku(const Certificate
*cert
, ExtKeyUsage
*eku
)
664 memset(eku
, 0, sizeof(*eku
));
666 e
= find_extension(cert
, oid_id_x509_ce_extKeyUsage(), &i
);
668 return HX509_EXTENSION_NOT_FOUND
;
670 return decode_ExtKeyUsage(e
->extnValue
.data
,
676 add_to_list(hx509_octet_string_list
*list
, const heim_octet_string
*entry
)
681 p
= realloc(list
->val
, (list
->len
+ 1) * sizeof(list
->val
[0]));
685 ret
= der_copy_octet_string(entry
, &list
->val
[list
->len
]);
693 * Free a list of octet strings returned by another hx509 library
696 * @param list list to be freed.
698 * @ingroup hx509_misc
702 hx509_free_octet_string_list(hx509_octet_string_list
*list
)
705 for (i
= 0; i
< list
->len
; i
++)
706 der_free_octet_string(&list
->val
[i
]);
713 * Return a list of subjectAltNames specified by oid in the
714 * certificate. On error the
716 * The returned list of octet string should be freed with
717 * hx509_free_octet_string_list().
719 * @param context A hx509 context.
720 * @param cert a hx509 certificate object.
721 * @param oid an oid to for SubjectAltName.
722 * @param list list of matching SubjectAltName.
724 * @return An hx509 error code, see hx509_get_error_string().
726 * @ingroup hx509_cert
730 hx509_cert_find_subjectAltName_otherName(hx509_context context
,
733 hx509_octet_string_list
*list
)
743 ret
= find_extension_subject_alt_name(_hx509_get_cert(cert
), &i
, &sa
);
745 if (ret
== HX509_EXTENSION_NOT_FOUND
) {
748 } else if (ret
!= 0) {
749 hx509_set_error_string(context
, 0, ret
, "Error searching for SAN");
750 hx509_free_octet_string_list(list
);
754 for (j
= 0; j
< sa
.len
; j
++) {
755 if (sa
.val
[j
].element
== choice_GeneralName_otherName
&&
756 der_heim_oid_cmp(&sa
.val
[j
].u
.otherName
.type_id
, oid
) == 0)
758 ret
= add_to_list(list
, &sa
.val
[j
].u
.otherName
.value
);
760 hx509_set_error_string(context
, 0, ret
,
761 "Error adding an exra SAN to "
763 hx509_free_octet_string_list(list
);
764 free_GeneralNames(&sa
);
769 free_GeneralNames(&sa
);
776 check_key_usage(hx509_context context
, const Certificate
*cert
,
777 unsigned flags
, int req_present
)
785 if (_hx509_cert_get_version(cert
) < 3)
788 e
= find_extension(cert
, oid_id_x509_ce_keyUsage(), &i
);
791 hx509_set_error_string(context
, 0, HX509_KU_CERT_MISSING
,
792 "Required extension key "
793 "usage missing from certifiate");
794 return HX509_KU_CERT_MISSING
;
799 ret
= decode_KeyUsage(e
->extnValue
.data
, e
->extnValue
.length
, &ku
, &size
);
802 ku_flags
= KeyUsage2int(ku
);
803 if ((ku_flags
& flags
) != flags
) {
804 unsigned missing
= (~ku_flags
) & flags
;
805 char buf
[256], *name
;
807 unparse_flags(missing
, asn1_KeyUsage_units(), buf
, sizeof(buf
));
808 _hx509_unparse_Name(&cert
->tbsCertificate
.subject
, &name
);
809 hx509_set_error_string(context
, 0, HX509_KU_CERT_MISSING
,
810 "Key usage %s required but missing "
811 "from certifiate %s", buf
, name
);
813 return HX509_KU_CERT_MISSING
;
819 * Return 0 on matching key usage 'flags' for 'cert', otherwise return
820 * an error code. If 'req_present' the existance is required of the
821 * KeyUsage extension.
825 _hx509_check_key_usage(hx509_context context
, hx509_cert cert
,
826 unsigned flags
, int req_present
)
828 return check_key_usage(context
, _hx509_get_cert(cert
), flags
, req_present
);
831 enum certtype
{ PROXY_CERT
, EE_CERT
, CA_CERT
};
834 check_basic_constraints(hx509_context context
, const Certificate
*cert
,
835 enum certtype type
, int depth
)
842 if (_hx509_cert_get_version(cert
) < 3)
845 e
= find_extension(cert
, oid_id_x509_ce_basicConstraints(), &i
);
853 ret
= _hx509_unparse_Name(&cert
->tbsCertificate
.subject
, &name
);
855 hx509_set_error_string(context
, 0, HX509_EXTENSION_NOT_FOUND
,
856 "basicConstraints missing from "
857 "CA certifiacte %s", name
);
859 return HX509_EXTENSION_NOT_FOUND
;
864 ret
= decode_BasicConstraints(e
->extnValue
.data
,
865 e
->extnValue
.length
, &bc
,
871 if (bc
.cA
!= NULL
&& *bc
.cA
)
872 ret
= HX509_PARENT_IS_CA
;
878 if (bc
.cA
== NULL
|| !*bc
.cA
)
879 ret
= HX509_PARENT_NOT_CA
;
880 else if (bc
.pathLenConstraint
)
881 if (depth
- 1 > *bc
.pathLenConstraint
)
882 ret
= HX509_CA_PATH_TOO_DEEP
;
885 free_BasicConstraints(&bc
);
890 _hx509_cert_is_parent_cmp(const Certificate
*subject
,
891 const Certificate
*issuer
,
892 int allow_self_signed
)
895 AuthorityKeyIdentifier ai
;
896 SubjectKeyIdentifier si
;
899 diff
= _hx509_name_cmp(&issuer
->tbsCertificate
.subject
,
900 &subject
->tbsCertificate
.issuer
);
904 memset(&ai
, 0, sizeof(ai
));
905 memset(&si
, 0, sizeof(si
));
908 * Try to find AuthorityKeyIdentifier, if it's not present in the
909 * subject certificate nor the parent.
912 ret_ai
= find_extension_auth_key_id(subject
, &ai
);
913 if (ret_ai
&& ret_ai
!= HX509_EXTENSION_NOT_FOUND
)
915 ret_si
= _hx509_find_extension_subject_key_id(issuer
, &si
);
916 if (ret_si
&& ret_si
!= HX509_EXTENSION_NOT_FOUND
)
919 if (ret_si
&& ret_ai
)
924 if (allow_self_signed
) {
927 } else if (ai
.keyIdentifier
) {
933 if (ai
.keyIdentifier
== NULL
) {
936 if (ai
.authorityCertIssuer
== NULL
)
938 if (ai
.authorityCertSerialNumber
== NULL
)
941 diff
= der_heim_integer_cmp(ai
.authorityCertSerialNumber
,
942 &issuer
->tbsCertificate
.serialNumber
);
945 if (ai
.authorityCertIssuer
->len
!= 1)
947 if (ai
.authorityCertIssuer
->val
[0].element
!= choice_GeneralName_directoryName
)
951 ai
.authorityCertIssuer
->val
[0].u
.directoryName
.element
;
953 ai
.authorityCertIssuer
->val
[0].u
.directoryName
.u
.rdnSequence
;
955 diff
= _hx509_name_cmp(&issuer
->tbsCertificate
.subject
,
961 diff
= der_heim_octet_string_cmp(ai
.keyIdentifier
, &si
);
966 free_AuthorityKeyIdentifier(&ai
);
967 free_SubjectKeyIdentifier(&si
);
972 certificate_is_anchor(hx509_context context
,
973 hx509_certs trust_anchors
,
974 const hx509_cert cert
)
980 if (trust_anchors
== NULL
)
983 _hx509_query_clear(&q
);
985 q
.match
= HX509_QUERY_MATCH_CERTIFICATE
;
986 q
.certificate
= _hx509_get_cert(cert
);
988 ret
= hx509_certs_find(context
, trust_anchors
, &q
, &c
);
995 certificate_is_self_signed(const Certificate
*cert
)
997 return _hx509_name_cmp(&cert
->tbsCertificate
.subject
,
998 &cert
->tbsCertificate
.issuer
) == 0;
1002 * The subjectName is "null" when it's empty set of relative DBs.
1006 subject_null_p(const Certificate
*c
)
1008 return c
->tbsCertificate
.subject
.u
.rdnSequence
.len
== 0;
1013 find_parent(hx509_context context
,
1015 hx509_certs trust_anchors
,
1021 AuthorityKeyIdentifier ai
;
1026 memset(&ai
, 0, sizeof(ai
));
1028 _hx509_query_clear(&q
);
1030 if (!subject_null_p(current
->data
)) {
1031 q
.match
|= HX509_QUERY_FIND_ISSUER_CERT
;
1032 q
.subject
= _hx509_get_cert(current
);
1034 ret
= find_extension_auth_key_id(current
->data
, &ai
);
1036 hx509_set_error_string(context
, 0, HX509_CERTIFICATE_MALFORMED
,
1037 "Subjectless certificate missing AuthKeyID");
1038 return HX509_CERTIFICATE_MALFORMED
;
1041 if (ai
.keyIdentifier
== NULL
) {
1042 free_AuthorityKeyIdentifier(&ai
);
1043 hx509_set_error_string(context
, 0, HX509_CERTIFICATE_MALFORMED
,
1044 "Subjectless certificate missing keyIdentifier "
1045 "inside AuthKeyID");
1046 return HX509_CERTIFICATE_MALFORMED
;
1049 q
.subject_id
= ai
.keyIdentifier
;
1050 q
.match
= HX509_QUERY_MATCH_SUBJECT_KEY_ID
;
1054 q
.match
|= HX509_QUERY_NO_MATCH_PATH
;
1057 q
.timenow
= time_now
;
1058 q
.match
|= HX509_QUERY_MATCH_TIME
;
1060 ret
= hx509_certs_find(context
, pool
, &q
, parent
);
1062 free_AuthorityKeyIdentifier(&ai
);
1065 q
.match
&= ~HX509_QUERY_MATCH_TIME
;
1068 if (trust_anchors
) {
1069 ret
= hx509_certs_find(context
, trust_anchors
, &q
, parent
);
1071 free_AuthorityKeyIdentifier(&ai
);
1075 free_AuthorityKeyIdentifier(&ai
);
1081 ret
= hx509_cert_get_subject(current
, &name
);
1083 hx509_clear_error_string(context
);
1084 return HX509_ISSUER_NOT_FOUND
;
1086 ret
= hx509_name_to_string(name
, &str
);
1087 hx509_name_free(&name
);
1089 hx509_clear_error_string(context
);
1090 return HX509_ISSUER_NOT_FOUND
;
1093 hx509_set_error_string(context
, 0, HX509_ISSUER_NOT_FOUND
,
1094 "Failed to find issuer for "
1095 "certificate with subject: '%s'", str
);
1098 return HX509_ISSUER_NOT_FOUND
;
1106 is_proxy_cert(hx509_context context
,
1107 const Certificate
*cert
,
1108 ProxyCertInfo
*rinfo
)
1116 memset(rinfo
, 0, sizeof(*rinfo
));
1118 e
= find_extension(cert
, oid_id_pkix_pe_proxyCertInfo(), &i
);
1120 hx509_clear_error_string(context
);
1121 return HX509_EXTENSION_NOT_FOUND
;
1124 ret
= decode_ProxyCertInfo(e
->extnValue
.data
,
1125 e
->extnValue
.length
,
1129 hx509_clear_error_string(context
);
1132 if (size
!= e
->extnValue
.length
) {
1133 free_ProxyCertInfo(&info
);
1134 hx509_clear_error_string(context
);
1135 return HX509_EXTRA_DATA_AFTER_STRUCTURE
;
1138 free_ProxyCertInfo(&info
);
1146 * Path operations are like MEMORY based keyset, but with exposed
1147 * internal so we can do easy searches.
1151 _hx509_path_append(hx509_context context
, hx509_path
*path
, hx509_cert cert
)
1154 val
= realloc(path
->val
, (path
->len
+ 1) * sizeof(path
->val
[0]));
1156 hx509_set_error_string(context
, 0, ENOMEM
, "out of memory");
1161 path
->val
[path
->len
] = hx509_cert_ref(cert
);
1168 _hx509_path_free(hx509_path
*path
)
1172 for (i
= 0; i
< path
->len
; i
++)
1173 hx509_cert_free(path
->val
[i
]);
1180 * Find path by looking up issuer for the top certificate and continue
1181 * until an anchor certificate is found or max limit is found. A
1182 * certificate never included twice in the path.
1184 * If the trust anchors are not given, calculate optimistic path, just
1185 * follow the chain upward until we no longer find a parent or we hit
1186 * the max path limit. In this case, a failure will always be returned
1187 * depending on what error condition is hit first.
1189 * The path includes a path from the top certificate to the anchor
1192 * The caller needs to free `path´ both on successful built path and
1197 _hx509_calculate_path(hx509_context context
,
1200 hx509_certs anchors
,
1201 unsigned int max_depth
,
1206 hx509_cert parent
, current
;
1210 max_depth
= HX509_VERIFY_MAX_DEPTH
;
1212 ret
= _hx509_path_append(context
, path
, cert
);
1216 current
= hx509_cert_ref(cert
);
1218 while (!certificate_is_anchor(context
, anchors
, current
)) {
1220 ret
= find_parent(context
, time_now
, anchors
, path
,
1221 pool
, current
, &parent
);
1222 hx509_cert_free(current
);
1226 ret
= _hx509_path_append(context
, path
, parent
);
1231 if (path
->len
> max_depth
) {
1232 hx509_cert_free(current
);
1233 hx509_set_error_string(context
, 0, HX509_PATH_TOO_LONG
,
1234 "Path too long while bulding "
1235 "certificate chain");
1236 return HX509_PATH_TOO_LONG
;
1240 if ((flags
& HX509_CALCULATE_PATH_NO_ANCHOR
) &&
1242 certificate_is_anchor(context
, anchors
, path
->val
[path
->len
- 1]))
1244 hx509_cert_free(path
->val
[path
->len
- 1]);
1248 hx509_cert_free(current
);
1253 _hx509_AlgorithmIdentifier_cmp(const AlgorithmIdentifier
*p
,
1254 const AlgorithmIdentifier
*q
)
1257 diff
= der_heim_oid_cmp(&p
->algorithm
, &q
->algorithm
);
1260 if (p
->parameters
) {
1262 return heim_any_cmp(p
->parameters
,
1275 _hx509_Certificate_cmp(const Certificate
*p
, const Certificate
*q
)
1278 diff
= der_heim_bit_string_cmp(&p
->signatureValue
, &q
->signatureValue
);
1281 diff
= _hx509_AlgorithmIdentifier_cmp(&p
->signatureAlgorithm
,
1282 &q
->signatureAlgorithm
);
1285 diff
= der_heim_octet_string_cmp(&p
->tbsCertificate
._save
,
1286 &q
->tbsCertificate
._save
);
1291 * Compare to hx509 certificate object, useful for sorting.
1293 * @param p a hx509 certificate object.
1294 * @param q a hx509 certificate object.
1296 * @return 0 the objects are the same, returns > 0 is p is "larger"
1297 * then q, < 0 if p is "smaller" then q.
1299 * @ingroup hx509_cert
1303 hx509_cert_cmp(hx509_cert p
, hx509_cert q
)
1305 return _hx509_Certificate_cmp(p
->data
, q
->data
);
1309 * Return the name of the issuer of the hx509 certificate.
1311 * @param p a hx509 certificate object.
1312 * @param name a pointer to a hx509 name, should be freed by
1313 * hx509_name_free().
1315 * @return An hx509 error code, see hx509_get_error_string().
1317 * @ingroup hx509_cert
1321 hx509_cert_get_issuer(hx509_cert p
, hx509_name
*name
)
1323 return _hx509_name_from_Name(&p
->data
->tbsCertificate
.issuer
, name
);
1327 * Return the name of the subject of the hx509 certificate.
1329 * @param p a hx509 certificate object.
1330 * @param name a pointer to a hx509 name, should be freed by
1331 * hx509_name_free(). See also hx509_cert_get_base_subject().
1333 * @return An hx509 error code, see hx509_get_error_string().
1335 * @ingroup hx509_cert
1339 hx509_cert_get_subject(hx509_cert p
, hx509_name
*name
)
1341 return _hx509_name_from_Name(&p
->data
->tbsCertificate
.subject
, name
);
1345 * Return the name of the base subject of the hx509 certificate. If
1346 * the certiicate is a verified proxy certificate, the this function
1347 * return the base certificate (root of the proxy chain). If the proxy
1348 * certificate is not verified with the base certificate
1349 * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned.
1351 * @param context a hx509 context.
1352 * @param c a hx509 certificate object.
1353 * @param name a pointer to a hx509 name, should be freed by
1354 * hx509_name_free(). See also hx509_cert_get_subject().
1356 * @return An hx509 error code, see hx509_get_error_string().
1358 * @ingroup hx509_cert
1362 hx509_cert_get_base_subject(hx509_context context
, hx509_cert c
,
1366 return hx509_name_copy(context
, c
->basename
, name
);
1367 if (is_proxy_cert(context
, c
->data
, NULL
) == 0) {
1368 int ret
= HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED
;
1369 hx509_set_error_string(context
, 0, ret
,
1370 "Proxy certificate have not been "
1371 "canonicalize yet, no base name");
1374 return _hx509_name_from_Name(&c
->data
->tbsCertificate
.subject
, name
);
1378 * Get serial number of the certificate.
1380 * @param p a hx509 certificate object.
1381 * @param i serial number, should be freed ith der_free_heim_integer().
1383 * @return An hx509 error code, see hx509_get_error_string().
1385 * @ingroup hx509_cert
1389 hx509_cert_get_serialnumber(hx509_cert p
, heim_integer
*i
)
1391 return der_copy_heim_integer(&p
->data
->tbsCertificate
.serialNumber
, i
);
1395 * Get notBefore time of the certificate.
1397 * @param p a hx509 certificate object.
1399 * @return return not before time
1401 * @ingroup hx509_cert
1405 hx509_cert_get_notBefore(hx509_cert p
)
1407 return _hx509_Time2time_t(&p
->data
->tbsCertificate
.validity
.notBefore
);
1411 * Get notAfter time of the certificate.
1413 * @param p a hx509 certificate object.
1415 * @return return not after time.
1417 * @ingroup hx509_cert
1421 hx509_cert_get_notAfter(hx509_cert p
)
1423 return _hx509_Time2time_t(&p
->data
->tbsCertificate
.validity
.notAfter
);
1427 * Get the SubjectPublicKeyInfo structure from the hx509 certificate.
1429 * @param context a hx509 context.
1430 * @param p a hx509 certificate object.
1431 * @param spki SubjectPublicKeyInfo, should be freed with
1432 * free_SubjectPublicKeyInfo().
1434 * @return An hx509 error code, see hx509_get_error_string().
1436 * @ingroup hx509_cert
1440 hx509_cert_get_SPKI(hx509_context context
, hx509_cert p
, SubjectPublicKeyInfo
*spki
)
1444 ret
= copy_SubjectPublicKeyInfo(&p
->data
->tbsCertificate
.subjectPublicKeyInfo
, spki
);
1446 hx509_set_error_string(context
, 0, ret
, "Failed to copy SPKI");
1451 * Get the AlgorithmIdentifier from the hx509 certificate.
1453 * @param context a hx509 context.
1454 * @param p a hx509 certificate object.
1455 * @param alg AlgorithmIdentifier, should be freed with
1456 * free_AlgorithmIdentifier().
1458 * @return An hx509 error code, see hx509_get_error_string().
1460 * @ingroup hx509_cert
1464 hx509_cert_get_SPKI_AlgorithmIdentifier(hx509_context context
,
1466 AlgorithmIdentifier
*alg
)
1470 ret
= copy_AlgorithmIdentifier(&p
->data
->tbsCertificate
.subjectPublicKeyInfo
.algorithm
, alg
);
1472 hx509_set_error_string(context
, 0, ret
,
1473 "Failed to copy SPKI AlgorithmIdentifier");
1479 _hx509_cert_private_key(hx509_cert p
)
1481 return p
->private_key
;
1485 hx509_cert_have_private_key(hx509_cert p
)
1487 return p
->private_key
? 1 : 0;
1492 _hx509_cert_private_key_exportable(hx509_cert p
)
1494 if (p
->private_key
== NULL
)
1496 return _hx509_private_key_exportable(p
->private_key
);
1500 _hx509_cert_private_decrypt(hx509_context context
,
1501 const heim_octet_string
*ciphertext
,
1502 const heim_oid
*encryption_oid
,
1504 heim_octet_string
*cleartext
)
1506 cleartext
->data
= NULL
;
1507 cleartext
->length
= 0;
1509 if (p
->private_key
== NULL
) {
1510 hx509_set_error_string(context
, 0, HX509_PRIVATE_KEY_MISSING
,
1511 "Private key missing");
1512 return HX509_PRIVATE_KEY_MISSING
;
1515 return _hx509_private_key_private_decrypt(context
,
1523 _hx509_cert_public_encrypt(hx509_context context
,
1524 const heim_octet_string
*cleartext
,
1526 heim_oid
*encryption_oid
,
1527 heim_octet_string
*ciphertext
)
1529 return _hx509_public_encrypt(context
,
1531 encryption_oid
, ciphertext
);
1539 _hx509_Time2time_t(const Time
*t
)
1541 switch(t
->element
) {
1542 case choice_Time_utcTime
:
1543 return t
->u
.utcTime
;
1544 case choice_Time_generalTime
:
1545 return t
->u
.generalTime
;
1555 init_name_constraints(hx509_name_constraints
*nc
)
1557 memset(nc
, 0, sizeof(*nc
));
1562 add_name_constraints(hx509_context context
, const Certificate
*c
, int not_ca
,
1563 hx509_name_constraints
*nc
)
1565 NameConstraints tnc
;
1568 ret
= find_extension_name_constraints(c
, &tnc
);
1569 if (ret
== HX509_EXTENSION_NOT_FOUND
)
1572 hx509_set_error_string(context
, 0, ret
, "Failed getting NameConstraints");
1574 } else if (not_ca
) {
1575 ret
= HX509_VERIFY_CONSTRAINTS
;
1576 hx509_set_error_string(context
, 0, ret
, "Not a CA and "
1577 "have NameConstraints");
1579 NameConstraints
*val
;
1580 val
= realloc(nc
->val
, sizeof(nc
->val
[0]) * (nc
->len
+ 1));
1582 hx509_clear_error_string(context
);
1587 ret
= copy_NameConstraints(&tnc
, &nc
->val
[nc
->len
]);
1589 hx509_clear_error_string(context
);
1595 free_NameConstraints(&tnc
);
1600 match_RDN(const RelativeDistinguishedName
*c
,
1601 const RelativeDistinguishedName
*n
)
1605 if (c
->len
!= n
->len
)
1606 return HX509_NAME_CONSTRAINT_ERROR
;
1608 for (i
= 0; i
< n
->len
; i
++) {
1609 if (der_heim_oid_cmp(&c
->val
[i
].type
, &n
->val
[i
].type
) != 0)
1610 return HX509_NAME_CONSTRAINT_ERROR
;
1611 if (_hx509_name_ds_cmp(&c
->val
[i
].value
, &n
->val
[i
].value
) != 0)
1612 return HX509_NAME_CONSTRAINT_ERROR
;
1618 match_X501Name(const Name
*c
, const Name
*n
)
1622 if (c
->element
!= choice_Name_rdnSequence
1623 || n
->element
!= choice_Name_rdnSequence
)
1625 if (c
->u
.rdnSequence
.len
> n
->u
.rdnSequence
.len
)
1626 return HX509_NAME_CONSTRAINT_ERROR
;
1627 for (i
= 0; i
< c
->u
.rdnSequence
.len
; i
++) {
1628 ret
= match_RDN(&c
->u
.rdnSequence
.val
[i
], &n
->u
.rdnSequence
.val
[i
]);
1637 match_general_name(const GeneralName
*c
, const GeneralName
*n
, int *match
)
1640 * Name constraints only apply to the same name type, see RFC3280,
1643 assert(c
->element
== n
->element
);
1645 switch(c
->element
) {
1646 case choice_GeneralName_otherName
:
1647 if (der_heim_oid_cmp(&c
->u
.otherName
.type_id
,
1648 &n
->u
.otherName
.type_id
) != 0)
1649 return HX509_NAME_CONSTRAINT_ERROR
;
1650 if (heim_any_cmp(&c
->u
.otherName
.value
,
1651 &n
->u
.otherName
.value
) != 0)
1652 return HX509_NAME_CONSTRAINT_ERROR
;
1655 case choice_GeneralName_rfc822Name
: {
1658 s
= strchr(c
->u
.rfc822Name
, '@');
1660 if (strcasecmp(c
->u
.rfc822Name
, n
->u
.rfc822Name
) != 0)
1661 return HX509_NAME_CONSTRAINT_ERROR
;
1663 s
= strchr(n
->u
.rfc822Name
, '@');
1665 return HX509_NAME_CONSTRAINT_ERROR
;
1666 len1
= strlen(c
->u
.rfc822Name
);
1667 len2
= strlen(s
+ 1);
1669 return HX509_NAME_CONSTRAINT_ERROR
;
1670 if (strcasecmp(s
+ 1 + len2
- len1
, c
->u
.rfc822Name
) != 0)
1671 return HX509_NAME_CONSTRAINT_ERROR
;
1672 if (len1
< len2
&& s
[len2
- len1
+ 1] != '.')
1673 return HX509_NAME_CONSTRAINT_ERROR
;
1678 case choice_GeneralName_dNSName
: {
1681 lenc
= strlen(c
->u
.dNSName
);
1682 lenn
= strlen(n
->u
.dNSName
);
1684 return HX509_NAME_CONSTRAINT_ERROR
;
1685 if (strcasecmp(&n
->u
.dNSName
[lenn
- lenc
], c
->u
.dNSName
) != 0)
1686 return HX509_NAME_CONSTRAINT_ERROR
;
1687 if (lenc
!= lenn
&& n
->u
.dNSName
[lenn
- lenc
- 1] != '.')
1688 return HX509_NAME_CONSTRAINT_ERROR
;
1692 case choice_GeneralName_directoryName
: {
1693 Name c_name
, n_name
;
1696 c_name
._save
.data
= NULL
;
1697 c_name
._save
.length
= 0;
1698 c_name
.element
= c
->u
.directoryName
.element
;
1699 c_name
.u
.rdnSequence
= c
->u
.directoryName
.u
.rdnSequence
;
1701 n_name
._save
.data
= NULL
;
1702 n_name
._save
.length
= 0;
1703 n_name
.element
= n
->u
.directoryName
.element
;
1704 n_name
.u
.rdnSequence
= n
->u
.directoryName
.u
.rdnSequence
;
1706 ret
= match_X501Name(&c_name
, &n_name
);
1711 case choice_GeneralName_uniformResourceIdentifier
:
1712 case choice_GeneralName_iPAddress
:
1713 case choice_GeneralName_registeredID
:
1715 return HX509_NAME_CONSTRAINT_ERROR
;
1720 match_alt_name(const GeneralName
*n
, const Certificate
*c
,
1721 int *same
, int *match
)
1728 ret
= find_extension_subject_alt_name(c
, &i
, &sa
);
1729 if (ret
== HX509_EXTENSION_NOT_FOUND
) {
1732 } else if (ret
!= 0)
1735 for (j
= 0; j
< sa
.len
; j
++) {
1736 if (n
->element
== sa
.val
[j
].element
) {
1738 ret
= match_general_name(n
, &sa
.val
[j
], match
);
1741 free_GeneralNames(&sa
);
1748 match_tree(const GeneralSubtrees
*t
, const Certificate
*c
, int *match
)
1750 int name
, alt_name
, same
;
1754 name
= alt_name
= same
= *match
= 0;
1755 for (i
= 0; i
< t
->len
; i
++) {
1756 if (t
->val
[i
].minimum
&& t
->val
[i
].maximum
)
1760 * If the constraint apply to directoryNames, test is with
1761 * subjectName of the certificate if the certificate have a
1762 * non-null (empty) subjectName.
1765 if (t
->val
[i
].base
.element
== choice_GeneralName_directoryName
1766 && !subject_null_p(c
))
1768 GeneralName certname
;
1770 memset(&certname
, 0, sizeof(certname
));
1771 certname
.element
= choice_GeneralName_directoryName
;
1772 certname
.u
.directoryName
.element
=
1773 c
->tbsCertificate
.subject
.element
;
1774 certname
.u
.directoryName
.u
.rdnSequence
=
1775 c
->tbsCertificate
.subject
.u
.rdnSequence
;
1777 ret
= match_general_name(&t
->val
[i
].base
, &certname
, &name
);
1780 /* Handle subjectAltNames, this is icky since they
1781 * restrictions only apply if the subjectAltName is of the
1782 * same type. So if there have been a match of type, require
1783 * altname to be set.
1785 ret
= match_alt_name(&t
->val
[i
].base
, c
, &same
, &alt_name
);
1787 if (name
&& (!same
|| alt_name
))
1793 check_name_constraints(hx509_context context
,
1794 const hx509_name_constraints
*nc
,
1795 const Certificate
*c
)
1800 for (i
= 0 ; i
< nc
->len
; i
++) {
1803 if (nc
->val
[i
].permittedSubtrees
) {
1804 GeneralSubtrees_SET(&gs
, nc
->val
[i
].permittedSubtrees
);
1805 ret
= match_tree(&gs
, c
, &match
);
1807 hx509_clear_error_string(context
);
1810 /* allow null subjectNames, they wont matches anything */
1811 if (match
== 0 && !subject_null_p(c
)) {
1812 hx509_set_error_string(context
, 0, HX509_VERIFY_CONSTRAINTS
,
1813 "Error verify constraints, "
1814 "certificate didn't match any "
1815 "permitted subtree");
1816 return HX509_VERIFY_CONSTRAINTS
;
1819 if (nc
->val
[i
].excludedSubtrees
) {
1820 GeneralSubtrees_SET(&gs
, nc
->val
[i
].excludedSubtrees
);
1821 ret
= match_tree(&gs
, c
, &match
);
1823 hx509_clear_error_string(context
);
1827 hx509_set_error_string(context
, 0, HX509_VERIFY_CONSTRAINTS
,
1828 "Error verify constraints, "
1829 "certificate included in excluded "
1831 return HX509_VERIFY_CONSTRAINTS
;
1839 free_name_constraints(hx509_name_constraints
*nc
)
1843 for (i
= 0 ; i
< nc
->len
; i
++)
1844 free_NameConstraints(&nc
->val
[i
]);
1849 * Build and verify the path for the certificate to the trust anchor
1850 * specified in the verify context. The path is constructed from the
1851 * certificate, the pool and the trust anchors.
1853 * @param context A hx509 context.
1854 * @param ctx A hx509 verification context.
1855 * @param cert the certificate to build the path from.
1856 * @param pool A keyset of certificates to build the chain from.
1858 * @return An hx509 error code, see hx509_get_error_string().
1860 * @ingroup hx509_verify
1864 hx509_verify_path(hx509_context context
,
1865 hx509_verify_ctx ctx
,
1869 hx509_name_constraints nc
;
1872 const AlgorithmIdentifier
*alg_id
;
1874 int ret
, i
, proxy_cert_depth
, selfsigned_depth
;
1877 hx509_certs anchors
= NULL
;
1879 memset(&proxy_issuer
, 0, sizeof(proxy_issuer
));
1881 ret
= init_name_constraints(&nc
);
1888 if ((ctx
->flags
& HX509_VERIFY_CTX_F_TIME_SET
) == 0)
1889 ctx
->time_now
= time(NULL
);
1894 if (ctx
->trust_anchors
)
1895 anchors
= _hx509_certs_ref(ctx
->trust_anchors
);
1896 else if (context
->default_trust_anchors
&& ALLOW_DEF_TA(ctx
))
1897 anchors
= _hx509_certs_ref(context
->default_trust_anchors
);
1899 ret
= hx509_certs_init(context
, "MEMORY:no-TA", 0, NULL
, &anchors
);
1905 * Calculate the path from the certificate user presented to the
1908 ret
= _hx509_calculate_path(context
, 0, ctx
->time_now
,
1909 anchors
, ctx
->max_depth
,
1915 alg_id
= path
.val
[path
->len
- 1]->data
->tbsCertificate
.signature
;
1919 * Check CA and proxy certificate chain from the top of the
1920 * certificate chain. Also check certificate is valid with respect
1921 * to the current time.
1925 proxy_cert_depth
= 0;
1926 selfsigned_depth
= 0;
1928 if (ctx
->flags
& HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE
)
1933 for (i
= 0; i
< path
.len
; i
++) {
1937 c
= _hx509_get_cert(path
.val
[i
]);
1940 * Lets do some basic check on issuer like
1941 * keyUsage.keyCertSign and basicConstraints.cA bit depending
1942 * on what type of certificate this is.
1947 /* XXX make constants for keyusage */
1948 ret
= check_key_usage(context
, c
, 1 << 5,
1949 REQUIRE_RFC3280(ctx
) ? TRUE
: FALSE
);
1951 hx509_set_error_string(context
, HX509_ERROR_APPEND
, ret
,
1952 "Key usage missing from CA certificate");
1956 if (i
+ 1 != path
.len
&& certificate_is_self_signed(c
))
1963 if (is_proxy_cert(context
, c
, &info
) == 0) {
1966 if (info
.pCPathLenConstraint
!= NULL
&&
1967 *info
.pCPathLenConstraint
< i
)
1969 free_ProxyCertInfo(&info
);
1970 ret
= HX509_PATH_TOO_LONG
;
1971 hx509_set_error_string(context
, 0, ret
,
1972 "Proxy certificate chain "
1973 "longer then allowed");
1976 /* XXX MUST check info.proxyPolicy */
1977 free_ProxyCertInfo(&info
);
1980 if (find_extension(c
, oid_id_x509_ce_subjectAltName(), &j
)) {
1981 ret
= HX509_PROXY_CERT_INVALID
;
1982 hx509_set_error_string(context
, 0, ret
,
1983 "Proxy certificate have explicity "
1984 "forbidden subjectAltName");
1989 if (find_extension(c
, oid_id_x509_ce_issuerAltName(), &j
)) {
1990 ret
= HX509_PROXY_CERT_INVALID
;
1991 hx509_set_error_string(context
, 0, ret
,
1992 "Proxy certificate have explicity "
1993 "forbidden issuerAltName");
1998 * The subject name of the proxy certificate should be
1999 * CN=XXX,<proxy issuer>, prune of CN and check if its
2000 * the same over the whole chain of proxy certs and
2001 * then check with the EE cert when we get to it.
2004 if (proxy_cert_depth
) {
2005 ret
= _hx509_name_cmp(&proxy_issuer
, &c
->tbsCertificate
.subject
);
2007 ret
= HX509_PROXY_CERT_NAME_WRONG
;
2008 hx509_set_error_string(context
, 0, ret
,
2009 "Base proxy name not right");
2014 free_Name(&proxy_issuer
);
2016 ret
= copy_Name(&c
->tbsCertificate
.subject
, &proxy_issuer
);
2018 hx509_clear_error_string(context
);
2022 j
= proxy_issuer
.u
.rdnSequence
.len
;
2023 if (proxy_issuer
.u
.rdnSequence
.len
< 2
2024 || proxy_issuer
.u
.rdnSequence
.val
[j
- 1].len
> 1
2025 || der_heim_oid_cmp(&proxy_issuer
.u
.rdnSequence
.val
[j
- 1].val
[0].type
,
2026 oid_id_at_commonName()))
2028 ret
= HX509_PROXY_CERT_NAME_WRONG
;
2029 hx509_set_error_string(context
, 0, ret
,
2030 "Proxy name too short or "
2031 "does not have Common name "
2036 free_RelativeDistinguishedName(&proxy_issuer
.u
.rdnSequence
.val
[j
- 1]);
2037 proxy_issuer
.u
.rdnSequence
.len
-= 1;
2039 ret
= _hx509_name_cmp(&proxy_issuer
, &c
->tbsCertificate
.issuer
);
2041 ret
= HX509_PROXY_CERT_NAME_WRONG
;
2042 hx509_set_error_string(context
, 0, ret
,
2043 "Proxy issuer name not as expected");
2050 * Now we are done with the proxy certificates, this
2051 * cert was an EE cert and we we will fall though to
2052 * EE checking below.
2060 * If there where any proxy certificates in the chain
2061 * (proxy_cert_depth > 0), check that the proxy issuer
2062 * matched proxy certificates "base" subject.
2064 if (proxy_cert_depth
) {
2066 ret
= _hx509_name_cmp(&proxy_issuer
,
2067 &c
->tbsCertificate
.subject
);
2069 ret
= HX509_PROXY_CERT_NAME_WRONG
;
2070 hx509_clear_error_string(context
);
2074 hx509_name_free(&cert
->basename
);
2076 ret
= _hx509_name_from_Name(&proxy_issuer
, &cert
->basename
);
2078 hx509_clear_error_string(context
);
2086 ret
= check_basic_constraints(context
, c
, type
,
2087 i
- proxy_cert_depth
- selfsigned_depth
);
2092 * Don't check the trust anchors expiration time since they
2093 * are transported out of band, from RFC3820.
2095 if (i
+ 1 != path
.len
|| CHECK_TA(ctx
)) {
2097 t
= _hx509_Time2time_t(&c
->tbsCertificate
.validity
.notBefore
);
2098 if (t
> ctx
->time_now
) {
2099 ret
= HX509_CERT_USED_BEFORE_TIME
;
2100 hx509_clear_error_string(context
);
2103 t
= _hx509_Time2time_t(&c
->tbsCertificate
.validity
.notAfter
);
2104 if (t
< ctx
->time_now
) {
2105 ret
= HX509_CERT_USED_AFTER_TIME
;
2106 hx509_clear_error_string(context
);
2111 if (type
== EE_CERT
)
2113 else if (type
== PROXY_CERT
)
2118 * Verify constraints, do this backward so path constraints are
2119 * checked in the right order.
2122 for (ret
= 0, i
= path
.len
- 1; i
>= 0; i
--) {
2125 c
= _hx509_get_cert(path
.val
[i
]);
2127 /* verify name constraints, not for selfsigned and anchor */
2128 if (!certificate_is_self_signed(c
) || i
+ 1 != path
.len
) {
2129 ret
= check_name_constraints(context
, &nc
, c
);
2134 ret
= add_name_constraints(context
, c
, i
== 0, &nc
);
2138 /* XXX verify all other silly constraints */
2143 * Verify that no certificates has been revoked.
2146 if (ctx
->revoke_ctx
) {
2149 ret
= hx509_certs_init(context
, "MEMORY:revoke-certs", 0,
2154 for (i
= 0; i
< path
.len
; i
++) {
2155 ret
= hx509_certs_add(context
, certs
, path
.val
[i
]);
2157 hx509_certs_free(&certs
);
2161 ret
= hx509_certs_merge(context
, certs
, pool
);
2163 hx509_certs_free(&certs
);
2167 for (i
= 0; i
< path
.len
- 1; i
++) {
2168 int parent
= (i
< path
.len
- 1) ? i
+ 1 : i
;
2170 ret
= hx509_revoke_verify(context
,
2177 hx509_certs_free(&certs
);
2181 hx509_certs_free(&certs
);
2185 * Verify signatures, do this backward so public key working
2186 * parameter is passed up from the anchor up though the chain.
2189 for (i
= path
.len
- 1; i
>= 0; i
--) {
2190 Certificate
*signer
, *c
;
2192 c
= _hx509_get_cert(path
.val
[i
]);
2194 /* is last in chain (trust anchor) */
2195 if (i
+ 1 == path
.len
) {
2196 signer
= path
.val
[i
]->data
;
2198 /* if trust anchor is not self signed, don't check sig */
2199 if (!certificate_is_self_signed(signer
))
2202 /* take next certificate in chain */
2203 signer
= path
.val
[i
+ 1]->data
;
2206 /* verify signatureValue */
2207 ret
= _hx509_verify_signature_bitstring(context
,
2209 &c
->signatureAlgorithm
,
2210 &c
->tbsCertificate
._save
,
2211 &c
->signatureValue
);
2213 hx509_set_error_string(context
, HX509_ERROR_APPEND
, ret
,
2214 "Failed to verify signature of certificate");
2220 hx509_certs_free(&anchors
);
2221 free_Name(&proxy_issuer
);
2222 free_name_constraints(&nc
);
2223 _hx509_path_free(&path
);
2229 * Verify a signature made using the private key of an certificate.
2231 * @param context A hx509 context.
2232 * @param signer the certificate that made the signature.
2233 * @param alg algorthm that was used to sign the data.
2234 * @param data the data that was signed.
2235 * @param sig the sigature to verify.
2237 * @return An hx509 error code, see hx509_get_error_string().
2239 * @ingroup hx509_crypto
2243 hx509_verify_signature(hx509_context context
,
2244 const hx509_cert signer
,
2245 const AlgorithmIdentifier
*alg
,
2246 const heim_octet_string
*data
,
2247 const heim_octet_string
*sig
)
2249 return _hx509_verify_signature(context
, signer
->data
, alg
, data
, sig
);
2254 * Verify that the certificate is allowed to be used for the hostname
2257 * @param context A hx509 context.
2258 * @param cert the certificate to match with
2259 * @param flags Flags to modify the behavior:
2260 * - HX509_VHN_F_ALLOW_NO_MATCH no match is ok
2261 * @param type type of hostname:
2262 * - HX509_HN_HOSTNAME for plain hostname.
2263 * - HX509_HN_DNSSRV for DNS SRV names.
2264 * @param hostname the hostname to check
2265 * @param sa address of the host
2266 * @param sa_size length of address
2268 * @return An hx509 error code, see hx509_get_error_string().
2270 * @ingroup hx509_cert
2274 hx509_verify_hostname(hx509_context context
,
2275 const hx509_cert cert
,
2277 hx509_hostname_type type
,
2278 const char *hostname
,
2279 const struct sockaddr
*sa
,
2280 /* XXX krb5_socklen_t */ int sa_size
)
2285 if (sa
&& sa_size
<= 0)
2288 memset(&san
, 0, sizeof(san
));
2292 ret
= find_extension_subject_alt_name(cert
->data
, &i
, &san
);
2293 if (ret
== HX509_EXTENSION_NOT_FOUND
) {
2296 } else if (ret
!= 0)
2299 for (j
= 0; j
< san
.len
; j
++) {
2300 switch (san
.val
[j
].element
) {
2301 case choice_GeneralName_dNSName
:
2302 if (strcasecmp(san
.val
[j
].u
.dNSName
, hostname
) == 0) {
2303 free_GeneralNames(&san
);
2311 free_GeneralNames(&san
);
2315 Name
*name
= &cert
->data
->tbsCertificate
.subject
;
2317 /* match if first component is a CN= */
2318 if (name
->u
.rdnSequence
.len
> 0
2319 && name
->u
.rdnSequence
.val
[0].len
== 1
2320 && der_heim_oid_cmp(&name
->u
.rdnSequence
.val
[0].val
[0].type
,
2321 oid_id_at_commonName()) == 0)
2323 DirectoryString
*ds
= &name
->u
.rdnSequence
.val
[0].val
[0].value
;
2325 switch (ds
->element
) {
2326 case choice_DirectoryString_printableString
:
2327 if (strcasecmp(ds
->u
.printableString
, hostname
) == 0)
2330 case choice_DirectoryString_ia5String
:
2331 if (strcasecmp(ds
->u
.ia5String
, hostname
) == 0)
2334 case choice_DirectoryString_utf8String
:
2335 if (strcasecmp(ds
->u
.utf8String
, hostname
) == 0)
2343 if ((flags
& HX509_VHN_F_ALLOW_NO_MATCH
) == 0)
2344 ret
= HX509_NAME_CONSTRAINT_ERROR
;
2350 _hx509_set_cert_attribute(hx509_context context
,
2352 const heim_oid
*oid
,
2353 const heim_octet_string
*attr
)
2355 hx509_cert_attribute a
;
2358 if (hx509_cert_get_attribute(cert
, oid
) != NULL
)
2361 d
= realloc(cert
->attrs
.val
,
2362 sizeof(cert
->attrs
.val
[0]) * (cert
->attrs
.len
+ 1));
2364 hx509_clear_error_string(context
);
2367 cert
->attrs
.val
= d
;
2369 a
= malloc(sizeof(*a
));
2373 der_copy_octet_string(attr
, &a
->data
);
2374 der_copy_oid(oid
, &a
->oid
);
2376 cert
->attrs
.val
[cert
->attrs
.len
] = a
;
2383 * Get an external attribute for the certificate, examples are
2384 * friendly name and id.
2386 * @param cert hx509 certificate object to search
2387 * @param oid an oid to search for.
2389 * @return an hx509_cert_attribute, only valid as long as the
2390 * certificate is referenced.
2392 * @ingroup hx509_cert
2395 hx509_cert_attribute
2396 hx509_cert_get_attribute(hx509_cert cert
, const heim_oid
*oid
)
2399 for (i
= 0; i
< cert
->attrs
.len
; i
++)
2400 if (der_heim_oid_cmp(oid
, &cert
->attrs
.val
[i
]->oid
) == 0)
2401 return cert
->attrs
.val
[i
];
2406 * Set the friendly name on the certificate.
2408 * @param cert The certificate to set the friendly name on
2409 * @param name Friendly name.
2411 * @return An hx509 error code, see hx509_get_error_string().
2413 * @ingroup hx509_cert
2417 hx509_cert_set_friendly_name(hx509_cert cert
, const char *name
)
2419 if (cert
->friendlyname
)
2420 free(cert
->friendlyname
);
2421 cert
->friendlyname
= strdup(name
);
2422 if (cert
->friendlyname
== NULL
)
2428 * Get friendly name of the certificate.
2430 * @param cert cert to get the friendly name from.
2432 * @return an friendly name or NULL if there is. The friendly name is
2433 * only valid as long as the certificate is referenced.
2435 * @ingroup hx509_cert
2439 hx509_cert_get_friendly_name(hx509_cert cert
)
2441 hx509_cert_attribute a
;
2442 PKCS9_friendlyName n
;
2446 if (cert
->friendlyname
)
2447 return cert
->friendlyname
;
2449 a
= hx509_cert_get_attribute(cert
, oid_id_pkcs_9_at_friendlyName());
2451 /* XXX use subject name ? */
2455 ret
= decode_PKCS9_friendlyName(a
->data
.data
, a
->data
.length
, &n
, &sz
);
2460 free_PKCS9_friendlyName(&n
);
2464 cert
->friendlyname
= malloc(n
.val
[0].length
+ 1);
2465 if (cert
->friendlyname
== NULL
) {
2466 free_PKCS9_friendlyName(&n
);
2470 for (i
= 0; i
< n
.val
[0].length
; i
++) {
2471 if (n
.val
[0].data
[i
] <= 0xff)
2472 cert
->friendlyname
[i
] = n
.val
[0].data
[i
] & 0xff;
2474 cert
->friendlyname
[i
] = 'X';
2476 cert
->friendlyname
[i
] = '\0';
2477 free_PKCS9_friendlyName(&n
);
2479 return cert
->friendlyname
;
2483 _hx509_query_clear(hx509_query
*q
)
2485 memset(q
, 0, sizeof(*q
));
2489 * Allocate an query controller. Free using hx509_query_free().
2491 * @param context A hx509 context.
2492 * @param q return pointer to a hx509_query.
2494 * @return An hx509 error code, see hx509_get_error_string().
2496 * @ingroup hx509_cert
2500 hx509_query_alloc(hx509_context context
, hx509_query
**q
)
2502 *q
= calloc(1, sizeof(**q
));
2509 * Set match options for the hx509 query controller.
2511 * @param q query controller.
2512 * @param option options to control the query controller.
2514 * @return An hx509 error code, see hx509_get_error_string().
2516 * @ingroup hx509_cert
2520 hx509_query_match_option(hx509_query
*q
, hx509_query_option option
)
2523 case HX509_QUERY_OPTION_PRIVATE_KEY
:
2524 q
->match
|= HX509_QUERY_PRIVATE_KEY
;
2526 case HX509_QUERY_OPTION_KU_ENCIPHERMENT
:
2527 q
->match
|= HX509_QUERY_KU_ENCIPHERMENT
;
2529 case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE
:
2530 q
->match
|= HX509_QUERY_KU_DIGITALSIGNATURE
;
2532 case HX509_QUERY_OPTION_KU_KEYCERTSIGN
:
2533 q
->match
|= HX509_QUERY_KU_KEYCERTSIGN
;
2535 case HX509_QUERY_OPTION_END
:
2542 * Set the issuer and serial number of match in the query
2543 * controller. The function make copies of the isser and serial number.
2545 * @param q a hx509 query controller
2546 * @param issuer issuer to search for
2547 * @param serialNumber the serialNumber of the issuer.
2549 * @return An hx509 error code, see hx509_get_error_string().
2551 * @ingroup hx509_cert
2555 hx509_query_match_issuer_serial(hx509_query
*q
,
2557 const heim_integer
*serialNumber
)
2561 der_free_heim_integer(q
->serial
);
2564 q
->serial
= malloc(sizeof(*q
->serial
));
2565 if (q
->serial
== NULL
)
2567 ret
= der_copy_heim_integer(serialNumber
, q
->serial
);
2573 if (q
->issuer_name
) {
2574 free_Name(q
->issuer_name
);
2575 free(q
->issuer_name
);
2577 q
->issuer_name
= malloc(sizeof(*q
->issuer_name
));
2578 if (q
->issuer_name
== NULL
)
2580 ret
= copy_Name(issuer
, q
->issuer_name
);
2582 free(q
->issuer_name
);
2583 q
->issuer_name
= NULL
;
2586 q
->match
|= HX509_QUERY_MATCH_SERIALNUMBER
|HX509_QUERY_MATCH_ISSUER_NAME
;
2591 * Set the query controller to match on a friendly name
2593 * @param q a hx509 query controller.
2594 * @param name a friendly name to match on
2596 * @return An hx509 error code, see hx509_get_error_string().
2598 * @ingroup hx509_cert
2602 hx509_query_match_friendly_name(hx509_query
*q
, const char *name
)
2604 if (q
->friendlyname
)
2605 free(q
->friendlyname
);
2606 q
->friendlyname
= strdup(name
);
2607 if (q
->friendlyname
== NULL
)
2609 q
->match
|= HX509_QUERY_MATCH_FRIENDLY_NAME
;
2614 * Set the query controller to match using a specific match function.
2616 * @param q a hx509 query controller.
2617 * @param func function to use for matching, if the argument is NULL,
2618 * the match function is removed.
2619 * @param ctx context passed to the function.
2621 * @return An hx509 error code, see hx509_get_error_string().
2623 * @ingroup hx509_cert
2627 hx509_query_match_cmp_func(hx509_query
*q
,
2628 int (*func
)(void *, hx509_cert
),
2632 q
->match
|= HX509_QUERY_MATCH_FUNCTION
;
2634 q
->match
&= ~HX509_QUERY_MATCH_FUNCTION
;
2636 q
->cmp_func_ctx
= ctx
;
2641 * Free the query controller.
2643 * @param context A hx509 context.
2644 * @param q a pointer to the query controller.
2646 * @ingroup hx509_cert
2650 hx509_query_free(hx509_context context
, hx509_query
*q
)
2653 der_free_heim_integer(q
->serial
);
2657 if (q
->issuer_name
) {
2658 free_Name(q
->issuer_name
);
2659 free(q
->issuer_name
);
2660 q
->issuer_name
= NULL
;
2663 free(q
->friendlyname
);
2664 memset(q
, 0, sizeof(*q
));
2670 _hx509_query_match_cert(hx509_context context
, const hx509_query
*q
, hx509_cert cert
)
2672 Certificate
*c
= _hx509_get_cert(cert
);
2674 _hx509_query_statistic(context
, 1, q
);
2676 if ((q
->match
& HX509_QUERY_FIND_ISSUER_CERT
) &&
2677 _hx509_cert_is_parent_cmp(q
->subject
, c
, 0) != 0)
2680 if ((q
->match
& HX509_QUERY_MATCH_CERTIFICATE
) &&
2681 _hx509_Certificate_cmp(q
->certificate
, c
) != 0)
2684 if ((q
->match
& HX509_QUERY_MATCH_SERIALNUMBER
)
2685 && der_heim_integer_cmp(&c
->tbsCertificate
.serialNumber
, q
->serial
) != 0)
2688 if ((q
->match
& HX509_QUERY_MATCH_ISSUER_NAME
)
2689 && _hx509_name_cmp(&c
->tbsCertificate
.issuer
, q
->issuer_name
) != 0)
2692 if ((q
->match
& HX509_QUERY_MATCH_SUBJECT_NAME
)
2693 && _hx509_name_cmp(&c
->tbsCertificate
.subject
, q
->subject_name
) != 0)
2696 if (q
->match
& HX509_QUERY_MATCH_SUBJECT_KEY_ID
) {
2697 SubjectKeyIdentifier si
;
2700 ret
= _hx509_find_extension_subject_key_id(c
, &si
);
2702 if (der_heim_octet_string_cmp(&si
, q
->subject_id
) != 0)
2704 free_SubjectKeyIdentifier(&si
);
2709 if ((q
->match
& HX509_QUERY_MATCH_ISSUER_ID
))
2711 if ((q
->match
& HX509_QUERY_PRIVATE_KEY
) &&
2712 _hx509_cert_private_key(cert
) == NULL
)
2717 if (q
->match
& HX509_QUERY_KU_DIGITALSIGNATURE
)
2719 if (q
->match
& HX509_QUERY_KU_NONREPUDIATION
)
2721 if (q
->match
& HX509_QUERY_KU_ENCIPHERMENT
)
2723 if (q
->match
& HX509_QUERY_KU_DATAENCIPHERMENT
)
2725 if (q
->match
& HX509_QUERY_KU_KEYAGREEMENT
)
2727 if (q
->match
& HX509_QUERY_KU_KEYCERTSIGN
)
2729 if (q
->match
& HX509_QUERY_KU_CRLSIGN
)
2731 if (ku
&& check_key_usage(context
, c
, ku
, TRUE
))
2734 if ((q
->match
& HX509_QUERY_ANCHOR
))
2737 if (q
->match
& HX509_QUERY_MATCH_LOCAL_KEY_ID
) {
2738 hx509_cert_attribute a
;
2740 a
= hx509_cert_get_attribute(cert
, oid_id_pkcs_9_at_localKeyId());
2743 if (der_heim_octet_string_cmp(&a
->data
, q
->local_key_id
) != 0)
2747 if (q
->match
& HX509_QUERY_NO_MATCH_PATH
) {
2750 for (i
= 0; i
< q
->path
->len
; i
++)
2751 if (hx509_cert_cmp(q
->path
->val
[i
], cert
) == 0)
2754 if (q
->match
& HX509_QUERY_MATCH_FRIENDLY_NAME
) {
2755 const char *name
= hx509_cert_get_friendly_name(cert
);
2758 if (strcasecmp(q
->friendlyname
, name
) != 0)
2761 if (q
->match
& HX509_QUERY_MATCH_FUNCTION
) {
2762 int ret
= (*q
->cmp_func
)(q
->cmp_func_ctx
, cert
);
2767 if (q
->match
& HX509_QUERY_MATCH_KEY_HASH_SHA1
) {
2768 heim_octet_string os
;
2771 os
.data
= c
->tbsCertificate
.subjectPublicKeyInfo
.subjectPublicKey
.data
;
2773 c
->tbsCertificate
.subjectPublicKeyInfo
.subjectPublicKey
.length
/ 8;
2775 ret
= _hx509_verify_signature(context
,
2777 hx509_signature_sha1(),
2784 if (q
->match
& HX509_QUERY_MATCH_TIME
) {
2786 t
= _hx509_Time2time_t(&c
->tbsCertificate
.validity
.notBefore
);
2789 t
= _hx509_Time2time_t(&c
->tbsCertificate
.validity
.notAfter
);
2794 if (q
->match
& ~HX509_QUERY_MASK
)
2801 * Set a statistic file for the query statistics.
2803 * @param context A hx509 context.
2804 * @param fn statistics file name
2806 * @ingroup hx509_cert
2810 hx509_query_statistic_file(hx509_context context
, const char *fn
)
2812 if (context
->querystat
)
2813 free(context
->querystat
);
2814 context
->querystat
= strdup(fn
);
2818 _hx509_query_statistic(hx509_context context
, int type
, const hx509_query
*q
)
2821 if (context
->querystat
== NULL
)
2823 f
= fopen(context
->querystat
, "a");
2826 fprintf(f
, "%d %d\n", type
, q
->match
);
2830 static const char *statname
[] = {
2832 "match serialnumber",
2833 "match issuer name",
2834 "match subject name",
2835 "match subject key id",
2839 "ku digitalsignature",
2842 "ku nonrepudiation",
2844 "ku dataencipherment",
2846 "match certificate",
2847 "match local key id",
2849 "match friendly name",
2851 "match key hash sha1",
2856 unsigned long stats
;
2862 stat_sort(const void *a
, const void *b
)
2864 const struct stat_el
*ae
= a
;
2865 const struct stat_el
*be
= b
;
2866 return be
->stats
- ae
->stats
;
2870 * Unparse the statistics file and print the result on a FILE descriptor.
2872 * @param context A hx509 context.
2873 * @param printtype tyep to print
2874 * @param out the FILE to write the data on.
2876 * @ingroup hx509_cert
2880 hx509_query_unparse_stats(hx509_context context
, int printtype
, FILE *out
)
2884 int type
, mask
, i
, num
;
2885 unsigned long multiqueries
= 0, totalqueries
= 0;
2886 struct stat_el stats
[32];
2888 if (context
->querystat
== NULL
)
2890 f
= fopen(context
->querystat
, "r");
2892 fprintf(out
, "No statistic file %s: %s.\n",
2893 context
->querystat
, strerror(errno
));
2897 for (i
= 0; i
< sizeof(stats
)/sizeof(stats
[0]); i
++) {
2902 while (fscanf(f
, "%d %d\n", &type
, &mask
) == 2) {
2903 if (type
!= printtype
)
2906 while (mask
&& i
< sizeof(stats
)/sizeof(stats
[0])) {
2920 qsort(stats
, sizeof(stats
)/sizeof(stats
[0]), sizeof(stats
[0]), stat_sort
);
2924 errx(1, "out of memory");
2926 rtbl_set_separator (t
, " ");
2928 rtbl_add_column_by_id (t
, 0, "Name", 0);
2929 rtbl_add_column_by_id (t
, 1, "Counter", 0);
2932 for (i
= 0; i
< sizeof(stats
)/sizeof(stats
[0]); i
++) {
2935 if (stats
[i
].index
< sizeof(statname
)/sizeof(statname
[0]))
2936 rtbl_add_column_entry_by_id (t
, 0, statname
[stats
[i
].index
]);
2938 snprintf(str
, sizeof(str
), "%d", stats
[i
].index
);
2939 rtbl_add_column_entry_by_id (t
, 0, str
);
2941 snprintf(str
, sizeof(str
), "%lu", stats
[i
].stats
);
2942 rtbl_add_column_entry_by_id (t
, 1, str
);
2945 rtbl_format(t
, out
);
2948 fprintf(out
, "\nQueries: multi %lu total %lu\n",
2949 multiqueries
, totalqueries
);
2953 * Check the extended key usage on the hx509 certificate.
2955 * @param context A hx509 context.
2956 * @param cert A hx509 context.
2957 * @param eku the EKU to check for
2958 * @param allow_any_eku if the any EKU is set, allow that to be a
2961 * @return An hx509 error code, see hx509_get_error_string().
2963 * @ingroup hx509_cert
2967 hx509_cert_check_eku(hx509_context context
, hx509_cert cert
,
2968 const heim_oid
*eku
, int allow_any_eku
)
2973 ret
= find_extension_eku(_hx509_get_cert(cert
), &e
);
2975 hx509_clear_error_string(context
);
2979 for (i
= 0; i
< e
.len
; i
++) {
2980 if (der_heim_oid_cmp(eku
, &e
.val
[i
]) == 0) {
2981 free_ExtKeyUsage(&e
);
2984 if (allow_any_eku
) {
2986 if (der_heim_oid_cmp(id_any_eku
, &e
.val
[i
]) == 0) {
2987 free_ExtKeyUsage(&e
);
2993 free_ExtKeyUsage(&e
);
2994 hx509_clear_error_string(context
);
2995 return HX509_CERTIFICATE_MISSING_EKU
;
2999 _hx509_cert_get_keyusage(hx509_context context
,
3008 memset(ku
, 0, sizeof(*ku
));
3010 cert
= _hx509_get_cert(c
);
3012 if (_hx509_cert_get_version(cert
) < 3)
3015 e
= find_extension(cert
, oid_id_x509_ce_keyUsage(), &i
);
3017 return HX509_KU_CERT_MISSING
;
3019 ret
= decode_KeyUsage(e
->extnValue
.data
, e
->extnValue
.length
, ku
, &size
);
3026 _hx509_cert_get_eku(hx509_context context
,
3032 memset(e
, 0, sizeof(*e
));
3034 ret
= find_extension_eku(_hx509_get_cert(cert
), e
);
3035 if (ret
&& ret
!= HX509_EXTENSION_NOT_FOUND
) {
3036 hx509_clear_error_string(context
);
3043 * Encodes the hx509 certificate as a DER encode binary.
3045 * @param context A hx509 context.
3046 * @param c the certificate to encode.
3047 * @param os the encode certificate, set to NULL, 0 on case of
3048 * error. Free the returned structure with hx509_xfree().
3050 * @return An hx509 error code, see hx509_get_error_string().
3052 * @ingroup hx509_cert
3056 hx509_cert_binary(hx509_context context
, hx509_cert c
, heim_octet_string
*os
)
3064 ASN1_MALLOC_ENCODE(Certificate
, os
->data
, os
->length
,
3065 _hx509_get_cert(c
), &size
, ret
);
3071 if (os
->length
!= size
)
3072 _hx509_abort("internal ASN.1 encoder error");
3078 * Last to avoid lost __attribute__s due to #undef.
3081 #undef __attribute__
3082 #define __attribute__(X)
3085 _hx509_abort(const char *fmt
, ...)
3086 __attribute__ ((noreturn
, format (printf
, 1, 2)))
3098 * Free a data element allocated in the library.
3100 * @param ptr data to be freed.
3102 * @ingroup hx509_misc
3106 hx509_xfree(void *ptr
)