Use anon realm for anonymous PKINIT
[heimdal.git] / lib / hx509 / cert.c
blobba7f112d57a1151cca7efe62614e497874e8dcc0
1 /*
2 * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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
31 * SUCH DAMAGE.
34 #include "hx_locl.h"
35 #include "crypto-headers.h"
36 #include <rtbl.h>
38 /**
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;
55 int flags;
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
62 time_t time_now;
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 {
73 size_t len;
74 hx509_cert_attribute *val;
77 struct hx509_cert_data {
78 unsigned int ref;
79 char *friendlyname;
80 Certificate *data;
81 hx509_private_key private_key;
82 struct _hx509_cert_attrs attrs;
83 hx509_name basename;
84 _hx509_cert_release_func release;
85 void *ctx;
88 typedef struct hx509_name_constraints {
89 NameConstraints *val;
90 size_t len;
91 } hx509_name_constraints;
93 #define GeneralSubtrees_SET(g,var) \
94 (g)->len = (var)->len, (g)->val = (var)->val;
96 static void
97 init_context_once(void *ignored)
100 ENGINE_add_conf_module();
101 OpenSSL_add_all_algorithms();
105 * Creates a hx509 context that most functions in the library
106 * uses. The context is only allowed to be used by one thread at each
107 * moment. Free the context with hx509_context_free().
109 * @param context Returns a pointer to new hx509 context.
111 * @return Returns an hx509 error code.
113 * @ingroup hx509
117 hx509_context_init(hx509_context *context)
119 static heim_base_once_t init_context = HEIM_BASE_ONCE_INIT;
121 *context = calloc(1, sizeof(**context));
122 if (*context == NULL)
123 return ENOMEM;
125 heim_base_once_f(&init_context, NULL, init_context_once);
127 _hx509_ks_null_register(*context);
128 _hx509_ks_mem_register(*context);
129 _hx509_ks_file_register(*context);
130 _hx509_ks_pkcs12_register(*context);
131 _hx509_ks_pkcs11_register(*context);
132 _hx509_ks_dir_register(*context);
133 _hx509_ks_keychain_register(*context);
135 (*context)->ocsp_time_diff = HX509_DEFAULT_OCSP_TIME_DIFF;
137 initialize_hx_error_table_r(&(*context)->et_list);
138 initialize_asn1_error_table_r(&(*context)->et_list);
140 #ifdef HX509_DEFAULT_ANCHORS
141 (void)hx509_certs_init(*context, HX509_DEFAULT_ANCHORS, 0,
142 NULL, &(*context)->default_trust_anchors);
143 #endif
145 return 0;
149 * Selects if the hx509_revoke_verify() function is going to require
150 * the existans of a revokation method (OCSP, CRL) or not. Note that
151 * hx509_verify_path(), hx509_cms_verify_signed(), and other function
152 * call hx509_revoke_verify().
154 * @param context hx509 context to change the flag for.
155 * @param flag zero, revokation method required, non zero missing
156 * revokation method ok
158 * @ingroup hx509_verify
161 void
162 hx509_context_set_missing_revoke(hx509_context context, int flag)
164 if (flag)
165 context->flags |= HX509_CTX_VERIFY_MISSING_OK;
166 else
167 context->flags &= ~HX509_CTX_VERIFY_MISSING_OK;
171 * Free the context allocated by hx509_context_init().
173 * @param context context to be freed.
175 * @ingroup hx509
178 void
179 hx509_context_free(hx509_context *context)
181 hx509_clear_error_string(*context);
182 if ((*context)->ks_ops) {
183 free((*context)->ks_ops);
184 (*context)->ks_ops = NULL;
186 (*context)->ks_num_ops = 0;
187 free_error_table ((*context)->et_list);
188 if ((*context)->querystat)
189 free((*context)->querystat);
190 memset(*context, 0, sizeof(**context));
191 free(*context);
192 *context = NULL;
199 Certificate *
200 _hx509_get_cert(hx509_cert cert)
202 return cert->data;
210 _hx509_cert_get_version(const Certificate *t)
212 return t->tbsCertificate.version ? *t->tbsCertificate.version + 1 : 1;
216 * Allocate and init an hx509 certificate object from the decoded
217 * certificate `c´.
219 * @param context A hx509 context.
220 * @param c
221 * @param error
223 * @return Returns an hx509 certificate
225 * @ingroup hx509_cert
228 hx509_cert
229 hx509_cert_init(hx509_context context, const Certificate *c, heim_error_t *error)
231 hx509_cert cert;
232 int ret;
234 cert = malloc(sizeof(*cert));
235 if (cert == NULL) {
236 if (error)
237 *error = heim_error_create_enomem();
238 return NULL;
240 cert->ref = 1;
241 cert->friendlyname = NULL;
242 cert->attrs.len = 0;
243 cert->attrs.val = NULL;
244 cert->private_key = NULL;
245 cert->basename = NULL;
246 cert->release = NULL;
247 cert->ctx = NULL;
249 cert->data = calloc(1, sizeof(*(cert->data)));
250 if (cert->data == NULL) {
251 free(cert);
252 if (error)
253 *error = heim_error_create_enomem();
254 return NULL;
256 ret = copy_Certificate(c, cert->data);
257 if (ret) {
258 free(cert->data);
259 free(cert);
260 cert = NULL;
262 return cert;
266 * Just like hx509_cert_init(), but instead of a decode certificate
267 * takes an pointer and length to a memory region that contains a
268 * DER/BER encoded certificate.
270 * If the memory region doesn't contain just the certificate and
271 * nothing more the function will fail with
272 * HX509_EXTRA_DATA_AFTER_STRUCTURE.
274 * @param context A hx509 context.
275 * @param ptr pointer to memory region containing encoded certificate.
276 * @param len length of memory region.
277 * @param error possibly returns an error
279 * @return An hx509 certificate
281 * @ingroup hx509_cert
284 hx509_cert
285 hx509_cert_init_data(hx509_context context,
286 const void *ptr,
287 size_t len,
288 heim_error_t *error)
290 hx509_cert cert;
291 Certificate t;
292 size_t size;
293 int ret;
295 ret = decode_Certificate(ptr, len, &t, &size);
296 if (ret) {
297 if (error)
298 *error = heim_error_create(ret, "Failed to decode certificate");
299 return NULL;
301 if (size != len) {
302 free_Certificate(&t);
303 if (error)
304 *error = heim_error_create(HX509_EXTRA_DATA_AFTER_STRUCTURE,
305 "Extra data after certificate");
306 return NULL;
309 cert = hx509_cert_init(context, &t, error);
310 free_Certificate(&t);
311 return cert;
314 void
315 _hx509_cert_set_release(hx509_cert cert,
316 _hx509_cert_release_func release,
317 void *ctx)
319 cert->release = release;
320 cert->ctx = ctx;
324 /* Doesn't make a copy of `private_key'. */
327 _hx509_cert_assign_key(hx509_cert cert, hx509_private_key private_key)
329 if (cert->private_key)
330 hx509_private_key_free(&cert->private_key);
331 cert->private_key = _hx509_private_key_ref(private_key);
332 return 0;
336 * Free reference to the hx509 certificate object, if the refcounter
337 * reaches 0, the object if freed. Its allowed to pass in NULL.
339 * @param cert the cert to free.
341 * @ingroup hx509_cert
344 void
345 hx509_cert_free(hx509_cert cert)
347 size_t i;
349 if (cert == NULL)
350 return;
352 if (cert->ref <= 0)
353 _hx509_abort("cert refcount <= 0 on free");
354 if (--cert->ref > 0)
355 return;
357 if (cert->release)
358 (cert->release)(cert, cert->ctx);
360 if (cert->private_key)
361 hx509_private_key_free(&cert->private_key);
363 free_Certificate(cert->data);
364 free(cert->data);
366 for (i = 0; i < cert->attrs.len; i++) {
367 der_free_octet_string(&cert->attrs.val[i]->data);
368 der_free_oid(&cert->attrs.val[i]->oid);
369 free(cert->attrs.val[i]);
371 free(cert->attrs.val);
372 free(cert->friendlyname);
373 if (cert->basename)
374 hx509_name_free(&cert->basename);
375 memset(cert, 0, sizeof(*cert));
376 free(cert);
380 * Add a reference to a hx509 certificate object.
382 * @param cert a pointer to an hx509 certificate object.
384 * @return the same object as is passed in.
386 * @ingroup hx509_cert
389 hx509_cert
390 hx509_cert_ref(hx509_cert cert)
392 if (cert == NULL)
393 return NULL;
394 if (cert->ref <= 0)
395 _hx509_abort("cert refcount <= 0");
396 cert->ref++;
397 if (cert->ref == 0)
398 _hx509_abort("cert refcount == 0");
399 return cert;
403 * Allocate an verification context that is used fo control the
404 * verification process.
406 * @param context A hx509 context.
407 * @param ctx returns a pointer to a hx509_verify_ctx object.
409 * @return An hx509 error code, see hx509_get_error_string().
411 * @ingroup hx509_verify
415 hx509_verify_init_ctx(hx509_context context, hx509_verify_ctx *ctx)
417 hx509_verify_ctx c;
419 c = calloc(1, sizeof(*c));
420 if (c == NULL)
421 return ENOMEM;
423 c->max_depth = HX509_VERIFY_MAX_DEPTH;
425 *ctx = c;
427 return 0;
431 * Free an hx509 verification context.
433 * @param ctx the context to be freed.
435 * @ingroup hx509_verify
438 void
439 hx509_verify_destroy_ctx(hx509_verify_ctx ctx)
441 if (ctx) {
442 hx509_certs_free(&ctx->trust_anchors);
443 hx509_revoke_free(&ctx->revoke_ctx);
444 memset(ctx, 0, sizeof(*ctx));
446 free(ctx);
450 * Set the trust anchors in the verification context, makes an
451 * reference to the keyset, so the consumer can free the keyset
452 * independent of the destruction of the verification context (ctx).
453 * If there already is a keyset attached, it's released.
455 * @param ctx a verification context
456 * @param set a keyset containing the trust anchors.
458 * @ingroup hx509_verify
461 void
462 hx509_verify_attach_anchors(hx509_verify_ctx ctx, hx509_certs set)
464 if (ctx->trust_anchors)
465 hx509_certs_free(&ctx->trust_anchors);
466 ctx->trust_anchors = hx509_certs_ref(set);
470 * Attach an revocation context to the verfication context, , makes an
471 * reference to the revoke context, so the consumer can free the
472 * revoke context independent of the destruction of the verification
473 * context. If there is no revoke context, the verification process is
474 * NOT going to check any verification status.
476 * @param ctx a verification context.
477 * @param revoke_ctx a revoke context.
479 * @ingroup hx509_verify
482 void
483 hx509_verify_attach_revoke(hx509_verify_ctx ctx, hx509_revoke_ctx revoke_ctx)
485 if (ctx->revoke_ctx)
486 hx509_revoke_free(&ctx->revoke_ctx);
487 ctx->revoke_ctx = _hx509_revoke_ref(revoke_ctx);
491 * Set the clock time the the verification process is going to
492 * use. Used to check certificate in the past and future time. If not
493 * set the current time will be used.
495 * @param ctx a verification context.
496 * @param t the time the verifiation is using.
499 * @ingroup hx509_verify
502 void
503 hx509_verify_set_time(hx509_verify_ctx ctx, time_t t)
505 ctx->flags |= HX509_VERIFY_CTX_F_TIME_SET;
506 ctx->time_now = t;
509 time_t
510 _hx509_verify_get_time(hx509_verify_ctx ctx)
512 return ctx->time_now;
516 * Set the maximum depth of the certificate chain that the path
517 * builder is going to try.
519 * @param ctx a verification context
520 * @param max_depth maxium depth of the certificate chain, include
521 * trust anchor.
523 * @ingroup hx509_verify
526 void
527 hx509_verify_set_max_depth(hx509_verify_ctx ctx, unsigned int max_depth)
529 ctx->max_depth = max_depth;
533 * Allow or deny the use of proxy certificates
535 * @param ctx a verification context
536 * @param boolean if non zero, allow proxy certificates.
538 * @ingroup hx509_verify
541 void
542 hx509_verify_set_proxy_certificate(hx509_verify_ctx ctx, int boolean)
544 if (boolean)
545 ctx->flags |= HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
546 else
547 ctx->flags &= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
551 * Select strict RFC3280 verification of certificiates. This means
552 * checking key usage on CA certificates, this will make version 1
553 * certificiates unuseable.
555 * @param ctx a verification context
556 * @param boolean if non zero, use strict verification.
558 * @ingroup hx509_verify
561 void
562 hx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx, int boolean)
564 if (boolean)
565 ctx->flags |= HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
566 else
567 ctx->flags &= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
571 * Allow using the operating system builtin trust anchors if no other
572 * trust anchors are configured.
574 * @param ctx a verification context
575 * @param boolean if non zero, useing the operating systems builtin
576 * trust anchors.
579 * @return An hx509 error code, see hx509_get_error_string().
581 * @ingroup hx509_cert
584 void
585 hx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx, int boolean)
587 if (boolean)
588 ctx->flags &= ~HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
589 else
590 ctx->flags |= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
593 void
594 hx509_verify_ctx_f_allow_best_before_signature_algs(hx509_context ctx,
595 int boolean)
597 if (boolean)
598 ctx->flags &= ~HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK;
599 else
600 ctx->flags |= HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK;
603 static const Extension *
604 find_extension(const Certificate *cert, const heim_oid *oid, size_t *idx)
606 const TBSCertificate *c = &cert->tbsCertificate;
608 if (c->version == NULL || *c->version < 2 || c->extensions == NULL)
609 return NULL;
611 for (;*idx < c->extensions->len; (*idx)++) {
612 if (der_heim_oid_cmp(&c->extensions->val[*idx].extnID, oid) == 0)
613 return &c->extensions->val[(*idx)++];
615 return NULL;
618 static int
619 find_extension_auth_key_id(const Certificate *subject,
620 AuthorityKeyIdentifier *ai)
622 const Extension *e;
623 size_t size;
624 size_t i = 0;
626 memset(ai, 0, sizeof(*ai));
628 e = find_extension(subject, &asn1_oid_id_x509_ce_authorityKeyIdentifier, &i);
629 if (e == NULL)
630 return HX509_EXTENSION_NOT_FOUND;
632 return decode_AuthorityKeyIdentifier(e->extnValue.data,
633 e->extnValue.length,
634 ai, &size);
638 _hx509_find_extension_subject_key_id(const Certificate *issuer,
639 SubjectKeyIdentifier *si)
641 const Extension *e;
642 size_t size;
643 size_t i = 0;
645 memset(si, 0, sizeof(*si));
647 e = find_extension(issuer, &asn1_oid_id_x509_ce_subjectKeyIdentifier, &i);
648 if (e == NULL)
649 return HX509_EXTENSION_NOT_FOUND;
651 return decode_SubjectKeyIdentifier(e->extnValue.data,
652 e->extnValue.length,
653 si, &size);
656 static int
657 find_extension_name_constraints(const Certificate *subject,
658 NameConstraints *nc)
660 const Extension *e;
661 size_t size;
662 size_t i = 0;
664 memset(nc, 0, sizeof(*nc));
666 e = find_extension(subject, &asn1_oid_id_x509_ce_nameConstraints, &i);
667 if (e == NULL)
668 return HX509_EXTENSION_NOT_FOUND;
670 return decode_NameConstraints(e->extnValue.data,
671 e->extnValue.length,
672 nc, &size);
675 static int
676 find_extension_subject_alt_name(const Certificate *cert, size_t *i,
677 GeneralNames *sa)
679 const Extension *e;
680 size_t size;
682 memset(sa, 0, sizeof(*sa));
684 e = find_extension(cert, &asn1_oid_id_x509_ce_subjectAltName, i);
685 if (e == NULL)
686 return HX509_EXTENSION_NOT_FOUND;
688 return decode_GeneralNames(e->extnValue.data,
689 e->extnValue.length,
690 sa, &size);
693 static int
694 find_extension_eku(const Certificate *cert, ExtKeyUsage *eku)
696 const Extension *e;
697 size_t size;
698 size_t i = 0;
700 memset(eku, 0, sizeof(*eku));
702 e = find_extension(cert, &asn1_oid_id_x509_ce_extKeyUsage, &i);
703 if (e == NULL)
704 return HX509_EXTENSION_NOT_FOUND;
706 return decode_ExtKeyUsage(e->extnValue.data,
707 e->extnValue.length,
708 eku, &size);
711 static int
712 add_to_list(hx509_octet_string_list *list, const heim_octet_string *entry)
714 void *p;
715 int ret;
717 p = realloc(list->val, (list->len + 1) * sizeof(list->val[0]));
718 if (p == NULL)
719 return ENOMEM;
720 list->val = p;
721 ret = der_copy_octet_string(entry, &list->val[list->len]);
722 if (ret)
723 return ret;
724 list->len++;
725 return 0;
729 * Free a list of octet strings returned by another hx509 library
730 * function.
732 * @param list list to be freed.
734 * @ingroup hx509_misc
737 void
738 hx509_free_octet_string_list(hx509_octet_string_list *list)
740 size_t i;
741 for (i = 0; i < list->len; i++)
742 der_free_octet_string(&list->val[i]);
743 free(list->val);
744 list->val = NULL;
745 list->len = 0;
749 * Return a list of subjectAltNames specified by oid in the
750 * certificate. On error the
752 * The returned list of octet string should be freed with
753 * hx509_free_octet_string_list().
755 * @param context A hx509 context.
756 * @param cert a hx509 certificate object.
757 * @param oid an oid to for SubjectAltName.
758 * @param list list of matching SubjectAltName.
760 * @return An hx509 error code, see hx509_get_error_string().
762 * @ingroup hx509_cert
766 hx509_cert_find_subjectAltName_otherName(hx509_context context,
767 hx509_cert cert,
768 const heim_oid *oid,
769 hx509_octet_string_list *list)
771 GeneralNames sa;
772 int ret;
773 size_t i, j;
775 list->val = NULL;
776 list->len = 0;
778 i = 0;
779 while (1) {
780 ret = find_extension_subject_alt_name(_hx509_get_cert(cert), &i, &sa);
781 i++;
782 if (ret == HX509_EXTENSION_NOT_FOUND) {
783 return 0;
784 } else if (ret != 0) {
785 hx509_set_error_string(context, 0, ret, "Error searching for SAN");
786 hx509_free_octet_string_list(list);
787 return ret;
790 for (j = 0; j < sa.len; j++) {
791 if (sa.val[j].element == choice_GeneralName_otherName &&
792 der_heim_oid_cmp(&sa.val[j].u.otherName.type_id, oid) == 0)
794 ret = add_to_list(list, &sa.val[j].u.otherName.value);
795 if (ret) {
796 hx509_set_error_string(context, 0, ret,
797 "Error adding an exra SAN to "
798 "return list");
799 hx509_free_octet_string_list(list);
800 free_GeneralNames(&sa);
801 return ret;
805 free_GeneralNames(&sa);
810 static int
811 check_key_usage(hx509_context context, const Certificate *cert,
812 unsigned flags, int req_present)
814 const Extension *e;
815 KeyUsage ku;
816 size_t size;
817 int ret;
818 size_t i = 0;
819 unsigned ku_flags;
821 if (_hx509_cert_get_version(cert) < 3)
822 return 0;
824 e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i);
825 if (e == NULL) {
826 if (req_present) {
827 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
828 "Required extension key "
829 "usage missing from certifiate");
830 return HX509_KU_CERT_MISSING;
832 return 0;
835 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, &ku, &size);
836 if (ret)
837 return ret;
838 ku_flags = KeyUsage2int(ku);
839 if ((ku_flags & flags) != flags) {
840 unsigned missing = (~ku_flags) & flags;
841 char buf[256], *name;
843 unparse_flags(missing, asn1_KeyUsage_units(), buf, sizeof(buf));
844 _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
845 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
846 "Key usage %s required but missing "
847 "from certifiate %s", buf, name);
848 free(name);
849 return HX509_KU_CERT_MISSING;
851 return 0;
855 * Return 0 on matching key usage 'flags' for 'cert', otherwise return
856 * an error code. If 'req_present' the existance is required of the
857 * KeyUsage extension.
861 _hx509_check_key_usage(hx509_context context, hx509_cert cert,
862 unsigned flags, int req_present)
864 return check_key_usage(context, _hx509_get_cert(cert), flags, req_present);
867 enum certtype { PROXY_CERT, EE_CERT, CA_CERT };
869 static int
870 check_basic_constraints(hx509_context context, const Certificate *cert,
871 enum certtype type, size_t depth)
873 BasicConstraints bc;
874 const Extension *e;
875 size_t size;
876 int ret;
877 size_t i = 0;
879 if (_hx509_cert_get_version(cert) < 3)
880 return 0;
882 e = find_extension(cert, &asn1_oid_id_x509_ce_basicConstraints, &i);
883 if (e == NULL) {
884 switch(type) {
885 case PROXY_CERT:
886 case EE_CERT:
887 return 0;
888 case CA_CERT: {
889 char *name;
890 ret = _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
891 assert(ret == 0);
892 hx509_set_error_string(context, 0, HX509_EXTENSION_NOT_FOUND,
893 "basicConstraints missing from "
894 "CA certifiacte %s", name);
895 free(name);
896 return HX509_EXTENSION_NOT_FOUND;
901 ret = decode_BasicConstraints(e->extnValue.data,
902 e->extnValue.length, &bc,
903 &size);
904 if (ret)
905 return ret;
906 switch(type) {
907 case PROXY_CERT:
908 if (bc.cA != NULL && *bc.cA)
909 ret = HX509_PARENT_IS_CA;
910 break;
911 case EE_CERT:
912 ret = 0;
913 break;
914 case CA_CERT:
915 if (bc.cA == NULL || !*bc.cA)
916 ret = HX509_PARENT_NOT_CA;
917 else if (bc.pathLenConstraint)
918 if (depth - 1 > *bc.pathLenConstraint)
919 ret = HX509_CA_PATH_TOO_DEEP;
920 break;
922 free_BasicConstraints(&bc);
923 return ret;
927 _hx509_cert_is_parent_cmp(const Certificate *subject,
928 const Certificate *issuer,
929 int allow_self_signed)
931 int diff;
932 AuthorityKeyIdentifier ai;
933 SubjectKeyIdentifier si;
934 int ret_ai, ret_si, ret;
936 ret = _hx509_name_cmp(&issuer->tbsCertificate.subject,
937 &subject->tbsCertificate.issuer,
938 &diff);
939 if (ret)
940 return ret;
941 if (diff)
942 return diff;
944 memset(&ai, 0, sizeof(ai));
945 memset(&si, 0, sizeof(si));
948 * Try to find AuthorityKeyIdentifier, if it's not present in the
949 * subject certificate nor the parent.
952 ret_ai = find_extension_auth_key_id(subject, &ai);
953 if (ret_ai && ret_ai != HX509_EXTENSION_NOT_FOUND)
954 return 1;
955 ret_si = _hx509_find_extension_subject_key_id(issuer, &si);
956 if (ret_si && ret_si != HX509_EXTENSION_NOT_FOUND)
957 return -1;
959 if (ret_si && ret_ai)
960 goto out;
961 if (ret_ai)
962 goto out;
963 if (ret_si) {
964 if (allow_self_signed) {
965 diff = 0;
966 goto out;
967 } else if (ai.keyIdentifier) {
968 diff = -1;
969 goto out;
973 if (ai.keyIdentifier == NULL) {
974 Name name;
976 if (ai.authorityCertIssuer == NULL)
977 return -1;
978 if (ai.authorityCertSerialNumber == NULL)
979 return -1;
981 diff = der_heim_integer_cmp(ai.authorityCertSerialNumber,
982 &issuer->tbsCertificate.serialNumber);
983 if (diff)
984 return diff;
985 if (ai.authorityCertIssuer->len != 1)
986 return -1;
987 if (ai.authorityCertIssuer->val[0].element != choice_GeneralName_directoryName)
988 return -1;
990 name.element = (enum Name_enum)
991 ai.authorityCertIssuer->val[0].u.directoryName.element;
992 name.u.rdnSequence =
993 ai.authorityCertIssuer->val[0].u.directoryName.u.rdnSequence;
995 ret = _hx509_name_cmp(&issuer->tbsCertificate.subject,
996 &name,
997 &diff);
998 if (ret)
999 return ret;
1000 if (diff)
1001 return diff;
1002 diff = 0;
1003 } else
1004 diff = der_heim_octet_string_cmp(ai.keyIdentifier, &si);
1005 if (diff)
1006 goto out;
1008 out:
1009 free_AuthorityKeyIdentifier(&ai);
1010 free_SubjectKeyIdentifier(&si);
1011 return diff;
1014 static int
1015 certificate_is_anchor(hx509_context context,
1016 hx509_certs trust_anchors,
1017 const hx509_cert cert)
1019 hx509_query q;
1020 hx509_cert c;
1021 int ret;
1023 if (trust_anchors == NULL)
1024 return 0;
1026 _hx509_query_clear(&q);
1028 q.match = HX509_QUERY_MATCH_CERTIFICATE;
1029 q.certificate = _hx509_get_cert(cert);
1031 ret = hx509_certs_find(context, trust_anchors, &q, &c);
1032 if (ret == 0)
1033 hx509_cert_free(c);
1034 return ret == 0;
1037 static int
1038 certificate_is_self_signed(hx509_context context,
1039 const Certificate *cert,
1040 int *self_signed)
1042 int ret, diff;
1043 ret = _hx509_name_cmp(&cert->tbsCertificate.subject,
1044 &cert->tbsCertificate.issuer, &diff);
1045 *self_signed = (diff == 0);
1046 if (ret) {
1047 hx509_set_error_string(context, 0, ret,
1048 "Failed to check if self signed");
1049 } else
1050 ret = _hx509_self_signed_valid(context, &cert->signatureAlgorithm);
1052 return ret;
1056 * The subjectName is "null" when it's empty set of relative DBs.
1059 static int
1060 subject_null_p(const Certificate *c)
1062 return c->tbsCertificate.subject.u.rdnSequence.len == 0;
1066 static int
1067 find_parent(hx509_context context,
1068 time_t time_now,
1069 hx509_certs trust_anchors,
1070 hx509_path *path,
1071 hx509_certs pool,
1072 hx509_cert current,
1073 hx509_cert *parent)
1075 AuthorityKeyIdentifier ai;
1076 hx509_query q;
1077 int ret;
1079 *parent = NULL;
1080 memset(&ai, 0, sizeof(ai));
1082 _hx509_query_clear(&q);
1084 if (!subject_null_p(current->data)) {
1085 q.match |= HX509_QUERY_FIND_ISSUER_CERT;
1086 q.subject = _hx509_get_cert(current);
1087 } else {
1088 ret = find_extension_auth_key_id(current->data, &ai);
1089 if (ret) {
1090 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1091 "Subjectless certificate missing AuthKeyID");
1092 return HX509_CERTIFICATE_MALFORMED;
1095 if (ai.keyIdentifier == NULL) {
1096 free_AuthorityKeyIdentifier(&ai);
1097 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1098 "Subjectless certificate missing keyIdentifier "
1099 "inside AuthKeyID");
1100 return HX509_CERTIFICATE_MALFORMED;
1103 q.subject_id = ai.keyIdentifier;
1104 q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
1107 q.path = path;
1108 q.match |= HX509_QUERY_NO_MATCH_PATH;
1110 if (pool) {
1111 q.timenow = time_now;
1112 q.match |= HX509_QUERY_MATCH_TIME;
1114 ret = hx509_certs_find(context, pool, &q, parent);
1115 if (ret == 0) {
1116 free_AuthorityKeyIdentifier(&ai);
1117 return 0;
1119 q.match &= ~HX509_QUERY_MATCH_TIME;
1122 if (trust_anchors) {
1123 ret = hx509_certs_find(context, trust_anchors, &q, parent);
1124 if (ret == 0) {
1125 free_AuthorityKeyIdentifier(&ai);
1126 return ret;
1129 free_AuthorityKeyIdentifier(&ai);
1132 hx509_name name;
1133 char *str;
1135 ret = hx509_cert_get_subject(current, &name);
1136 if (ret) {
1137 hx509_clear_error_string(context);
1138 return HX509_ISSUER_NOT_FOUND;
1140 ret = hx509_name_to_string(name, &str);
1141 hx509_name_free(&name);
1142 if (ret) {
1143 hx509_clear_error_string(context);
1144 return HX509_ISSUER_NOT_FOUND;
1147 hx509_set_error_string(context, 0, HX509_ISSUER_NOT_FOUND,
1148 "Failed to find issuer for "
1149 "certificate with subject: '%s'", str);
1150 free(str);
1152 return HX509_ISSUER_NOT_FOUND;
1159 static int
1160 is_proxy_cert(hx509_context context,
1161 const Certificate *cert,
1162 ProxyCertInfo *rinfo)
1164 ProxyCertInfo info;
1165 const Extension *e;
1166 size_t size;
1167 int ret;
1168 size_t i = 0;
1170 if (rinfo)
1171 memset(rinfo, 0, sizeof(*rinfo));
1173 e = find_extension(cert, &asn1_oid_id_pkix_pe_proxyCertInfo, &i);
1174 if (e == NULL) {
1175 hx509_clear_error_string(context);
1176 return HX509_EXTENSION_NOT_FOUND;
1179 ret = decode_ProxyCertInfo(e->extnValue.data,
1180 e->extnValue.length,
1181 &info,
1182 &size);
1183 if (ret) {
1184 hx509_clear_error_string(context);
1185 return ret;
1187 if (size != e->extnValue.length) {
1188 free_ProxyCertInfo(&info);
1189 hx509_clear_error_string(context);
1190 return HX509_EXTRA_DATA_AFTER_STRUCTURE;
1192 if (rinfo == NULL)
1193 free_ProxyCertInfo(&info);
1194 else
1195 *rinfo = info;
1197 return 0;
1201 * Path operations are like MEMORY based keyset, but with exposed
1202 * internal so we can do easy searches.
1206 _hx509_path_append(hx509_context context, hx509_path *path, hx509_cert cert)
1208 hx509_cert *val;
1209 val = realloc(path->val, (path->len + 1) * sizeof(path->val[0]));
1210 if (val == NULL) {
1211 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1212 return ENOMEM;
1215 path->val = val;
1216 path->val[path->len] = hx509_cert_ref(cert);
1217 path->len++;
1219 return 0;
1222 void
1223 _hx509_path_free(hx509_path *path)
1225 unsigned i;
1227 for (i = 0; i < path->len; i++)
1228 hx509_cert_free(path->val[i]);
1229 free(path->val);
1230 path->val = NULL;
1231 path->len = 0;
1235 * Find path by looking up issuer for the top certificate and continue
1236 * until an anchor certificate is found or max limit is found. A
1237 * certificate never included twice in the path.
1239 * If the trust anchors are not given, calculate optimistic path, just
1240 * follow the chain upward until we no longer find a parent or we hit
1241 * the max path limit. In this case, a failure will always be returned
1242 * depending on what error condition is hit first.
1244 * The path includes a path from the top certificate to the anchor
1245 * certificate.
1247 * The caller needs to free `path´ both on successful built path and
1248 * failure.
1252 _hx509_calculate_path(hx509_context context,
1253 int flags,
1254 time_t time_now,
1255 hx509_certs anchors,
1256 unsigned int max_depth,
1257 hx509_cert cert,
1258 hx509_certs pool,
1259 hx509_path *path)
1261 hx509_cert parent, current;
1262 int ret;
1264 if (max_depth == 0)
1265 max_depth = HX509_VERIFY_MAX_DEPTH;
1267 ret = _hx509_path_append(context, path, cert);
1268 if (ret)
1269 return ret;
1271 current = hx509_cert_ref(cert);
1273 while (!certificate_is_anchor(context, anchors, current)) {
1275 ret = find_parent(context, time_now, anchors, path,
1276 pool, current, &parent);
1277 hx509_cert_free(current);
1278 if (ret)
1279 return ret;
1281 ret = _hx509_path_append(context, path, parent);
1282 if (ret)
1283 return ret;
1284 current = parent;
1286 if (path->len > max_depth) {
1287 hx509_cert_free(current);
1288 hx509_set_error_string(context, 0, HX509_PATH_TOO_LONG,
1289 "Path too long while bulding "
1290 "certificate chain");
1291 return HX509_PATH_TOO_LONG;
1295 if ((flags & HX509_CALCULATE_PATH_NO_ANCHOR) &&
1296 path->len > 0 &&
1297 certificate_is_anchor(context, anchors, path->val[path->len - 1]))
1299 hx509_cert_free(path->val[path->len - 1]);
1300 path->len--;
1303 hx509_cert_free(current);
1304 return 0;
1308 _hx509_AlgorithmIdentifier_cmp(const AlgorithmIdentifier *p,
1309 const AlgorithmIdentifier *q)
1311 int diff;
1312 diff = der_heim_oid_cmp(&p->algorithm, &q->algorithm);
1313 if (diff)
1314 return diff;
1315 if (p->parameters) {
1316 if (q->parameters)
1317 return heim_any_cmp(p->parameters,
1318 q->parameters);
1319 else
1320 return 1;
1321 } else {
1322 if (q->parameters)
1323 return -1;
1324 else
1325 return 0;
1330 _hx509_Certificate_cmp(const Certificate *p, const Certificate *q)
1332 int diff;
1333 diff = der_heim_bit_string_cmp(&p->signatureValue, &q->signatureValue);
1334 if (diff)
1335 return diff;
1336 diff = _hx509_AlgorithmIdentifier_cmp(&p->signatureAlgorithm,
1337 &q->signatureAlgorithm);
1338 if (diff)
1339 return diff;
1340 diff = der_heim_octet_string_cmp(&p->tbsCertificate._save,
1341 &q->tbsCertificate._save);
1342 return diff;
1346 * Compare to hx509 certificate object, useful for sorting.
1348 * @param p a hx509 certificate object.
1349 * @param q a hx509 certificate object.
1351 * @return 0 the objects are the same, returns > 0 is p is "larger"
1352 * then q, < 0 if p is "smaller" then q.
1354 * @ingroup hx509_cert
1358 hx509_cert_cmp(hx509_cert p, hx509_cert q)
1360 return _hx509_Certificate_cmp(p->data, q->data);
1364 * Return the name of the issuer of the hx509 certificate.
1366 * @param p a hx509 certificate object.
1367 * @param name a pointer to a hx509 name, should be freed by
1368 * hx509_name_free().
1370 * @return An hx509 error code, see hx509_get_error_string().
1372 * @ingroup hx509_cert
1376 hx509_cert_get_issuer(hx509_cert p, hx509_name *name)
1378 return _hx509_name_from_Name(&p->data->tbsCertificate.issuer, name);
1382 * Return the name of the subject of the hx509 certificate.
1384 * @param p a hx509 certificate object.
1385 * @param name a pointer to a hx509 name, should be freed by
1386 * hx509_name_free(). See also hx509_cert_get_base_subject().
1388 * @return An hx509 error code, see hx509_get_error_string().
1390 * @ingroup hx509_cert
1394 hx509_cert_get_subject(hx509_cert p, hx509_name *name)
1396 return _hx509_name_from_Name(&p->data->tbsCertificate.subject, name);
1400 * Return the name of the base subject of the hx509 certificate. If
1401 * the certiicate is a verified proxy certificate, the this function
1402 * return the base certificate (root of the proxy chain). If the proxy
1403 * certificate is not verified with the base certificate
1404 * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned.
1406 * @param context a hx509 context.
1407 * @param c a hx509 certificate object.
1408 * @param name a pointer to a hx509 name, should be freed by
1409 * hx509_name_free(). See also hx509_cert_get_subject().
1411 * @return An hx509 error code, see hx509_get_error_string().
1413 * @ingroup hx509_cert
1417 hx509_cert_get_base_subject(hx509_context context, hx509_cert c,
1418 hx509_name *name)
1420 if (c->basename)
1421 return hx509_name_copy(context, c->basename, name);
1422 if (is_proxy_cert(context, c->data, NULL) == 0) {
1423 int ret = HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED;
1424 hx509_set_error_string(context, 0, ret,
1425 "Proxy certificate have not been "
1426 "canonicalize yet, no base name");
1427 return ret;
1429 return _hx509_name_from_Name(&c->data->tbsCertificate.subject, name);
1433 * Get serial number of the certificate.
1435 * @param p a hx509 certificate object.
1436 * @param i serial number, should be freed ith der_free_heim_integer().
1438 * @return An hx509 error code, see hx509_get_error_string().
1440 * @ingroup hx509_cert
1444 hx509_cert_get_serialnumber(hx509_cert p, heim_integer *i)
1446 return der_copy_heim_integer(&p->data->tbsCertificate.serialNumber, i);
1450 * Get notBefore time of the certificate.
1452 * @param p a hx509 certificate object.
1454 * @return return not before time
1456 * @ingroup hx509_cert
1459 time_t
1460 hx509_cert_get_notBefore(hx509_cert p)
1462 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notBefore);
1466 * Get notAfter time of the certificate.
1468 * @param p a hx509 certificate object.
1470 * @return return not after time.
1472 * @ingroup hx509_cert
1475 time_t
1476 hx509_cert_get_notAfter(hx509_cert p)
1478 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notAfter);
1482 * Get the SubjectPublicKeyInfo structure from the hx509 certificate.
1484 * @param context a hx509 context.
1485 * @param p a hx509 certificate object.
1486 * @param spki SubjectPublicKeyInfo, should be freed with
1487 * free_SubjectPublicKeyInfo().
1489 * @return An hx509 error code, see hx509_get_error_string().
1491 * @ingroup hx509_cert
1495 hx509_cert_get_SPKI(hx509_context context, hx509_cert p, SubjectPublicKeyInfo *spki)
1497 int ret;
1499 ret = copy_SubjectPublicKeyInfo(&p->data->tbsCertificate.subjectPublicKeyInfo, spki);
1500 if (ret)
1501 hx509_set_error_string(context, 0, ret, "Failed to copy SPKI");
1502 return ret;
1506 * Get the AlgorithmIdentifier from the hx509 certificate.
1508 * @param context a hx509 context.
1509 * @param p a hx509 certificate object.
1510 * @param alg AlgorithmIdentifier, should be freed with
1511 * free_AlgorithmIdentifier(). The algorithmidentifier is
1512 * typicly rsaEncryption, or id-ecPublicKey, or some other
1513 * public key mechanism.
1515 * @return An hx509 error code, see hx509_get_error_string().
1517 * @ingroup hx509_cert
1521 hx509_cert_get_SPKI_AlgorithmIdentifier(hx509_context context,
1522 hx509_cert p,
1523 AlgorithmIdentifier *alg)
1525 int ret;
1527 ret = copy_AlgorithmIdentifier(&p->data->tbsCertificate.subjectPublicKeyInfo.algorithm, alg);
1528 if (ret)
1529 hx509_set_error_string(context, 0, ret,
1530 "Failed to copy SPKI AlgorithmIdentifier");
1531 return ret;
1534 static int
1535 get_x_unique_id(hx509_context context, const char *name,
1536 const heim_bit_string *cert, heim_bit_string *subject)
1538 int ret;
1540 if (cert == NULL) {
1541 ret = HX509_EXTENSION_NOT_FOUND;
1542 hx509_set_error_string(context, 0, ret, "%s unique id doesn't exists", name);
1543 return ret;
1545 ret = der_copy_bit_string(cert, subject);
1546 if (ret) {
1547 hx509_set_error_string(context, 0, ret, "malloc out of memory", name);
1548 return ret;
1550 return 0;
1554 * Get a copy of the Issuer Unique ID
1556 * @param context a hx509_context
1557 * @param p a hx509 certificate
1558 * @param issuer the issuer id returned, free with der_free_bit_string()
1560 * @return An hx509 error code, see hx509_get_error_string(). The
1561 * error code HX509_EXTENSION_NOT_FOUND is returned if the certificate
1562 * doesn't have a issuerUniqueID
1564 * @ingroup hx509_cert
1568 hx509_cert_get_issuer_unique_id(hx509_context context, hx509_cert p, heim_bit_string *issuer)
1570 return get_x_unique_id(context, "issuer", p->data->tbsCertificate.issuerUniqueID, issuer);
1574 * Get a copy of the Subect Unique ID
1576 * @param context a hx509_context
1577 * @param p a hx509 certificate
1578 * @param subject the subject id returned, free with der_free_bit_string()
1580 * @return An hx509 error code, see hx509_get_error_string(). The
1581 * error code HX509_EXTENSION_NOT_FOUND is returned if the certificate
1582 * doesn't have a subjectUniqueID
1584 * @ingroup hx509_cert
1588 hx509_cert_get_subject_unique_id(hx509_context context, hx509_cert p, heim_bit_string *subject)
1590 return get_x_unique_id(context, "subject", p->data->tbsCertificate.subjectUniqueID, subject);
1594 hx509_private_key
1595 _hx509_cert_private_key(hx509_cert p)
1597 return p->private_key;
1601 hx509_cert_have_private_key(hx509_cert p)
1603 return p->private_key ? 1 : 0;
1608 _hx509_cert_private_key_exportable(hx509_cert p)
1610 if (p->private_key == NULL)
1611 return 0;
1612 return _hx509_private_key_exportable(p->private_key);
1616 _hx509_cert_private_decrypt(hx509_context context,
1617 const heim_octet_string *ciphertext,
1618 const heim_oid *encryption_oid,
1619 hx509_cert p,
1620 heim_octet_string *cleartext)
1622 cleartext->data = NULL;
1623 cleartext->length = 0;
1625 if (p->private_key == NULL) {
1626 hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
1627 "Private key missing");
1628 return HX509_PRIVATE_KEY_MISSING;
1631 return hx509_private_key_private_decrypt(context,
1632 ciphertext,
1633 encryption_oid,
1634 p->private_key,
1635 cleartext);
1639 hx509_cert_public_encrypt(hx509_context context,
1640 const heim_octet_string *cleartext,
1641 const hx509_cert p,
1642 heim_oid *encryption_oid,
1643 heim_octet_string *ciphertext)
1645 return _hx509_public_encrypt(context,
1646 cleartext, p->data,
1647 encryption_oid, ciphertext);
1654 time_t
1655 _hx509_Time2time_t(const Time *t)
1657 switch(t->element) {
1658 case choice_Time_utcTime:
1659 return t->u.utcTime;
1660 case choice_Time_generalTime:
1661 return t->u.generalTime;
1663 return 0;
1670 static int
1671 init_name_constraints(hx509_name_constraints *nc)
1673 memset(nc, 0, sizeof(*nc));
1674 return 0;
1677 static int
1678 add_name_constraints(hx509_context context, const Certificate *c, int not_ca,
1679 hx509_name_constraints *nc)
1681 NameConstraints tnc;
1682 int ret;
1684 ret = find_extension_name_constraints(c, &tnc);
1685 if (ret == HX509_EXTENSION_NOT_FOUND)
1686 return 0;
1687 else if (ret) {
1688 hx509_set_error_string(context, 0, ret, "Failed getting NameConstraints");
1689 return ret;
1690 } else if (not_ca) {
1691 ret = HX509_VERIFY_CONSTRAINTS;
1692 hx509_set_error_string(context, 0, ret, "Not a CA and "
1693 "have NameConstraints");
1694 } else {
1695 NameConstraints *val;
1696 val = realloc(nc->val, sizeof(nc->val[0]) * (nc->len + 1));
1697 if (val == NULL) {
1698 hx509_clear_error_string(context);
1699 ret = ENOMEM;
1700 goto out;
1702 nc->val = val;
1703 ret = copy_NameConstraints(&tnc, &nc->val[nc->len]);
1704 if (ret) {
1705 hx509_clear_error_string(context);
1706 goto out;
1708 nc->len += 1;
1710 out:
1711 free_NameConstraints(&tnc);
1712 return ret;
1715 static int
1716 match_RDN(const RelativeDistinguishedName *c,
1717 const RelativeDistinguishedName *n)
1719 size_t i;
1721 if (c->len != n->len)
1722 return HX509_NAME_CONSTRAINT_ERROR;
1724 for (i = 0; i < n->len; i++) {
1725 int diff, ret;
1727 if (der_heim_oid_cmp(&c->val[i].type, &n->val[i].type) != 0)
1728 return HX509_NAME_CONSTRAINT_ERROR;
1729 ret = _hx509_name_ds_cmp(&c->val[i].value, &n->val[i].value, &diff);
1730 if (ret)
1731 return ret;
1732 if (diff != 0)
1733 return HX509_NAME_CONSTRAINT_ERROR;
1735 return 0;
1738 static int
1739 match_X501Name(const Name *c, const Name *n)
1741 size_t i;
1742 int ret;
1744 if (c->element != choice_Name_rdnSequence
1745 || n->element != choice_Name_rdnSequence)
1746 return 0;
1747 if (c->u.rdnSequence.len > n->u.rdnSequence.len)
1748 return HX509_NAME_CONSTRAINT_ERROR;
1749 for (i = 0; i < c->u.rdnSequence.len; i++) {
1750 ret = match_RDN(&c->u.rdnSequence.val[i], &n->u.rdnSequence.val[i]);
1751 if (ret)
1752 return ret;
1754 return 0;
1758 static int
1759 match_general_name(const GeneralName *c, const GeneralName *n, int *match)
1762 * Name constraints only apply to the same name type, see RFC3280,
1763 * 4.2.1.11.
1765 assert(c->element == n->element);
1767 switch(c->element) {
1768 case choice_GeneralName_otherName:
1769 if (der_heim_oid_cmp(&c->u.otherName.type_id,
1770 &n->u.otherName.type_id) != 0)
1771 return HX509_NAME_CONSTRAINT_ERROR;
1772 if (heim_any_cmp(&c->u.otherName.value,
1773 &n->u.otherName.value) != 0)
1774 return HX509_NAME_CONSTRAINT_ERROR;
1775 *match = 1;
1776 return 0;
1777 case choice_GeneralName_rfc822Name: {
1778 const char *s;
1779 size_t len1, len2;
1780 s = memchr(c->u.rfc822Name.data, '@', c->u.rfc822Name.length);
1781 if (s) {
1782 if (der_printable_string_cmp(&c->u.rfc822Name, &n->u.rfc822Name) != 0)
1783 return HX509_NAME_CONSTRAINT_ERROR;
1784 } else {
1785 s = memchr(n->u.rfc822Name.data, '@', n->u.rfc822Name.length);
1786 if (s == NULL)
1787 return HX509_NAME_CONSTRAINT_ERROR;
1788 len1 = c->u.rfc822Name.length;
1789 len2 = n->u.rfc822Name.length -
1790 (s - ((char *)n->u.rfc822Name.data));
1791 if (len1 > len2)
1792 return HX509_NAME_CONSTRAINT_ERROR;
1793 if (memcmp(s + 1 + len2 - len1, c->u.rfc822Name.data, len1) != 0)
1794 return HX509_NAME_CONSTRAINT_ERROR;
1795 if (len1 < len2 && s[len2 - len1 + 1] != '.')
1796 return HX509_NAME_CONSTRAINT_ERROR;
1798 *match = 1;
1799 return 0;
1801 case choice_GeneralName_dNSName: {
1802 size_t lenc, lenn;
1803 char *ptr;
1805 lenc = c->u.dNSName.length;
1806 lenn = n->u.dNSName.length;
1807 if (lenc > lenn)
1808 return HX509_NAME_CONSTRAINT_ERROR;
1809 ptr = n->u.dNSName.data;
1810 if (memcmp(&ptr[lenn - lenc], c->u.dNSName.data, lenc) != 0)
1811 return HX509_NAME_CONSTRAINT_ERROR;
1812 if (lenn != lenc && ptr[lenn - lenc - 1] != '.')
1813 return HX509_NAME_CONSTRAINT_ERROR;
1814 *match = 1;
1815 return 0;
1817 case choice_GeneralName_directoryName: {
1818 Name c_name, n_name;
1819 int ret;
1821 c_name._save.data = NULL;
1822 c_name._save.length = 0;
1823 c_name.element = (enum Name_enum)c->u.directoryName.element;
1824 c_name.u.rdnSequence = c->u.directoryName.u.rdnSequence;
1826 n_name._save.data = NULL;
1827 n_name._save.length = 0;
1828 n_name.element = (enum Name_enum)n->u.directoryName.element;
1829 n_name.u.rdnSequence = n->u.directoryName.u.rdnSequence;
1831 ret = match_X501Name(&c_name, &n_name);
1832 if (ret == 0)
1833 *match = 1;
1834 return ret;
1836 case choice_GeneralName_uniformResourceIdentifier:
1837 case choice_GeneralName_iPAddress:
1838 case choice_GeneralName_registeredID:
1839 default:
1840 return HX509_NAME_CONSTRAINT_ERROR;
1844 static int
1845 match_alt_name(const GeneralName *n, const Certificate *c,
1846 int *same, int *match)
1848 GeneralNames sa;
1849 int ret;
1850 size_t i, j;
1852 i = 0;
1853 do {
1854 ret = find_extension_subject_alt_name(c, &i, &sa);
1855 if (ret == HX509_EXTENSION_NOT_FOUND) {
1856 ret = 0;
1857 break;
1858 } else if (ret != 0)
1859 break;
1861 for (j = 0; j < sa.len; j++) {
1862 if (n->element == sa.val[j].element) {
1863 *same = 1;
1864 ret = match_general_name(n, &sa.val[j], match);
1867 free_GeneralNames(&sa);
1868 } while (1);
1869 return ret;
1873 static int
1874 match_tree(const GeneralSubtrees *t, const Certificate *c, int *match)
1876 int name, alt_name, same;
1877 unsigned int i;
1878 int ret = 0;
1880 name = alt_name = same = *match = 0;
1881 for (i = 0; i < t->len; i++) {
1882 if (t->val[i].minimum && t->val[i].maximum)
1883 return HX509_RANGE;
1886 * If the constraint apply to directoryNames, test is with
1887 * subjectName of the certificate if the certificate have a
1888 * non-null (empty) subjectName.
1891 if (t->val[i].base.element == choice_GeneralName_directoryName
1892 && !subject_null_p(c))
1894 GeneralName certname;
1896 memset(&certname, 0, sizeof(certname));
1897 certname.element = choice_GeneralName_directoryName;
1898 certname.u.directoryName.element = (enum GeneralName_directoryName_enum)
1899 c->tbsCertificate.subject.element;
1900 certname.u.directoryName.u.rdnSequence =
1901 c->tbsCertificate.subject.u.rdnSequence;
1903 ret = match_general_name(&t->val[i].base, &certname, &name);
1906 /* Handle subjectAltNames, this is icky since they
1907 * restrictions only apply if the subjectAltName is of the
1908 * same type. So if there have been a match of type, require
1909 * altname to be set.
1911 ret = match_alt_name(&t->val[i].base, c, &same, &alt_name);
1913 if (name && (!same || alt_name))
1914 *match = 1;
1915 return ret;
1918 static int
1919 check_name_constraints(hx509_context context,
1920 const hx509_name_constraints *nc,
1921 const Certificate *c)
1923 int match, ret;
1924 size_t i;
1926 for (i = 0 ; i < nc->len; i++) {
1927 GeneralSubtrees gs;
1929 if (nc->val[i].permittedSubtrees) {
1930 GeneralSubtrees_SET(&gs, nc->val[i].permittedSubtrees);
1931 ret = match_tree(&gs, c, &match);
1932 if (ret) {
1933 hx509_clear_error_string(context);
1934 return ret;
1936 /* allow null subjectNames, they wont matches anything */
1937 if (match == 0 && !subject_null_p(c)) {
1938 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1939 "Error verify constraints, "
1940 "certificate didn't match any "
1941 "permitted subtree");
1942 return HX509_VERIFY_CONSTRAINTS;
1945 if (nc->val[i].excludedSubtrees) {
1946 GeneralSubtrees_SET(&gs, nc->val[i].excludedSubtrees);
1947 ret = match_tree(&gs, c, &match);
1948 if (ret) {
1949 hx509_clear_error_string(context);
1950 return ret;
1952 if (match) {
1953 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1954 "Error verify constraints, "
1955 "certificate included in excluded "
1956 "subtree");
1957 return HX509_VERIFY_CONSTRAINTS;
1961 return 0;
1964 static void
1965 free_name_constraints(hx509_name_constraints *nc)
1967 size_t i;
1969 for (i = 0 ; i < nc->len; i++)
1970 free_NameConstraints(&nc->val[i]);
1971 free(nc->val);
1975 * Build and verify the path for the certificate to the trust anchor
1976 * specified in the verify context. The path is constructed from the
1977 * certificate, the pool and the trust anchors.
1979 * @param context A hx509 context.
1980 * @param ctx A hx509 verification context.
1981 * @param cert the certificate to build the path from.
1982 * @param pool A keyset of certificates to build the chain from.
1984 * @return An hx509 error code, see hx509_get_error_string().
1986 * @ingroup hx509_verify
1990 hx509_verify_path(hx509_context context,
1991 hx509_verify_ctx ctx,
1992 hx509_cert cert,
1993 hx509_certs pool)
1995 hx509_name_constraints nc;
1996 hx509_path path;
1997 int ret, proxy_cert_depth, selfsigned_depth, diff;
1998 size_t i, k;
1999 enum certtype type;
2000 Name proxy_issuer;
2001 hx509_certs anchors = NULL;
2003 memset(&proxy_issuer, 0, sizeof(proxy_issuer));
2005 if ((ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE) == 0 &&
2006 is_proxy_cert(context, cert->data, NULL) == 0)
2008 ret = HX509_PROXY_CERT_INVALID;
2009 hx509_set_error_string(context, 0, ret,
2010 "Proxy certificate is not allowed as an EE "
2011 "certificae if proxy certificate is disabled");
2012 return ret;
2015 ret = init_name_constraints(&nc);
2016 if (ret)
2017 return ret;
2019 path.val = NULL;
2020 path.len = 0;
2022 if ((ctx->flags & HX509_VERIFY_CTX_F_TIME_SET) == 0)
2023 ctx->time_now = time(NULL);
2028 if (ctx->trust_anchors)
2029 anchors = hx509_certs_ref(ctx->trust_anchors);
2030 else if (context->default_trust_anchors && ALLOW_DEF_TA(ctx))
2031 anchors = hx509_certs_ref(context->default_trust_anchors);
2032 else {
2033 ret = hx509_certs_init(context, "MEMORY:no-TA", 0, NULL, &anchors);
2034 if (ret)
2035 goto out;
2039 * Calculate the path from the certificate user presented to the
2040 * to an anchor.
2042 ret = _hx509_calculate_path(context, 0, ctx->time_now,
2043 anchors, ctx->max_depth,
2044 cert, pool, &path);
2045 if (ret)
2046 goto out;
2049 * Check CA and proxy certificate chain from the top of the
2050 * certificate chain. Also check certificate is valid with respect
2051 * to the current time.
2055 proxy_cert_depth = 0;
2056 selfsigned_depth = 0;
2058 if (ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE)
2059 type = PROXY_CERT;
2060 else
2061 type = EE_CERT;
2063 for (i = 0; i < path.len; i++) {
2064 Certificate *c;
2065 time_t t;
2067 c = _hx509_get_cert(path.val[i]);
2070 * Lets do some basic check on issuer like
2071 * keyUsage.keyCertSign and basicConstraints.cA bit depending
2072 * on what type of certificate this is.
2075 switch (type) {
2076 case CA_CERT:
2078 /* XXX make constants for keyusage */
2079 ret = check_key_usage(context, c, 1 << 5,
2080 REQUIRE_RFC3280(ctx) ? TRUE : FALSE);
2081 if (ret) {
2082 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
2083 "Key usage missing from CA certificate");
2084 goto out;
2087 /* self signed cert doesn't add to path length */
2088 if (i + 1 != path.len) {
2089 int selfsigned;
2091 ret = certificate_is_self_signed(context, c, &selfsigned);
2092 if (ret)
2093 goto out;
2094 if (selfsigned)
2095 selfsigned_depth++;
2098 break;
2099 case PROXY_CERT: {
2100 ProxyCertInfo info;
2102 if (is_proxy_cert(context, c, &info) == 0) {
2103 size_t j;
2105 if (info.pCPathLenConstraint != NULL &&
2106 *info.pCPathLenConstraint < i)
2108 free_ProxyCertInfo(&info);
2109 ret = HX509_PATH_TOO_LONG;
2110 hx509_set_error_string(context, 0, ret,
2111 "Proxy certificate chain "
2112 "longer then allowed");
2113 goto out;
2115 /* XXX MUST check info.proxyPolicy */
2116 free_ProxyCertInfo(&info);
2118 j = 0;
2119 if (find_extension(c, &asn1_oid_id_x509_ce_subjectAltName, &j)) {
2120 ret = HX509_PROXY_CERT_INVALID;
2121 hx509_set_error_string(context, 0, ret,
2122 "Proxy certificate have explicity "
2123 "forbidden subjectAltName");
2124 goto out;
2127 j = 0;
2128 if (find_extension(c, &asn1_oid_id_x509_ce_issuerAltName, &j)) {
2129 ret = HX509_PROXY_CERT_INVALID;
2130 hx509_set_error_string(context, 0, ret,
2131 "Proxy certificate have explicity "
2132 "forbidden issuerAltName");
2133 goto out;
2137 * The subject name of the proxy certificate should be
2138 * CN=XXX,<proxy issuer>, prune of CN and check if its
2139 * the same over the whole chain of proxy certs and
2140 * then check with the EE cert when we get to it.
2143 if (proxy_cert_depth) {
2144 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.subject, &diff);
2145 if (ret) {
2146 hx509_set_error_string(context, 0, ret, "Out of memory");
2147 goto out;
2149 if (diff) {
2150 ret = HX509_PROXY_CERT_NAME_WRONG;
2151 hx509_set_error_string(context, 0, ret,
2152 "Base proxy name not right");
2153 goto out;
2157 free_Name(&proxy_issuer);
2159 ret = copy_Name(&c->tbsCertificate.subject, &proxy_issuer);
2160 if (ret) {
2161 hx509_clear_error_string(context);
2162 goto out;
2165 j = proxy_issuer.u.rdnSequence.len;
2166 if (proxy_issuer.u.rdnSequence.len < 2
2167 || proxy_issuer.u.rdnSequence.val[j - 1].len > 1
2168 || der_heim_oid_cmp(&proxy_issuer.u.rdnSequence.val[j - 1].val[0].type,
2169 &asn1_oid_id_at_commonName))
2171 ret = HX509_PROXY_CERT_NAME_WRONG;
2172 hx509_set_error_string(context, 0, ret,
2173 "Proxy name too short or "
2174 "does not have Common name "
2175 "at the top");
2176 goto out;
2179 free_RelativeDistinguishedName(&proxy_issuer.u.rdnSequence.val[j - 1]);
2180 proxy_issuer.u.rdnSequence.len -= 1;
2182 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.issuer, &diff);
2183 if (ret) {
2184 hx509_set_error_string(context, 0, ret, "Out of memory");
2185 goto out;
2187 if (diff != 0) {
2188 ret = HX509_PROXY_CERT_NAME_WRONG;
2189 hx509_set_error_string(context, 0, ret,
2190 "Proxy issuer name not as expected");
2191 goto out;
2194 break;
2195 } else {
2197 * Now we are done with the proxy certificates, this
2198 * cert was an EE cert and we we will fall though to
2199 * EE checking below.
2201 type = EE_CERT;
2202 /* FALLTHOUGH */
2205 case EE_CERT:
2207 * If there where any proxy certificates in the chain
2208 * (proxy_cert_depth > 0), check that the proxy issuer
2209 * matched proxy certificates "base" subject.
2211 if (proxy_cert_depth) {
2213 ret = _hx509_name_cmp(&proxy_issuer,
2214 &c->tbsCertificate.subject, &diff);
2215 if (ret) {
2216 hx509_set_error_string(context, 0, ret, "out of memory");
2217 goto out;
2219 if (diff) {
2220 ret = HX509_PROXY_CERT_NAME_WRONG;
2221 hx509_clear_error_string(context);
2222 goto out;
2224 if (cert->basename)
2225 hx509_name_free(&cert->basename);
2227 ret = _hx509_name_from_Name(&proxy_issuer, &cert->basename);
2228 if (ret) {
2229 hx509_clear_error_string(context);
2230 goto out;
2234 break;
2237 ret = check_basic_constraints(context, c, type,
2238 i - proxy_cert_depth - selfsigned_depth);
2239 if (ret)
2240 goto out;
2243 * Don't check the trust anchors expiration time since they
2244 * are transported out of band, from RFC3820.
2246 if (i + 1 != path.len || CHECK_TA(ctx)) {
2248 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2249 if (t > ctx->time_now) {
2250 ret = HX509_CERT_USED_BEFORE_TIME;
2251 hx509_clear_error_string(context);
2252 goto out;
2254 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2255 if (t < ctx->time_now) {
2256 ret = HX509_CERT_USED_AFTER_TIME;
2257 hx509_clear_error_string(context);
2258 goto out;
2262 if (type == EE_CERT)
2263 type = CA_CERT;
2264 else if (type == PROXY_CERT)
2265 proxy_cert_depth++;
2269 * Verify constraints, do this backward so path constraints are
2270 * checked in the right order.
2273 for (ret = 0, k = path.len; k > 0; k--) {
2274 Certificate *c;
2275 int selfsigned;
2276 i = k - 1;
2278 c = _hx509_get_cert(path.val[i]);
2280 ret = certificate_is_self_signed(context, c, &selfsigned);
2281 if (ret)
2282 goto out;
2284 /* verify name constraints, not for selfsigned and anchor */
2285 if (!selfsigned || i + 1 != path.len) {
2286 ret = check_name_constraints(context, &nc, c);
2287 if (ret) {
2288 goto out;
2291 ret = add_name_constraints(context, c, i == 0, &nc);
2292 if (ret)
2293 goto out;
2295 /* XXX verify all other silly constraints */
2300 * Verify that no certificates has been revoked.
2303 if (ctx->revoke_ctx) {
2304 hx509_certs certs;
2306 ret = hx509_certs_init(context, "MEMORY:revoke-certs", 0,
2307 NULL, &certs);
2308 if (ret)
2309 goto out;
2311 for (i = 0; i < path.len; i++) {
2312 ret = hx509_certs_add(context, certs, path.val[i]);
2313 if (ret) {
2314 hx509_certs_free(&certs);
2315 goto out;
2318 ret = hx509_certs_merge(context, certs, pool);
2319 if (ret) {
2320 hx509_certs_free(&certs);
2321 goto out;
2324 for (i = 0; i < path.len - 1; i++) {
2325 size_t parent = (i < path.len - 1) ? i + 1 : i;
2327 ret = hx509_revoke_verify(context,
2328 ctx->revoke_ctx,
2329 certs,
2330 ctx->time_now,
2331 path.val[i],
2332 path.val[parent]);
2333 if (ret) {
2334 hx509_certs_free(&certs);
2335 goto out;
2338 hx509_certs_free(&certs);
2342 * Verify signatures, do this backward so public key working
2343 * parameter is passed up from the anchor up though the chain.
2346 for (k = path.len; k > 0; k--) {
2347 hx509_cert signer;
2348 Certificate *c;
2349 i = k - 1;
2351 c = _hx509_get_cert(path.val[i]);
2353 /* is last in chain (trust anchor) */
2354 if (i + 1 == path.len) {
2355 int selfsigned;
2357 signer = path.val[i];
2359 ret = certificate_is_self_signed(context, signer->data, &selfsigned);
2360 if (ret)
2361 goto out;
2363 /* if trust anchor is not self signed, don't check sig */
2364 if (!selfsigned)
2365 continue;
2366 } else {
2367 /* take next certificate in chain */
2368 signer = path.val[i + 1];
2371 /* verify signatureValue */
2372 ret = _hx509_verify_signature_bitstring(context,
2373 signer,
2374 &c->signatureAlgorithm,
2375 &c->tbsCertificate._save,
2376 &c->signatureValue);
2377 if (ret) {
2378 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
2379 "Failed to verify signature of certificate");
2380 goto out;
2383 * Verify that the sigature algorithm is not weak. Ignore
2384 * trust anchors since they are provisioned by the user.
2387 if (i + 1 != path.len && (ctx->flags & HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK) == 0) {
2388 ret = _hx509_signature_is_weak(context, &c->signatureAlgorithm);
2389 if (ret)
2390 goto out;
2394 out:
2395 hx509_certs_free(&anchors);
2396 free_Name(&proxy_issuer);
2397 free_name_constraints(&nc);
2398 _hx509_path_free(&path);
2400 return ret;
2404 * Verify a signature made using the private key of an certificate.
2406 * @param context A hx509 context.
2407 * @param signer the certificate that made the signature.
2408 * @param alg algorthm that was used to sign the data.
2409 * @param data the data that was signed.
2410 * @param sig the sigature to verify.
2412 * @return An hx509 error code, see hx509_get_error_string().
2414 * @ingroup hx509_crypto
2418 hx509_verify_signature(hx509_context context,
2419 const hx509_cert signer,
2420 const AlgorithmIdentifier *alg,
2421 const heim_octet_string *data,
2422 const heim_octet_string *sig)
2424 return _hx509_verify_signature(context, signer, alg, data, sig);
2428 _hx509_verify_signature_bitstring(hx509_context context,
2429 const hx509_cert signer,
2430 const AlgorithmIdentifier *alg,
2431 const heim_octet_string *data,
2432 const heim_bit_string *sig)
2434 heim_octet_string os;
2436 if (sig->length & 7) {
2437 hx509_set_error_string(context, 0, HX509_CRYPTO_SIG_INVALID_FORMAT,
2438 "signature not multiple of 8 bits");
2439 return HX509_CRYPTO_SIG_INVALID_FORMAT;
2442 os.data = sig->data;
2443 os.length = sig->length / 8;
2445 return _hx509_verify_signature(context, signer, alg, data, &os);
2451 * Verify that the certificate is allowed to be used for the hostname
2452 * and address.
2454 * @param context A hx509 context.
2455 * @param cert the certificate to match with
2456 * @param flags Flags to modify the behavior:
2457 * - HX509_VHN_F_ALLOW_NO_MATCH no match is ok
2458 * @param type type of hostname:
2459 * - HX509_HN_HOSTNAME for plain hostname.
2460 * - HX509_HN_DNSSRV for DNS SRV names.
2461 * @param hostname the hostname to check
2462 * @param sa address of the host
2463 * @param sa_size length of address
2465 * @return An hx509 error code, see hx509_get_error_string().
2467 * @ingroup hx509_cert
2471 hx509_verify_hostname(hx509_context context,
2472 const hx509_cert cert,
2473 int flags,
2474 hx509_hostname_type type,
2475 const char *hostname,
2476 const struct sockaddr *sa,
2477 /* XXX krb5_socklen_t */ int sa_size)
2479 GeneralNames san;
2480 const Name *name;
2481 int ret;
2482 size_t i, j, k;
2484 if (sa && sa_size <= 0)
2485 return EINVAL;
2487 memset(&san, 0, sizeof(san));
2489 i = 0;
2490 do {
2491 ret = find_extension_subject_alt_name(cert->data, &i, &san);
2492 if (ret == HX509_EXTENSION_NOT_FOUND)
2493 break;
2494 else if (ret != 0)
2495 return HX509_PARSING_NAME_FAILED;
2497 for (j = 0; j < san.len; j++) {
2498 switch (san.val[j].element) {
2499 case choice_GeneralName_dNSName: {
2500 heim_printable_string hn;
2501 hn.data = rk_UNCONST(hostname);
2502 hn.length = strlen(hostname);
2504 if (der_printable_string_cmp(&san.val[j].u.dNSName, &hn) == 0) {
2505 free_GeneralNames(&san);
2506 return 0;
2508 break;
2510 default:
2511 break;
2514 free_GeneralNames(&san);
2515 } while (1);
2517 name = &cert->data->tbsCertificate.subject;
2519 /* Find first CN= in the name, and try to match the hostname on that */
2520 for (ret = 0, k = name->u.rdnSequence.len; ret == 0 && k > 0; k--) {
2521 i = k - 1;
2522 for (j = 0; ret == 0 && j < name->u.rdnSequence.val[i].len; j++) {
2523 AttributeTypeAndValue *n = &name->u.rdnSequence.val[i].val[j];
2525 if (der_heim_oid_cmp(&n->type, &asn1_oid_id_at_commonName) == 0) {
2526 DirectoryString *ds = &n->value;
2527 switch (ds->element) {
2528 case choice_DirectoryString_printableString: {
2529 heim_printable_string hn;
2530 hn.data = rk_UNCONST(hostname);
2531 hn.length = strlen(hostname);
2533 if (der_printable_string_cmp(&ds->u.printableString, &hn) == 0)
2534 return 0;
2535 break;
2537 case choice_DirectoryString_ia5String: {
2538 heim_ia5_string hn;
2539 hn.data = rk_UNCONST(hostname);
2540 hn.length = strlen(hostname);
2542 if (der_ia5_string_cmp(&ds->u.ia5String, &hn) == 0)
2543 return 0;
2544 break;
2546 case choice_DirectoryString_utf8String:
2547 if (strcasecmp(ds->u.utf8String, hostname) == 0)
2548 return 0;
2549 default:
2550 break;
2552 ret = HX509_NAME_CONSTRAINT_ERROR;
2557 if ((flags & HX509_VHN_F_ALLOW_NO_MATCH) == 0)
2558 ret = HX509_NAME_CONSTRAINT_ERROR;
2560 return ret;
2564 _hx509_set_cert_attribute(hx509_context context,
2565 hx509_cert cert,
2566 const heim_oid *oid,
2567 const heim_octet_string *attr)
2569 hx509_cert_attribute a;
2570 void *d;
2572 if (hx509_cert_get_attribute(cert, oid) != NULL)
2573 return 0;
2575 d = realloc(cert->attrs.val,
2576 sizeof(cert->attrs.val[0]) * (cert->attrs.len + 1));
2577 if (d == NULL) {
2578 hx509_clear_error_string(context);
2579 return ENOMEM;
2581 cert->attrs.val = d;
2583 a = malloc(sizeof(*a));
2584 if (a == NULL)
2585 return ENOMEM;
2587 der_copy_octet_string(attr, &a->data);
2588 der_copy_oid(oid, &a->oid);
2590 cert->attrs.val[cert->attrs.len] = a;
2591 cert->attrs.len++;
2593 return 0;
2597 * Get an external attribute for the certificate, examples are
2598 * friendly name and id.
2600 * @param cert hx509 certificate object to search
2601 * @param oid an oid to search for.
2603 * @return an hx509_cert_attribute, only valid as long as the
2604 * certificate is referenced.
2606 * @ingroup hx509_cert
2609 hx509_cert_attribute
2610 hx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid)
2612 size_t i;
2613 for (i = 0; i < cert->attrs.len; i++)
2614 if (der_heim_oid_cmp(oid, &cert->attrs.val[i]->oid) == 0)
2615 return cert->attrs.val[i];
2616 return NULL;
2620 * Set the friendly name on the certificate.
2622 * @param cert The certificate to set the friendly name on
2623 * @param name Friendly name.
2625 * @return An hx509 error code, see hx509_get_error_string().
2627 * @ingroup hx509_cert
2631 hx509_cert_set_friendly_name(hx509_cert cert, const char *name)
2633 if (cert->friendlyname)
2634 free(cert->friendlyname);
2635 cert->friendlyname = strdup(name);
2636 if (cert->friendlyname == NULL)
2637 return ENOMEM;
2638 return 0;
2642 * Get friendly name of the certificate.
2644 * @param cert cert to get the friendly name from.
2646 * @return an friendly name or NULL if there is. The friendly name is
2647 * only valid as long as the certificate is referenced.
2649 * @ingroup hx509_cert
2652 const char *
2653 hx509_cert_get_friendly_name(hx509_cert cert)
2655 hx509_cert_attribute a;
2656 PKCS9_friendlyName n;
2657 size_t sz;
2658 int ret;
2659 size_t i;
2661 if (cert->friendlyname)
2662 return cert->friendlyname;
2664 a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_friendlyName);
2665 if (a == NULL) {
2666 hx509_name name;
2668 ret = hx509_cert_get_subject(cert, &name);
2669 if (ret)
2670 return NULL;
2671 ret = hx509_name_to_string(name, &cert->friendlyname);
2672 hx509_name_free(&name);
2673 if (ret)
2674 return NULL;
2675 return cert->friendlyname;
2678 ret = decode_PKCS9_friendlyName(a->data.data, a->data.length, &n, &sz);
2679 if (ret)
2680 return NULL;
2682 if (n.len != 1) {
2683 free_PKCS9_friendlyName(&n);
2684 return NULL;
2687 cert->friendlyname = malloc(n.val[0].length + 1);
2688 if (cert->friendlyname == NULL) {
2689 free_PKCS9_friendlyName(&n);
2690 return NULL;
2693 for (i = 0; i < n.val[0].length; i++) {
2694 if (n.val[0].data[i] <= 0xff)
2695 cert->friendlyname[i] = n.val[0].data[i] & 0xff;
2696 else
2697 cert->friendlyname[i] = 'X';
2699 cert->friendlyname[i] = '\0';
2700 free_PKCS9_friendlyName(&n);
2702 return cert->friendlyname;
2705 void
2706 _hx509_query_clear(hx509_query *q)
2708 memset(q, 0, sizeof(*q));
2712 * Allocate an query controller. Free using hx509_query_free().
2714 * @param context A hx509 context.
2715 * @param q return pointer to a hx509_query.
2717 * @return An hx509 error code, see hx509_get_error_string().
2719 * @ingroup hx509_cert
2723 hx509_query_alloc(hx509_context context, hx509_query **q)
2725 *q = calloc(1, sizeof(**q));
2726 if (*q == NULL)
2727 return ENOMEM;
2728 return 0;
2733 * Set match options for the hx509 query controller.
2735 * @param q query controller.
2736 * @param option options to control the query controller.
2738 * @return An hx509 error code, see hx509_get_error_string().
2740 * @ingroup hx509_cert
2743 void
2744 hx509_query_match_option(hx509_query *q, hx509_query_option option)
2746 switch(option) {
2747 case HX509_QUERY_OPTION_PRIVATE_KEY:
2748 q->match |= HX509_QUERY_PRIVATE_KEY;
2749 break;
2750 case HX509_QUERY_OPTION_KU_ENCIPHERMENT:
2751 q->match |= HX509_QUERY_KU_ENCIPHERMENT;
2752 break;
2753 case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE:
2754 q->match |= HX509_QUERY_KU_DIGITALSIGNATURE;
2755 break;
2756 case HX509_QUERY_OPTION_KU_KEYCERTSIGN:
2757 q->match |= HX509_QUERY_KU_KEYCERTSIGN;
2758 break;
2759 case HX509_QUERY_OPTION_END:
2760 default:
2761 break;
2766 * Set the issuer and serial number of match in the query
2767 * controller. The function make copies of the isser and serial number.
2769 * @param q a hx509 query controller
2770 * @param issuer issuer to search for
2771 * @param serialNumber the serialNumber of the issuer.
2773 * @return An hx509 error code, see hx509_get_error_string().
2775 * @ingroup hx509_cert
2779 hx509_query_match_issuer_serial(hx509_query *q,
2780 const Name *issuer,
2781 const heim_integer *serialNumber)
2783 int ret;
2784 if (q->serial) {
2785 der_free_heim_integer(q->serial);
2786 free(q->serial);
2788 q->serial = malloc(sizeof(*q->serial));
2789 if (q->serial == NULL)
2790 return ENOMEM;
2791 ret = der_copy_heim_integer(serialNumber, q->serial);
2792 if (ret) {
2793 free(q->serial);
2794 q->serial = NULL;
2795 return ret;
2797 if (q->issuer_name) {
2798 free_Name(q->issuer_name);
2799 free(q->issuer_name);
2801 q->issuer_name = malloc(sizeof(*q->issuer_name));
2802 if (q->issuer_name == NULL)
2803 return ENOMEM;
2804 ret = copy_Name(issuer, q->issuer_name);
2805 if (ret) {
2806 free(q->issuer_name);
2807 q->issuer_name = NULL;
2808 return ret;
2810 q->match |= HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
2811 return 0;
2815 * Set the query controller to match on a friendly name
2817 * @param q a hx509 query controller.
2818 * @param name a friendly name to match on
2820 * @return An hx509 error code, see hx509_get_error_string().
2822 * @ingroup hx509_cert
2826 hx509_query_match_friendly_name(hx509_query *q, const char *name)
2828 if (q->friendlyname)
2829 free(q->friendlyname);
2830 q->friendlyname = strdup(name);
2831 if (q->friendlyname == NULL)
2832 return ENOMEM;
2833 q->match |= HX509_QUERY_MATCH_FRIENDLY_NAME;
2834 return 0;
2838 * Set the query controller to require an one specific EKU (extended
2839 * key usage). Any previous EKU matching is overwitten. If NULL is
2840 * passed in as the eku, the EKU requirement is reset.
2842 * @param q a hx509 query controller.
2843 * @param eku an EKU to match on.
2845 * @return An hx509 error code, see hx509_get_error_string().
2847 * @ingroup hx509_cert
2851 hx509_query_match_eku(hx509_query *q, const heim_oid *eku)
2853 int ret;
2855 if (eku == NULL) {
2856 if (q->eku) {
2857 der_free_oid(q->eku);
2858 free(q->eku);
2859 q->eku = NULL;
2861 q->match &= ~HX509_QUERY_MATCH_EKU;
2862 } else {
2863 if (q->eku) {
2864 der_free_oid(q->eku);
2865 } else {
2866 q->eku = calloc(1, sizeof(*q->eku));
2867 if (q->eku == NULL)
2868 return ENOMEM;
2870 ret = der_copy_oid(eku, q->eku);
2871 if (ret) {
2872 free(q->eku);
2873 q->eku = NULL;
2874 return ret;
2876 q->match |= HX509_QUERY_MATCH_EKU;
2878 return 0;
2882 hx509_query_match_expr(hx509_context context, hx509_query *q, const char *expr)
2884 if (q->expr) {
2885 _hx509_expr_free(q->expr);
2886 q->expr = NULL;
2889 if (expr == NULL) {
2890 q->match &= ~HX509_QUERY_MATCH_EXPR;
2891 } else {
2892 q->expr = _hx509_expr_parse(expr);
2893 if (q->expr)
2894 q->match |= HX509_QUERY_MATCH_EXPR;
2897 return 0;
2901 * Set the query controller to match using a specific match function.
2903 * @param q a hx509 query controller.
2904 * @param func function to use for matching, if the argument is NULL,
2905 * the match function is removed.
2906 * @param ctx context passed to the function.
2908 * @return An hx509 error code, see hx509_get_error_string().
2910 * @ingroup hx509_cert
2914 hx509_query_match_cmp_func(hx509_query *q,
2915 int (*func)(hx509_context, hx509_cert, void *),
2916 void *ctx)
2918 if (func)
2919 q->match |= HX509_QUERY_MATCH_FUNCTION;
2920 else
2921 q->match &= ~HX509_QUERY_MATCH_FUNCTION;
2922 q->cmp_func = func;
2923 q->cmp_func_ctx = ctx;
2924 return 0;
2928 * Free the query controller.
2930 * @param context A hx509 context.
2931 * @param q a pointer to the query controller.
2933 * @ingroup hx509_cert
2936 void
2937 hx509_query_free(hx509_context context, hx509_query *q)
2939 if (q == NULL)
2940 return;
2942 if (q->serial) {
2943 der_free_heim_integer(q->serial);
2944 free(q->serial);
2946 if (q->issuer_name) {
2947 free_Name(q->issuer_name);
2948 free(q->issuer_name);
2950 if (q->eku) {
2951 der_free_oid(q->eku);
2952 free(q->eku);
2954 if (q->friendlyname)
2955 free(q->friendlyname);
2956 if (q->expr)
2957 _hx509_expr_free(q->expr);
2959 memset(q, 0, sizeof(*q));
2960 free(q);
2964 _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert cert)
2966 Certificate *c = _hx509_get_cert(cert);
2967 int ret, diff;
2969 _hx509_query_statistic(context, 1, q);
2971 if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) &&
2972 _hx509_cert_is_parent_cmp(q->subject, c, 0) != 0)
2973 return 0;
2975 if ((q->match & HX509_QUERY_MATCH_CERTIFICATE) &&
2976 _hx509_Certificate_cmp(q->certificate, c) != 0)
2977 return 0;
2979 if ((q->match & HX509_QUERY_MATCH_SERIALNUMBER)
2980 && der_heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0)
2981 return 0;
2983 if (q->match & HX509_QUERY_MATCH_ISSUER_NAME) {
2984 ret = _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name, &diff);
2985 if (ret || diff)
2986 return 0;
2989 if (q->match & HX509_QUERY_MATCH_SUBJECT_NAME) {
2990 ret = _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name, &diff);
2991 if (ret || diff)
2992 return 0;
2995 if (q->match & HX509_QUERY_MATCH_SUBJECT_KEY_ID) {
2996 SubjectKeyIdentifier si;
2998 ret = _hx509_find_extension_subject_key_id(c, &si);
2999 if (ret == 0) {
3000 if (der_heim_octet_string_cmp(&si, q->subject_id) != 0)
3001 ret = 1;
3002 free_SubjectKeyIdentifier(&si);
3004 if (ret)
3005 return 0;
3007 if ((q->match & HX509_QUERY_MATCH_ISSUER_ID))
3008 return 0;
3009 if ((q->match & HX509_QUERY_PRIVATE_KEY) &&
3010 _hx509_cert_private_key(cert) == NULL)
3011 return 0;
3014 unsigned ku = 0;
3015 if (q->match & HX509_QUERY_KU_DIGITALSIGNATURE)
3016 ku |= (1 << 0);
3017 if (q->match & HX509_QUERY_KU_NONREPUDIATION)
3018 ku |= (1 << 1);
3019 if (q->match & HX509_QUERY_KU_ENCIPHERMENT)
3020 ku |= (1 << 2);
3021 if (q->match & HX509_QUERY_KU_DATAENCIPHERMENT)
3022 ku |= (1 << 3);
3023 if (q->match & HX509_QUERY_KU_KEYAGREEMENT)
3024 ku |= (1 << 4);
3025 if (q->match & HX509_QUERY_KU_KEYCERTSIGN)
3026 ku |= (1 << 5);
3027 if (q->match & HX509_QUERY_KU_CRLSIGN)
3028 ku |= (1 << 6);
3029 if (ku && check_key_usage(context, c, ku, TRUE))
3030 return 0;
3032 if ((q->match & HX509_QUERY_ANCHOR))
3033 return 0;
3035 if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) {
3036 hx509_cert_attribute a;
3038 a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_localKeyId);
3039 if (a == NULL)
3040 return 0;
3041 if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0)
3042 return 0;
3045 if (q->match & HX509_QUERY_NO_MATCH_PATH) {
3046 size_t i;
3048 for (i = 0; i < q->path->len; i++)
3049 if (hx509_cert_cmp(q->path->val[i], cert) == 0)
3050 return 0;
3052 if (q->match & HX509_QUERY_MATCH_FRIENDLY_NAME) {
3053 const char *name = hx509_cert_get_friendly_name(cert);
3054 if (name == NULL)
3055 return 0;
3056 if (strcasecmp(q->friendlyname, name) != 0)
3057 return 0;
3059 if (q->match & HX509_QUERY_MATCH_FUNCTION) {
3060 ret = (*q->cmp_func)(context, cert, q->cmp_func_ctx);
3061 if (ret != 0)
3062 return 0;
3065 if (q->match & HX509_QUERY_MATCH_KEY_HASH_SHA1) {
3066 heim_octet_string os;
3068 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
3069 os.length =
3070 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
3072 ret = _hx509_verify_signature(context,
3073 NULL,
3074 hx509_signature_sha1(),
3075 &os,
3076 q->keyhash_sha1);
3077 if (ret != 0)
3078 return 0;
3081 if (q->match & HX509_QUERY_MATCH_TIME) {
3082 time_t t;
3083 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
3084 if (t > q->timenow)
3085 return 0;
3086 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
3087 if (t < q->timenow)
3088 return 0;
3091 /* If an EKU is required, check the cert for it. */
3092 if ((q->match & HX509_QUERY_MATCH_EKU) &&
3093 hx509_cert_check_eku(context, cert, q->eku, 0))
3094 return 0;
3096 if ((q->match & HX509_QUERY_MATCH_EXPR)) {
3097 hx509_env env = NULL;
3099 ret = _hx509_cert_to_env(context, cert, &env);
3100 if (ret)
3101 return 0;
3103 ret = _hx509_expr_eval(context, env, q->expr);
3104 hx509_env_free(&env);
3105 if (ret == 0)
3106 return 0;
3109 if (q->match & ~HX509_QUERY_MASK)
3110 return 0;
3112 return 1;
3116 * Set a statistic file for the query statistics.
3118 * @param context A hx509 context.
3119 * @param fn statistics file name
3121 * @ingroup hx509_cert
3124 void
3125 hx509_query_statistic_file(hx509_context context, const char *fn)
3127 if (context->querystat)
3128 free(context->querystat);
3129 context->querystat = strdup(fn);
3132 void
3133 _hx509_query_statistic(hx509_context context, int type, const hx509_query *q)
3135 FILE *f;
3136 if (context->querystat == NULL)
3137 return;
3138 f = fopen(context->querystat, "a");
3139 if (f == NULL)
3140 return;
3141 rk_cloexec_file(f);
3142 fprintf(f, "%d %d\n", type, q->match);
3143 fclose(f);
3146 static const char *statname[] = {
3147 "find issuer cert",
3148 "match serialnumber",
3149 "match issuer name",
3150 "match subject name",
3151 "match subject key id",
3152 "match issuer id",
3153 "private key",
3154 "ku encipherment",
3155 "ku digitalsignature",
3156 "ku keycertsign",
3157 "ku crlsign",
3158 "ku nonrepudiation",
3159 "ku keyagreement",
3160 "ku dataencipherment",
3161 "anchor",
3162 "match certificate",
3163 "match local key id",
3164 "no match path",
3165 "match friendly name",
3166 "match function",
3167 "match key hash sha1",
3168 "match time"
3171 struct stat_el {
3172 unsigned long stats;
3173 unsigned int index;
3177 static int
3178 stat_sort(const void *a, const void *b)
3180 const struct stat_el *ae = a;
3181 const struct stat_el *be = b;
3182 return be->stats - ae->stats;
3186 * Unparse the statistics file and print the result on a FILE descriptor.
3188 * @param context A hx509 context.
3189 * @param printtype tyep to print
3190 * @param out the FILE to write the data on.
3192 * @ingroup hx509_cert
3195 void
3196 hx509_query_unparse_stats(hx509_context context, int printtype, FILE *out)
3198 rtbl_t t;
3199 FILE *f;
3200 int type, mask, num;
3201 size_t i;
3202 unsigned long multiqueries = 0, totalqueries = 0;
3203 struct stat_el stats[32];
3205 if (context->querystat == NULL)
3206 return;
3207 f = fopen(context->querystat, "r");
3208 if (f == NULL) {
3209 fprintf(out, "No statistic file %s: %s.\n",
3210 context->querystat, strerror(errno));
3211 return;
3213 rk_cloexec_file(f);
3215 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
3216 stats[i].index = i;
3217 stats[i].stats = 0;
3220 while (fscanf(f, "%d %d\n", &type, &mask) == 2) {
3221 if (type != printtype)
3222 continue;
3223 num = i = 0;
3224 while (mask && i < sizeof(stats)/sizeof(stats[0])) {
3225 if (mask & 1) {
3226 stats[i].stats++;
3227 num++;
3229 mask = mask >>1 ;
3230 i++;
3232 if (num > 1)
3233 multiqueries++;
3234 totalqueries++;
3236 fclose(f);
3238 qsort(stats, sizeof(stats)/sizeof(stats[0]), sizeof(stats[0]), stat_sort);
3240 t = rtbl_create();
3241 if (t == NULL)
3242 errx(1, "out of memory");
3244 rtbl_set_separator (t, " ");
3246 rtbl_add_column_by_id (t, 0, "Name", 0);
3247 rtbl_add_column_by_id (t, 1, "Counter", 0);
3250 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
3251 char str[10];
3253 if (stats[i].index < sizeof(statname)/sizeof(statname[0]))
3254 rtbl_add_column_entry_by_id (t, 0, statname[stats[i].index]);
3255 else {
3256 snprintf(str, sizeof(str), "%d", stats[i].index);
3257 rtbl_add_column_entry_by_id (t, 0, str);
3259 snprintf(str, sizeof(str), "%lu", stats[i].stats);
3260 rtbl_add_column_entry_by_id (t, 1, str);
3263 rtbl_format(t, out);
3264 rtbl_destroy(t);
3266 fprintf(out, "\nQueries: multi %lu total %lu\n",
3267 multiqueries, totalqueries);
3271 * Check the extended key usage on the hx509 certificate.
3273 * @param context A hx509 context.
3274 * @param cert A hx509 context.
3275 * @param eku the EKU to check for
3276 * @param allow_any_eku if the any EKU is set, allow that to be a
3277 * substitute.
3279 * @return An hx509 error code, see hx509_get_error_string().
3281 * @ingroup hx509_cert
3285 hx509_cert_check_eku(hx509_context context, hx509_cert cert,
3286 const heim_oid *eku, int allow_any_eku)
3288 ExtKeyUsage e;
3289 int ret;
3290 size_t i;
3292 ret = find_extension_eku(_hx509_get_cert(cert), &e);
3293 if (ret) {
3294 hx509_clear_error_string(context);
3295 return ret;
3298 for (i = 0; i < e.len; i++) {
3299 if (der_heim_oid_cmp(eku, &e.val[i]) == 0) {
3300 free_ExtKeyUsage(&e);
3301 return 0;
3303 if (allow_any_eku) {
3304 #if 0
3305 if (der_heim_oid_cmp(id_any_eku, &e.val[i]) == 0) {
3306 free_ExtKeyUsage(&e);
3307 return 0;
3309 #endif
3312 free_ExtKeyUsage(&e);
3313 hx509_clear_error_string(context);
3314 return HX509_CERTIFICATE_MISSING_EKU;
3318 _hx509_cert_get_keyusage(hx509_context context,
3319 hx509_cert c,
3320 KeyUsage *ku)
3322 Certificate *cert;
3323 const Extension *e;
3324 size_t size;
3325 int ret;
3326 size_t i = 0;
3328 memset(ku, 0, sizeof(*ku));
3330 cert = _hx509_get_cert(c);
3332 if (_hx509_cert_get_version(cert) < 3)
3333 return 0;
3335 e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i);
3336 if (e == NULL)
3337 return HX509_KU_CERT_MISSING;
3339 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, ku, &size);
3340 if (ret)
3341 return ret;
3342 return 0;
3346 _hx509_cert_get_eku(hx509_context context,
3347 hx509_cert cert,
3348 ExtKeyUsage *e)
3350 int ret;
3352 memset(e, 0, sizeof(*e));
3354 ret = find_extension_eku(_hx509_get_cert(cert), e);
3355 if (ret && ret != HX509_EXTENSION_NOT_FOUND) {
3356 hx509_clear_error_string(context);
3357 return ret;
3359 return 0;
3363 * Encodes the hx509 certificate as a DER encode binary.
3365 * @param context A hx509 context.
3366 * @param c the certificate to encode.
3367 * @param os the encode certificate, set to NULL, 0 on case of
3368 * error. Free the os->data with hx509_xfree().
3370 * @return An hx509 error code, see hx509_get_error_string().
3372 * @ingroup hx509_cert
3376 hx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os)
3378 size_t size;
3379 int ret;
3381 os->data = NULL;
3382 os->length = 0;
3384 ASN1_MALLOC_ENCODE(Certificate, os->data, os->length,
3385 _hx509_get_cert(c), &size, ret);
3386 if (ret) {
3387 os->data = NULL;
3388 os->length = 0;
3389 return ret;
3391 if (os->length != size)
3392 _hx509_abort("internal ASN.1 encoder error");
3394 return ret;
3398 * Last to avoid lost __attribute__s due to #undef.
3401 #undef __attribute__
3402 #define __attribute__(X)
3404 void
3405 _hx509_abort(const char *fmt, ...)
3406 __attribute__ ((noreturn, format (printf, 1, 2)))
3408 va_list ap;
3409 va_start(ap, fmt);
3410 vprintf(fmt, ap);
3411 va_end(ap);
3412 printf("\n");
3413 fflush(stdout);
3414 abort();
3418 * Free a data element allocated in the library.
3420 * @param ptr data to be freed.
3422 * @ingroup hx509_misc
3425 void
3426 hx509_xfree(void *ptr)
3428 free(ptr);
3436 _hx509_cert_to_env(hx509_context context, hx509_cert cert, hx509_env *env)
3438 ExtKeyUsage eku;
3439 hx509_name name;
3440 char *buf;
3441 int ret;
3442 hx509_env envcert = NULL;
3444 *env = NULL;
3446 /* version */
3447 ret = asprintf(&buf, "%d", _hx509_cert_get_version(_hx509_get_cert(cert)));
3448 if (ret == -1)
3449 goto out;
3450 ret = hx509_env_add(context, &envcert, "version", buf);
3451 free(buf);
3452 if (ret)
3453 goto out;
3455 /* subject */
3456 ret = hx509_cert_get_subject(cert, &name);
3457 if (ret)
3458 goto out;
3460 ret = hx509_name_to_string(name, &buf);
3461 if (ret) {
3462 hx509_name_free(&name);
3463 goto out;
3466 ret = hx509_env_add(context, &envcert, "subject", buf);
3467 hx509_name_free(&name);
3468 if (ret)
3469 goto out;
3471 /* issuer */
3472 ret = hx509_cert_get_issuer(cert, &name);
3473 if (ret)
3474 goto out;
3476 ret = hx509_name_to_string(name, &buf);
3477 hx509_name_free(&name);
3478 if (ret)
3479 goto out;
3481 ret = hx509_env_add(context, &envcert, "issuer", buf);
3482 hx509_xfree(buf);
3483 if (ret)
3484 goto out;
3486 /* eku */
3488 ret = _hx509_cert_get_eku(context, cert, &eku);
3489 if (ret == HX509_EXTENSION_NOT_FOUND)
3491 else if (ret != 0)
3492 goto out;
3493 else {
3494 size_t i;
3495 hx509_env enveku = NULL;
3497 for (i = 0; i < eku.len; i++) {
3499 ret = der_print_heim_oid(&eku.val[i], '.', &buf);
3500 if (ret) {
3501 free_ExtKeyUsage(&eku);
3502 hx509_env_free(&enveku);
3503 goto out;
3505 ret = hx509_env_add(context, &enveku, buf, "oid-name-here");
3506 free(buf);
3507 if (ret) {
3508 free_ExtKeyUsage(&eku);
3509 hx509_env_free(&enveku);
3510 goto out;
3513 free_ExtKeyUsage(&eku);
3515 ret = hx509_env_add_binding(context, &envcert, "eku", enveku);
3516 if (ret) {
3517 hx509_env_free(&enveku);
3518 goto out;
3523 Certificate *c = _hx509_get_cert(cert);
3524 heim_octet_string os, sig;
3525 hx509_env envhash = NULL;
3527 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
3528 os.length =
3529 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
3531 ret = _hx509_create_signature(context,
3532 NULL,
3533 hx509_signature_sha1(),
3534 &os,
3535 NULL,
3536 &sig);
3537 if (ret != 0)
3538 goto out;
3540 ret = hex_encode(sig.data, sig.length, &buf);
3541 der_free_octet_string(&sig);
3542 if (ret < 0) {
3543 ret = ENOMEM;
3544 hx509_set_error_string(context, 0, ret,
3545 "Out of memory");
3546 goto out;
3549 ret = hx509_env_add(context, &envhash, "sha1", buf);
3550 free(buf);
3551 if (ret)
3552 goto out;
3554 ret = hx509_env_add_binding(context, &envcert, "hash", envhash);
3555 if (ret) {
3556 hx509_env_free(&envhash);
3557 goto out;
3561 ret = hx509_env_add_binding(context, env, "certificate", envcert);
3562 if (ret)
3563 goto out;
3565 return 0;
3567 out:
3568 hx509_env_free(&envcert);
3569 return ret;
3573 * Print a simple representation of a certificate
3575 * @param context A hx509 context, can be NULL
3576 * @param cert certificate to print
3577 * @param out the stdio output stream, if NULL, stdout is used
3579 * @return An hx509 error code
3581 * @ingroup hx509_cert
3585 hx509_print_cert(hx509_context context, hx509_cert cert, FILE *out)
3587 hx509_name name;
3588 char *str;
3589 int ret;
3591 if (out == NULL)
3592 out = stderr;
3594 ret = hx509_cert_get_issuer(cert, &name);
3595 if (ret)
3596 return ret;
3597 hx509_name_to_string(name, &str);
3598 hx509_name_free(&name);
3599 fprintf(out, " issuer: \"%s\"\n", str);
3600 free(str);
3602 ret = hx509_cert_get_subject(cert, &name);
3603 if (ret)
3604 return ret;
3605 hx509_name_to_string(name, &str);
3606 hx509_name_free(&name);
3607 fprintf(out, " subject: \"%s\"\n", str);
3608 free(str);
3611 heim_integer serialNumber;
3613 ret = hx509_cert_get_serialnumber(cert, &serialNumber);
3614 if (ret)
3615 return ret;
3616 ret = der_print_hex_heim_integer(&serialNumber, &str);
3617 if (ret)
3618 return ret;
3619 der_free_heim_integer(&serialNumber);
3620 fprintf(out, " serial: %s\n", str);
3621 free(str);
3624 printf(" keyusage: ");
3625 ret = hx509_cert_keyusage_print(context, cert, &str);
3626 if (ret == 0) {
3627 fprintf(out, "%s\n", str);
3628 free(str);
3629 } else
3630 fprintf(out, "no");
3632 return 0;