Remove building with NOCRYPTO option
[minix.git] / crypto / external / bsd / heimdal / dist / lib / hx509 / cert.c
blob006c538beb6a5d52104df8e0f6be267b7d0d776b
1 /* $NetBSD: cert.c,v 1.3 2014/04/24 13:45:34 pettai Exp $ */
3 /*
4 * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
36 #include "hx_locl.h"
37 #include "crypto-headers.h"
38 #include <krb5/rtbl.h>
40 /**
41 * @page page_cert The basic certificate
43 * The basic hx509 cerificate object in hx509 is hx509_cert. The
44 * hx509_cert object is representing one X509/PKIX certificate and
45 * associated attributes; like private key, friendly name, etc.
47 * A hx509_cert object is usully found via the keyset interfaces (@ref
48 * page_keyset), but its also possible to create a certificate
49 * directly from a parsed object with hx509_cert_init() and
50 * hx509_cert_init_data().
52 * See the library functions here: @ref hx509_cert
55 struct hx509_verify_ctx_data {
56 hx509_certs trust_anchors;
57 int flags;
58 #define HX509_VERIFY_CTX_F_TIME_SET 1
59 #define HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE 2
60 #define HX509_VERIFY_CTX_F_REQUIRE_RFC3280 4
61 #define HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS 8
62 #define HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS 16
63 #define HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK 32
64 time_t time_now;
65 unsigned int max_depth;
66 #define HX509_VERIFY_MAX_DEPTH 30
67 hx509_revoke_ctx revoke_ctx;
70 #define REQUIRE_RFC3280(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_REQUIRE_RFC3280)
71 #define CHECK_TA(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS)
72 #define ALLOW_DEF_TA(ctx) (((ctx)->flags & HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS) == 0)
74 struct _hx509_cert_attrs {
75 size_t len;
76 hx509_cert_attribute *val;
79 struct hx509_cert_data {
80 unsigned int ref;
81 char *friendlyname;
82 Certificate *data;
83 hx509_private_key private_key;
84 struct _hx509_cert_attrs attrs;
85 hx509_name basename;
86 _hx509_cert_release_func release;
87 void *ctx;
90 typedef struct hx509_name_constraints {
91 NameConstraints *val;
92 size_t len;
93 } hx509_name_constraints;
95 #define GeneralSubtrees_SET(g,var) \
96 (g)->len = (var)->len, (g)->val = (var)->val;
98 /**
99 * Creates a hx509 context that most functions in the library
100 * uses. The context is only allowed to be used by one thread at each
101 * moment. Free the context with hx509_context_free().
103 * @param context Returns a pointer to new hx509 context.
105 * @return Returns an hx509 error code.
107 * @ingroup hx509
111 hx509_context_init(hx509_context *context)
113 *context = calloc(1, sizeof(**context));
114 if (*context == NULL)
115 return ENOMEM;
117 _hx509_ks_null_register(*context);
118 _hx509_ks_mem_register(*context);
119 _hx509_ks_file_register(*context);
120 _hx509_ks_pkcs12_register(*context);
121 _hx509_ks_pkcs11_register(*context);
122 _hx509_ks_dir_register(*context);
123 _hx509_ks_keychain_register(*context);
125 ENGINE_add_conf_module();
126 OpenSSL_add_all_algorithms();
128 (*context)->ocsp_time_diff = HX509_DEFAULT_OCSP_TIME_DIFF;
130 initialize_hx_error_table_r(&(*context)->et_list);
131 initialize_asn1_error_table_r(&(*context)->et_list);
133 #ifdef HX509_DEFAULT_ANCHORS
134 (void)hx509_certs_init(*context, HX509_DEFAULT_ANCHORS, 0,
135 NULL, &(*context)->default_trust_anchors);
136 #endif
138 return 0;
142 * Selects if the hx509_revoke_verify() function is going to require
143 * the existans of a revokation method (OCSP, CRL) or not. Note that
144 * hx509_verify_path(), hx509_cms_verify_signed(), and other function
145 * call hx509_revoke_verify().
147 * @param context hx509 context to change the flag for.
148 * @param flag zero, revokation method required, non zero missing
149 * revokation method ok
151 * @ingroup hx509_verify
154 void
155 hx509_context_set_missing_revoke(hx509_context context, int flag)
157 if (flag)
158 context->flags |= HX509_CTX_VERIFY_MISSING_OK;
159 else
160 context->flags &= ~HX509_CTX_VERIFY_MISSING_OK;
164 * Free the context allocated by hx509_context_init().
166 * @param context context to be freed.
168 * @ingroup hx509
171 void
172 hx509_context_free(hx509_context *context)
174 hx509_clear_error_string(*context);
175 if ((*context)->ks_ops) {
176 free((*context)->ks_ops);
177 (*context)->ks_ops = NULL;
179 (*context)->ks_num_ops = 0;
180 free_error_table ((*context)->et_list);
181 if ((*context)->querystat)
182 free((*context)->querystat);
183 memset(*context, 0, sizeof(**context));
184 free(*context);
185 *context = NULL;
192 Certificate *
193 _hx509_get_cert(hx509_cert cert)
195 return cert->data;
203 _hx509_cert_get_version(const Certificate *t)
205 return t->tbsCertificate.version ? *t->tbsCertificate.version + 1 : 1;
209 * Allocate and init an hx509 certificate object from the decoded
210 * certificate `c´.
212 * @param context A hx509 context.
213 * @param c
214 * @param cert
216 * @return Returns an hx509 error code.
218 * @ingroup hx509_cert
222 hx509_cert_init(hx509_context context, const Certificate *c, hx509_cert *cert)
224 int ret;
226 *cert = malloc(sizeof(**cert));
227 if (*cert == NULL)
228 return ENOMEM;
229 (*cert)->ref = 1;
230 (*cert)->friendlyname = NULL;
231 (*cert)->attrs.len = 0;
232 (*cert)->attrs.val = NULL;
233 (*cert)->private_key = NULL;
234 (*cert)->basename = NULL;
235 (*cert)->release = NULL;
236 (*cert)->ctx = NULL;
238 (*cert)->data = calloc(1, sizeof(*(*cert)->data));
239 if ((*cert)->data == NULL) {
240 free(*cert);
241 return ENOMEM;
243 ret = copy_Certificate(c, (*cert)->data);
244 if (ret) {
245 free((*cert)->data);
246 free(*cert);
247 *cert = NULL;
249 return ret;
253 * Just like hx509_cert_init(), but instead of a decode certificate
254 * takes an pointer and length to a memory region that contains a
255 * DER/BER encoded certificate.
257 * If the memory region doesn't contain just the certificate and
258 * nothing more the function will fail with
259 * HX509_EXTRA_DATA_AFTER_STRUCTURE.
261 * @param context A hx509 context.
262 * @param ptr pointer to memory region containing encoded certificate.
263 * @param len length of memory region.
264 * @param cert a return pointer to a hx509 certificate object, will
265 * contain NULL on error.
267 * @return An hx509 error code, see hx509_get_error_string().
269 * @ingroup hx509_cert
273 hx509_cert_init_data(hx509_context context,
274 const void *ptr,
275 size_t len,
276 hx509_cert *cert)
278 Certificate t;
279 size_t size;
280 int ret;
282 ret = decode_Certificate(ptr, len, &t, &size);
283 if (ret) {
284 hx509_set_error_string(context, 0, ret, "Failed to decode certificate");
285 return ret;
287 if (size != len) {
288 free_Certificate(&t);
289 hx509_set_error_string(context, 0, HX509_EXTRA_DATA_AFTER_STRUCTURE,
290 "Extra data after certificate");
291 return HX509_EXTRA_DATA_AFTER_STRUCTURE;
294 ret = hx509_cert_init(context, &t, cert);
295 free_Certificate(&t);
296 return ret;
299 void
300 _hx509_cert_set_release(hx509_cert cert,
301 _hx509_cert_release_func release,
302 void *ctx)
304 cert->release = release;
305 cert->ctx = ctx;
309 /* Doesn't make a copy of `private_key'. */
312 _hx509_cert_assign_key(hx509_cert cert, hx509_private_key private_key)
314 if (cert->private_key)
315 hx509_private_key_free(&cert->private_key);
316 cert->private_key = _hx509_private_key_ref(private_key);
317 return 0;
321 * Free reference to the hx509 certificate object, if the refcounter
322 * reaches 0, the object if freed. Its allowed to pass in NULL.
324 * @param cert the cert to free.
326 * @ingroup hx509_cert
329 void
330 hx509_cert_free(hx509_cert cert)
332 size_t i;
334 if (cert == NULL)
335 return;
337 if (cert->ref <= 0)
338 _hx509_abort("cert refcount <= 0 on free");
339 if (--cert->ref > 0)
340 return;
342 if (cert->release)
343 (cert->release)(cert, cert->ctx);
345 if (cert->private_key)
346 hx509_private_key_free(&cert->private_key);
348 free_Certificate(cert->data);
349 free(cert->data);
351 for (i = 0; i < cert->attrs.len; i++) {
352 der_free_octet_string(&cert->attrs.val[i]->data);
353 der_free_oid(&cert->attrs.val[i]->oid);
354 free(cert->attrs.val[i]);
356 free(cert->attrs.val);
357 free(cert->friendlyname);
358 if (cert->basename)
359 hx509_name_free(&cert->basename);
360 memset(cert, 0, sizeof(*cert));
361 free(cert);
365 * Add a reference to a hx509 certificate object.
367 * @param cert a pointer to an hx509 certificate object.
369 * @return the same object as is passed in.
371 * @ingroup hx509_cert
374 hx509_cert
375 hx509_cert_ref(hx509_cert cert)
377 if (cert == NULL)
378 return NULL;
379 if (cert->ref <= 0)
380 _hx509_abort("cert refcount <= 0");
381 cert->ref++;
382 if (cert->ref == 0)
383 _hx509_abort("cert refcount == 0");
384 return cert;
388 * Allocate an verification context that is used fo control the
389 * verification process.
391 * @param context A hx509 context.
392 * @param ctx returns a pointer to a hx509_verify_ctx object.
394 * @return An hx509 error code, see hx509_get_error_string().
396 * @ingroup hx509_verify
400 hx509_verify_init_ctx(hx509_context context, hx509_verify_ctx *ctx)
402 hx509_verify_ctx c;
404 c = calloc(1, sizeof(*c));
405 if (c == NULL)
406 return ENOMEM;
408 c->max_depth = HX509_VERIFY_MAX_DEPTH;
410 *ctx = c;
412 return 0;
416 * Free an hx509 verification context.
418 * @param ctx the context to be freed.
420 * @ingroup hx509_verify
423 void
424 hx509_verify_destroy_ctx(hx509_verify_ctx ctx)
426 if (ctx) {
427 hx509_certs_free(&ctx->trust_anchors);
428 hx509_revoke_free(&ctx->revoke_ctx);
429 memset(ctx, 0, sizeof(*ctx));
431 free(ctx);
435 * Set the trust anchors in the verification context, makes an
436 * reference to the keyset, so the consumer can free the keyset
437 * independent of the destruction of the verification context (ctx).
438 * If there already is a keyset attached, it's released.
440 * @param ctx a verification context
441 * @param set a keyset containing the trust anchors.
443 * @ingroup hx509_verify
446 void
447 hx509_verify_attach_anchors(hx509_verify_ctx ctx, hx509_certs set)
449 if (ctx->trust_anchors)
450 hx509_certs_free(&ctx->trust_anchors);
451 ctx->trust_anchors = hx509_certs_ref(set);
455 * Attach an revocation context to the verfication context, , makes an
456 * reference to the revoke context, so the consumer can free the
457 * revoke context independent of the destruction of the verification
458 * context. If there is no revoke context, the verification process is
459 * NOT going to check any verification status.
461 * @param ctx a verification context.
462 * @param revoke_ctx a revoke context.
464 * @ingroup hx509_verify
467 void
468 hx509_verify_attach_revoke(hx509_verify_ctx ctx, hx509_revoke_ctx revoke_ctx)
470 if (ctx->revoke_ctx)
471 hx509_revoke_free(&ctx->revoke_ctx);
472 ctx->revoke_ctx = _hx509_revoke_ref(revoke_ctx);
476 * Set the clock time the the verification process is going to
477 * use. Used to check certificate in the past and future time. If not
478 * set the current time will be used.
480 * @param ctx a verification context.
481 * @param t the time the verifiation is using.
484 * @ingroup hx509_verify
487 void
488 hx509_verify_set_time(hx509_verify_ctx ctx, time_t t)
490 ctx->flags |= HX509_VERIFY_CTX_F_TIME_SET;
491 ctx->time_now = t;
494 time_t
495 _hx509_verify_get_time(hx509_verify_ctx ctx)
497 return ctx->time_now;
501 * Set the maximum depth of the certificate chain that the path
502 * builder is going to try.
504 * @param ctx a verification context
505 * @param max_depth maxium depth of the certificate chain, include
506 * trust anchor.
508 * @ingroup hx509_verify
511 void
512 hx509_verify_set_max_depth(hx509_verify_ctx ctx, unsigned int max_depth)
514 ctx->max_depth = max_depth;
518 * Allow or deny the use of proxy certificates
520 * @param ctx a verification context
521 * @param boolean if non zero, allow proxy certificates.
523 * @ingroup hx509_verify
526 void
527 hx509_verify_set_proxy_certificate(hx509_verify_ctx ctx, int boolean)
529 if (boolean)
530 ctx->flags |= HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
531 else
532 ctx->flags &= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
536 * Select strict RFC3280 verification of certificiates. This means
537 * checking key usage on CA certificates, this will make version 1
538 * certificiates unuseable.
540 * @param ctx a verification context
541 * @param boolean if non zero, use strict verification.
543 * @ingroup hx509_verify
546 void
547 hx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx, int boolean)
549 if (boolean)
550 ctx->flags |= HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
551 else
552 ctx->flags &= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
556 * Allow using the operating system builtin trust anchors if no other
557 * trust anchors are configured.
559 * @param ctx a verification context
560 * @param boolean if non zero, useing the operating systems builtin
561 * trust anchors.
564 * @return An hx509 error code, see hx509_get_error_string().
566 * @ingroup hx509_cert
569 void
570 hx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx, int boolean)
572 if (boolean)
573 ctx->flags &= ~HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
574 else
575 ctx->flags |= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
578 void
579 hx509_verify_ctx_f_allow_best_before_signature_algs(hx509_context ctx,
580 int boolean)
582 if (boolean)
583 ctx->flags &= ~HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK;
584 else
585 ctx->flags |= HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK;
588 static const Extension *
589 find_extension(const Certificate *cert, const heim_oid *oid, size_t *idx)
591 const TBSCertificate *c = &cert->tbsCertificate;
593 if (c->version == NULL || *c->version < 2 || c->extensions == NULL)
594 return NULL;
596 for (;*idx < c->extensions->len; (*idx)++) {
597 if (der_heim_oid_cmp(&c->extensions->val[*idx].extnID, oid) == 0)
598 return &c->extensions->val[(*idx)++];
600 return NULL;
603 static int
604 find_extension_auth_key_id(const Certificate *subject,
605 AuthorityKeyIdentifier *ai)
607 const Extension *e;
608 size_t size;
609 size_t i = 0;
611 memset(ai, 0, sizeof(*ai));
613 e = find_extension(subject, &asn1_oid_id_x509_ce_authorityKeyIdentifier, &i);
614 if (e == NULL)
615 return HX509_EXTENSION_NOT_FOUND;
617 return decode_AuthorityKeyIdentifier(e->extnValue.data,
618 e->extnValue.length,
619 ai, &size);
623 _hx509_find_extension_subject_key_id(const Certificate *issuer,
624 SubjectKeyIdentifier *si)
626 const Extension *e;
627 size_t size;
628 size_t i = 0;
630 memset(si, 0, sizeof(*si));
632 e = find_extension(issuer, &asn1_oid_id_x509_ce_subjectKeyIdentifier, &i);
633 if (e == NULL)
634 return HX509_EXTENSION_NOT_FOUND;
636 return decode_SubjectKeyIdentifier(e->extnValue.data,
637 e->extnValue.length,
638 si, &size);
641 static int
642 find_extension_name_constraints(const Certificate *subject,
643 NameConstraints *nc)
645 const Extension *e;
646 size_t size;
647 size_t i = 0;
649 memset(nc, 0, sizeof(*nc));
651 e = find_extension(subject, &asn1_oid_id_x509_ce_nameConstraints, &i);
652 if (e == NULL)
653 return HX509_EXTENSION_NOT_FOUND;
655 return decode_NameConstraints(e->extnValue.data,
656 e->extnValue.length,
657 nc, &size);
660 static int
661 find_extension_subject_alt_name(const Certificate *cert, size_t *i,
662 GeneralNames *sa)
664 const Extension *e;
665 size_t size;
667 memset(sa, 0, sizeof(*sa));
669 e = find_extension(cert, &asn1_oid_id_x509_ce_subjectAltName, i);
670 if (e == NULL)
671 return HX509_EXTENSION_NOT_FOUND;
673 return decode_GeneralNames(e->extnValue.data,
674 e->extnValue.length,
675 sa, &size);
678 static int
679 find_extension_eku(const Certificate *cert, ExtKeyUsage *eku)
681 const Extension *e;
682 size_t size;
683 size_t i = 0;
685 memset(eku, 0, sizeof(*eku));
687 e = find_extension(cert, &asn1_oid_id_x509_ce_extKeyUsage, &i);
688 if (e == NULL)
689 return HX509_EXTENSION_NOT_FOUND;
691 return decode_ExtKeyUsage(e->extnValue.data,
692 e->extnValue.length,
693 eku, &size);
696 static int
697 add_to_list(hx509_octet_string_list *list, const heim_octet_string *entry)
699 void *p;
700 int ret;
702 p = realloc(list->val, (list->len + 1) * sizeof(list->val[0]));
703 if (p == NULL)
704 return ENOMEM;
705 list->val = p;
706 ret = der_copy_octet_string(entry, &list->val[list->len]);
707 if (ret)
708 return ret;
709 list->len++;
710 return 0;
714 * Free a list of octet strings returned by another hx509 library
715 * function.
717 * @param list list to be freed.
719 * @ingroup hx509_misc
722 void
723 hx509_free_octet_string_list(hx509_octet_string_list *list)
725 size_t i;
726 for (i = 0; i < list->len; i++)
727 der_free_octet_string(&list->val[i]);
728 free(list->val);
729 list->val = NULL;
730 list->len = 0;
734 * Return a list of subjectAltNames specified by oid in the
735 * certificate. On error the
737 * The returned list of octet string should be freed with
738 * hx509_free_octet_string_list().
740 * @param context A hx509 context.
741 * @param cert a hx509 certificate object.
742 * @param oid an oid to for SubjectAltName.
743 * @param list list of matching SubjectAltName.
745 * @return An hx509 error code, see hx509_get_error_string().
747 * @ingroup hx509_cert
751 hx509_cert_find_subjectAltName_otherName(hx509_context context,
752 hx509_cert cert,
753 const heim_oid *oid,
754 hx509_octet_string_list *list)
756 GeneralNames sa;
757 int ret;
758 size_t i, j;
760 list->val = NULL;
761 list->len = 0;
763 i = 0;
764 while (1) {
765 ret = find_extension_subject_alt_name(_hx509_get_cert(cert), &i, &sa);
766 i++;
767 if (ret == HX509_EXTENSION_NOT_FOUND) {
768 return 0;
769 } else if (ret != 0) {
770 hx509_set_error_string(context, 0, ret, "Error searching for SAN");
771 hx509_free_octet_string_list(list);
772 return ret;
775 for (j = 0; j < sa.len; j++) {
776 if (sa.val[j].element == choice_GeneralName_otherName &&
777 der_heim_oid_cmp(&sa.val[j].u.otherName.type_id, oid) == 0)
779 ret = add_to_list(list, &sa.val[j].u.otherName.value);
780 if (ret) {
781 hx509_set_error_string(context, 0, ret,
782 "Error adding an exra SAN to "
783 "return list");
784 hx509_free_octet_string_list(list);
785 free_GeneralNames(&sa);
786 return ret;
790 free_GeneralNames(&sa);
795 static int
796 check_key_usage(hx509_context context, const Certificate *cert,
797 unsigned flags, int req_present)
799 const Extension *e;
800 KeyUsage ku;
801 size_t size;
802 int ret;
803 size_t i = 0;
804 unsigned ku_flags;
806 if (_hx509_cert_get_version(cert) < 3)
807 return 0;
809 e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i);
810 if (e == NULL) {
811 if (req_present) {
812 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
813 "Required extension key "
814 "usage missing from certifiate");
815 return HX509_KU_CERT_MISSING;
817 return 0;
820 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, &ku, &size);
821 if (ret)
822 return ret;
823 ku_flags = KeyUsage2int(ku);
824 if ((ku_flags & flags) != flags) {
825 unsigned missing = (~ku_flags) & flags;
826 char buf[256], *name;
828 unparse_flags(missing, asn1_KeyUsage_units(), buf, sizeof(buf));
829 _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
830 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
831 "Key usage %s required but missing "
832 "from certifiate %s", buf, name);
833 free(name);
834 return HX509_KU_CERT_MISSING;
836 return 0;
840 * Return 0 on matching key usage 'flags' for 'cert', otherwise return
841 * an error code. If 'req_present' the existance is required of the
842 * KeyUsage extension.
846 _hx509_check_key_usage(hx509_context context, hx509_cert cert,
847 unsigned flags, int req_present)
849 return check_key_usage(context, _hx509_get_cert(cert), flags, req_present);
852 enum certtype { PROXY_CERT, EE_CERT, CA_CERT };
854 static int
855 check_basic_constraints(hx509_context context, const Certificate *cert,
856 enum certtype type, size_t depth)
858 BasicConstraints bc;
859 const Extension *e;
860 size_t size;
861 int ret;
862 size_t i = 0;
864 if (_hx509_cert_get_version(cert) < 3)
865 return 0;
867 e = find_extension(cert, &asn1_oid_id_x509_ce_basicConstraints, &i);
868 if (e == NULL) {
869 switch(type) {
870 case PROXY_CERT:
871 case EE_CERT:
872 return 0;
873 case CA_CERT: {
874 char *name;
875 ret = _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
876 assert(ret == 0);
877 hx509_set_error_string(context, 0, HX509_EXTENSION_NOT_FOUND,
878 "basicConstraints missing from "
879 "CA certifiacte %s", name);
880 free(name);
881 return HX509_EXTENSION_NOT_FOUND;
886 ret = decode_BasicConstraints(e->extnValue.data,
887 e->extnValue.length, &bc,
888 &size);
889 if (ret)
890 return ret;
891 switch(type) {
892 case PROXY_CERT:
893 if (bc.cA != NULL && *bc.cA)
894 ret = HX509_PARENT_IS_CA;
895 break;
896 case EE_CERT:
897 ret = 0;
898 break;
899 case CA_CERT:
900 if (bc.cA == NULL || !*bc.cA)
901 ret = HX509_PARENT_NOT_CA;
902 else if (bc.pathLenConstraint)
903 if (depth - 1 > *bc.pathLenConstraint)
904 ret = HX509_CA_PATH_TOO_DEEP;
905 break;
907 free_BasicConstraints(&bc);
908 return ret;
912 _hx509_cert_is_parent_cmp(const Certificate *subject,
913 const Certificate *issuer,
914 int allow_self_signed)
916 int diff;
917 AuthorityKeyIdentifier ai;
918 SubjectKeyIdentifier si;
919 int ret_ai, ret_si, ret;
921 ret = _hx509_name_cmp(&issuer->tbsCertificate.subject,
922 &subject->tbsCertificate.issuer,
923 &diff);
924 if (ret)
925 return ret;
926 if (diff)
927 return diff;
929 memset(&ai, 0, sizeof(ai));
930 memset(&si, 0, sizeof(si));
933 * Try to find AuthorityKeyIdentifier, if it's not present in the
934 * subject certificate nor the parent.
937 ret_ai = find_extension_auth_key_id(subject, &ai);
938 if (ret_ai && ret_ai != HX509_EXTENSION_NOT_FOUND)
939 return 1;
940 ret_si = _hx509_find_extension_subject_key_id(issuer, &si);
941 if (ret_si && ret_si != HX509_EXTENSION_NOT_FOUND)
942 return -1;
944 if (ret_si && ret_ai)
945 goto out;
946 if (ret_ai)
947 goto out;
948 if (ret_si) {
949 if (allow_self_signed) {
950 diff = 0;
951 goto out;
952 } else if (ai.keyIdentifier) {
953 diff = -1;
954 goto out;
958 if (ai.keyIdentifier == NULL) {
959 Name name;
961 if (ai.authorityCertIssuer == NULL)
962 return -1;
963 if (ai.authorityCertSerialNumber == NULL)
964 return -1;
966 diff = der_heim_integer_cmp(ai.authorityCertSerialNumber,
967 &issuer->tbsCertificate.serialNumber);
968 if (diff)
969 return diff;
970 if (ai.authorityCertIssuer->len != 1)
971 return -1;
972 if (ai.authorityCertIssuer->val[0].element != choice_GeneralName_directoryName)
973 return -1;
975 name.element =
976 ai.authorityCertIssuer->val[0].u.directoryName.element;
977 name.u.rdnSequence =
978 ai.authorityCertIssuer->val[0].u.directoryName.u.rdnSequence;
980 ret = _hx509_name_cmp(&issuer->tbsCertificate.subject,
981 &name,
982 &diff);
983 if (ret)
984 return ret;
985 if (diff)
986 return diff;
987 diff = 0;
988 } else
989 diff = der_heim_octet_string_cmp(ai.keyIdentifier, &si);
990 if (diff)
991 goto out;
993 out:
994 free_AuthorityKeyIdentifier(&ai);
995 free_SubjectKeyIdentifier(&si);
996 return diff;
999 static int
1000 certificate_is_anchor(hx509_context context,
1001 hx509_certs trust_anchors,
1002 const hx509_cert cert)
1004 hx509_query q;
1005 hx509_cert c;
1006 int ret;
1008 if (trust_anchors == NULL)
1009 return 0;
1011 _hx509_query_clear(&q);
1013 q.match = HX509_QUERY_MATCH_CERTIFICATE;
1014 q.certificate = _hx509_get_cert(cert);
1016 ret = hx509_certs_find(context, trust_anchors, &q, &c);
1017 if (ret == 0)
1018 hx509_cert_free(c);
1019 return ret == 0;
1022 static int
1023 certificate_is_self_signed(hx509_context context,
1024 const Certificate *cert,
1025 int *self_signed)
1027 int ret, diff;
1028 ret = _hx509_name_cmp(&cert->tbsCertificate.subject,
1029 &cert->tbsCertificate.issuer, &diff);
1030 *self_signed = (diff == 0);
1031 if (ret) {
1032 hx509_set_error_string(context, 0, ret,
1033 "Failed to check if self signed");
1034 } else
1035 ret = _hx509_self_signed_valid(context, &cert->signatureAlgorithm);
1037 return ret;
1041 * The subjectName is "null" when it's empty set of relative DBs.
1044 static int
1045 subject_null_p(const Certificate *c)
1047 return c->tbsCertificate.subject.u.rdnSequence.len == 0;
1051 static int
1052 find_parent(hx509_context context,
1053 time_t time_now,
1054 hx509_certs trust_anchors,
1055 hx509_path *path,
1056 hx509_certs pool,
1057 hx509_cert current,
1058 hx509_cert *parent)
1060 AuthorityKeyIdentifier ai;
1061 hx509_query q;
1062 int ret;
1064 *parent = NULL;
1065 memset(&ai, 0, sizeof(ai));
1067 _hx509_query_clear(&q);
1069 if (!subject_null_p(current->data)) {
1070 q.match |= HX509_QUERY_FIND_ISSUER_CERT;
1071 q.subject = _hx509_get_cert(current);
1072 } else {
1073 ret = find_extension_auth_key_id(current->data, &ai);
1074 if (ret) {
1075 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1076 "Subjectless certificate missing AuthKeyID");
1077 return HX509_CERTIFICATE_MALFORMED;
1080 if (ai.keyIdentifier == NULL) {
1081 free_AuthorityKeyIdentifier(&ai);
1082 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1083 "Subjectless certificate missing keyIdentifier "
1084 "inside AuthKeyID");
1085 return HX509_CERTIFICATE_MALFORMED;
1088 q.subject_id = ai.keyIdentifier;
1089 q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
1092 q.path = path;
1093 q.match |= HX509_QUERY_NO_MATCH_PATH;
1095 if (pool) {
1096 q.timenow = time_now;
1097 q.match |= HX509_QUERY_MATCH_TIME;
1099 ret = hx509_certs_find(context, pool, &q, parent);
1100 if (ret == 0) {
1101 free_AuthorityKeyIdentifier(&ai);
1102 return 0;
1104 q.match &= ~HX509_QUERY_MATCH_TIME;
1107 if (trust_anchors) {
1108 ret = hx509_certs_find(context, trust_anchors, &q, parent);
1109 if (ret == 0) {
1110 free_AuthorityKeyIdentifier(&ai);
1111 return ret;
1114 free_AuthorityKeyIdentifier(&ai);
1117 hx509_name name;
1118 char *str;
1120 ret = hx509_cert_get_subject(current, &name);
1121 if (ret) {
1122 hx509_clear_error_string(context);
1123 return HX509_ISSUER_NOT_FOUND;
1125 ret = hx509_name_to_string(name, &str);
1126 hx509_name_free(&name);
1127 if (ret) {
1128 hx509_clear_error_string(context);
1129 return HX509_ISSUER_NOT_FOUND;
1132 hx509_set_error_string(context, 0, HX509_ISSUER_NOT_FOUND,
1133 "Failed to find issuer for "
1134 "certificate with subject: '%s'", str);
1135 free(str);
1137 return HX509_ISSUER_NOT_FOUND;
1144 static int
1145 is_proxy_cert(hx509_context context,
1146 const Certificate *cert,
1147 ProxyCertInfo *rinfo)
1149 ProxyCertInfo info;
1150 const Extension *e;
1151 size_t size;
1152 int ret;
1153 size_t i = 0;
1155 if (rinfo)
1156 memset(rinfo, 0, sizeof(*rinfo));
1158 e = find_extension(cert, &asn1_oid_id_pkix_pe_proxyCertInfo, &i);
1159 if (e == NULL) {
1160 hx509_clear_error_string(context);
1161 return HX509_EXTENSION_NOT_FOUND;
1164 ret = decode_ProxyCertInfo(e->extnValue.data,
1165 e->extnValue.length,
1166 &info,
1167 &size);
1168 if (ret) {
1169 hx509_clear_error_string(context);
1170 return ret;
1172 if (size != e->extnValue.length) {
1173 free_ProxyCertInfo(&info);
1174 hx509_clear_error_string(context);
1175 return HX509_EXTRA_DATA_AFTER_STRUCTURE;
1177 if (rinfo == NULL)
1178 free_ProxyCertInfo(&info);
1179 else
1180 *rinfo = info;
1182 return 0;
1186 * Path operations are like MEMORY based keyset, but with exposed
1187 * internal so we can do easy searches.
1191 _hx509_path_append(hx509_context context, hx509_path *path, hx509_cert cert)
1193 hx509_cert *val;
1194 val = realloc(path->val, (path->len + 1) * sizeof(path->val[0]));
1195 if (val == NULL) {
1196 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1197 return ENOMEM;
1200 path->val = val;
1201 path->val[path->len] = hx509_cert_ref(cert);
1202 path->len++;
1204 return 0;
1207 void
1208 _hx509_path_free(hx509_path *path)
1210 unsigned i;
1212 for (i = 0; i < path->len; i++)
1213 hx509_cert_free(path->val[i]);
1214 free(path->val);
1215 path->val = NULL;
1216 path->len = 0;
1220 * Find path by looking up issuer for the top certificate and continue
1221 * until an anchor certificate is found or max limit is found. A
1222 * certificate never included twice in the path.
1224 * If the trust anchors are not given, calculate optimistic path, just
1225 * follow the chain upward until we no longer find a parent or we hit
1226 * the max path limit. In this case, a failure will always be returned
1227 * depending on what error condition is hit first.
1229 * The path includes a path from the top certificate to the anchor
1230 * certificate.
1232 * The caller needs to free `path´ both on successful built path and
1233 * failure.
1237 _hx509_calculate_path(hx509_context context,
1238 int flags,
1239 time_t time_now,
1240 hx509_certs anchors,
1241 unsigned int max_depth,
1242 hx509_cert cert,
1243 hx509_certs pool,
1244 hx509_path *path)
1246 hx509_cert parent, current;
1247 int ret;
1249 if (max_depth == 0)
1250 max_depth = HX509_VERIFY_MAX_DEPTH;
1252 ret = _hx509_path_append(context, path, cert);
1253 if (ret)
1254 return ret;
1256 current = hx509_cert_ref(cert);
1258 while (!certificate_is_anchor(context, anchors, current)) {
1260 ret = find_parent(context, time_now, anchors, path,
1261 pool, current, &parent);
1262 hx509_cert_free(current);
1263 if (ret)
1264 return ret;
1266 ret = _hx509_path_append(context, path, parent);
1267 if (ret)
1268 return ret;
1269 current = parent;
1271 if (path->len > max_depth) {
1272 hx509_cert_free(current);
1273 hx509_set_error_string(context, 0, HX509_PATH_TOO_LONG,
1274 "Path too long while bulding "
1275 "certificate chain");
1276 return HX509_PATH_TOO_LONG;
1280 if ((flags & HX509_CALCULATE_PATH_NO_ANCHOR) &&
1281 path->len > 0 &&
1282 certificate_is_anchor(context, anchors, path->val[path->len - 1]))
1284 hx509_cert_free(path->val[path->len - 1]);
1285 path->len--;
1288 hx509_cert_free(current);
1289 return 0;
1293 _hx509_AlgorithmIdentifier_cmp(const AlgorithmIdentifier *p,
1294 const AlgorithmIdentifier *q)
1296 int diff;
1297 diff = der_heim_oid_cmp(&p->algorithm, &q->algorithm);
1298 if (diff)
1299 return diff;
1300 if (p->parameters) {
1301 if (q->parameters)
1302 return heim_any_cmp(p->parameters,
1303 q->parameters);
1304 else
1305 return 1;
1306 } else {
1307 if (q->parameters)
1308 return -1;
1309 else
1310 return 0;
1315 _hx509_Certificate_cmp(const Certificate *p, const Certificate *q)
1317 int diff;
1318 diff = der_heim_bit_string_cmp(&p->signatureValue, &q->signatureValue);
1319 if (diff)
1320 return diff;
1321 diff = _hx509_AlgorithmIdentifier_cmp(&p->signatureAlgorithm,
1322 &q->signatureAlgorithm);
1323 if (diff)
1324 return diff;
1325 diff = der_heim_octet_string_cmp(&p->tbsCertificate._save,
1326 &q->tbsCertificate._save);
1327 return diff;
1331 * Compare to hx509 certificate object, useful for sorting.
1333 * @param p a hx509 certificate object.
1334 * @param q a hx509 certificate object.
1336 * @return 0 the objects are the same, returns > 0 is p is "larger"
1337 * then q, < 0 if p is "smaller" then q.
1339 * @ingroup hx509_cert
1343 hx509_cert_cmp(hx509_cert p, hx509_cert q)
1345 return _hx509_Certificate_cmp(p->data, q->data);
1349 * Return the name of the issuer of the hx509 certificate.
1351 * @param p a hx509 certificate object.
1352 * @param name a pointer to a hx509 name, should be freed by
1353 * hx509_name_free().
1355 * @return An hx509 error code, see hx509_get_error_string().
1357 * @ingroup hx509_cert
1361 hx509_cert_get_issuer(hx509_cert p, hx509_name *name)
1363 return _hx509_name_from_Name(&p->data->tbsCertificate.issuer, name);
1367 * Return the name of the subject of the hx509 certificate.
1369 * @param p a hx509 certificate object.
1370 * @param name a pointer to a hx509 name, should be freed by
1371 * hx509_name_free(). See also hx509_cert_get_base_subject().
1373 * @return An hx509 error code, see hx509_get_error_string().
1375 * @ingroup hx509_cert
1379 hx509_cert_get_subject(hx509_cert p, hx509_name *name)
1381 return _hx509_name_from_Name(&p->data->tbsCertificate.subject, name);
1385 * Return the name of the base subject of the hx509 certificate. If
1386 * the certiicate is a verified proxy certificate, the this function
1387 * return the base certificate (root of the proxy chain). If the proxy
1388 * certificate is not verified with the base certificate
1389 * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned.
1391 * @param context a hx509 context.
1392 * @param c a hx509 certificate object.
1393 * @param name a pointer to a hx509 name, should be freed by
1394 * hx509_name_free(). See also hx509_cert_get_subject().
1396 * @return An hx509 error code, see hx509_get_error_string().
1398 * @ingroup hx509_cert
1402 hx509_cert_get_base_subject(hx509_context context, hx509_cert c,
1403 hx509_name *name)
1405 if (c->basename)
1406 return hx509_name_copy(context, c->basename, name);
1407 if (is_proxy_cert(context, c->data, NULL) == 0) {
1408 int ret = HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED;
1409 hx509_set_error_string(context, 0, ret,
1410 "Proxy certificate have not been "
1411 "canonicalize yet, no base name");
1412 return ret;
1414 return _hx509_name_from_Name(&c->data->tbsCertificate.subject, name);
1418 * Get serial number of the certificate.
1420 * @param p a hx509 certificate object.
1421 * @param i serial number, should be freed ith der_free_heim_integer().
1423 * @return An hx509 error code, see hx509_get_error_string().
1425 * @ingroup hx509_cert
1429 hx509_cert_get_serialnumber(hx509_cert p, heim_integer *i)
1431 return der_copy_heim_integer(&p->data->tbsCertificate.serialNumber, i);
1435 * Get notBefore time of the certificate.
1437 * @param p a hx509 certificate object.
1439 * @return return not before time
1441 * @ingroup hx509_cert
1444 time_t
1445 hx509_cert_get_notBefore(hx509_cert p)
1447 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notBefore);
1451 * Get notAfter time of the certificate.
1453 * @param p a hx509 certificate object.
1455 * @return return not after time.
1457 * @ingroup hx509_cert
1460 time_t
1461 hx509_cert_get_notAfter(hx509_cert p)
1463 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notAfter);
1467 * Get the SubjectPublicKeyInfo structure from the hx509 certificate.
1469 * @param context a hx509 context.
1470 * @param p a hx509 certificate object.
1471 * @param spki SubjectPublicKeyInfo, should be freed with
1472 * free_SubjectPublicKeyInfo().
1474 * @return An hx509 error code, see hx509_get_error_string().
1476 * @ingroup hx509_cert
1480 hx509_cert_get_SPKI(hx509_context context, hx509_cert p, SubjectPublicKeyInfo *spki)
1482 int ret;
1484 ret = copy_SubjectPublicKeyInfo(&p->data->tbsCertificate.subjectPublicKeyInfo, spki);
1485 if (ret)
1486 hx509_set_error_string(context, 0, ret, "Failed to copy SPKI");
1487 return ret;
1491 * Get the AlgorithmIdentifier from the hx509 certificate.
1493 * @param context a hx509 context.
1494 * @param p a hx509 certificate object.
1495 * @param alg AlgorithmIdentifier, should be freed with
1496 * free_AlgorithmIdentifier(). The algorithmidentifier is
1497 * typicly rsaEncryption, or id-ecPublicKey, or some other
1498 * public key mechanism.
1500 * @return An hx509 error code, see hx509_get_error_string().
1502 * @ingroup hx509_cert
1506 hx509_cert_get_SPKI_AlgorithmIdentifier(hx509_context context,
1507 hx509_cert p,
1508 AlgorithmIdentifier *alg)
1510 int ret;
1512 ret = copy_AlgorithmIdentifier(&p->data->tbsCertificate.subjectPublicKeyInfo.algorithm, alg);
1513 if (ret)
1514 hx509_set_error_string(context, 0, ret,
1515 "Failed to copy SPKI AlgorithmIdentifier");
1516 return ret;
1519 static int
1520 get_x_unique_id(hx509_context context, const char *name,
1521 const heim_bit_string *cert, heim_bit_string *subject)
1523 int ret;
1525 if (cert == NULL) {
1526 ret = HX509_EXTENSION_NOT_FOUND;
1527 hx509_set_error_string(context, 0, ret, "%s unique id doesn't exists", name);
1528 return ret;
1530 ret = der_copy_bit_string(cert, subject);
1531 if (ret) {
1532 hx509_set_error_string(context, 0, ret, "malloc out of memory", name);
1533 return ret;
1535 return 0;
1539 * Get a copy of the Issuer Unique ID
1541 * @param context a hx509_context
1542 * @param p a hx509 certificate
1543 * @param issuer the issuer id returned, free with der_free_bit_string()
1545 * @return An hx509 error code, see hx509_get_error_string(). The
1546 * error code HX509_EXTENSION_NOT_FOUND is returned if the certificate
1547 * doesn't have a issuerUniqueID
1549 * @ingroup hx509_cert
1553 hx509_cert_get_issuer_unique_id(hx509_context context, hx509_cert p, heim_bit_string *issuer)
1555 return get_x_unique_id(context, "issuer", p->data->tbsCertificate.issuerUniqueID, issuer);
1559 * Get a copy of the Subect Unique ID
1561 * @param context a hx509_context
1562 * @param p a hx509 certificate
1563 * @param subject the subject id returned, free with der_free_bit_string()
1565 * @return An hx509 error code, see hx509_get_error_string(). The
1566 * error code HX509_EXTENSION_NOT_FOUND is returned if the certificate
1567 * doesn't have a subjectUniqueID
1569 * @ingroup hx509_cert
1573 hx509_cert_get_subject_unique_id(hx509_context context, hx509_cert p, heim_bit_string *subject)
1575 return get_x_unique_id(context, "subject", p->data->tbsCertificate.subjectUniqueID, subject);
1579 hx509_private_key
1580 _hx509_cert_private_key(hx509_cert p)
1582 return p->private_key;
1586 hx509_cert_have_private_key(hx509_cert p)
1588 return p->private_key ? 1 : 0;
1593 _hx509_cert_private_key_exportable(hx509_cert p)
1595 if (p->private_key == NULL)
1596 return 0;
1597 return _hx509_private_key_exportable(p->private_key);
1601 _hx509_cert_private_decrypt(hx509_context context,
1602 const heim_octet_string *ciphertext,
1603 const heim_oid *encryption_oid,
1604 hx509_cert p,
1605 heim_octet_string *cleartext)
1607 cleartext->data = NULL;
1608 cleartext->length = 0;
1610 if (p->private_key == NULL) {
1611 hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
1612 "Private key missing");
1613 return HX509_PRIVATE_KEY_MISSING;
1616 return hx509_private_key_private_decrypt(context,
1617 ciphertext,
1618 encryption_oid,
1619 p->private_key,
1620 cleartext);
1624 hx509_cert_public_encrypt(hx509_context context,
1625 const heim_octet_string *cleartext,
1626 const hx509_cert p,
1627 heim_oid *encryption_oid,
1628 heim_octet_string *ciphertext)
1630 return _hx509_public_encrypt(context,
1631 cleartext, p->data,
1632 encryption_oid, ciphertext);
1639 time_t
1640 _hx509_Time2time_t(const Time *t)
1642 switch(t->element) {
1643 case choice_Time_utcTime:
1644 return t->u.utcTime;
1645 case choice_Time_generalTime:
1646 return t->u.generalTime;
1648 return 0;
1655 static int
1656 init_name_constraints(hx509_name_constraints *nc)
1658 memset(nc, 0, sizeof(*nc));
1659 return 0;
1662 static int
1663 add_name_constraints(hx509_context context, const Certificate *c, int not_ca,
1664 hx509_name_constraints *nc)
1666 NameConstraints tnc;
1667 int ret;
1669 ret = find_extension_name_constraints(c, &tnc);
1670 if (ret == HX509_EXTENSION_NOT_FOUND)
1671 return 0;
1672 else if (ret) {
1673 hx509_set_error_string(context, 0, ret, "Failed getting NameConstraints");
1674 return ret;
1675 } else if (not_ca) {
1676 ret = HX509_VERIFY_CONSTRAINTS;
1677 hx509_set_error_string(context, 0, ret, "Not a CA and "
1678 "have NameConstraints");
1679 } else {
1680 NameConstraints *val;
1681 val = realloc(nc->val, sizeof(nc->val[0]) * (nc->len + 1));
1682 if (val == NULL) {
1683 hx509_clear_error_string(context);
1684 ret = ENOMEM;
1685 goto out;
1687 nc->val = val;
1688 ret = copy_NameConstraints(&tnc, &nc->val[nc->len]);
1689 if (ret) {
1690 hx509_clear_error_string(context);
1691 goto out;
1693 nc->len += 1;
1695 out:
1696 free_NameConstraints(&tnc);
1697 return ret;
1700 static int
1701 match_RDN(const RelativeDistinguishedName *c,
1702 const RelativeDistinguishedName *n)
1704 size_t i;
1706 if (c->len != n->len)
1707 return HX509_NAME_CONSTRAINT_ERROR;
1709 for (i = 0; i < n->len; i++) {
1710 int diff, ret;
1712 if (der_heim_oid_cmp(&c->val[i].type, &n->val[i].type) != 0)
1713 return HX509_NAME_CONSTRAINT_ERROR;
1714 ret = _hx509_name_ds_cmp(&c->val[i].value, &n->val[i].value, &diff);
1715 if (ret)
1716 return ret;
1717 if (diff != 0)
1718 return HX509_NAME_CONSTRAINT_ERROR;
1720 return 0;
1723 static int
1724 match_X501Name(const Name *c, const Name *n)
1726 size_t i;
1727 int ret;
1729 if (c->element != choice_Name_rdnSequence
1730 || n->element != choice_Name_rdnSequence)
1731 return 0;
1732 if (c->u.rdnSequence.len > n->u.rdnSequence.len)
1733 return HX509_NAME_CONSTRAINT_ERROR;
1734 for (i = 0; i < c->u.rdnSequence.len; i++) {
1735 ret = match_RDN(&c->u.rdnSequence.val[i], &n->u.rdnSequence.val[i]);
1736 if (ret)
1737 return ret;
1739 return 0;
1743 static int
1744 match_general_name(const GeneralName *c, const GeneralName *n, int *match)
1747 * Name constraints only apply to the same name type, see RFC3280,
1748 * 4.2.1.11.
1750 assert(c->element == n->element);
1752 switch(c->element) {
1753 case choice_GeneralName_otherName:
1754 if (der_heim_oid_cmp(&c->u.otherName.type_id,
1755 &n->u.otherName.type_id) != 0)
1756 return HX509_NAME_CONSTRAINT_ERROR;
1757 if (heim_any_cmp(&c->u.otherName.value,
1758 &n->u.otherName.value) != 0)
1759 return HX509_NAME_CONSTRAINT_ERROR;
1760 *match = 1;
1761 return 0;
1762 case choice_GeneralName_rfc822Name: {
1763 const char *s;
1764 size_t len1, len2;
1765 s = memchr(c->u.rfc822Name.data, '@', c->u.rfc822Name.length);
1766 if (s) {
1767 if (der_printable_string_cmp(&c->u.rfc822Name, &n->u.rfc822Name) != 0)
1768 return HX509_NAME_CONSTRAINT_ERROR;
1769 } else {
1770 s = memchr(n->u.rfc822Name.data, '@', n->u.rfc822Name.length);
1771 if (s == NULL)
1772 return HX509_NAME_CONSTRAINT_ERROR;
1773 len1 = c->u.rfc822Name.length;
1774 len2 = n->u.rfc822Name.length -
1775 (s - ((char *)n->u.rfc822Name.data));
1776 if (len1 > len2)
1777 return HX509_NAME_CONSTRAINT_ERROR;
1778 if (memcmp(s + 1 + len2 - len1, c->u.rfc822Name.data, len1) != 0)
1779 return HX509_NAME_CONSTRAINT_ERROR;
1780 if (len1 < len2 && s[len2 - len1 + 1] != '.')
1781 return HX509_NAME_CONSTRAINT_ERROR;
1783 *match = 1;
1784 return 0;
1786 case choice_GeneralName_dNSName: {
1787 size_t lenc, lenn;
1788 char *ptr;
1790 lenc = c->u.dNSName.length;
1791 lenn = n->u.dNSName.length;
1792 if (lenc > lenn)
1793 return HX509_NAME_CONSTRAINT_ERROR;
1794 ptr = n->u.dNSName.data;
1795 if (memcmp(&ptr[lenn - lenc], c->u.dNSName.data, lenc) != 0)
1796 return HX509_NAME_CONSTRAINT_ERROR;
1797 if (lenn != lenc && ptr[lenn - lenc - 1] != '.')
1798 return HX509_NAME_CONSTRAINT_ERROR;
1799 *match = 1;
1800 return 0;
1802 case choice_GeneralName_directoryName: {
1803 Name c_name, n_name;
1804 int ret;
1806 c_name._save.data = NULL;
1807 c_name._save.length = 0;
1808 c_name.element = c->u.directoryName.element;
1809 c_name.u.rdnSequence = c->u.directoryName.u.rdnSequence;
1811 n_name._save.data = NULL;
1812 n_name._save.length = 0;
1813 n_name.element = n->u.directoryName.element;
1814 n_name.u.rdnSequence = n->u.directoryName.u.rdnSequence;
1816 ret = match_X501Name(&c_name, &n_name);
1817 if (ret == 0)
1818 *match = 1;
1819 return ret;
1821 case choice_GeneralName_uniformResourceIdentifier:
1822 case choice_GeneralName_iPAddress:
1823 case choice_GeneralName_registeredID:
1824 default:
1825 return HX509_NAME_CONSTRAINT_ERROR;
1829 static int
1830 match_alt_name(const GeneralName *n, const Certificate *c,
1831 int *same, int *match)
1833 GeneralNames sa;
1834 int ret;
1835 size_t i, j;
1837 i = 0;
1838 do {
1839 ret = find_extension_subject_alt_name(c, &i, &sa);
1840 if (ret == HX509_EXTENSION_NOT_FOUND) {
1841 ret = 0;
1842 break;
1843 } else if (ret != 0)
1844 break;
1846 for (j = 0; j < sa.len; j++) {
1847 if (n->element == sa.val[j].element) {
1848 *same = 1;
1849 ret = match_general_name(n, &sa.val[j], match);
1852 free_GeneralNames(&sa);
1853 } while (1);
1854 return ret;
1858 static int
1859 match_tree(const GeneralSubtrees *t, const Certificate *c, int *match)
1861 int name, alt_name, same;
1862 unsigned int i;
1863 int ret = 0;
1865 name = alt_name = same = *match = 0;
1866 for (i = 0; i < t->len; i++) {
1867 if (t->val[i].minimum && t->val[i].maximum)
1868 return HX509_RANGE;
1871 * If the constraint apply to directoryNames, test is with
1872 * subjectName of the certificate if the certificate have a
1873 * non-null (empty) subjectName.
1876 if (t->val[i].base.element == choice_GeneralName_directoryName
1877 && !subject_null_p(c))
1879 GeneralName certname;
1881 memset(&certname, 0, sizeof(certname));
1882 certname.element = choice_GeneralName_directoryName;
1883 certname.u.directoryName.element =
1884 c->tbsCertificate.subject.element;
1885 certname.u.directoryName.u.rdnSequence =
1886 c->tbsCertificate.subject.u.rdnSequence;
1888 ret = match_general_name(&t->val[i].base, &certname, &name);
1891 /* Handle subjectAltNames, this is icky since they
1892 * restrictions only apply if the subjectAltName is of the
1893 * same type. So if there have been a match of type, require
1894 * altname to be set.
1896 ret = match_alt_name(&t->val[i].base, c, &same, &alt_name);
1898 if (name && (!same || alt_name))
1899 *match = 1;
1900 return ret;
1903 static int
1904 check_name_constraints(hx509_context context,
1905 const hx509_name_constraints *nc,
1906 const Certificate *c)
1908 int match, ret;
1909 size_t i;
1911 for (i = 0 ; i < nc->len; i++) {
1912 GeneralSubtrees gs;
1914 if (nc->val[i].permittedSubtrees) {
1915 GeneralSubtrees_SET(&gs, nc->val[i].permittedSubtrees);
1916 ret = match_tree(&gs, c, &match);
1917 if (ret) {
1918 hx509_clear_error_string(context);
1919 return ret;
1921 /* allow null subjectNames, they wont matches anything */
1922 if (match == 0 && !subject_null_p(c)) {
1923 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1924 "Error verify constraints, "
1925 "certificate didn't match any "
1926 "permitted subtree");
1927 return HX509_VERIFY_CONSTRAINTS;
1930 if (nc->val[i].excludedSubtrees) {
1931 GeneralSubtrees_SET(&gs, nc->val[i].excludedSubtrees);
1932 ret = match_tree(&gs, c, &match);
1933 if (ret) {
1934 hx509_clear_error_string(context);
1935 return ret;
1937 if (match) {
1938 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1939 "Error verify constraints, "
1940 "certificate included in excluded "
1941 "subtree");
1942 return HX509_VERIFY_CONSTRAINTS;
1946 return 0;
1949 static void
1950 free_name_constraints(hx509_name_constraints *nc)
1952 size_t i;
1954 for (i = 0 ; i < nc->len; i++)
1955 free_NameConstraints(&nc->val[i]);
1956 free(nc->val);
1960 * Build and verify the path for the certificate to the trust anchor
1961 * specified in the verify context. The path is constructed from the
1962 * certificate, the pool and the trust anchors.
1964 * @param context A hx509 context.
1965 * @param ctx A hx509 verification context.
1966 * @param cert the certificate to build the path from.
1967 * @param pool A keyset of certificates to build the chain from.
1969 * @return An hx509 error code, see hx509_get_error_string().
1971 * @ingroup hx509_verify
1975 hx509_verify_path(hx509_context context,
1976 hx509_verify_ctx ctx,
1977 hx509_cert cert,
1978 hx509_certs pool)
1980 hx509_name_constraints nc;
1981 hx509_path path;
1982 int ret, proxy_cert_depth, selfsigned_depth, diff;
1983 size_t i, k;
1984 enum certtype type;
1985 Name proxy_issuer;
1986 hx509_certs anchors = NULL;
1988 memset(&proxy_issuer, 0, sizeof(proxy_issuer));
1990 ret = init_name_constraints(&nc);
1991 if (ret)
1992 return ret;
1994 path.val = NULL;
1995 path.len = 0;
1997 if ((ctx->flags & HX509_VERIFY_CTX_F_TIME_SET) == 0)
1998 ctx->time_now = time(NULL);
2003 if (ctx->trust_anchors)
2004 anchors = hx509_certs_ref(ctx->trust_anchors);
2005 else if (context->default_trust_anchors && ALLOW_DEF_TA(ctx))
2006 anchors = hx509_certs_ref(context->default_trust_anchors);
2007 else {
2008 ret = hx509_certs_init(context, "MEMORY:no-TA", 0, NULL, &anchors);
2009 if (ret)
2010 goto out;
2014 * Calculate the path from the certificate user presented to the
2015 * to an anchor.
2017 ret = _hx509_calculate_path(context, 0, ctx->time_now,
2018 anchors, ctx->max_depth,
2019 cert, pool, &path);
2020 if (ret)
2021 goto out;
2024 * Check CA and proxy certificate chain from the top of the
2025 * certificate chain. Also check certificate is valid with respect
2026 * to the current time.
2030 proxy_cert_depth = 0;
2031 selfsigned_depth = 0;
2033 if (ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE)
2034 type = PROXY_CERT;
2035 else
2036 type = EE_CERT;
2038 for (i = 0; i < path.len; i++) {
2039 Certificate *c;
2040 time_t t;
2042 c = _hx509_get_cert(path.val[i]);
2045 * Lets do some basic check on issuer like
2046 * keyUsage.keyCertSign and basicConstraints.cA bit depending
2047 * on what type of certificate this is.
2050 switch (type) {
2051 case CA_CERT:
2053 /* XXX make constants for keyusage */
2054 ret = check_key_usage(context, c, 1 << 5,
2055 REQUIRE_RFC3280(ctx) ? TRUE : FALSE);
2056 if (ret) {
2057 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
2058 "Key usage missing from CA certificate");
2059 goto out;
2062 /* self signed cert doesn't add to path length */
2063 if (i + 1 != path.len) {
2064 int selfsigned;
2066 ret = certificate_is_self_signed(context, c, &selfsigned);
2067 if (ret)
2068 goto out;
2069 if (selfsigned)
2070 selfsigned_depth++;
2073 break;
2074 case PROXY_CERT: {
2075 ProxyCertInfo info;
2077 if (is_proxy_cert(context, c, &info) == 0) {
2078 size_t j;
2080 if (info.pCPathLenConstraint != NULL &&
2081 *info.pCPathLenConstraint < i)
2083 free_ProxyCertInfo(&info);
2084 ret = HX509_PATH_TOO_LONG;
2085 hx509_set_error_string(context, 0, ret,
2086 "Proxy certificate chain "
2087 "longer then allowed");
2088 goto out;
2090 /* XXX MUST check info.proxyPolicy */
2091 free_ProxyCertInfo(&info);
2093 j = 0;
2094 if (find_extension(c, &asn1_oid_id_x509_ce_subjectAltName, &j)) {
2095 ret = HX509_PROXY_CERT_INVALID;
2096 hx509_set_error_string(context, 0, ret,
2097 "Proxy certificate have explicity "
2098 "forbidden subjectAltName");
2099 goto out;
2102 j = 0;
2103 if (find_extension(c, &asn1_oid_id_x509_ce_issuerAltName, &j)) {
2104 ret = HX509_PROXY_CERT_INVALID;
2105 hx509_set_error_string(context, 0, ret,
2106 "Proxy certificate have explicity "
2107 "forbidden issuerAltName");
2108 goto out;
2112 * The subject name of the proxy certificate should be
2113 * CN=XXX,<proxy issuer>, prune of CN and check if its
2114 * the same over the whole chain of proxy certs and
2115 * then check with the EE cert when we get to it.
2118 if (proxy_cert_depth) {
2119 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.subject, &diff);
2120 if (ret) {
2121 hx509_set_error_string(context, 0, ret, "Out of memory");
2122 goto out;
2124 if (diff) {
2125 ret = HX509_PROXY_CERT_NAME_WRONG;
2126 hx509_set_error_string(context, 0, ret,
2127 "Base proxy name not right");
2128 goto out;
2132 free_Name(&proxy_issuer);
2134 ret = copy_Name(&c->tbsCertificate.subject, &proxy_issuer);
2135 if (ret) {
2136 hx509_clear_error_string(context);
2137 goto out;
2140 j = proxy_issuer.u.rdnSequence.len;
2141 if (proxy_issuer.u.rdnSequence.len < 2
2142 || proxy_issuer.u.rdnSequence.val[j - 1].len > 1
2143 || der_heim_oid_cmp(&proxy_issuer.u.rdnSequence.val[j - 1].val[0].type,
2144 &asn1_oid_id_at_commonName))
2146 ret = HX509_PROXY_CERT_NAME_WRONG;
2147 hx509_set_error_string(context, 0, ret,
2148 "Proxy name too short or "
2149 "does not have Common name "
2150 "at the top");
2151 goto out;
2154 free_RelativeDistinguishedName(&proxy_issuer.u.rdnSequence.val[j - 1]);
2155 proxy_issuer.u.rdnSequence.len -= 1;
2157 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.issuer, &diff);
2158 if (ret) {
2159 hx509_set_error_string(context, 0, ret, "Out of memory");
2160 goto out;
2162 if (diff != 0) {
2163 ret = HX509_PROXY_CERT_NAME_WRONG;
2164 hx509_set_error_string(context, 0, ret,
2165 "Proxy issuer name not as expected");
2166 goto out;
2169 break;
2170 } else {
2172 * Now we are done with the proxy certificates, this
2173 * cert was an EE cert and we we will fall though to
2174 * EE checking below.
2176 type = EE_CERT;
2177 /* FALLTHOUGH */
2180 case EE_CERT:
2182 * If there where any proxy certificates in the chain
2183 * (proxy_cert_depth > 0), check that the proxy issuer
2184 * matched proxy certificates "base" subject.
2186 if (proxy_cert_depth) {
2188 ret = _hx509_name_cmp(&proxy_issuer,
2189 &c->tbsCertificate.subject, &diff);
2190 if (ret) {
2191 hx509_set_error_string(context, 0, ret, "out of memory");
2192 goto out;
2194 if (diff) {
2195 ret = HX509_PROXY_CERT_NAME_WRONG;
2196 hx509_clear_error_string(context);
2197 goto out;
2199 if (cert->basename)
2200 hx509_name_free(&cert->basename);
2202 ret = _hx509_name_from_Name(&proxy_issuer, &cert->basename);
2203 if (ret) {
2204 hx509_clear_error_string(context);
2205 goto out;
2209 break;
2212 ret = check_basic_constraints(context, c, type,
2213 i - proxy_cert_depth - selfsigned_depth);
2214 if (ret)
2215 goto out;
2218 * Don't check the trust anchors expiration time since they
2219 * are transported out of band, from RFC3820.
2221 if (i + 1 != path.len || CHECK_TA(ctx)) {
2223 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2224 if (t > ctx->time_now) {
2225 ret = HX509_CERT_USED_BEFORE_TIME;
2226 hx509_clear_error_string(context);
2227 goto out;
2229 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2230 if (t < ctx->time_now) {
2231 ret = HX509_CERT_USED_AFTER_TIME;
2232 hx509_clear_error_string(context);
2233 goto out;
2237 if (type == EE_CERT)
2238 type = CA_CERT;
2239 else if (type == PROXY_CERT)
2240 proxy_cert_depth++;
2244 * Verify constraints, do this backward so path constraints are
2245 * checked in the right order.
2248 for (ret = 0, k = path.len; k > 0; k--) {
2249 Certificate *c;
2250 int selfsigned;
2251 i = k - 1;
2253 c = _hx509_get_cert(path.val[i]);
2255 ret = certificate_is_self_signed(context, c, &selfsigned);
2256 if (ret)
2257 goto out;
2259 /* verify name constraints, not for selfsigned and anchor */
2260 if (!selfsigned || i + 1 != path.len) {
2261 ret = check_name_constraints(context, &nc, c);
2262 if (ret) {
2263 goto out;
2266 ret = add_name_constraints(context, c, i == 0, &nc);
2267 if (ret)
2268 goto out;
2270 /* XXX verify all other silly constraints */
2275 * Verify that no certificates has been revoked.
2278 if (ctx->revoke_ctx) {
2279 hx509_certs certs;
2281 ret = hx509_certs_init(context, "MEMORY:revoke-certs", 0,
2282 NULL, &certs);
2283 if (ret)
2284 goto out;
2286 for (i = 0; i < path.len; i++) {
2287 ret = hx509_certs_add(context, certs, path.val[i]);
2288 if (ret) {
2289 hx509_certs_free(&certs);
2290 goto out;
2293 ret = hx509_certs_merge(context, certs, pool);
2294 if (ret) {
2295 hx509_certs_free(&certs);
2296 goto out;
2299 for (i = 0; i < path.len - 1; i++) {
2300 size_t parent = (i < path.len - 1) ? i + 1 : i;
2302 ret = hx509_revoke_verify(context,
2303 ctx->revoke_ctx,
2304 certs,
2305 ctx->time_now,
2306 path.val[i],
2307 path.val[parent]);
2308 if (ret) {
2309 hx509_certs_free(&certs);
2310 goto out;
2313 hx509_certs_free(&certs);
2317 * Verify signatures, do this backward so public key working
2318 * parameter is passed up from the anchor up though the chain.
2321 for (k = path.len; k > 0; k--) {
2322 hx509_cert signer;
2323 Certificate *c;
2324 i = k - 1;
2326 c = _hx509_get_cert(path.val[i]);
2328 /* is last in chain (trust anchor) */
2329 if (i + 1 == path.len) {
2330 int selfsigned;
2332 signer = path.val[i];
2334 ret = certificate_is_self_signed(context, signer->data, &selfsigned);
2335 if (ret)
2336 goto out;
2338 /* if trust anchor is not self signed, don't check sig */
2339 if (!selfsigned)
2340 continue;
2341 } else {
2342 /* take next certificate in chain */
2343 signer = path.val[i + 1];
2346 /* verify signatureValue */
2347 ret = _hx509_verify_signature_bitstring(context,
2348 signer,
2349 &c->signatureAlgorithm,
2350 &c->tbsCertificate._save,
2351 &c->signatureValue);
2352 if (ret) {
2353 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
2354 "Failed to verify signature of certificate");
2355 goto out;
2358 * Verify that the sigature algorithm "best-before" date is
2359 * before the creation date of the certificate, do this for
2360 * trust anchors too, since any trust anchor that is created
2361 * after a algorithm is known to be bad deserved to be invalid.
2363 * Skip the leaf certificate for now...
2366 if (i != 0 && (ctx->flags & HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK) == 0) {
2367 time_t notBefore =
2368 _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2369 ret = _hx509_signature_best_before(context,
2370 &c->signatureAlgorithm,
2371 notBefore);
2372 if (ret)
2373 goto out;
2377 out:
2378 hx509_certs_free(&anchors);
2379 free_Name(&proxy_issuer);
2380 free_name_constraints(&nc);
2381 _hx509_path_free(&path);
2383 return ret;
2387 * Verify a signature made using the private key of an certificate.
2389 * @param context A hx509 context.
2390 * @param signer the certificate that made the signature.
2391 * @param alg algorthm that was used to sign the data.
2392 * @param data the data that was signed.
2393 * @param sig the sigature to verify.
2395 * @return An hx509 error code, see hx509_get_error_string().
2397 * @ingroup hx509_crypto
2401 hx509_verify_signature(hx509_context context,
2402 const hx509_cert signer,
2403 const AlgorithmIdentifier *alg,
2404 const heim_octet_string *data,
2405 const heim_octet_string *sig)
2407 return _hx509_verify_signature(context, signer, alg, data, sig);
2411 _hx509_verify_signature_bitstring(hx509_context context,
2412 const hx509_cert signer,
2413 const AlgorithmIdentifier *alg,
2414 const heim_octet_string *data,
2415 const heim_bit_string *sig)
2417 heim_octet_string os;
2419 if (sig->length & 7) {
2420 hx509_set_error_string(context, 0, HX509_CRYPTO_SIG_INVALID_FORMAT,
2421 "signature not multiple of 8 bits");
2422 return HX509_CRYPTO_SIG_INVALID_FORMAT;
2425 os.data = sig->data;
2426 os.length = sig->length / 8;
2428 return _hx509_verify_signature(context, signer, alg, data, &os);
2434 * Verify that the certificate is allowed to be used for the hostname
2435 * and address.
2437 * @param context A hx509 context.
2438 * @param cert the certificate to match with
2439 * @param flags Flags to modify the behavior:
2440 * - HX509_VHN_F_ALLOW_NO_MATCH no match is ok
2441 * @param type type of hostname:
2442 * - HX509_HN_HOSTNAME for plain hostname.
2443 * - HX509_HN_DNSSRV for DNS SRV names.
2444 * @param hostname the hostname to check
2445 * @param sa address of the host
2446 * @param sa_size length of address
2448 * @return An hx509 error code, see hx509_get_error_string().
2450 * @ingroup hx509_cert
2454 hx509_verify_hostname(hx509_context context,
2455 const hx509_cert cert,
2456 int flags,
2457 hx509_hostname_type type,
2458 const char *hostname,
2459 const struct sockaddr *sa,
2460 /* XXX krb5_socklen_t */ int sa_size)
2462 GeneralNames san;
2463 const Name *name;
2464 int ret;
2465 size_t i, j, k;
2467 if (sa && sa_size <= 0)
2468 return EINVAL;
2470 memset(&san, 0, sizeof(san));
2472 i = 0;
2473 do {
2474 ret = find_extension_subject_alt_name(cert->data, &i, &san);
2475 if (ret == HX509_EXTENSION_NOT_FOUND)
2476 break;
2477 else if (ret != 0)
2478 return HX509_PARSING_NAME_FAILED;
2480 for (j = 0; j < san.len; j++) {
2481 switch (san.val[j].element) {
2482 case choice_GeneralName_dNSName: {
2483 heim_printable_string hn;
2484 hn.data = rk_UNCONST(hostname);
2485 hn.length = strlen(hostname);
2487 if (der_printable_string_cmp(&san.val[j].u.dNSName, &hn) == 0) {
2488 free_GeneralNames(&san);
2489 return 0;
2491 break;
2493 default:
2494 break;
2497 free_GeneralNames(&san);
2498 } while (1);
2500 name = &cert->data->tbsCertificate.subject;
2502 /* Find first CN= in the name, and try to match the hostname on that */
2503 for (ret = 0, k = name->u.rdnSequence.len; ret == 0 && k > 0; k--) {
2504 i = k - 1;
2505 for (j = 0; ret == 0 && j < name->u.rdnSequence.val[i].len; j++) {
2506 AttributeTypeAndValue *n = &name->u.rdnSequence.val[i].val[j];
2508 if (der_heim_oid_cmp(&n->type, &asn1_oid_id_at_commonName) == 0) {
2509 DirectoryString *ds = &n->value;
2510 switch (ds->element) {
2511 case choice_DirectoryString_printableString: {
2512 heim_printable_string hn;
2513 hn.data = rk_UNCONST(hostname);
2514 hn.length = strlen(hostname);
2516 if (der_printable_string_cmp(&ds->u.printableString, &hn) == 0)
2517 return 0;
2518 break;
2520 case choice_DirectoryString_ia5String: {
2521 heim_ia5_string hn;
2522 hn.data = rk_UNCONST(hostname);
2523 hn.length = strlen(hostname);
2525 if (der_ia5_string_cmp(&ds->u.ia5String, &hn) == 0)
2526 return 0;
2527 break;
2529 case choice_DirectoryString_utf8String:
2530 if (strcasecmp(ds->u.utf8String, hostname) == 0)
2531 return 0;
2532 default:
2533 break;
2535 ret = HX509_NAME_CONSTRAINT_ERROR;
2540 if ((flags & HX509_VHN_F_ALLOW_NO_MATCH) == 0)
2541 ret = HX509_NAME_CONSTRAINT_ERROR;
2543 return ret;
2547 _hx509_set_cert_attribute(hx509_context context,
2548 hx509_cert cert,
2549 const heim_oid *oid,
2550 const heim_octet_string *attr)
2552 hx509_cert_attribute a;
2553 void *d;
2555 if (hx509_cert_get_attribute(cert, oid) != NULL)
2556 return 0;
2558 d = realloc(cert->attrs.val,
2559 sizeof(cert->attrs.val[0]) * (cert->attrs.len + 1));
2560 if (d == NULL) {
2561 hx509_clear_error_string(context);
2562 return ENOMEM;
2564 cert->attrs.val = d;
2566 a = malloc(sizeof(*a));
2567 if (a == NULL)
2568 return ENOMEM;
2570 der_copy_octet_string(attr, &a->data);
2571 der_copy_oid(oid, &a->oid);
2573 cert->attrs.val[cert->attrs.len] = a;
2574 cert->attrs.len++;
2576 return 0;
2580 * Get an external attribute for the certificate, examples are
2581 * friendly name and id.
2583 * @param cert hx509 certificate object to search
2584 * @param oid an oid to search for.
2586 * @return an hx509_cert_attribute, only valid as long as the
2587 * certificate is referenced.
2589 * @ingroup hx509_cert
2592 hx509_cert_attribute
2593 hx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid)
2595 size_t i;
2596 for (i = 0; i < cert->attrs.len; i++)
2597 if (der_heim_oid_cmp(oid, &cert->attrs.val[i]->oid) == 0)
2598 return cert->attrs.val[i];
2599 return NULL;
2603 * Set the friendly name on the certificate.
2605 * @param cert The certificate to set the friendly name on
2606 * @param name Friendly name.
2608 * @return An hx509 error code, see hx509_get_error_string().
2610 * @ingroup hx509_cert
2614 hx509_cert_set_friendly_name(hx509_cert cert, const char *name)
2616 if (cert->friendlyname)
2617 free(cert->friendlyname);
2618 cert->friendlyname = strdup(name);
2619 if (cert->friendlyname == NULL)
2620 return ENOMEM;
2621 return 0;
2625 * Get friendly name of the certificate.
2627 * @param cert cert to get the friendly name from.
2629 * @return an friendly name or NULL if there is. The friendly name is
2630 * only valid as long as the certificate is referenced.
2632 * @ingroup hx509_cert
2635 const char *
2636 hx509_cert_get_friendly_name(hx509_cert cert)
2638 hx509_cert_attribute a;
2639 PKCS9_friendlyName n;
2640 size_t sz;
2641 int ret;
2642 size_t i;
2644 if (cert->friendlyname)
2645 return cert->friendlyname;
2647 a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_friendlyName);
2648 if (a == NULL) {
2649 hx509_name name;
2651 ret = hx509_cert_get_subject(cert, &name);
2652 if (ret)
2653 return NULL;
2654 ret = hx509_name_to_string(name, &cert->friendlyname);
2655 hx509_name_free(&name);
2656 if (ret)
2657 return NULL;
2658 return cert->friendlyname;
2661 ret = decode_PKCS9_friendlyName(a->data.data, a->data.length, &n, &sz);
2662 if (ret)
2663 return NULL;
2665 if (n.len != 1) {
2666 free_PKCS9_friendlyName(&n);
2667 return NULL;
2670 cert->friendlyname = malloc(n.val[0].length + 1);
2671 if (cert->friendlyname == NULL) {
2672 free_PKCS9_friendlyName(&n);
2673 return NULL;
2676 for (i = 0; i < n.val[0].length; i++) {
2677 if (n.val[0].data[i] <= 0xff)
2678 cert->friendlyname[i] = n.val[0].data[i] & 0xff;
2679 else
2680 cert->friendlyname[i] = 'X';
2682 cert->friendlyname[i] = '\0';
2683 free_PKCS9_friendlyName(&n);
2685 return cert->friendlyname;
2688 void
2689 _hx509_query_clear(hx509_query *q)
2691 memset(q, 0, sizeof(*q));
2695 * Allocate an query controller. Free using hx509_query_free().
2697 * @param context A hx509 context.
2698 * @param q return pointer to a hx509_query.
2700 * @return An hx509 error code, see hx509_get_error_string().
2702 * @ingroup hx509_cert
2706 hx509_query_alloc(hx509_context context, hx509_query **q)
2708 *q = calloc(1, sizeof(**q));
2709 if (*q == NULL)
2710 return ENOMEM;
2711 return 0;
2716 * Set match options for the hx509 query controller.
2718 * @param q query controller.
2719 * @param option options to control the query controller.
2721 * @return An hx509 error code, see hx509_get_error_string().
2723 * @ingroup hx509_cert
2726 void
2727 hx509_query_match_option(hx509_query *q, hx509_query_option option)
2729 switch(option) {
2730 case HX509_QUERY_OPTION_PRIVATE_KEY:
2731 q->match |= HX509_QUERY_PRIVATE_KEY;
2732 break;
2733 case HX509_QUERY_OPTION_KU_ENCIPHERMENT:
2734 q->match |= HX509_QUERY_KU_ENCIPHERMENT;
2735 break;
2736 case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE:
2737 q->match |= HX509_QUERY_KU_DIGITALSIGNATURE;
2738 break;
2739 case HX509_QUERY_OPTION_KU_KEYCERTSIGN:
2740 q->match |= HX509_QUERY_KU_KEYCERTSIGN;
2741 break;
2742 case HX509_QUERY_OPTION_END:
2743 default:
2744 break;
2749 * Set the issuer and serial number of match in the query
2750 * controller. The function make copies of the isser and serial number.
2752 * @param q a hx509 query controller
2753 * @param issuer issuer to search for
2754 * @param serialNumber the serialNumber of the issuer.
2756 * @return An hx509 error code, see hx509_get_error_string().
2758 * @ingroup hx509_cert
2762 hx509_query_match_issuer_serial(hx509_query *q,
2763 const Name *issuer,
2764 const heim_integer *serialNumber)
2766 int ret;
2767 if (q->serial) {
2768 der_free_heim_integer(q->serial);
2769 free(q->serial);
2771 q->serial = malloc(sizeof(*q->serial));
2772 if (q->serial == NULL)
2773 return ENOMEM;
2774 ret = der_copy_heim_integer(serialNumber, q->serial);
2775 if (ret) {
2776 free(q->serial);
2777 q->serial = NULL;
2778 return ret;
2780 if (q->issuer_name) {
2781 free_Name(q->issuer_name);
2782 free(q->issuer_name);
2784 q->issuer_name = malloc(sizeof(*q->issuer_name));
2785 if (q->issuer_name == NULL)
2786 return ENOMEM;
2787 ret = copy_Name(issuer, q->issuer_name);
2788 if (ret) {
2789 free(q->issuer_name);
2790 q->issuer_name = NULL;
2791 return ret;
2793 q->match |= HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
2794 return 0;
2798 * Set the query controller to match on a friendly name
2800 * @param q a hx509 query controller.
2801 * @param name a friendly name to match on
2803 * @return An hx509 error code, see hx509_get_error_string().
2805 * @ingroup hx509_cert
2809 hx509_query_match_friendly_name(hx509_query *q, const char *name)
2811 if (q->friendlyname)
2812 free(q->friendlyname);
2813 q->friendlyname = strdup(name);
2814 if (q->friendlyname == NULL)
2815 return ENOMEM;
2816 q->match |= HX509_QUERY_MATCH_FRIENDLY_NAME;
2817 return 0;
2821 * Set the query controller to require an one specific EKU (extended
2822 * key usage). Any previous EKU matching is overwitten. If NULL is
2823 * passed in as the eku, the EKU requirement is reset.
2825 * @param q a hx509 query controller.
2826 * @param eku an EKU to match on.
2828 * @return An hx509 error code, see hx509_get_error_string().
2830 * @ingroup hx509_cert
2834 hx509_query_match_eku(hx509_query *q, const heim_oid *eku)
2836 int ret;
2838 if (eku == NULL) {
2839 if (q->eku) {
2840 der_free_oid(q->eku);
2841 free(q->eku);
2842 q->eku = NULL;
2844 q->match &= ~HX509_QUERY_MATCH_EKU;
2845 } else {
2846 if (q->eku) {
2847 der_free_oid(q->eku);
2848 } else {
2849 q->eku = calloc(1, sizeof(*q->eku));
2850 if (q->eku == NULL)
2851 return ENOMEM;
2853 ret = der_copy_oid(eku, q->eku);
2854 if (ret) {
2855 free(q->eku);
2856 q->eku = NULL;
2857 return ret;
2859 q->match |= HX509_QUERY_MATCH_EKU;
2861 return 0;
2865 hx509_query_match_expr(hx509_context context, hx509_query *q, const char *expr)
2867 if (q->expr) {
2868 _hx509_expr_free(q->expr);
2869 q->expr = NULL;
2872 if (expr == NULL) {
2873 q->match &= ~HX509_QUERY_MATCH_EXPR;
2874 } else {
2875 q->expr = _hx509_expr_parse(expr);
2876 if (q->expr)
2877 q->match |= HX509_QUERY_MATCH_EXPR;
2880 return 0;
2884 * Set the query controller to match using a specific match function.
2886 * @param q a hx509 query controller.
2887 * @param func function to use for matching, if the argument is NULL,
2888 * the match function is removed.
2889 * @param ctx context passed to the function.
2891 * @return An hx509 error code, see hx509_get_error_string().
2893 * @ingroup hx509_cert
2897 hx509_query_match_cmp_func(hx509_query *q,
2898 int (*func)(hx509_context, hx509_cert, void *),
2899 void *ctx)
2901 if (func)
2902 q->match |= HX509_QUERY_MATCH_FUNCTION;
2903 else
2904 q->match &= ~HX509_QUERY_MATCH_FUNCTION;
2905 q->cmp_func = func;
2906 q->cmp_func_ctx = ctx;
2907 return 0;
2911 * Free the query controller.
2913 * @param context A hx509 context.
2914 * @param q a pointer to the query controller.
2916 * @ingroup hx509_cert
2919 void
2920 hx509_query_free(hx509_context context, hx509_query *q)
2922 if (q == NULL)
2923 return;
2925 if (q->serial) {
2926 der_free_heim_integer(q->serial);
2927 free(q->serial);
2929 if (q->issuer_name) {
2930 free_Name(q->issuer_name);
2931 free(q->issuer_name);
2933 if (q->eku) {
2934 der_free_oid(q->eku);
2935 free(q->eku);
2937 if (q->friendlyname)
2938 free(q->friendlyname);
2939 if (q->expr)
2940 _hx509_expr_free(q->expr);
2942 memset(q, 0, sizeof(*q));
2943 free(q);
2947 _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert cert)
2949 Certificate *c = _hx509_get_cert(cert);
2950 int ret, diff;
2952 _hx509_query_statistic(context, 1, q);
2954 if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) &&
2955 _hx509_cert_is_parent_cmp(q->subject, c, 0) != 0)
2956 return 0;
2958 if ((q->match & HX509_QUERY_MATCH_CERTIFICATE) &&
2959 _hx509_Certificate_cmp(q->certificate, c) != 0)
2960 return 0;
2962 if ((q->match & HX509_QUERY_MATCH_SERIALNUMBER)
2963 && der_heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0)
2964 return 0;
2966 if (q->match & HX509_QUERY_MATCH_ISSUER_NAME) {
2967 ret = _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name, &diff);
2968 if (ret || diff)
2969 return 0;
2972 if (q->match & HX509_QUERY_MATCH_SUBJECT_NAME) {
2973 ret = _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name, &diff);
2974 if (ret || diff)
2975 return 0;
2978 if (q->match & HX509_QUERY_MATCH_SUBJECT_KEY_ID) {
2979 SubjectKeyIdentifier si;
2981 ret = _hx509_find_extension_subject_key_id(c, &si);
2982 if (ret == 0) {
2983 if (der_heim_octet_string_cmp(&si, q->subject_id) != 0)
2984 ret = 1;
2985 free_SubjectKeyIdentifier(&si);
2987 if (ret)
2988 return 0;
2990 if ((q->match & HX509_QUERY_MATCH_ISSUER_ID))
2991 return 0;
2992 if ((q->match & HX509_QUERY_PRIVATE_KEY) &&
2993 _hx509_cert_private_key(cert) == NULL)
2994 return 0;
2997 unsigned ku = 0;
2998 if (q->match & HX509_QUERY_KU_DIGITALSIGNATURE)
2999 ku |= (1 << 0);
3000 if (q->match & HX509_QUERY_KU_NONREPUDIATION)
3001 ku |= (1 << 1);
3002 if (q->match & HX509_QUERY_KU_ENCIPHERMENT)
3003 ku |= (1 << 2);
3004 if (q->match & HX509_QUERY_KU_DATAENCIPHERMENT)
3005 ku |= (1 << 3);
3006 if (q->match & HX509_QUERY_KU_KEYAGREEMENT)
3007 ku |= (1 << 4);
3008 if (q->match & HX509_QUERY_KU_KEYCERTSIGN)
3009 ku |= (1 << 5);
3010 if (q->match & HX509_QUERY_KU_CRLSIGN)
3011 ku |= (1 << 6);
3012 if (ku && check_key_usage(context, c, ku, TRUE))
3013 return 0;
3015 if ((q->match & HX509_QUERY_ANCHOR))
3016 return 0;
3018 if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) {
3019 hx509_cert_attribute a;
3021 a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_localKeyId);
3022 if (a == NULL)
3023 return 0;
3024 if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0)
3025 return 0;
3028 if (q->match & HX509_QUERY_NO_MATCH_PATH) {
3029 size_t i;
3031 for (i = 0; i < q->path->len; i++)
3032 if (hx509_cert_cmp(q->path->val[i], cert) == 0)
3033 return 0;
3035 if (q->match & HX509_QUERY_MATCH_FRIENDLY_NAME) {
3036 const char *name = hx509_cert_get_friendly_name(cert);
3037 if (name == NULL)
3038 return 0;
3039 if (strcasecmp(q->friendlyname, name) != 0)
3040 return 0;
3042 if (q->match & HX509_QUERY_MATCH_FUNCTION) {
3043 ret = (*q->cmp_func)(context, cert, q->cmp_func_ctx);
3044 if (ret != 0)
3045 return 0;
3048 if (q->match & HX509_QUERY_MATCH_KEY_HASH_SHA1) {
3049 heim_octet_string os;
3051 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
3052 os.length =
3053 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
3055 ret = _hx509_verify_signature(context,
3056 NULL,
3057 hx509_signature_sha1(),
3058 &os,
3059 q->keyhash_sha1);
3060 if (ret != 0)
3061 return 0;
3064 if (q->match & HX509_QUERY_MATCH_TIME) {
3065 time_t t;
3066 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
3067 if (t > q->timenow)
3068 return 0;
3069 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
3070 if (t < q->timenow)
3071 return 0;
3074 /* If an EKU is required, check the cert for it. */
3075 if ((q->match & HX509_QUERY_MATCH_EKU) &&
3076 hx509_cert_check_eku(context, cert, q->eku, 0))
3077 return 0;
3079 if ((q->match & HX509_QUERY_MATCH_EXPR)) {
3080 hx509_env env = NULL;
3082 ret = _hx509_cert_to_env(context, cert, &env);
3083 if (ret)
3084 return 0;
3086 ret = _hx509_expr_eval(context, env, q->expr);
3087 hx509_env_free(&env);
3088 if (ret == 0)
3089 return 0;
3092 if (q->match & ~HX509_QUERY_MASK)
3093 return 0;
3095 return 1;
3099 * Set a statistic file for the query statistics.
3101 * @param context A hx509 context.
3102 * @param fn statistics file name
3104 * @ingroup hx509_cert
3107 void
3108 hx509_query_statistic_file(hx509_context context, const char *fn)
3110 if (context->querystat)
3111 free(context->querystat);
3112 context->querystat = strdup(fn);
3115 void
3116 _hx509_query_statistic(hx509_context context, int type, const hx509_query *q)
3118 FILE *f;
3119 if (context->querystat == NULL)
3120 return;
3121 f = fopen(context->querystat, "a");
3122 if (f == NULL)
3123 return;
3124 rk_cloexec_file(f);
3125 fprintf(f, "%d %d\n", type, q->match);
3126 fclose(f);
3129 static const char *statname[] = {
3130 "find issuer cert",
3131 "match serialnumber",
3132 "match issuer name",
3133 "match subject name",
3134 "match subject key id",
3135 "match issuer id",
3136 "private key",
3137 "ku encipherment",
3138 "ku digitalsignature",
3139 "ku keycertsign",
3140 "ku crlsign",
3141 "ku nonrepudiation",
3142 "ku keyagreement",
3143 "ku dataencipherment",
3144 "anchor",
3145 "match certificate",
3146 "match local key id",
3147 "no match path",
3148 "match friendly name",
3149 "match function",
3150 "match key hash sha1",
3151 "match time"
3154 struct stat_el {
3155 unsigned long stats;
3156 unsigned int index;
3160 static int
3161 stat_sort(const void *a, const void *b)
3163 const struct stat_el *ae = a;
3164 const struct stat_el *be = b;
3165 return be->stats - ae->stats;
3169 * Unparse the statistics file and print the result on a FILE descriptor.
3171 * @param context A hx509 context.
3172 * @param printtype tyep to print
3173 * @param out the FILE to write the data on.
3175 * @ingroup hx509_cert
3178 void
3179 hx509_query_unparse_stats(hx509_context context, int printtype, FILE *out)
3181 rtbl_t t;
3182 FILE *f;
3183 int type, mask, num;
3184 size_t i;
3185 unsigned long multiqueries = 0, totalqueries = 0;
3186 struct stat_el stats[32];
3188 if (context->querystat == NULL)
3189 return;
3190 f = fopen(context->querystat, "r");
3191 if (f == NULL) {
3192 fprintf(out, "No statistic file %s: %s.\n",
3193 context->querystat, strerror(errno));
3194 return;
3196 rk_cloexec_file(f);
3198 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
3199 stats[i].index = i;
3200 stats[i].stats = 0;
3203 while (fscanf(f, "%d %d\n", &type, &mask) == 2) {
3204 if (type != printtype)
3205 continue;
3206 num = i = 0;
3207 while (mask && i < sizeof(stats)/sizeof(stats[0])) {
3208 if (mask & 1) {
3209 stats[i].stats++;
3210 num++;
3212 mask = mask >>1 ;
3213 i++;
3215 if (num > 1)
3216 multiqueries++;
3217 totalqueries++;
3219 fclose(f);
3221 qsort(stats, sizeof(stats)/sizeof(stats[0]), sizeof(stats[0]), stat_sort);
3223 t = rtbl_create();
3224 if (t == NULL)
3225 errx(1, "out of memory");
3227 rtbl_set_separator (t, " ");
3229 rtbl_add_column_by_id (t, 0, "Name", 0);
3230 rtbl_add_column_by_id (t, 1, "Counter", 0);
3233 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
3234 char str[10];
3236 if (stats[i].index < sizeof(statname)/sizeof(statname[0]))
3237 rtbl_add_column_entry_by_id (t, 0, statname[stats[i].index]);
3238 else {
3239 snprintf(str, sizeof(str), "%d", stats[i].index);
3240 rtbl_add_column_entry_by_id (t, 0, str);
3242 snprintf(str, sizeof(str), "%lu", stats[i].stats);
3243 rtbl_add_column_entry_by_id (t, 1, str);
3246 rtbl_format(t, out);
3247 rtbl_destroy(t);
3249 fprintf(out, "\nQueries: multi %lu total %lu\n",
3250 multiqueries, totalqueries);
3254 * Check the extended key usage on the hx509 certificate.
3256 * @param context A hx509 context.
3257 * @param cert A hx509 context.
3258 * @param eku the EKU to check for
3259 * @param allow_any_eku if the any EKU is set, allow that to be a
3260 * substitute.
3262 * @return An hx509 error code, see hx509_get_error_string().
3264 * @ingroup hx509_cert
3268 hx509_cert_check_eku(hx509_context context, hx509_cert cert,
3269 const heim_oid *eku, int allow_any_eku)
3271 ExtKeyUsage e;
3272 int ret;
3273 size_t i;
3275 ret = find_extension_eku(_hx509_get_cert(cert), &e);
3276 if (ret) {
3277 hx509_clear_error_string(context);
3278 return ret;
3281 for (i = 0; i < e.len; i++) {
3282 if (der_heim_oid_cmp(eku, &e.val[i]) == 0) {
3283 free_ExtKeyUsage(&e);
3284 return 0;
3286 if (allow_any_eku) {
3287 #if 0
3288 if (der_heim_oid_cmp(id_any_eku, &e.val[i]) == 0) {
3289 free_ExtKeyUsage(&e);
3290 return 0;
3292 #endif
3295 free_ExtKeyUsage(&e);
3296 hx509_clear_error_string(context);
3297 return HX509_CERTIFICATE_MISSING_EKU;
3301 _hx509_cert_get_keyusage(hx509_context context,
3302 hx509_cert c,
3303 KeyUsage *ku)
3305 Certificate *cert;
3306 const Extension *e;
3307 size_t size;
3308 int ret;
3309 size_t i = 0;
3311 memset(ku, 0, sizeof(*ku));
3313 cert = _hx509_get_cert(c);
3315 if (_hx509_cert_get_version(cert) < 3)
3316 return 0;
3318 e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i);
3319 if (e == NULL)
3320 return HX509_KU_CERT_MISSING;
3322 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, ku, &size);
3323 if (ret)
3324 return ret;
3325 return 0;
3329 _hx509_cert_get_eku(hx509_context context,
3330 hx509_cert cert,
3331 ExtKeyUsage *e)
3333 int ret;
3335 memset(e, 0, sizeof(*e));
3337 ret = find_extension_eku(_hx509_get_cert(cert), e);
3338 if (ret && ret != HX509_EXTENSION_NOT_FOUND) {
3339 hx509_clear_error_string(context);
3340 return ret;
3342 return 0;
3346 * Encodes the hx509 certificate as a DER encode binary.
3348 * @param context A hx509 context.
3349 * @param c the certificate to encode.
3350 * @param os the encode certificate, set to NULL, 0 on case of
3351 * error. Free the os->data with hx509_xfree().
3353 * @return An hx509 error code, see hx509_get_error_string().
3355 * @ingroup hx509_cert
3359 hx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os)
3361 size_t size;
3362 int ret;
3364 os->data = NULL;
3365 os->length = 0;
3367 ASN1_MALLOC_ENCODE(Certificate, os->data, os->length,
3368 _hx509_get_cert(c), &size, ret);
3369 if (ret) {
3370 os->data = NULL;
3371 os->length = 0;
3372 return ret;
3374 if (os->length != size)
3375 _hx509_abort("internal ASN.1 encoder error");
3377 return ret;
3381 * Last to avoid lost __attribute__s due to #undef.
3384 #undef __attribute__
3385 #define __attribute__(X)
3387 void
3388 _hx509_abort(const char *fmt, ...)
3389 __attribute__ ((noreturn, format (printf, 1, 2)))
3391 va_list ap;
3392 va_start(ap, fmt);
3393 vprintf(fmt, ap);
3394 va_end(ap);
3395 printf("\n");
3396 fflush(stdout);
3397 abort();
3401 * Free a data element allocated in the library.
3403 * @param ptr data to be freed.
3405 * @ingroup hx509_misc
3408 void
3409 hx509_xfree(void *ptr)
3411 free(ptr);
3419 _hx509_cert_to_env(hx509_context context, hx509_cert cert, hx509_env *env)
3421 ExtKeyUsage eku;
3422 hx509_name name;
3423 char *buf;
3424 int ret;
3425 hx509_env envcert = NULL;
3427 *env = NULL;
3429 /* version */
3430 asprintf(&buf, "%d", _hx509_cert_get_version(_hx509_get_cert(cert)));
3431 ret = hx509_env_add(context, &envcert, "version", buf);
3432 free(buf);
3433 if (ret)
3434 goto out;
3436 /* subject */
3437 ret = hx509_cert_get_subject(cert, &name);
3438 if (ret)
3439 goto out;
3441 ret = hx509_name_to_string(name, &buf);
3442 if (ret) {
3443 hx509_name_free(&name);
3444 goto out;
3447 ret = hx509_env_add(context, &envcert, "subject", buf);
3448 hx509_name_free(&name);
3449 if (ret)
3450 goto out;
3452 /* issuer */
3453 ret = hx509_cert_get_issuer(cert, &name);
3454 if (ret)
3455 goto out;
3457 ret = hx509_name_to_string(name, &buf);
3458 hx509_name_free(&name);
3459 if (ret)
3460 goto out;
3462 ret = hx509_env_add(context, &envcert, "issuer", buf);
3463 hx509_xfree(buf);
3464 if (ret)
3465 goto out;
3467 /* eku */
3469 ret = _hx509_cert_get_eku(context, cert, &eku);
3470 if (ret == HX509_EXTENSION_NOT_FOUND)
3472 else if (ret != 0)
3473 goto out;
3474 else {
3475 size_t i;
3476 hx509_env enveku = NULL;
3478 for (i = 0; i < eku.len; i++) {
3480 ret = der_print_heim_oid(&eku.val[i], '.', &buf);
3481 if (ret) {
3482 free_ExtKeyUsage(&eku);
3483 hx509_env_free(&enveku);
3484 goto out;
3486 ret = hx509_env_add(context, &enveku, buf, "oid-name-here");
3487 free(buf);
3488 if (ret) {
3489 free_ExtKeyUsage(&eku);
3490 hx509_env_free(&enveku);
3491 goto out;
3494 free_ExtKeyUsage(&eku);
3496 ret = hx509_env_add_binding(context, &envcert, "eku", enveku);
3497 if (ret) {
3498 hx509_env_free(&enveku);
3499 goto out;
3504 Certificate *c = _hx509_get_cert(cert);
3505 heim_octet_string os, sig;
3506 hx509_env envhash = NULL;
3508 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
3509 os.length =
3510 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
3512 ret = _hx509_create_signature(context,
3513 NULL,
3514 hx509_signature_sha1(),
3515 &os,
3516 NULL,
3517 &sig);
3518 if (ret != 0)
3519 goto out;
3521 ret = hex_encode(sig.data, sig.length, &buf);
3522 der_free_octet_string(&sig);
3523 if (ret < 0) {
3524 ret = ENOMEM;
3525 hx509_set_error_string(context, 0, ret,
3526 "Out of memory");
3527 goto out;
3530 ret = hx509_env_add(context, &envhash, "sha1", buf);
3531 free(buf);
3532 if (ret)
3533 goto out;
3535 ret = hx509_env_add_binding(context, &envcert, "hash", envhash);
3536 if (ret) {
3537 hx509_env_free(&envhash);
3538 goto out;
3542 ret = hx509_env_add_binding(context, env, "certificate", envcert);
3543 if (ret)
3544 goto out;
3546 return 0;
3548 out:
3549 hx509_env_free(&envcert);
3550 return ret;
3554 * Print a simple representation of a certificate
3556 * @param context A hx509 context, can be NULL
3557 * @param cert certificate to print
3558 * @param out the stdio output stream, if NULL, stdout is used
3560 * @return An hx509 error code
3562 * @ingroup hx509_cert
3566 hx509_print_cert(hx509_context context, hx509_cert cert, FILE *out)
3568 hx509_name name;
3569 char *str;
3570 int ret;
3572 if (out == NULL)
3573 out = stderr;
3575 ret = hx509_cert_get_issuer(cert, &name);
3576 if (ret)
3577 return ret;
3578 hx509_name_to_string(name, &str);
3579 hx509_name_free(&name);
3580 fprintf(out, " issuer: \"%s\"\n", str);
3581 free(str);
3583 ret = hx509_cert_get_subject(cert, &name);
3584 if (ret)
3585 return ret;
3586 hx509_name_to_string(name, &str);
3587 hx509_name_free(&name);
3588 fprintf(out, " subject: \"%s\"\n", str);
3589 free(str);
3592 heim_integer serialNumber;
3594 ret = hx509_cert_get_serialnumber(cert, &serialNumber);
3595 if (ret)
3596 return ret;
3597 ret = der_print_hex_heim_integer(&serialNumber, &str);
3598 if (ret)
3599 return ret;
3600 der_free_heim_integer(&serialNumber);
3601 fprintf(out, " serial: %s\n", str);
3602 free(str);
3605 printf(" keyusage: ");
3606 ret = hx509_cert_keyusage_print(context, cert, &str);
3607 if (ret == 0) {
3608 fprintf(out, "%s\n", str);
3609 free(str);
3610 } else
3611 fprintf(out, "no");
3613 return 0;