remove unused variable
[heimdal.git] / lib / hx509 / cert.c
blobc921194cf1a832c3c5a7a95405073823c6b7b69b
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 hx509_set_error_string(context, 0, HX509_EXTRA_DATA_AFTER_STRUCTURE,
287 "Extra data after certificate");
288 return HX509_EXTRA_DATA_AFTER_STRUCTURE;
291 ret = hx509_cert_init(context, &t, cert);
292 free_Certificate(&t);
293 return ret;
296 void
297 _hx509_cert_set_release(hx509_cert cert,
298 _hx509_cert_release_func release,
299 void *ctx)
301 cert->release = release;
302 cert->ctx = ctx;
306 /* Doesn't make a copy of `private_key'. */
309 _hx509_cert_assign_key(hx509_cert cert, hx509_private_key private_key)
311 if (cert->private_key)
312 _hx509_private_key_free(&cert->private_key);
313 cert->private_key = _hx509_private_key_ref(private_key);
314 return 0;
318 * Free reference to the hx509 certificate object, if the refcounter
319 * reaches 0, the object if freed. Its allowed to pass in NULL.
321 * @param cert the cert to free.
323 * @ingroup hx509_cert
326 void
327 hx509_cert_free(hx509_cert cert)
329 int i;
331 if (cert == NULL)
332 return;
334 if (cert->ref <= 0)
335 _hx509_abort("cert refcount <= 0 on free");
336 if (--cert->ref > 0)
337 return;
339 if (cert->release)
340 (cert->release)(cert, cert->ctx);
342 if (cert->private_key)
343 _hx509_private_key_free(&cert->private_key);
345 free_Certificate(cert->data);
346 free(cert->data);
348 for (i = 0; i < cert->attrs.len; i++) {
349 der_free_octet_string(&cert->attrs.val[i]->data);
350 der_free_oid(&cert->attrs.val[i]->oid);
351 free(cert->attrs.val[i]);
353 free(cert->attrs.val);
354 free(cert->friendlyname);
355 if (cert->basename)
356 hx509_name_free(&cert->basename);
357 memset(cert, 0, sizeof(cert));
358 free(cert);
362 * Add a reference to a hx509 certificate object.
364 * @param cert a pointer to an hx509 certificate object.
366 * @return the same object as is passed in.
368 * @ingroup hx509_cert
371 hx509_cert
372 hx509_cert_ref(hx509_cert cert)
374 if (cert == NULL)
375 return NULL;
376 if (cert->ref <= 0)
377 _hx509_abort("cert refcount <= 0");
378 cert->ref++;
379 if (cert->ref == 0)
380 _hx509_abort("cert refcount == 0");
381 return cert;
385 * Allocate an verification context that is used fo control the
386 * verification process.
388 * @param context A hx509 context.
389 * @param ctx returns a pointer to a hx509_verify_ctx object.
391 * @return An hx509 error code, see hx509_get_error_string().
393 * @ingroup hx509_verify
397 hx509_verify_init_ctx(hx509_context context, hx509_verify_ctx *ctx)
399 hx509_verify_ctx c;
401 c = calloc(1, sizeof(*c));
402 if (c == NULL)
403 return ENOMEM;
405 c->max_depth = HX509_VERIFY_MAX_DEPTH;
407 *ctx = c;
409 return 0;
413 * Free an hx509 verification context.
415 * @param ctx the context to be freed.
417 * @ingroup hx509_verify
420 void
421 hx509_verify_destroy_ctx(hx509_verify_ctx ctx)
423 if (ctx) {
424 hx509_certs_free(&ctx->trust_anchors);
425 hx509_revoke_free(&ctx->revoke_ctx);
426 memset(ctx, 0, sizeof(*ctx));
428 free(ctx);
432 * Set the trust anchors in the verification context, makes an
433 * reference to the keyset, so the consumer can free the keyset
434 * independent of the destruction of the verification context (ctx).
435 * If there already is a keyset attached, it's released.
437 * @param ctx a verification context
438 * @param set a keyset containing the trust anchors.
440 * @ingroup hx509_verify
443 void
444 hx509_verify_attach_anchors(hx509_verify_ctx ctx, hx509_certs set)
446 if (ctx->trust_anchors)
447 hx509_certs_free(&ctx->trust_anchors);
448 ctx->trust_anchors = hx509_certs_ref(set);
452 * Attach an revocation context to the verfication context, , makes an
453 * reference to the revoke context, so the consumer can free the
454 * revoke context independent of the destruction of the verification
455 * context. If there is no revoke context, the verification process is
456 * NOT going to check any verification status.
458 * @param ctx a verification context.
459 * @param revoke_ctx a revoke context.
461 * @ingroup hx509_verify
464 void
465 hx509_verify_attach_revoke(hx509_verify_ctx ctx, hx509_revoke_ctx revoke_ctx)
467 if (ctx->revoke_ctx)
468 hx509_revoke_free(&ctx->revoke_ctx);
469 ctx->revoke_ctx = _hx509_revoke_ref(revoke_ctx);
473 * Set the clock time the the verification process is going to
474 * use. Used to check certificate in the past and future time. If not
475 * set the current time will be used.
477 * @param ctx a verification context.
478 * @param t the time the verifiation is using.
481 * @ingroup hx509_verify
484 void
485 hx509_verify_set_time(hx509_verify_ctx ctx, time_t t)
487 ctx->flags |= HX509_VERIFY_CTX_F_TIME_SET;
488 ctx->time_now = t;
491 time_t
492 _hx509_verify_get_time(hx509_verify_ctx ctx)
494 return ctx->time_now;
498 * Set the maximum depth of the certificate chain that the path
499 * builder is going to try.
501 * @param ctx a verification context
502 * @param max_depth maxium depth of the certificate chain, include
503 * trust anchor.
505 * @ingroup hx509_verify
508 void
509 hx509_verify_set_max_depth(hx509_verify_ctx ctx, unsigned int max_depth)
511 ctx->max_depth = max_depth;
515 * Allow or deny the use of proxy certificates
517 * @param ctx a verification context
518 * @param boolean if non zero, allow proxy certificates.
520 * @ingroup hx509_verify
523 void
524 hx509_verify_set_proxy_certificate(hx509_verify_ctx ctx, int boolean)
526 if (boolean)
527 ctx->flags |= HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
528 else
529 ctx->flags &= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
533 * Select strict RFC3280 verification of certificiates. This means
534 * checking key usage on CA certificates, this will make version 1
535 * certificiates unuseable.
537 * @param ctx a verification context
538 * @param boolean if non zero, use strict verification.
540 * @ingroup hx509_verify
543 void
544 hx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx, int boolean)
546 if (boolean)
547 ctx->flags |= HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
548 else
549 ctx->flags &= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
553 * Allow using the operating system builtin trust anchors if no other
554 * trust anchors are configured.
556 * @param ctx a verification context
557 * @param boolean if non zero, useing the operating systems builtin
558 * trust anchors.
561 * @return An hx509 error code, see hx509_get_error_string().
563 * @ingroup hx509_cert
566 void
567 hx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx, int boolean)
569 if (boolean)
570 ctx->flags &= ~HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
571 else
572 ctx->flags |= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
575 void
576 hx509_verify_ctx_f_allow_best_before_signature_algs(hx509_context ctx,
577 int boolean)
579 if (boolean)
580 ctx->flags &= ~HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK;
581 else
582 ctx->flags |= HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK;
585 static const Extension *
586 find_extension(const Certificate *cert, const heim_oid *oid, int *idx)
588 const TBSCertificate *c = &cert->tbsCertificate;
590 if (c->version == NULL || *c->version < 2 || c->extensions == NULL)
591 return NULL;
593 for (;*idx < c->extensions->len; (*idx)++) {
594 if (der_heim_oid_cmp(&c->extensions->val[*idx].extnID, oid) == 0)
595 return &c->extensions->val[(*idx)++];
597 return NULL;
600 static int
601 find_extension_auth_key_id(const Certificate *subject,
602 AuthorityKeyIdentifier *ai)
604 const Extension *e;
605 size_t size;
606 int i = 0;
608 memset(ai, 0, sizeof(*ai));
610 e = find_extension(subject, &asn1_oid_id_x509_ce_authorityKeyIdentifier, &i);
611 if (e == NULL)
612 return HX509_EXTENSION_NOT_FOUND;
614 return decode_AuthorityKeyIdentifier(e->extnValue.data,
615 e->extnValue.length,
616 ai, &size);
620 _hx509_find_extension_subject_key_id(const Certificate *issuer,
621 SubjectKeyIdentifier *si)
623 const Extension *e;
624 size_t size;
625 int i = 0;
627 memset(si, 0, sizeof(*si));
629 e = find_extension(issuer, &asn1_oid_id_x509_ce_subjectKeyIdentifier, &i);
630 if (e == NULL)
631 return HX509_EXTENSION_NOT_FOUND;
633 return decode_SubjectKeyIdentifier(e->extnValue.data,
634 e->extnValue.length,
635 si, &size);
638 static int
639 find_extension_name_constraints(const Certificate *subject,
640 NameConstraints *nc)
642 const Extension *e;
643 size_t size;
644 int i = 0;
646 memset(nc, 0, sizeof(*nc));
648 e = find_extension(subject, &asn1_oid_id_x509_ce_nameConstraints, &i);
649 if (e == NULL)
650 return HX509_EXTENSION_NOT_FOUND;
652 return decode_NameConstraints(e->extnValue.data,
653 e->extnValue.length,
654 nc, &size);
657 static int
658 find_extension_subject_alt_name(const Certificate *cert, int *i,
659 GeneralNames *sa)
661 const Extension *e;
662 size_t size;
664 memset(sa, 0, sizeof(*sa));
666 e = find_extension(cert, &asn1_oid_id_x509_ce_subjectAltName, i);
667 if (e == NULL)
668 return HX509_EXTENSION_NOT_FOUND;
670 return decode_GeneralNames(e->extnValue.data,
671 e->extnValue.length,
672 sa, &size);
675 static int
676 find_extension_eku(const Certificate *cert, ExtKeyUsage *eku)
678 const Extension *e;
679 size_t size;
680 int i = 0;
682 memset(eku, 0, sizeof(*eku));
684 e = find_extension(cert, &asn1_oid_id_x509_ce_extKeyUsage, &i);
685 if (e == NULL)
686 return HX509_EXTENSION_NOT_FOUND;
688 return decode_ExtKeyUsage(e->extnValue.data,
689 e->extnValue.length,
690 eku, &size);
693 static int
694 add_to_list(hx509_octet_string_list *list, const heim_octet_string *entry)
696 void *p;
697 int ret;
699 p = realloc(list->val, (list->len + 1) * sizeof(list->val[0]));
700 if (p == NULL)
701 return ENOMEM;
702 list->val = p;
703 ret = der_copy_octet_string(entry, &list->val[list->len]);
704 if (ret)
705 return ret;
706 list->len++;
707 return 0;
711 * Free a list of octet strings returned by another hx509 library
712 * function.
714 * @param list list to be freed.
716 * @ingroup hx509_misc
719 void
720 hx509_free_octet_string_list(hx509_octet_string_list *list)
722 int i;
723 for (i = 0; i < list->len; i++)
724 der_free_octet_string(&list->val[i]);
725 free(list->val);
726 list->val = NULL;
727 list->len = 0;
731 * Return a list of subjectAltNames specified by oid in the
732 * certificate. On error the
734 * The returned list of octet string should be freed with
735 * hx509_free_octet_string_list().
737 * @param context A hx509 context.
738 * @param cert a hx509 certificate object.
739 * @param oid an oid to for SubjectAltName.
740 * @param list list of matching SubjectAltName.
742 * @return An hx509 error code, see hx509_get_error_string().
744 * @ingroup hx509_cert
748 hx509_cert_find_subjectAltName_otherName(hx509_context context,
749 hx509_cert cert,
750 const heim_oid *oid,
751 hx509_octet_string_list *list)
753 GeneralNames sa;
754 int ret, i, j;
756 list->val = NULL;
757 list->len = 0;
759 i = 0;
760 while (1) {
761 ret = find_extension_subject_alt_name(_hx509_get_cert(cert), &i, &sa);
762 i++;
763 if (ret == HX509_EXTENSION_NOT_FOUND) {
764 return 0;
765 } else if (ret != 0) {
766 hx509_set_error_string(context, 0, ret, "Error searching for SAN");
767 hx509_free_octet_string_list(list);
768 return ret;
771 for (j = 0; j < sa.len; j++) {
772 if (sa.val[j].element == choice_GeneralName_otherName &&
773 der_heim_oid_cmp(&sa.val[j].u.otherName.type_id, oid) == 0)
775 ret = add_to_list(list, &sa.val[j].u.otherName.value);
776 if (ret) {
777 hx509_set_error_string(context, 0, ret,
778 "Error adding an exra SAN to "
779 "return list");
780 hx509_free_octet_string_list(list);
781 free_GeneralNames(&sa);
782 return ret;
786 free_GeneralNames(&sa);
791 static int
792 check_key_usage(hx509_context context, const Certificate *cert,
793 unsigned flags, int req_present)
795 const Extension *e;
796 KeyUsage ku;
797 size_t size;
798 int ret, i = 0;
799 unsigned ku_flags;
801 if (_hx509_cert_get_version(cert) < 3)
802 return 0;
804 e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i);
805 if (e == NULL) {
806 if (req_present) {
807 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
808 "Required extension key "
809 "usage missing from certifiate");
810 return HX509_KU_CERT_MISSING;
812 return 0;
815 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, &ku, &size);
816 if (ret)
817 return ret;
818 ku_flags = KeyUsage2int(ku);
819 if ((ku_flags & flags) != flags) {
820 unsigned missing = (~ku_flags) & flags;
821 char buf[256], *name;
823 unparse_flags(missing, asn1_KeyUsage_units(), buf, sizeof(buf));
824 _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
825 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
826 "Key usage %s required but missing "
827 "from certifiate %s", buf, name);
828 free(name);
829 return HX509_KU_CERT_MISSING;
831 return 0;
835 * Return 0 on matching key usage 'flags' for 'cert', otherwise return
836 * an error code. If 'req_present' the existance is required of the
837 * KeyUsage extension.
841 _hx509_check_key_usage(hx509_context context, hx509_cert cert,
842 unsigned flags, int req_present)
844 return check_key_usage(context, _hx509_get_cert(cert), flags, req_present);
847 enum certtype { PROXY_CERT, EE_CERT, CA_CERT };
849 static int
850 check_basic_constraints(hx509_context context, const Certificate *cert,
851 enum certtype type, int depth)
853 BasicConstraints bc;
854 const Extension *e;
855 size_t size;
856 int ret, i = 0;
858 if (_hx509_cert_get_version(cert) < 3)
859 return 0;
861 e = find_extension(cert, &asn1_oid_id_x509_ce_basicConstraints, &i);
862 if (e == NULL) {
863 switch(type) {
864 case PROXY_CERT:
865 case EE_CERT:
866 return 0;
867 case CA_CERT: {
868 char *name;
869 ret = _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
870 assert(ret == 0);
871 hx509_set_error_string(context, 0, HX509_EXTENSION_NOT_FOUND,
872 "basicConstraints missing from "
873 "CA certifiacte %s", name);
874 free(name);
875 return HX509_EXTENSION_NOT_FOUND;
880 ret = decode_BasicConstraints(e->extnValue.data,
881 e->extnValue.length, &bc,
882 &size);
883 if (ret)
884 return ret;
885 switch(type) {
886 case PROXY_CERT:
887 if (bc.cA != NULL && *bc.cA)
888 ret = HX509_PARENT_IS_CA;
889 break;
890 case EE_CERT:
891 ret = 0;
892 break;
893 case CA_CERT:
894 if (bc.cA == NULL || !*bc.cA)
895 ret = HX509_PARENT_NOT_CA;
896 else if (bc.pathLenConstraint)
897 if (depth - 1 > *bc.pathLenConstraint)
898 ret = HX509_CA_PATH_TOO_DEEP;
899 break;
901 free_BasicConstraints(&bc);
902 return ret;
906 _hx509_cert_is_parent_cmp(const Certificate *subject,
907 const Certificate *issuer,
908 int allow_self_signed)
910 int diff;
911 AuthorityKeyIdentifier ai;
912 SubjectKeyIdentifier si;
913 int ret_ai, ret_si, ret;
915 ret = _hx509_name_cmp(&issuer->tbsCertificate.subject,
916 &subject->tbsCertificate.issuer,
917 &diff);
918 if (ret)
919 return ret;
920 if (diff)
921 return diff;
923 memset(&ai, 0, sizeof(ai));
924 memset(&si, 0, sizeof(si));
927 * Try to find AuthorityKeyIdentifier, if it's not present in the
928 * subject certificate nor the parent.
931 ret_ai = find_extension_auth_key_id(subject, &ai);
932 if (ret_ai && ret_ai != HX509_EXTENSION_NOT_FOUND)
933 return 1;
934 ret_si = _hx509_find_extension_subject_key_id(issuer, &si);
935 if (ret_si && ret_si != HX509_EXTENSION_NOT_FOUND)
936 return -1;
938 if (ret_si && ret_ai)
939 goto out;
940 if (ret_ai)
941 goto out;
942 if (ret_si) {
943 if (allow_self_signed) {
944 diff = 0;
945 goto out;
946 } else if (ai.keyIdentifier) {
947 diff = -1;
948 goto out;
952 if (ai.keyIdentifier == NULL) {
953 Name name;
955 if (ai.authorityCertIssuer == NULL)
956 return -1;
957 if (ai.authorityCertSerialNumber == NULL)
958 return -1;
960 diff = der_heim_integer_cmp(ai.authorityCertSerialNumber,
961 &issuer->tbsCertificate.serialNumber);
962 if (diff)
963 return diff;
964 if (ai.authorityCertIssuer->len != 1)
965 return -1;
966 if (ai.authorityCertIssuer->val[0].element != choice_GeneralName_directoryName)
967 return -1;
969 name.element =
970 ai.authorityCertIssuer->val[0].u.directoryName.element;
971 name.u.rdnSequence =
972 ai.authorityCertIssuer->val[0].u.directoryName.u.rdnSequence;
974 ret = _hx509_name_cmp(&issuer->tbsCertificate.subject,
975 &name,
976 &diff);
977 if (ret)
978 return ret;
979 if (diff)
980 return diff;
981 diff = 0;
982 } else
983 diff = der_heim_octet_string_cmp(ai.keyIdentifier, &si);
984 if (diff)
985 goto out;
987 out:
988 free_AuthorityKeyIdentifier(&ai);
989 free_SubjectKeyIdentifier(&si);
990 return diff;
993 static int
994 certificate_is_anchor(hx509_context context,
995 hx509_certs trust_anchors,
996 const hx509_cert cert)
998 hx509_query q;
999 hx509_cert c;
1000 int ret;
1002 if (trust_anchors == NULL)
1003 return 0;
1005 _hx509_query_clear(&q);
1007 q.match = HX509_QUERY_MATCH_CERTIFICATE;
1008 q.certificate = _hx509_get_cert(cert);
1010 ret = hx509_certs_find(context, trust_anchors, &q, &c);
1011 if (ret == 0)
1012 hx509_cert_free(c);
1013 return ret == 0;
1016 static int
1017 certificate_is_self_signed(hx509_context context,
1018 const Certificate *cert,
1019 int *self_signed)
1021 int ret, diff;
1022 ret = _hx509_name_cmp(&cert->tbsCertificate.subject,
1023 &cert->tbsCertificate.issuer, &diff);
1024 *self_signed = (diff == 0);
1025 if (ret)
1026 hx509_set_error_string(context, 0, ret,
1027 "Failed to check if self signed");
1028 return ret;
1032 * The subjectName is "null" when it's empty set of relative DBs.
1035 static int
1036 subject_null_p(const Certificate *c)
1038 return c->tbsCertificate.subject.u.rdnSequence.len == 0;
1042 static int
1043 find_parent(hx509_context context,
1044 time_t time_now,
1045 hx509_certs trust_anchors,
1046 hx509_path *path,
1047 hx509_certs pool,
1048 hx509_cert current,
1049 hx509_cert *parent)
1051 AuthorityKeyIdentifier ai;
1052 hx509_query q;
1053 int ret;
1055 *parent = NULL;
1056 memset(&ai, 0, sizeof(ai));
1058 _hx509_query_clear(&q);
1060 if (!subject_null_p(current->data)) {
1061 q.match |= HX509_QUERY_FIND_ISSUER_CERT;
1062 q.subject = _hx509_get_cert(current);
1063 } else {
1064 ret = find_extension_auth_key_id(current->data, &ai);
1065 if (ret) {
1066 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1067 "Subjectless certificate missing AuthKeyID");
1068 return HX509_CERTIFICATE_MALFORMED;
1071 if (ai.keyIdentifier == NULL) {
1072 free_AuthorityKeyIdentifier(&ai);
1073 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1074 "Subjectless certificate missing keyIdentifier "
1075 "inside AuthKeyID");
1076 return HX509_CERTIFICATE_MALFORMED;
1079 q.subject_id = ai.keyIdentifier;
1080 q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
1083 q.path = path;
1084 q.match |= HX509_QUERY_NO_MATCH_PATH;
1086 if (pool) {
1087 q.timenow = time_now;
1088 q.match |= HX509_QUERY_MATCH_TIME;
1090 ret = hx509_certs_find(context, pool, &q, parent);
1091 if (ret == 0) {
1092 free_AuthorityKeyIdentifier(&ai);
1093 return 0;
1095 q.match &= ~HX509_QUERY_MATCH_TIME;
1098 if (trust_anchors) {
1099 ret = hx509_certs_find(context, trust_anchors, &q, parent);
1100 if (ret == 0) {
1101 free_AuthorityKeyIdentifier(&ai);
1102 return ret;
1105 free_AuthorityKeyIdentifier(&ai);
1108 hx509_name name;
1109 char *str;
1111 ret = hx509_cert_get_subject(current, &name);
1112 if (ret) {
1113 hx509_clear_error_string(context);
1114 return HX509_ISSUER_NOT_FOUND;
1116 ret = hx509_name_to_string(name, &str);
1117 hx509_name_free(&name);
1118 if (ret) {
1119 hx509_clear_error_string(context);
1120 return HX509_ISSUER_NOT_FOUND;
1123 hx509_set_error_string(context, 0, HX509_ISSUER_NOT_FOUND,
1124 "Failed to find issuer for "
1125 "certificate with subject: '%s'", str);
1126 free(str);
1128 return HX509_ISSUER_NOT_FOUND;
1135 static int
1136 is_proxy_cert(hx509_context context,
1137 const Certificate *cert,
1138 ProxyCertInfo *rinfo)
1140 ProxyCertInfo info;
1141 const Extension *e;
1142 size_t size;
1143 int ret, i = 0;
1145 if (rinfo)
1146 memset(rinfo, 0, sizeof(*rinfo));
1148 e = find_extension(cert, &asn1_oid_id_pkix_pe_proxyCertInfo, &i);
1149 if (e == NULL) {
1150 hx509_clear_error_string(context);
1151 return HX509_EXTENSION_NOT_FOUND;
1154 ret = decode_ProxyCertInfo(e->extnValue.data,
1155 e->extnValue.length,
1156 &info,
1157 &size);
1158 if (ret) {
1159 hx509_clear_error_string(context);
1160 return ret;
1162 if (size != e->extnValue.length) {
1163 free_ProxyCertInfo(&info);
1164 hx509_clear_error_string(context);
1165 return HX509_EXTRA_DATA_AFTER_STRUCTURE;
1167 if (rinfo == NULL)
1168 free_ProxyCertInfo(&info);
1169 else
1170 *rinfo = info;
1172 return 0;
1176 * Path operations are like MEMORY based keyset, but with exposed
1177 * internal so we can do easy searches.
1181 _hx509_path_append(hx509_context context, hx509_path *path, hx509_cert cert)
1183 hx509_cert *val;
1184 val = realloc(path->val, (path->len + 1) * sizeof(path->val[0]));
1185 if (val == NULL) {
1186 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1187 return ENOMEM;
1190 path->val = val;
1191 path->val[path->len] = hx509_cert_ref(cert);
1192 path->len++;
1194 return 0;
1197 void
1198 _hx509_path_free(hx509_path *path)
1200 unsigned i;
1202 for (i = 0; i < path->len; i++)
1203 hx509_cert_free(path->val[i]);
1204 free(path->val);
1205 path->val = NULL;
1206 path->len = 0;
1210 * Find path by looking up issuer for the top certificate and continue
1211 * until an anchor certificate is found or max limit is found. A
1212 * certificate never included twice in the path.
1214 * If the trust anchors are not given, calculate optimistic path, just
1215 * follow the chain upward until we no longer find a parent or we hit
1216 * the max path limit. In this case, a failure will always be returned
1217 * depending on what error condition is hit first.
1219 * The path includes a path from the top certificate to the anchor
1220 * certificate.
1222 * The caller needs to free `path´ both on successful built path and
1223 * failure.
1227 _hx509_calculate_path(hx509_context context,
1228 int flags,
1229 time_t time_now,
1230 hx509_certs anchors,
1231 unsigned int max_depth,
1232 hx509_cert cert,
1233 hx509_certs pool,
1234 hx509_path *path)
1236 hx509_cert parent, current;
1237 int ret;
1239 if (max_depth == 0)
1240 max_depth = HX509_VERIFY_MAX_DEPTH;
1242 ret = _hx509_path_append(context, path, cert);
1243 if (ret)
1244 return ret;
1246 current = hx509_cert_ref(cert);
1248 while (!certificate_is_anchor(context, anchors, current)) {
1250 ret = find_parent(context, time_now, anchors, path,
1251 pool, current, &parent);
1252 hx509_cert_free(current);
1253 if (ret)
1254 return ret;
1256 ret = _hx509_path_append(context, path, parent);
1257 if (ret)
1258 return ret;
1259 current = parent;
1261 if (path->len > max_depth) {
1262 hx509_cert_free(current);
1263 hx509_set_error_string(context, 0, HX509_PATH_TOO_LONG,
1264 "Path too long while bulding "
1265 "certificate chain");
1266 return HX509_PATH_TOO_LONG;
1270 if ((flags & HX509_CALCULATE_PATH_NO_ANCHOR) &&
1271 path->len > 0 &&
1272 certificate_is_anchor(context, anchors, path->val[path->len - 1]))
1274 hx509_cert_free(path->val[path->len - 1]);
1275 path->len--;
1278 hx509_cert_free(current);
1279 return 0;
1283 _hx509_AlgorithmIdentifier_cmp(const AlgorithmIdentifier *p,
1284 const AlgorithmIdentifier *q)
1286 int diff;
1287 diff = der_heim_oid_cmp(&p->algorithm, &q->algorithm);
1288 if (diff)
1289 return diff;
1290 if (p->parameters) {
1291 if (q->parameters)
1292 return heim_any_cmp(p->parameters,
1293 q->parameters);
1294 else
1295 return 1;
1296 } else {
1297 if (q->parameters)
1298 return -1;
1299 else
1300 return 0;
1305 _hx509_Certificate_cmp(const Certificate *p, const Certificate *q)
1307 int diff;
1308 diff = der_heim_bit_string_cmp(&p->signatureValue, &q->signatureValue);
1309 if (diff)
1310 return diff;
1311 diff = _hx509_AlgorithmIdentifier_cmp(&p->signatureAlgorithm,
1312 &q->signatureAlgorithm);
1313 if (diff)
1314 return diff;
1315 diff = der_heim_octet_string_cmp(&p->tbsCertificate._save,
1316 &q->tbsCertificate._save);
1317 return diff;
1321 * Compare to hx509 certificate object, useful for sorting.
1323 * @param p a hx509 certificate object.
1324 * @param q a hx509 certificate object.
1326 * @return 0 the objects are the same, returns > 0 is p is "larger"
1327 * then q, < 0 if p is "smaller" then q.
1329 * @ingroup hx509_cert
1333 hx509_cert_cmp(hx509_cert p, hx509_cert q)
1335 return _hx509_Certificate_cmp(p->data, q->data);
1339 * Return the name of the issuer of the hx509 certificate.
1341 * @param p a hx509 certificate object.
1342 * @param name a pointer to a hx509 name, should be freed by
1343 * hx509_name_free().
1345 * @return An hx509 error code, see hx509_get_error_string().
1347 * @ingroup hx509_cert
1351 hx509_cert_get_issuer(hx509_cert p, hx509_name *name)
1353 return _hx509_name_from_Name(&p->data->tbsCertificate.issuer, name);
1357 * Return the name of the subject of the hx509 certificate.
1359 * @param p a hx509 certificate object.
1360 * @param name a pointer to a hx509 name, should be freed by
1361 * hx509_name_free(). See also hx509_cert_get_base_subject().
1363 * @return An hx509 error code, see hx509_get_error_string().
1365 * @ingroup hx509_cert
1369 hx509_cert_get_subject(hx509_cert p, hx509_name *name)
1371 return _hx509_name_from_Name(&p->data->tbsCertificate.subject, name);
1375 * Return the name of the base subject of the hx509 certificate. If
1376 * the certiicate is a verified proxy certificate, the this function
1377 * return the base certificate (root of the proxy chain). If the proxy
1378 * certificate is not verified with the base certificate
1379 * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned.
1381 * @param context a hx509 context.
1382 * @param c a hx509 certificate object.
1383 * @param name a pointer to a hx509 name, should be freed by
1384 * hx509_name_free(). See also hx509_cert_get_subject().
1386 * @return An hx509 error code, see hx509_get_error_string().
1388 * @ingroup hx509_cert
1392 hx509_cert_get_base_subject(hx509_context context, hx509_cert c,
1393 hx509_name *name)
1395 if (c->basename)
1396 return hx509_name_copy(context, c->basename, name);
1397 if (is_proxy_cert(context, c->data, NULL) == 0) {
1398 int ret = HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED;
1399 hx509_set_error_string(context, 0, ret,
1400 "Proxy certificate have not been "
1401 "canonicalize yet, no base name");
1402 return ret;
1404 return _hx509_name_from_Name(&c->data->tbsCertificate.subject, name);
1408 * Get serial number of the certificate.
1410 * @param p a hx509 certificate object.
1411 * @param i serial number, should be freed ith der_free_heim_integer().
1413 * @return An hx509 error code, see hx509_get_error_string().
1415 * @ingroup hx509_cert
1419 hx509_cert_get_serialnumber(hx509_cert p, heim_integer *i)
1421 return der_copy_heim_integer(&p->data->tbsCertificate.serialNumber, i);
1425 * Get notBefore time of the certificate.
1427 * @param p a hx509 certificate object.
1429 * @return return not before time
1431 * @ingroup hx509_cert
1434 time_t
1435 hx509_cert_get_notBefore(hx509_cert p)
1437 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notBefore);
1441 * Get notAfter time of the certificate.
1443 * @param p a hx509 certificate object.
1445 * @return return not after time.
1447 * @ingroup hx509_cert
1450 time_t
1451 hx509_cert_get_notAfter(hx509_cert p)
1453 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notAfter);
1457 * Get the SubjectPublicKeyInfo structure from the hx509 certificate.
1459 * @param context a hx509 context.
1460 * @param p a hx509 certificate object.
1461 * @param spki SubjectPublicKeyInfo, should be freed with
1462 * free_SubjectPublicKeyInfo().
1464 * @return An hx509 error code, see hx509_get_error_string().
1466 * @ingroup hx509_cert
1470 hx509_cert_get_SPKI(hx509_context context, hx509_cert p, SubjectPublicKeyInfo *spki)
1472 int ret;
1474 ret = copy_SubjectPublicKeyInfo(&p->data->tbsCertificate.subjectPublicKeyInfo, spki);
1475 if (ret)
1476 hx509_set_error_string(context, 0, ret, "Failed to copy SPKI");
1477 return ret;
1481 * Get the AlgorithmIdentifier from the hx509 certificate.
1483 * @param context a hx509 context.
1484 * @param p a hx509 certificate object.
1485 * @param alg AlgorithmIdentifier, should be freed with
1486 * free_AlgorithmIdentifier(). The algorithmidentifier is
1487 * typicly rsaEncryption, or id-ecPublicKey, or some other
1488 * public key mechanism.
1490 * @return An hx509 error code, see hx509_get_error_string().
1492 * @ingroup hx509_cert
1496 hx509_cert_get_SPKI_AlgorithmIdentifier(hx509_context context,
1497 hx509_cert p,
1498 AlgorithmIdentifier *alg)
1500 int ret;
1502 ret = copy_AlgorithmIdentifier(&p->data->tbsCertificate.subjectPublicKeyInfo.algorithm, alg);
1503 if (ret)
1504 hx509_set_error_string(context, 0, ret,
1505 "Failed to copy SPKI AlgorithmIdentifier");
1506 return ret;
1510 hx509_private_key
1511 _hx509_cert_private_key(hx509_cert p)
1513 return p->private_key;
1517 hx509_cert_have_private_key(hx509_cert p)
1519 return p->private_key ? 1 : 0;
1524 _hx509_cert_private_key_exportable(hx509_cert p)
1526 if (p->private_key == NULL)
1527 return 0;
1528 return _hx509_private_key_exportable(p->private_key);
1532 _hx509_cert_private_decrypt(hx509_context context,
1533 const heim_octet_string *ciphertext,
1534 const heim_oid *encryption_oid,
1535 hx509_cert p,
1536 heim_octet_string *cleartext)
1538 cleartext->data = NULL;
1539 cleartext->length = 0;
1541 if (p->private_key == NULL) {
1542 hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
1543 "Private key missing");
1544 return HX509_PRIVATE_KEY_MISSING;
1547 return _hx509_private_key_private_decrypt(context,
1548 ciphertext,
1549 encryption_oid,
1550 p->private_key,
1551 cleartext);
1555 _hx509_cert_public_encrypt(hx509_context context,
1556 const heim_octet_string *cleartext,
1557 const hx509_cert p,
1558 heim_oid *encryption_oid,
1559 heim_octet_string *ciphertext)
1561 return _hx509_public_encrypt(context,
1562 cleartext, p->data,
1563 encryption_oid, ciphertext);
1570 time_t
1571 _hx509_Time2time_t(const Time *t)
1573 switch(t->element) {
1574 case choice_Time_utcTime:
1575 return t->u.utcTime;
1576 case choice_Time_generalTime:
1577 return t->u.generalTime;
1579 return 0;
1586 static int
1587 init_name_constraints(hx509_name_constraints *nc)
1589 memset(nc, 0, sizeof(*nc));
1590 return 0;
1593 static int
1594 add_name_constraints(hx509_context context, const Certificate *c, int not_ca,
1595 hx509_name_constraints *nc)
1597 NameConstraints tnc;
1598 int ret;
1600 ret = find_extension_name_constraints(c, &tnc);
1601 if (ret == HX509_EXTENSION_NOT_FOUND)
1602 return 0;
1603 else if (ret) {
1604 hx509_set_error_string(context, 0, ret, "Failed getting NameConstraints");
1605 return ret;
1606 } else if (not_ca) {
1607 ret = HX509_VERIFY_CONSTRAINTS;
1608 hx509_set_error_string(context, 0, ret, "Not a CA and "
1609 "have NameConstraints");
1610 } else {
1611 NameConstraints *val;
1612 val = realloc(nc->val, sizeof(nc->val[0]) * (nc->len + 1));
1613 if (val == NULL) {
1614 hx509_clear_error_string(context);
1615 ret = ENOMEM;
1616 goto out;
1618 nc->val = val;
1619 ret = copy_NameConstraints(&tnc, &nc->val[nc->len]);
1620 if (ret) {
1621 hx509_clear_error_string(context);
1622 goto out;
1624 nc->len += 1;
1626 out:
1627 free_NameConstraints(&tnc);
1628 return ret;
1631 static int
1632 match_RDN(const RelativeDistinguishedName *c,
1633 const RelativeDistinguishedName *n)
1635 int i;
1637 if (c->len != n->len)
1638 return HX509_NAME_CONSTRAINT_ERROR;
1640 for (i = 0; i < n->len; i++) {
1641 int diff, ret;
1643 if (der_heim_oid_cmp(&c->val[i].type, &n->val[i].type) != 0)
1644 return HX509_NAME_CONSTRAINT_ERROR;
1645 ret = _hx509_name_ds_cmp(&c->val[i].value, &n->val[i].value, &diff);
1646 if (ret)
1647 return ret;
1648 if (diff != 0)
1649 return HX509_NAME_CONSTRAINT_ERROR;
1651 return 0;
1654 static int
1655 match_X501Name(const Name *c, const Name *n)
1657 int i, ret;
1659 if (c->element != choice_Name_rdnSequence
1660 || n->element != choice_Name_rdnSequence)
1661 return 0;
1662 if (c->u.rdnSequence.len > n->u.rdnSequence.len)
1663 return HX509_NAME_CONSTRAINT_ERROR;
1664 for (i = 0; i < c->u.rdnSequence.len; i++) {
1665 ret = match_RDN(&c->u.rdnSequence.val[i], &n->u.rdnSequence.val[i]);
1666 if (ret)
1667 return ret;
1669 return 0;
1673 static int
1674 match_general_name(const GeneralName *c, const GeneralName *n, int *match)
1677 * Name constraints only apply to the same name type, see RFC3280,
1678 * 4.2.1.11.
1680 assert(c->element == n->element);
1682 switch(c->element) {
1683 case choice_GeneralName_otherName:
1684 if (der_heim_oid_cmp(&c->u.otherName.type_id,
1685 &n->u.otherName.type_id) != 0)
1686 return HX509_NAME_CONSTRAINT_ERROR;
1687 if (heim_any_cmp(&c->u.otherName.value,
1688 &n->u.otherName.value) != 0)
1689 return HX509_NAME_CONSTRAINT_ERROR;
1690 *match = 1;
1691 return 0;
1692 case choice_GeneralName_rfc822Name: {
1693 const char *s;
1694 size_t len1, len2;
1695 s = strchr(c->u.rfc822Name, '@');
1696 if (s) {
1697 if (strcasecmp(c->u.rfc822Name, n->u.rfc822Name) != 0)
1698 return HX509_NAME_CONSTRAINT_ERROR;
1699 } else {
1700 s = strchr(n->u.rfc822Name, '@');
1701 if (s == NULL)
1702 return HX509_NAME_CONSTRAINT_ERROR;
1703 len1 = strlen(c->u.rfc822Name);
1704 len2 = strlen(s + 1);
1705 if (len1 > len2)
1706 return HX509_NAME_CONSTRAINT_ERROR;
1707 if (strcasecmp(s + 1 + len2 - len1, c->u.rfc822Name) != 0)
1708 return HX509_NAME_CONSTRAINT_ERROR;
1709 if (len1 < len2 && s[len2 - len1 + 1] != '.')
1710 return HX509_NAME_CONSTRAINT_ERROR;
1712 *match = 1;
1713 return 0;
1715 case choice_GeneralName_dNSName: {
1716 size_t lenc, lenn;
1718 lenc = strlen(c->u.dNSName);
1719 lenn = strlen(n->u.dNSName);
1720 if (lenc > lenn)
1721 return HX509_NAME_CONSTRAINT_ERROR;
1722 if (strcasecmp(&n->u.dNSName[lenn - lenc], c->u.dNSName) != 0)
1723 return HX509_NAME_CONSTRAINT_ERROR;
1724 if (lenc != lenn && n->u.dNSName[lenn - lenc - 1] != '.')
1725 return HX509_NAME_CONSTRAINT_ERROR;
1726 *match = 1;
1727 return 0;
1729 case choice_GeneralName_directoryName: {
1730 Name c_name, n_name;
1731 int ret;
1733 c_name._save.data = NULL;
1734 c_name._save.length = 0;
1735 c_name.element = c->u.directoryName.element;
1736 c_name.u.rdnSequence = c->u.directoryName.u.rdnSequence;
1738 n_name._save.data = NULL;
1739 n_name._save.length = 0;
1740 n_name.element = n->u.directoryName.element;
1741 n_name.u.rdnSequence = n->u.directoryName.u.rdnSequence;
1743 ret = match_X501Name(&c_name, &n_name);
1744 if (ret == 0)
1745 *match = 1;
1746 return ret;
1748 case choice_GeneralName_uniformResourceIdentifier:
1749 case choice_GeneralName_iPAddress:
1750 case choice_GeneralName_registeredID:
1751 default:
1752 return HX509_NAME_CONSTRAINT_ERROR;
1756 static int
1757 match_alt_name(const GeneralName *n, const Certificate *c,
1758 int *same, int *match)
1760 GeneralNames sa;
1761 int ret, i, j;
1763 i = 0;
1764 do {
1765 ret = find_extension_subject_alt_name(c, &i, &sa);
1766 if (ret == HX509_EXTENSION_NOT_FOUND) {
1767 ret = 0;
1768 break;
1769 } else if (ret != 0)
1770 break;
1772 for (j = 0; j < sa.len; j++) {
1773 if (n->element == sa.val[j].element) {
1774 *same = 1;
1775 ret = match_general_name(n, &sa.val[j], match);
1778 free_GeneralNames(&sa);
1779 } while (1);
1780 return ret;
1784 static int
1785 match_tree(const GeneralSubtrees *t, const Certificate *c, int *match)
1787 int name, alt_name, same;
1788 unsigned int i;
1789 int ret = 0;
1791 name = alt_name = same = *match = 0;
1792 for (i = 0; i < t->len; i++) {
1793 if (t->val[i].minimum && t->val[i].maximum)
1794 return HX509_RANGE;
1797 * If the constraint apply to directoryNames, test is with
1798 * subjectName of the certificate if the certificate have a
1799 * non-null (empty) subjectName.
1802 if (t->val[i].base.element == choice_GeneralName_directoryName
1803 && !subject_null_p(c))
1805 GeneralName certname;
1807 memset(&certname, 0, sizeof(certname));
1808 certname.element = choice_GeneralName_directoryName;
1809 certname.u.directoryName.element =
1810 c->tbsCertificate.subject.element;
1811 certname.u.directoryName.u.rdnSequence =
1812 c->tbsCertificate.subject.u.rdnSequence;
1814 ret = match_general_name(&t->val[i].base, &certname, &name);
1817 /* Handle subjectAltNames, this is icky since they
1818 * restrictions only apply if the subjectAltName is of the
1819 * same type. So if there have been a match of type, require
1820 * altname to be set.
1822 ret = match_alt_name(&t->val[i].base, c, &same, &alt_name);
1824 if (name && (!same || alt_name))
1825 *match = 1;
1826 return ret;
1829 static int
1830 check_name_constraints(hx509_context context,
1831 const hx509_name_constraints *nc,
1832 const Certificate *c)
1834 int match, ret;
1835 int i;
1837 for (i = 0 ; i < nc->len; i++) {
1838 GeneralSubtrees gs;
1840 if (nc->val[i].permittedSubtrees) {
1841 GeneralSubtrees_SET(&gs, nc->val[i].permittedSubtrees);
1842 ret = match_tree(&gs, c, &match);
1843 if (ret) {
1844 hx509_clear_error_string(context);
1845 return ret;
1847 /* allow null subjectNames, they wont matches anything */
1848 if (match == 0 && !subject_null_p(c)) {
1849 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1850 "Error verify constraints, "
1851 "certificate didn't match any "
1852 "permitted subtree");
1853 return HX509_VERIFY_CONSTRAINTS;
1856 if (nc->val[i].excludedSubtrees) {
1857 GeneralSubtrees_SET(&gs, nc->val[i].excludedSubtrees);
1858 ret = match_tree(&gs, c, &match);
1859 if (ret) {
1860 hx509_clear_error_string(context);
1861 return ret;
1863 if (match) {
1864 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1865 "Error verify constraints, "
1866 "certificate included in excluded "
1867 "subtree");
1868 return HX509_VERIFY_CONSTRAINTS;
1872 return 0;
1875 static void
1876 free_name_constraints(hx509_name_constraints *nc)
1878 int i;
1880 for (i = 0 ; i < nc->len; i++)
1881 free_NameConstraints(&nc->val[i]);
1882 free(nc->val);
1886 * Build and verify the path for the certificate to the trust anchor
1887 * specified in the verify context. The path is constructed from the
1888 * certificate, the pool and the trust anchors.
1890 * @param context A hx509 context.
1891 * @param ctx A hx509 verification context.
1892 * @param cert the certificate to build the path from.
1893 * @param pool A keyset of certificates to build the chain from.
1895 * @return An hx509 error code, see hx509_get_error_string().
1897 * @ingroup hx509_verify
1901 hx509_verify_path(hx509_context context,
1902 hx509_verify_ctx ctx,
1903 hx509_cert cert,
1904 hx509_certs pool)
1906 hx509_name_constraints nc;
1907 hx509_path path;
1908 int ret, i, proxy_cert_depth, selfsigned_depth, diff;
1909 enum certtype type;
1910 Name proxy_issuer;
1911 hx509_certs anchors = NULL;
1913 memset(&proxy_issuer, 0, sizeof(proxy_issuer));
1915 ret = init_name_constraints(&nc);
1916 if (ret)
1917 return ret;
1919 path.val = NULL;
1920 path.len = 0;
1922 if ((ctx->flags & HX509_VERIFY_CTX_F_TIME_SET) == 0)
1923 ctx->time_now = time(NULL);
1928 if (ctx->trust_anchors)
1929 anchors = hx509_certs_ref(ctx->trust_anchors);
1930 else if (context->default_trust_anchors && ALLOW_DEF_TA(ctx))
1931 anchors = hx509_certs_ref(context->default_trust_anchors);
1932 else {
1933 ret = hx509_certs_init(context, "MEMORY:no-TA", 0, NULL, &anchors);
1934 if (ret)
1935 goto out;
1939 * Calculate the path from the certificate user presented to the
1940 * to an anchor.
1942 ret = _hx509_calculate_path(context, 0, ctx->time_now,
1943 anchors, ctx->max_depth,
1944 cert, pool, &path);
1945 if (ret)
1946 goto out;
1949 * Check CA and proxy certificate chain from the top of the
1950 * certificate chain. Also check certificate is valid with respect
1951 * to the current time.
1955 proxy_cert_depth = 0;
1956 selfsigned_depth = 0;
1958 if (ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE)
1959 type = PROXY_CERT;
1960 else
1961 type = EE_CERT;
1963 for (i = 0; i < path.len; i++) {
1964 Certificate *c;
1965 time_t t;
1967 c = _hx509_get_cert(path.val[i]);
1970 * Lets do some basic check on issuer like
1971 * keyUsage.keyCertSign and basicConstraints.cA bit depending
1972 * on what type of certificate this is.
1975 switch (type) {
1976 case CA_CERT:
1978 /* XXX make constants for keyusage */
1979 ret = check_key_usage(context, c, 1 << 5,
1980 REQUIRE_RFC3280(ctx) ? TRUE : FALSE);
1981 if (ret) {
1982 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
1983 "Key usage missing from CA certificate");
1984 goto out;
1987 /* self signed cert doesn't add to path length */
1988 if (i + 1 != path.len) {
1989 int selfsigned;
1991 ret = certificate_is_self_signed(context, c, &selfsigned);
1992 if (ret)
1993 goto out;
1994 if (selfsigned)
1995 selfsigned_depth++;
1998 break;
1999 case PROXY_CERT: {
2000 ProxyCertInfo info;
2002 if (is_proxy_cert(context, c, &info) == 0) {
2003 int j;
2005 if (info.pCPathLenConstraint != NULL &&
2006 *info.pCPathLenConstraint < i)
2008 free_ProxyCertInfo(&info);
2009 ret = HX509_PATH_TOO_LONG;
2010 hx509_set_error_string(context, 0, ret,
2011 "Proxy certificate chain "
2012 "longer then allowed");
2013 goto out;
2015 /* XXX MUST check info.proxyPolicy */
2016 free_ProxyCertInfo(&info);
2018 j = 0;
2019 if (find_extension(c, &asn1_oid_id_x509_ce_subjectAltName, &j)) {
2020 ret = HX509_PROXY_CERT_INVALID;
2021 hx509_set_error_string(context, 0, ret,
2022 "Proxy certificate have explicity "
2023 "forbidden subjectAltName");
2024 goto out;
2027 j = 0;
2028 if (find_extension(c, &asn1_oid_id_x509_ce_issuerAltName, &j)) {
2029 ret = HX509_PROXY_CERT_INVALID;
2030 hx509_set_error_string(context, 0, ret,
2031 "Proxy certificate have explicity "
2032 "forbidden issuerAltName");
2033 goto out;
2037 * The subject name of the proxy certificate should be
2038 * CN=XXX,<proxy issuer>, prune of CN and check if its
2039 * the same over the whole chain of proxy certs and
2040 * then check with the EE cert when we get to it.
2043 if (proxy_cert_depth) {
2044 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.subject, &diff);
2045 if (ret) {
2046 hx509_set_error_string(context, 0, ret, "Out of memory");
2047 goto out;
2049 if (diff) {
2050 ret = HX509_PROXY_CERT_NAME_WRONG;
2051 hx509_set_error_string(context, 0, ret,
2052 "Base proxy name not right");
2053 goto out;
2057 free_Name(&proxy_issuer);
2059 ret = copy_Name(&c->tbsCertificate.subject, &proxy_issuer);
2060 if (ret) {
2061 hx509_clear_error_string(context);
2062 goto out;
2065 j = proxy_issuer.u.rdnSequence.len;
2066 if (proxy_issuer.u.rdnSequence.len < 2
2067 || proxy_issuer.u.rdnSequence.val[j - 1].len > 1
2068 || der_heim_oid_cmp(&proxy_issuer.u.rdnSequence.val[j - 1].val[0].type,
2069 &asn1_oid_id_at_commonName))
2071 ret = HX509_PROXY_CERT_NAME_WRONG;
2072 hx509_set_error_string(context, 0, ret,
2073 "Proxy name too short or "
2074 "does not have Common name "
2075 "at the top");
2076 goto out;
2079 free_RelativeDistinguishedName(&proxy_issuer.u.rdnSequence.val[j - 1]);
2080 proxy_issuer.u.rdnSequence.len -= 1;
2082 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.issuer, &diff);
2083 if (ret) {
2084 hx509_set_error_string(context, 0, ret, "Out of memory");
2085 goto out;
2087 if (diff != 0) {
2088 ret = HX509_PROXY_CERT_NAME_WRONG;
2089 hx509_set_error_string(context, 0, ret,
2090 "Proxy issuer name not as expected");
2091 goto out;
2094 break;
2095 } else {
2097 * Now we are done with the proxy certificates, this
2098 * cert was an EE cert and we we will fall though to
2099 * EE checking below.
2101 type = EE_CERT;
2102 /* FALLTHOUGH */
2105 case EE_CERT:
2107 * If there where any proxy certificates in the chain
2108 * (proxy_cert_depth > 0), check that the proxy issuer
2109 * matched proxy certificates "base" subject.
2111 if (proxy_cert_depth) {
2113 ret = _hx509_name_cmp(&proxy_issuer,
2114 &c->tbsCertificate.subject, &diff);
2115 if (ret) {
2116 hx509_set_error_string(context, 0, ret, "out of memory");
2117 goto out;
2119 if (diff) {
2120 ret = HX509_PROXY_CERT_NAME_WRONG;
2121 hx509_clear_error_string(context);
2122 goto out;
2124 if (cert->basename)
2125 hx509_name_free(&cert->basename);
2127 ret = _hx509_name_from_Name(&proxy_issuer, &cert->basename);
2128 if (ret) {
2129 hx509_clear_error_string(context);
2130 goto out;
2134 break;
2137 ret = check_basic_constraints(context, c, type,
2138 i - proxy_cert_depth - selfsigned_depth);
2139 if (ret)
2140 goto out;
2143 * Don't check the trust anchors expiration time since they
2144 * are transported out of band, from RFC3820.
2146 if (i + 1 != path.len || CHECK_TA(ctx)) {
2148 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2149 if (t > ctx->time_now) {
2150 ret = HX509_CERT_USED_BEFORE_TIME;
2151 hx509_clear_error_string(context);
2152 goto out;
2154 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2155 if (t < ctx->time_now) {
2156 ret = HX509_CERT_USED_AFTER_TIME;
2157 hx509_clear_error_string(context);
2158 goto out;
2162 if (type == EE_CERT)
2163 type = CA_CERT;
2164 else if (type == PROXY_CERT)
2165 proxy_cert_depth++;
2169 * Verify constraints, do this backward so path constraints are
2170 * checked in the right order.
2173 for (ret = 0, i = path.len - 1; i >= 0; i--) {
2174 Certificate *c;
2175 int selfsigned;
2177 c = _hx509_get_cert(path.val[i]);
2179 ret = certificate_is_self_signed(context, c, &selfsigned);
2180 if (ret)
2181 goto out;
2183 /* verify name constraints, not for selfsigned and anchor */
2184 if (!selfsigned || i + 1 != path.len) {
2185 ret = check_name_constraints(context, &nc, c);
2186 if (ret) {
2187 goto out;
2190 ret = add_name_constraints(context, c, i == 0, &nc);
2191 if (ret)
2192 goto out;
2194 /* XXX verify all other silly constraints */
2199 * Verify that no certificates has been revoked.
2202 if (ctx->revoke_ctx) {
2203 hx509_certs certs;
2205 ret = hx509_certs_init(context, "MEMORY:revoke-certs", 0,
2206 NULL, &certs);
2207 if (ret)
2208 goto out;
2210 for (i = 0; i < path.len; i++) {
2211 ret = hx509_certs_add(context, certs, path.val[i]);
2212 if (ret) {
2213 hx509_certs_free(&certs);
2214 goto out;
2217 ret = hx509_certs_merge(context, certs, pool);
2218 if (ret) {
2219 hx509_certs_free(&certs);
2220 goto out;
2223 for (i = 0; i < path.len - 1; i++) {
2224 int parent = (i < path.len - 1) ? i + 1 : i;
2226 ret = hx509_revoke_verify(context,
2227 ctx->revoke_ctx,
2228 certs,
2229 ctx->time_now,
2230 path.val[i],
2231 path.val[parent]);
2232 if (ret) {
2233 hx509_certs_free(&certs);
2234 goto out;
2237 hx509_certs_free(&certs);
2241 * Verify signatures, do this backward so public key working
2242 * parameter is passed up from the anchor up though the chain.
2245 for (i = path.len - 1; i >= 0; i--) {
2246 hx509_cert signer;
2247 Certificate *c;
2249 c = _hx509_get_cert(path.val[i]);
2251 /* is last in chain (trust anchor) */
2252 if (i + 1 == path.len) {
2253 int selfsigned;
2255 signer = path.val[i];
2257 ret = certificate_is_self_signed(context, signer->data, &selfsigned);
2258 if (ret)
2259 goto out;
2261 /* if trust anchor is not self signed, don't check sig */
2262 if (!selfsigned)
2263 continue;
2264 } else {
2265 /* take next certificate in chain */
2266 signer = path.val[i + 1];
2269 /* verify signatureValue */
2270 ret = _hx509_verify_signature_bitstring(context,
2271 signer,
2272 &c->signatureAlgorithm,
2273 &c->tbsCertificate._save,
2274 &c->signatureValue);
2275 if (ret) {
2276 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
2277 "Failed to verify signature of certificate");
2278 goto out;
2281 * Verify that the sigature algorithm "best-before" date is
2282 * before the creation date of the certificate, do this for
2283 * trust anchors too, since any trust anchor that is created
2284 * after a algorithm is known to be bad deserved to be invalid.
2286 * Skip the leaf certificate for now...
2289 if (i != 0 && (ctx->flags & HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK) == 0) {
2290 time_t notBefore =
2291 _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2292 ret = _hx509_signature_best_before(context,
2293 &c->signatureAlgorithm,
2294 notBefore);
2295 if (ret)
2296 goto out;
2300 out:
2301 hx509_certs_free(&anchors);
2302 free_Name(&proxy_issuer);
2303 free_name_constraints(&nc);
2304 _hx509_path_free(&path);
2306 return ret;
2310 * Verify a signature made using the private key of an certificate.
2312 * @param context A hx509 context.
2313 * @param signer the certificate that made the signature.
2314 * @param alg algorthm that was used to sign the data.
2315 * @param data the data that was signed.
2316 * @param sig the sigature to verify.
2318 * @return An hx509 error code, see hx509_get_error_string().
2320 * @ingroup hx509_crypto
2324 hx509_verify_signature(hx509_context context,
2325 const hx509_cert signer,
2326 const AlgorithmIdentifier *alg,
2327 const heim_octet_string *data,
2328 const heim_octet_string *sig)
2330 return _hx509_verify_signature(context, signer, alg, data, sig);
2334 _hx509_verify_signature_bitstring(hx509_context context,
2335 const hx509_cert signer,
2336 const AlgorithmIdentifier *alg,
2337 const heim_octet_string *data,
2338 const heim_bit_string *sig)
2340 heim_octet_string os;
2342 if (sig->length & 7) {
2343 hx509_set_error_string(context, 0, HX509_CRYPTO_SIG_INVALID_FORMAT,
2344 "signature not multiple of 8 bits");
2345 return HX509_CRYPTO_SIG_INVALID_FORMAT;
2348 os.data = sig->data;
2349 os.length = sig->length / 8;
2351 return _hx509_verify_signature(context, signer, alg, data, &os);
2357 * Verify that the certificate is allowed to be used for the hostname
2358 * and address.
2360 * @param context A hx509 context.
2361 * @param cert the certificate to match with
2362 * @param flags Flags to modify the behavior:
2363 * - HX509_VHN_F_ALLOW_NO_MATCH no match is ok
2364 * @param type type of hostname:
2365 * - HX509_HN_HOSTNAME for plain hostname.
2366 * - HX509_HN_DNSSRV for DNS SRV names.
2367 * @param hostname the hostname to check
2368 * @param sa address of the host
2369 * @param sa_size length of address
2371 * @return An hx509 error code, see hx509_get_error_string().
2373 * @ingroup hx509_cert
2377 hx509_verify_hostname(hx509_context context,
2378 const hx509_cert cert,
2379 int flags,
2380 hx509_hostname_type type,
2381 const char *hostname,
2382 const struct sockaddr *sa,
2383 /* XXX krb5_socklen_t */ int sa_size)
2385 GeneralNames san;
2386 const Name *name;
2387 int ret, i, j;
2389 if (sa && sa_size <= 0)
2390 return EINVAL;
2392 memset(&san, 0, sizeof(san));
2394 i = 0;
2395 do {
2396 ret = find_extension_subject_alt_name(cert->data, &i, &san);
2397 if (ret == HX509_EXTENSION_NOT_FOUND)
2398 break;
2399 else if (ret != 0)
2400 return HX509_PARSING_NAME_FAILED;
2402 for (j = 0; j < san.len; j++) {
2403 switch (san.val[j].element) {
2404 case choice_GeneralName_dNSName:
2405 if (strcasecmp(san.val[j].u.dNSName, hostname) == 0) {
2406 free_GeneralNames(&san);
2407 return 0;
2409 break;
2410 default:
2411 break;
2414 free_GeneralNames(&san);
2415 } while (1);
2417 name = &cert->data->tbsCertificate.subject;
2419 /* Find first CN= in the name, and try to match the hostname on that */
2420 for (ret = 0, i = name->u.rdnSequence.len - 1; ret == 0 && i >= 0; i--) {
2421 for (j = 0; ret == 0 && j < name->u.rdnSequence.val[i].len; j++) {
2422 AttributeTypeAndValue *n = &name->u.rdnSequence.val[i].val[j];
2424 if (der_heim_oid_cmp(&n->type, &asn1_oid_id_at_commonName) == 0) {
2425 DirectoryString *ds = &n->value;
2426 switch (ds->element) {
2427 case choice_DirectoryString_printableString:
2428 if (strcasecmp(ds->u.printableString, hostname) == 0)
2429 return 0;
2430 break;
2431 case choice_DirectoryString_ia5String:
2432 if (strcasecmp(ds->u.ia5String, hostname) == 0)
2433 return 0;
2434 break;
2435 case choice_DirectoryString_utf8String:
2436 if (strcasecmp(ds->u.utf8String, hostname) == 0)
2437 return 0;
2438 default:
2439 break;
2441 ret = HX509_NAME_CONSTRAINT_ERROR;
2446 if ((flags & HX509_VHN_F_ALLOW_NO_MATCH) == 0)
2447 ret = HX509_NAME_CONSTRAINT_ERROR;
2449 return ret;
2453 _hx509_set_cert_attribute(hx509_context context,
2454 hx509_cert cert,
2455 const heim_oid *oid,
2456 const heim_octet_string *attr)
2458 hx509_cert_attribute a;
2459 void *d;
2461 if (hx509_cert_get_attribute(cert, oid) != NULL)
2462 return 0;
2464 d = realloc(cert->attrs.val,
2465 sizeof(cert->attrs.val[0]) * (cert->attrs.len + 1));
2466 if (d == NULL) {
2467 hx509_clear_error_string(context);
2468 return ENOMEM;
2470 cert->attrs.val = d;
2472 a = malloc(sizeof(*a));
2473 if (a == NULL)
2474 return ENOMEM;
2476 der_copy_octet_string(attr, &a->data);
2477 der_copy_oid(oid, &a->oid);
2479 cert->attrs.val[cert->attrs.len] = a;
2480 cert->attrs.len++;
2482 return 0;
2486 * Get an external attribute for the certificate, examples are
2487 * friendly name and id.
2489 * @param cert hx509 certificate object to search
2490 * @param oid an oid to search for.
2492 * @return an hx509_cert_attribute, only valid as long as the
2493 * certificate is referenced.
2495 * @ingroup hx509_cert
2498 hx509_cert_attribute
2499 hx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid)
2501 int i;
2502 for (i = 0; i < cert->attrs.len; i++)
2503 if (der_heim_oid_cmp(oid, &cert->attrs.val[i]->oid) == 0)
2504 return cert->attrs.val[i];
2505 return NULL;
2509 * Set the friendly name on the certificate.
2511 * @param cert The certificate to set the friendly name on
2512 * @param name Friendly name.
2514 * @return An hx509 error code, see hx509_get_error_string().
2516 * @ingroup hx509_cert
2520 hx509_cert_set_friendly_name(hx509_cert cert, const char *name)
2522 if (cert->friendlyname)
2523 free(cert->friendlyname);
2524 cert->friendlyname = strdup(name);
2525 if (cert->friendlyname == NULL)
2526 return ENOMEM;
2527 return 0;
2531 * Get friendly name of the certificate.
2533 * @param cert cert to get the friendly name from.
2535 * @return an friendly name or NULL if there is. The friendly name is
2536 * only valid as long as the certificate is referenced.
2538 * @ingroup hx509_cert
2541 const char *
2542 hx509_cert_get_friendly_name(hx509_cert cert)
2544 hx509_cert_attribute a;
2545 PKCS9_friendlyName n;
2546 size_t sz;
2547 int ret, i;
2549 if (cert->friendlyname)
2550 return cert->friendlyname;
2552 a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_friendlyName);
2553 if (a == NULL) {
2554 hx509_name name;
2556 ret = hx509_cert_get_subject(cert, &name);
2557 if (ret)
2558 return NULL;
2559 ret = hx509_name_to_string(name, &cert->friendlyname);
2560 hx509_name_free(&name);
2561 if (ret)
2562 return NULL;
2563 return cert->friendlyname;
2566 ret = decode_PKCS9_friendlyName(a->data.data, a->data.length, &n, &sz);
2567 if (ret)
2568 return NULL;
2570 if (n.len != 1) {
2571 free_PKCS9_friendlyName(&n);
2572 return NULL;
2575 cert->friendlyname = malloc(n.val[0].length + 1);
2576 if (cert->friendlyname == NULL) {
2577 free_PKCS9_friendlyName(&n);
2578 return NULL;
2581 for (i = 0; i < n.val[0].length; i++) {
2582 if (n.val[0].data[i] <= 0xff)
2583 cert->friendlyname[i] = n.val[0].data[i] & 0xff;
2584 else
2585 cert->friendlyname[i] = 'X';
2587 cert->friendlyname[i] = '\0';
2588 free_PKCS9_friendlyName(&n);
2590 return cert->friendlyname;
2593 void
2594 _hx509_query_clear(hx509_query *q)
2596 memset(q, 0, sizeof(*q));
2600 * Allocate an query controller. Free using hx509_query_free().
2602 * @param context A hx509 context.
2603 * @param q return pointer to a hx509_query.
2605 * @return An hx509 error code, see hx509_get_error_string().
2607 * @ingroup hx509_cert
2611 hx509_query_alloc(hx509_context context, hx509_query **q)
2613 *q = calloc(1, sizeof(**q));
2614 if (*q == NULL)
2615 return ENOMEM;
2616 return 0;
2621 * Set match options for the hx509 query controller.
2623 * @param q query controller.
2624 * @param option options to control the query controller.
2626 * @return An hx509 error code, see hx509_get_error_string().
2628 * @ingroup hx509_cert
2631 void
2632 hx509_query_match_option(hx509_query *q, hx509_query_option option)
2634 switch(option) {
2635 case HX509_QUERY_OPTION_PRIVATE_KEY:
2636 q->match |= HX509_QUERY_PRIVATE_KEY;
2637 break;
2638 case HX509_QUERY_OPTION_KU_ENCIPHERMENT:
2639 q->match |= HX509_QUERY_KU_ENCIPHERMENT;
2640 break;
2641 case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE:
2642 q->match |= HX509_QUERY_KU_DIGITALSIGNATURE;
2643 break;
2644 case HX509_QUERY_OPTION_KU_KEYCERTSIGN:
2645 q->match |= HX509_QUERY_KU_KEYCERTSIGN;
2646 break;
2647 case HX509_QUERY_OPTION_END:
2648 default:
2649 break;
2654 * Set the issuer and serial number of match in the query
2655 * controller. The function make copies of the isser and serial number.
2657 * @param q a hx509 query controller
2658 * @param issuer issuer to search for
2659 * @param serialNumber the serialNumber of the issuer.
2661 * @return An hx509 error code, see hx509_get_error_string().
2663 * @ingroup hx509_cert
2667 hx509_query_match_issuer_serial(hx509_query *q,
2668 const Name *issuer,
2669 const heim_integer *serialNumber)
2671 int ret;
2672 if (q->serial) {
2673 der_free_heim_integer(q->serial);
2674 free(q->serial);
2676 q->serial = malloc(sizeof(*q->serial));
2677 if (q->serial == NULL)
2678 return ENOMEM;
2679 ret = der_copy_heim_integer(serialNumber, q->serial);
2680 if (ret) {
2681 free(q->serial);
2682 q->serial = NULL;
2683 return ret;
2685 if (q->issuer_name) {
2686 free_Name(q->issuer_name);
2687 free(q->issuer_name);
2689 q->issuer_name = malloc(sizeof(*q->issuer_name));
2690 if (q->issuer_name == NULL)
2691 return ENOMEM;
2692 ret = copy_Name(issuer, q->issuer_name);
2693 if (ret) {
2694 free(q->issuer_name);
2695 q->issuer_name = NULL;
2696 return ret;
2698 q->match |= HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
2699 return 0;
2703 * Set the query controller to match on a friendly name
2705 * @param q a hx509 query controller.
2706 * @param name a friendly name to match on
2708 * @return An hx509 error code, see hx509_get_error_string().
2710 * @ingroup hx509_cert
2714 hx509_query_match_friendly_name(hx509_query *q, const char *name)
2716 if (q->friendlyname)
2717 free(q->friendlyname);
2718 q->friendlyname = strdup(name);
2719 if (q->friendlyname == NULL)
2720 return ENOMEM;
2721 q->match |= HX509_QUERY_MATCH_FRIENDLY_NAME;
2722 return 0;
2726 * Set the query controller to require an one specific EKU (extended
2727 * key usage). Any previous EKU matching is overwitten. If NULL is
2728 * passed in as the eku, the EKU requirement is reset.
2730 * @param q a hx509 query controller.
2731 * @param eku an EKU to match on.
2733 * @return An hx509 error code, see hx509_get_error_string().
2735 * @ingroup hx509_cert
2739 hx509_query_match_eku(hx509_query *q, const heim_oid *eku)
2741 int ret;
2743 if (eku == NULL) {
2744 if (q->eku) {
2745 der_free_oid(q->eku);
2746 free(q->eku);
2747 q->eku = NULL;
2749 q->match &= ~HX509_QUERY_MATCH_EKU;
2750 } else {
2751 if (q->eku) {
2752 der_free_oid(q->eku);
2753 } else {
2754 q->eku = calloc(1, sizeof(*q->eku));
2755 if (q->eku == NULL)
2756 return ENOMEM;
2758 ret = der_copy_oid(eku, q->eku);
2759 if (ret) {
2760 free(q->eku);
2761 q->eku = NULL;
2762 return ret;
2764 q->match |= HX509_QUERY_MATCH_EKU;
2766 return 0;
2770 hx509_query_match_expr(hx509_context context, hx509_query *q, const char *expr)
2772 if (q->expr) {
2773 _hx509_expr_free(q->expr);
2774 q->expr = NULL;
2777 if (expr == NULL) {
2778 q->match &= ~HX509_QUERY_MATCH_EXPR;
2779 } else {
2780 q->expr = _hx509_expr_parse(expr);
2781 if (q->expr)
2782 q->match |= HX509_QUERY_MATCH_EXPR;
2785 return 0;
2789 * Set the query controller to match using a specific match function.
2791 * @param q a hx509 query controller.
2792 * @param func function to use for matching, if the argument is NULL,
2793 * the match function is removed.
2794 * @param ctx context passed to the function.
2796 * @return An hx509 error code, see hx509_get_error_string().
2798 * @ingroup hx509_cert
2802 hx509_query_match_cmp_func(hx509_query *q,
2803 int (*func)(hx509_context, hx509_cert, void *),
2804 void *ctx)
2806 if (func)
2807 q->match |= HX509_QUERY_MATCH_FUNCTION;
2808 else
2809 q->match &= ~HX509_QUERY_MATCH_FUNCTION;
2810 q->cmp_func = func;
2811 q->cmp_func_ctx = ctx;
2812 return 0;
2816 * Free the query controller.
2818 * @param context A hx509 context.
2819 * @param q a pointer to the query controller.
2821 * @ingroup hx509_cert
2824 void
2825 hx509_query_free(hx509_context context, hx509_query *q)
2827 if (q == NULL)
2828 return;
2830 if (q->serial) {
2831 der_free_heim_integer(q->serial);
2832 free(q->serial);
2834 if (q->issuer_name) {
2835 free_Name(q->issuer_name);
2836 free(q->issuer_name);
2838 if (q->eku) {
2839 der_free_oid(q->eku);
2840 free(q->eku);
2842 if (q->friendlyname)
2843 free(q->friendlyname);
2844 if (q->expr)
2845 _hx509_expr_free(q->expr);
2847 memset(q, 0, sizeof(*q));
2848 free(q);
2852 _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert cert)
2854 Certificate *c = _hx509_get_cert(cert);
2855 int ret, diff;
2857 _hx509_query_statistic(context, 1, q);
2859 if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) &&
2860 _hx509_cert_is_parent_cmp(q->subject, c, 0) != 0)
2861 return 0;
2863 if ((q->match & HX509_QUERY_MATCH_CERTIFICATE) &&
2864 _hx509_Certificate_cmp(q->certificate, c) != 0)
2865 return 0;
2867 if ((q->match & HX509_QUERY_MATCH_SERIALNUMBER)
2868 && der_heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0)
2869 return 0;
2871 if (q->match & HX509_QUERY_MATCH_ISSUER_NAME) {
2872 ret = _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name, &diff);
2873 if (ret || diff)
2874 return 0;
2877 if (q->match & HX509_QUERY_MATCH_SUBJECT_NAME) {
2878 ret = _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name, &diff);
2879 if (ret || diff)
2880 return 0;
2883 if (q->match & HX509_QUERY_MATCH_SUBJECT_KEY_ID) {
2884 SubjectKeyIdentifier si;
2886 ret = _hx509_find_extension_subject_key_id(c, &si);
2887 if (ret == 0) {
2888 if (der_heim_octet_string_cmp(&si, q->subject_id) != 0)
2889 ret = 1;
2890 free_SubjectKeyIdentifier(&si);
2892 if (ret)
2893 return 0;
2895 if ((q->match & HX509_QUERY_MATCH_ISSUER_ID))
2896 return 0;
2897 if ((q->match & HX509_QUERY_PRIVATE_KEY) &&
2898 _hx509_cert_private_key(cert) == NULL)
2899 return 0;
2902 unsigned ku = 0;
2903 if (q->match & HX509_QUERY_KU_DIGITALSIGNATURE)
2904 ku |= (1 << 0);
2905 if (q->match & HX509_QUERY_KU_NONREPUDIATION)
2906 ku |= (1 << 1);
2907 if (q->match & HX509_QUERY_KU_ENCIPHERMENT)
2908 ku |= (1 << 2);
2909 if (q->match & HX509_QUERY_KU_DATAENCIPHERMENT)
2910 ku |= (1 << 3);
2911 if (q->match & HX509_QUERY_KU_KEYAGREEMENT)
2912 ku |= (1 << 4);
2913 if (q->match & HX509_QUERY_KU_KEYCERTSIGN)
2914 ku |= (1 << 5);
2915 if (q->match & HX509_QUERY_KU_CRLSIGN)
2916 ku |= (1 << 6);
2917 if (ku && check_key_usage(context, c, ku, TRUE))
2918 return 0;
2920 if ((q->match & HX509_QUERY_ANCHOR))
2921 return 0;
2923 if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) {
2924 hx509_cert_attribute a;
2926 a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_localKeyId);
2927 if (a == NULL)
2928 return 0;
2929 if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0)
2930 return 0;
2933 if (q->match & HX509_QUERY_NO_MATCH_PATH) {
2934 size_t i;
2936 for (i = 0; i < q->path->len; i++)
2937 if (hx509_cert_cmp(q->path->val[i], cert) == 0)
2938 return 0;
2940 if (q->match & HX509_QUERY_MATCH_FRIENDLY_NAME) {
2941 const char *name = hx509_cert_get_friendly_name(cert);
2942 if (name == NULL)
2943 return 0;
2944 if (strcasecmp(q->friendlyname, name) != 0)
2945 return 0;
2947 if (q->match & HX509_QUERY_MATCH_FUNCTION) {
2948 ret = (*q->cmp_func)(context, cert, q->cmp_func_ctx);
2949 if (ret != 0)
2950 return 0;
2953 if (q->match & HX509_QUERY_MATCH_KEY_HASH_SHA1) {
2954 heim_octet_string os;
2956 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
2957 os.length =
2958 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
2960 ret = _hx509_verify_signature(context,
2961 NULL,
2962 hx509_signature_sha1(),
2963 &os,
2964 q->keyhash_sha1);
2965 if (ret != 0)
2966 return 0;
2969 if (q->match & HX509_QUERY_MATCH_TIME) {
2970 time_t t;
2971 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2972 if (t > q->timenow)
2973 return 0;
2974 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2975 if (t < q->timenow)
2976 return 0;
2979 /* If an EKU is required, check the cert for it. */
2980 if ((q->match & HX509_QUERY_MATCH_EKU) &&
2981 hx509_cert_check_eku(context, cert, q->eku, 0))
2982 return 0;
2984 if ((q->match & HX509_QUERY_MATCH_EXPR)) {
2985 hx509_env env = NULL;
2987 ret = _hx509_cert_to_env(context, cert, &env);
2988 if (ret)
2989 return 0;
2991 ret = _hx509_expr_eval(context, env, q->expr);
2992 hx509_env_free(&env);
2993 if (ret == 0)
2994 return 0;
2997 if (q->match & ~HX509_QUERY_MASK)
2998 return 0;
3000 return 1;
3004 * Set a statistic file for the query statistics.
3006 * @param context A hx509 context.
3007 * @param fn statistics file name
3009 * @ingroup hx509_cert
3012 void
3013 hx509_query_statistic_file(hx509_context context, const char *fn)
3015 if (context->querystat)
3016 free(context->querystat);
3017 context->querystat = strdup(fn);
3020 void
3021 _hx509_query_statistic(hx509_context context, int type, const hx509_query *q)
3023 FILE *f;
3024 if (context->querystat == NULL)
3025 return;
3026 f = fopen(context->querystat, "a");
3027 if (f == NULL)
3028 return;
3029 rk_cloexec_file(f);
3030 fprintf(f, "%d %d\n", type, q->match);
3031 fclose(f);
3034 static const char *statname[] = {
3035 "find issuer cert",
3036 "match serialnumber",
3037 "match issuer name",
3038 "match subject name",
3039 "match subject key id",
3040 "match issuer id",
3041 "private key",
3042 "ku encipherment",
3043 "ku digitalsignature",
3044 "ku keycertsign",
3045 "ku crlsign",
3046 "ku nonrepudiation",
3047 "ku keyagreement",
3048 "ku dataencipherment",
3049 "anchor",
3050 "match certificate",
3051 "match local key id",
3052 "no match path",
3053 "match friendly name",
3054 "match function",
3055 "match key hash sha1",
3056 "match time"
3059 struct stat_el {
3060 unsigned long stats;
3061 unsigned int index;
3065 static int
3066 stat_sort(const void *a, const void *b)
3068 const struct stat_el *ae = a;
3069 const struct stat_el *be = b;
3070 return be->stats - ae->stats;
3074 * Unparse the statistics file and print the result on a FILE descriptor.
3076 * @param context A hx509 context.
3077 * @param printtype tyep to print
3078 * @param out the FILE to write the data on.
3080 * @ingroup hx509_cert
3083 void
3084 hx509_query_unparse_stats(hx509_context context, int printtype, FILE *out)
3086 rtbl_t t;
3087 FILE *f;
3088 int type, mask, i, num;
3089 unsigned long multiqueries = 0, totalqueries = 0;
3090 struct stat_el stats[32];
3092 if (context->querystat == NULL)
3093 return;
3094 f = fopen(context->querystat, "r");
3095 if (f == NULL) {
3096 fprintf(out, "No statistic file %s: %s.\n",
3097 context->querystat, strerror(errno));
3098 return;
3100 rk_cloexec_file(f);
3102 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
3103 stats[i].index = i;
3104 stats[i].stats = 0;
3107 while (fscanf(f, "%d %d\n", &type, &mask) == 2) {
3108 if (type != printtype)
3109 continue;
3110 num = i = 0;
3111 while (mask && i < sizeof(stats)/sizeof(stats[0])) {
3112 if (mask & 1) {
3113 stats[i].stats++;
3114 num++;
3116 mask = mask >>1 ;
3117 i++;
3119 if (num > 1)
3120 multiqueries++;
3121 totalqueries++;
3123 fclose(f);
3125 qsort(stats, sizeof(stats)/sizeof(stats[0]), sizeof(stats[0]), stat_sort);
3127 t = rtbl_create();
3128 if (t == NULL)
3129 errx(1, "out of memory");
3131 rtbl_set_separator (t, " ");
3133 rtbl_add_column_by_id (t, 0, "Name", 0);
3134 rtbl_add_column_by_id (t, 1, "Counter", 0);
3137 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
3138 char str[10];
3140 if (stats[i].index < sizeof(statname)/sizeof(statname[0]))
3141 rtbl_add_column_entry_by_id (t, 0, statname[stats[i].index]);
3142 else {
3143 snprintf(str, sizeof(str), "%d", stats[i].index);
3144 rtbl_add_column_entry_by_id (t, 0, str);
3146 snprintf(str, sizeof(str), "%lu", stats[i].stats);
3147 rtbl_add_column_entry_by_id (t, 1, str);
3150 rtbl_format(t, out);
3151 rtbl_destroy(t);
3153 fprintf(out, "\nQueries: multi %lu total %lu\n",
3154 multiqueries, totalqueries);
3158 * Check the extended key usage on the hx509 certificate.
3160 * @param context A hx509 context.
3161 * @param cert A hx509 context.
3162 * @param eku the EKU to check for
3163 * @param allow_any_eku if the any EKU is set, allow that to be a
3164 * substitute.
3166 * @return An hx509 error code, see hx509_get_error_string().
3168 * @ingroup hx509_cert
3172 hx509_cert_check_eku(hx509_context context, hx509_cert cert,
3173 const heim_oid *eku, int allow_any_eku)
3175 ExtKeyUsage e;
3176 int ret, i;
3178 ret = find_extension_eku(_hx509_get_cert(cert), &e);
3179 if (ret) {
3180 hx509_clear_error_string(context);
3181 return ret;
3184 for (i = 0; i < e.len; i++) {
3185 if (der_heim_oid_cmp(eku, &e.val[i]) == 0) {
3186 free_ExtKeyUsage(&e);
3187 return 0;
3189 if (allow_any_eku) {
3190 #if 0
3191 if (der_heim_oid_cmp(id_any_eku, &e.val[i]) == 0) {
3192 free_ExtKeyUsage(&e);
3193 return 0;
3195 #endif
3198 free_ExtKeyUsage(&e);
3199 hx509_clear_error_string(context);
3200 return HX509_CERTIFICATE_MISSING_EKU;
3204 _hx509_cert_get_keyusage(hx509_context context,
3205 hx509_cert c,
3206 KeyUsage *ku)
3208 Certificate *cert;
3209 const Extension *e;
3210 size_t size;
3211 int ret, i = 0;
3213 memset(ku, 0, sizeof(*ku));
3215 cert = _hx509_get_cert(c);
3217 if (_hx509_cert_get_version(cert) < 3)
3218 return 0;
3220 e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i);
3221 if (e == NULL)
3222 return HX509_KU_CERT_MISSING;
3224 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, ku, &size);
3225 if (ret)
3226 return ret;
3227 return 0;
3231 _hx509_cert_get_eku(hx509_context context,
3232 hx509_cert cert,
3233 ExtKeyUsage *e)
3235 int ret;
3237 memset(e, 0, sizeof(*e));
3239 ret = find_extension_eku(_hx509_get_cert(cert), e);
3240 if (ret && ret != HX509_EXTENSION_NOT_FOUND) {
3241 hx509_clear_error_string(context);
3242 return ret;
3244 return 0;
3248 * Encodes the hx509 certificate as a DER encode binary.
3250 * @param context A hx509 context.
3251 * @param c the certificate to encode.
3252 * @param os the encode certificate, set to NULL, 0 on case of
3253 * error. Free the returned structure with hx509_xfree().
3255 * @return An hx509 error code, see hx509_get_error_string().
3257 * @ingroup hx509_cert
3261 hx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os)
3263 size_t size;
3264 int ret;
3266 os->data = NULL;
3267 os->length = 0;
3269 ASN1_MALLOC_ENCODE(Certificate, os->data, os->length,
3270 _hx509_get_cert(c), &size, ret);
3271 if (ret) {
3272 os->data = NULL;
3273 os->length = 0;
3274 return ret;
3276 if (os->length != size)
3277 _hx509_abort("internal ASN.1 encoder error");
3279 return ret;
3283 * Last to avoid lost __attribute__s due to #undef.
3286 #undef __attribute__
3287 #define __attribute__(X)
3289 void
3290 _hx509_abort(const char *fmt, ...)
3291 __attribute__ ((noreturn, format (printf, 1, 2)))
3293 va_list ap;
3294 va_start(ap, fmt);
3295 vprintf(fmt, ap);
3296 va_end(ap);
3297 printf("\n");
3298 fflush(stdout);
3299 abort();
3303 * Free a data element allocated in the library.
3305 * @param ptr data to be freed.
3307 * @ingroup hx509_misc
3310 void
3311 hx509_xfree(void *ptr)
3313 free(ptr);
3321 _hx509_cert_to_env(hx509_context context, hx509_cert cert, hx509_env *env)
3323 ExtKeyUsage eku;
3324 hx509_name name;
3325 char *buf;
3326 int ret;
3327 hx509_env envcert = NULL;
3329 *env = NULL;
3331 /* version */
3332 asprintf(&buf, "%d", _hx509_cert_get_version(_hx509_get_cert(cert)));
3333 ret = hx509_env_add(context, &envcert, "version", buf);
3334 free(buf);
3335 if (ret)
3336 goto out;
3338 /* subject */
3339 ret = hx509_cert_get_subject(cert, &name);
3340 if (ret)
3341 goto out;
3343 ret = hx509_name_to_string(name, &buf);
3344 if (ret) {
3345 hx509_name_free(&name);
3346 goto out;
3349 ret = hx509_env_add(context, &envcert, "subject", buf);
3350 hx509_name_free(&name);
3351 if (ret)
3352 goto out;
3354 /* issuer */
3355 ret = hx509_cert_get_issuer(cert, &name);
3356 if (ret)
3357 goto out;
3359 ret = hx509_name_to_string(name, &buf);
3360 hx509_name_free(&name);
3361 if (ret)
3362 goto out;
3364 ret = hx509_env_add(context, &envcert, "issuer", buf);
3365 hx509_xfree(buf);
3366 if (ret)
3367 goto out;
3369 /* eku */
3371 ret = _hx509_cert_get_eku(context, cert, &eku);
3372 if (ret == HX509_EXTENSION_NOT_FOUND)
3374 else if (ret != 0)
3375 goto out;
3376 else {
3377 int i;
3378 hx509_env enveku = NULL;
3380 for (i = 0; i < eku.len; i++) {
3382 ret = der_print_heim_oid(&eku.val[i], '.', &buf);
3383 if (ret) {
3384 free_ExtKeyUsage(&eku);
3385 hx509_env_free(&enveku);
3386 goto out;
3388 ret = hx509_env_add(context, &enveku, buf, "oid-name-here");
3389 free(buf);
3390 if (ret) {
3391 free_ExtKeyUsage(&eku);
3392 hx509_env_free(&enveku);
3393 goto out;
3396 free_ExtKeyUsage(&eku);
3398 ret = hx509_env_add_binding(context, &envcert, "eku", enveku);
3399 if (ret) {
3400 hx509_env_free(&enveku);
3401 goto out;
3406 Certificate *c = _hx509_get_cert(cert);
3407 heim_octet_string os, sig;
3408 hx509_env envhash = NULL;
3410 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
3411 os.length =
3412 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
3414 ret = _hx509_create_signature(context,
3415 NULL,
3416 hx509_signature_sha1(),
3417 &os,
3418 NULL,
3419 &sig);
3420 if (ret != 0)
3421 goto out;
3423 ret = hex_encode(sig.data, sig.length, &buf);
3424 der_free_octet_string(&sig);
3425 if (ret < 0) {
3426 ret = ENOMEM;
3427 hx509_set_error_string(context, 0, ret,
3428 "Out of memory");
3429 goto out;
3432 ret = hx509_env_add(context, &envhash, "sha1", buf);
3433 free(buf);
3434 if (ret)
3435 goto out;
3437 ret = hx509_env_add_binding(context, &envcert, "hash", envhash);
3438 if (ret) {
3439 hx509_env_free(&envhash);
3440 goto out;
3444 ret = hx509_env_add_binding(context, env, "certificate", envcert);
3445 if (ret)
3446 goto out;
3448 return 0;
3450 out:
3451 hx509_env_free(&envcert);
3452 return ret;
3456 * Print a simple representation of a certificate
3458 * @param context A hx509 context, can be NULL
3459 * @param cert certificate to print
3460 * @param out the stdio output stream, if NULL, stdout is used
3462 * @return An hx509 error code
3464 * @ingroup hx509_cert
3468 hx509_print_cert(hx509_context context, hx509_cert cert, FILE *out)
3470 hx509_name name;
3471 char *str;
3472 int ret;
3474 if (out == NULL)
3475 out = stderr;
3477 ret = hx509_cert_get_issuer(cert, &name);
3478 if (ret)
3479 return ret;
3480 hx509_name_to_string(name, &str);
3481 hx509_name_free(&name);
3482 fprintf(out, " issuer: \"%s\"\n", str);
3483 free(str);
3485 ret = hx509_cert_get_subject(cert, &name);
3486 if (ret)
3487 return ret;
3488 hx509_name_to_string(name, &str);
3489 hx509_name_free(&name);
3490 fprintf(out, " subject: \"%s\"\n", str);
3491 free(str);
3494 heim_integer serialNumber;
3496 ret = hx509_cert_get_serialnumber(cert, &serialNumber);
3497 if (ret)
3498 return ret;
3499 ret = der_print_hex_heim_integer(&serialNumber, &str);
3500 if (ret)
3501 return ret;
3502 der_free_heim_integer(&serialNumber);
3503 fprintf(out, " serial: %s\n", str);
3504 free(str);
3507 printf(" keyusage: ");
3508 ret = hx509_cert_keyusage_print(context, cert, &str);
3509 if (ret == 0) {
3510 fprintf(out, "%s\n", str);
3511 free(str);
3512 } else
3513 fprintf(out, "no");
3515 return 0;