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 #include "crypto-headers.h"
39 * @page page_cert The basic certificate
41 * The basic hx509 cerificate object in hx509 is hx509_cert. The
42 * hx509_cert object is representing one X509/PKIX certificate and
43 * associated attributes; like private key, friendly name, etc.
45 * A hx509_cert object is usully found via the keyset interfaces (@ref
46 * page_keyset), but its also possible to create a certificate
47 * directly from a parsed object with hx509_cert_init() and
48 * hx509_cert_init_data().
50 * See the library functions here: @ref hx509_cert
53 struct hx509_verify_ctx_data
{
54 hx509_certs trust_anchors
;
56 #define HX509_VERIFY_CTX_F_TIME_SET 1
57 #define HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE 2
58 #define HX509_VERIFY_CTX_F_REQUIRE_RFC3280 4
59 #define HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS 8
60 #define HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS 16
61 #define HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK 32
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 init_context_once(void *ignored
)
100 ENGINE_add_conf_module();
101 OpenSSL_add_all_algorithms();
105 * Return a cookie identifying this instance of a library.
109 * @context A krb5_context
110 * @module Our library name or a library we depend on
112 * Outputs: The instance cookie
114 * @ingroup krb5_support
117 HX509_LIB_FUNCTION
uintptr_t HX509_LIB_CALL
118 hx509_get_instance(const char *libname
)
120 static const char *instance
= "libhx509";
122 if (strcmp(libname
, "hx509") == 0)
123 return (uintptr_t)instance
;
129 # define PATH_SEP ":"
131 static const char *hx509_config_file
=
132 "~/.hx509/config" PATH_SEP
133 SYSCONFDIR
"/hx509.conf" PATH_SEP
135 "%{COMMON_APPDATA}/Heimdal/hx509.conf" PATH_SEP
136 "%{WINDOWS}/hx509.ini"
143 * Creates a hx509 context that most functions in the library
144 * uses. The context is only allowed to be used by one thread at each
145 * moment. Free the context with hx509_context_free().
147 * @param context Returns a pointer to new hx509 context.
149 * @return Returns an hx509 error code.
154 HX509_LIB_FUNCTION
int HX509_LIB_CALL
155 hx509_context_init(hx509_context
*contextp
)
157 static heim_base_once_t init_context
= HEIM_BASE_ONCE_INIT
;
159 hx509_context context
;
164 context
= calloc(1, sizeof(*context
));
168 heim_base_once_f(&init_context
, NULL
, init_context_once
);
170 if ((context
->hcontext
= heim_context_init()) == NULL
) {
175 if ((ret
= heim_get_default_config_files(hx509_config_file
,
178 heim_context_free(&context
->hcontext
);
183 /* If there's no hx509 config, we continue, as we never needed it before */
185 (void) heim_set_config_files(context
->hcontext
, files
, &context
->cf
);
186 heim_free_config_files(files
);
188 _hx509_ks_null_register(context
);
189 _hx509_ks_mem_register(context
);
190 _hx509_ks_file_register(context
);
191 _hx509_ks_pkcs12_register(context
);
192 _hx509_ks_pkcs11_register(context
);
193 _hx509_ks_dir_register(context
);
194 _hx509_ks_keychain_register(context
);
196 context
->ocsp_time_diff
=
197 heim_config_get_time_default(context
->hcontext
, context
->cf
,
198 HX509_DEFAULT_OCSP_TIME_DIFF
,
199 "libdefaults", "ocsp_time_dif", NULL
);
201 initialize_hx_error_table_r(&context
->et_list
);
202 initialize_asn1_error_table_r(&context
->et_list
);
204 #ifdef HX509_DEFAULT_ANCHORS
205 anchors
= heim_config_get_string_default(context
->hcontext
, context
->cf
,
206 HX509_DEFAULT_ANCHORS
,
207 "libdefaults", "anchors", NULL
);
209 anchors
= heim_config_get_string(context
->hcontext
, context
->cf
,
210 "libdefaults", "anchors", NULL
);
213 (void)hx509_certs_init(context
, anchors
, 0, NULL
,
214 &context
->default_trust_anchors
);
220 HX509_LIB_FUNCTION
int HX509_LIB_CALL
221 hx509_set_log_dest(hx509_context context
, heim_log_facility
*fac
)
223 return heim_set_log_dest(context
->hcontext
, fac
);
226 HX509_LIB_FUNCTION
int HX509_LIB_CALL
227 hx509_set_debug_dest(hx509_context context
, heim_log_facility
*fac
)
229 return heim_set_debug_dest(context
->hcontext
, fac
);
232 HX509_LIB_FUNCTION
int HX509_LIB_CALL
233 hx509_set_warn_dest(hx509_context context
, heim_log_facility
*fac
)
235 return heim_set_warn_dest(context
->hcontext
, fac
);
239 * Selects if the hx509_revoke_verify() function is going to require
240 * the existence of a revocation method (OCSP, CRL) or not. Note that
241 * hx509_verify_path(), hx509_cms_verify_signed(), and other functions
242 * call hx509_revoke_verify().
244 * @param context hx509 context to change the flag for.
245 * @param flag zero, revocation method required, non zero missing
246 * revocation method ok
248 * @ingroup hx509_verify
251 HX509_LIB_FUNCTION
void HX509_LIB_CALL
252 hx509_context_set_missing_revoke(hx509_context context
, int flag
)
255 context
->flags
|= HX509_CTX_VERIFY_MISSING_OK
;
257 context
->flags
&= ~HX509_CTX_VERIFY_MISSING_OK
;
261 * Free the context allocated by hx509_context_init().
263 * @param context context to be freed.
268 HX509_LIB_FUNCTION
void HX509_LIB_CALL
269 hx509_context_free(hx509_context
*context
)
274 hx509_clear_error_string(*context
);
275 if ((*context
)->ks_ops
) {
276 free((*context
)->ks_ops
);
277 (*context
)->ks_ops
= NULL
;
279 (*context
)->ks_num_ops
= 0;
280 free_error_table ((*context
)->et_list
);
281 if ((*context
)->querystat
)
282 free((*context
)->querystat
);
283 hx509_certs_free(&(*context
)->default_trust_anchors
);
284 heim_config_file_free((*context
)->hcontext
, (*context
)->cf
);
285 heim_context_free(&(*context
)->hcontext
);
286 memset(*context
, 0, sizeof(**context
));
295 HX509_LIB_FUNCTION Certificate
* HX509_LIB_CALL
296 _hx509_get_cert(hx509_cert cert
)
305 HX509_LIB_FUNCTION
int HX509_LIB_CALL
306 _hx509_cert_get_version(const Certificate
*t
)
308 return t
->tbsCertificate
.version
? *t
->tbsCertificate
.version
+ 1 : 1;
312 cert_init(hx509_context context
, heim_error_t
*error
)
316 cert
= malloc(sizeof(*cert
));
319 *error
= heim_error_create_enomem();
323 cert
->friendlyname
= NULL
;
325 cert
->attrs
.val
= NULL
;
326 cert
->private_key
= NULL
;
327 cert
->basename
= NULL
;
328 cert
->release
= NULL
;
335 * Allocate and init an hx509 certificate object from the decoded
338 * @param context A hx509 context.
342 * @return Returns an hx509 certificate
344 * @ingroup hx509_cert
347 HX509_LIB_FUNCTION hx509_cert HX509_LIB_CALL
348 hx509_cert_init(hx509_context context
, const Certificate
*c
, heim_error_t
*error
)
353 if ((cert
= cert_init(context
, error
)) == NULL
)
356 cert
->data
= calloc(1, sizeof(*(cert
->data
)));
357 if (cert
->data
== NULL
) {
360 *error
= heim_error_create_enomem();
363 ret
= copy_Certificate(c
, cert
->data
);
373 * Copy a certificate object, but drop any private key assignment.
375 * @param context A hx509 context.
376 * @param src Certificate object
379 * @return Returns an hx509 certificate
381 * @ingroup hx509_cert
384 HX509_LIB_FUNCTION hx509_cert HX509_LIB_CALL
385 hx509_cert_copy_no_private_key(hx509_context context
,
389 return hx509_cert_init(context
, src
->data
, error
);
393 * Allocate and init an hx509 certificate object containing only a private key
394 * (but no Certificate).
396 * @param context A hx509 context.
400 * @return Returns an hx509 certificate
402 * @ingroup hx509_cert
405 HX509_LIB_FUNCTION hx509_cert HX509_LIB_CALL
406 hx509_cert_init_private_key(hx509_context context
,
407 hx509_private_key key
,
412 if ((cert
= cert_init(context
, error
)))
413 (void) _hx509_cert_assign_key(cert
, key
);
418 * Just like hx509_cert_init(), but instead of a decode certificate
419 * takes an pointer and length to a memory region that contains a
420 * DER/BER encoded certificate.
422 * If the memory region doesn't contain just the certificate and
423 * nothing more the function will fail with
424 * HX509_EXTRA_DATA_AFTER_STRUCTURE.
426 * @param context A hx509 context.
427 * @param ptr pointer to memory region containing encoded certificate.
428 * @param len length of memory region.
429 * @param error possibly returns an error
431 * @return An hx509 certificate
433 * @ingroup hx509_cert
436 HX509_LIB_FUNCTION hx509_cert HX509_LIB_CALL
437 hx509_cert_init_data(hx509_context context
,
447 ret
= decode_Certificate(ptr
, len
, &t
, &size
);
450 *error
= heim_error_create(ret
, "Failed to decode certificate");
455 free_Certificate(&t
);
457 *error
= heim_error_create(HX509_EXTRA_DATA_AFTER_STRUCTURE
,
458 "Extra data after certificate");
459 errno
= HX509_EXTRA_DATA_AFTER_STRUCTURE
;
463 cert
= hx509_cert_init(context
, &t
, error
);
464 free_Certificate(&t
);
468 HX509_LIB_FUNCTION
void HX509_LIB_CALL
469 _hx509_cert_set_release(hx509_cert cert
,
470 _hx509_cert_release_func release
,
473 cert
->release
= release
;
478 /* Doesn't make a copy of `private_key'. */
480 HX509_LIB_FUNCTION
int HX509_LIB_CALL
481 _hx509_cert_assign_key(hx509_cert cert
, hx509_private_key private_key
)
483 if (cert
->private_key
)
484 hx509_private_key_free(&cert
->private_key
);
485 cert
->private_key
= _hx509_private_key_ref(private_key
);
490 * Free reference to the hx509 certificate object, if the refcounter
491 * reaches 0, the object if freed. Its allowed to pass in NULL.
493 * @param cert the cert to free.
495 * @ingroup hx509_cert
498 HX509_LIB_FUNCTION
void HX509_LIB_CALL
499 hx509_cert_free(hx509_cert cert
)
507 _hx509_abort("cert refcount <= 0 on free");
512 (cert
->release
)(cert
, cert
->ctx
);
514 if (cert
->private_key
)
515 hx509_private_key_free(&cert
->private_key
);
518 free_Certificate(cert
->data
);
521 for (i
= 0; i
< cert
->attrs
.len
; i
++) {
522 der_free_octet_string(&cert
->attrs
.val
[i
]->data
);
523 der_free_oid(&cert
->attrs
.val
[i
]->oid
);
524 free(cert
->attrs
.val
[i
]);
526 free(cert
->attrs
.val
);
527 free(cert
->friendlyname
);
529 hx509_name_free(&cert
->basename
);
530 memset(cert
, 0, sizeof(*cert
));
535 * Add a reference to a hx509 certificate object.
537 * @param cert a pointer to an hx509 certificate object.
539 * @return the same object as is passed in.
541 * @ingroup hx509_cert
544 HX509_LIB_FUNCTION hx509_cert HX509_LIB_CALL
545 hx509_cert_ref(hx509_cert cert
)
550 _hx509_abort("cert refcount <= 0");
553 _hx509_abort("cert refcount == 0");
558 * Allocate an verification context that is used to control the
559 * verification process.
561 * @param context A hx509 context.
562 * @param ctx returns a pointer to a hx509_verify_ctx object.
564 * @return An hx509 error code, see hx509_get_error_string().
566 * @ingroup hx509_verify
569 HX509_LIB_FUNCTION
int HX509_LIB_CALL
570 hx509_verify_init_ctx(hx509_context context
, hx509_verify_ctx
*ctx
)
574 c
= calloc(1, sizeof(*c
));
578 c
->max_depth
= HX509_VERIFY_MAX_DEPTH
;
586 * Free an hx509 verification context.
588 * @param ctx the context to be freed.
590 * @ingroup hx509_verify
593 HX509_LIB_FUNCTION
void HX509_LIB_CALL
594 hx509_verify_destroy_ctx(hx509_verify_ctx ctx
)
597 hx509_certs_free(&ctx
->trust_anchors
);
598 hx509_revoke_free(&ctx
->revoke_ctx
);
599 memset(ctx
, 0, sizeof(*ctx
));
605 * Set the trust anchors in the verification context, makes an
606 * reference to the keyset, so the consumer can free the keyset
607 * independent of the destruction of the verification context (ctx).
608 * If there already is a keyset attached, it's released.
610 * @param ctx a verification context
611 * @param set a keyset containing the trust anchors.
613 * @ingroup hx509_verify
616 HX509_LIB_FUNCTION
void HX509_LIB_CALL
617 hx509_verify_attach_anchors(hx509_verify_ctx ctx
, hx509_certs set
)
619 if (ctx
->trust_anchors
)
620 hx509_certs_free(&ctx
->trust_anchors
);
621 ctx
->trust_anchors
= hx509_certs_ref(set
);
625 * Attach an revocation context to the verfication context, , makes an
626 * reference to the revoke context, so the consumer can free the
627 * revoke context independent of the destruction of the verification
628 * context. If there is no revoke context, the verification process is
629 * NOT going to check any verification status.
631 * @param ctx a verification context.
632 * @param revoke_ctx a revoke context.
634 * @ingroup hx509_verify
637 HX509_LIB_FUNCTION
void HX509_LIB_CALL
638 hx509_verify_attach_revoke(hx509_verify_ctx ctx
, hx509_revoke_ctx revoke_ctx
)
641 hx509_revoke_free(&ctx
->revoke_ctx
);
642 ctx
->revoke_ctx
= _hx509_revoke_ref(revoke_ctx
);
646 * Set the clock time the the verification process is going to
647 * use. Used to check certificate in the past and future time. If not
648 * set the current time will be used.
650 * @param ctx a verification context.
651 * @param t the time the verifiation is using.
654 * @ingroup hx509_verify
657 HX509_LIB_FUNCTION
void HX509_LIB_CALL
658 hx509_verify_set_time(hx509_verify_ctx ctx
, time_t t
)
660 ctx
->flags
|= HX509_VERIFY_CTX_F_TIME_SET
;
664 HX509_LIB_FUNCTION
time_t HX509_LIB_CALL
665 _hx509_verify_get_time(hx509_verify_ctx ctx
)
667 return ctx
->time_now
;
671 * Set the maximum depth of the certificate chain that the path
672 * builder is going to try.
674 * @param ctx a verification context
675 * @param max_depth maxium depth of the certificate chain, include
678 * @ingroup hx509_verify
681 HX509_LIB_FUNCTION
void HX509_LIB_CALL
682 hx509_verify_set_max_depth(hx509_verify_ctx ctx
, unsigned int max_depth
)
684 ctx
->max_depth
= max_depth
;
688 * Allow or deny the use of proxy certificates
690 * @param ctx a verification context
691 * @param boolean if non zero, allow proxy certificates.
693 * @ingroup hx509_verify
696 HX509_LIB_FUNCTION
void HX509_LIB_CALL
697 hx509_verify_set_proxy_certificate(hx509_verify_ctx ctx
, int boolean
)
700 ctx
->flags
|= HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE
;
702 ctx
->flags
&= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE
;
706 * Select strict RFC3280 verification of certificiates. This means
707 * checking key usage on CA certificates, this will make version 1
708 * certificiates unuseable.
710 * @param ctx a verification context
711 * @param boolean if non zero, use strict verification.
713 * @ingroup hx509_verify
716 HX509_LIB_FUNCTION
void HX509_LIB_CALL
717 hx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx
, int boolean
)
720 ctx
->flags
|= HX509_VERIFY_CTX_F_REQUIRE_RFC3280
;
722 ctx
->flags
&= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280
;
726 * Allow using the operating system builtin trust anchors if no other
727 * trust anchors are configured.
729 * @param ctx a verification context
730 * @param boolean if non zero, useing the operating systems builtin
734 * @return An hx509 error code, see hx509_get_error_string().
736 * @ingroup hx509_cert
739 HX509_LIB_FUNCTION
void HX509_LIB_CALL
740 hx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx
, int boolean
)
743 ctx
->flags
&= ~HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS
;
745 ctx
->flags
|= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS
;
748 HX509_LIB_FUNCTION
void HX509_LIB_CALL
749 hx509_verify_ctx_f_allow_best_before_signature_algs(hx509_context ctx
,
753 ctx
->flags
&= ~HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK
;
755 ctx
->flags
|= HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK
;
758 static const Extension
*
759 find_extension(const Certificate
*cert
, const heim_oid
*oid
, size_t *idx
)
761 const TBSCertificate
*c
= &cert
->tbsCertificate
;
763 if (c
->version
== NULL
|| *c
->version
< 2 || c
->extensions
== NULL
)
766 for (;*idx
< c
->extensions
->len
; (*idx
)++) {
767 if (der_heim_oid_cmp(&c
->extensions
->val
[*idx
].extnID
, oid
) == 0)
768 return &c
->extensions
->val
[(*idx
)++];
774 find_extension_auth_key_id(const Certificate
*subject
,
775 AuthorityKeyIdentifier
*ai
)
781 memset(ai
, 0, sizeof(*ai
));
783 e
= find_extension(subject
, &asn1_oid_id_x509_ce_authorityKeyIdentifier
, &i
);
785 return HX509_EXTENSION_NOT_FOUND
;
787 return decode_AuthorityKeyIdentifier(e
->extnValue
.data
,
792 HX509_LIB_FUNCTION
int HX509_LIB_CALL
793 _hx509_find_extension_subject_key_id(const Certificate
*issuer
,
794 SubjectKeyIdentifier
*si
)
800 memset(si
, 0, sizeof(*si
));
802 e
= find_extension(issuer
, &asn1_oid_id_x509_ce_subjectKeyIdentifier
, &i
);
804 return HX509_EXTENSION_NOT_FOUND
;
806 return decode_SubjectKeyIdentifier(e
->extnValue
.data
,
812 find_extension_name_constraints(const Certificate
*subject
,
819 memset(nc
, 0, sizeof(*nc
));
821 e
= find_extension(subject
, &asn1_oid_id_x509_ce_nameConstraints
, &i
);
823 return HX509_EXTENSION_NOT_FOUND
;
825 return decode_NameConstraints(e
->extnValue
.data
,
831 find_extension_subject_alt_name(const Certificate
*cert
, size_t *i
,
837 memset(sa
, 0, sizeof(*sa
));
839 e
= find_extension(cert
, &asn1_oid_id_x509_ce_subjectAltName
, i
);
841 return HX509_EXTENSION_NOT_FOUND
;
843 return decode_GeneralNames(e
->extnValue
.data
,
849 find_extension_eku(const Certificate
*cert
, ExtKeyUsage
*eku
)
855 memset(eku
, 0, sizeof(*eku
));
857 e
= find_extension(cert
, &asn1_oid_id_x509_ce_extKeyUsage
, &i
);
859 return HX509_EXTENSION_NOT_FOUND
;
861 return decode_ExtKeyUsage(e
->extnValue
.data
,
867 add_to_list(hx509_octet_string_list
*list
, const heim_octet_string
*entry
)
872 p
= realloc(list
->val
, (list
->len
+ 1) * sizeof(list
->val
[0]));
876 ret
= der_copy_octet_string(entry
, &list
->val
[list
->len
]);
884 * Free a list of octet strings returned by another hx509 library
887 * @param list list to be freed.
889 * @ingroup hx509_misc
892 HX509_LIB_FUNCTION
void HX509_LIB_CALL
893 hx509_free_octet_string_list(hx509_octet_string_list
*list
)
898 for (i
= 0; i
< list
->len
; i
++)
899 der_free_octet_string(&list
->val
[i
]);
907 * Return a list of subjectAltNames specified by oid in the
908 * certificate. On error the
910 * The returned list of octet string should be freed with
911 * hx509_free_octet_string_list().
913 * @param context A hx509 context.
914 * @param cert a hx509 certificate object.
915 * @param oid an oid to for SubjectAltName.
916 * @param list list of matching SubjectAltName.
918 * @return An hx509 error code, see hx509_get_error_string().
920 * @ingroup hx509_cert
923 HX509_LIB_FUNCTION
int HX509_LIB_CALL
924 hx509_cert_find_subjectAltName_otherName(hx509_context context
,
927 hx509_octet_string_list
*list
)
938 ret
= find_extension_subject_alt_name(_hx509_get_cert(cert
), &i
, &sa
);
940 if (ret
== HX509_EXTENSION_NOT_FOUND
) {
942 } else if (ret
!= 0) {
943 hx509_set_error_string(context
, 0, ret
, "Error searching for SAN");
944 hx509_free_octet_string_list(list
);
948 for (j
= 0; j
< sa
.len
; j
++) {
949 if (sa
.val
[j
].element
== choice_GeneralName_otherName
&&
950 der_heim_oid_cmp(&sa
.val
[j
].u
.otherName
.type_id
, oid
) == 0)
952 ret
= add_to_list(list
, &sa
.val
[j
].u
.otherName
.value
);
954 hx509_set_error_string(context
, 0, ret
,
955 "Error adding an extra SAN to "
957 hx509_free_octet_string_list(list
);
958 free_GeneralNames(&sa
);
963 free_GeneralNames(&sa
);
969 check_key_usage(hx509_context context
, const Certificate
*cert
,
970 unsigned flags
, int req_present
)
979 if (_hx509_cert_get_version(cert
) < 3)
982 e
= find_extension(cert
, &asn1_oid_id_x509_ce_keyUsage
, &i
);
985 hx509_set_error_string(context
, 0, HX509_KU_CERT_MISSING
,
986 "Required extension key "
987 "usage missing from certificate");
988 return HX509_KU_CERT_MISSING
;
993 ret
= decode_KeyUsage(e
->extnValue
.data
, e
->extnValue
.length
, &ku
, &size
);
996 ku_flags
= KeyUsage2int(ku
);
997 if ((ku_flags
& flags
) != flags
) {
998 uint64_t missing
= (~ku_flags
) & flags
;
999 char buf
[256], *name
;
1001 int result
= unparse_flags(missing
, asn1_KeyUsage_units(),
1003 _hx509_unparse_Name(&cert
->tbsCertificate
.subject
, &name
);
1004 hx509_set_error_string(context
, 0, HX509_KU_CERT_MISSING
,
1005 "Key usage %s required but missing "
1006 "from certificate %s",
1007 (result
> 0) ? buf
: "<unknown>",
1008 name
? name
: "<unknown>");
1010 return HX509_KU_CERT_MISSING
;
1016 * Return 0 on matching key usage 'flags' for 'cert', otherwise return
1017 * an error code. If 'req_present' the existence is required of the
1018 * KeyUsage extension.
1021 HX509_LIB_FUNCTION
int HX509_LIB_CALL
1022 _hx509_check_key_usage(hx509_context context
, hx509_cert cert
,
1023 unsigned flags
, int req_present
)
1025 return check_key_usage(context
, _hx509_get_cert(cert
), flags
, req_present
);
1028 enum certtype
{ PROXY_CERT
, EE_CERT
, CA_CERT
};
1031 check_basic_constraints(hx509_context context
, const Certificate
*cert
,
1032 enum certtype type
, size_t depth
)
1034 BasicConstraints bc
;
1040 if (_hx509_cert_get_version(cert
) < 3)
1043 e
= find_extension(cert
, &asn1_oid_id_x509_ce_basicConstraints
, &i
);
1051 ret
= _hx509_unparse_Name(&cert
->tbsCertificate
.subject
, &name
);
1053 hx509_set_error_string(context
, 0, HX509_EXTENSION_NOT_FOUND
,
1054 "basicConstraints missing from "
1055 "CA certifiacte %s", name
);
1057 return HX509_EXTENSION_NOT_FOUND
;
1062 ret
= decode_BasicConstraints(e
->extnValue
.data
,
1063 e
->extnValue
.length
, &bc
,
1070 ret
= HX509_PARENT_IS_CA
;
1077 ret
= HX509_PARENT_NOT_CA
;
1078 else if (bc
.pathLenConstraint
)
1079 if (depth
- 1 > *bc
.pathLenConstraint
)
1080 ret
= HX509_CA_PATH_TOO_DEEP
;
1083 free_BasicConstraints(&bc
);
1087 HX509_LIB_FUNCTION
int HX509_LIB_CALL
1088 _hx509_cert_is_parent_cmp(const Certificate
*subject
,
1089 const Certificate
*issuer
,
1090 int allow_self_signed
)
1093 AuthorityKeyIdentifier ai
;
1094 SubjectKeyIdentifier si
;
1095 int ret_ai
, ret_si
, ret
;
1097 ret
= _hx509_name_cmp(&issuer
->tbsCertificate
.subject
,
1098 &subject
->tbsCertificate
.issuer
,
1105 memset(&ai
, 0, sizeof(ai
));
1106 memset(&si
, 0, sizeof(si
));
1109 * Try to find AuthorityKeyIdentifier, if it's not present in the
1110 * subject certificate nor the parent.
1113 ret_ai
= find_extension_auth_key_id(subject
, &ai
);
1114 if (ret_ai
&& ret_ai
!= HX509_EXTENSION_NOT_FOUND
)
1116 ret_si
= _hx509_find_extension_subject_key_id(issuer
, &si
);
1117 if (ret_si
&& ret_si
!= HX509_EXTENSION_NOT_FOUND
)
1120 if (ret_si
&& ret_ai
)
1125 if (allow_self_signed
) {
1128 } else if (ai
.keyIdentifier
) {
1134 if (ai
.keyIdentifier
== NULL
) {
1137 if (ai
.authorityCertIssuer
== NULL
)
1139 if (ai
.authorityCertSerialNumber
== NULL
)
1142 diff
= der_heim_integer_cmp(ai
.authorityCertSerialNumber
,
1143 &issuer
->tbsCertificate
.serialNumber
);
1146 if (ai
.authorityCertIssuer
->len
!= 1)
1148 if (ai
.authorityCertIssuer
->val
[0].element
!= choice_GeneralName_directoryName
)
1151 name
.element
= (enum Name_enum
)
1152 ai
.authorityCertIssuer
->val
[0].u
.directoryName
.element
;
1153 name
.u
.rdnSequence
=
1154 ai
.authorityCertIssuer
->val
[0].u
.directoryName
.u
.rdnSequence
;
1156 ret
= _hx509_name_cmp(&issuer
->tbsCertificate
.subject
,
1165 diff
= der_heim_octet_string_cmp(ai
.keyIdentifier
, &si
);
1170 free_AuthorityKeyIdentifier(&ai
);
1171 free_SubjectKeyIdentifier(&si
);
1176 certificate_is_anchor(hx509_context context
,
1177 hx509_certs trust_anchors
,
1178 const hx509_cert cert
)
1184 if (trust_anchors
== NULL
)
1187 _hx509_query_clear(&q
);
1189 q
.match
= HX509_QUERY_MATCH_CERTIFICATE
;
1190 q
.certificate
= _hx509_get_cert(cert
);
1192 ret
= hx509_certs_find(context
, trust_anchors
, &q
, &c
);
1199 certificate_is_self_signed(hx509_context context
,
1200 const Certificate
*cert
,
1204 ret
= _hx509_name_cmp(&cert
->tbsCertificate
.subject
,
1205 &cert
->tbsCertificate
.issuer
, &diff
);
1206 *self_signed
= (diff
== 0);
1208 hx509_set_error_string(context
, 0, ret
,
1209 "Failed to check if self signed");
1210 } else if (diff
== 0)
1211 ret
= _hx509_self_signed_valid(context
, &cert
->signatureAlgorithm
);
1216 HX509_LIB_FUNCTION
int HX509_LIB_CALL
1217 hx509_cert_is_self_signed(hx509_context context
,
1221 return certificate_is_self_signed(context
, c
->data
, self_signed
);
1224 HX509_LIB_FUNCTION
int HX509_LIB_CALL
1225 hx509_cert_is_ca(hx509_context context
,
1229 BasicConstraints bc
;
1236 if (_hx509_cert_get_version(c
->data
) < 3)
1237 return certificate_is_self_signed(context
, c
->data
, is_ca
);
1239 e
= find_extension(c
->data
, &asn1_oid_id_x509_ce_basicConstraints
, &i
);
1245 ret
= decode_BasicConstraints(e
->extnValue
.data
,
1246 e
->extnValue
.length
, &bc
,
1252 free_BasicConstraints(&bc
);
1256 HX509_LIB_FUNCTION
int HX509_LIB_CALL
1257 hx509_cert_is_root(hx509_context context
,
1264 ret
= hx509_cert_is_ca(context
, c
, is_root
);
1268 /* Not a CA certificate -> not a root certificate */
1271 /* A CA certificate. If it's self-signed, it's a root certificate. */
1272 return hx509_cert_is_self_signed(context
, c
, is_root
);
1276 * The subjectName is "null" when it's empty set of relative DBs.
1280 subject_null_p(const Certificate
*c
)
1282 return c
->tbsCertificate
.subject
.u
.rdnSequence
.len
== 0;
1287 find_parent(hx509_context context
,
1289 hx509_certs trust_anchors
,
1295 AuthorityKeyIdentifier ai
;
1300 memset(&ai
, 0, sizeof(ai
));
1302 _hx509_query_clear(&q
);
1304 if (!subject_null_p(current
->data
)) {
1305 q
.match
|= HX509_QUERY_FIND_ISSUER_CERT
;
1306 q
.subject
= _hx509_get_cert(current
);
1308 ret
= find_extension_auth_key_id(current
->data
, &ai
);
1310 hx509_set_error_string(context
, 0, HX509_CERTIFICATE_MALFORMED
,
1311 "Subjectless certificate missing AuthKeyID");
1312 return HX509_CERTIFICATE_MALFORMED
;
1315 if (ai
.keyIdentifier
== NULL
) {
1316 free_AuthorityKeyIdentifier(&ai
);
1317 hx509_set_error_string(context
, 0, HX509_CERTIFICATE_MALFORMED
,
1318 "Subjectless certificate missing keyIdentifier "
1319 "inside AuthKeyID");
1320 return HX509_CERTIFICATE_MALFORMED
;
1323 q
.subject_id
= ai
.keyIdentifier
;
1324 q
.match
= HX509_QUERY_MATCH_SUBJECT_KEY_ID
;
1328 q
.match
|= HX509_QUERY_NO_MATCH_PATH
;
1331 q
.timenow
= time_now
;
1332 q
.match
|= HX509_QUERY_MATCH_TIME
;
1334 ret
= hx509_certs_find(context
, pool
, &q
, parent
);
1336 free_AuthorityKeyIdentifier(&ai
);
1339 q
.match
&= ~HX509_QUERY_MATCH_TIME
;
1342 if (trust_anchors
) {
1343 ret
= hx509_certs_find(context
, trust_anchors
, &q
, parent
);
1345 free_AuthorityKeyIdentifier(&ai
);
1349 free_AuthorityKeyIdentifier(&ai
);
1355 ret
= hx509_cert_get_subject(current
, &name
);
1357 hx509_clear_error_string(context
);
1358 return HX509_ISSUER_NOT_FOUND
;
1360 ret
= hx509_name_to_string(name
, &str
);
1361 hx509_name_free(&name
);
1363 hx509_clear_error_string(context
);
1364 return HX509_ISSUER_NOT_FOUND
;
1367 hx509_set_error_string(context
, 0, HX509_ISSUER_NOT_FOUND
,
1368 "Failed to find issuer for "
1369 "certificate with subject: '%s'", str
);
1372 return HX509_ISSUER_NOT_FOUND
;
1380 is_proxy_cert(hx509_context context
,
1381 const Certificate
*cert
,
1382 ProxyCertInfo
*rinfo
)
1391 memset(rinfo
, 0, sizeof(*rinfo
));
1393 e
= find_extension(cert
, &asn1_oid_id_pkix_pe_proxyCertInfo
, &i
);
1395 hx509_clear_error_string(context
);
1396 return HX509_EXTENSION_NOT_FOUND
;
1399 ret
= decode_ProxyCertInfo(e
->extnValue
.data
,
1400 e
->extnValue
.length
,
1404 hx509_clear_error_string(context
);
1407 if (size
!= e
->extnValue
.length
) {
1408 free_ProxyCertInfo(&info
);
1409 hx509_clear_error_string(context
);
1410 return HX509_EXTRA_DATA_AFTER_STRUCTURE
;
1413 free_ProxyCertInfo(&info
);
1421 * Path operations are like MEMORY based keyset, but with exposed
1422 * internal so we can do easy searches.
1425 HX509_LIB_FUNCTION
int HX509_LIB_CALL
1426 _hx509_path_append(hx509_context context
, hx509_path
*path
, hx509_cert cert
)
1429 val
= realloc(path
->val
, (path
->len
+ 1) * sizeof(path
->val
[0]));
1431 hx509_set_error_string(context
, 0, ENOMEM
, "out of memory");
1436 path
->val
[path
->len
] = hx509_cert_ref(cert
);
1442 HX509_LIB_FUNCTION
void HX509_LIB_CALL
1443 _hx509_path_free(hx509_path
*path
)
1447 for (i
= 0; i
< path
->len
; i
++)
1448 hx509_cert_free(path
->val
[i
]);
1455 * Find path by looking up issuer for the top certificate and continue
1456 * until an anchor certificate is found or max limit is found. A
1457 * certificate never included twice in the path.
1459 * If the trust anchors are not given, calculate optimistic path, just
1460 * follow the chain upward until we no longer find a parent or we hit
1461 * the max path limit. In this case, a failure will always be returned
1462 * depending on what error condition is hit first.
1464 * The path includes a path from the top certificate to the anchor
1467 * The caller needs to free `path´ both on successful built path and
1471 HX509_LIB_FUNCTION
int HX509_LIB_CALL
1472 _hx509_calculate_path(hx509_context context
,
1475 hx509_certs anchors
,
1476 unsigned int max_depth
,
1481 hx509_cert parent
, current
;
1485 max_depth
= HX509_VERIFY_MAX_DEPTH
;
1487 ret
= _hx509_path_append(context
, path
, cert
);
1491 current
= hx509_cert_ref(cert
);
1493 while (!certificate_is_anchor(context
, anchors
, current
)) {
1495 ret
= find_parent(context
, time_now
, anchors
, path
,
1496 pool
, current
, &parent
);
1497 hx509_cert_free(current
);
1501 ret
= _hx509_path_append(context
, path
, parent
);
1506 if (path
->len
> max_depth
) {
1507 hx509_cert_free(current
);
1508 hx509_set_error_string(context
, 0, HX509_PATH_TOO_LONG
,
1509 "Path too long while building "
1510 "certificate chain");
1511 return HX509_PATH_TOO_LONG
;
1515 if ((flags
& HX509_CALCULATE_PATH_NO_ANCHOR
) &&
1517 certificate_is_anchor(context
, anchors
, path
->val
[path
->len
- 1]))
1519 hx509_cert_free(path
->val
[path
->len
- 1]);
1523 hx509_cert_free(current
);
1527 HX509_LIB_FUNCTION
int HX509_LIB_CALL
1528 _hx509_AlgorithmIdentifier_cmp(const AlgorithmIdentifier
*p
,
1529 const AlgorithmIdentifier
*q
)
1532 diff
= der_heim_oid_cmp(&p
->algorithm
, &q
->algorithm
);
1535 if (p
->parameters
) {
1537 return heim_any_cmp(p
->parameters
,
1549 HX509_LIB_FUNCTION
int HX509_LIB_CALL
1550 _hx509_Certificate_cmp(const Certificate
*p
, const Certificate
*q
)
1553 diff
= der_heim_bit_string_cmp(&p
->signatureValue
, &q
->signatureValue
);
1556 diff
= _hx509_AlgorithmIdentifier_cmp(&p
->signatureAlgorithm
,
1557 &q
->signatureAlgorithm
);
1560 diff
= der_heim_octet_string_cmp(&p
->tbsCertificate
._save
,
1561 &q
->tbsCertificate
._save
);
1566 * Compare to hx509 certificate object, useful for sorting.
1568 * @param p a hx509 certificate object.
1569 * @param q a hx509 certificate object.
1571 * @return 0 the objects are the same, returns > 0 is p is "larger"
1572 * then q, < 0 if p is "smaller" then q.
1574 * @ingroup hx509_cert
1577 HX509_LIB_FUNCTION
int HX509_LIB_CALL
1578 hx509_cert_cmp(hx509_cert p
, hx509_cert q
)
1580 return _hx509_Certificate_cmp(p
->data
, q
->data
);
1584 * Return the name of the issuer of the hx509 certificate.
1586 * @param p a hx509 certificate object.
1587 * @param name a pointer to a hx509 name, should be freed by
1588 * hx509_name_free().
1590 * @return An hx509 error code, see hx509_get_error_string().
1592 * @ingroup hx509_cert
1595 HX509_LIB_FUNCTION
int HX509_LIB_CALL
1596 hx509_cert_get_issuer(hx509_cert p
, hx509_name
*name
)
1598 return _hx509_name_from_Name(&p
->data
->tbsCertificate
.issuer
, name
);
1602 * Return the name of the subject of the hx509 certificate.
1604 * @param p a hx509 certificate object.
1605 * @param name a pointer to a hx509 name, should be freed by
1606 * hx509_name_free(). See also hx509_cert_get_base_subject().
1608 * @return An hx509 error code, see hx509_get_error_string().
1610 * @ingroup hx509_cert
1613 HX509_LIB_FUNCTION
int HX509_LIB_CALL
1614 hx509_cert_get_subject(hx509_cert p
, hx509_name
*name
)
1616 return _hx509_name_from_Name(&p
->data
->tbsCertificate
.subject
, name
);
1620 * Return the name of the base subject of the hx509 certificate. If
1621 * the certiicate is a verified proxy certificate, the this function
1622 * return the base certificate (root of the proxy chain). If the proxy
1623 * certificate is not verified with the base certificate
1624 * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned.
1626 * @param context a hx509 context.
1627 * @param c a hx509 certificate object.
1628 * @param name a pointer to a hx509 name, should be freed by
1629 * hx509_name_free(). See also hx509_cert_get_subject().
1631 * @return An hx509 error code, see hx509_get_error_string().
1633 * @ingroup hx509_cert
1636 HX509_LIB_FUNCTION
int HX509_LIB_CALL
1637 hx509_cert_get_base_subject(hx509_context context
, hx509_cert c
,
1641 return hx509_name_copy(context
, c
->basename
, name
);
1642 if (is_proxy_cert(context
, c
->data
, NULL
) == 0) {
1643 int ret
= HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED
;
1644 hx509_set_error_string(context
, 0, ret
,
1645 "Proxy certificate has not been "
1646 "canonicalized yet: no base name");
1649 return _hx509_name_from_Name(&c
->data
->tbsCertificate
.subject
, name
);
1653 * Get serial number of the certificate.
1655 * @param p a hx509 certificate object.
1656 * @param i serial number, should be freed ith der_free_heim_integer().
1658 * @return An hx509 error code, see hx509_get_error_string().
1660 * @ingroup hx509_cert
1663 HX509_LIB_FUNCTION
int HX509_LIB_CALL
1664 hx509_cert_get_serialnumber(hx509_cert p
, heim_integer
*i
)
1666 return der_copy_heim_integer(&p
->data
->tbsCertificate
.serialNumber
, i
);
1670 * Get notBefore time of the certificate.
1672 * @param p a hx509 certificate object.
1674 * @return return not before time
1676 * @ingroup hx509_cert
1679 HX509_LIB_FUNCTION
time_t HX509_LIB_CALL
1680 hx509_cert_get_notBefore(hx509_cert p
)
1682 return _hx509_Time2time_t(&p
->data
->tbsCertificate
.validity
.notBefore
);
1686 * Get notAfter time of the certificate.
1688 * @param p a hx509 certificate object.
1690 * @return return not after time.
1692 * @ingroup hx509_cert
1695 HX509_LIB_FUNCTION
time_t HX509_LIB_CALL
1696 hx509_cert_get_notAfter(hx509_cert p
)
1698 return _hx509_Time2time_t(&p
->data
->tbsCertificate
.validity
.notAfter
);
1702 * Get a maximum Kerberos credential lifetime from a Heimdal certificate
1705 * @param context hx509 context.
1706 * @param cert Certificate.
1707 * @param bound If larger than zero, return no more than this.
1709 * @return maximum ticket lifetime.
1711 HX509_LIB_FUNCTION
time_t HX509_LIB_CALL
1712 hx509_cert_get_pkinit_max_life(hx509_context context
,
1716 HeimPkinitPrincMaxLifeSecs r
= 0;
1721 for (i
= 0; i
< cert
->data
->tbsCertificate
.extensions
->len
; i
++) {
1722 Extension
*ext
= &cert
->data
->tbsCertificate
.extensions
->val
[i
];
1724 if (ext
->_ioschoice_extnValue
.element
!=
1725 choice_Extension_iosnumunknown
&&
1726 ext
->_ioschoice_extnValue
.element
!=
1727 choice_Extension_iosnum_id_heim_ce_pkinit_princ_max_life
)
1729 if (ext
->_ioschoice_extnValue
.element
== choice_Extension_iosnumunknown
&&
1730 der_heim_oid_cmp(&asn1_oid_id_heim_ce_pkinit_princ_max_life
, &ext
->extnID
))
1732 if (ext
->_ioschoice_extnValue
.u
.ext_HeimPkinitPrincMaxLife
) {
1733 r
= *ext
->_ioschoice_extnValue
.u
.ext_HeimPkinitPrincMaxLife
;
1735 ret
= decode_HeimPkinitPrincMaxLifeSecs(ext
->extnValue
.data
,
1736 ext
->extnValue
.length
,
1738 /* No need to free_HeimPkinitPrincMaxLifeSecs(); it's an int */
1742 if (bound
> 0 && r
> bound
)
1746 if (hx509_cert_check_eku(context
, cert
,
1747 &asn1_oid_id_heim_eku_pkinit_certlife_is_max_life
, 0))
1749 b
= hx509_cert_get_notBefore(cert
);
1750 e
= hx509_cert_get_notAfter(cert
);
1753 if (bound
> 0 && r
> bound
)
1759 * Get the SubjectPublicKeyInfo structure from the hx509 certificate.
1761 * @param context a hx509 context.
1762 * @param p a hx509 certificate object.
1763 * @param spki SubjectPublicKeyInfo, should be freed with
1764 * free_SubjectPublicKeyInfo().
1766 * @return An hx509 error code, see hx509_get_error_string().
1768 * @ingroup hx509_cert
1771 HX509_LIB_FUNCTION
int HX509_LIB_CALL
1772 hx509_cert_get_SPKI(hx509_context context
, hx509_cert p
, SubjectPublicKeyInfo
*spki
)
1776 ret
= copy_SubjectPublicKeyInfo(&p
->data
->tbsCertificate
.subjectPublicKeyInfo
, spki
);
1778 hx509_set_error_string(context
, 0, ret
, "Failed to copy SPKI");
1783 * Get the AlgorithmIdentifier from the hx509 certificate.
1785 * @param context a hx509 context.
1786 * @param p a hx509 certificate object.
1787 * @param alg AlgorithmIdentifier, should be freed with
1788 * free_AlgorithmIdentifier(). The algorithmidentifier is
1789 * typicly rsaEncryption, or id-ecPublicKey, or some other
1790 * public key mechanism.
1792 * @return An hx509 error code, see hx509_get_error_string().
1794 * @ingroup hx509_cert
1797 HX509_LIB_FUNCTION
int HX509_LIB_CALL
1798 hx509_cert_get_SPKI_AlgorithmIdentifier(hx509_context context
,
1800 AlgorithmIdentifier
*alg
)
1804 ret
= copy_AlgorithmIdentifier(&p
->data
->tbsCertificate
.subjectPublicKeyInfo
.algorithm
, alg
);
1806 hx509_set_error_string(context
, 0, ret
,
1807 "Failed to copy SPKI AlgorithmIdentifier");
1812 get_x_unique_id(hx509_context context
, const char *name
,
1813 const heim_bit_string
*cert
, heim_bit_string
*subject
)
1818 ret
= HX509_EXTENSION_NOT_FOUND
;
1819 hx509_set_error_string(context
, 0, ret
, "%s unique id doesn't exist", name
);
1822 ret
= der_copy_bit_string(cert
, subject
);
1824 hx509_set_error_string(context
, 0, ret
, "malloc out of memory", name
);
1831 * Get a copy of the Issuer Unique ID
1833 * @param context a hx509_context
1834 * @param p a hx509 certificate
1835 * @param issuer the issuer id returned, free with der_free_bit_string()
1837 * @return An hx509 error code, see hx509_get_error_string(). The
1838 * error code HX509_EXTENSION_NOT_FOUND is returned if the certificate
1839 * doesn't have a issuerUniqueID
1841 * @ingroup hx509_cert
1844 HX509_LIB_FUNCTION
int HX509_LIB_CALL
1845 hx509_cert_get_issuer_unique_id(hx509_context context
, hx509_cert p
, heim_bit_string
*issuer
)
1847 return get_x_unique_id(context
, "issuer", p
->data
->tbsCertificate
.issuerUniqueID
, issuer
);
1851 * Get a copy of the Subect Unique ID
1853 * @param context a hx509_context
1854 * @param p a hx509 certificate
1855 * @param subject the subject id returned, free with der_free_bit_string()
1857 * @return An hx509 error code, see hx509_get_error_string(). The
1858 * error code HX509_EXTENSION_NOT_FOUND is returned if the certificate
1859 * doesn't have a subjectUniqueID
1861 * @ingroup hx509_cert
1864 HX509_LIB_FUNCTION
int HX509_LIB_CALL
1865 hx509_cert_get_subject_unique_id(hx509_context context
, hx509_cert p
, heim_bit_string
*subject
)
1867 return get_x_unique_id(context
, "subject", p
->data
->tbsCertificate
.subjectUniqueID
, subject
);
1871 HX509_LIB_FUNCTION hx509_private_key HX509_LIB_CALL
1872 _hx509_cert_private_key(hx509_cert p
)
1874 return p
->private_key
;
1878 * Indicate whether a hx509_cert has a private key.
1880 * @param p a hx509 certificate
1882 * @return 1 if p has a private key, 0 otherwise.
1884 * @ingroup hx509_cert
1886 HX509_LIB_FUNCTION
int HX509_LIB_CALL
1887 hx509_cert_have_private_key(hx509_cert p
)
1889 return p
->private_key
? 1 : 0;
1893 * Indicate whether a hx509_cert has a private key only (no certificate).
1895 * @param p a hx509 certificate
1897 * @return 1 if p has a private key only (no certificate), 0 otherwise.
1899 * @ingroup hx509_cert
1901 HX509_LIB_FUNCTION
int HX509_LIB_CALL
1902 hx509_cert_have_private_key_only(hx509_cert p
)
1904 return p
->private_key
&& !p
->data
? 1 : 0;
1908 HX509_LIB_FUNCTION
int HX509_LIB_CALL
1909 _hx509_cert_private_key_exportable(hx509_cert p
)
1911 if (p
->private_key
== NULL
)
1913 return _hx509_private_key_exportable(p
->private_key
);
1916 HX509_LIB_FUNCTION
int HX509_LIB_CALL
1917 _hx509_cert_private_decrypt(hx509_context context
,
1918 const heim_octet_string
*ciphertext
,
1919 const heim_oid
*encryption_oid
,
1921 heim_octet_string
*cleartext
)
1923 cleartext
->data
= NULL
;
1924 cleartext
->length
= 0;
1926 if (p
->private_key
== NULL
) {
1927 hx509_set_error_string(context
, 0, HX509_PRIVATE_KEY_MISSING
,
1928 "Private key missing");
1929 return HX509_PRIVATE_KEY_MISSING
;
1932 return hx509_private_key_private_decrypt(context
,
1939 HX509_LIB_FUNCTION
int HX509_LIB_CALL
1940 hx509_cert_public_encrypt(hx509_context context
,
1941 const heim_octet_string
*cleartext
,
1943 heim_oid
*encryption_oid
,
1944 heim_octet_string
*ciphertext
)
1946 return _hx509_public_encrypt(context
,
1948 encryption_oid
, ciphertext
);
1955 HX509_LIB_FUNCTION
time_t HX509_LIB_CALL
1956 _hx509_Time2time_t(const Time
*t
)
1958 switch(t
->element
) {
1959 case choice_Time_utcTime
:
1960 return t
->u
.utcTime
;
1961 case choice_Time_generalTime
:
1962 return t
->u
.generalTime
;
1972 init_name_constraints(hx509_name_constraints
*nc
)
1974 memset(nc
, 0, sizeof(*nc
));
1979 add_name_constraints(hx509_context context
, const Certificate
*c
, int not_ca
,
1980 hx509_name_constraints
*nc
)
1982 NameConstraints tnc
;
1985 ret
= find_extension_name_constraints(c
, &tnc
);
1986 if (ret
== HX509_EXTENSION_NOT_FOUND
)
1989 hx509_set_error_string(context
, 0, ret
, "Failed getting NameConstraints");
1991 } else if (not_ca
) {
1992 ret
= HX509_VERIFY_CONSTRAINTS
;
1993 hx509_set_error_string(context
, 0, ret
, "Not a CA and "
1994 "have NameConstraints");
1996 NameConstraints
*val
;
1997 val
= realloc(nc
->val
, sizeof(nc
->val
[0]) * (nc
->len
+ 1));
1999 hx509_clear_error_string(context
);
2004 ret
= copy_NameConstraints(&tnc
, &nc
->val
[nc
->len
]);
2006 hx509_clear_error_string(context
);
2012 free_NameConstraints(&tnc
);
2017 match_RDN(const RelativeDistinguishedName
*c
,
2018 const RelativeDistinguishedName
*n
)
2022 if (c
->len
!= n
->len
)
2023 return HX509_NAME_CONSTRAINT_ERROR
;
2025 for (i
= 0; i
< n
->len
; i
++) {
2028 if (der_heim_oid_cmp(&c
->val
[i
].type
, &n
->val
[i
].type
) != 0)
2029 return HX509_NAME_CONSTRAINT_ERROR
;
2030 ret
= _hx509_name_ds_cmp(&c
->val
[i
].value
, &n
->val
[i
].value
, &diff
);
2034 return HX509_NAME_CONSTRAINT_ERROR
;
2040 match_X501Name(const Name
*c
, const Name
*n
)
2045 if (c
->element
!= choice_Name_rdnSequence
2046 || n
->element
!= choice_Name_rdnSequence
)
2048 if (c
->u
.rdnSequence
.len
> n
->u
.rdnSequence
.len
)
2049 return HX509_NAME_CONSTRAINT_ERROR
;
2050 for (i
= 0; i
< c
->u
.rdnSequence
.len
; i
++) {
2051 ret
= match_RDN(&c
->u
.rdnSequence
.val
[i
], &n
->u
.rdnSequence
.val
[i
]);
2060 match_general_name(const GeneralName
*c
, const GeneralName
*n
, int *match
)
2063 * Name constraints only apply to the same name type, see RFC3280,
2066 assert(c
->element
== n
->element
);
2068 switch(c
->element
) {
2069 case choice_GeneralName_otherName
:
2070 if (der_heim_oid_cmp(&c
->u
.otherName
.type_id
,
2071 &n
->u
.otherName
.type_id
) != 0)
2072 return HX509_NAME_CONSTRAINT_ERROR
;
2073 if (heim_any_cmp(&c
->u
.otherName
.value
,
2074 &n
->u
.otherName
.value
) != 0)
2075 return HX509_NAME_CONSTRAINT_ERROR
;
2078 case choice_GeneralName_rfc822Name
: {
2081 s
= memchr(c
->u
.rfc822Name
.data
, '@', c
->u
.rfc822Name
.length
);
2083 if (der_printable_string_cmp(&c
->u
.rfc822Name
, &n
->u
.rfc822Name
) != 0)
2084 return HX509_NAME_CONSTRAINT_ERROR
;
2086 s
= memchr(n
->u
.rfc822Name
.data
, '@', n
->u
.rfc822Name
.length
);
2088 return HX509_NAME_CONSTRAINT_ERROR
;
2089 len1
= c
->u
.rfc822Name
.length
;
2090 len2
= n
->u
.rfc822Name
.length
-
2091 (s
- ((char *)n
->u
.rfc822Name
.data
));
2093 return HX509_NAME_CONSTRAINT_ERROR
;
2094 if (memcmp(s
+ 1 + len2
- len1
, c
->u
.rfc822Name
.data
, len1
) != 0)
2095 return HX509_NAME_CONSTRAINT_ERROR
;
2096 if (len1
< len2
&& s
[len2
- len1
+ 1] != '.')
2097 return HX509_NAME_CONSTRAINT_ERROR
;
2102 case choice_GeneralName_dNSName
: {
2106 lenc
= c
->u
.dNSName
.length
;
2107 lenn
= n
->u
.dNSName
.length
;
2109 return HX509_NAME_CONSTRAINT_ERROR
;
2110 ptr
= n
->u
.dNSName
.data
;
2111 if (memcmp(&ptr
[lenn
- lenc
], c
->u
.dNSName
.data
, lenc
) != 0)
2112 return HX509_NAME_CONSTRAINT_ERROR
;
2113 if (lenn
!= lenc
&& ptr
[lenn
- lenc
- 1] != '.')
2114 return HX509_NAME_CONSTRAINT_ERROR
;
2118 case choice_GeneralName_directoryName
: {
2119 Name c_name
, n_name
;
2122 c_name
._save
.data
= NULL
;
2123 c_name
._save
.length
= 0;
2124 c_name
.element
= (enum Name_enum
)c
->u
.directoryName
.element
;
2125 c_name
.u
.rdnSequence
= c
->u
.directoryName
.u
.rdnSequence
;
2127 n_name
._save
.data
= NULL
;
2128 n_name
._save
.length
= 0;
2129 n_name
.element
= (enum Name_enum
)n
->u
.directoryName
.element
;
2130 n_name
.u
.rdnSequence
= n
->u
.directoryName
.u
.rdnSequence
;
2132 ret
= match_X501Name(&c_name
, &n_name
);
2137 case choice_GeneralName_uniformResourceIdentifier
:
2138 case choice_GeneralName_iPAddress
:
2139 case choice_GeneralName_registeredID
:
2141 return HX509_NAME_CONSTRAINT_ERROR
;
2146 match_alt_name(const GeneralName
*n
, const Certificate
*c
,
2147 int *same
, int *match
)
2155 ret
= find_extension_subject_alt_name(c
, &i
, &sa
);
2156 if (ret
== HX509_EXTENSION_NOT_FOUND
) {
2159 } else if (ret
!= 0)
2162 for (j
= 0; j
< sa
.len
; j
++) {
2163 if (n
->element
== sa
.val
[j
].element
) {
2165 match_general_name(n
, &sa
.val
[j
], match
);
2168 free_GeneralNames(&sa
);
2175 match_tree(const GeneralSubtrees
*t
, const Certificate
*c
, int *match
)
2177 int name
, alt_name
, same
;
2181 name
= alt_name
= same
= *match
= 0;
2182 for (i
= 0; i
< t
->len
; i
++) {
2183 if (t
->val
[i
].minimum
&& t
->val
[i
].maximum
)
2187 * If the constraint apply to directoryNames, test is with
2188 * subjectName of the certificate if the certificate have a
2189 * non-null (empty) subjectName.
2192 if (t
->val
[i
].base
.element
== choice_GeneralName_directoryName
2193 && !subject_null_p(c
))
2195 GeneralName certname
;
2197 memset(&certname
, 0, sizeof(certname
));
2198 certname
.element
= choice_GeneralName_directoryName
;
2199 certname
.u
.directoryName
.element
= (enum Name_enum
)
2200 c
->tbsCertificate
.subject
.element
;
2201 certname
.u
.directoryName
.u
.rdnSequence
=
2202 c
->tbsCertificate
.subject
.u
.rdnSequence
;
2204 match_general_name(&t
->val
[i
].base
, &certname
, &name
);
2207 /* Handle subjectAltNames, this is icky since they
2208 * restrictions only apply if the subjectAltName is of the
2209 * same type. So if there have been a match of type, require
2210 * altname to be set.
2212 match_alt_name(&t
->val
[i
].base
, c
, &same
, &alt_name
);
2214 if (name
&& (!same
|| alt_name
))
2220 check_name_constraints(hx509_context context
,
2221 const hx509_name_constraints
*nc
,
2222 const Certificate
*c
)
2227 for (i
= 0 ; i
< nc
->len
; i
++) {
2230 if (nc
->val
[i
].permittedSubtrees
) {
2231 GeneralSubtrees_SET(&gs
, nc
->val
[i
].permittedSubtrees
);
2232 ret
= match_tree(&gs
, c
, &match
);
2234 hx509_clear_error_string(context
);
2237 /* allow null subjectNames, they wont matches anything */
2238 if (match
== 0 && !subject_null_p(c
)) {
2239 hx509_set_error_string(context
, 0, HX509_VERIFY_CONSTRAINTS
,
2240 "Error verifying constraints: "
2241 "certificate didn't match any "
2242 "permitted subtree");
2243 return HX509_VERIFY_CONSTRAINTS
;
2246 if (nc
->val
[i
].excludedSubtrees
) {
2247 GeneralSubtrees_SET(&gs
, nc
->val
[i
].excludedSubtrees
);
2248 ret
= match_tree(&gs
, c
, &match
);
2250 hx509_clear_error_string(context
);
2254 hx509_set_error_string(context
, 0, HX509_VERIFY_CONSTRAINTS
,
2255 "Error verifying constraints: "
2256 "certificate included in excluded "
2258 return HX509_VERIFY_CONSTRAINTS
;
2266 free_name_constraints(hx509_name_constraints
*nc
)
2270 for (i
= 0 ; i
< nc
->len
; i
++)
2271 free_NameConstraints(&nc
->val
[i
]);
2276 * Build and verify the path for the certificate to the trust anchor
2277 * specified in the verify context. The path is constructed from the
2278 * certificate, the pool and the trust anchors.
2280 * @param context A hx509 context.
2281 * @param ctx A hx509 verification context.
2282 * @param cert the certificate to build the path from.
2283 * @param pool A keyset of certificates to build the chain from.
2285 * @return An hx509 error code, see hx509_get_error_string().
2287 * @ingroup hx509_verify
2290 HX509_LIB_FUNCTION
int HX509_LIB_CALL
2291 hx509_verify_path(hx509_context context
,
2292 hx509_verify_ctx ctx
,
2296 hx509_name_constraints nc
;
2298 int ret
, proxy_cert_depth
, selfsigned_depth
, diff
;
2302 hx509_certs anchors
= NULL
;
2304 memset(&proxy_issuer
, 0, sizeof(proxy_issuer
));
2306 if ((ctx
->flags
& HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE
) == 0 &&
2307 is_proxy_cert(context
, cert
->data
, NULL
) == 0)
2309 ret
= HX509_PROXY_CERT_INVALID
;
2310 hx509_set_error_string(context
, 0, ret
,
2311 "Proxy certificate is not allowed as an EE "
2312 "certificate if proxy certificate is disabled");
2316 ret
= init_name_constraints(&nc
);
2323 if ((ctx
->flags
& HX509_VERIFY_CTX_F_TIME_SET
) == 0)
2324 ctx
->time_now
= time(NULL
);
2329 if (ctx
->trust_anchors
)
2330 anchors
= hx509_certs_ref(ctx
->trust_anchors
);
2331 else if (context
->default_trust_anchors
&& ALLOW_DEF_TA(ctx
))
2332 anchors
= hx509_certs_ref(context
->default_trust_anchors
);
2334 ret
= hx509_certs_init(context
, "MEMORY:no-TA", 0, NULL
, &anchors
);
2340 * Calculate the path from the certificate user presented to the
2343 ret
= _hx509_calculate_path(context
, 0, ctx
->time_now
,
2344 anchors
, ctx
->max_depth
,
2350 * Check CA and proxy certificate chain from the top of the
2351 * certificate chain. Also check certificate is valid with respect
2352 * to the current time.
2356 proxy_cert_depth
= 0;
2357 selfsigned_depth
= 0;
2359 if (ctx
->flags
& HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE
)
2364 for (i
= 0; i
< path
.len
; i
++) {
2368 c
= _hx509_get_cert(path
.val
[i
]);
2371 * Lets do some basic check on issuer like
2372 * keyUsage.keyCertSign and basicConstraints.cA bit depending
2373 * on what type of certificate this is.
2379 /* XXX make constants for keyusage */
2380 ret
= check_key_usage(context
, c
, 1 << 5,
2381 REQUIRE_RFC3280(ctx
) ? TRUE
: FALSE
);
2383 hx509_set_error_string(context
, HX509_ERROR_APPEND
, ret
,
2384 "Key usage missing from CA certificate");
2388 /* self signed cert doesn't add to path length */
2389 if (i
+ 1 != path
.len
) {
2392 ret
= certificate_is_self_signed(context
, c
, &selfsigned
);
2403 if (is_proxy_cert(context
, c
, &info
) == 0) {
2406 if (info
.pCPathLenConstraint
!= NULL
&&
2407 *info
.pCPathLenConstraint
< i
)
2409 free_ProxyCertInfo(&info
);
2410 ret
= HX509_PATH_TOO_LONG
;
2411 hx509_set_error_string(context
, 0, ret
,
2412 "Proxy certificate chain "
2413 "longer than allowed");
2416 /* XXX MUST check info.proxyPolicy */
2417 free_ProxyCertInfo(&info
);
2420 if (find_extension(c
, &asn1_oid_id_x509_ce_subjectAltName
, &j
)) {
2421 ret
= HX509_PROXY_CERT_INVALID
;
2422 hx509_set_error_string(context
, 0, ret
,
2423 "Proxy certificate has explicitly "
2424 "forbidden subjectAltName");
2429 if (find_extension(c
, &asn1_oid_id_x509_ce_issuerAltName
, &j
)) {
2430 ret
= HX509_PROXY_CERT_INVALID
;
2431 hx509_set_error_string(context
, 0, ret
,
2432 "Proxy certificate has explicitly "
2433 "forbidden issuerAltName");
2438 * The subject name of the proxy certificate should be
2439 * CN=XXX,<proxy issuer>. Prune off CN and check if it's
2440 * the same over the whole chain of proxy certs and
2441 * then check with the EE cert when we get to it.
2444 if (proxy_cert_depth
) {
2445 ret
= _hx509_name_cmp(&proxy_issuer
, &c
->tbsCertificate
.subject
, &diff
);
2447 hx509_set_error_string(context
, 0, ret
, "Out of memory");
2451 ret
= HX509_PROXY_CERT_NAME_WRONG
;
2452 hx509_set_error_string(context
, 0, ret
,
2453 "Base proxy name not right");
2458 free_Name(&proxy_issuer
);
2460 ret
= copy_Name(&c
->tbsCertificate
.subject
, &proxy_issuer
);
2462 hx509_clear_error_string(context
);
2466 j
= proxy_issuer
.u
.rdnSequence
.len
;
2467 if (proxy_issuer
.u
.rdnSequence
.len
< 2
2468 || proxy_issuer
.u
.rdnSequence
.val
[j
- 1].len
> 1
2469 || der_heim_oid_cmp(&proxy_issuer
.u
.rdnSequence
.val
[j
- 1].val
[0].type
,
2470 &asn1_oid_id_at_commonName
))
2472 ret
= HX509_PROXY_CERT_NAME_WRONG
;
2473 hx509_set_error_string(context
, 0, ret
,
2474 "Proxy name too short or "
2475 "does not have Common name "
2480 free_RelativeDistinguishedName(&proxy_issuer
.u
.rdnSequence
.val
[j
- 1]);
2481 proxy_issuer
.u
.rdnSequence
.len
-= 1;
2483 ret
= _hx509_name_cmp(&proxy_issuer
, &c
->tbsCertificate
.issuer
, &diff
);
2485 hx509_set_error_string(context
, 0, ret
, "Out of memory");
2489 ret
= HX509_PROXY_CERT_NAME_WRONG
;
2490 hx509_set_error_string(context
, 0, ret
,
2491 "Proxy issuer name not as expected");
2498 * Now we are done with the proxy certificates, this
2499 * cert was an EE cert and we will fall though to
2500 * EE checking below.
2508 * If there were any proxy certificates in the chain
2509 * (proxy_cert_depth > 0), check that the proxy issuer
2510 * matched the proxy certificate's "base" subject.
2512 if (proxy_cert_depth
) {
2514 ret
= _hx509_name_cmp(&proxy_issuer
,
2515 &c
->tbsCertificate
.subject
, &diff
);
2517 hx509_set_error_string(context
, 0, ret
, "out of memory");
2521 ret
= HX509_PROXY_CERT_NAME_WRONG
;
2522 hx509_clear_error_string(context
);
2526 hx509_name_free(&cert
->basename
);
2528 ret
= _hx509_name_from_Name(&proxy_issuer
, &cert
->basename
);
2530 hx509_clear_error_string(context
);
2538 ret
= check_basic_constraints(context
, c
, type
,
2539 i
- proxy_cert_depth
- selfsigned_depth
);
2544 * Don't check the trust anchors expiration time since they
2545 * are transported out of band, from RFC3820.
2547 if (i
+ 1 != path
.len
|| CHECK_TA(ctx
)) {
2549 t
= _hx509_Time2time_t(&c
->tbsCertificate
.validity
.notBefore
);
2550 if (t
> ctx
->time_now
) {
2551 ret
= HX509_CERT_USED_BEFORE_TIME
;
2552 hx509_clear_error_string(context
);
2555 t
= _hx509_Time2time_t(&c
->tbsCertificate
.validity
.notAfter
);
2556 if (t
< ctx
->time_now
) {
2557 ret
= HX509_CERT_USED_AFTER_TIME
;
2558 hx509_clear_error_string(context
);
2563 if (type
== EE_CERT
)
2565 else if (type
== PROXY_CERT
)
2570 * Verify constraints, do this backward so path constraints are
2571 * checked in the right order.
2574 for (ret
= 0, k
= path
.len
; k
> 0; k
--) {
2579 c
= _hx509_get_cert(path
.val
[i
]);
2581 ret
= certificate_is_self_signed(context
, c
, &selfsigned
);
2585 /* verify name constraints, not for selfsigned and anchor */
2586 if (!selfsigned
|| i
+ 1 != path
.len
) {
2587 ret
= check_name_constraints(context
, &nc
, c
);
2592 ret
= add_name_constraints(context
, c
, i
== 0, &nc
);
2596 /* XXX verify all other silly constraints */
2601 * Verify that no certificates have been revoked.
2604 if (ctx
->revoke_ctx
) {
2607 ret
= hx509_certs_init(context
, "MEMORY:revoke-certs", 0,
2612 for (i
= 0; i
< path
.len
; i
++) {
2613 ret
= hx509_certs_add(context
, certs
, path
.val
[i
]);
2615 hx509_certs_free(&certs
);
2619 ret
= hx509_certs_merge(context
, certs
, pool
);
2621 hx509_certs_free(&certs
);
2625 for (i
= 0; i
< path
.len
- 1; i
++) {
2626 size_t parent
= (i
< path
.len
- 1) ? i
+ 1 : i
;
2628 ret
= hx509_revoke_verify(context
,
2635 hx509_certs_free(&certs
);
2639 hx509_certs_free(&certs
);
2643 * Verify signatures, do this backward so public key working
2644 * parameter is passed up from the anchor up though the chain.
2647 for (k
= path
.len
; k
> 0; k
--) {
2652 c
= _hx509_get_cert(path
.val
[i
]);
2654 /* is last in chain (trust anchor) */
2655 if (i
+ 1 == path
.len
) {
2658 signer
= path
.val
[i
];
2660 ret
= certificate_is_self_signed(context
, signer
->data
, &selfsigned
);
2664 /* if trust anchor is not self signed, don't check sig */
2668 /* take next certificate in chain */
2669 signer
= path
.val
[i
+ 1];
2672 /* verify signatureValue */
2673 ret
= _hx509_verify_signature_bitstring(context
,
2675 &c
->signatureAlgorithm
,
2676 &c
->tbsCertificate
._save
,
2677 &c
->signatureValue
);
2679 hx509_set_error_string(context
, HX509_ERROR_APPEND
, ret
,
2680 "Failed to verify signature of certificate");
2684 * Verify that the signature algorithm is not weak. Ignore
2685 * trust anchors since they are provisioned by the user.
2688 if (i
+ 1 != path
.len
&& (ctx
->flags
& HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK
) == 0) {
2689 ret
= _hx509_signature_is_weak(context
, &c
->signatureAlgorithm
);
2696 hx509_certs_free(&anchors
);
2697 free_Name(&proxy_issuer
);
2698 free_name_constraints(&nc
);
2699 _hx509_path_free(&path
);
2705 * Verify a signature made using the private key of an certificate.
2707 * @param context A hx509 context.
2708 * @param signer the certificate that made the signature.
2709 * @param alg algorthm that was used to sign the data.
2710 * @param data the data that was signed.
2711 * @param sig the signature to verify.
2713 * @return An hx509 error code, see hx509_get_error_string().
2715 * @ingroup hx509_crypto
2718 HX509_LIB_FUNCTION
int HX509_LIB_CALL
2719 hx509_verify_signature(hx509_context context
,
2720 const hx509_cert signer
,
2721 const AlgorithmIdentifier
*alg
,
2722 const heim_octet_string
*data
,
2723 const heim_octet_string
*sig
)
2725 return _hx509_verify_signature(context
, signer
, alg
, data
, sig
);
2728 HX509_LIB_FUNCTION
int HX509_LIB_CALL
2729 _hx509_verify_signature_bitstring(hx509_context context
,
2730 const hx509_cert signer
,
2731 const AlgorithmIdentifier
*alg
,
2732 const heim_octet_string
*data
,
2733 const heim_bit_string
*sig
)
2735 heim_octet_string os
;
2737 if (sig
->length
& 7) {
2738 hx509_set_error_string(context
, 0, HX509_CRYPTO_SIG_INVALID_FORMAT
,
2739 "signature not multiple of 8 bits");
2740 return HX509_CRYPTO_SIG_INVALID_FORMAT
;
2743 os
.data
= sig
->data
;
2744 os
.length
= sig
->length
/ 8;
2746 return _hx509_verify_signature(context
, signer
, alg
, data
, &os
);
2752 * Verify that the certificate is allowed to be used for the hostname
2755 * @param context A hx509 context.
2756 * @param cert the certificate to match with
2757 * @param flags Flags to modify the behavior:
2758 * - HX509_VHN_F_ALLOW_NO_MATCH no match is ok
2759 * @param type type of hostname:
2760 * - HX509_HN_HOSTNAME for plain hostname.
2761 * - HX509_HN_DNSSRV for DNS SRV names.
2762 * @param hostname the hostname to check
2763 * @param sa address of the host
2764 * @param sa_size length of address
2766 * @return An hx509 error code, see hx509_get_error_string().
2768 * @ingroup hx509_cert
2771 HX509_LIB_FUNCTION
int HX509_LIB_CALL
2772 hx509_verify_hostname(hx509_context context
,
2773 const hx509_cert cert
,
2775 hx509_hostname_type type
,
2776 const char *hostname
,
2777 const struct sockaddr
*sa
,
2778 /* XXX krb5_socklen_t */ int sa_size
)
2785 if (sa
&& sa_size
<= 0)
2788 memset(&san
, 0, sizeof(san
));
2792 ret
= find_extension_subject_alt_name(cert
->data
, &i
, &san
);
2793 if (ret
== HX509_EXTENSION_NOT_FOUND
)
2796 return HX509_PARSING_NAME_FAILED
;
2798 for (j
= 0; j
< san
.len
; j
++) {
2799 switch (san
.val
[j
].element
) {
2800 case choice_GeneralName_dNSName
: {
2801 heim_printable_string hn
;
2802 hn
.data
= rk_UNCONST(hostname
);
2803 hn
.length
= strlen(hostname
);
2805 if (der_printable_string_cmp(&san
.val
[j
].u
.dNSName
, &hn
) == 0) {
2806 free_GeneralNames(&san
);
2815 free_GeneralNames(&san
);
2818 name
= &cert
->data
->tbsCertificate
.subject
;
2820 /* Find first CN= in the name, and try to match the hostname on that */
2821 for (ret
= 0, k
= name
->u
.rdnSequence
.len
; ret
== 0 && k
> 0; k
--) {
2823 for (j
= 0; ret
== 0 && j
< name
->u
.rdnSequence
.val
[i
].len
; j
++) {
2824 AttributeTypeAndValue
*n
= &name
->u
.rdnSequence
.val
[i
].val
[j
];
2826 if (der_heim_oid_cmp(&n
->type
, &asn1_oid_id_at_commonName
) == 0) {
2827 DirectoryString
*ds
= &n
->value
;
2828 switch (ds
->element
) {
2829 case choice_DirectoryString_printableString
: {
2830 heim_printable_string hn
;
2831 hn
.data
= rk_UNCONST(hostname
);
2832 hn
.length
= strlen(hostname
);
2834 if (der_printable_string_cmp(&ds
->u
.printableString
, &hn
) == 0)
2838 case choice_DirectoryString_ia5String
: {
2840 hn
.data
= rk_UNCONST(hostname
);
2841 hn
.length
= strlen(hostname
);
2843 if (der_ia5_string_cmp(&ds
->u
.ia5String
, &hn
) == 0)
2847 case choice_DirectoryString_utf8String
:
2848 if (strcasecmp(ds
->u
.utf8String
, hostname
) == 0)
2853 ret
= HX509_NAME_CONSTRAINT_ERROR
;
2858 if ((flags
& HX509_VHN_F_ALLOW_NO_MATCH
) == 0)
2859 ret
= HX509_NAME_CONSTRAINT_ERROR
;
2864 HX509_LIB_FUNCTION
int HX509_LIB_CALL
2865 _hx509_set_cert_attribute(hx509_context context
,
2867 const heim_oid
*oid
,
2868 const heim_octet_string
*attr
)
2870 hx509_cert_attribute a
;
2875 * TODO: Rewrite this (and hx509_cert_attribute, and _hx509_cert_attrs) to
2876 * use the add_AttributeValues() util generated by asn1_compile.
2879 if (hx509_cert_get_attribute(cert
, oid
) != NULL
)
2882 d
= realloc(cert
->attrs
.val
,
2883 sizeof(cert
->attrs
.val
[0]) * (cert
->attrs
.len
+ 1));
2885 hx509_clear_error_string(context
);
2888 cert
->attrs
.val
= d
;
2890 a
= malloc(sizeof(*a
));
2894 ret
= der_copy_octet_string(attr
, &a
->data
);
2896 ret
= der_copy_oid(oid
, &a
->oid
);
2898 cert
->attrs
.val
[cert
->attrs
.len
] = a
;
2901 der_free_octet_string(&a
->data
);
2909 * Get an external attribute for the certificate, examples are
2910 * friendly name and id.
2912 * @param cert hx509 certificate object to search
2913 * @param oid an oid to search for.
2915 * @return an hx509_cert_attribute, only valid as long as the
2916 * certificate is referenced.
2918 * @ingroup hx509_cert
2921 HX509_LIB_FUNCTION hx509_cert_attribute HX509_LIB_CALL
2922 hx509_cert_get_attribute(hx509_cert cert
, const heim_oid
*oid
)
2925 for (i
= 0; i
< cert
->attrs
.len
; i
++)
2926 if (der_heim_oid_cmp(oid
, &cert
->attrs
.val
[i
]->oid
) == 0)
2927 return cert
->attrs
.val
[i
];
2932 * Set the friendly name on the certificate.
2934 * @param cert The certificate to set the friendly name on
2935 * @param name Friendly name.
2937 * @return An hx509 error code, see hx509_get_error_string().
2939 * @ingroup hx509_cert
2942 HX509_LIB_FUNCTION
int HX509_LIB_CALL
2943 hx509_cert_set_friendly_name(hx509_cert cert
, const char *name
)
2945 if (cert
->friendlyname
)
2946 free(cert
->friendlyname
);
2947 cert
->friendlyname
= strdup(name
);
2948 if (cert
->friendlyname
== NULL
)
2954 * Get friendly name of the certificate.
2956 * @param cert cert to get the friendly name from.
2958 * @return an friendly name or NULL if there is. The friendly name is
2959 * only valid as long as the certificate is referenced.
2961 * @ingroup hx509_cert
2964 HX509_LIB_FUNCTION
const char * HX509_LIB_CALL
2965 hx509_cert_get_friendly_name(hx509_cert cert
)
2967 hx509_cert_attribute a
;
2968 PKCS9_friendlyName n
;
2973 if (cert
->friendlyname
)
2974 return cert
->friendlyname
;
2976 a
= hx509_cert_get_attribute(cert
, &asn1_oid_id_pkcs_9_at_friendlyName
);
2980 ret
= hx509_cert_get_subject(cert
, &name
);
2983 ret
= hx509_name_to_string(name
, &cert
->friendlyname
);
2984 hx509_name_free(&name
);
2987 return cert
->friendlyname
;
2990 ret
= decode_PKCS9_friendlyName(a
->data
.data
, a
->data
.length
, &n
, &sz
);
2995 free_PKCS9_friendlyName(&n
);
2999 cert
->friendlyname
= malloc(n
.val
[0].length
+ 1);
3000 if (cert
->friendlyname
== NULL
) {
3001 free_PKCS9_friendlyName(&n
);
3005 for (i
= 0; i
< n
.val
[0].length
; i
++) {
3006 if (n
.val
[0].data
[i
] <= 0xff)
3007 cert
->friendlyname
[i
] = n
.val
[0].data
[i
] & 0xff;
3009 cert
->friendlyname
[i
] = 'X';
3011 cert
->friendlyname
[i
] = '\0';
3012 free_PKCS9_friendlyName(&n
);
3014 return cert
->friendlyname
;
3017 HX509_LIB_FUNCTION
void HX509_LIB_CALL
3018 _hx509_query_clear(hx509_query
*q
)
3020 memset(q
, 0, sizeof(*q
));
3024 * Allocate an query controller. Free using hx509_query_free().
3026 * @param context A hx509 context.
3027 * @param q return pointer to a hx509_query.
3029 * @return An hx509 error code, see hx509_get_error_string().
3031 * @ingroup hx509_cert
3034 HX509_LIB_FUNCTION
int HX509_LIB_CALL
3035 hx509_query_alloc(hx509_context context
, hx509_query
**q
)
3037 *q
= calloc(1, sizeof(**q
));
3045 * Set match options for the hx509 query controller.
3047 * @param q query controller.
3048 * @param option options to control the query controller.
3050 * @return An hx509 error code, see hx509_get_error_string().
3052 * @ingroup hx509_cert
3055 HX509_LIB_FUNCTION
void HX509_LIB_CALL
3056 hx509_query_match_option(hx509_query
*q
, hx509_query_option option
)
3059 case HX509_QUERY_OPTION_PRIVATE_KEY
:
3060 q
->match
|= HX509_QUERY_PRIVATE_KEY
;
3062 case HX509_QUERY_OPTION_KU_ENCIPHERMENT
:
3063 q
->match
|= HX509_QUERY_KU_ENCIPHERMENT
;
3065 case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE
:
3066 q
->match
|= HX509_QUERY_KU_DIGITALSIGNATURE
;
3068 case HX509_QUERY_OPTION_KU_KEYCERTSIGN
:
3069 q
->match
|= HX509_QUERY_KU_KEYCERTSIGN
;
3071 case HX509_QUERY_OPTION_END
:
3078 * Set the issuer and serial number of match in the query
3079 * controller. The function make copies of the isser and serial number.
3081 * @param q a hx509 query controller
3082 * @param issuer issuer to search for
3083 * @param serialNumber the serialNumber of the issuer.
3085 * @return An hx509 error code, see hx509_get_error_string().
3087 * @ingroup hx509_cert
3090 HX509_LIB_FUNCTION
int HX509_LIB_CALL
3091 hx509_query_match_issuer_serial(hx509_query
*q
,
3093 const heim_integer
*serialNumber
)
3097 der_free_heim_integer(q
->serial
);
3100 q
->serial
= malloc(sizeof(*q
->serial
));
3101 if (q
->serial
== NULL
)
3103 ret
= der_copy_heim_integer(serialNumber
, q
->serial
);
3109 if (q
->issuer_name
) {
3110 free_Name(q
->issuer_name
);
3111 free(q
->issuer_name
);
3113 q
->issuer_name
= malloc(sizeof(*q
->issuer_name
));
3114 if (q
->issuer_name
== NULL
)
3116 ret
= copy_Name(issuer
, q
->issuer_name
);
3118 free(q
->issuer_name
);
3119 q
->issuer_name
= NULL
;
3122 q
->match
|= HX509_QUERY_MATCH_SERIALNUMBER
|HX509_QUERY_MATCH_ISSUER_NAME
;
3127 * Set the query controller to match on a friendly name
3129 * @param q a hx509 query controller.
3130 * @param name a friendly name to match on
3132 * @return An hx509 error code, see hx509_get_error_string().
3134 * @ingroup hx509_cert
3137 HX509_LIB_FUNCTION
int HX509_LIB_CALL
3138 hx509_query_match_friendly_name(hx509_query
*q
, const char *name
)
3140 if (q
->friendlyname
)
3141 free(q
->friendlyname
);
3142 q
->friendlyname
= strdup(name
);
3143 if (q
->friendlyname
== NULL
)
3145 q
->match
|= HX509_QUERY_MATCH_FRIENDLY_NAME
;
3150 * Set the query controller to require an one specific EKU (extended
3151 * key usage). Any previous EKU matching is overwitten. If NULL is
3152 * passed in as the eku, the EKU requirement is reset.
3154 * @param q a hx509 query controller.
3155 * @param eku an EKU to match on.
3157 * @return An hx509 error code, see hx509_get_error_string().
3159 * @ingroup hx509_cert
3162 HX509_LIB_FUNCTION
int HX509_LIB_CALL
3163 hx509_query_match_eku(hx509_query
*q
, const heim_oid
*eku
)
3169 der_free_oid(q
->eku
);
3173 q
->match
&= ~HX509_QUERY_MATCH_EKU
;
3176 der_free_oid(q
->eku
);
3178 q
->eku
= calloc(1, sizeof(*q
->eku
));
3182 ret
= der_copy_oid(eku
, q
->eku
);
3188 q
->match
|= HX509_QUERY_MATCH_EKU
;
3193 HX509_LIB_FUNCTION
int HX509_LIB_CALL
3194 hx509_query_match_expr(hx509_context context
, hx509_query
*q
, const char *expr
)
3197 _hx509_expr_free(q
->expr
);
3202 q
->match
&= ~HX509_QUERY_MATCH_EXPR
;
3206 q
->expr
= _hx509_expr_parse(expr
);
3207 if (q
->expr
== NULL
) {
3208 const char *reason
= _hx509_expr_parse_error();
3210 hx509_set_error_string(context
, 0, EINVAL
,
3211 "Invalid certificate query match expression: "
3213 reason
? reason
: "syntax error");
3217 q
->match
|= HX509_QUERY_MATCH_EXPR
;
3222 * Set the query controller to match using a specific match function.
3224 * @param q a hx509 query controller.
3225 * @param func function to use for matching, if the argument is NULL,
3226 * the match function is removed.
3227 * @param ctx context passed to the function.
3229 * @return An hx509 error code, see hx509_get_error_string().
3231 * @ingroup hx509_cert
3234 HX509_LIB_FUNCTION
int HX509_LIB_CALL
3235 hx509_query_match_cmp_func(hx509_query
*q
,
3236 int (*func
)(hx509_context
, hx509_cert
, void *),
3240 q
->match
|= HX509_QUERY_MATCH_FUNCTION
;
3242 q
->match
&= ~HX509_QUERY_MATCH_FUNCTION
;
3244 q
->cmp_func_ctx
= ctx
;
3249 * Free the query controller.
3251 * @param context A hx509 context.
3252 * @param q a pointer to the query controller.
3254 * @ingroup hx509_cert
3257 HX509_LIB_FUNCTION
void HX509_LIB_CALL
3258 hx509_query_free(hx509_context context
, hx509_query
*q
)
3264 der_free_heim_integer(q
->serial
);
3267 if (q
->issuer_name
) {
3268 free_Name(q
->issuer_name
);
3269 free(q
->issuer_name
);
3272 der_free_oid(q
->eku
);
3275 if (q
->friendlyname
)
3276 free(q
->friendlyname
);
3278 _hx509_expr_free(q
->expr
);
3280 memset(q
, 0, sizeof(*q
));
3284 HX509_LIB_FUNCTION
int HX509_LIB_CALL
3285 _hx509_query_match_cert(hx509_context context
, const hx509_query
*q
, hx509_cert cert
)
3287 Certificate
*c
= _hx509_get_cert(cert
);
3290 _hx509_query_statistic(context
, 1, q
);
3292 if ((q
->match
& HX509_QUERY_FIND_ISSUER_CERT
) &&
3293 _hx509_cert_is_parent_cmp(q
->subject
, c
, 0) != 0)
3296 if ((q
->match
& HX509_QUERY_MATCH_CERTIFICATE
) &&
3297 _hx509_Certificate_cmp(q
->certificate
, c
) != 0)
3300 if ((q
->match
& HX509_QUERY_MATCH_SERIALNUMBER
)
3301 && der_heim_integer_cmp(&c
->tbsCertificate
.serialNumber
, q
->serial
) != 0)
3304 if (q
->match
& HX509_QUERY_MATCH_ISSUER_NAME
) {
3305 ret
= _hx509_name_cmp(&c
->tbsCertificate
.issuer
, q
->issuer_name
, &diff
);
3310 if (q
->match
& HX509_QUERY_MATCH_SUBJECT_NAME
) {
3311 ret
= _hx509_name_cmp(&c
->tbsCertificate
.subject
, q
->subject_name
, &diff
);
3316 if (q
->match
& HX509_QUERY_MATCH_SUBJECT_KEY_ID
) {
3317 SubjectKeyIdentifier si
;
3319 ret
= _hx509_find_extension_subject_key_id(c
, &si
);
3321 if (der_heim_octet_string_cmp(&si
, q
->subject_id
) != 0)
3323 free_SubjectKeyIdentifier(&si
);
3328 if ((q
->match
& HX509_QUERY_MATCH_ISSUER_ID
))
3330 if ((q
->match
& HX509_QUERY_PRIVATE_KEY
) &&
3331 _hx509_cert_private_key(cert
) == NULL
)
3336 if (q
->match
& HX509_QUERY_KU_DIGITALSIGNATURE
)
3338 if (q
->match
& HX509_QUERY_KU_NONREPUDIATION
)
3340 if (q
->match
& HX509_QUERY_KU_ENCIPHERMENT
)
3342 if (q
->match
& HX509_QUERY_KU_DATAENCIPHERMENT
)
3344 if (q
->match
& HX509_QUERY_KU_KEYAGREEMENT
)
3346 if (q
->match
& HX509_QUERY_KU_KEYCERTSIGN
)
3348 if (q
->match
& HX509_QUERY_KU_CRLSIGN
)
3350 if (ku
&& check_key_usage(context
, c
, ku
, TRUE
))
3353 if ((q
->match
& HX509_QUERY_ANCHOR
))
3356 if (q
->match
& HX509_QUERY_MATCH_LOCAL_KEY_ID
) {
3357 hx509_cert_attribute a
;
3359 a
= hx509_cert_get_attribute(cert
, &asn1_oid_id_pkcs_9_at_localKeyId
);
3362 if (der_heim_octet_string_cmp(&a
->data
, q
->local_key_id
) != 0)
3366 if (q
->match
& HX509_QUERY_NO_MATCH_PATH
) {
3369 for (i
= 0; i
< q
->path
->len
; i
++)
3370 if (hx509_cert_cmp(q
->path
->val
[i
], cert
) == 0)
3373 if (q
->match
& HX509_QUERY_MATCH_FRIENDLY_NAME
) {
3374 const char *name
= hx509_cert_get_friendly_name(cert
);
3377 if (strcasecmp(q
->friendlyname
, name
) != 0)
3380 if (q
->match
& HX509_QUERY_MATCH_FUNCTION
) {
3381 ret
= (*q
->cmp_func
)(context
, cert
, q
->cmp_func_ctx
);
3386 if (q
->match
& HX509_QUERY_MATCH_KEY_HASH_SHA1
) {
3387 heim_octet_string os
;
3389 os
.data
= c
->tbsCertificate
.subjectPublicKeyInfo
.subjectPublicKey
.data
;
3391 c
->tbsCertificate
.subjectPublicKeyInfo
.subjectPublicKey
.length
/ 8;
3393 ret
= _hx509_verify_signature(context
,
3395 hx509_signature_sha1(),
3402 if (q
->match
& HX509_QUERY_MATCH_TIME
) {
3404 t
= _hx509_Time2time_t(&c
->tbsCertificate
.validity
.notBefore
);
3407 t
= _hx509_Time2time_t(&c
->tbsCertificate
.validity
.notAfter
);
3412 /* If an EKU is required, check the cert for it. */
3413 if ((q
->match
& HX509_QUERY_MATCH_EKU
) &&
3414 hx509_cert_check_eku(context
, cert
, q
->eku
, 0))
3417 if ((q
->match
& HX509_QUERY_MATCH_EXPR
)) {
3418 hx509_env env
= NULL
;
3420 ret
= _hx509_cert_to_env(context
, cert
, &env
);
3424 ret
= _hx509_expr_eval(context
, env
, q
->expr
);
3425 hx509_env_free(&env
);
3430 if (q
->match
& ~HX509_QUERY_MASK
)
3437 * Set a statistic file for the query statistics.
3439 * @param context A hx509 context.
3440 * @param fn statistics file name
3442 * @ingroup hx509_cert
3445 HX509_LIB_FUNCTION
void HX509_LIB_CALL
3446 hx509_query_statistic_file(hx509_context context
, const char *fn
)
3448 if (context
->querystat
)
3449 free(context
->querystat
);
3450 context
->querystat
= strdup(fn
);
3453 HX509_LIB_FUNCTION
void HX509_LIB_CALL
3454 _hx509_query_statistic(hx509_context context
, int type
, const hx509_query
*q
)
3457 if (context
->querystat
== NULL
)
3459 f
= fopen(context
->querystat
, "a");
3463 fprintf(f
, "%d %d\n", type
, q
->match
);
3467 static const char *statname
[] = {
3469 "match serialnumber",
3470 "match issuer name",
3471 "match subject name",
3472 "match subject key id",
3476 "ku digitalsignature",
3479 "ku nonrepudiation",
3481 "ku dataencipherment",
3483 "match certificate",
3484 "match local key id",
3486 "match friendly name",
3488 "match key hash sha1",
3493 unsigned long stats
;
3499 stat_sort(const void *a
, const void *b
)
3501 const struct stat_el
*ae
= a
;
3502 const struct stat_el
*be
= b
;
3503 return be
->stats
- ae
->stats
;
3507 * Unparse the statistics file and print the result on a FILE descriptor.
3509 * @param context A hx509 context.
3510 * @param printtype tyep to print
3511 * @param out the FILE to write the data on.
3513 * @ingroup hx509_cert
3516 HX509_LIB_FUNCTION
void HX509_LIB_CALL
3517 hx509_query_unparse_stats(hx509_context context
, int printtype
, FILE *out
)
3521 int type
, mask
, num
;
3523 unsigned long multiqueries
= 0, totalqueries
= 0;
3524 struct stat_el stats
[32];
3526 if (context
->querystat
== NULL
)
3528 f
= fopen(context
->querystat
, "r");
3530 fprintf(out
, "No statistics file %s: %s.\n",
3531 context
->querystat
, strerror(errno
));
3536 for (i
= 0; i
< sizeof(stats
)/sizeof(stats
[0]); i
++) {
3541 while (fscanf(f
, "%d %d\n", &type
, &mask
) == 2) {
3542 if (type
!= printtype
)
3545 while (mask
&& i
< sizeof(stats
)/sizeof(stats
[0])) {
3559 qsort(stats
, sizeof(stats
)/sizeof(stats
[0]), sizeof(stats
[0]), stat_sort
);
3563 errx(1, "out of memory");
3565 rtbl_set_separator (t
, " ");
3567 rtbl_add_column_by_id (t
, 0, "Name", 0);
3568 rtbl_add_column_by_id (t
, 1, "Counter", 0);
3571 for (i
= 0; i
< sizeof(stats
)/sizeof(stats
[0]); i
++) {
3574 if (stats
[i
].index
< sizeof(statname
)/sizeof(statname
[0]))
3575 rtbl_add_column_entry_by_id (t
, 0, statname
[stats
[i
].index
]);
3577 snprintf(str
, sizeof(str
), "%d", stats
[i
].index
);
3578 rtbl_add_column_entry_by_id (t
, 0, str
);
3580 snprintf(str
, sizeof(str
), "%lu", stats
[i
].stats
);
3581 rtbl_add_column_entry_by_id (t
, 1, str
);
3584 rtbl_format(t
, out
);
3587 fprintf(out
, "\nQueries: multi %lu total %lu\n",
3588 multiqueries
, totalqueries
);
3592 * Check the extended key usage on the hx509 certificate.
3594 * @param context A hx509 context.
3595 * @param cert A hx509 context.
3596 * @param eku the EKU to check for
3597 * @param allow_any_eku if the any EKU is set, allow that to be a
3600 * @return An hx509 error code, see hx509_get_error_string().
3602 * @ingroup hx509_cert
3605 HX509_LIB_FUNCTION
int HX509_LIB_CALL
3606 hx509_cert_check_eku(hx509_context context
, hx509_cert cert
,
3607 const heim_oid
*eku
, int allow_any_eku
)
3613 ret
= find_extension_eku(_hx509_get_cert(cert
), &e
);
3615 hx509_clear_error_string(context
);
3619 for (i
= 0; i
< e
.len
; i
++) {
3620 if (der_heim_oid_cmp(eku
, &e
.val
[i
]) == 0) {
3621 free_ExtKeyUsage(&e
);
3624 if (allow_any_eku
) {
3625 if (der_heim_oid_cmp(&asn1_oid_id_x509_ce_anyExtendedKeyUsage
,
3627 free_ExtKeyUsage(&e
);
3632 free_ExtKeyUsage(&e
);
3633 hx509_clear_error_string(context
);
3634 return HX509_CERTIFICATE_MISSING_EKU
;
3637 HX509_LIB_FUNCTION
int HX509_LIB_CALL
3638 _hx509_cert_get_keyusage(hx509_context context
,
3648 memset(ku
, 0, sizeof(*ku
));
3650 cert
= _hx509_get_cert(c
);
3652 if (_hx509_cert_get_version(cert
) < 3)
3655 e
= find_extension(cert
, &asn1_oid_id_x509_ce_keyUsage
, &i
);
3657 return HX509_KU_CERT_MISSING
;
3659 ret
= decode_KeyUsage(e
->extnValue
.data
, e
->extnValue
.length
, ku
, &size
);
3665 HX509_LIB_FUNCTION
int HX509_LIB_CALL
3666 _hx509_cert_get_eku(hx509_context context
,
3672 memset(e
, 0, sizeof(*e
));
3674 ret
= find_extension_eku(_hx509_get_cert(cert
), e
);
3675 if (ret
&& ret
!= HX509_EXTENSION_NOT_FOUND
) {
3676 hx509_clear_error_string(context
);
3683 * Encodes the hx509 certificate as a DER encode binary.
3685 * @param context A hx509 context.
3686 * @param c the certificate to encode.
3687 * @param os the encode certificate, set to NULL, 0 on case of
3688 * error. Free the os->data with hx509_xfree().
3690 * @return An hx509 error code, see hx509_get_error_string().
3692 * @ingroup hx509_cert
3695 HX509_LIB_FUNCTION
int HX509_LIB_CALL
3696 hx509_cert_binary(hx509_context context
, hx509_cert c
, heim_octet_string
*os
)
3704 ASN1_MALLOC_ENCODE(Certificate
, os
->data
, os
->length
,
3705 _hx509_get_cert(c
), &size
, ret
);
3711 if (os
->length
!= size
)
3712 _hx509_abort("internal ASN.1 encoder error");
3717 * Last to avoid lost __attribute__s due to #undef.
3720 #undef __attribute__
3721 #define __attribute__(X)
3723 HX509_LIB_NORETURN_FUNCTION
void HX509_LIB_CALL
3724 _hx509_abort(const char *fmt
, ...)
3725 __attribute__ ((__noreturn__
, __format__ (__printf__
, 1, 2)))
3737 * Free a data element allocated in the library.
3739 * @param ptr data to be freed.
3741 * @ingroup hx509_misc
3744 HX509_LIB_FUNCTION
void HX509_LIB_CALL
3745 hx509_xfree(void *ptr
)
3754 HX509_LIB_FUNCTION
int HX509_LIB_CALL
3755 _hx509_cert_to_env(hx509_context context
, hx509_cert cert
, hx509_env
*env
)
3761 hx509_env envcert
= NULL
;
3766 ret
= asprintf(&buf
, "%d", _hx509_cert_get_version(_hx509_get_cert(cert
)));
3769 ret
= hx509_env_add(context
, &envcert
, "version", buf
);
3775 ret
= hx509_cert_get_subject(cert
, &name
);
3779 ret
= hx509_name_to_string(name
, &buf
);
3780 hx509_name_free(&name
);
3784 ret
= hx509_env_add(context
, &envcert
, "subject", buf
);
3790 ret
= hx509_cert_get_issuer(cert
, &name
);
3794 ret
= hx509_name_to_string(name
, &buf
);
3795 hx509_name_free(&name
);
3799 ret
= hx509_env_add(context
, &envcert
, "issuer", buf
);
3806 ret
= _hx509_cert_get_eku(context
, cert
, &eku
);
3807 if (ret
== HX509_EXTENSION_NOT_FOUND
)
3813 hx509_env enveku
= NULL
;
3815 for (i
= 0; i
< eku
.len
; i
++) {
3817 ret
= der_print_heim_oid(&eku
.val
[i
], '.', &buf
);
3819 free_ExtKeyUsage(&eku
);
3820 hx509_env_free(&enveku
);
3823 ret
= hx509_env_add(context
, &enveku
, buf
, "oid-name-here");
3826 free_ExtKeyUsage(&eku
);
3827 hx509_env_free(&enveku
);
3831 free_ExtKeyUsage(&eku
);
3833 ret
= hx509_env_add_binding(context
, &envcert
, "eku", enveku
);
3835 hx509_env_free(&enveku
);
3841 Certificate
*c
= _hx509_get_cert(cert
);
3842 heim_octet_string os
, sig
;
3843 hx509_env envhash
= NULL
;
3845 os
.data
= c
->tbsCertificate
.subjectPublicKeyInfo
.subjectPublicKey
.data
;
3847 c
->tbsCertificate
.subjectPublicKeyInfo
.subjectPublicKey
.length
/ 8;
3849 ret
= _hx509_create_signature(context
,
3851 hx509_signature_sha1(),
3858 ret
= hex_encode(sig
.data
, sig
.length
, &buf
);
3859 der_free_octet_string(&sig
);
3862 hx509_set_error_string(context
, 0, ret
,
3867 ret
= hx509_env_add(context
, &envhash
, "sha1", buf
);
3872 ret
= hx509_env_add_binding(context
, &envcert
, "hash", envhash
);
3874 hx509_env_free(&envhash
);
3879 ret
= hx509_env_add_binding(context
, env
, "certificate", envcert
);
3886 hx509_env_free(&envcert
);
3891 * Print a simple representation of a certificate
3893 * @param context A hx509 context, can be NULL
3894 * @param cert certificate to print
3895 * @param out the stdio output stream, if NULL, stdout is used
3897 * @return An hx509 error code
3899 * @ingroup hx509_cert
3902 HX509_LIB_FUNCTION
int HX509_LIB_CALL
3903 hx509_print_cert(hx509_context context
, hx509_cert cert
, FILE *out
)
3912 ret
= hx509_cert_get_issuer(cert
, &name
);
3915 hx509_name_to_string(name
, &str
);
3916 hx509_name_free(&name
);
3917 fprintf(out
, " issuer: \"%s\"\n", str
);
3920 ret
= hx509_cert_get_subject(cert
, &name
);
3923 hx509_name_to_string(name
, &str
);
3924 hx509_name_free(&name
);
3925 fprintf(out
, " subject: \"%s\"\n", str
);
3929 heim_integer serialNumber
;
3931 ret
= hx509_cert_get_serialnumber(cert
, &serialNumber
);
3934 ret
= der_print_hex_heim_integer(&serialNumber
, &str
);
3937 der_free_heim_integer(&serialNumber
);
3938 fprintf(out
, " serial: %s\n", str
);
3942 fprintf(out
, " keyusage: ");
3943 ret
= hx509_cert_keyusage_print(context
, cert
, &str
);
3945 fprintf(out
, "%s\n", str
);