compare right thing
[heimdal.git] / lib / hx509 / cert.c
blob25c62cf7c02d40cebdd7964997cb0f348d943b4e
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 /**
97 * Creates a hx509 context that most functions in the library
98 * uses. The context is only allowed to be used by one thread at each
99 * moment. Free the context with hx509_context_free().
101 * @param context Returns a pointer to new hx509 context.
103 * @return Returns an hx509 error code.
105 * @ingroup hx509
109 hx509_context_init(hx509_context *context)
111 *context = calloc(1, sizeof(**context));
112 if (*context == NULL)
113 return ENOMEM;
115 _hx509_ks_null_register(*context);
116 _hx509_ks_mem_register(*context);
117 _hx509_ks_file_register(*context);
118 _hx509_ks_pkcs12_register(*context);
119 _hx509_ks_pkcs11_register(*context);
120 _hx509_ks_dir_register(*context);
121 _hx509_ks_keychain_register(*context);
123 ENGINE_add_conf_module();
124 OpenSSL_add_all_algorithms();
126 (*context)->ocsp_time_diff = HX509_DEFAULT_OCSP_TIME_DIFF;
128 initialize_hx_error_table_r(&(*context)->et_list);
129 initialize_asn1_error_table_r(&(*context)->et_list);
131 #ifdef HX509_DEFAULT_ANCHORS
132 (void)hx509_certs_init(*context, HX509_DEFAULT_ANCHORS, 0,
133 NULL, &(*context)->default_trust_anchors);
134 #endif
136 return 0;
140 * Selects if the hx509_revoke_verify() function is going to require
141 * the existans of a revokation method (OCSP, CRL) or not. Note that
142 * hx509_verify_path(), hx509_cms_verify_signed(), and other function
143 * call hx509_revoke_verify().
145 * @param context hx509 context to change the flag for.
146 * @param flag zero, revokation method required, non zero missing
147 * revokation method ok
149 * @ingroup hx509_verify
152 void
153 hx509_context_set_missing_revoke(hx509_context context, int flag)
155 if (flag)
156 context->flags |= HX509_CTX_VERIFY_MISSING_OK;
157 else
158 context->flags &= ~HX509_CTX_VERIFY_MISSING_OK;
162 * Free the context allocated by hx509_context_init().
164 * @param context context to be freed.
166 * @ingroup hx509
169 void
170 hx509_context_free(hx509_context *context)
172 hx509_clear_error_string(*context);
173 if ((*context)->ks_ops) {
174 free((*context)->ks_ops);
175 (*context)->ks_ops = NULL;
177 (*context)->ks_num_ops = 0;
178 free_error_table ((*context)->et_list);
179 if ((*context)->querystat)
180 free((*context)->querystat);
181 memset(*context, 0, sizeof(**context));
182 free(*context);
183 *context = NULL;
190 Certificate *
191 _hx509_get_cert(hx509_cert cert)
193 return cert->data;
201 _hx509_cert_get_version(const Certificate *t)
203 return t->tbsCertificate.version ? *t->tbsCertificate.version + 1 : 1;
207 * Allocate and init an hx509 certificate object from the decoded
208 * certificate `c´.
210 * @param context A hx509 context.
211 * @param c
212 * @param cert
214 * @return Returns an hx509 error code.
216 * @ingroup hx509_cert
220 hx509_cert_init(hx509_context context, const Certificate *c, hx509_cert *cert)
222 int ret;
224 *cert = malloc(sizeof(**cert));
225 if (*cert == NULL)
226 return ENOMEM;
227 (*cert)->ref = 1;
228 (*cert)->friendlyname = NULL;
229 (*cert)->attrs.len = 0;
230 (*cert)->attrs.val = NULL;
231 (*cert)->private_key = NULL;
232 (*cert)->basename = NULL;
233 (*cert)->release = NULL;
234 (*cert)->ctx = NULL;
236 (*cert)->data = calloc(1, sizeof(*(*cert)->data));
237 if ((*cert)->data == NULL) {
238 free(*cert);
239 return ENOMEM;
241 ret = copy_Certificate(c, (*cert)->data);
242 if (ret) {
243 free((*cert)->data);
244 free(*cert);
245 *cert = NULL;
247 return ret;
251 * Just like hx509_cert_init(), but instead of a decode certificate
252 * takes an pointer and length to a memory region that contains a
253 * DER/BER encoded certificate.
255 * If the memory region doesn't contain just the certificate and
256 * nothing more the function will fail with
257 * HX509_EXTRA_DATA_AFTER_STRUCTURE.
259 * @param context A hx509 context.
260 * @param ptr pointer to memory region containing encoded certificate.
261 * @param len length of memory region.
262 * @param cert a return pointer to a hx509 certificate object, will
263 * contain NULL on error.
265 * @return An hx509 error code, see hx509_get_error_string().
267 * @ingroup hx509_cert
271 hx509_cert_init_data(hx509_context context,
272 const void *ptr,
273 size_t len,
274 hx509_cert *cert)
276 Certificate t;
277 size_t size;
278 int ret;
280 ret = decode_Certificate(ptr, len, &t, &size);
281 if (ret) {
282 hx509_set_error_string(context, 0, ret, "Failed to decode certificate");
283 return ret;
285 if (size != len) {
286 free_Certificate(&t);
287 hx509_set_error_string(context, 0, HX509_EXTRA_DATA_AFTER_STRUCTURE,
288 "Extra data after certificate");
289 return HX509_EXTRA_DATA_AFTER_STRUCTURE;
292 ret = hx509_cert_init(context, &t, cert);
293 free_Certificate(&t);
294 return ret;
297 void
298 _hx509_cert_set_release(hx509_cert cert,
299 _hx509_cert_release_func release,
300 void *ctx)
302 cert->release = release;
303 cert->ctx = ctx;
307 /* Doesn't make a copy of `private_key'. */
310 _hx509_cert_assign_key(hx509_cert cert, hx509_private_key private_key)
312 if (cert->private_key)
313 _hx509_private_key_free(&cert->private_key);
314 cert->private_key = _hx509_private_key_ref(private_key);
315 return 0;
319 * Free reference to the hx509 certificate object, if the refcounter
320 * reaches 0, the object if freed. Its allowed to pass in NULL.
322 * @param cert the cert to free.
324 * @ingroup hx509_cert
327 void
328 hx509_cert_free(hx509_cert cert)
330 int i;
332 if (cert == NULL)
333 return;
335 if (cert->ref <= 0)
336 _hx509_abort("cert refcount <= 0 on free");
337 if (--cert->ref > 0)
338 return;
340 if (cert->release)
341 (cert->release)(cert, cert->ctx);
343 if (cert->private_key)
344 _hx509_private_key_free(&cert->private_key);
346 free_Certificate(cert->data);
347 free(cert->data);
349 for (i = 0; i < cert->attrs.len; i++) {
350 der_free_octet_string(&cert->attrs.val[i]->data);
351 der_free_oid(&cert->attrs.val[i]->oid);
352 free(cert->attrs.val[i]);
354 free(cert->attrs.val);
355 free(cert->friendlyname);
356 if (cert->basename)
357 hx509_name_free(&cert->basename);
358 memset(cert, 0, sizeof(cert));
359 free(cert);
363 * Add a reference to a hx509 certificate object.
365 * @param cert a pointer to an hx509 certificate object.
367 * @return the same object as is passed in.
369 * @ingroup hx509_cert
372 hx509_cert
373 hx509_cert_ref(hx509_cert cert)
375 if (cert == NULL)
376 return NULL;
377 if (cert->ref <= 0)
378 _hx509_abort("cert refcount <= 0");
379 cert->ref++;
380 if (cert->ref == 0)
381 _hx509_abort("cert refcount == 0");
382 return cert;
386 * Allocate an verification context that is used fo control the
387 * verification process.
389 * @param context A hx509 context.
390 * @param ctx returns a pointer to a hx509_verify_ctx object.
392 * @return An hx509 error code, see hx509_get_error_string().
394 * @ingroup hx509_verify
398 hx509_verify_init_ctx(hx509_context context, hx509_verify_ctx *ctx)
400 hx509_verify_ctx c;
402 c = calloc(1, sizeof(*c));
403 if (c == NULL)
404 return ENOMEM;
406 c->max_depth = HX509_VERIFY_MAX_DEPTH;
408 *ctx = c;
410 return 0;
414 * Free an hx509 verification context.
416 * @param ctx the context to be freed.
418 * @ingroup hx509_verify
421 void
422 hx509_verify_destroy_ctx(hx509_verify_ctx ctx)
424 if (ctx) {
425 hx509_certs_free(&ctx->trust_anchors);
426 hx509_revoke_free(&ctx->revoke_ctx);
427 memset(ctx, 0, sizeof(*ctx));
429 free(ctx);
433 * Set the trust anchors in the verification context, makes an
434 * reference to the keyset, so the consumer can free the keyset
435 * independent of the destruction of the verification context (ctx).
436 * If there already is a keyset attached, it's released.
438 * @param ctx a verification context
439 * @param set a keyset containing the trust anchors.
441 * @ingroup hx509_verify
444 void
445 hx509_verify_attach_anchors(hx509_verify_ctx ctx, hx509_certs set)
447 if (ctx->trust_anchors)
448 hx509_certs_free(&ctx->trust_anchors);
449 ctx->trust_anchors = hx509_certs_ref(set);
453 * Attach an revocation context to the verfication context, , makes an
454 * reference to the revoke context, so the consumer can free the
455 * revoke context independent of the destruction of the verification
456 * context. If there is no revoke context, the verification process is
457 * NOT going to check any verification status.
459 * @param ctx a verification context.
460 * @param revoke_ctx a revoke context.
462 * @ingroup hx509_verify
465 void
466 hx509_verify_attach_revoke(hx509_verify_ctx ctx, hx509_revoke_ctx revoke_ctx)
468 if (ctx->revoke_ctx)
469 hx509_revoke_free(&ctx->revoke_ctx);
470 ctx->revoke_ctx = _hx509_revoke_ref(revoke_ctx);
474 * Set the clock time the the verification process is going to
475 * use. Used to check certificate in the past and future time. If not
476 * set the current time will be used.
478 * @param ctx a verification context.
479 * @param t the time the verifiation is using.
482 * @ingroup hx509_verify
485 void
486 hx509_verify_set_time(hx509_verify_ctx ctx, time_t t)
488 ctx->flags |= HX509_VERIFY_CTX_F_TIME_SET;
489 ctx->time_now = t;
492 time_t
493 _hx509_verify_get_time(hx509_verify_ctx ctx)
495 return ctx->time_now;
499 * Set the maximum depth of the certificate chain that the path
500 * builder is going to try.
502 * @param ctx a verification context
503 * @param max_depth maxium depth of the certificate chain, include
504 * trust anchor.
506 * @ingroup hx509_verify
509 void
510 hx509_verify_set_max_depth(hx509_verify_ctx ctx, unsigned int max_depth)
512 ctx->max_depth = max_depth;
516 * Allow or deny the use of proxy certificates
518 * @param ctx a verification context
519 * @param boolean if non zero, allow proxy certificates.
521 * @ingroup hx509_verify
524 void
525 hx509_verify_set_proxy_certificate(hx509_verify_ctx ctx, int boolean)
527 if (boolean)
528 ctx->flags |= HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
529 else
530 ctx->flags &= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
534 * Select strict RFC3280 verification of certificiates. This means
535 * checking key usage on CA certificates, this will make version 1
536 * certificiates unuseable.
538 * @param ctx a verification context
539 * @param boolean if non zero, use strict verification.
541 * @ingroup hx509_verify
544 void
545 hx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx, int boolean)
547 if (boolean)
548 ctx->flags |= HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
549 else
550 ctx->flags &= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
554 * Allow using the operating system builtin trust anchors if no other
555 * trust anchors are configured.
557 * @param ctx a verification context
558 * @param boolean if non zero, useing the operating systems builtin
559 * trust anchors.
562 * @return An hx509 error code, see hx509_get_error_string().
564 * @ingroup hx509_cert
567 void
568 hx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx, int boolean)
570 if (boolean)
571 ctx->flags &= ~HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
572 else
573 ctx->flags |= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
576 void
577 hx509_verify_ctx_f_allow_best_before_signature_algs(hx509_context ctx,
578 int boolean)
580 if (boolean)
581 ctx->flags &= ~HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK;
582 else
583 ctx->flags |= HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK;
586 static const Extension *
587 find_extension(const Certificate *cert, const heim_oid *oid, int *idx)
589 const TBSCertificate *c = &cert->tbsCertificate;
591 if (c->version == NULL || *c->version < 2 || c->extensions == NULL)
592 return NULL;
594 for (;*idx < c->extensions->len; (*idx)++) {
595 if (der_heim_oid_cmp(&c->extensions->val[*idx].extnID, oid) == 0)
596 return &c->extensions->val[(*idx)++];
598 return NULL;
601 static int
602 find_extension_auth_key_id(const Certificate *subject,
603 AuthorityKeyIdentifier *ai)
605 const Extension *e;
606 size_t size;
607 int i = 0;
609 memset(ai, 0, sizeof(*ai));
611 e = find_extension(subject, &asn1_oid_id_x509_ce_authorityKeyIdentifier, &i);
612 if (e == NULL)
613 return HX509_EXTENSION_NOT_FOUND;
615 return decode_AuthorityKeyIdentifier(e->extnValue.data,
616 e->extnValue.length,
617 ai, &size);
621 _hx509_find_extension_subject_key_id(const Certificate *issuer,
622 SubjectKeyIdentifier *si)
624 const Extension *e;
625 size_t size;
626 int i = 0;
628 memset(si, 0, sizeof(*si));
630 e = find_extension(issuer, &asn1_oid_id_x509_ce_subjectKeyIdentifier, &i);
631 if (e == NULL)
632 return HX509_EXTENSION_NOT_FOUND;
634 return decode_SubjectKeyIdentifier(e->extnValue.data,
635 e->extnValue.length,
636 si, &size);
639 static int
640 find_extension_name_constraints(const Certificate *subject,
641 NameConstraints *nc)
643 const Extension *e;
644 size_t size;
645 int i = 0;
647 memset(nc, 0, sizeof(*nc));
649 e = find_extension(subject, &asn1_oid_id_x509_ce_nameConstraints, &i);
650 if (e == NULL)
651 return HX509_EXTENSION_NOT_FOUND;
653 return decode_NameConstraints(e->extnValue.data,
654 e->extnValue.length,
655 nc, &size);
658 static int
659 find_extension_subject_alt_name(const Certificate *cert, int *i,
660 GeneralNames *sa)
662 const Extension *e;
663 size_t size;
665 memset(sa, 0, sizeof(*sa));
667 e = find_extension(cert, &asn1_oid_id_x509_ce_subjectAltName, i);
668 if (e == NULL)
669 return HX509_EXTENSION_NOT_FOUND;
671 return decode_GeneralNames(e->extnValue.data,
672 e->extnValue.length,
673 sa, &size);
676 static int
677 find_extension_eku(const Certificate *cert, ExtKeyUsage *eku)
679 const Extension *e;
680 size_t size;
681 int i = 0;
683 memset(eku, 0, sizeof(*eku));
685 e = find_extension(cert, &asn1_oid_id_x509_ce_extKeyUsage, &i);
686 if (e == NULL)
687 return HX509_EXTENSION_NOT_FOUND;
689 return decode_ExtKeyUsage(e->extnValue.data,
690 e->extnValue.length,
691 eku, &size);
694 static int
695 add_to_list(hx509_octet_string_list *list, const heim_octet_string *entry)
697 void *p;
698 int ret;
700 p = realloc(list->val, (list->len + 1) * sizeof(list->val[0]));
701 if (p == NULL)
702 return ENOMEM;
703 list->val = p;
704 ret = der_copy_octet_string(entry, &list->val[list->len]);
705 if (ret)
706 return ret;
707 list->len++;
708 return 0;
712 * Free a list of octet strings returned by another hx509 library
713 * function.
715 * @param list list to be freed.
717 * @ingroup hx509_misc
720 void
721 hx509_free_octet_string_list(hx509_octet_string_list *list)
723 int i;
724 for (i = 0; i < list->len; i++)
725 der_free_octet_string(&list->val[i]);
726 free(list->val);
727 list->val = NULL;
728 list->len = 0;
732 * Return a list of subjectAltNames specified by oid in the
733 * certificate. On error the
735 * The returned list of octet string should be freed with
736 * hx509_free_octet_string_list().
738 * @param context A hx509 context.
739 * @param cert a hx509 certificate object.
740 * @param oid an oid to for SubjectAltName.
741 * @param list list of matching SubjectAltName.
743 * @return An hx509 error code, see hx509_get_error_string().
745 * @ingroup hx509_cert
749 hx509_cert_find_subjectAltName_otherName(hx509_context context,
750 hx509_cert cert,
751 const heim_oid *oid,
752 hx509_octet_string_list *list)
754 GeneralNames sa;
755 int ret, i, j;
757 list->val = NULL;
758 list->len = 0;
760 i = 0;
761 while (1) {
762 ret = find_extension_subject_alt_name(_hx509_get_cert(cert), &i, &sa);
763 i++;
764 if (ret == HX509_EXTENSION_NOT_FOUND) {
765 return 0;
766 } else if (ret != 0) {
767 hx509_set_error_string(context, 0, ret, "Error searching for SAN");
768 hx509_free_octet_string_list(list);
769 return ret;
772 for (j = 0; j < sa.len; j++) {
773 if (sa.val[j].element == choice_GeneralName_otherName &&
774 der_heim_oid_cmp(&sa.val[j].u.otherName.type_id, oid) == 0)
776 ret = add_to_list(list, &sa.val[j].u.otherName.value);
777 if (ret) {
778 hx509_set_error_string(context, 0, ret,
779 "Error adding an exra SAN to "
780 "return list");
781 hx509_free_octet_string_list(list);
782 free_GeneralNames(&sa);
783 return ret;
787 free_GeneralNames(&sa);
792 static int
793 check_key_usage(hx509_context context, const Certificate *cert,
794 unsigned flags, int req_present)
796 const Extension *e;
797 KeyUsage ku;
798 size_t size;
799 int ret, i = 0;
800 unsigned ku_flags;
802 if (_hx509_cert_get_version(cert) < 3)
803 return 0;
805 e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i);
806 if (e == NULL) {
807 if (req_present) {
808 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
809 "Required extension key "
810 "usage missing from certifiate");
811 return HX509_KU_CERT_MISSING;
813 return 0;
816 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, &ku, &size);
817 if (ret)
818 return ret;
819 ku_flags = KeyUsage2int(ku);
820 if ((ku_flags & flags) != flags) {
821 unsigned missing = (~ku_flags) & flags;
822 char buf[256], *name;
824 unparse_flags(missing, asn1_KeyUsage_units(), buf, sizeof(buf));
825 _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
826 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
827 "Key usage %s required but missing "
828 "from certifiate %s", buf, name);
829 free(name);
830 return HX509_KU_CERT_MISSING;
832 return 0;
836 * Return 0 on matching key usage 'flags' for 'cert', otherwise return
837 * an error code. If 'req_present' the existance is required of the
838 * KeyUsage extension.
842 _hx509_check_key_usage(hx509_context context, hx509_cert cert,
843 unsigned flags, int req_present)
845 return check_key_usage(context, _hx509_get_cert(cert), flags, req_present);
848 enum certtype { PROXY_CERT, EE_CERT, CA_CERT };
850 static int
851 check_basic_constraints(hx509_context context, const Certificate *cert,
852 enum certtype type, int depth)
854 BasicConstraints bc;
855 const Extension *e;
856 size_t size;
857 int ret, i = 0;
859 if (_hx509_cert_get_version(cert) < 3)
860 return 0;
862 e = find_extension(cert, &asn1_oid_id_x509_ce_basicConstraints, &i);
863 if (e == NULL) {
864 switch(type) {
865 case PROXY_CERT:
866 case EE_CERT:
867 return 0;
868 case CA_CERT: {
869 char *name;
870 ret = _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
871 assert(ret == 0);
872 hx509_set_error_string(context, 0, HX509_EXTENSION_NOT_FOUND,
873 "basicConstraints missing from "
874 "CA certifiacte %s", name);
875 free(name);
876 return HX509_EXTENSION_NOT_FOUND;
881 ret = decode_BasicConstraints(e->extnValue.data,
882 e->extnValue.length, &bc,
883 &size);
884 if (ret)
885 return ret;
886 switch(type) {
887 case PROXY_CERT:
888 if (bc.cA != NULL && *bc.cA)
889 ret = HX509_PARENT_IS_CA;
890 break;
891 case EE_CERT:
892 ret = 0;
893 break;
894 case CA_CERT:
895 if (bc.cA == NULL || !*bc.cA)
896 ret = HX509_PARENT_NOT_CA;
897 else if (bc.pathLenConstraint)
898 if (depth - 1 > *bc.pathLenConstraint)
899 ret = HX509_CA_PATH_TOO_DEEP;
900 break;
902 free_BasicConstraints(&bc);
903 return ret;
907 _hx509_cert_is_parent_cmp(const Certificate *subject,
908 const Certificate *issuer,
909 int allow_self_signed)
911 int diff;
912 AuthorityKeyIdentifier ai;
913 SubjectKeyIdentifier si;
914 int ret_ai, ret_si, ret;
916 ret = _hx509_name_cmp(&issuer->tbsCertificate.subject,
917 &subject->tbsCertificate.issuer,
918 &diff);
919 if (ret)
920 return ret;
921 if (diff)
922 return diff;
924 memset(&ai, 0, sizeof(ai));
925 memset(&si, 0, sizeof(si));
928 * Try to find AuthorityKeyIdentifier, if it's not present in the
929 * subject certificate nor the parent.
932 ret_ai = find_extension_auth_key_id(subject, &ai);
933 if (ret_ai && ret_ai != HX509_EXTENSION_NOT_FOUND)
934 return 1;
935 ret_si = _hx509_find_extension_subject_key_id(issuer, &si);
936 if (ret_si && ret_si != HX509_EXTENSION_NOT_FOUND)
937 return -1;
939 if (ret_si && ret_ai)
940 goto out;
941 if (ret_ai)
942 goto out;
943 if (ret_si) {
944 if (allow_self_signed) {
945 diff = 0;
946 goto out;
947 } else if (ai.keyIdentifier) {
948 diff = -1;
949 goto out;
953 if (ai.keyIdentifier == NULL) {
954 Name name;
956 if (ai.authorityCertIssuer == NULL)
957 return -1;
958 if (ai.authorityCertSerialNumber == NULL)
959 return -1;
961 diff = der_heim_integer_cmp(ai.authorityCertSerialNumber,
962 &issuer->tbsCertificate.serialNumber);
963 if (diff)
964 return diff;
965 if (ai.authorityCertIssuer->len != 1)
966 return -1;
967 if (ai.authorityCertIssuer->val[0].element != choice_GeneralName_directoryName)
968 return -1;
970 name.element =
971 ai.authorityCertIssuer->val[0].u.directoryName.element;
972 name.u.rdnSequence =
973 ai.authorityCertIssuer->val[0].u.directoryName.u.rdnSequence;
975 ret = _hx509_name_cmp(&issuer->tbsCertificate.subject,
976 &name,
977 &diff);
978 if (ret)
979 return ret;
980 if (diff)
981 return diff;
982 diff = 0;
983 } else
984 diff = der_heim_octet_string_cmp(ai.keyIdentifier, &si);
985 if (diff)
986 goto out;
988 out:
989 free_AuthorityKeyIdentifier(&ai);
990 free_SubjectKeyIdentifier(&si);
991 return diff;
994 static int
995 certificate_is_anchor(hx509_context context,
996 hx509_certs trust_anchors,
997 const hx509_cert cert)
999 hx509_query q;
1000 hx509_cert c;
1001 int ret;
1003 if (trust_anchors == NULL)
1004 return 0;
1006 _hx509_query_clear(&q);
1008 q.match = HX509_QUERY_MATCH_CERTIFICATE;
1009 q.certificate = _hx509_get_cert(cert);
1011 ret = hx509_certs_find(context, trust_anchors, &q, &c);
1012 if (ret == 0)
1013 hx509_cert_free(c);
1014 return ret == 0;
1017 static int
1018 certificate_is_self_signed(hx509_context context,
1019 const Certificate *cert,
1020 int *self_signed)
1022 int ret, diff;
1023 ret = _hx509_name_cmp(&cert->tbsCertificate.subject,
1024 &cert->tbsCertificate.issuer, &diff);
1025 *self_signed = (diff == 0);
1026 if (ret) {
1027 hx509_set_error_string(context, 0, ret,
1028 "Failed to check if self signed");
1029 } else
1030 ret = _hx509_self_signed_valid(context, &cert->signatureAlgorithm);
1032 return ret;
1036 * The subjectName is "null" when it's empty set of relative DBs.
1039 static int
1040 subject_null_p(const Certificate *c)
1042 return c->tbsCertificate.subject.u.rdnSequence.len == 0;
1046 static int
1047 find_parent(hx509_context context,
1048 time_t time_now,
1049 hx509_certs trust_anchors,
1050 hx509_path *path,
1051 hx509_certs pool,
1052 hx509_cert current,
1053 hx509_cert *parent)
1055 AuthorityKeyIdentifier ai;
1056 hx509_query q;
1057 int ret;
1059 *parent = NULL;
1060 memset(&ai, 0, sizeof(ai));
1062 _hx509_query_clear(&q);
1064 if (!subject_null_p(current->data)) {
1065 q.match |= HX509_QUERY_FIND_ISSUER_CERT;
1066 q.subject = _hx509_get_cert(current);
1067 } else {
1068 ret = find_extension_auth_key_id(current->data, &ai);
1069 if (ret) {
1070 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1071 "Subjectless certificate missing AuthKeyID");
1072 return HX509_CERTIFICATE_MALFORMED;
1075 if (ai.keyIdentifier == NULL) {
1076 free_AuthorityKeyIdentifier(&ai);
1077 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1078 "Subjectless certificate missing keyIdentifier "
1079 "inside AuthKeyID");
1080 return HX509_CERTIFICATE_MALFORMED;
1083 q.subject_id = ai.keyIdentifier;
1084 q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
1087 q.path = path;
1088 q.match |= HX509_QUERY_NO_MATCH_PATH;
1090 if (pool) {
1091 q.timenow = time_now;
1092 q.match |= HX509_QUERY_MATCH_TIME;
1094 ret = hx509_certs_find(context, pool, &q, parent);
1095 if (ret == 0) {
1096 free_AuthorityKeyIdentifier(&ai);
1097 return 0;
1099 q.match &= ~HX509_QUERY_MATCH_TIME;
1102 if (trust_anchors) {
1103 ret = hx509_certs_find(context, trust_anchors, &q, parent);
1104 if (ret == 0) {
1105 free_AuthorityKeyIdentifier(&ai);
1106 return ret;
1109 free_AuthorityKeyIdentifier(&ai);
1112 hx509_name name;
1113 char *str;
1115 ret = hx509_cert_get_subject(current, &name);
1116 if (ret) {
1117 hx509_clear_error_string(context);
1118 return HX509_ISSUER_NOT_FOUND;
1120 ret = hx509_name_to_string(name, &str);
1121 hx509_name_free(&name);
1122 if (ret) {
1123 hx509_clear_error_string(context);
1124 return HX509_ISSUER_NOT_FOUND;
1127 hx509_set_error_string(context, 0, HX509_ISSUER_NOT_FOUND,
1128 "Failed to find issuer for "
1129 "certificate with subject: '%s'", str);
1130 free(str);
1132 return HX509_ISSUER_NOT_FOUND;
1139 static int
1140 is_proxy_cert(hx509_context context,
1141 const Certificate *cert,
1142 ProxyCertInfo *rinfo)
1144 ProxyCertInfo info;
1145 const Extension *e;
1146 size_t size;
1147 int ret, i = 0;
1149 if (rinfo)
1150 memset(rinfo, 0, sizeof(*rinfo));
1152 e = find_extension(cert, &asn1_oid_id_pkix_pe_proxyCertInfo, &i);
1153 if (e == NULL) {
1154 hx509_clear_error_string(context);
1155 return HX509_EXTENSION_NOT_FOUND;
1158 ret = decode_ProxyCertInfo(e->extnValue.data,
1159 e->extnValue.length,
1160 &info,
1161 &size);
1162 if (ret) {
1163 hx509_clear_error_string(context);
1164 return ret;
1166 if (size != e->extnValue.length) {
1167 free_ProxyCertInfo(&info);
1168 hx509_clear_error_string(context);
1169 return HX509_EXTRA_DATA_AFTER_STRUCTURE;
1171 if (rinfo == NULL)
1172 free_ProxyCertInfo(&info);
1173 else
1174 *rinfo = info;
1176 return 0;
1180 * Path operations are like MEMORY based keyset, but with exposed
1181 * internal so we can do easy searches.
1185 _hx509_path_append(hx509_context context, hx509_path *path, hx509_cert cert)
1187 hx509_cert *val;
1188 val = realloc(path->val, (path->len + 1) * sizeof(path->val[0]));
1189 if (val == NULL) {
1190 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1191 return ENOMEM;
1194 path->val = val;
1195 path->val[path->len] = hx509_cert_ref(cert);
1196 path->len++;
1198 return 0;
1201 void
1202 _hx509_path_free(hx509_path *path)
1204 unsigned i;
1206 for (i = 0; i < path->len; i++)
1207 hx509_cert_free(path->val[i]);
1208 free(path->val);
1209 path->val = NULL;
1210 path->len = 0;
1214 * Find path by looking up issuer for the top certificate and continue
1215 * until an anchor certificate is found or max limit is found. A
1216 * certificate never included twice in the path.
1218 * If the trust anchors are not given, calculate optimistic path, just
1219 * follow the chain upward until we no longer find a parent or we hit
1220 * the max path limit. In this case, a failure will always be returned
1221 * depending on what error condition is hit first.
1223 * The path includes a path from the top certificate to the anchor
1224 * certificate.
1226 * The caller needs to free `path´ both on successful built path and
1227 * failure.
1231 _hx509_calculate_path(hx509_context context,
1232 int flags,
1233 time_t time_now,
1234 hx509_certs anchors,
1235 unsigned int max_depth,
1236 hx509_cert cert,
1237 hx509_certs pool,
1238 hx509_path *path)
1240 hx509_cert parent, current;
1241 int ret;
1243 if (max_depth == 0)
1244 max_depth = HX509_VERIFY_MAX_DEPTH;
1246 ret = _hx509_path_append(context, path, cert);
1247 if (ret)
1248 return ret;
1250 current = hx509_cert_ref(cert);
1252 while (!certificate_is_anchor(context, anchors, current)) {
1254 ret = find_parent(context, time_now, anchors, path,
1255 pool, current, &parent);
1256 hx509_cert_free(current);
1257 if (ret)
1258 return ret;
1260 ret = _hx509_path_append(context, path, parent);
1261 if (ret)
1262 return ret;
1263 current = parent;
1265 if (path->len > max_depth) {
1266 hx509_cert_free(current);
1267 hx509_set_error_string(context, 0, HX509_PATH_TOO_LONG,
1268 "Path too long while bulding "
1269 "certificate chain");
1270 return HX509_PATH_TOO_LONG;
1274 if ((flags & HX509_CALCULATE_PATH_NO_ANCHOR) &&
1275 path->len > 0 &&
1276 certificate_is_anchor(context, anchors, path->val[path->len - 1]))
1278 hx509_cert_free(path->val[path->len - 1]);
1279 path->len--;
1282 hx509_cert_free(current);
1283 return 0;
1287 _hx509_AlgorithmIdentifier_cmp(const AlgorithmIdentifier *p,
1288 const AlgorithmIdentifier *q)
1290 int diff;
1291 diff = der_heim_oid_cmp(&p->algorithm, &q->algorithm);
1292 if (diff)
1293 return diff;
1294 if (p->parameters) {
1295 if (q->parameters)
1296 return heim_any_cmp(p->parameters,
1297 q->parameters);
1298 else
1299 return 1;
1300 } else {
1301 if (q->parameters)
1302 return -1;
1303 else
1304 return 0;
1309 _hx509_Certificate_cmp(const Certificate *p, const Certificate *q)
1311 int diff;
1312 diff = der_heim_bit_string_cmp(&p->signatureValue, &q->signatureValue);
1313 if (diff)
1314 return diff;
1315 diff = _hx509_AlgorithmIdentifier_cmp(&p->signatureAlgorithm,
1316 &q->signatureAlgorithm);
1317 if (diff)
1318 return diff;
1319 diff = der_heim_octet_string_cmp(&p->tbsCertificate._save,
1320 &q->tbsCertificate._save);
1321 return diff;
1325 * Compare to hx509 certificate object, useful for sorting.
1327 * @param p a hx509 certificate object.
1328 * @param q a hx509 certificate object.
1330 * @return 0 the objects are the same, returns > 0 is p is "larger"
1331 * then q, < 0 if p is "smaller" then q.
1333 * @ingroup hx509_cert
1337 hx509_cert_cmp(hx509_cert p, hx509_cert q)
1339 return _hx509_Certificate_cmp(p->data, q->data);
1343 * Return the name of the issuer of the hx509 certificate.
1345 * @param p a hx509 certificate object.
1346 * @param name a pointer to a hx509 name, should be freed by
1347 * hx509_name_free().
1349 * @return An hx509 error code, see hx509_get_error_string().
1351 * @ingroup hx509_cert
1355 hx509_cert_get_issuer(hx509_cert p, hx509_name *name)
1357 return _hx509_name_from_Name(&p->data->tbsCertificate.issuer, name);
1361 * Return the name of the subject of the hx509 certificate.
1363 * @param p a hx509 certificate object.
1364 * @param name a pointer to a hx509 name, should be freed by
1365 * hx509_name_free(). See also hx509_cert_get_base_subject().
1367 * @return An hx509 error code, see hx509_get_error_string().
1369 * @ingroup hx509_cert
1373 hx509_cert_get_subject(hx509_cert p, hx509_name *name)
1375 return _hx509_name_from_Name(&p->data->tbsCertificate.subject, name);
1379 * Return the name of the base subject of the hx509 certificate. If
1380 * the certiicate is a verified proxy certificate, the this function
1381 * return the base certificate (root of the proxy chain). If the proxy
1382 * certificate is not verified with the base certificate
1383 * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned.
1385 * @param context a hx509 context.
1386 * @param c a hx509 certificate object.
1387 * @param name a pointer to a hx509 name, should be freed by
1388 * hx509_name_free(). See also hx509_cert_get_subject().
1390 * @return An hx509 error code, see hx509_get_error_string().
1392 * @ingroup hx509_cert
1396 hx509_cert_get_base_subject(hx509_context context, hx509_cert c,
1397 hx509_name *name)
1399 if (c->basename)
1400 return hx509_name_copy(context, c->basename, name);
1401 if (is_proxy_cert(context, c->data, NULL) == 0) {
1402 int ret = HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED;
1403 hx509_set_error_string(context, 0, ret,
1404 "Proxy certificate have not been "
1405 "canonicalize yet, no base name");
1406 return ret;
1408 return _hx509_name_from_Name(&c->data->tbsCertificate.subject, name);
1412 * Get serial number of the certificate.
1414 * @param p a hx509 certificate object.
1415 * @param i serial number, should be freed ith der_free_heim_integer().
1417 * @return An hx509 error code, see hx509_get_error_string().
1419 * @ingroup hx509_cert
1423 hx509_cert_get_serialnumber(hx509_cert p, heim_integer *i)
1425 return der_copy_heim_integer(&p->data->tbsCertificate.serialNumber, i);
1429 * Get notBefore time of the certificate.
1431 * @param p a hx509 certificate object.
1433 * @return return not before time
1435 * @ingroup hx509_cert
1438 time_t
1439 hx509_cert_get_notBefore(hx509_cert p)
1441 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notBefore);
1445 * Get notAfter time of the certificate.
1447 * @param p a hx509 certificate object.
1449 * @return return not after time.
1451 * @ingroup hx509_cert
1454 time_t
1455 hx509_cert_get_notAfter(hx509_cert p)
1457 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notAfter);
1461 * Get the SubjectPublicKeyInfo structure from the hx509 certificate.
1463 * @param context a hx509 context.
1464 * @param p a hx509 certificate object.
1465 * @param spki SubjectPublicKeyInfo, should be freed with
1466 * free_SubjectPublicKeyInfo().
1468 * @return An hx509 error code, see hx509_get_error_string().
1470 * @ingroup hx509_cert
1474 hx509_cert_get_SPKI(hx509_context context, hx509_cert p, SubjectPublicKeyInfo *spki)
1476 int ret;
1478 ret = copy_SubjectPublicKeyInfo(&p->data->tbsCertificate.subjectPublicKeyInfo, spki);
1479 if (ret)
1480 hx509_set_error_string(context, 0, ret, "Failed to copy SPKI");
1481 return ret;
1485 * Get the AlgorithmIdentifier from the hx509 certificate.
1487 * @param context a hx509 context.
1488 * @param p a hx509 certificate object.
1489 * @param alg AlgorithmIdentifier, should be freed with
1490 * free_AlgorithmIdentifier(). The algorithmidentifier is
1491 * typicly rsaEncryption, or id-ecPublicKey, or some other
1492 * public key mechanism.
1494 * @return An hx509 error code, see hx509_get_error_string().
1496 * @ingroup hx509_cert
1500 hx509_cert_get_SPKI_AlgorithmIdentifier(hx509_context context,
1501 hx509_cert p,
1502 AlgorithmIdentifier *alg)
1504 int ret;
1506 ret = copy_AlgorithmIdentifier(&p->data->tbsCertificate.subjectPublicKeyInfo.algorithm, alg);
1507 if (ret)
1508 hx509_set_error_string(context, 0, ret,
1509 "Failed to copy SPKI AlgorithmIdentifier");
1510 return ret;
1514 hx509_private_key
1515 _hx509_cert_private_key(hx509_cert p)
1517 return p->private_key;
1521 hx509_cert_have_private_key(hx509_cert p)
1523 return p->private_key ? 1 : 0;
1528 _hx509_cert_private_key_exportable(hx509_cert p)
1530 if (p->private_key == NULL)
1531 return 0;
1532 return _hx509_private_key_exportable(p->private_key);
1536 _hx509_cert_private_decrypt(hx509_context context,
1537 const heim_octet_string *ciphertext,
1538 const heim_oid *encryption_oid,
1539 hx509_cert p,
1540 heim_octet_string *cleartext)
1542 cleartext->data = NULL;
1543 cleartext->length = 0;
1545 if (p->private_key == NULL) {
1546 hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
1547 "Private key missing");
1548 return HX509_PRIVATE_KEY_MISSING;
1551 return _hx509_private_key_private_decrypt(context,
1552 ciphertext,
1553 encryption_oid,
1554 p->private_key,
1555 cleartext);
1559 _hx509_cert_public_encrypt(hx509_context context,
1560 const heim_octet_string *cleartext,
1561 const hx509_cert p,
1562 heim_oid *encryption_oid,
1563 heim_octet_string *ciphertext)
1565 return _hx509_public_encrypt(context,
1566 cleartext, p->data,
1567 encryption_oid, ciphertext);
1574 time_t
1575 _hx509_Time2time_t(const Time *t)
1577 switch(t->element) {
1578 case choice_Time_utcTime:
1579 return t->u.utcTime;
1580 case choice_Time_generalTime:
1581 return t->u.generalTime;
1583 return 0;
1590 static int
1591 init_name_constraints(hx509_name_constraints *nc)
1593 memset(nc, 0, sizeof(*nc));
1594 return 0;
1597 static int
1598 add_name_constraints(hx509_context context, const Certificate *c, int not_ca,
1599 hx509_name_constraints *nc)
1601 NameConstraints tnc;
1602 int ret;
1604 ret = find_extension_name_constraints(c, &tnc);
1605 if (ret == HX509_EXTENSION_NOT_FOUND)
1606 return 0;
1607 else if (ret) {
1608 hx509_set_error_string(context, 0, ret, "Failed getting NameConstraints");
1609 return ret;
1610 } else if (not_ca) {
1611 ret = HX509_VERIFY_CONSTRAINTS;
1612 hx509_set_error_string(context, 0, ret, "Not a CA and "
1613 "have NameConstraints");
1614 } else {
1615 NameConstraints *val;
1616 val = realloc(nc->val, sizeof(nc->val[0]) * (nc->len + 1));
1617 if (val == NULL) {
1618 hx509_clear_error_string(context);
1619 ret = ENOMEM;
1620 goto out;
1622 nc->val = val;
1623 ret = copy_NameConstraints(&tnc, &nc->val[nc->len]);
1624 if (ret) {
1625 hx509_clear_error_string(context);
1626 goto out;
1628 nc->len += 1;
1630 out:
1631 free_NameConstraints(&tnc);
1632 return ret;
1635 static int
1636 match_RDN(const RelativeDistinguishedName *c,
1637 const RelativeDistinguishedName *n)
1639 int i;
1641 if (c->len != n->len)
1642 return HX509_NAME_CONSTRAINT_ERROR;
1644 for (i = 0; i < n->len; i++) {
1645 int diff, ret;
1647 if (der_heim_oid_cmp(&c->val[i].type, &n->val[i].type) != 0)
1648 return HX509_NAME_CONSTRAINT_ERROR;
1649 ret = _hx509_name_ds_cmp(&c->val[i].value, &n->val[i].value, &diff);
1650 if (ret)
1651 return ret;
1652 if (diff != 0)
1653 return HX509_NAME_CONSTRAINT_ERROR;
1655 return 0;
1658 static int
1659 match_X501Name(const Name *c, const Name *n)
1661 int i, ret;
1663 if (c->element != choice_Name_rdnSequence
1664 || n->element != choice_Name_rdnSequence)
1665 return 0;
1666 if (c->u.rdnSequence.len > n->u.rdnSequence.len)
1667 return HX509_NAME_CONSTRAINT_ERROR;
1668 for (i = 0; i < c->u.rdnSequence.len; i++) {
1669 ret = match_RDN(&c->u.rdnSequence.val[i], &n->u.rdnSequence.val[i]);
1670 if (ret)
1671 return ret;
1673 return 0;
1677 static int
1678 match_general_name(const GeneralName *c, const GeneralName *n, int *match)
1681 * Name constraints only apply to the same name type, see RFC3280,
1682 * 4.2.1.11.
1684 assert(c->element == n->element);
1686 switch(c->element) {
1687 case choice_GeneralName_otherName:
1688 if (der_heim_oid_cmp(&c->u.otherName.type_id,
1689 &n->u.otherName.type_id) != 0)
1690 return HX509_NAME_CONSTRAINT_ERROR;
1691 if (heim_any_cmp(&c->u.otherName.value,
1692 &n->u.otherName.value) != 0)
1693 return HX509_NAME_CONSTRAINT_ERROR;
1694 *match = 1;
1695 return 0;
1696 case choice_GeneralName_rfc822Name: {
1697 const char *s;
1698 size_t len1, len2;
1699 s = memchr(c->u.rfc822Name.data, '@', c->u.rfc822Name.length);
1700 if (s) {
1701 if (der_printable_string_cmp(&c->u.rfc822Name, &n->u.rfc822Name) != 0)
1702 return HX509_NAME_CONSTRAINT_ERROR;
1703 } else {
1704 s = memchr(n->u.rfc822Name.data, '@', n->u.rfc822Name.length);
1705 if (s == NULL)
1706 return HX509_NAME_CONSTRAINT_ERROR;
1707 len1 = c->u.rfc822Name.length;
1708 len2 = n->u.rfc822Name.length -
1709 (s - ((char *)n->u.rfc822Name.data));
1710 if (len1 > len2)
1711 return HX509_NAME_CONSTRAINT_ERROR;
1712 if (memcmp(s + 1 + len2 - len1, c->u.rfc822Name.data, len1) != 0)
1713 return HX509_NAME_CONSTRAINT_ERROR;
1714 if (len1 < len2 && s[len2 - len1 + 1] != '.')
1715 return HX509_NAME_CONSTRAINT_ERROR;
1717 *match = 1;
1718 return 0;
1720 case choice_GeneralName_dNSName: {
1721 size_t lenc, lenn;
1722 char *ptr;
1724 lenc = c->u.dNSName.length;
1725 lenn = n->u.dNSName.length;
1726 if (lenc > lenn)
1727 return HX509_NAME_CONSTRAINT_ERROR;
1728 ptr = n->u.dNSName.data;
1729 if (memcmp(&ptr[lenn - lenc], c->u.dNSName.data, c->u.dNSName.length) != 0)
1730 return HX509_NAME_CONSTRAINT_ERROR;
1731 if (lenc != lenn && ptr[lenn - lenc - 1] != '.')
1732 return HX509_NAME_CONSTRAINT_ERROR;
1733 *match = 1;
1734 return 0;
1736 case choice_GeneralName_directoryName: {
1737 Name c_name, n_name;
1738 int ret;
1740 c_name._save.data = NULL;
1741 c_name._save.length = 0;
1742 c_name.element = c->u.directoryName.element;
1743 c_name.u.rdnSequence = c->u.directoryName.u.rdnSequence;
1745 n_name._save.data = NULL;
1746 n_name._save.length = 0;
1747 n_name.element = n->u.directoryName.element;
1748 n_name.u.rdnSequence = n->u.directoryName.u.rdnSequence;
1750 ret = match_X501Name(&c_name, &n_name);
1751 if (ret == 0)
1752 *match = 1;
1753 return ret;
1755 case choice_GeneralName_uniformResourceIdentifier:
1756 case choice_GeneralName_iPAddress:
1757 case choice_GeneralName_registeredID:
1758 default:
1759 return HX509_NAME_CONSTRAINT_ERROR;
1763 static int
1764 match_alt_name(const GeneralName *n, const Certificate *c,
1765 int *same, int *match)
1767 GeneralNames sa;
1768 int ret, i, j;
1770 i = 0;
1771 do {
1772 ret = find_extension_subject_alt_name(c, &i, &sa);
1773 if (ret == HX509_EXTENSION_NOT_FOUND) {
1774 ret = 0;
1775 break;
1776 } else if (ret != 0)
1777 break;
1779 for (j = 0; j < sa.len; j++) {
1780 if (n->element == sa.val[j].element) {
1781 *same = 1;
1782 ret = match_general_name(n, &sa.val[j], match);
1785 free_GeneralNames(&sa);
1786 } while (1);
1787 return ret;
1791 static int
1792 match_tree(const GeneralSubtrees *t, const Certificate *c, int *match)
1794 int name, alt_name, same;
1795 unsigned int i;
1796 int ret = 0;
1798 name = alt_name = same = *match = 0;
1799 for (i = 0; i < t->len; i++) {
1800 if (t->val[i].minimum && t->val[i].maximum)
1801 return HX509_RANGE;
1804 * If the constraint apply to directoryNames, test is with
1805 * subjectName of the certificate if the certificate have a
1806 * non-null (empty) subjectName.
1809 if (t->val[i].base.element == choice_GeneralName_directoryName
1810 && !subject_null_p(c))
1812 GeneralName certname;
1814 memset(&certname, 0, sizeof(certname));
1815 certname.element = choice_GeneralName_directoryName;
1816 certname.u.directoryName.element =
1817 c->tbsCertificate.subject.element;
1818 certname.u.directoryName.u.rdnSequence =
1819 c->tbsCertificate.subject.u.rdnSequence;
1821 ret = match_general_name(&t->val[i].base, &certname, &name);
1824 /* Handle subjectAltNames, this is icky since they
1825 * restrictions only apply if the subjectAltName is of the
1826 * same type. So if there have been a match of type, require
1827 * altname to be set.
1829 ret = match_alt_name(&t->val[i].base, c, &same, &alt_name);
1831 if (name && (!same || alt_name))
1832 *match = 1;
1833 return ret;
1836 static int
1837 check_name_constraints(hx509_context context,
1838 const hx509_name_constraints *nc,
1839 const Certificate *c)
1841 int match, ret;
1842 int i;
1844 for (i = 0 ; i < nc->len; i++) {
1845 GeneralSubtrees gs;
1847 if (nc->val[i].permittedSubtrees) {
1848 GeneralSubtrees_SET(&gs, nc->val[i].permittedSubtrees);
1849 ret = match_tree(&gs, c, &match);
1850 if (ret) {
1851 hx509_clear_error_string(context);
1852 return ret;
1854 /* allow null subjectNames, they wont matches anything */
1855 if (match == 0 && !subject_null_p(c)) {
1856 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1857 "Error verify constraints, "
1858 "certificate didn't match any "
1859 "permitted subtree");
1860 return HX509_VERIFY_CONSTRAINTS;
1863 if (nc->val[i].excludedSubtrees) {
1864 GeneralSubtrees_SET(&gs, nc->val[i].excludedSubtrees);
1865 ret = match_tree(&gs, c, &match);
1866 if (ret) {
1867 hx509_clear_error_string(context);
1868 return ret;
1870 if (match) {
1871 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1872 "Error verify constraints, "
1873 "certificate included in excluded "
1874 "subtree");
1875 return HX509_VERIFY_CONSTRAINTS;
1879 return 0;
1882 static void
1883 free_name_constraints(hx509_name_constraints *nc)
1885 int i;
1887 for (i = 0 ; i < nc->len; i++)
1888 free_NameConstraints(&nc->val[i]);
1889 free(nc->val);
1893 * Build and verify the path for the certificate to the trust anchor
1894 * specified in the verify context. The path is constructed from the
1895 * certificate, the pool and the trust anchors.
1897 * @param context A hx509 context.
1898 * @param ctx A hx509 verification context.
1899 * @param cert the certificate to build the path from.
1900 * @param pool A keyset of certificates to build the chain from.
1902 * @return An hx509 error code, see hx509_get_error_string().
1904 * @ingroup hx509_verify
1908 hx509_verify_path(hx509_context context,
1909 hx509_verify_ctx ctx,
1910 hx509_cert cert,
1911 hx509_certs pool)
1913 hx509_name_constraints nc;
1914 hx509_path path;
1915 int ret, i, proxy_cert_depth, selfsigned_depth, diff;
1916 enum certtype type;
1917 Name proxy_issuer;
1918 hx509_certs anchors = NULL;
1920 memset(&proxy_issuer, 0, sizeof(proxy_issuer));
1922 ret = init_name_constraints(&nc);
1923 if (ret)
1924 return ret;
1926 path.val = NULL;
1927 path.len = 0;
1929 if ((ctx->flags & HX509_VERIFY_CTX_F_TIME_SET) == 0)
1930 ctx->time_now = time(NULL);
1935 if (ctx->trust_anchors)
1936 anchors = hx509_certs_ref(ctx->trust_anchors);
1937 else if (context->default_trust_anchors && ALLOW_DEF_TA(ctx))
1938 anchors = hx509_certs_ref(context->default_trust_anchors);
1939 else {
1940 ret = hx509_certs_init(context, "MEMORY:no-TA", 0, NULL, &anchors);
1941 if (ret)
1942 goto out;
1946 * Calculate the path from the certificate user presented to the
1947 * to an anchor.
1949 ret = _hx509_calculate_path(context, 0, ctx->time_now,
1950 anchors, ctx->max_depth,
1951 cert, pool, &path);
1952 if (ret)
1953 goto out;
1956 * Check CA and proxy certificate chain from the top of the
1957 * certificate chain. Also check certificate is valid with respect
1958 * to the current time.
1962 proxy_cert_depth = 0;
1963 selfsigned_depth = 0;
1965 if (ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE)
1966 type = PROXY_CERT;
1967 else
1968 type = EE_CERT;
1970 for (i = 0; i < path.len; i++) {
1971 Certificate *c;
1972 time_t t;
1974 c = _hx509_get_cert(path.val[i]);
1977 * Lets do some basic check on issuer like
1978 * keyUsage.keyCertSign and basicConstraints.cA bit depending
1979 * on what type of certificate this is.
1982 switch (type) {
1983 case CA_CERT:
1985 /* XXX make constants for keyusage */
1986 ret = check_key_usage(context, c, 1 << 5,
1987 REQUIRE_RFC3280(ctx) ? TRUE : FALSE);
1988 if (ret) {
1989 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
1990 "Key usage missing from CA certificate");
1991 goto out;
1994 /* self signed cert doesn't add to path length */
1995 if (i + 1 != path.len) {
1996 int selfsigned;
1998 ret = certificate_is_self_signed(context, c, &selfsigned);
1999 if (ret)
2000 goto out;
2001 if (selfsigned)
2002 selfsigned_depth++;
2005 break;
2006 case PROXY_CERT: {
2007 ProxyCertInfo info;
2009 if (is_proxy_cert(context, c, &info) == 0) {
2010 int j;
2012 if (info.pCPathLenConstraint != NULL &&
2013 *info.pCPathLenConstraint < i)
2015 free_ProxyCertInfo(&info);
2016 ret = HX509_PATH_TOO_LONG;
2017 hx509_set_error_string(context, 0, ret,
2018 "Proxy certificate chain "
2019 "longer then allowed");
2020 goto out;
2022 /* XXX MUST check info.proxyPolicy */
2023 free_ProxyCertInfo(&info);
2025 j = 0;
2026 if (find_extension(c, &asn1_oid_id_x509_ce_subjectAltName, &j)) {
2027 ret = HX509_PROXY_CERT_INVALID;
2028 hx509_set_error_string(context, 0, ret,
2029 "Proxy certificate have explicity "
2030 "forbidden subjectAltName");
2031 goto out;
2034 j = 0;
2035 if (find_extension(c, &asn1_oid_id_x509_ce_issuerAltName, &j)) {
2036 ret = HX509_PROXY_CERT_INVALID;
2037 hx509_set_error_string(context, 0, ret,
2038 "Proxy certificate have explicity "
2039 "forbidden issuerAltName");
2040 goto out;
2044 * The subject name of the proxy certificate should be
2045 * CN=XXX,<proxy issuer>, prune of CN and check if its
2046 * the same over the whole chain of proxy certs and
2047 * then check with the EE cert when we get to it.
2050 if (proxy_cert_depth) {
2051 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.subject, &diff);
2052 if (ret) {
2053 hx509_set_error_string(context, 0, ret, "Out of memory");
2054 goto out;
2056 if (diff) {
2057 ret = HX509_PROXY_CERT_NAME_WRONG;
2058 hx509_set_error_string(context, 0, ret,
2059 "Base proxy name not right");
2060 goto out;
2064 free_Name(&proxy_issuer);
2066 ret = copy_Name(&c->tbsCertificate.subject, &proxy_issuer);
2067 if (ret) {
2068 hx509_clear_error_string(context);
2069 goto out;
2072 j = proxy_issuer.u.rdnSequence.len;
2073 if (proxy_issuer.u.rdnSequence.len < 2
2074 || proxy_issuer.u.rdnSequence.val[j - 1].len > 1
2075 || der_heim_oid_cmp(&proxy_issuer.u.rdnSequence.val[j - 1].val[0].type,
2076 &asn1_oid_id_at_commonName))
2078 ret = HX509_PROXY_CERT_NAME_WRONG;
2079 hx509_set_error_string(context, 0, ret,
2080 "Proxy name too short or "
2081 "does not have Common name "
2082 "at the top");
2083 goto out;
2086 free_RelativeDistinguishedName(&proxy_issuer.u.rdnSequence.val[j - 1]);
2087 proxy_issuer.u.rdnSequence.len -= 1;
2089 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.issuer, &diff);
2090 if (ret) {
2091 hx509_set_error_string(context, 0, ret, "Out of memory");
2092 goto out;
2094 if (diff != 0) {
2095 ret = HX509_PROXY_CERT_NAME_WRONG;
2096 hx509_set_error_string(context, 0, ret,
2097 "Proxy issuer name not as expected");
2098 goto out;
2101 break;
2102 } else {
2104 * Now we are done with the proxy certificates, this
2105 * cert was an EE cert and we we will fall though to
2106 * EE checking below.
2108 type = EE_CERT;
2109 /* FALLTHOUGH */
2112 case EE_CERT:
2114 * If there where any proxy certificates in the chain
2115 * (proxy_cert_depth > 0), check that the proxy issuer
2116 * matched proxy certificates "base" subject.
2118 if (proxy_cert_depth) {
2120 ret = _hx509_name_cmp(&proxy_issuer,
2121 &c->tbsCertificate.subject, &diff);
2122 if (ret) {
2123 hx509_set_error_string(context, 0, ret, "out of memory");
2124 goto out;
2126 if (diff) {
2127 ret = HX509_PROXY_CERT_NAME_WRONG;
2128 hx509_clear_error_string(context);
2129 goto out;
2131 if (cert->basename)
2132 hx509_name_free(&cert->basename);
2134 ret = _hx509_name_from_Name(&proxy_issuer, &cert->basename);
2135 if (ret) {
2136 hx509_clear_error_string(context);
2137 goto out;
2141 break;
2144 ret = check_basic_constraints(context, c, type,
2145 i - proxy_cert_depth - selfsigned_depth);
2146 if (ret)
2147 goto out;
2150 * Don't check the trust anchors expiration time since they
2151 * are transported out of band, from RFC3820.
2153 if (i + 1 != path.len || CHECK_TA(ctx)) {
2155 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2156 if (t > ctx->time_now) {
2157 ret = HX509_CERT_USED_BEFORE_TIME;
2158 hx509_clear_error_string(context);
2159 goto out;
2161 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2162 if (t < ctx->time_now) {
2163 ret = HX509_CERT_USED_AFTER_TIME;
2164 hx509_clear_error_string(context);
2165 goto out;
2169 if (type == EE_CERT)
2170 type = CA_CERT;
2171 else if (type == PROXY_CERT)
2172 proxy_cert_depth++;
2176 * Verify constraints, do this backward so path constraints are
2177 * checked in the right order.
2180 for (ret = 0, i = path.len - 1; i >= 0; i--) {
2181 Certificate *c;
2182 int selfsigned;
2184 c = _hx509_get_cert(path.val[i]);
2186 ret = certificate_is_self_signed(context, c, &selfsigned);
2187 if (ret)
2188 goto out;
2190 /* verify name constraints, not for selfsigned and anchor */
2191 if (!selfsigned || i + 1 != path.len) {
2192 ret = check_name_constraints(context, &nc, c);
2193 if (ret) {
2194 goto out;
2197 ret = add_name_constraints(context, c, i == 0, &nc);
2198 if (ret)
2199 goto out;
2201 /* XXX verify all other silly constraints */
2206 * Verify that no certificates has been revoked.
2209 if (ctx->revoke_ctx) {
2210 hx509_certs certs;
2212 ret = hx509_certs_init(context, "MEMORY:revoke-certs", 0,
2213 NULL, &certs);
2214 if (ret)
2215 goto out;
2217 for (i = 0; i < path.len; i++) {
2218 ret = hx509_certs_add(context, certs, path.val[i]);
2219 if (ret) {
2220 hx509_certs_free(&certs);
2221 goto out;
2224 ret = hx509_certs_merge(context, certs, pool);
2225 if (ret) {
2226 hx509_certs_free(&certs);
2227 goto out;
2230 for (i = 0; i < path.len - 1; i++) {
2231 int parent = (i < path.len - 1) ? i + 1 : i;
2233 ret = hx509_revoke_verify(context,
2234 ctx->revoke_ctx,
2235 certs,
2236 ctx->time_now,
2237 path.val[i],
2238 path.val[parent]);
2239 if (ret) {
2240 hx509_certs_free(&certs);
2241 goto out;
2244 hx509_certs_free(&certs);
2248 * Verify signatures, do this backward so public key working
2249 * parameter is passed up from the anchor up though the chain.
2252 for (i = path.len - 1; i >= 0; i--) {
2253 hx509_cert signer;
2254 Certificate *c;
2256 c = _hx509_get_cert(path.val[i]);
2258 /* is last in chain (trust anchor) */
2259 if (i + 1 == path.len) {
2260 int selfsigned;
2262 signer = path.val[i];
2264 ret = certificate_is_self_signed(context, signer->data, &selfsigned);
2265 if (ret)
2266 goto out;
2268 /* if trust anchor is not self signed, don't check sig */
2269 if (!selfsigned)
2270 continue;
2271 } else {
2272 /* take next certificate in chain */
2273 signer = path.val[i + 1];
2276 /* verify signatureValue */
2277 ret = _hx509_verify_signature_bitstring(context,
2278 signer,
2279 &c->signatureAlgorithm,
2280 &c->tbsCertificate._save,
2281 &c->signatureValue);
2282 if (ret) {
2283 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
2284 "Failed to verify signature of certificate");
2285 goto out;
2288 * Verify that the sigature algorithm "best-before" date is
2289 * before the creation date of the certificate, do this for
2290 * trust anchors too, since any trust anchor that is created
2291 * after a algorithm is known to be bad deserved to be invalid.
2293 * Skip the leaf certificate for now...
2296 if (i != 0 && (ctx->flags & HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK) == 0) {
2297 time_t notBefore =
2298 _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2299 ret = _hx509_signature_best_before(context,
2300 &c->signatureAlgorithm,
2301 notBefore);
2302 if (ret)
2303 goto out;
2307 out:
2308 hx509_certs_free(&anchors);
2309 free_Name(&proxy_issuer);
2310 free_name_constraints(&nc);
2311 _hx509_path_free(&path);
2313 return ret;
2317 * Verify a signature made using the private key of an certificate.
2319 * @param context A hx509 context.
2320 * @param signer the certificate that made the signature.
2321 * @param alg algorthm that was used to sign the data.
2322 * @param data the data that was signed.
2323 * @param sig the sigature to verify.
2325 * @return An hx509 error code, see hx509_get_error_string().
2327 * @ingroup hx509_crypto
2331 hx509_verify_signature(hx509_context context,
2332 const hx509_cert signer,
2333 const AlgorithmIdentifier *alg,
2334 const heim_octet_string *data,
2335 const heim_octet_string *sig)
2337 return _hx509_verify_signature(context, signer, alg, data, sig);
2341 _hx509_verify_signature_bitstring(hx509_context context,
2342 const hx509_cert signer,
2343 const AlgorithmIdentifier *alg,
2344 const heim_octet_string *data,
2345 const heim_bit_string *sig)
2347 heim_octet_string os;
2349 if (sig->length & 7) {
2350 hx509_set_error_string(context, 0, HX509_CRYPTO_SIG_INVALID_FORMAT,
2351 "signature not multiple of 8 bits");
2352 return HX509_CRYPTO_SIG_INVALID_FORMAT;
2355 os.data = sig->data;
2356 os.length = sig->length / 8;
2358 return _hx509_verify_signature(context, signer, alg, data, &os);
2364 * Verify that the certificate is allowed to be used for the hostname
2365 * and address.
2367 * @param context A hx509 context.
2368 * @param cert the certificate to match with
2369 * @param flags Flags to modify the behavior:
2370 * - HX509_VHN_F_ALLOW_NO_MATCH no match is ok
2371 * @param type type of hostname:
2372 * - HX509_HN_HOSTNAME for plain hostname.
2373 * - HX509_HN_DNSSRV for DNS SRV names.
2374 * @param hostname the hostname to check
2375 * @param sa address of the host
2376 * @param sa_size length of address
2378 * @return An hx509 error code, see hx509_get_error_string().
2380 * @ingroup hx509_cert
2384 hx509_verify_hostname(hx509_context context,
2385 const hx509_cert cert,
2386 int flags,
2387 hx509_hostname_type type,
2388 const char *hostname,
2389 const struct sockaddr *sa,
2390 /* XXX krb5_socklen_t */ int sa_size)
2392 GeneralNames san;
2393 const Name *name;
2394 int ret, i, j;
2396 if (sa && sa_size <= 0)
2397 return EINVAL;
2399 memset(&san, 0, sizeof(san));
2401 i = 0;
2402 do {
2403 ret = find_extension_subject_alt_name(cert->data, &i, &san);
2404 if (ret == HX509_EXTENSION_NOT_FOUND)
2405 break;
2406 else if (ret != 0)
2407 return HX509_PARSING_NAME_FAILED;
2409 for (j = 0; j < san.len; j++) {
2410 switch (san.val[j].element) {
2411 case choice_GeneralName_dNSName: {
2412 heim_printable_string hn;
2413 hn.data = rk_UNCONST(hostname);
2414 hn.length = strlen(hostname);
2416 if (der_printable_string_cmp(&san.val[j].u.dNSName, &hn) == 0) {
2417 free_GeneralNames(&san);
2418 return 0;
2420 break;
2422 default:
2423 break;
2426 free_GeneralNames(&san);
2427 } while (1);
2429 name = &cert->data->tbsCertificate.subject;
2431 /* Find first CN= in the name, and try to match the hostname on that */
2432 for (ret = 0, i = name->u.rdnSequence.len - 1; ret == 0 && i >= 0; i--) {
2433 for (j = 0; ret == 0 && j < name->u.rdnSequence.val[i].len; j++) {
2434 AttributeTypeAndValue *n = &name->u.rdnSequence.val[i].val[j];
2436 if (der_heim_oid_cmp(&n->type, &asn1_oid_id_at_commonName) == 0) {
2437 DirectoryString *ds = &n->value;
2438 switch (ds->element) {
2439 case choice_DirectoryString_printableString: {
2440 heim_printable_string hn;
2441 hn.data = rk_UNCONST(hostname);
2442 hn.length = strlen(hostname);
2444 if (der_printable_string_cmp(&ds->u.printableString, &hn) == 0)
2445 return 0;
2446 break;
2448 case choice_DirectoryString_ia5String: {
2449 heim_ia5_string hn;
2450 hn.data = rk_UNCONST(hostname);
2451 hn.length = strlen(hostname);
2453 if (der_ia5_string_cmp(&ds->u.ia5String, &hn) == 0)
2454 return 0;
2455 break;
2457 case choice_DirectoryString_utf8String:
2458 if (strcasecmp(ds->u.utf8String, hostname) == 0)
2459 return 0;
2460 default:
2461 break;
2463 ret = HX509_NAME_CONSTRAINT_ERROR;
2468 if ((flags & HX509_VHN_F_ALLOW_NO_MATCH) == 0)
2469 ret = HX509_NAME_CONSTRAINT_ERROR;
2471 return ret;
2475 _hx509_set_cert_attribute(hx509_context context,
2476 hx509_cert cert,
2477 const heim_oid *oid,
2478 const heim_octet_string *attr)
2480 hx509_cert_attribute a;
2481 void *d;
2483 if (hx509_cert_get_attribute(cert, oid) != NULL)
2484 return 0;
2486 d = realloc(cert->attrs.val,
2487 sizeof(cert->attrs.val[0]) * (cert->attrs.len + 1));
2488 if (d == NULL) {
2489 hx509_clear_error_string(context);
2490 return ENOMEM;
2492 cert->attrs.val = d;
2494 a = malloc(sizeof(*a));
2495 if (a == NULL)
2496 return ENOMEM;
2498 der_copy_octet_string(attr, &a->data);
2499 der_copy_oid(oid, &a->oid);
2501 cert->attrs.val[cert->attrs.len] = a;
2502 cert->attrs.len++;
2504 return 0;
2508 * Get an external attribute for the certificate, examples are
2509 * friendly name and id.
2511 * @param cert hx509 certificate object to search
2512 * @param oid an oid to search for.
2514 * @return an hx509_cert_attribute, only valid as long as the
2515 * certificate is referenced.
2517 * @ingroup hx509_cert
2520 hx509_cert_attribute
2521 hx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid)
2523 int i;
2524 for (i = 0; i < cert->attrs.len; i++)
2525 if (der_heim_oid_cmp(oid, &cert->attrs.val[i]->oid) == 0)
2526 return cert->attrs.val[i];
2527 return NULL;
2531 * Set the friendly name on the certificate.
2533 * @param cert The certificate to set the friendly name on
2534 * @param name Friendly name.
2536 * @return An hx509 error code, see hx509_get_error_string().
2538 * @ingroup hx509_cert
2542 hx509_cert_set_friendly_name(hx509_cert cert, const char *name)
2544 if (cert->friendlyname)
2545 free(cert->friendlyname);
2546 cert->friendlyname = strdup(name);
2547 if (cert->friendlyname == NULL)
2548 return ENOMEM;
2549 return 0;
2553 * Get friendly name of the certificate.
2555 * @param cert cert to get the friendly name from.
2557 * @return an friendly name or NULL if there is. The friendly name is
2558 * only valid as long as the certificate is referenced.
2560 * @ingroup hx509_cert
2563 const char *
2564 hx509_cert_get_friendly_name(hx509_cert cert)
2566 hx509_cert_attribute a;
2567 PKCS9_friendlyName n;
2568 size_t sz;
2569 int ret, i;
2571 if (cert->friendlyname)
2572 return cert->friendlyname;
2574 a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_friendlyName);
2575 if (a == NULL) {
2576 hx509_name name;
2578 ret = hx509_cert_get_subject(cert, &name);
2579 if (ret)
2580 return NULL;
2581 ret = hx509_name_to_string(name, &cert->friendlyname);
2582 hx509_name_free(&name);
2583 if (ret)
2584 return NULL;
2585 return cert->friendlyname;
2588 ret = decode_PKCS9_friendlyName(a->data.data, a->data.length, &n, &sz);
2589 if (ret)
2590 return NULL;
2592 if (n.len != 1) {
2593 free_PKCS9_friendlyName(&n);
2594 return NULL;
2597 cert->friendlyname = malloc(n.val[0].length + 1);
2598 if (cert->friendlyname == NULL) {
2599 free_PKCS9_friendlyName(&n);
2600 return NULL;
2603 for (i = 0; i < n.val[0].length; i++) {
2604 if (n.val[0].data[i] <= 0xff)
2605 cert->friendlyname[i] = n.val[0].data[i] & 0xff;
2606 else
2607 cert->friendlyname[i] = 'X';
2609 cert->friendlyname[i] = '\0';
2610 free_PKCS9_friendlyName(&n);
2612 return cert->friendlyname;
2615 void
2616 _hx509_query_clear(hx509_query *q)
2618 memset(q, 0, sizeof(*q));
2622 * Allocate an query controller. Free using hx509_query_free().
2624 * @param context A hx509 context.
2625 * @param q return pointer to a hx509_query.
2627 * @return An hx509 error code, see hx509_get_error_string().
2629 * @ingroup hx509_cert
2633 hx509_query_alloc(hx509_context context, hx509_query **q)
2635 *q = calloc(1, sizeof(**q));
2636 if (*q == NULL)
2637 return ENOMEM;
2638 return 0;
2643 * Set match options for the hx509 query controller.
2645 * @param q query controller.
2646 * @param option options to control the query controller.
2648 * @return An hx509 error code, see hx509_get_error_string().
2650 * @ingroup hx509_cert
2653 void
2654 hx509_query_match_option(hx509_query *q, hx509_query_option option)
2656 switch(option) {
2657 case HX509_QUERY_OPTION_PRIVATE_KEY:
2658 q->match |= HX509_QUERY_PRIVATE_KEY;
2659 break;
2660 case HX509_QUERY_OPTION_KU_ENCIPHERMENT:
2661 q->match |= HX509_QUERY_KU_ENCIPHERMENT;
2662 break;
2663 case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE:
2664 q->match |= HX509_QUERY_KU_DIGITALSIGNATURE;
2665 break;
2666 case HX509_QUERY_OPTION_KU_KEYCERTSIGN:
2667 q->match |= HX509_QUERY_KU_KEYCERTSIGN;
2668 break;
2669 case HX509_QUERY_OPTION_END:
2670 default:
2671 break;
2676 * Set the issuer and serial number of match in the query
2677 * controller. The function make copies of the isser and serial number.
2679 * @param q a hx509 query controller
2680 * @param issuer issuer to search for
2681 * @param serialNumber the serialNumber of the issuer.
2683 * @return An hx509 error code, see hx509_get_error_string().
2685 * @ingroup hx509_cert
2689 hx509_query_match_issuer_serial(hx509_query *q,
2690 const Name *issuer,
2691 const heim_integer *serialNumber)
2693 int ret;
2694 if (q->serial) {
2695 der_free_heim_integer(q->serial);
2696 free(q->serial);
2698 q->serial = malloc(sizeof(*q->serial));
2699 if (q->serial == NULL)
2700 return ENOMEM;
2701 ret = der_copy_heim_integer(serialNumber, q->serial);
2702 if (ret) {
2703 free(q->serial);
2704 q->serial = NULL;
2705 return ret;
2707 if (q->issuer_name) {
2708 free_Name(q->issuer_name);
2709 free(q->issuer_name);
2711 q->issuer_name = malloc(sizeof(*q->issuer_name));
2712 if (q->issuer_name == NULL)
2713 return ENOMEM;
2714 ret = copy_Name(issuer, q->issuer_name);
2715 if (ret) {
2716 free(q->issuer_name);
2717 q->issuer_name = NULL;
2718 return ret;
2720 q->match |= HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
2721 return 0;
2725 * Set the query controller to match on a friendly name
2727 * @param q a hx509 query controller.
2728 * @param name a friendly name to match on
2730 * @return An hx509 error code, see hx509_get_error_string().
2732 * @ingroup hx509_cert
2736 hx509_query_match_friendly_name(hx509_query *q, const char *name)
2738 if (q->friendlyname)
2739 free(q->friendlyname);
2740 q->friendlyname = strdup(name);
2741 if (q->friendlyname == NULL)
2742 return ENOMEM;
2743 q->match |= HX509_QUERY_MATCH_FRIENDLY_NAME;
2744 return 0;
2748 * Set the query controller to require an one specific EKU (extended
2749 * key usage). Any previous EKU matching is overwitten. If NULL is
2750 * passed in as the eku, the EKU requirement is reset.
2752 * @param q a hx509 query controller.
2753 * @param eku an EKU to match on.
2755 * @return An hx509 error code, see hx509_get_error_string().
2757 * @ingroup hx509_cert
2761 hx509_query_match_eku(hx509_query *q, const heim_oid *eku)
2763 int ret;
2765 if (eku == NULL) {
2766 if (q->eku) {
2767 der_free_oid(q->eku);
2768 free(q->eku);
2769 q->eku = NULL;
2771 q->match &= ~HX509_QUERY_MATCH_EKU;
2772 } else {
2773 if (q->eku) {
2774 der_free_oid(q->eku);
2775 } else {
2776 q->eku = calloc(1, sizeof(*q->eku));
2777 if (q->eku == NULL)
2778 return ENOMEM;
2780 ret = der_copy_oid(eku, q->eku);
2781 if (ret) {
2782 free(q->eku);
2783 q->eku = NULL;
2784 return ret;
2786 q->match |= HX509_QUERY_MATCH_EKU;
2788 return 0;
2792 hx509_query_match_expr(hx509_context context, hx509_query *q, const char *expr)
2794 if (q->expr) {
2795 _hx509_expr_free(q->expr);
2796 q->expr = NULL;
2799 if (expr == NULL) {
2800 q->match &= ~HX509_QUERY_MATCH_EXPR;
2801 } else {
2802 q->expr = _hx509_expr_parse(expr);
2803 if (q->expr)
2804 q->match |= HX509_QUERY_MATCH_EXPR;
2807 return 0;
2811 * Set the query controller to match using a specific match function.
2813 * @param q a hx509 query controller.
2814 * @param func function to use for matching, if the argument is NULL,
2815 * the match function is removed.
2816 * @param ctx context passed to the function.
2818 * @return An hx509 error code, see hx509_get_error_string().
2820 * @ingroup hx509_cert
2824 hx509_query_match_cmp_func(hx509_query *q,
2825 int (*func)(hx509_context, hx509_cert, void *),
2826 void *ctx)
2828 if (func)
2829 q->match |= HX509_QUERY_MATCH_FUNCTION;
2830 else
2831 q->match &= ~HX509_QUERY_MATCH_FUNCTION;
2832 q->cmp_func = func;
2833 q->cmp_func_ctx = ctx;
2834 return 0;
2838 * Free the query controller.
2840 * @param context A hx509 context.
2841 * @param q a pointer to the query controller.
2843 * @ingroup hx509_cert
2846 void
2847 hx509_query_free(hx509_context context, hx509_query *q)
2849 if (q == NULL)
2850 return;
2852 if (q->serial) {
2853 der_free_heim_integer(q->serial);
2854 free(q->serial);
2856 if (q->issuer_name) {
2857 free_Name(q->issuer_name);
2858 free(q->issuer_name);
2860 if (q->eku) {
2861 der_free_oid(q->eku);
2862 free(q->eku);
2864 if (q->friendlyname)
2865 free(q->friendlyname);
2866 if (q->expr)
2867 _hx509_expr_free(q->expr);
2869 memset(q, 0, sizeof(*q));
2870 free(q);
2874 _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert cert)
2876 Certificate *c = _hx509_get_cert(cert);
2877 int ret, diff;
2879 _hx509_query_statistic(context, 1, q);
2881 if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) &&
2882 _hx509_cert_is_parent_cmp(q->subject, c, 0) != 0)
2883 return 0;
2885 if ((q->match & HX509_QUERY_MATCH_CERTIFICATE) &&
2886 _hx509_Certificate_cmp(q->certificate, c) != 0)
2887 return 0;
2889 if ((q->match & HX509_QUERY_MATCH_SERIALNUMBER)
2890 && der_heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0)
2891 return 0;
2893 if (q->match & HX509_QUERY_MATCH_ISSUER_NAME) {
2894 ret = _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name, &diff);
2895 if (ret || diff)
2896 return 0;
2899 if (q->match & HX509_QUERY_MATCH_SUBJECT_NAME) {
2900 ret = _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name, &diff);
2901 if (ret || diff)
2902 return 0;
2905 if (q->match & HX509_QUERY_MATCH_SUBJECT_KEY_ID) {
2906 SubjectKeyIdentifier si;
2908 ret = _hx509_find_extension_subject_key_id(c, &si);
2909 if (ret == 0) {
2910 if (der_heim_octet_string_cmp(&si, q->subject_id) != 0)
2911 ret = 1;
2912 free_SubjectKeyIdentifier(&si);
2914 if (ret)
2915 return 0;
2917 if ((q->match & HX509_QUERY_MATCH_ISSUER_ID))
2918 return 0;
2919 if ((q->match & HX509_QUERY_PRIVATE_KEY) &&
2920 _hx509_cert_private_key(cert) == NULL)
2921 return 0;
2924 unsigned ku = 0;
2925 if (q->match & HX509_QUERY_KU_DIGITALSIGNATURE)
2926 ku |= (1 << 0);
2927 if (q->match & HX509_QUERY_KU_NONREPUDIATION)
2928 ku |= (1 << 1);
2929 if (q->match & HX509_QUERY_KU_ENCIPHERMENT)
2930 ku |= (1 << 2);
2931 if (q->match & HX509_QUERY_KU_DATAENCIPHERMENT)
2932 ku |= (1 << 3);
2933 if (q->match & HX509_QUERY_KU_KEYAGREEMENT)
2934 ku |= (1 << 4);
2935 if (q->match & HX509_QUERY_KU_KEYCERTSIGN)
2936 ku |= (1 << 5);
2937 if (q->match & HX509_QUERY_KU_CRLSIGN)
2938 ku |= (1 << 6);
2939 if (ku && check_key_usage(context, c, ku, TRUE))
2940 return 0;
2942 if ((q->match & HX509_QUERY_ANCHOR))
2943 return 0;
2945 if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) {
2946 hx509_cert_attribute a;
2948 a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_localKeyId);
2949 if (a == NULL)
2950 return 0;
2951 if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0)
2952 return 0;
2955 if (q->match & HX509_QUERY_NO_MATCH_PATH) {
2956 size_t i;
2958 for (i = 0; i < q->path->len; i++)
2959 if (hx509_cert_cmp(q->path->val[i], cert) == 0)
2960 return 0;
2962 if (q->match & HX509_QUERY_MATCH_FRIENDLY_NAME) {
2963 const char *name = hx509_cert_get_friendly_name(cert);
2964 if (name == NULL)
2965 return 0;
2966 if (strcasecmp(q->friendlyname, name) != 0)
2967 return 0;
2969 if (q->match & HX509_QUERY_MATCH_FUNCTION) {
2970 ret = (*q->cmp_func)(context, cert, q->cmp_func_ctx);
2971 if (ret != 0)
2972 return 0;
2975 if (q->match & HX509_QUERY_MATCH_KEY_HASH_SHA1) {
2976 heim_octet_string os;
2978 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
2979 os.length =
2980 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
2982 ret = _hx509_verify_signature(context,
2983 NULL,
2984 hx509_signature_sha1(),
2985 &os,
2986 q->keyhash_sha1);
2987 if (ret != 0)
2988 return 0;
2991 if (q->match & HX509_QUERY_MATCH_TIME) {
2992 time_t t;
2993 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2994 if (t > q->timenow)
2995 return 0;
2996 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2997 if (t < q->timenow)
2998 return 0;
3001 /* If an EKU is required, check the cert for it. */
3002 if ((q->match & HX509_QUERY_MATCH_EKU) &&
3003 hx509_cert_check_eku(context, cert, q->eku, 0))
3004 return 0;
3006 if ((q->match & HX509_QUERY_MATCH_EXPR)) {
3007 hx509_env env = NULL;
3009 ret = _hx509_cert_to_env(context, cert, &env);
3010 if (ret)
3011 return 0;
3013 ret = _hx509_expr_eval(context, env, q->expr);
3014 hx509_env_free(&env);
3015 if (ret == 0)
3016 return 0;
3019 if (q->match & ~HX509_QUERY_MASK)
3020 return 0;
3022 return 1;
3026 * Set a statistic file for the query statistics.
3028 * @param context A hx509 context.
3029 * @param fn statistics file name
3031 * @ingroup hx509_cert
3034 void
3035 hx509_query_statistic_file(hx509_context context, const char *fn)
3037 if (context->querystat)
3038 free(context->querystat);
3039 context->querystat = strdup(fn);
3042 void
3043 _hx509_query_statistic(hx509_context context, int type, const hx509_query *q)
3045 FILE *f;
3046 if (context->querystat == NULL)
3047 return;
3048 f = fopen(context->querystat, "a");
3049 if (f == NULL)
3050 return;
3051 rk_cloexec_file(f);
3052 fprintf(f, "%d %d\n", type, q->match);
3053 fclose(f);
3056 static const char *statname[] = {
3057 "find issuer cert",
3058 "match serialnumber",
3059 "match issuer name",
3060 "match subject name",
3061 "match subject key id",
3062 "match issuer id",
3063 "private key",
3064 "ku encipherment",
3065 "ku digitalsignature",
3066 "ku keycertsign",
3067 "ku crlsign",
3068 "ku nonrepudiation",
3069 "ku keyagreement",
3070 "ku dataencipherment",
3071 "anchor",
3072 "match certificate",
3073 "match local key id",
3074 "no match path",
3075 "match friendly name",
3076 "match function",
3077 "match key hash sha1",
3078 "match time"
3081 struct stat_el {
3082 unsigned long stats;
3083 unsigned int index;
3087 static int
3088 stat_sort(const void *a, const void *b)
3090 const struct stat_el *ae = a;
3091 const struct stat_el *be = b;
3092 return be->stats - ae->stats;
3096 * Unparse the statistics file and print the result on a FILE descriptor.
3098 * @param context A hx509 context.
3099 * @param printtype tyep to print
3100 * @param out the FILE to write the data on.
3102 * @ingroup hx509_cert
3105 void
3106 hx509_query_unparse_stats(hx509_context context, int printtype, FILE *out)
3108 rtbl_t t;
3109 FILE *f;
3110 int type, mask, i, num;
3111 unsigned long multiqueries = 0, totalqueries = 0;
3112 struct stat_el stats[32];
3114 if (context->querystat == NULL)
3115 return;
3116 f = fopen(context->querystat, "r");
3117 if (f == NULL) {
3118 fprintf(out, "No statistic file %s: %s.\n",
3119 context->querystat, strerror(errno));
3120 return;
3122 rk_cloexec_file(f);
3124 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
3125 stats[i].index = i;
3126 stats[i].stats = 0;
3129 while (fscanf(f, "%d %d\n", &type, &mask) == 2) {
3130 if (type != printtype)
3131 continue;
3132 num = i = 0;
3133 while (mask && i < sizeof(stats)/sizeof(stats[0])) {
3134 if (mask & 1) {
3135 stats[i].stats++;
3136 num++;
3138 mask = mask >>1 ;
3139 i++;
3141 if (num > 1)
3142 multiqueries++;
3143 totalqueries++;
3145 fclose(f);
3147 qsort(stats, sizeof(stats)/sizeof(stats[0]), sizeof(stats[0]), stat_sort);
3149 t = rtbl_create();
3150 if (t == NULL)
3151 errx(1, "out of memory");
3153 rtbl_set_separator (t, " ");
3155 rtbl_add_column_by_id (t, 0, "Name", 0);
3156 rtbl_add_column_by_id (t, 1, "Counter", 0);
3159 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
3160 char str[10];
3162 if (stats[i].index < sizeof(statname)/sizeof(statname[0]))
3163 rtbl_add_column_entry_by_id (t, 0, statname[stats[i].index]);
3164 else {
3165 snprintf(str, sizeof(str), "%d", stats[i].index);
3166 rtbl_add_column_entry_by_id (t, 0, str);
3168 snprintf(str, sizeof(str), "%lu", stats[i].stats);
3169 rtbl_add_column_entry_by_id (t, 1, str);
3172 rtbl_format(t, out);
3173 rtbl_destroy(t);
3175 fprintf(out, "\nQueries: multi %lu total %lu\n",
3176 multiqueries, totalqueries);
3180 * Check the extended key usage on the hx509 certificate.
3182 * @param context A hx509 context.
3183 * @param cert A hx509 context.
3184 * @param eku the EKU to check for
3185 * @param allow_any_eku if the any EKU is set, allow that to be a
3186 * substitute.
3188 * @return An hx509 error code, see hx509_get_error_string().
3190 * @ingroup hx509_cert
3194 hx509_cert_check_eku(hx509_context context, hx509_cert cert,
3195 const heim_oid *eku, int allow_any_eku)
3197 ExtKeyUsage e;
3198 int ret, i;
3200 ret = find_extension_eku(_hx509_get_cert(cert), &e);
3201 if (ret) {
3202 hx509_clear_error_string(context);
3203 return ret;
3206 for (i = 0; i < e.len; i++) {
3207 if (der_heim_oid_cmp(eku, &e.val[i]) == 0) {
3208 free_ExtKeyUsage(&e);
3209 return 0;
3211 if (allow_any_eku) {
3212 #if 0
3213 if (der_heim_oid_cmp(id_any_eku, &e.val[i]) == 0) {
3214 free_ExtKeyUsage(&e);
3215 return 0;
3217 #endif
3220 free_ExtKeyUsage(&e);
3221 hx509_clear_error_string(context);
3222 return HX509_CERTIFICATE_MISSING_EKU;
3226 _hx509_cert_get_keyusage(hx509_context context,
3227 hx509_cert c,
3228 KeyUsage *ku)
3230 Certificate *cert;
3231 const Extension *e;
3232 size_t size;
3233 int ret, i = 0;
3235 memset(ku, 0, sizeof(*ku));
3237 cert = _hx509_get_cert(c);
3239 if (_hx509_cert_get_version(cert) < 3)
3240 return 0;
3242 e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i);
3243 if (e == NULL)
3244 return HX509_KU_CERT_MISSING;
3246 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, ku, &size);
3247 if (ret)
3248 return ret;
3249 return 0;
3253 _hx509_cert_get_eku(hx509_context context,
3254 hx509_cert cert,
3255 ExtKeyUsage *e)
3257 int ret;
3259 memset(e, 0, sizeof(*e));
3261 ret = find_extension_eku(_hx509_get_cert(cert), e);
3262 if (ret && ret != HX509_EXTENSION_NOT_FOUND) {
3263 hx509_clear_error_string(context);
3264 return ret;
3266 return 0;
3270 * Encodes the hx509 certificate as a DER encode binary.
3272 * @param context A hx509 context.
3273 * @param c the certificate to encode.
3274 * @param os the encode certificate, set to NULL, 0 on case of
3275 * error. Free the os->data with hx509_xfree().
3277 * @return An hx509 error code, see hx509_get_error_string().
3279 * @ingroup hx509_cert
3283 hx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os)
3285 size_t size;
3286 int ret;
3288 os->data = NULL;
3289 os->length = 0;
3291 ASN1_MALLOC_ENCODE(Certificate, os->data, os->length,
3292 _hx509_get_cert(c), &size, ret);
3293 if (ret) {
3294 os->data = NULL;
3295 os->length = 0;
3296 return ret;
3298 if (os->length != size)
3299 _hx509_abort("internal ASN.1 encoder error");
3301 return ret;
3305 * Last to avoid lost __attribute__s due to #undef.
3308 #undef __attribute__
3309 #define __attribute__(X)
3311 void
3312 _hx509_abort(const char *fmt, ...)
3313 __attribute__ ((noreturn, format (printf, 1, 2)))
3315 va_list ap;
3316 va_start(ap, fmt);
3317 vprintf(fmt, ap);
3318 va_end(ap);
3319 printf("\n");
3320 fflush(stdout);
3321 abort();
3325 * Free a data element allocated in the library.
3327 * @param ptr data to be freed.
3329 * @ingroup hx509_misc
3332 void
3333 hx509_xfree(void *ptr)
3335 free(ptr);
3343 _hx509_cert_to_env(hx509_context context, hx509_cert cert, hx509_env *env)
3345 ExtKeyUsage eku;
3346 hx509_name name;
3347 char *buf;
3348 int ret;
3349 hx509_env envcert = NULL;
3351 *env = NULL;
3353 /* version */
3354 asprintf(&buf, "%d", _hx509_cert_get_version(_hx509_get_cert(cert)));
3355 ret = hx509_env_add(context, &envcert, "version", buf);
3356 free(buf);
3357 if (ret)
3358 goto out;
3360 /* subject */
3361 ret = hx509_cert_get_subject(cert, &name);
3362 if (ret)
3363 goto out;
3365 ret = hx509_name_to_string(name, &buf);
3366 if (ret) {
3367 hx509_name_free(&name);
3368 goto out;
3371 ret = hx509_env_add(context, &envcert, "subject", buf);
3372 hx509_name_free(&name);
3373 if (ret)
3374 goto out;
3376 /* issuer */
3377 ret = hx509_cert_get_issuer(cert, &name);
3378 if (ret)
3379 goto out;
3381 ret = hx509_name_to_string(name, &buf);
3382 hx509_name_free(&name);
3383 if (ret)
3384 goto out;
3386 ret = hx509_env_add(context, &envcert, "issuer", buf);
3387 hx509_xfree(buf);
3388 if (ret)
3389 goto out;
3391 /* eku */
3393 ret = _hx509_cert_get_eku(context, cert, &eku);
3394 if (ret == HX509_EXTENSION_NOT_FOUND)
3396 else if (ret != 0)
3397 goto out;
3398 else {
3399 int i;
3400 hx509_env enveku = NULL;
3402 for (i = 0; i < eku.len; i++) {
3404 ret = der_print_heim_oid(&eku.val[i], '.', &buf);
3405 if (ret) {
3406 free_ExtKeyUsage(&eku);
3407 hx509_env_free(&enveku);
3408 goto out;
3410 ret = hx509_env_add(context, &enveku, buf, "oid-name-here");
3411 free(buf);
3412 if (ret) {
3413 free_ExtKeyUsage(&eku);
3414 hx509_env_free(&enveku);
3415 goto out;
3418 free_ExtKeyUsage(&eku);
3420 ret = hx509_env_add_binding(context, &envcert, "eku", enveku);
3421 if (ret) {
3422 hx509_env_free(&enveku);
3423 goto out;
3428 Certificate *c = _hx509_get_cert(cert);
3429 heim_octet_string os, sig;
3430 hx509_env envhash = NULL;
3432 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
3433 os.length =
3434 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
3436 ret = _hx509_create_signature(context,
3437 NULL,
3438 hx509_signature_sha1(),
3439 &os,
3440 NULL,
3441 &sig);
3442 if (ret != 0)
3443 goto out;
3445 ret = hex_encode(sig.data, sig.length, &buf);
3446 der_free_octet_string(&sig);
3447 if (ret < 0) {
3448 ret = ENOMEM;
3449 hx509_set_error_string(context, 0, ret,
3450 "Out of memory");
3451 goto out;
3454 ret = hx509_env_add(context, &envhash, "sha1", buf);
3455 free(buf);
3456 if (ret)
3457 goto out;
3459 ret = hx509_env_add_binding(context, &envcert, "hash", envhash);
3460 if (ret) {
3461 hx509_env_free(&envhash);
3462 goto out;
3466 ret = hx509_env_add_binding(context, env, "certificate", envcert);
3467 if (ret)
3468 goto out;
3470 return 0;
3472 out:
3473 hx509_env_free(&envcert);
3474 return ret;
3478 * Print a simple representation of a certificate
3480 * @param context A hx509 context, can be NULL
3481 * @param cert certificate to print
3482 * @param out the stdio output stream, if NULL, stdout is used
3484 * @return An hx509 error code
3486 * @ingroup hx509_cert
3490 hx509_print_cert(hx509_context context, hx509_cert cert, FILE *out)
3492 hx509_name name;
3493 char *str;
3494 int ret;
3496 if (out == NULL)
3497 out = stderr;
3499 ret = hx509_cert_get_issuer(cert, &name);
3500 if (ret)
3501 return ret;
3502 hx509_name_to_string(name, &str);
3503 hx509_name_free(&name);
3504 fprintf(out, " issuer: \"%s\"\n", str);
3505 free(str);
3507 ret = hx509_cert_get_subject(cert, &name);
3508 if (ret)
3509 return ret;
3510 hx509_name_to_string(name, &str);
3511 hx509_name_free(&name);
3512 fprintf(out, " subject: \"%s\"\n", str);
3513 free(str);
3516 heim_integer serialNumber;
3518 ret = hx509_cert_get_serialnumber(cert, &serialNumber);
3519 if (ret)
3520 return ret;
3521 ret = der_print_hex_heim_integer(&serialNumber, &str);
3522 if (ret)
3523 return ret;
3524 der_free_heim_integer(&serialNumber);
3525 fprintf(out, " serial: %s\n", str);
3526 free(str);
3529 printf(" keyusage: ");
3530 ret = hx509_cert_keyusage_print(context, cert, &str);
3531 if (ret == 0) {
3532 fprintf(out, "%s\n", str);
3533 free(str);
3534 } else
3535 fprintf(out, "no");
3537 return 0;