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
;
896 int ret_ai
, ret_si
, ret
;
898 ret
= _hx509_name_cmp(&issuer
->tbsCertificate
.subject
,
899 &subject
->tbsCertificate
.issuer
,
906 memset(&ai
, 0, sizeof(ai
));
907 memset(&si
, 0, sizeof(si
));
910 * Try to find AuthorityKeyIdentifier, if it's not present in the
911 * subject certificate nor the parent.
914 ret_ai
= find_extension_auth_key_id(subject
, &ai
);
915 if (ret_ai
&& ret_ai
!= HX509_EXTENSION_NOT_FOUND
)
917 ret_si
= _hx509_find_extension_subject_key_id(issuer
, &si
);
918 if (ret_si
&& ret_si
!= HX509_EXTENSION_NOT_FOUND
)
921 if (ret_si
&& ret_ai
)
926 if (allow_self_signed
) {
929 } else if (ai
.keyIdentifier
) {
935 if (ai
.keyIdentifier
== NULL
) {
938 if (ai
.authorityCertIssuer
== NULL
)
940 if (ai
.authorityCertSerialNumber
== NULL
)
943 diff
= der_heim_integer_cmp(ai
.authorityCertSerialNumber
,
944 &issuer
->tbsCertificate
.serialNumber
);
947 if (ai
.authorityCertIssuer
->len
!= 1)
949 if (ai
.authorityCertIssuer
->val
[0].element
!= choice_GeneralName_directoryName
)
953 ai
.authorityCertIssuer
->val
[0].u
.directoryName
.element
;
955 ai
.authorityCertIssuer
->val
[0].u
.directoryName
.u
.rdnSequence
;
957 ret
= _hx509_name_cmp(&issuer
->tbsCertificate
.subject
,
966 diff
= der_heim_octet_string_cmp(ai
.keyIdentifier
, &si
);
971 free_AuthorityKeyIdentifier(&ai
);
972 free_SubjectKeyIdentifier(&si
);
977 certificate_is_anchor(hx509_context context
,
978 hx509_certs trust_anchors
,
979 const hx509_cert cert
)
985 if (trust_anchors
== NULL
)
988 _hx509_query_clear(&q
);
990 q
.match
= HX509_QUERY_MATCH_CERTIFICATE
;
991 q
.certificate
= _hx509_get_cert(cert
);
993 ret
= hx509_certs_find(context
, trust_anchors
, &q
, &c
);
1000 certificate_is_self_signed(hx509_context context
,
1001 const Certificate
*cert
,
1005 ret
= _hx509_name_cmp(&cert
->tbsCertificate
.subject
,
1006 &cert
->tbsCertificate
.issuer
, &diff
);
1007 *self_signed
= (diff
== 0);
1009 hx509_set_error_string(context
, 0, ret
,
1010 "Failed to check if self signed");
1015 * The subjectName is "null" when it's empty set of relative DBs.
1019 subject_null_p(const Certificate
*c
)
1021 return c
->tbsCertificate
.subject
.u
.rdnSequence
.len
== 0;
1026 find_parent(hx509_context context
,
1028 hx509_certs trust_anchors
,
1034 AuthorityKeyIdentifier ai
;
1039 memset(&ai
, 0, sizeof(ai
));
1041 _hx509_query_clear(&q
);
1043 if (!subject_null_p(current
->data
)) {
1044 q
.match
|= HX509_QUERY_FIND_ISSUER_CERT
;
1045 q
.subject
= _hx509_get_cert(current
);
1047 ret
= find_extension_auth_key_id(current
->data
, &ai
);
1049 hx509_set_error_string(context
, 0, HX509_CERTIFICATE_MALFORMED
,
1050 "Subjectless certificate missing AuthKeyID");
1051 return HX509_CERTIFICATE_MALFORMED
;
1054 if (ai
.keyIdentifier
== NULL
) {
1055 free_AuthorityKeyIdentifier(&ai
);
1056 hx509_set_error_string(context
, 0, HX509_CERTIFICATE_MALFORMED
,
1057 "Subjectless certificate missing keyIdentifier "
1058 "inside AuthKeyID");
1059 return HX509_CERTIFICATE_MALFORMED
;
1062 q
.subject_id
= ai
.keyIdentifier
;
1063 q
.match
= HX509_QUERY_MATCH_SUBJECT_KEY_ID
;
1067 q
.match
|= HX509_QUERY_NO_MATCH_PATH
;
1070 q
.timenow
= time_now
;
1071 q
.match
|= HX509_QUERY_MATCH_TIME
;
1073 ret
= hx509_certs_find(context
, pool
, &q
, parent
);
1075 free_AuthorityKeyIdentifier(&ai
);
1078 q
.match
&= ~HX509_QUERY_MATCH_TIME
;
1081 if (trust_anchors
) {
1082 ret
= hx509_certs_find(context
, trust_anchors
, &q
, parent
);
1084 free_AuthorityKeyIdentifier(&ai
);
1088 free_AuthorityKeyIdentifier(&ai
);
1094 ret
= hx509_cert_get_subject(current
, &name
);
1096 hx509_clear_error_string(context
);
1097 return HX509_ISSUER_NOT_FOUND
;
1099 ret
= hx509_name_to_string(name
, &str
);
1100 hx509_name_free(&name
);
1102 hx509_clear_error_string(context
);
1103 return HX509_ISSUER_NOT_FOUND
;
1106 hx509_set_error_string(context
, 0, HX509_ISSUER_NOT_FOUND
,
1107 "Failed to find issuer for "
1108 "certificate with subject: '%s'", str
);
1111 return HX509_ISSUER_NOT_FOUND
;
1119 is_proxy_cert(hx509_context context
,
1120 const Certificate
*cert
,
1121 ProxyCertInfo
*rinfo
)
1129 memset(rinfo
, 0, sizeof(*rinfo
));
1131 e
= find_extension(cert
, oid_id_pkix_pe_proxyCertInfo(), &i
);
1133 hx509_clear_error_string(context
);
1134 return HX509_EXTENSION_NOT_FOUND
;
1137 ret
= decode_ProxyCertInfo(e
->extnValue
.data
,
1138 e
->extnValue
.length
,
1142 hx509_clear_error_string(context
);
1145 if (size
!= e
->extnValue
.length
) {
1146 free_ProxyCertInfo(&info
);
1147 hx509_clear_error_string(context
);
1148 return HX509_EXTRA_DATA_AFTER_STRUCTURE
;
1151 free_ProxyCertInfo(&info
);
1159 * Path operations are like MEMORY based keyset, but with exposed
1160 * internal so we can do easy searches.
1164 _hx509_path_append(hx509_context context
, hx509_path
*path
, hx509_cert cert
)
1167 val
= realloc(path
->val
, (path
->len
+ 1) * sizeof(path
->val
[0]));
1169 hx509_set_error_string(context
, 0, ENOMEM
, "out of memory");
1174 path
->val
[path
->len
] = hx509_cert_ref(cert
);
1181 _hx509_path_free(hx509_path
*path
)
1185 for (i
= 0; i
< path
->len
; i
++)
1186 hx509_cert_free(path
->val
[i
]);
1193 * Find path by looking up issuer for the top certificate and continue
1194 * until an anchor certificate is found or max limit is found. A
1195 * certificate never included twice in the path.
1197 * If the trust anchors are not given, calculate optimistic path, just
1198 * follow the chain upward until we no longer find a parent or we hit
1199 * the max path limit. In this case, a failure will always be returned
1200 * depending on what error condition is hit first.
1202 * The path includes a path from the top certificate to the anchor
1205 * The caller needs to free `path´ both on successful built path and
1210 _hx509_calculate_path(hx509_context context
,
1213 hx509_certs anchors
,
1214 unsigned int max_depth
,
1219 hx509_cert parent
, current
;
1223 max_depth
= HX509_VERIFY_MAX_DEPTH
;
1225 ret
= _hx509_path_append(context
, path
, cert
);
1229 current
= hx509_cert_ref(cert
);
1231 while (!certificate_is_anchor(context
, anchors
, current
)) {
1233 ret
= find_parent(context
, time_now
, anchors
, path
,
1234 pool
, current
, &parent
);
1235 hx509_cert_free(current
);
1239 ret
= _hx509_path_append(context
, path
, parent
);
1244 if (path
->len
> max_depth
) {
1245 hx509_cert_free(current
);
1246 hx509_set_error_string(context
, 0, HX509_PATH_TOO_LONG
,
1247 "Path too long while bulding "
1248 "certificate chain");
1249 return HX509_PATH_TOO_LONG
;
1253 if ((flags
& HX509_CALCULATE_PATH_NO_ANCHOR
) &&
1255 certificate_is_anchor(context
, anchors
, path
->val
[path
->len
- 1]))
1257 hx509_cert_free(path
->val
[path
->len
- 1]);
1261 hx509_cert_free(current
);
1266 _hx509_AlgorithmIdentifier_cmp(const AlgorithmIdentifier
*p
,
1267 const AlgorithmIdentifier
*q
)
1270 diff
= der_heim_oid_cmp(&p
->algorithm
, &q
->algorithm
);
1273 if (p
->parameters
) {
1275 return heim_any_cmp(p
->parameters
,
1288 _hx509_Certificate_cmp(const Certificate
*p
, const Certificate
*q
)
1291 diff
= der_heim_bit_string_cmp(&p
->signatureValue
, &q
->signatureValue
);
1294 diff
= _hx509_AlgorithmIdentifier_cmp(&p
->signatureAlgorithm
,
1295 &q
->signatureAlgorithm
);
1298 diff
= der_heim_octet_string_cmp(&p
->tbsCertificate
._save
,
1299 &q
->tbsCertificate
._save
);
1304 * Compare to hx509 certificate object, useful for sorting.
1306 * @param p a hx509 certificate object.
1307 * @param q a hx509 certificate object.
1309 * @return 0 the objects are the same, returns > 0 is p is "larger"
1310 * then q, < 0 if p is "smaller" then q.
1312 * @ingroup hx509_cert
1316 hx509_cert_cmp(hx509_cert p
, hx509_cert q
)
1318 return _hx509_Certificate_cmp(p
->data
, q
->data
);
1322 * Return the name of the issuer of the hx509 certificate.
1324 * @param p a hx509 certificate object.
1325 * @param name a pointer to a hx509 name, should be freed by
1326 * hx509_name_free().
1328 * @return An hx509 error code, see hx509_get_error_string().
1330 * @ingroup hx509_cert
1334 hx509_cert_get_issuer(hx509_cert p
, hx509_name
*name
)
1336 return _hx509_name_from_Name(&p
->data
->tbsCertificate
.issuer
, name
);
1340 * Return the name of the subject of the hx509 certificate.
1342 * @param p a hx509 certificate object.
1343 * @param name a pointer to a hx509 name, should be freed by
1344 * hx509_name_free(). See also hx509_cert_get_base_subject().
1346 * @return An hx509 error code, see hx509_get_error_string().
1348 * @ingroup hx509_cert
1352 hx509_cert_get_subject(hx509_cert p
, hx509_name
*name
)
1354 return _hx509_name_from_Name(&p
->data
->tbsCertificate
.subject
, name
);
1358 * Return the name of the base subject of the hx509 certificate. If
1359 * the certiicate is a verified proxy certificate, the this function
1360 * return the base certificate (root of the proxy chain). If the proxy
1361 * certificate is not verified with the base certificate
1362 * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned.
1364 * @param context a hx509 context.
1365 * @param c a hx509 certificate object.
1366 * @param name a pointer to a hx509 name, should be freed by
1367 * hx509_name_free(). See also hx509_cert_get_subject().
1369 * @return An hx509 error code, see hx509_get_error_string().
1371 * @ingroup hx509_cert
1375 hx509_cert_get_base_subject(hx509_context context
, hx509_cert c
,
1379 return hx509_name_copy(context
, c
->basename
, name
);
1380 if (is_proxy_cert(context
, c
->data
, NULL
) == 0) {
1381 int ret
= HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED
;
1382 hx509_set_error_string(context
, 0, ret
,
1383 "Proxy certificate have not been "
1384 "canonicalize yet, no base name");
1387 return _hx509_name_from_Name(&c
->data
->tbsCertificate
.subject
, name
);
1391 * Get serial number of the certificate.
1393 * @param p a hx509 certificate object.
1394 * @param i serial number, should be freed ith der_free_heim_integer().
1396 * @return An hx509 error code, see hx509_get_error_string().
1398 * @ingroup hx509_cert
1402 hx509_cert_get_serialnumber(hx509_cert p
, heim_integer
*i
)
1404 return der_copy_heim_integer(&p
->data
->tbsCertificate
.serialNumber
, i
);
1408 * Get notBefore time of the certificate.
1410 * @param p a hx509 certificate object.
1412 * @return return not before time
1414 * @ingroup hx509_cert
1418 hx509_cert_get_notBefore(hx509_cert p
)
1420 return _hx509_Time2time_t(&p
->data
->tbsCertificate
.validity
.notBefore
);
1424 * Get notAfter time of the certificate.
1426 * @param p a hx509 certificate object.
1428 * @return return not after time.
1430 * @ingroup hx509_cert
1434 hx509_cert_get_notAfter(hx509_cert p
)
1436 return _hx509_Time2time_t(&p
->data
->tbsCertificate
.validity
.notAfter
);
1440 * Get the SubjectPublicKeyInfo structure from the hx509 certificate.
1442 * @param context a hx509 context.
1443 * @param p a hx509 certificate object.
1444 * @param spki SubjectPublicKeyInfo, should be freed with
1445 * free_SubjectPublicKeyInfo().
1447 * @return An hx509 error code, see hx509_get_error_string().
1449 * @ingroup hx509_cert
1453 hx509_cert_get_SPKI(hx509_context context
, hx509_cert p
, SubjectPublicKeyInfo
*spki
)
1457 ret
= copy_SubjectPublicKeyInfo(&p
->data
->tbsCertificate
.subjectPublicKeyInfo
, spki
);
1459 hx509_set_error_string(context
, 0, ret
, "Failed to copy SPKI");
1464 * Get the AlgorithmIdentifier from the hx509 certificate.
1466 * @param context a hx509 context.
1467 * @param p a hx509 certificate object.
1468 * @param alg AlgorithmIdentifier, should be freed with
1469 * free_AlgorithmIdentifier().
1471 * @return An hx509 error code, see hx509_get_error_string().
1473 * @ingroup hx509_cert
1477 hx509_cert_get_SPKI_AlgorithmIdentifier(hx509_context context
,
1479 AlgorithmIdentifier
*alg
)
1483 ret
= copy_AlgorithmIdentifier(&p
->data
->tbsCertificate
.subjectPublicKeyInfo
.algorithm
, alg
);
1485 hx509_set_error_string(context
, 0, ret
,
1486 "Failed to copy SPKI AlgorithmIdentifier");
1492 _hx509_cert_private_key(hx509_cert p
)
1494 return p
->private_key
;
1498 hx509_cert_have_private_key(hx509_cert p
)
1500 return p
->private_key
? 1 : 0;
1505 _hx509_cert_private_key_exportable(hx509_cert p
)
1507 if (p
->private_key
== NULL
)
1509 return _hx509_private_key_exportable(p
->private_key
);
1513 _hx509_cert_private_decrypt(hx509_context context
,
1514 const heim_octet_string
*ciphertext
,
1515 const heim_oid
*encryption_oid
,
1517 heim_octet_string
*cleartext
)
1519 cleartext
->data
= NULL
;
1520 cleartext
->length
= 0;
1522 if (p
->private_key
== NULL
) {
1523 hx509_set_error_string(context
, 0, HX509_PRIVATE_KEY_MISSING
,
1524 "Private key missing");
1525 return HX509_PRIVATE_KEY_MISSING
;
1528 return _hx509_private_key_private_decrypt(context
,
1536 _hx509_cert_public_encrypt(hx509_context context
,
1537 const heim_octet_string
*cleartext
,
1539 heim_oid
*encryption_oid
,
1540 heim_octet_string
*ciphertext
)
1542 return _hx509_public_encrypt(context
,
1544 encryption_oid
, ciphertext
);
1552 _hx509_Time2time_t(const Time
*t
)
1554 switch(t
->element
) {
1555 case choice_Time_utcTime
:
1556 return t
->u
.utcTime
;
1557 case choice_Time_generalTime
:
1558 return t
->u
.generalTime
;
1568 init_name_constraints(hx509_name_constraints
*nc
)
1570 memset(nc
, 0, sizeof(*nc
));
1575 add_name_constraints(hx509_context context
, const Certificate
*c
, int not_ca
,
1576 hx509_name_constraints
*nc
)
1578 NameConstraints tnc
;
1581 ret
= find_extension_name_constraints(c
, &tnc
);
1582 if (ret
== HX509_EXTENSION_NOT_FOUND
)
1585 hx509_set_error_string(context
, 0, ret
, "Failed getting NameConstraints");
1587 } else if (not_ca
) {
1588 ret
= HX509_VERIFY_CONSTRAINTS
;
1589 hx509_set_error_string(context
, 0, ret
, "Not a CA and "
1590 "have NameConstraints");
1592 NameConstraints
*val
;
1593 val
= realloc(nc
->val
, sizeof(nc
->val
[0]) * (nc
->len
+ 1));
1595 hx509_clear_error_string(context
);
1600 ret
= copy_NameConstraints(&tnc
, &nc
->val
[nc
->len
]);
1602 hx509_clear_error_string(context
);
1608 free_NameConstraints(&tnc
);
1613 match_RDN(const RelativeDistinguishedName
*c
,
1614 const RelativeDistinguishedName
*n
)
1618 if (c
->len
!= n
->len
)
1619 return HX509_NAME_CONSTRAINT_ERROR
;
1621 for (i
= 0; i
< n
->len
; i
++) {
1624 if (der_heim_oid_cmp(&c
->val
[i
].type
, &n
->val
[i
].type
) != 0)
1625 return HX509_NAME_CONSTRAINT_ERROR
;
1626 ret
= _hx509_name_ds_cmp(&c
->val
[i
].value
, &n
->val
[i
].value
, &diff
);
1630 return HX509_NAME_CONSTRAINT_ERROR
;
1636 match_X501Name(const Name
*c
, const Name
*n
)
1640 if (c
->element
!= choice_Name_rdnSequence
1641 || n
->element
!= choice_Name_rdnSequence
)
1643 if (c
->u
.rdnSequence
.len
> n
->u
.rdnSequence
.len
)
1644 return HX509_NAME_CONSTRAINT_ERROR
;
1645 for (i
= 0; i
< c
->u
.rdnSequence
.len
; i
++) {
1646 ret
= match_RDN(&c
->u
.rdnSequence
.val
[i
], &n
->u
.rdnSequence
.val
[i
]);
1655 match_general_name(const GeneralName
*c
, const GeneralName
*n
, int *match
)
1658 * Name constraints only apply to the same name type, see RFC3280,
1661 assert(c
->element
== n
->element
);
1663 switch(c
->element
) {
1664 case choice_GeneralName_otherName
:
1665 if (der_heim_oid_cmp(&c
->u
.otherName
.type_id
,
1666 &n
->u
.otherName
.type_id
) != 0)
1667 return HX509_NAME_CONSTRAINT_ERROR
;
1668 if (heim_any_cmp(&c
->u
.otherName
.value
,
1669 &n
->u
.otherName
.value
) != 0)
1670 return HX509_NAME_CONSTRAINT_ERROR
;
1673 case choice_GeneralName_rfc822Name
: {
1676 s
= strchr(c
->u
.rfc822Name
, '@');
1678 if (strcasecmp(c
->u
.rfc822Name
, n
->u
.rfc822Name
) != 0)
1679 return HX509_NAME_CONSTRAINT_ERROR
;
1681 s
= strchr(n
->u
.rfc822Name
, '@');
1683 return HX509_NAME_CONSTRAINT_ERROR
;
1684 len1
= strlen(c
->u
.rfc822Name
);
1685 len2
= strlen(s
+ 1);
1687 return HX509_NAME_CONSTRAINT_ERROR
;
1688 if (strcasecmp(s
+ 1 + len2
- len1
, c
->u
.rfc822Name
) != 0)
1689 return HX509_NAME_CONSTRAINT_ERROR
;
1690 if (len1
< len2
&& s
[len2
- len1
+ 1] != '.')
1691 return HX509_NAME_CONSTRAINT_ERROR
;
1696 case choice_GeneralName_dNSName
: {
1699 lenc
= strlen(c
->u
.dNSName
);
1700 lenn
= strlen(n
->u
.dNSName
);
1702 return HX509_NAME_CONSTRAINT_ERROR
;
1703 if (strcasecmp(&n
->u
.dNSName
[lenn
- lenc
], c
->u
.dNSName
) != 0)
1704 return HX509_NAME_CONSTRAINT_ERROR
;
1705 if (lenc
!= lenn
&& n
->u
.dNSName
[lenn
- lenc
- 1] != '.')
1706 return HX509_NAME_CONSTRAINT_ERROR
;
1710 case choice_GeneralName_directoryName
: {
1711 Name c_name
, n_name
;
1714 c_name
._save
.data
= NULL
;
1715 c_name
._save
.length
= 0;
1716 c_name
.element
= c
->u
.directoryName
.element
;
1717 c_name
.u
.rdnSequence
= c
->u
.directoryName
.u
.rdnSequence
;
1719 n_name
._save
.data
= NULL
;
1720 n_name
._save
.length
= 0;
1721 n_name
.element
= n
->u
.directoryName
.element
;
1722 n_name
.u
.rdnSequence
= n
->u
.directoryName
.u
.rdnSequence
;
1724 ret
= match_X501Name(&c_name
, &n_name
);
1729 case choice_GeneralName_uniformResourceIdentifier
:
1730 case choice_GeneralName_iPAddress
:
1731 case choice_GeneralName_registeredID
:
1733 return HX509_NAME_CONSTRAINT_ERROR
;
1738 match_alt_name(const GeneralName
*n
, const Certificate
*c
,
1739 int *same
, int *match
)
1746 ret
= find_extension_subject_alt_name(c
, &i
, &sa
);
1747 if (ret
== HX509_EXTENSION_NOT_FOUND
) {
1750 } else if (ret
!= 0)
1753 for (j
= 0; j
< sa
.len
; j
++) {
1754 if (n
->element
== sa
.val
[j
].element
) {
1756 ret
= match_general_name(n
, &sa
.val
[j
], match
);
1759 free_GeneralNames(&sa
);
1766 match_tree(const GeneralSubtrees
*t
, const Certificate
*c
, int *match
)
1768 int name
, alt_name
, same
;
1772 name
= alt_name
= same
= *match
= 0;
1773 for (i
= 0; i
< t
->len
; i
++) {
1774 if (t
->val
[i
].minimum
&& t
->val
[i
].maximum
)
1778 * If the constraint apply to directoryNames, test is with
1779 * subjectName of the certificate if the certificate have a
1780 * non-null (empty) subjectName.
1783 if (t
->val
[i
].base
.element
== choice_GeneralName_directoryName
1784 && !subject_null_p(c
))
1786 GeneralName certname
;
1788 memset(&certname
, 0, sizeof(certname
));
1789 certname
.element
= choice_GeneralName_directoryName
;
1790 certname
.u
.directoryName
.element
=
1791 c
->tbsCertificate
.subject
.element
;
1792 certname
.u
.directoryName
.u
.rdnSequence
=
1793 c
->tbsCertificate
.subject
.u
.rdnSequence
;
1795 ret
= match_general_name(&t
->val
[i
].base
, &certname
, &name
);
1798 /* Handle subjectAltNames, this is icky since they
1799 * restrictions only apply if the subjectAltName is of the
1800 * same type. So if there have been a match of type, require
1801 * altname to be set.
1803 ret
= match_alt_name(&t
->val
[i
].base
, c
, &same
, &alt_name
);
1805 if (name
&& (!same
|| alt_name
))
1811 check_name_constraints(hx509_context context
,
1812 const hx509_name_constraints
*nc
,
1813 const Certificate
*c
)
1818 for (i
= 0 ; i
< nc
->len
; i
++) {
1821 if (nc
->val
[i
].permittedSubtrees
) {
1822 GeneralSubtrees_SET(&gs
, nc
->val
[i
].permittedSubtrees
);
1823 ret
= match_tree(&gs
, c
, &match
);
1825 hx509_clear_error_string(context
);
1828 /* allow null subjectNames, they wont matches anything */
1829 if (match
== 0 && !subject_null_p(c
)) {
1830 hx509_set_error_string(context
, 0, HX509_VERIFY_CONSTRAINTS
,
1831 "Error verify constraints, "
1832 "certificate didn't match any "
1833 "permitted subtree");
1834 return HX509_VERIFY_CONSTRAINTS
;
1837 if (nc
->val
[i
].excludedSubtrees
) {
1838 GeneralSubtrees_SET(&gs
, nc
->val
[i
].excludedSubtrees
);
1839 ret
= match_tree(&gs
, c
, &match
);
1841 hx509_clear_error_string(context
);
1845 hx509_set_error_string(context
, 0, HX509_VERIFY_CONSTRAINTS
,
1846 "Error verify constraints, "
1847 "certificate included in excluded "
1849 return HX509_VERIFY_CONSTRAINTS
;
1857 free_name_constraints(hx509_name_constraints
*nc
)
1861 for (i
= 0 ; i
< nc
->len
; i
++)
1862 free_NameConstraints(&nc
->val
[i
]);
1867 * Build and verify the path for the certificate to the trust anchor
1868 * specified in the verify context. The path is constructed from the
1869 * certificate, the pool and the trust anchors.
1871 * @param context A hx509 context.
1872 * @param ctx A hx509 verification context.
1873 * @param cert the certificate to build the path from.
1874 * @param pool A keyset of certificates to build the chain from.
1876 * @return An hx509 error code, see hx509_get_error_string().
1878 * @ingroup hx509_verify
1882 hx509_verify_path(hx509_context context
,
1883 hx509_verify_ctx ctx
,
1887 hx509_name_constraints nc
;
1889 int ret
, i
, proxy_cert_depth
, selfsigned_depth
, diff
;
1892 hx509_certs anchors
= NULL
;
1894 memset(&proxy_issuer
, 0, sizeof(proxy_issuer
));
1896 ret
= init_name_constraints(&nc
);
1903 if ((ctx
->flags
& HX509_VERIFY_CTX_F_TIME_SET
) == 0)
1904 ctx
->time_now
= time(NULL
);
1909 if (ctx
->trust_anchors
)
1910 anchors
= _hx509_certs_ref(ctx
->trust_anchors
);
1911 else if (context
->default_trust_anchors
&& ALLOW_DEF_TA(ctx
))
1912 anchors
= _hx509_certs_ref(context
->default_trust_anchors
);
1914 ret
= hx509_certs_init(context
, "MEMORY:no-TA", 0, NULL
, &anchors
);
1920 * Calculate the path from the certificate user presented to the
1923 ret
= _hx509_calculate_path(context
, 0, ctx
->time_now
,
1924 anchors
, ctx
->max_depth
,
1930 * Check CA and proxy certificate chain from the top of the
1931 * certificate chain. Also check certificate is valid with respect
1932 * to the current time.
1936 proxy_cert_depth
= 0;
1937 selfsigned_depth
= 0;
1939 if (ctx
->flags
& HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE
)
1944 for (i
= 0; i
< path
.len
; i
++) {
1948 c
= _hx509_get_cert(path
.val
[i
]);
1951 * Lets do some basic check on issuer like
1952 * keyUsage.keyCertSign and basicConstraints.cA bit depending
1953 * on what type of certificate this is.
1959 /* XXX make constants for keyusage */
1960 ret
= check_key_usage(context
, c
, 1 << 5,
1961 REQUIRE_RFC3280(ctx
) ? TRUE
: FALSE
);
1963 hx509_set_error_string(context
, HX509_ERROR_APPEND
, ret
,
1964 "Key usage missing from CA certificate");
1968 /* self signed cert doesn't add to path length */
1969 if (i
+ 1 != path
.len
) {
1972 ret
= certificate_is_self_signed(context
, c
, &selfsigned
);
1983 if (is_proxy_cert(context
, c
, &info
) == 0) {
1986 if (info
.pCPathLenConstraint
!= NULL
&&
1987 *info
.pCPathLenConstraint
< i
)
1989 free_ProxyCertInfo(&info
);
1990 ret
= HX509_PATH_TOO_LONG
;
1991 hx509_set_error_string(context
, 0, ret
,
1992 "Proxy certificate chain "
1993 "longer then allowed");
1996 /* XXX MUST check info.proxyPolicy */
1997 free_ProxyCertInfo(&info
);
2000 if (find_extension(c
, oid_id_x509_ce_subjectAltName(), &j
)) {
2001 ret
= HX509_PROXY_CERT_INVALID
;
2002 hx509_set_error_string(context
, 0, ret
,
2003 "Proxy certificate have explicity "
2004 "forbidden subjectAltName");
2009 if (find_extension(c
, oid_id_x509_ce_issuerAltName(), &j
)) {
2010 ret
= HX509_PROXY_CERT_INVALID
;
2011 hx509_set_error_string(context
, 0, ret
,
2012 "Proxy certificate have explicity "
2013 "forbidden issuerAltName");
2018 * The subject name of the proxy certificate should be
2019 * CN=XXX,<proxy issuer>, prune of CN and check if its
2020 * the same over the whole chain of proxy certs and
2021 * then check with the EE cert when we get to it.
2024 if (proxy_cert_depth
) {
2025 ret
= _hx509_name_cmp(&proxy_issuer
, &c
->tbsCertificate
.subject
, &diff
);
2027 hx509_set_error_string(context
, 0, ret
, "Out of memory");
2031 ret
= HX509_PROXY_CERT_NAME_WRONG
;
2032 hx509_set_error_string(context
, 0, ret
,
2033 "Base proxy name not right");
2038 free_Name(&proxy_issuer
);
2040 ret
= copy_Name(&c
->tbsCertificate
.subject
, &proxy_issuer
);
2042 hx509_clear_error_string(context
);
2046 j
= proxy_issuer
.u
.rdnSequence
.len
;
2047 if (proxy_issuer
.u
.rdnSequence
.len
< 2
2048 || proxy_issuer
.u
.rdnSequence
.val
[j
- 1].len
> 1
2049 || der_heim_oid_cmp(&proxy_issuer
.u
.rdnSequence
.val
[j
- 1].val
[0].type
,
2050 oid_id_at_commonName()))
2052 ret
= HX509_PROXY_CERT_NAME_WRONG
;
2053 hx509_set_error_string(context
, 0, ret
,
2054 "Proxy name too short or "
2055 "does not have Common name "
2060 free_RelativeDistinguishedName(&proxy_issuer
.u
.rdnSequence
.val
[j
- 1]);
2061 proxy_issuer
.u
.rdnSequence
.len
-= 1;
2063 ret
= _hx509_name_cmp(&proxy_issuer
, &c
->tbsCertificate
.issuer
, &diff
);
2065 hx509_set_error_string(context
, 0, ret
, "Out of memory");
2069 ret
= HX509_PROXY_CERT_NAME_WRONG
;
2070 hx509_set_error_string(context
, 0, ret
,
2071 "Proxy issuer name not as expected");
2078 * Now we are done with the proxy certificates, this
2079 * cert was an EE cert and we we will fall though to
2080 * EE checking below.
2088 * If there where any proxy certificates in the chain
2089 * (proxy_cert_depth > 0), check that the proxy issuer
2090 * matched proxy certificates "base" subject.
2092 if (proxy_cert_depth
) {
2094 ret
= _hx509_name_cmp(&proxy_issuer
,
2095 &c
->tbsCertificate
.subject
, &diff
);
2097 hx509_set_error_string(context
, 0, ret
, "out of memory");
2101 ret
= HX509_PROXY_CERT_NAME_WRONG
;
2102 hx509_clear_error_string(context
);
2106 hx509_name_free(&cert
->basename
);
2108 ret
= _hx509_name_from_Name(&proxy_issuer
, &cert
->basename
);
2110 hx509_clear_error_string(context
);
2118 ret
= check_basic_constraints(context
, c
, type
,
2119 i
- proxy_cert_depth
- selfsigned_depth
);
2124 * Don't check the trust anchors expiration time since they
2125 * are transported out of band, from RFC3820.
2127 if (i
+ 1 != path
.len
|| CHECK_TA(ctx
)) {
2129 t
= _hx509_Time2time_t(&c
->tbsCertificate
.validity
.notBefore
);
2130 if (t
> ctx
->time_now
) {
2131 ret
= HX509_CERT_USED_BEFORE_TIME
;
2132 hx509_clear_error_string(context
);
2135 t
= _hx509_Time2time_t(&c
->tbsCertificate
.validity
.notAfter
);
2136 if (t
< ctx
->time_now
) {
2137 ret
= HX509_CERT_USED_AFTER_TIME
;
2138 hx509_clear_error_string(context
);
2143 if (type
== EE_CERT
)
2145 else if (type
== PROXY_CERT
)
2150 * Verify constraints, do this backward so path constraints are
2151 * checked in the right order.
2154 for (ret
= 0, i
= path
.len
- 1; i
>= 0; i
--) {
2158 c
= _hx509_get_cert(path
.val
[i
]);
2160 ret
= certificate_is_self_signed(context
, c
, &selfsigned
);
2164 /* verify name constraints, not for selfsigned and anchor */
2165 if (!selfsigned
|| i
+ 1 != path
.len
) {
2166 ret
= check_name_constraints(context
, &nc
, c
);
2171 ret
= add_name_constraints(context
, c
, i
== 0, &nc
);
2175 /* XXX verify all other silly constraints */
2180 * Verify that no certificates has been revoked.
2183 if (ctx
->revoke_ctx
) {
2186 ret
= hx509_certs_init(context
, "MEMORY:revoke-certs", 0,
2191 for (i
= 0; i
< path
.len
; i
++) {
2192 ret
= hx509_certs_add(context
, certs
, path
.val
[i
]);
2194 hx509_certs_free(&certs
);
2198 ret
= hx509_certs_merge(context
, certs
, pool
);
2200 hx509_certs_free(&certs
);
2204 for (i
= 0; i
< path
.len
- 1; i
++) {
2205 int parent
= (i
< path
.len
- 1) ? i
+ 1 : i
;
2207 ret
= hx509_revoke_verify(context
,
2214 hx509_certs_free(&certs
);
2218 hx509_certs_free(&certs
);
2222 * Verify signatures, do this backward so public key working
2223 * parameter is passed up from the anchor up though the chain.
2226 for (i
= path
.len
- 1; i
>= 0; i
--) {
2227 Certificate
*signer
, *c
;
2229 c
= _hx509_get_cert(path
.val
[i
]);
2231 /* is last in chain (trust anchor) */
2232 if (i
+ 1 == path
.len
) {
2235 signer
= path
.val
[i
]->data
;
2237 ret
= certificate_is_self_signed(context
, signer
, &selfsigned
);
2241 /* if trust anchor is not self signed, don't check sig */
2245 /* take next certificate in chain */
2246 signer
= path
.val
[i
+ 1]->data
;
2249 /* verify signatureValue */
2250 ret
= _hx509_verify_signature_bitstring(context
,
2252 &c
->signatureAlgorithm
,
2253 &c
->tbsCertificate
._save
,
2254 &c
->signatureValue
);
2256 hx509_set_error_string(context
, HX509_ERROR_APPEND
, ret
,
2257 "Failed to verify signature of certificate");
2263 hx509_certs_free(&anchors
);
2264 free_Name(&proxy_issuer
);
2265 free_name_constraints(&nc
);
2266 _hx509_path_free(&path
);
2272 * Verify a signature made using the private key of an certificate.
2274 * @param context A hx509 context.
2275 * @param signer the certificate that made the signature.
2276 * @param alg algorthm that was used to sign the data.
2277 * @param data the data that was signed.
2278 * @param sig the sigature to verify.
2280 * @return An hx509 error code, see hx509_get_error_string().
2282 * @ingroup hx509_crypto
2286 hx509_verify_signature(hx509_context context
,
2287 const hx509_cert signer
,
2288 const AlgorithmIdentifier
*alg
,
2289 const heim_octet_string
*data
,
2290 const heim_octet_string
*sig
)
2292 return _hx509_verify_signature(context
, signer
->data
, alg
, data
, sig
);
2297 * Verify that the certificate is allowed to be used for the hostname
2300 * @param context A hx509 context.
2301 * @param cert the certificate to match with
2302 * @param flags Flags to modify the behavior:
2303 * - HX509_VHN_F_ALLOW_NO_MATCH no match is ok
2304 * @param type type of hostname:
2305 * - HX509_HN_HOSTNAME for plain hostname.
2306 * - HX509_HN_DNSSRV for DNS SRV names.
2307 * @param hostname the hostname to check
2308 * @param sa address of the host
2309 * @param sa_size length of address
2311 * @return An hx509 error code, see hx509_get_error_string().
2313 * @ingroup hx509_cert
2317 hx509_verify_hostname(hx509_context context
,
2318 const hx509_cert cert
,
2320 hx509_hostname_type type
,
2321 const char *hostname
,
2322 const struct sockaddr
*sa
,
2323 /* XXX krb5_socklen_t */ int sa_size
)
2328 if (sa
&& sa_size
<= 0)
2331 memset(&san
, 0, sizeof(san
));
2335 ret
= find_extension_subject_alt_name(cert
->data
, &i
, &san
);
2336 if (ret
== HX509_EXTENSION_NOT_FOUND
) {
2339 } else if (ret
!= 0)
2342 for (j
= 0; j
< san
.len
; j
++) {
2343 switch (san
.val
[j
].element
) {
2344 case choice_GeneralName_dNSName
:
2345 if (strcasecmp(san
.val
[j
].u
.dNSName
, hostname
) == 0) {
2346 free_GeneralNames(&san
);
2354 free_GeneralNames(&san
);
2358 const Name
*name
= &cert
->data
->tbsCertificate
.subject
;
2360 /* match if first component is a CN= */
2361 if (name
->u
.rdnSequence
.len
> 0
2362 && name
->u
.rdnSequence
.val
[0].len
== 1
2363 && der_heim_oid_cmp(&name
->u
.rdnSequence
.val
[0].val
[0].type
,
2364 oid_id_at_commonName()) == 0)
2366 DirectoryString
*ds
= &name
->u
.rdnSequence
.val
[0].val
[0].value
;
2368 switch (ds
->element
) {
2369 case choice_DirectoryString_printableString
:
2370 if (strcasecmp(ds
->u
.printableString
, hostname
) == 0)
2373 case choice_DirectoryString_ia5String
:
2374 if (strcasecmp(ds
->u
.ia5String
, hostname
) == 0)
2377 case choice_DirectoryString_utf8String
:
2378 if (strcasecmp(ds
->u
.utf8String
, hostname
) == 0)
2386 if ((flags
& HX509_VHN_F_ALLOW_NO_MATCH
) == 0)
2387 ret
= HX509_NAME_CONSTRAINT_ERROR
;
2393 _hx509_set_cert_attribute(hx509_context context
,
2395 const heim_oid
*oid
,
2396 const heim_octet_string
*attr
)
2398 hx509_cert_attribute a
;
2401 if (hx509_cert_get_attribute(cert
, oid
) != NULL
)
2404 d
= realloc(cert
->attrs
.val
,
2405 sizeof(cert
->attrs
.val
[0]) * (cert
->attrs
.len
+ 1));
2407 hx509_clear_error_string(context
);
2410 cert
->attrs
.val
= d
;
2412 a
= malloc(sizeof(*a
));
2416 der_copy_octet_string(attr
, &a
->data
);
2417 der_copy_oid(oid
, &a
->oid
);
2419 cert
->attrs
.val
[cert
->attrs
.len
] = a
;
2426 * Get an external attribute for the certificate, examples are
2427 * friendly name and id.
2429 * @param cert hx509 certificate object to search
2430 * @param oid an oid to search for.
2432 * @return an hx509_cert_attribute, only valid as long as the
2433 * certificate is referenced.
2435 * @ingroup hx509_cert
2438 hx509_cert_attribute
2439 hx509_cert_get_attribute(hx509_cert cert
, const heim_oid
*oid
)
2442 for (i
= 0; i
< cert
->attrs
.len
; i
++)
2443 if (der_heim_oid_cmp(oid
, &cert
->attrs
.val
[i
]->oid
) == 0)
2444 return cert
->attrs
.val
[i
];
2449 * Set the friendly name on the certificate.
2451 * @param cert The certificate to set the friendly name on
2452 * @param name Friendly name.
2454 * @return An hx509 error code, see hx509_get_error_string().
2456 * @ingroup hx509_cert
2460 hx509_cert_set_friendly_name(hx509_cert cert
, const char *name
)
2462 if (cert
->friendlyname
)
2463 free(cert
->friendlyname
);
2464 cert
->friendlyname
= strdup(name
);
2465 if (cert
->friendlyname
== NULL
)
2471 * Get friendly name of the certificate.
2473 * @param cert cert to get the friendly name from.
2475 * @return an friendly name or NULL if there is. The friendly name is
2476 * only valid as long as the certificate is referenced.
2478 * @ingroup hx509_cert
2482 hx509_cert_get_friendly_name(hx509_cert cert
)
2484 hx509_cert_attribute a
;
2485 PKCS9_friendlyName n
;
2489 if (cert
->friendlyname
)
2490 return cert
->friendlyname
;
2492 a
= hx509_cert_get_attribute(cert
, oid_id_pkcs_9_at_friendlyName());
2494 /* XXX use subject name ? */
2498 ret
= decode_PKCS9_friendlyName(a
->data
.data
, a
->data
.length
, &n
, &sz
);
2503 free_PKCS9_friendlyName(&n
);
2507 cert
->friendlyname
= malloc(n
.val
[0].length
+ 1);
2508 if (cert
->friendlyname
== NULL
) {
2509 free_PKCS9_friendlyName(&n
);
2513 for (i
= 0; i
< n
.val
[0].length
; i
++) {
2514 if (n
.val
[0].data
[i
] <= 0xff)
2515 cert
->friendlyname
[i
] = n
.val
[0].data
[i
] & 0xff;
2517 cert
->friendlyname
[i
] = 'X';
2519 cert
->friendlyname
[i
] = '\0';
2520 free_PKCS9_friendlyName(&n
);
2522 return cert
->friendlyname
;
2526 _hx509_query_clear(hx509_query
*q
)
2528 memset(q
, 0, sizeof(*q
));
2532 * Allocate an query controller. Free using hx509_query_free().
2534 * @param context A hx509 context.
2535 * @param q return pointer to a hx509_query.
2537 * @return An hx509 error code, see hx509_get_error_string().
2539 * @ingroup hx509_cert
2543 hx509_query_alloc(hx509_context context
, hx509_query
**q
)
2545 *q
= calloc(1, sizeof(**q
));
2553 * Set match options for the hx509 query controller.
2555 * @param q query controller.
2556 * @param option options to control the query controller.
2558 * @return An hx509 error code, see hx509_get_error_string().
2560 * @ingroup hx509_cert
2564 hx509_query_match_option(hx509_query
*q
, hx509_query_option option
)
2567 case HX509_QUERY_OPTION_PRIVATE_KEY
:
2568 q
->match
|= HX509_QUERY_PRIVATE_KEY
;
2570 case HX509_QUERY_OPTION_KU_ENCIPHERMENT
:
2571 q
->match
|= HX509_QUERY_KU_ENCIPHERMENT
;
2573 case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE
:
2574 q
->match
|= HX509_QUERY_KU_DIGITALSIGNATURE
;
2576 case HX509_QUERY_OPTION_KU_KEYCERTSIGN
:
2577 q
->match
|= HX509_QUERY_KU_KEYCERTSIGN
;
2579 case HX509_QUERY_OPTION_END
:
2586 * Set the issuer and serial number of match in the query
2587 * controller. The function make copies of the isser and serial number.
2589 * @param q a hx509 query controller
2590 * @param issuer issuer to search for
2591 * @param serialNumber the serialNumber of the issuer.
2593 * @return An hx509 error code, see hx509_get_error_string().
2595 * @ingroup hx509_cert
2599 hx509_query_match_issuer_serial(hx509_query
*q
,
2601 const heim_integer
*serialNumber
)
2605 der_free_heim_integer(q
->serial
);
2608 q
->serial
= malloc(sizeof(*q
->serial
));
2609 if (q
->serial
== NULL
)
2611 ret
= der_copy_heim_integer(serialNumber
, q
->serial
);
2617 if (q
->issuer_name
) {
2618 free_Name(q
->issuer_name
);
2619 free(q
->issuer_name
);
2621 q
->issuer_name
= malloc(sizeof(*q
->issuer_name
));
2622 if (q
->issuer_name
== NULL
)
2624 ret
= copy_Name(issuer
, q
->issuer_name
);
2626 free(q
->issuer_name
);
2627 q
->issuer_name
= NULL
;
2630 q
->match
|= HX509_QUERY_MATCH_SERIALNUMBER
|HX509_QUERY_MATCH_ISSUER_NAME
;
2635 * Set the query controller to match on a friendly name
2637 * @param q a hx509 query controller.
2638 * @param name a friendly name to match on
2640 * @return An hx509 error code, see hx509_get_error_string().
2642 * @ingroup hx509_cert
2646 hx509_query_match_friendly_name(hx509_query
*q
, const char *name
)
2648 if (q
->friendlyname
)
2649 free(q
->friendlyname
);
2650 q
->friendlyname
= strdup(name
);
2651 if (q
->friendlyname
== NULL
)
2653 q
->match
|= HX509_QUERY_MATCH_FRIENDLY_NAME
;
2658 * Set the query controller to require an one specific EKU (extended
2659 * key usage). Any previous EKU matching is overwitten. If NULL is
2660 * passed in as the eku, the EKU requirement is reset.
2662 * @param q a hx509 query controller.
2663 * @param eku an EKU to match on.
2665 * @return An hx509 error code, see hx509_get_error_string().
2667 * @ingroup hx509_cert
2671 hx509_query_match_eku(hx509_query
*q
, const heim_oid
*eku
)
2677 der_free_oid(q
->eku
);
2681 q
->match
&= ~HX509_QUERY_MATCH_EKU
;
2684 der_free_oid(q
->eku
);
2686 q
->eku
= calloc(1, sizeof(*q
->eku
));
2690 ret
= der_copy_oid(eku
, q
->eku
);
2696 q
->match
|= HX509_QUERY_MATCH_EKU
;
2702 hx509_query_match_expr(hx509_context context
, hx509_query
*q
, const char *expr
)
2705 _hx509_expr_free(q
->expr
);
2710 q
->match
&= ~HX509_QUERY_MATCH_EXPR
;
2712 q
->expr
= _hx509_expr_parse(expr
);
2714 q
->match
|= HX509_QUERY_MATCH_EXPR
;
2721 * Set the query controller to match using a specific match function.
2723 * @param q a hx509 query controller.
2724 * @param func function to use for matching, if the argument is NULL,
2725 * the match function is removed.
2726 * @param ctx context passed to the function.
2728 * @return An hx509 error code, see hx509_get_error_string().
2730 * @ingroup hx509_cert
2734 hx509_query_match_cmp_func(hx509_query
*q
,
2735 int (*func
)(void *, hx509_cert
),
2739 q
->match
|= HX509_QUERY_MATCH_FUNCTION
;
2741 q
->match
&= ~HX509_QUERY_MATCH_FUNCTION
;
2743 q
->cmp_func_ctx
= ctx
;
2748 * Free the query controller.
2750 * @param context A hx509 context.
2751 * @param q a pointer to the query controller.
2753 * @ingroup hx509_cert
2757 hx509_query_free(hx509_context context
, hx509_query
*q
)
2763 der_free_heim_integer(q
->serial
);
2766 if (q
->issuer_name
) {
2767 free_Name(q
->issuer_name
);
2768 free(q
->issuer_name
);
2771 der_free_oid(q
->eku
);
2774 if (q
->friendlyname
)
2775 free(q
->friendlyname
);
2777 _hx509_expr_free(q
->expr
);
2779 memset(q
, 0, sizeof(*q
));
2784 _hx509_query_match_cert(hx509_context context
, const hx509_query
*q
, hx509_cert cert
)
2786 Certificate
*c
= _hx509_get_cert(cert
);
2789 _hx509_query_statistic(context
, 1, q
);
2791 if ((q
->match
& HX509_QUERY_FIND_ISSUER_CERT
) &&
2792 _hx509_cert_is_parent_cmp(q
->subject
, c
, 0) != 0)
2795 if ((q
->match
& HX509_QUERY_MATCH_CERTIFICATE
) &&
2796 _hx509_Certificate_cmp(q
->certificate
, c
) != 0)
2799 if ((q
->match
& HX509_QUERY_MATCH_SERIALNUMBER
)
2800 && der_heim_integer_cmp(&c
->tbsCertificate
.serialNumber
, q
->serial
) != 0)
2803 if (q
->match
& HX509_QUERY_MATCH_ISSUER_NAME
) {
2804 ret
= _hx509_name_cmp(&c
->tbsCertificate
.issuer
, q
->issuer_name
, &diff
);
2809 if (q
->match
& HX509_QUERY_MATCH_SUBJECT_NAME
) {
2810 ret
= _hx509_name_cmp(&c
->tbsCertificate
.subject
, q
->subject_name
, &diff
);
2815 if (q
->match
& HX509_QUERY_MATCH_SUBJECT_KEY_ID
) {
2816 SubjectKeyIdentifier si
;
2818 ret
= _hx509_find_extension_subject_key_id(c
, &si
);
2820 if (der_heim_octet_string_cmp(&si
, q
->subject_id
) != 0)
2822 free_SubjectKeyIdentifier(&si
);
2827 if ((q
->match
& HX509_QUERY_MATCH_ISSUER_ID
))
2829 if ((q
->match
& HX509_QUERY_PRIVATE_KEY
) &&
2830 _hx509_cert_private_key(cert
) == NULL
)
2835 if (q
->match
& HX509_QUERY_KU_DIGITALSIGNATURE
)
2837 if (q
->match
& HX509_QUERY_KU_NONREPUDIATION
)
2839 if (q
->match
& HX509_QUERY_KU_ENCIPHERMENT
)
2841 if (q
->match
& HX509_QUERY_KU_DATAENCIPHERMENT
)
2843 if (q
->match
& HX509_QUERY_KU_KEYAGREEMENT
)
2845 if (q
->match
& HX509_QUERY_KU_KEYCERTSIGN
)
2847 if (q
->match
& HX509_QUERY_KU_CRLSIGN
)
2849 if (ku
&& check_key_usage(context
, c
, ku
, TRUE
))
2852 if ((q
->match
& HX509_QUERY_ANCHOR
))
2855 if (q
->match
& HX509_QUERY_MATCH_LOCAL_KEY_ID
) {
2856 hx509_cert_attribute a
;
2858 a
= hx509_cert_get_attribute(cert
, oid_id_pkcs_9_at_localKeyId());
2861 if (der_heim_octet_string_cmp(&a
->data
, q
->local_key_id
) != 0)
2865 if (q
->match
& HX509_QUERY_NO_MATCH_PATH
) {
2868 for (i
= 0; i
< q
->path
->len
; i
++)
2869 if (hx509_cert_cmp(q
->path
->val
[i
], cert
) == 0)
2872 if (q
->match
& HX509_QUERY_MATCH_FRIENDLY_NAME
) {
2873 const char *name
= hx509_cert_get_friendly_name(cert
);
2876 if (strcasecmp(q
->friendlyname
, name
) != 0)
2879 if (q
->match
& HX509_QUERY_MATCH_FUNCTION
) {
2880 ret
= (*q
->cmp_func
)(q
->cmp_func_ctx
, cert
);
2885 if (q
->match
& HX509_QUERY_MATCH_KEY_HASH_SHA1
) {
2886 heim_octet_string os
;
2888 os
.data
= c
->tbsCertificate
.subjectPublicKeyInfo
.subjectPublicKey
.data
;
2890 c
->tbsCertificate
.subjectPublicKeyInfo
.subjectPublicKey
.length
/ 8;
2892 ret
= _hx509_verify_signature(context
,
2894 hx509_signature_sha1(),
2901 if (q
->match
& HX509_QUERY_MATCH_TIME
) {
2903 t
= _hx509_Time2time_t(&c
->tbsCertificate
.validity
.notBefore
);
2906 t
= _hx509_Time2time_t(&c
->tbsCertificate
.validity
.notAfter
);
2911 /* If an EKU is required, check the cert for it. */
2912 if ((q
->match
& HX509_QUERY_MATCH_EKU
) &&
2913 hx509_cert_check_eku(context
, cert
, q
->eku
, 0))
2916 if ((q
->match
& HX509_QUERY_MATCH_EXPR
)) {
2917 hx509_env env
= NULL
;
2919 ret
= _hx509_cert_to_env(context
, cert
, &env
);
2923 ret
= _hx509_expr_eval(context
, env
, q
->expr
);
2924 hx509_env_free(&env
);
2929 if (q
->match
& ~HX509_QUERY_MASK
)
2936 * Set a statistic file for the query statistics.
2938 * @param context A hx509 context.
2939 * @param fn statistics file name
2941 * @ingroup hx509_cert
2945 hx509_query_statistic_file(hx509_context context
, const char *fn
)
2947 if (context
->querystat
)
2948 free(context
->querystat
);
2949 context
->querystat
= strdup(fn
);
2953 _hx509_query_statistic(hx509_context context
, int type
, const hx509_query
*q
)
2956 if (context
->querystat
== NULL
)
2958 f
= fopen(context
->querystat
, "a");
2961 fprintf(f
, "%d %d\n", type
, q
->match
);
2965 static const char *statname
[] = {
2967 "match serialnumber",
2968 "match issuer name",
2969 "match subject name",
2970 "match subject key id",
2974 "ku digitalsignature",
2977 "ku nonrepudiation",
2979 "ku dataencipherment",
2981 "match certificate",
2982 "match local key id",
2984 "match friendly name",
2986 "match key hash sha1",
2991 unsigned long stats
;
2997 stat_sort(const void *a
, const void *b
)
2999 const struct stat_el
*ae
= a
;
3000 const struct stat_el
*be
= b
;
3001 return be
->stats
- ae
->stats
;
3005 * Unparse the statistics file and print the result on a FILE descriptor.
3007 * @param context A hx509 context.
3008 * @param printtype tyep to print
3009 * @param out the FILE to write the data on.
3011 * @ingroup hx509_cert
3015 hx509_query_unparse_stats(hx509_context context
, int printtype
, FILE *out
)
3019 int type
, mask
, i
, num
;
3020 unsigned long multiqueries
= 0, totalqueries
= 0;
3021 struct stat_el stats
[32];
3023 if (context
->querystat
== NULL
)
3025 f
= fopen(context
->querystat
, "r");
3027 fprintf(out
, "No statistic file %s: %s.\n",
3028 context
->querystat
, strerror(errno
));
3032 for (i
= 0; i
< sizeof(stats
)/sizeof(stats
[0]); i
++) {
3037 while (fscanf(f
, "%d %d\n", &type
, &mask
) == 2) {
3038 if (type
!= printtype
)
3041 while (mask
&& i
< sizeof(stats
)/sizeof(stats
[0])) {
3055 qsort(stats
, sizeof(stats
)/sizeof(stats
[0]), sizeof(stats
[0]), stat_sort
);
3059 errx(1, "out of memory");
3061 rtbl_set_separator (t
, " ");
3063 rtbl_add_column_by_id (t
, 0, "Name", 0);
3064 rtbl_add_column_by_id (t
, 1, "Counter", 0);
3067 for (i
= 0; i
< sizeof(stats
)/sizeof(stats
[0]); i
++) {
3070 if (stats
[i
].index
< sizeof(statname
)/sizeof(statname
[0]))
3071 rtbl_add_column_entry_by_id (t
, 0, statname
[stats
[i
].index
]);
3073 snprintf(str
, sizeof(str
), "%d", stats
[i
].index
);
3074 rtbl_add_column_entry_by_id (t
, 0, str
);
3076 snprintf(str
, sizeof(str
), "%lu", stats
[i
].stats
);
3077 rtbl_add_column_entry_by_id (t
, 1, str
);
3080 rtbl_format(t
, out
);
3083 fprintf(out
, "\nQueries: multi %lu total %lu\n",
3084 multiqueries
, totalqueries
);
3088 * Check the extended key usage on the hx509 certificate.
3090 * @param context A hx509 context.
3091 * @param cert A hx509 context.
3092 * @param eku the EKU to check for
3093 * @param allow_any_eku if the any EKU is set, allow that to be a
3096 * @return An hx509 error code, see hx509_get_error_string().
3098 * @ingroup hx509_cert
3102 hx509_cert_check_eku(hx509_context context
, hx509_cert cert
,
3103 const heim_oid
*eku
, int allow_any_eku
)
3108 ret
= find_extension_eku(_hx509_get_cert(cert
), &e
);
3110 hx509_clear_error_string(context
);
3114 for (i
= 0; i
< e
.len
; i
++) {
3115 if (der_heim_oid_cmp(eku
, &e
.val
[i
]) == 0) {
3116 free_ExtKeyUsage(&e
);
3119 if (allow_any_eku
) {
3121 if (der_heim_oid_cmp(id_any_eku
, &e
.val
[i
]) == 0) {
3122 free_ExtKeyUsage(&e
);
3128 free_ExtKeyUsage(&e
);
3129 hx509_clear_error_string(context
);
3130 return HX509_CERTIFICATE_MISSING_EKU
;
3134 _hx509_cert_get_keyusage(hx509_context context
,
3143 memset(ku
, 0, sizeof(*ku
));
3145 cert
= _hx509_get_cert(c
);
3147 if (_hx509_cert_get_version(cert
) < 3)
3150 e
= find_extension(cert
, oid_id_x509_ce_keyUsage(), &i
);
3152 return HX509_KU_CERT_MISSING
;
3154 ret
= decode_KeyUsage(e
->extnValue
.data
, e
->extnValue
.length
, ku
, &size
);
3161 _hx509_cert_get_eku(hx509_context context
,
3167 memset(e
, 0, sizeof(*e
));
3169 ret
= find_extension_eku(_hx509_get_cert(cert
), e
);
3170 if (ret
&& ret
!= HX509_EXTENSION_NOT_FOUND
) {
3171 hx509_clear_error_string(context
);
3178 * Encodes the hx509 certificate as a DER encode binary.
3180 * @param context A hx509 context.
3181 * @param c the certificate to encode.
3182 * @param os the encode certificate, set to NULL, 0 on case of
3183 * error. Free the returned structure with hx509_xfree().
3185 * @return An hx509 error code, see hx509_get_error_string().
3187 * @ingroup hx509_cert
3191 hx509_cert_binary(hx509_context context
, hx509_cert c
, heim_octet_string
*os
)
3199 ASN1_MALLOC_ENCODE(Certificate
, os
->data
, os
->length
,
3200 _hx509_get_cert(c
), &size
, ret
);
3206 if (os
->length
!= size
)
3207 _hx509_abort("internal ASN.1 encoder error");
3213 * Last to avoid lost __attribute__s due to #undef.
3216 #undef __attribute__
3217 #define __attribute__(X)
3220 _hx509_abort(const char *fmt
, ...)
3221 __attribute__ ((noreturn
, format (printf
, 1, 2)))
3233 * Free a data element allocated in the library.
3235 * @param ptr data to be freed.
3237 * @ingroup hx509_misc
3241 hx509_xfree(void *ptr
)
3251 _hx509_cert_to_env(hx509_context context
, hx509_cert cert
, hx509_env
*env
)
3257 hx509_env envcert
= NULL
;
3262 asprintf(&buf
, "%d", _hx509_cert_get_version(_hx509_get_cert(cert
)));
3263 ret
= hx509_env_add(context
, &envcert
, "version", buf
);
3269 ret
= hx509_cert_get_subject(cert
, &name
);
3273 ret
= hx509_name_to_string(name
, &buf
);
3275 hx509_name_free(&name
);
3279 ret
= hx509_env_add(context
, &envcert
, "subject", buf
);
3280 hx509_name_free(&name
);
3285 ret
= hx509_cert_get_issuer(cert
, &name
);
3289 ret
= hx509_name_to_string(name
, &buf
);
3290 hx509_name_free(&name
);
3294 ret
= hx509_env_add(context
, &envcert
, "issuer", buf
);
3301 ret
= _hx509_cert_get_eku(context
, cert
, &eku
);
3302 if (ret
== HX509_EXTENSION_NOT_FOUND
)
3308 hx509_env enveku
= NULL
;
3310 for (i
= 0; i
< eku
.len
; i
++) {
3312 ret
= der_print_heim_oid(&eku
.val
[i
], '.', &buf
);
3314 free_ExtKeyUsage(&eku
);
3315 hx509_env_free(&enveku
);
3318 ret
= hx509_env_add(context
, &enveku
, buf
, "oid-name-here");
3321 free_ExtKeyUsage(&eku
);
3322 hx509_env_free(&enveku
);
3326 free_ExtKeyUsage(&eku
);
3328 ret
= hx509_env_add_binding(context
, &envcert
, "eku", enveku
);
3330 hx509_env_free(&enveku
);
3335 ret
= hx509_env_add_binding(context
, env
, "certificate", envcert
);
3342 hx509_env_free(&envcert
);