source: trunk/server/source4/heimdal/lib/hx509/cert.c

Last change on this file was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 86.4 KB
Line 
1/*
2 * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
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.
16 *
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.
20 *
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.
32 */
33
34#include "hx_locl.h"
35#include "crypto-headers.h"
36#include <rtbl.h>
37
38/**
39 * @page page_cert The basic certificate
40 *
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.
44 *
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().
49 *
50 * See the library functions here: @ref hx509_cert
51 */
52
53struct 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;
66};
67
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)
71
72struct _hx509_cert_attrs {
73 size_t len;
74 hx509_cert_attribute *val;
75};
76
77struct 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;
86};
87
88typedef struct hx509_name_constraints {
89 NameConstraints *val;
90 size_t len;
91} hx509_name_constraints;
92
93#define GeneralSubtrees_SET(g,var) \
94 (g)->len = (var)->len, (g)->val = (var)->val;
95
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().
100 *
101 * @param context Returns a pointer to new hx509 context.
102 *
103 * @return Returns an hx509 error code.
104 *
105 * @ingroup hx509
106 */
107
108int
109hx509_context_init(hx509_context *context)
110{
111 *context = calloc(1, sizeof(**context));
112 if (*context == NULL)
113 return ENOMEM;
114
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);
122
123 ENGINE_add_conf_module();
124 OpenSSL_add_all_algorithms();
125
126 (*context)->ocsp_time_diff = HX509_DEFAULT_OCSP_TIME_DIFF;
127
128 initialize_hx_error_table_r(&(*context)->et_list);
129 initialize_asn1_error_table_r(&(*context)->et_list);
130
131#ifdef HX509_DEFAULT_ANCHORS
132 (void)hx509_certs_init(*context, HX509_DEFAULT_ANCHORS, 0,
133 NULL, &(*context)->default_trust_anchors);
134#endif
135
136 return 0;
137}
138
139/**
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().
144 *
145 * @param context hx509 context to change the flag for.
146 * @param flag zero, revokation method required, non zero missing
147 * revokation method ok
148 *
149 * @ingroup hx509_verify
150 */
151
152void
153hx509_context_set_missing_revoke(hx509_context context, int flag)
154{
155 if (flag)
156 context->flags |= HX509_CTX_VERIFY_MISSING_OK;
157 else
158 context->flags &= ~HX509_CTX_VERIFY_MISSING_OK;
159}
160
161/**
162 * Free the context allocated by hx509_context_init().
163 *
164 * @param context context to be freed.
165 *
166 * @ingroup hx509
167 */
168
169void
170hx509_context_free(hx509_context *context)
171{
172 hx509_clear_error_string(*context);
173 if ((*context)->ks_ops) {
174 free((*context)->ks_ops);
175 (*context)->ks_ops = NULL;
176 }
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;
184}
185
186/*
187 *
188 */
189
190Certificate *
191_hx509_get_cert(hx509_cert cert)
192{
193 return cert->data;
194}
195
196/*
197 *
198 */
199
200int
201_hx509_cert_get_version(const Certificate *t)
202{
203 return t->tbsCertificate.version ? *t->tbsCertificate.version + 1 : 1;
204}
205
206/**
207 * Allocate and init an hx509 certificate object from the decoded
208 * certificate `cÂŽ.
209 *
210 * @param context A hx509 context.
211 * @param c
212 * @param cert
213 *
214 * @return Returns an hx509 error code.
215 *
216 * @ingroup hx509_cert
217 */
218
219int
220hx509_cert_init(hx509_context context, const Certificate *c, hx509_cert *cert)
221{
222 int ret;
223
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;
235
236 (*cert)->data = calloc(1, sizeof(*(*cert)->data));
237 if ((*cert)->data == NULL) {
238 free(*cert);
239 return ENOMEM;
240 }
241 ret = copy_Certificate(c, (*cert)->data);
242 if (ret) {
243 free((*cert)->data);
244 free(*cert);
245 *cert = NULL;
246 }
247 return ret;
248}
249
250/**
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.
254 *
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.
258 *
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.
264 *
265 * @return An hx509 error code, see hx509_get_error_string().
266 *
267 * @ingroup hx509_cert
268 */
269
270int
271hx509_cert_init_data(hx509_context context,
272 const void *ptr,
273 size_t len,
274 hx509_cert *cert)
275{
276 Certificate t;
277 size_t size;
278 int ret;
279
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;
284 }
285 if (size != len) {
286 free_Certificate(&t);
287 hx509_set_error_string(context, 0, HX509_EXTRA_DATA_AFTER_STRUCTURE,
288 "Extra data after certificate");
289 return HX509_EXTRA_DATA_AFTER_STRUCTURE;
290 }
291
292 ret = hx509_cert_init(context, &t, cert);
293 free_Certificate(&t);
294 return ret;
295}
296
297void
298_hx509_cert_set_release(hx509_cert cert,
299 _hx509_cert_release_func release,
300 void *ctx)
301{
302 cert->release = release;
303 cert->ctx = ctx;
304}
305
306
307/* Doesn't make a copy of `private_key'. */
308
309int
310_hx509_cert_assign_key(hx509_cert cert, hx509_private_key private_key)
311{
312 if (cert->private_key)
313 hx509_private_key_free(&cert->private_key);
314 cert->private_key = _hx509_private_key_ref(private_key);
315 return 0;
316}
317
318/**
319 * Free reference to the hx509 certificate object, if the refcounter
320 * reaches 0, the object if freed. Its allowed to pass in NULL.
321 *
322 * @param cert the cert to free.
323 *
324 * @ingroup hx509_cert
325 */
326
327void
328hx509_cert_free(hx509_cert cert)
329{
330 int i;
331
332 if (cert == NULL)
333 return;
334
335 if (cert->ref <= 0)
336 _hx509_abort("cert refcount <= 0 on free");
337 if (--cert->ref > 0)
338 return;
339
340 if (cert->release)
341 (cert->release)(cert, cert->ctx);
342
343 if (cert->private_key)
344 hx509_private_key_free(&cert->private_key);
345
346 free_Certificate(cert->data);
347 free(cert->data);
348
349 for (i = 0; i < cert->attrs.len; i++) {
350 der_free_octet_string(&cert->attrs.val[i]->data);
351 der_free_oid(&cert->attrs.val[i]->oid);
352 free(cert->attrs.val[i]);
353 }
354 free(cert->attrs.val);
355 free(cert->friendlyname);
356 if (cert->basename)
357 hx509_name_free(&cert->basename);
358 memset(cert, 0, sizeof(cert));
359 free(cert);
360}
361
362/**
363 * Add a reference to a hx509 certificate object.
364 *
365 * @param cert a pointer to an hx509 certificate object.
366 *
367 * @return the same object as is passed in.
368 *
369 * @ingroup hx509_cert
370 */
371
372hx509_cert
373hx509_cert_ref(hx509_cert cert)
374{
375 if (cert == NULL)
376 return NULL;
377 if (cert->ref <= 0)
378 _hx509_abort("cert refcount <= 0");
379 cert->ref++;
380 if (cert->ref == 0)
381 _hx509_abort("cert refcount == 0");
382 return cert;
383}
384
385/**
386 * Allocate an verification context that is used fo control the
387 * verification process.
388 *
389 * @param context A hx509 context.
390 * @param ctx returns a pointer to a hx509_verify_ctx object.
391 *
392 * @return An hx509 error code, see hx509_get_error_string().
393 *
394 * @ingroup hx509_verify
395 */
396
397int
398hx509_verify_init_ctx(hx509_context context, hx509_verify_ctx *ctx)
399{
400 hx509_verify_ctx c;
401
402 c = calloc(1, sizeof(*c));
403 if (c == NULL)
404 return ENOMEM;
405
406 c->max_depth = HX509_VERIFY_MAX_DEPTH;
407
408 *ctx = c;
409
410 return 0;
411}
412
413/**
414 * Free an hx509 verification context.
415 *
416 * @param ctx the context to be freed.
417 *
418 * @ingroup hx509_verify
419 */
420
421void
422hx509_verify_destroy_ctx(hx509_verify_ctx ctx)
423{
424 if (ctx) {
425 hx509_certs_free(&ctx->trust_anchors);
426 hx509_revoke_free(&ctx->revoke_ctx);
427 memset(ctx, 0, sizeof(*ctx));
428 }
429 free(ctx);
430}
431
432/**
433 * Set the trust anchors in the verification context, makes an
434 * reference to the keyset, so the consumer can free the keyset
435 * independent of the destruction of the verification context (ctx).
436 * If there already is a keyset attached, it's released.
437 *
438 * @param ctx a verification context
439 * @param set a keyset containing the trust anchors.
440 *
441 * @ingroup hx509_verify
442 */
443
444void
445hx509_verify_attach_anchors(hx509_verify_ctx ctx, hx509_certs set)
446{
447 if (ctx->trust_anchors)
448 hx509_certs_free(&ctx->trust_anchors);
449 ctx->trust_anchors = hx509_certs_ref(set);
450}
451
452/**
453 * Attach an revocation context to the verfication context, , makes an
454 * reference to the revoke context, so the consumer can free the
455 * revoke context independent of the destruction of the verification
456 * context. If there is no revoke context, the verification process is
457 * NOT going to check any verification status.
458 *
459 * @param ctx a verification context.
460 * @param revoke_ctx a revoke context.
461 *
462 * @ingroup hx509_verify
463 */
464
465void
466hx509_verify_attach_revoke(hx509_verify_ctx ctx, hx509_revoke_ctx revoke_ctx)
467{
468 if (ctx->revoke_ctx)
469 hx509_revoke_free(&ctx->revoke_ctx);
470 ctx->revoke_ctx = _hx509_revoke_ref(revoke_ctx);
471}
472
473/**
474 * Set the clock time the the verification process is going to
475 * use. Used to check certificate in the past and future time. If not
476 * set the current time will be used.
477 *
478 * @param ctx a verification context.
479 * @param t the time the verifiation is using.
480 *
481 *
482 * @ingroup hx509_verify
483 */
484
485void
486hx509_verify_set_time(hx509_verify_ctx ctx, time_t t)
487{
488 ctx->flags |= HX509_VERIFY_CTX_F_TIME_SET;
489 ctx->time_now = t;
490}
491
492time_t
493_hx509_verify_get_time(hx509_verify_ctx ctx)
494{
495 return ctx->time_now;
496}
497
498/**
499 * Set the maximum depth of the certificate chain that the path
500 * builder is going to try.
501 *
502 * @param ctx a verification context
503 * @param max_depth maxium depth of the certificate chain, include
504 * trust anchor.
505 *
506 * @ingroup hx509_verify
507 */
508
509void
510hx509_verify_set_max_depth(hx509_verify_ctx ctx, unsigned int max_depth)
511{
512 ctx->max_depth = max_depth;
513}
514
515/**
516 * Allow or deny the use of proxy certificates
517 *
518 * @param ctx a verification context
519 * @param boolean if non zero, allow proxy certificates.
520 *
521 * @ingroup hx509_verify
522 */
523
524void
525hx509_verify_set_proxy_certificate(hx509_verify_ctx ctx, int boolean)
526{
527 if (boolean)
528 ctx->flags |= HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
529 else
530 ctx->flags &= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
531}
532
533/**
534 * Select strict RFC3280 verification of certificiates. This means
535 * checking key usage on CA certificates, this will make version 1
536 * certificiates unuseable.
537 *
538 * @param ctx a verification context
539 * @param boolean if non zero, use strict verification.
540 *
541 * @ingroup hx509_verify
542 */
543
544void
545hx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx, int boolean)
546{
547 if (boolean)
548 ctx->flags |= HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
549 else
550 ctx->flags &= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
551}
552
553/**
554 * Allow using the operating system builtin trust anchors if no other
555 * trust anchors are configured.
556 *
557 * @param ctx a verification context
558 * @param boolean if non zero, useing the operating systems builtin
559 * trust anchors.
560 *
561 *
562 * @return An hx509 error code, see hx509_get_error_string().
563 *
564 * @ingroup hx509_cert
565 */
566
567void
568hx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx, int boolean)
569{
570 if (boolean)
571 ctx->flags &= ~HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
572 else
573 ctx->flags |= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
574}
575
576void
577hx509_verify_ctx_f_allow_best_before_signature_algs(hx509_context ctx,
578 int boolean)
579{
580 if (boolean)
581 ctx->flags &= ~HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK;
582 else
583 ctx->flags |= HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK;
584}
585
586static const Extension *
587find_extension(const Certificate *cert, const heim_oid *oid, int *idx)
588{
589 const TBSCertificate *c = &cert->tbsCertificate;
590
591 if (c->version == NULL || *c->version < 2 || c->extensions == NULL)
592 return NULL;
593
594 for (;*idx < c->extensions->len; (*idx)++) {
595 if (der_heim_oid_cmp(&c->extensions->val[*idx].extnID, oid) == 0)
596 return &c->extensions->val[(*idx)++];
597 }
598 return NULL;
599}
600
601static int
602find_extension_auth_key_id(const Certificate *subject,
603 AuthorityKeyIdentifier *ai)
604{
605 const Extension *e;
606 size_t size;
607 int i = 0;
608
609 memset(ai, 0, sizeof(*ai));
610
611 e = find_extension(subject, &asn1_oid_id_x509_ce_authorityKeyIdentifier, &i);
612 if (e == NULL)
613 return HX509_EXTENSION_NOT_FOUND;
614
615 return decode_AuthorityKeyIdentifier(e->extnValue.data,
616 e->extnValue.length,
617 ai, &size);
618}
619
620int
621_hx509_find_extension_subject_key_id(const Certificate *issuer,
622 SubjectKeyIdentifier *si)
623{
624 const Extension *e;
625 size_t size;
626 int i = 0;
627
628 memset(si, 0, sizeof(*si));
629
630 e = find_extension(issuer, &asn1_oid_id_x509_ce_subjectKeyIdentifier, &i);
631 if (e == NULL)
632 return HX509_EXTENSION_NOT_FOUND;
633
634 return decode_SubjectKeyIdentifier(e->extnValue.data,
635 e->extnValue.length,
636 si, &size);
637}
638
639static int
640find_extension_name_constraints(const Certificate *subject,
641 NameConstraints *nc)
642{
643 const Extension *e;
644 size_t size;
645 int i = 0;
646
647 memset(nc, 0, sizeof(*nc));
648
649 e = find_extension(subject, &asn1_oid_id_x509_ce_nameConstraints, &i);
650 if (e == NULL)
651 return HX509_EXTENSION_NOT_FOUND;
652
653 return decode_NameConstraints(e->extnValue.data,
654 e->extnValue.length,
655 nc, &size);
656}
657
658static int
659find_extension_subject_alt_name(const Certificate *cert, int *i,
660 GeneralNames *sa)
661{
662 const Extension *e;
663 size_t size;
664
665 memset(sa, 0, sizeof(*sa));
666
667 e = find_extension(cert, &asn1_oid_id_x509_ce_subjectAltName, i);
668 if (e == NULL)
669 return HX509_EXTENSION_NOT_FOUND;
670
671 return decode_GeneralNames(e->extnValue.data,
672 e->extnValue.length,
673 sa, &size);
674}
675
676static int
677find_extension_eku(const Certificate *cert, ExtKeyUsage *eku)
678{
679 const Extension *e;
680 size_t size;
681 int i = 0;
682
683 memset(eku, 0, sizeof(*eku));
684
685 e = find_extension(cert, &asn1_oid_id_x509_ce_extKeyUsage, &i);
686 if (e == NULL)
687 return HX509_EXTENSION_NOT_FOUND;
688
689 return decode_ExtKeyUsage(e->extnValue.data,
690 e->extnValue.length,
691 eku, &size);
692}
693
694static int
695add_to_list(hx509_octet_string_list *list, const heim_octet_string *entry)
696{
697 void *p;
698 int ret;
699
700 p = realloc(list->val, (list->len + 1) * sizeof(list->val[0]));
701 if (p == NULL)
702 return ENOMEM;
703 list->val = p;
704 ret = der_copy_octet_string(entry, &list->val[list->len]);
705 if (ret)
706 return ret;
707 list->len++;
708 return 0;
709}
710
711/**
712 * Free a list of octet strings returned by another hx509 library
713 * function.
714 *
715 * @param list list to be freed.
716 *
717 * @ingroup hx509_misc
718 */
719
720void
721hx509_free_octet_string_list(hx509_octet_string_list *list)
722{
723 int i;
724 for (i = 0; i < list->len; i++)
725 der_free_octet_string(&list->val[i]);
726 free(list->val);
727 list->val = NULL;
728 list->len = 0;
729}
730
731/**
732 * Return a list of subjectAltNames specified by oid in the
733 * certificate. On error the
734 *
735 * The returned list of octet string should be freed with
736 * hx509_free_octet_string_list().
737 *
738 * @param context A hx509 context.
739 * @param cert a hx509 certificate object.
740 * @param oid an oid to for SubjectAltName.
741 * @param list list of matching SubjectAltName.
742 *
743 * @return An hx509 error code, see hx509_get_error_string().
744 *
745 * @ingroup hx509_cert
746 */
747
748int
749hx509_cert_find_subjectAltName_otherName(hx509_context context,
750 hx509_cert cert,
751 const heim_oid *oid,
752 hx509_octet_string_list *list)
753{
754 GeneralNames sa;
755 int ret, i, j;
756
757 list->val = NULL;
758 list->len = 0;
759
760 i = 0;
761 while (1) {
762 ret = find_extension_subject_alt_name(_hx509_get_cert(cert), &i, &sa);
763 i++;
764 if (ret == HX509_EXTENSION_NOT_FOUND) {
765 return 0;
766 } else if (ret != 0) {
767 hx509_set_error_string(context, 0, ret, "Error searching for SAN");
768 hx509_free_octet_string_list(list);
769 return ret;
770 }
771
772 for (j = 0; j < sa.len; j++) {
773 if (sa.val[j].element == choice_GeneralName_otherName &&
774 der_heim_oid_cmp(&sa.val[j].u.otherName.type_id, oid) == 0)
775 {
776 ret = add_to_list(list, &sa.val[j].u.otherName.value);
777 if (ret) {
778 hx509_set_error_string(context, 0, ret,
779 "Error adding an exra SAN to "
780 "return list");
781 hx509_free_octet_string_list(list);
782 free_GeneralNames(&sa);
783 return ret;
784 }
785 }
786 }
787 free_GeneralNames(&sa);
788 }
789}
790
791
792static int
793check_key_usage(hx509_context context, const Certificate *cert,
794 unsigned flags, int req_present)
795{
796 const Extension *e;
797 KeyUsage ku;
798 size_t size;
799 int ret, i = 0;
800 unsigned ku_flags;
801
802 if (_hx509_cert_get_version(cert) < 3)
803 return 0;
804
805 e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i);
806 if (e == NULL) {
807 if (req_present) {
808 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
809 "Required extension key "
810 "usage missing from certifiate");
811 return HX509_KU_CERT_MISSING;
812 }
813 return 0;
814 }
815
816 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, &ku, &size);
817 if (ret)
818 return ret;
819 ku_flags = KeyUsage2int(ku);
820 if ((ku_flags & flags) != flags) {
821 unsigned missing = (~ku_flags) & flags;
822 char buf[256], *name;
823
824 unparse_flags(missing, asn1_KeyUsage_units(), buf, sizeof(buf));
825 _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
826 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
827 "Key usage %s required but missing "
828 "from certifiate %s", buf, name);
829 free(name);
830 return HX509_KU_CERT_MISSING;
831 }
832 return 0;
833}
834
835/*
836 * Return 0 on matching key usage 'flags' for 'cert', otherwise return
837 * an error code. If 'req_present' the existance is required of the
838 * KeyUsage extension.
839 */
840
841int
842_hx509_check_key_usage(hx509_context context, hx509_cert cert,
843 unsigned flags, int req_present)
844{
845 return check_key_usage(context, _hx509_get_cert(cert), flags, req_present);
846}
847
848enum certtype { PROXY_CERT, EE_CERT, CA_CERT };
849
850static int
851check_basic_constraints(hx509_context context, const Certificate *cert,
852 enum certtype type, int depth)
853{
854 BasicConstraints bc;
855 const Extension *e;
856 size_t size;
857 int ret, i = 0;
858
859 if (_hx509_cert_get_version(cert) < 3)
860 return 0;
861
862 e = find_extension(cert, &asn1_oid_id_x509_ce_basicConstraints, &i);
863 if (e == NULL) {
864 switch(type) {
865 case PROXY_CERT:
866 case EE_CERT:
867 return 0;
868 case CA_CERT: {
869 char *name;
870 ret = _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
871 assert(ret == 0);
872 hx509_set_error_string(context, 0, HX509_EXTENSION_NOT_FOUND,
873 "basicConstraints missing from "
874 "CA certifiacte %s", name);
875 free(name);
876 return HX509_EXTENSION_NOT_FOUND;
877 }
878 }
879 }
880
881 ret = decode_BasicConstraints(e->extnValue.data,
882 e->extnValue.length, &bc,
883 &size);
884 if (ret)
885 return ret;
886 switch(type) {
887 case PROXY_CERT:
888 if (bc.cA != NULL && *bc.cA)
889 ret = HX509_PARENT_IS_CA;
890 break;
891 case EE_CERT:
892 ret = 0;
893 break;
894 case CA_CERT:
895 if (bc.cA == NULL || !*bc.cA)
896 ret = HX509_PARENT_NOT_CA;
897 else if (bc.pathLenConstraint)
898 if (depth - 1 > *bc.pathLenConstraint)
899 ret = HX509_CA_PATH_TOO_DEEP;
900 break;
901 }
902 free_BasicConstraints(&bc);
903 return ret;
904}
905
906int
907_hx509_cert_is_parent_cmp(const Certificate *subject,
908 const Certificate *issuer,
909 int allow_self_signed)
910{
911 int diff;
912 AuthorityKeyIdentifier ai;
913 SubjectKeyIdentifier si;
914 int ret_ai, ret_si, ret;
915
916 ret = _hx509_name_cmp(&issuer->tbsCertificate.subject,
917 &subject->tbsCertificate.issuer,
918 &diff);
919 if (ret)
920 return ret;
921 if (diff)
922 return diff;
923
924 memset(&ai, 0, sizeof(ai));
925 memset(&si, 0, sizeof(si));
926
927 /*
928 * Try to find AuthorityKeyIdentifier, if it's not present in the
929 * subject certificate nor the parent.
930 */
931
932 ret_ai = find_extension_auth_key_id(subject, &ai);
933 if (ret_ai && ret_ai != HX509_EXTENSION_NOT_FOUND)
934 return 1;
935 ret_si = _hx509_find_extension_subject_key_id(issuer, &si);
936 if (ret_si && ret_si != HX509_EXTENSION_NOT_FOUND)
937 return -1;
938
939 if (ret_si && ret_ai)
940 goto out;
941 if (ret_ai)
942 goto out;
943 if (ret_si) {
944 if (allow_self_signed) {
945 diff = 0;
946 goto out;
947 } else if (ai.keyIdentifier) {
948 diff = -1;
949 goto out;
950 }
951 }
952
953 if (ai.keyIdentifier == NULL) {
954 Name name;
955
956 if (ai.authorityCertIssuer == NULL)
957 return -1;
958 if (ai.authorityCertSerialNumber == NULL)
959 return -1;
960
961 diff = der_heim_integer_cmp(ai.authorityCertSerialNumber,
962 &issuer->tbsCertificate.serialNumber);
963 if (diff)
964 return diff;
965 if (ai.authorityCertIssuer->len != 1)
966 return -1;
967 if (ai.authorityCertIssuer->val[0].element != choice_GeneralName_directoryName)
968 return -1;
969
970 name.element =
971 ai.authorityCertIssuer->val[0].u.directoryName.element;
972 name.u.rdnSequence =
973 ai.authorityCertIssuer->val[0].u.directoryName.u.rdnSequence;
974
975 ret = _hx509_name_cmp(&issuer->tbsCertificate.subject,
976 &name,
977 &diff);
978 if (ret)
979 return ret;
980 if (diff)
981 return diff;
982 diff = 0;
983 } else
984 diff = der_heim_octet_string_cmp(ai.keyIdentifier, &si);
985 if (diff)
986 goto out;
987
988 out:
989 free_AuthorityKeyIdentifier(&ai);
990 free_SubjectKeyIdentifier(&si);
991 return diff;
992}
993
994static int
995certificate_is_anchor(hx509_context context,
996 hx509_certs trust_anchors,
997 const hx509_cert cert)
998{
999 hx509_query q;
1000 hx509_cert c;
1001 int ret;
1002
1003 if (trust_anchors == NULL)
1004 return 0;
1005
1006 _hx509_query_clear(&q);
1007
1008 q.match = HX509_QUERY_MATCH_CERTIFICATE;
1009 q.certificate = _hx509_get_cert(cert);
1010
1011 ret = hx509_certs_find(context, trust_anchors, &q, &c);
1012 if (ret == 0)
1013 hx509_cert_free(c);
1014 return ret == 0;
1015}
1016
1017static int
1018certificate_is_self_signed(hx509_context context,
1019 const Certificate *cert,
1020 int *self_signed)
1021{
1022 int ret, diff;
1023 ret = _hx509_name_cmp(&cert->tbsCertificate.subject,
1024 &cert->tbsCertificate.issuer, &diff);
1025 *self_signed = (diff == 0);
1026 if (ret) {
1027 hx509_set_error_string(context, 0, ret,
1028 "Failed to check if self signed");
1029 } else
1030 ret = _hx509_self_signed_valid(context, &cert->signatureAlgorithm);
1031
1032 return ret;
1033}
1034
1035/*
1036 * The subjectName is "null" when it's empty set of relative DBs.
1037 */
1038
1039static int
1040subject_null_p(const Certificate *c)
1041{
1042 return c->tbsCertificate.subject.u.rdnSequence.len == 0;
1043}
1044
1045
1046static int
1047find_parent(hx509_context context,
1048 time_t time_now,
1049 hx509_certs trust_anchors,
1050 hx509_path *path,
1051 hx509_certs pool,
1052 hx509_cert current,
1053 hx509_cert *parent)
1054{
1055 AuthorityKeyIdentifier ai;
1056 hx509_query q;
1057 int ret;
1058
1059 *parent = NULL;
1060 memset(&ai, 0, sizeof(ai));
1061
1062 _hx509_query_clear(&q);
1063
1064 if (!subject_null_p(current->data)) {
1065 q.match |= HX509_QUERY_FIND_ISSUER_CERT;
1066 q.subject = _hx509_get_cert(current);
1067 } else {
1068 ret = find_extension_auth_key_id(current->data, &ai);
1069 if (ret) {
1070 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1071 "Subjectless certificate missing AuthKeyID");
1072 return HX509_CERTIFICATE_MALFORMED;
1073 }
1074
1075 if (ai.keyIdentifier == NULL) {
1076 free_AuthorityKeyIdentifier(&ai);
1077 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1078 "Subjectless certificate missing keyIdentifier "
1079 "inside AuthKeyID");
1080 return HX509_CERTIFICATE_MALFORMED;
1081 }
1082
1083 q.subject_id = ai.keyIdentifier;
1084 q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
1085 }
1086
1087 q.path = path;
1088 q.match |= HX509_QUERY_NO_MATCH_PATH;
1089
1090 if (pool) {
1091 q.timenow = time_now;
1092 q.match |= HX509_QUERY_MATCH_TIME;
1093
1094 ret = hx509_certs_find(context, pool, &q, parent);
1095 if (ret == 0) {
1096 free_AuthorityKeyIdentifier(&ai);
1097 return 0;
1098 }
1099 q.match &= ~HX509_QUERY_MATCH_TIME;
1100 }
1101
1102 if (trust_anchors) {
1103 ret = hx509_certs_find(context, trust_anchors, &q, parent);
1104 if (ret == 0) {
1105 free_AuthorityKeyIdentifier(&ai);
1106 return ret;
1107 }
1108 }
1109 free_AuthorityKeyIdentifier(&ai);
1110
1111 {
1112 hx509_name name;
1113 char *str;
1114
1115 ret = hx509_cert_get_subject(current, &name);
1116 if (ret) {
1117 hx509_clear_error_string(context);
1118 return HX509_ISSUER_NOT_FOUND;
1119 }
1120 ret = hx509_name_to_string(name, &str);
1121 hx509_name_free(&name);
1122 if (ret) {
1123 hx509_clear_error_string(context);
1124 return HX509_ISSUER_NOT_FOUND;
1125 }
1126
1127 hx509_set_error_string(context, 0, HX509_ISSUER_NOT_FOUND,
1128 "Failed to find issuer for "
1129 "certificate with subject: '%s'", str);
1130 free(str);
1131 }
1132 return HX509_ISSUER_NOT_FOUND;
1133}
1134
1135/*
1136 *
1137 */
1138
1139static int
1140is_proxy_cert(hx509_context context,
1141 const Certificate *cert,
1142 ProxyCertInfo *rinfo)
1143{
1144 ProxyCertInfo info;
1145 const Extension *e;
1146 size_t size;
1147 int ret, i = 0;
1148
1149 if (rinfo)
1150 memset(rinfo, 0, sizeof(*rinfo));
1151
1152 e = find_extension(cert, &asn1_oid_id_pkix_pe_proxyCertInfo, &i);
1153 if (e == NULL) {
1154 hx509_clear_error_string(context);
1155 return HX509_EXTENSION_NOT_FOUND;
1156 }
1157
1158 ret = decode_ProxyCertInfo(e->extnValue.data,
1159 e->extnValue.length,
1160 &info,
1161 &size);
1162 if (ret) {
1163 hx509_clear_error_string(context);
1164 return ret;
1165 }
1166 if (size != e->extnValue.length) {
1167 free_ProxyCertInfo(&info);
1168 hx509_clear_error_string(context);
1169 return HX509_EXTRA_DATA_AFTER_STRUCTURE;
1170 }
1171 if (rinfo == NULL)
1172 free_ProxyCertInfo(&info);
1173 else
1174 *rinfo = info;
1175
1176 return 0;
1177}
1178
1179/*
1180 * Path operations are like MEMORY based keyset, but with exposed
1181 * internal so we can do easy searches.
1182 */
1183
1184int
1185_hx509_path_append(hx509_context context, hx509_path *path, hx509_cert cert)
1186{
1187 hx509_cert *val;
1188 val = realloc(path->val, (path->len + 1) * sizeof(path->val[0]));
1189 if (val == NULL) {
1190 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1191 return ENOMEM;
1192 }
1193
1194 path->val = val;
1195 path->val[path->len] = hx509_cert_ref(cert);
1196 path->len++;
1197
1198 return 0;
1199}
1200
1201void
1202_hx509_path_free(hx509_path *path)
1203{
1204 unsigned i;
1205
1206 for (i = 0; i < path->len; i++)
1207 hx509_cert_free(path->val[i]);
1208 free(path->val);
1209 path->val = NULL;
1210 path->len = 0;
1211}
1212
1213/*
1214 * Find path by looking up issuer for the top certificate and continue
1215 * until an anchor certificate is found or max limit is found. A
1216 * certificate never included twice in the path.
1217 *
1218 * If the trust anchors are not given, calculate optimistic path, just
1219 * follow the chain upward until we no longer find a parent or we hit
1220 * the max path limit. In this case, a failure will always be returned
1221 * depending on what error condition is hit first.
1222 *
1223 * The path includes a path from the top certificate to the anchor
1224 * certificate.
1225 *
1226 * The caller needs to free `pathÂŽ both on successful built path and
1227 * failure.
1228 */
1229
1230int
1231_hx509_calculate_path(hx509_context context,
1232 int flags,
1233 time_t time_now,
1234 hx509_certs anchors,
1235 unsigned int max_depth,
1236 hx509_cert cert,
1237 hx509_certs pool,
1238 hx509_path *path)
1239{
1240 hx509_cert parent, current;
1241 int ret;
1242
1243 if (max_depth == 0)
1244 max_depth = HX509_VERIFY_MAX_DEPTH;
1245
1246 ret = _hx509_path_append(context, path, cert);
1247 if (ret)
1248 return ret;
1249
1250 current = hx509_cert_ref(cert);
1251
1252 while (!certificate_is_anchor(context, anchors, current)) {
1253
1254 ret = find_parent(context, time_now, anchors, path,
1255 pool, current, &parent);
1256 hx509_cert_free(current);
1257 if (ret)
1258 return ret;
1259
1260 ret = _hx509_path_append(context, path, parent);
1261 if (ret)
1262 return ret;
1263 current = parent;
1264
1265 if (path->len > max_depth) {
1266 hx509_cert_free(current);
1267 hx509_set_error_string(context, 0, HX509_PATH_TOO_LONG,
1268 "Path too long while bulding "
1269 "certificate chain");
1270 return HX509_PATH_TOO_LONG;
1271 }
1272 }
1273
1274 if ((flags & HX509_CALCULATE_PATH_NO_ANCHOR) &&
1275 path->len > 0 &&
1276 certificate_is_anchor(context, anchors, path->val[path->len - 1]))
1277 {
1278 hx509_cert_free(path->val[path->len - 1]);
1279 path->len--;
1280 }
1281
1282 hx509_cert_free(current);
1283 return 0;
1284}
1285
1286int
1287_hx509_AlgorithmIdentifier_cmp(const AlgorithmIdentifier *p,
1288 const AlgorithmIdentifier *q)
1289{
1290 int diff;
1291 diff = der_heim_oid_cmp(&p->algorithm, &q->algorithm);
1292 if (diff)
1293 return diff;
1294 if (p->parameters) {
1295 if (q->parameters)
1296 return heim_any_cmp(p->parameters,
1297 q->parameters);
1298 else
1299 return 1;
1300 } else {
1301 if (q->parameters)
1302 return -1;
1303 else
1304 return 0;
1305 }
1306}
1307
1308int
1309_hx509_Certificate_cmp(const Certificate *p, const Certificate *q)
1310{
1311 int diff;
1312 diff = der_heim_bit_string_cmp(&p->signatureValue, &q->signatureValue);
1313 if (diff)
1314 return diff;
1315 diff = _hx509_AlgorithmIdentifier_cmp(&p->signatureAlgorithm,
1316 &q->signatureAlgorithm);
1317 if (diff)
1318 return diff;
1319 diff = der_heim_octet_string_cmp(&p->tbsCertificate._save,
1320 &q->tbsCertificate._save);
1321 return diff;
1322}
1323
1324/**
1325 * Compare to hx509 certificate object, useful for sorting.
1326 *
1327 * @param p a hx509 certificate object.
1328 * @param q a hx509 certificate object.
1329 *
1330 * @return 0 the objects are the same, returns > 0 is p is "larger"
1331 * then q, < 0 if p is "smaller" then q.
1332 *
1333 * @ingroup hx509_cert
1334 */
1335
1336int
1337hx509_cert_cmp(hx509_cert p, hx509_cert q)
1338{
1339 return _hx509_Certificate_cmp(p->data, q->data);
1340}
1341
1342/**
1343 * Return the name of the issuer of the hx509 certificate.
1344 *
1345 * @param p a hx509 certificate object.
1346 * @param name a pointer to a hx509 name, should be freed by
1347 * hx509_name_free().
1348 *
1349 * @return An hx509 error code, see hx509_get_error_string().
1350 *
1351 * @ingroup hx509_cert
1352 */
1353
1354int
1355hx509_cert_get_issuer(hx509_cert p, hx509_name *name)
1356{
1357 return _hx509_name_from_Name(&p->data->tbsCertificate.issuer, name);
1358}
1359
1360/**
1361 * Return the name of the subject of the hx509 certificate.
1362 *
1363 * @param p a hx509 certificate object.
1364 * @param name a pointer to a hx509 name, should be freed by
1365 * hx509_name_free(). See also hx509_cert_get_base_subject().
1366 *
1367 * @return An hx509 error code, see hx509_get_error_string().
1368 *
1369 * @ingroup hx509_cert
1370 */
1371
1372int
1373hx509_cert_get_subject(hx509_cert p, hx509_name *name)
1374{
1375 return _hx509_name_from_Name(&p->data->tbsCertificate.subject, name);
1376}
1377
1378/**
1379 * Return the name of the base subject of the hx509 certificate. If
1380 * the certiicate is a verified proxy certificate, the this function
1381 * return the base certificate (root of the proxy chain). If the proxy
1382 * certificate is not verified with the base certificate
1383 * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned.
1384 *
1385 * @param context a hx509 context.
1386 * @param c a hx509 certificate object.
1387 * @param name a pointer to a hx509 name, should be freed by
1388 * hx509_name_free(). See also hx509_cert_get_subject().
1389 *
1390 * @return An hx509 error code, see hx509_get_error_string().
1391 *
1392 * @ingroup hx509_cert
1393 */
1394
1395int
1396hx509_cert_get_base_subject(hx509_context context, hx509_cert c,
1397 hx509_name *name)
1398{
1399 if (c->basename)
1400 return hx509_name_copy(context, c->basename, name);
1401 if (is_proxy_cert(context, c->data, NULL) == 0) {
1402 int ret = HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED;
1403 hx509_set_error_string(context, 0, ret,
1404 "Proxy certificate have not been "
1405 "canonicalize yet, no base name");
1406 return ret;
1407 }
1408 return _hx509_name_from_Name(&c->data->tbsCertificate.subject, name);
1409}
1410
1411/**
1412 * Get serial number of the certificate.
1413 *
1414 * @param p a hx509 certificate object.
1415 * @param i serial number, should be freed ith der_free_heim_integer().
1416 *
1417 * @return An hx509 error code, see hx509_get_error_string().
1418 *
1419 * @ingroup hx509_cert
1420 */
1421
1422int
1423hx509_cert_get_serialnumber(hx509_cert p, heim_integer *i)
1424{
1425 return der_copy_heim_integer(&p->data->tbsCertificate.serialNumber, i);
1426}
1427
1428/**
1429 * Get notBefore time of the certificate.
1430 *
1431 * @param p a hx509 certificate object.
1432 *
1433 * @return return not before time
1434 *
1435 * @ingroup hx509_cert
1436 */
1437
1438time_t
1439hx509_cert_get_notBefore(hx509_cert p)
1440{
1441 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notBefore);
1442}
1443
1444/**
1445 * Get notAfter time of the certificate.
1446 *
1447 * @param p a hx509 certificate object.
1448 *
1449 * @return return not after time.
1450 *
1451 * @ingroup hx509_cert
1452 */
1453
1454time_t
1455hx509_cert_get_notAfter(hx509_cert p)
1456{
1457 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notAfter);
1458}
1459
1460/**
1461 * Get the SubjectPublicKeyInfo structure from the hx509 certificate.
1462 *
1463 * @param context a hx509 context.
1464 * @param p a hx509 certificate object.
1465 * @param spki SubjectPublicKeyInfo, should be freed with
1466 * free_SubjectPublicKeyInfo().
1467 *
1468 * @return An hx509 error code, see hx509_get_error_string().
1469 *
1470 * @ingroup hx509_cert
1471 */
1472
1473int
1474hx509_cert_get_SPKI(hx509_context context, hx509_cert p, SubjectPublicKeyInfo *spki)
1475{
1476 int ret;
1477
1478 ret = copy_SubjectPublicKeyInfo(&p->data->tbsCertificate.subjectPublicKeyInfo, spki);
1479 if (ret)
1480 hx509_set_error_string(context, 0, ret, "Failed to copy SPKI");
1481 return ret;
1482}
1483
1484/**
1485 * Get the AlgorithmIdentifier from the hx509 certificate.
1486 *
1487 * @param context a hx509 context.
1488 * @param p a hx509 certificate object.
1489 * @param alg AlgorithmIdentifier, should be freed with
1490 * free_AlgorithmIdentifier(). The algorithmidentifier is
1491 * typicly rsaEncryption, or id-ecPublicKey, or some other
1492 * public key mechanism.
1493 *
1494 * @return An hx509 error code, see hx509_get_error_string().
1495 *
1496 * @ingroup hx509_cert
1497 */
1498
1499int
1500hx509_cert_get_SPKI_AlgorithmIdentifier(hx509_context context,
1501 hx509_cert p,
1502 AlgorithmIdentifier *alg)
1503{
1504 int ret;
1505
1506 ret = copy_AlgorithmIdentifier(&p->data->tbsCertificate.subjectPublicKeyInfo.algorithm, alg);
1507 if (ret)
1508 hx509_set_error_string(context, 0, ret,
1509 "Failed to copy SPKI AlgorithmIdentifier");
1510 return ret;
1511}
1512
1513static int
1514get_x_unique_id(hx509_context context, const char *name,
1515 const heim_bit_string *cert, heim_bit_string *subject)
1516{
1517 int ret;
1518
1519 if (cert == NULL) {
1520 ret = HX509_EXTENSION_NOT_FOUND;
1521 hx509_set_error_string(context, 0, ret, "%s unique id doesn't exists", name);
1522 return ret;
1523 }
1524 ret = der_copy_bit_string(cert, subject);
1525 if (ret) {
1526 hx509_set_error_string(context, 0, ret, "malloc out of memory", name);
1527 return ret;
1528 }
1529 return 0;
1530}
1531
1532/**
1533 * Get a copy of the Issuer Unique ID
1534 *
1535 * @param context a hx509_context
1536 * @param p a hx509 certificate
1537 * @param issuer the issuer id returned, free with der_free_bit_string()
1538 *
1539 * @return An hx509 error code, see hx509_get_error_string(). The
1540 * error code HX509_EXTENSION_NOT_FOUND is returned if the certificate
1541 * doesn't have a issuerUniqueID
1542 *
1543 * @ingroup hx509_cert
1544 */
1545
1546int
1547hx509_cert_get_issuer_unique_id(hx509_context context, hx509_cert p, heim_bit_string *issuer)
1548{
1549 return get_x_unique_id(context, "issuer", p->data->tbsCertificate.issuerUniqueID, issuer);
1550}
1551
1552/**
1553 * Get a copy of the Subect Unique ID
1554 *
1555 * @param context a hx509_context
1556 * @param p a hx509 certificate
1557 * @param subject the subject id returned, free with der_free_bit_string()
1558 *
1559 * @return An hx509 error code, see hx509_get_error_string(). The
1560 * error code HX509_EXTENSION_NOT_FOUND is returned if the certificate
1561 * doesn't have a subjectUniqueID
1562 *
1563 * @ingroup hx509_cert
1564 */
1565
1566int
1567hx509_cert_get_subject_unique_id(hx509_context context, hx509_cert p, heim_bit_string *subject)
1568{
1569 return get_x_unique_id(context, "subject", p->data->tbsCertificate.subjectUniqueID, subject);
1570}
1571
1572
1573hx509_private_key
1574_hx509_cert_private_key(hx509_cert p)
1575{
1576 return p->private_key;
1577}
1578
1579int
1580hx509_cert_have_private_key(hx509_cert p)
1581{
1582 return p->private_key ? 1 : 0;
1583}
1584
1585
1586int
1587_hx509_cert_private_key_exportable(hx509_cert p)
1588{
1589 if (p->private_key == NULL)
1590 return 0;
1591 return _hx509_private_key_exportable(p->private_key);
1592}
1593
1594int
1595_hx509_cert_private_decrypt(hx509_context context,
1596 const heim_octet_string *ciphertext,
1597 const heim_oid *encryption_oid,
1598 hx509_cert p,
1599 heim_octet_string *cleartext)
1600{
1601 cleartext->data = NULL;
1602 cleartext->length = 0;
1603
1604 if (p->private_key == NULL) {
1605 hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
1606 "Private key missing");
1607 return HX509_PRIVATE_KEY_MISSING;
1608 }
1609
1610 return hx509_private_key_private_decrypt(context,
1611 ciphertext,
1612 encryption_oid,
1613 p->private_key,
1614 cleartext);
1615}
1616
1617int
1618hx509_cert_public_encrypt(hx509_context context,
1619 const heim_octet_string *cleartext,
1620 const hx509_cert p,
1621 heim_oid *encryption_oid,
1622 heim_octet_string *ciphertext)
1623{
1624 return _hx509_public_encrypt(context,
1625 cleartext, p->data,
1626 encryption_oid, ciphertext);
1627}
1628
1629/*
1630 *
1631 */
1632
1633time_t
1634_hx509_Time2time_t(const Time *t)
1635{
1636 switch(t->element) {
1637 case choice_Time_utcTime:
1638 return t->u.utcTime;
1639 case choice_Time_generalTime:
1640 return t->u.generalTime;
1641 }
1642 return 0;
1643}
1644
1645/*
1646 *
1647 */
1648
1649static int
1650init_name_constraints(hx509_name_constraints *nc)
1651{
1652 memset(nc, 0, sizeof(*nc));
1653 return 0;
1654}
1655
1656static int
1657add_name_constraints(hx509_context context, const Certificate *c, int not_ca,
1658 hx509_name_constraints *nc)
1659{
1660 NameConstraints tnc;
1661 int ret;
1662
1663 ret = find_extension_name_constraints(c, &tnc);
1664 if (ret == HX509_EXTENSION_NOT_FOUND)
1665 return 0;
1666 else if (ret) {
1667 hx509_set_error_string(context, 0, ret, "Failed getting NameConstraints");
1668 return ret;
1669 } else if (not_ca) {
1670 ret = HX509_VERIFY_CONSTRAINTS;
1671 hx509_set_error_string(context, 0, ret, "Not a CA and "
1672 "have NameConstraints");
1673 } else {
1674 NameConstraints *val;
1675 val = realloc(nc->val, sizeof(nc->val[0]) * (nc->len + 1));
1676 if (val == NULL) {
1677 hx509_clear_error_string(context);
1678 ret = ENOMEM;
1679 goto out;
1680 }
1681 nc->val = val;
1682 ret = copy_NameConstraints(&tnc, &nc->val[nc->len]);
1683 if (ret) {
1684 hx509_clear_error_string(context);
1685 goto out;
1686 }
1687 nc->len += 1;
1688 }
1689out:
1690 free_NameConstraints(&tnc);
1691 return ret;
1692}
1693
1694static int
1695match_RDN(const RelativeDistinguishedName *c,
1696 const RelativeDistinguishedName *n)
1697{
1698 int i;
1699
1700 if (c->len != n->len)
1701 return HX509_NAME_CONSTRAINT_ERROR;
1702
1703 for (i = 0; i < n->len; i++) {
1704 int diff, ret;
1705
1706 if (der_heim_oid_cmp(&c->val[i].type, &n->val[i].type) != 0)
1707 return HX509_NAME_CONSTRAINT_ERROR;
1708 ret = _hx509_name_ds_cmp(&c->val[i].value, &n->val[i].value, &diff);
1709 if (ret)
1710 return ret;
1711 if (diff != 0)
1712 return HX509_NAME_CONSTRAINT_ERROR;
1713 }
1714 return 0;
1715}
1716
1717static int
1718match_X501Name(const Name *c, const Name *n)
1719{
1720 int i, ret;
1721
1722 if (c->element != choice_Name_rdnSequence
1723 || n->element != choice_Name_rdnSequence)
1724 return 0;
1725 if (c->u.rdnSequence.len > n->u.rdnSequence.len)
1726 return HX509_NAME_CONSTRAINT_ERROR;
1727 for (i = 0; i < c->u.rdnSequence.len; i++) {
1728 ret = match_RDN(&c->u.rdnSequence.val[i], &n->u.rdnSequence.val[i]);
1729 if (ret)
1730 return ret;
1731 }
1732 return 0;
1733}
1734
1735
1736static int
1737match_general_name(const GeneralName *c, const GeneralName *n, int *match)
1738{
1739 /*
1740 * Name constraints only apply to the same name type, see RFC3280,
1741 * 4.2.1.11.
1742 */
1743 assert(c->element == n->element);
1744
1745 switch(c->element) {
1746 case choice_GeneralName_otherName:
1747 if (der_heim_oid_cmp(&c->u.otherName.type_id,
1748 &n->u.otherName.type_id) != 0)
1749 return HX509_NAME_CONSTRAINT_ERROR;
1750 if (heim_any_cmp(&c->u.otherName.value,
1751 &n->u.otherName.value) != 0)
1752 return HX509_NAME_CONSTRAINT_ERROR;
1753 *match = 1;
1754 return 0;
1755 case choice_GeneralName_rfc822Name: {
1756 const char *s;
1757 size_t len1, len2;
1758 s = memchr(c->u.rfc822Name.data, '@', c->u.rfc822Name.length);
1759 if (s) {
1760 if (der_printable_string_cmp(&c->u.rfc822Name, &n->u.rfc822Name) != 0)
1761 return HX509_NAME_CONSTRAINT_ERROR;
1762 } else {
1763 s = memchr(n->u.rfc822Name.data, '@', n->u.rfc822Name.length);
1764 if (s == NULL)
1765 return HX509_NAME_CONSTRAINT_ERROR;
1766 len1 = c->u.rfc822Name.length;
1767 len2 = n->u.rfc822Name.length -
1768 (s - ((char *)n->u.rfc822Name.data));
1769 if (len1 > len2)
1770 return HX509_NAME_CONSTRAINT_ERROR;
1771 if (memcmp(s + 1 + len2 - len1, c->u.rfc822Name.data, len1) != 0)
1772 return HX509_NAME_CONSTRAINT_ERROR;
1773 if (len1 < len2 && s[len2 - len1 + 1] != '.')
1774 return HX509_NAME_CONSTRAINT_ERROR;
1775 }
1776 *match = 1;
1777 return 0;
1778 }
1779 case choice_GeneralName_dNSName: {
1780 size_t lenc, lenn;
1781 char *ptr;
1782
1783 lenc = c->u.dNSName.length;
1784 lenn = n->u.dNSName.length;
1785 if (lenc > lenn)
1786 return HX509_NAME_CONSTRAINT_ERROR;
1787 ptr = n->u.dNSName.data;
1788 if (memcmp(&ptr[lenn - lenc], c->u.dNSName.data, lenc) != 0)
1789 return HX509_NAME_CONSTRAINT_ERROR;
1790 if (lenn != lenc && ptr[lenn - lenc - 1] != '.')
1791 return HX509_NAME_CONSTRAINT_ERROR;
1792 *match = 1;
1793 return 0;
1794 }
1795 case choice_GeneralName_directoryName: {
1796 Name c_name, n_name;
1797 int ret;
1798
1799 c_name._save.data = NULL;
1800 c_name._save.length = 0;
1801 c_name.element = c->u.directoryName.element;
1802 c_name.u.rdnSequence = c->u.directoryName.u.rdnSequence;
1803
1804 n_name._save.data = NULL;
1805 n_name._save.length = 0;
1806 n_name.element = n->u.directoryName.element;
1807 n_name.u.rdnSequence = n->u.directoryName.u.rdnSequence;
1808
1809 ret = match_X501Name(&c_name, &n_name);
1810 if (ret == 0)
1811 *match = 1;
1812 return ret;
1813 }
1814 case choice_GeneralName_uniformResourceIdentifier:
1815 case choice_GeneralName_iPAddress:
1816 case choice_GeneralName_registeredID:
1817 default:
1818 return HX509_NAME_CONSTRAINT_ERROR;
1819 }
1820}
1821
1822static int
1823match_alt_name(const GeneralName *n, const Certificate *c,
1824 int *same, int *match)
1825{
1826 GeneralNames sa;
1827 int ret, i, j;
1828
1829 i = 0;
1830 do {
1831 ret = find_extension_subject_alt_name(c, &i, &sa);
1832 if (ret == HX509_EXTENSION_NOT_FOUND) {
1833 ret = 0;
1834 break;
1835 } else if (ret != 0)
1836 break;
1837
1838 for (j = 0; j < sa.len; j++) {
1839 if (n->element == sa.val[j].element) {
1840 *same = 1;
1841 ret = match_general_name(n, &sa.val[j], match);
1842 }
1843 }
1844 free_GeneralNames(&sa);
1845 } while (1);
1846 return ret;
1847}
1848
1849
1850static int
1851match_tree(const GeneralSubtrees *t, const Certificate *c, int *match)
1852{
1853 int name, alt_name, same;
1854 unsigned int i;
1855 int ret = 0;
1856
1857 name = alt_name = same = *match = 0;
1858 for (i = 0; i < t->len; i++) {
1859 if (t->val[i].minimum && t->val[i].maximum)
1860 return HX509_RANGE;
1861
1862 /*
1863 * If the constraint apply to directoryNames, test is with
1864 * subjectName of the certificate if the certificate have a
1865 * non-null (empty) subjectName.
1866 */
1867
1868 if (t->val[i].base.element == choice_GeneralName_directoryName
1869 && !subject_null_p(c))
1870 {
1871 GeneralName certname;
1872
1873 memset(&certname, 0, sizeof(certname));
1874 certname.element = choice_GeneralName_directoryName;
1875 certname.u.directoryName.element =
1876 c->tbsCertificate.subject.element;
1877 certname.u.directoryName.u.rdnSequence =
1878 c->tbsCertificate.subject.u.rdnSequence;
1879
1880 ret = match_general_name(&t->val[i].base, &certname, &name);
1881 }
1882
1883 /* Handle subjectAltNames, this is icky since they
1884 * restrictions only apply if the subjectAltName is of the
1885 * same type. So if there have been a match of type, require
1886 * altname to be set.
1887 */
1888 ret = match_alt_name(&t->val[i].base, c, &same, &alt_name);
1889 }
1890 if (name && (!same || alt_name))
1891 *match = 1;
1892 return ret;
1893}
1894
1895static int
1896check_name_constraints(hx509_context context,
1897 const hx509_name_constraints *nc,
1898 const Certificate *c)
1899{
1900 int match, ret;
1901 int i;
1902
1903 for (i = 0 ; i < nc->len; i++) {
1904 GeneralSubtrees gs;
1905
1906 if (nc->val[i].permittedSubtrees) {
1907 GeneralSubtrees_SET(&gs, nc->val[i].permittedSubtrees);
1908 ret = match_tree(&gs, c, &match);
1909 if (ret) {
1910 hx509_clear_error_string(context);
1911 return ret;
1912 }
1913 /* allow null subjectNames, they wont matches anything */
1914 if (match == 0 && !subject_null_p(c)) {
1915 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1916 "Error verify constraints, "
1917 "certificate didn't match any "
1918 "permitted subtree");
1919 return HX509_VERIFY_CONSTRAINTS;
1920 }
1921 }
1922 if (nc->val[i].excludedSubtrees) {
1923 GeneralSubtrees_SET(&gs, nc->val[i].excludedSubtrees);
1924 ret = match_tree(&gs, c, &match);
1925 if (ret) {
1926 hx509_clear_error_string(context);
1927 return ret;
1928 }
1929 if (match) {
1930 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1931 "Error verify constraints, "
1932 "certificate included in excluded "
1933 "subtree");
1934 return HX509_VERIFY_CONSTRAINTS;
1935 }
1936 }
1937 }
1938 return 0;
1939}
1940
1941static void
1942free_name_constraints(hx509_name_constraints *nc)
1943{
1944 int i;
1945
1946 for (i = 0 ; i < nc->len; i++)
1947 free_NameConstraints(&nc->val[i]);
1948 free(nc->val);
1949}
1950
1951/**
1952 * Build and verify the path for the certificate to the trust anchor
1953 * specified in the verify context. The path is constructed from the
1954 * certificate, the pool and the trust anchors.
1955 *
1956 * @param context A hx509 context.
1957 * @param ctx A hx509 verification context.
1958 * @param cert the certificate to build the path from.
1959 * @param pool A keyset of certificates to build the chain from.
1960 *
1961 * @return An hx509 error code, see hx509_get_error_string().
1962 *
1963 * @ingroup hx509_verify
1964 */
1965
1966int
1967hx509_verify_path(hx509_context context,
1968 hx509_verify_ctx ctx,
1969 hx509_cert cert,
1970 hx509_certs pool)
1971{
1972 hx509_name_constraints nc;
1973 hx509_path path;
1974 int ret, i, proxy_cert_depth, selfsigned_depth, diff;
1975 enum certtype type;
1976 Name proxy_issuer;
1977 hx509_certs anchors = NULL;
1978
1979 memset(&proxy_issuer, 0, sizeof(proxy_issuer));
1980
1981 ret = init_name_constraints(&nc);
1982 if (ret)
1983 return ret;
1984
1985 path.val = NULL;
1986 path.len = 0;
1987
1988 if ((ctx->flags & HX509_VERIFY_CTX_F_TIME_SET) == 0)
1989 ctx->time_now = time(NULL);
1990
1991 /*
1992 *
1993 */
1994 if (ctx->trust_anchors)
1995 anchors = hx509_certs_ref(ctx->trust_anchors);
1996 else if (context->default_trust_anchors && ALLOW_DEF_TA(ctx))
1997 anchors = hx509_certs_ref(context->default_trust_anchors);
1998 else {
1999 ret = hx509_certs_init(context, "MEMORY:no-TA", 0, NULL, &anchors);
2000 if (ret)
2001 goto out;
2002 }
2003
2004 /*
2005 * Calculate the path from the certificate user presented to the
2006 * to an anchor.
2007 */
2008 ret = _hx509_calculate_path(context, 0, ctx->time_now,
2009 anchors, ctx->max_depth,
2010 cert, pool, &path);
2011 if (ret)
2012 goto out;
2013
2014 /*
2015 * Check CA and proxy certificate chain from the top of the
2016 * certificate chain. Also check certificate is valid with respect
2017 * to the current time.
2018 *
2019 */
2020
2021 proxy_cert_depth = 0;
2022 selfsigned_depth = 0;
2023
2024 if (ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE)
2025 type = PROXY_CERT;
2026 else
2027 type = EE_CERT;
2028
2029 for (i = 0; i < path.len; i++) {
2030 Certificate *c;
2031 time_t t;
2032
2033 c = _hx509_get_cert(path.val[i]);
2034
2035 /*
2036 * Lets do some basic check on issuer like
2037 * keyUsage.keyCertSign and basicConstraints.cA bit depending
2038 * on what type of certificate this is.
2039 */
2040
2041 switch (type) {
2042 case CA_CERT:
2043
2044 /* XXX make constants for keyusage */
2045 ret = check_key_usage(context, c, 1 << 5,
2046 REQUIRE_RFC3280(ctx) ? TRUE : FALSE);
2047 if (ret) {
2048 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
2049 "Key usage missing from CA certificate");
2050 goto out;
2051 }
2052
2053 /* self signed cert doesn't add to path length */
2054 if (i + 1 != path.len) {
2055 int selfsigned;
2056
2057 ret = certificate_is_self_signed(context, c, &selfsigned);
2058 if (ret)
2059 goto out;
2060 if (selfsigned)
2061 selfsigned_depth++;
2062 }
2063
2064 break;
2065 case PROXY_CERT: {
2066 ProxyCertInfo info;
2067
2068 if (is_proxy_cert(context, c, &info) == 0) {
2069 int j;
2070
2071 if (info.pCPathLenConstraint != NULL &&
2072 *info.pCPathLenConstraint < i)
2073 {
2074 free_ProxyCertInfo(&info);
2075 ret = HX509_PATH_TOO_LONG;
2076 hx509_set_error_string(context, 0, ret,
2077 "Proxy certificate chain "
2078 "longer then allowed");
2079 goto out;
2080 }
2081 /* XXX MUST check info.proxyPolicy */
2082 free_ProxyCertInfo(&info);
2083
2084 j = 0;
2085 if (find_extension(c, &asn1_oid_id_x509_ce_subjectAltName, &j)) {
2086 ret = HX509_PROXY_CERT_INVALID;
2087 hx509_set_error_string(context, 0, ret,
2088 "Proxy certificate have explicity "
2089 "forbidden subjectAltName");
2090 goto out;
2091 }
2092
2093 j = 0;
2094 if (find_extension(c, &asn1_oid_id_x509_ce_issuerAltName, &j)) {
2095 ret = HX509_PROXY_CERT_INVALID;
2096 hx509_set_error_string(context, 0, ret,
2097 "Proxy certificate have explicity "
2098 "forbidden issuerAltName");
2099 goto out;
2100 }
2101
2102 /*
2103 * The subject name of the proxy certificate should be
2104 * CN=XXX,<proxy issuer>, prune of CN and check if its
2105 * the same over the whole chain of proxy certs and
2106 * then check with the EE cert when we get to it.
2107 */
2108
2109 if (proxy_cert_depth) {
2110 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.subject, &diff);
2111 if (ret) {
2112 hx509_set_error_string(context, 0, ret, "Out of memory");
2113 goto out;
2114 }
2115 if (diff) {
2116 ret = HX509_PROXY_CERT_NAME_WRONG;
2117 hx509_set_error_string(context, 0, ret,
2118 "Base proxy name not right");
2119 goto out;
2120 }
2121 }
2122
2123 free_Name(&proxy_issuer);
2124
2125 ret = copy_Name(&c->tbsCertificate.subject, &proxy_issuer);
2126 if (ret) {
2127 hx509_clear_error_string(context);
2128 goto out;
2129 }
2130
2131 j = proxy_issuer.u.rdnSequence.len;
2132 if (proxy_issuer.u.rdnSequence.len < 2
2133 || proxy_issuer.u.rdnSequence.val[j - 1].len > 1
2134 || der_heim_oid_cmp(&proxy_issuer.u.rdnSequence.val[j - 1].val[0].type,
2135 &asn1_oid_id_at_commonName))
2136 {
2137 ret = HX509_PROXY_CERT_NAME_WRONG;
2138 hx509_set_error_string(context, 0, ret,
2139 "Proxy name too short or "
2140 "does not have Common name "
2141 "at the top");
2142 goto out;
2143 }
2144
2145 free_RelativeDistinguishedName(&proxy_issuer.u.rdnSequence.val[j - 1]);
2146 proxy_issuer.u.rdnSequence.len -= 1;
2147
2148 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.issuer, &diff);
2149 if (ret) {
2150 hx509_set_error_string(context, 0, ret, "Out of memory");
2151 goto out;
2152 }
2153 if (diff != 0) {
2154 ret = HX509_PROXY_CERT_NAME_WRONG;
2155 hx509_set_error_string(context, 0, ret,
2156 "Proxy issuer name not as expected");
2157 goto out;
2158 }
2159
2160 break;
2161 } else {
2162 /*
2163 * Now we are done with the proxy certificates, this
2164 * cert was an EE cert and we we will fall though to
2165 * EE checking below.
2166 */
2167 type = EE_CERT;
2168 /* FALLTHOUGH */
2169 }
2170 }
2171 case EE_CERT:
2172 /*
2173 * If there where any proxy certificates in the chain
2174 * (proxy_cert_depth > 0), check that the proxy issuer
2175 * matched proxy certificates "base" subject.
2176 */
2177 if (proxy_cert_depth) {
2178
2179 ret = _hx509_name_cmp(&proxy_issuer,
2180 &c->tbsCertificate.subject, &diff);
2181 if (ret) {
2182 hx509_set_error_string(context, 0, ret, "out of memory");
2183 goto out;
2184 }
2185 if (diff) {
2186 ret = HX509_PROXY_CERT_NAME_WRONG;
2187 hx509_clear_error_string(context);
2188 goto out;
2189 }
2190 if (cert->basename)
2191 hx509_name_free(&cert->basename);
2192
2193 ret = _hx509_name_from_Name(&proxy_issuer, &cert->basename);
2194 if (ret) {
2195 hx509_clear_error_string(context);
2196 goto out;
2197 }
2198 }
2199
2200 break;
2201 }
2202
2203 ret = check_basic_constraints(context, c, type,
2204 i - proxy_cert_depth - selfsigned_depth);
2205 if (ret)
2206 goto out;
2207
2208 /*
2209 * Don't check the trust anchors expiration time since they
2210 * are transported out of band, from RFC3820.
2211 */
2212 if (i + 1 != path.len || CHECK_TA(ctx)) {
2213
2214 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2215 if (t > ctx->time_now) {
2216 ret = HX509_CERT_USED_BEFORE_TIME;
2217 hx509_clear_error_string(context);
2218 goto out;
2219 }
2220 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2221 if (t < ctx->time_now) {
2222 ret = HX509_CERT_USED_AFTER_TIME;
2223 hx509_clear_error_string(context);
2224 goto out;
2225 }
2226 }
2227
2228 if (type == EE_CERT)
2229 type = CA_CERT;
2230 else if (type == PROXY_CERT)
2231 proxy_cert_depth++;
2232 }
2233
2234 /*
2235 * Verify constraints, do this backward so path constraints are
2236 * checked in the right order.
2237 */
2238
2239 for (ret = 0, i = path.len - 1; i >= 0; i--) {
2240 Certificate *c;
2241 int selfsigned;
2242
2243 c = _hx509_get_cert(path.val[i]);
2244
2245 ret = certificate_is_self_signed(context, c, &selfsigned);
2246 if (ret)
2247 goto out;
2248
2249 /* verify name constraints, not for selfsigned and anchor */
2250 if (!selfsigned || i + 1 != path.len) {
2251 ret = check_name_constraints(context, &nc, c);
2252 if (ret) {
2253 goto out;
2254 }
2255 }
2256 ret = add_name_constraints(context, c, i == 0, &nc);
2257 if (ret)
2258 goto out;
2259
2260 /* XXX verify all other silly constraints */
2261
2262 }
2263
2264 /*
2265 * Verify that no certificates has been revoked.
2266 */
2267
2268 if (ctx->revoke_ctx) {
2269 hx509_certs certs;
2270
2271 ret = hx509_certs_init(context, "MEMORY:revoke-certs", 0,
2272 NULL, &certs);
2273 if (ret)
2274 goto out;
2275
2276 for (i = 0; i < path.len; i++) {
2277 ret = hx509_certs_add(context, certs, path.val[i]);
2278 if (ret) {
2279 hx509_certs_free(&certs);
2280 goto out;
2281 }
2282 }
2283 ret = hx509_certs_merge(context, certs, pool);
2284 if (ret) {
2285 hx509_certs_free(&certs);
2286 goto out;
2287 }
2288
2289 for (i = 0; i < path.len - 1; i++) {
2290 int parent = (i < path.len - 1) ? i + 1 : i;
2291
2292 ret = hx509_revoke_verify(context,
2293 ctx->revoke_ctx,
2294 certs,
2295 ctx->time_now,
2296 path.val[i],
2297 path.val[parent]);
2298 if (ret) {
2299 hx509_certs_free(&certs);
2300 goto out;
2301 }
2302 }
2303 hx509_certs_free(&certs);
2304 }
2305
2306 /*
2307 * Verify signatures, do this backward so public key working
2308 * parameter is passed up from the anchor up though the chain.
2309 */
2310
2311 for (i = path.len - 1; i >= 0; i--) {
2312 hx509_cert signer;
2313 Certificate *c;
2314
2315 c = _hx509_get_cert(path.val[i]);
2316
2317 /* is last in chain (trust anchor) */
2318 if (i + 1 == path.len) {
2319 int selfsigned;
2320
2321 signer = path.val[i];
2322
2323 ret = certificate_is_self_signed(context, signer->data, &selfsigned);
2324 if (ret)
2325 goto out;
2326
2327 /* if trust anchor is not self signed, don't check sig */
2328 if (!selfsigned)
2329 continue;
2330 } else {
2331 /* take next certificate in chain */
2332 signer = path.val[i + 1];
2333 }
2334
2335 /* verify signatureValue */
2336 ret = _hx509_verify_signature_bitstring(context,
2337 signer,
2338 &c->signatureAlgorithm,
2339 &c->tbsCertificate._save,
2340 &c->signatureValue);
2341 if (ret) {
2342 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
2343 "Failed to verify signature of certificate");
2344 goto out;
2345 }
2346 /*
2347 * Verify that the sigature algorithm "best-before" date is
2348 * before the creation date of the certificate, do this for
2349 * trust anchors too, since any trust anchor that is created
2350 * after a algorithm is known to be bad deserved to be invalid.
2351 *
2352 * Skip the leaf certificate for now...
2353 */
2354
2355 if (i != 0 && (ctx->flags & HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK) == 0) {
2356 time_t notBefore =
2357 _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2358 ret = _hx509_signature_best_before(context,
2359 &c->signatureAlgorithm,
2360 notBefore);
2361 if (ret)
2362 goto out;
2363 }
2364 }
2365
2366out:
2367 hx509_certs_free(&anchors);
2368 free_Name(&proxy_issuer);
2369 free_name_constraints(&nc);
2370 _hx509_path_free(&path);
2371
2372 return ret;
2373}
2374
2375/**
2376 * Verify a signature made using the private key of an certificate.
2377 *
2378 * @param context A hx509 context.
2379 * @param signer the certificate that made the signature.
2380 * @param alg algorthm that was used to sign the data.
2381 * @param data the data that was signed.
2382 * @param sig the sigature to verify.
2383 *
2384 * @return An hx509 error code, see hx509_get_error_string().
2385 *
2386 * @ingroup hx509_crypto
2387 */
2388
2389int
2390hx509_verify_signature(hx509_context context,
2391 const hx509_cert signer,
2392 const AlgorithmIdentifier *alg,
2393 const heim_octet_string *data,
2394 const heim_octet_string *sig)
2395{
2396 return _hx509_verify_signature(context, signer, alg, data, sig);
2397}
2398
2399int
2400_hx509_verify_signature_bitstring(hx509_context context,
2401 const hx509_cert signer,
2402 const AlgorithmIdentifier *alg,
2403 const heim_octet_string *data,
2404 const heim_bit_string *sig)
2405{
2406 heim_octet_string os;
2407
2408 if (sig->length & 7) {
2409 hx509_set_error_string(context, 0, HX509_CRYPTO_SIG_INVALID_FORMAT,
2410 "signature not multiple of 8 bits");
2411 return HX509_CRYPTO_SIG_INVALID_FORMAT;
2412 }
2413
2414 os.data = sig->data;
2415 os.length = sig->length / 8;
2416
2417 return _hx509_verify_signature(context, signer, alg, data, &os);
2418}
2419
2420
2421
2422/**
2423 * Verify that the certificate is allowed to be used for the hostname
2424 * and address.
2425 *
2426 * @param context A hx509 context.
2427 * @param cert the certificate to match with
2428 * @param flags Flags to modify the behavior:
2429 * - HX509_VHN_F_ALLOW_NO_MATCH no match is ok
2430 * @param type type of hostname:
2431 * - HX509_HN_HOSTNAME for plain hostname.
2432 * - HX509_HN_DNSSRV for DNS SRV names.
2433 * @param hostname the hostname to check
2434 * @param sa address of the host
2435 * @param sa_size length of address
2436 *
2437 * @return An hx509 error code, see hx509_get_error_string().
2438 *
2439 * @ingroup hx509_cert
2440 */
2441
2442int
2443hx509_verify_hostname(hx509_context context,
2444 const hx509_cert cert,
2445 int flags,
2446 hx509_hostname_type type,
2447 const char *hostname,
2448 const struct sockaddr *sa,
2449 /* XXX krb5_socklen_t */ int sa_size)
2450{
2451 GeneralNames san;
2452 const Name *name;
2453 int ret, i, j;
2454
2455 if (sa && sa_size <= 0)
2456 return EINVAL;
2457
2458 memset(&san, 0, sizeof(san));
2459
2460 i = 0;
2461 do {
2462 ret = find_extension_subject_alt_name(cert->data, &i, &san);
2463 if (ret == HX509_EXTENSION_NOT_FOUND)
2464 break;
2465 else if (ret != 0)
2466 return HX509_PARSING_NAME_FAILED;
2467
2468 for (j = 0; j < san.len; j++) {
2469 switch (san.val[j].element) {
2470 case choice_GeneralName_dNSName: {
2471 heim_printable_string hn;
2472 hn.data = rk_UNCONST(hostname);
2473 hn.length = strlen(hostname);
2474
2475 if (der_printable_string_cmp(&san.val[j].u.dNSName, &hn) == 0) {
2476 free_GeneralNames(&san);
2477 return 0;
2478 }
2479 break;
2480 }
2481 default:
2482 break;
2483 }
2484 }
2485 free_GeneralNames(&san);
2486 } while (1);
2487
2488 name = &cert->data->tbsCertificate.subject;
2489
2490 /* Find first CN= in the name, and try to match the hostname on that */
2491 for (ret = 0, i = name->u.rdnSequence.len - 1; ret == 0 && i >= 0; i--) {
2492 for (j = 0; ret == 0 && j < name->u.rdnSequence.val[i].len; j++) {
2493 AttributeTypeAndValue *n = &name->u.rdnSequence.val[i].val[j];
2494
2495 if (der_heim_oid_cmp(&n->type, &asn1_oid_id_at_commonName) == 0) {
2496 DirectoryString *ds = &n->value;
2497 switch (ds->element) {
2498 case choice_DirectoryString_printableString: {
2499 heim_printable_string hn;
2500 hn.data = rk_UNCONST(hostname);
2501 hn.length = strlen(hostname);
2502
2503 if (der_printable_string_cmp(&ds->u.printableString, &hn) == 0)
2504 return 0;
2505 break;
2506 }
2507 case choice_DirectoryString_ia5String: {
2508 heim_ia5_string hn;
2509 hn.data = rk_UNCONST(hostname);
2510 hn.length = strlen(hostname);
2511
2512 if (der_ia5_string_cmp(&ds->u.ia5String, &hn) == 0)
2513 return 0;
2514 break;
2515 }
2516 case choice_DirectoryString_utf8String:
2517 if (strcasecmp(ds->u.utf8String, hostname) == 0)
2518 return 0;
2519 default:
2520 break;
2521 }
2522 ret = HX509_NAME_CONSTRAINT_ERROR;
2523 }
2524 }
2525 }
2526
2527 if ((flags & HX509_VHN_F_ALLOW_NO_MATCH) == 0)
2528 ret = HX509_NAME_CONSTRAINT_ERROR;
2529
2530 return ret;
2531}
2532
2533int
2534_hx509_set_cert_attribute(hx509_context context,
2535 hx509_cert cert,
2536 const heim_oid *oid,
2537 const heim_octet_string *attr)
2538{
2539 hx509_cert_attribute a;
2540 void *d;
2541
2542 if (hx509_cert_get_attribute(cert, oid) != NULL)
2543 return 0;
2544
2545 d = realloc(cert->attrs.val,
2546 sizeof(cert->attrs.val[0]) * (cert->attrs.len + 1));
2547 if (d == NULL) {
2548 hx509_clear_error_string(context);
2549 return ENOMEM;
2550 }
2551 cert->attrs.val = d;
2552
2553 a = malloc(sizeof(*a));
2554 if (a == NULL)
2555 return ENOMEM;
2556
2557 der_copy_octet_string(attr, &a->data);
2558 der_copy_oid(oid, &a->oid);
2559
2560 cert->attrs.val[cert->attrs.len] = a;
2561 cert->attrs.len++;
2562
2563 return 0;
2564}
2565
2566/**
2567 * Get an external attribute for the certificate, examples are
2568 * friendly name and id.
2569 *
2570 * @param cert hx509 certificate object to search
2571 * @param oid an oid to search for.
2572 *
2573 * @return an hx509_cert_attribute, only valid as long as the
2574 * certificate is referenced.
2575 *
2576 * @ingroup hx509_cert
2577 */
2578
2579hx509_cert_attribute
2580hx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid)
2581{
2582 int i;
2583 for (i = 0; i < cert->attrs.len; i++)
2584 if (der_heim_oid_cmp(oid, &cert->attrs.val[i]->oid) == 0)
2585 return cert->attrs.val[i];
2586 return NULL;
2587}
2588
2589/**
2590 * Set the friendly name on the certificate.
2591 *
2592 * @param cert The certificate to set the friendly name on
2593 * @param name Friendly name.
2594 *
2595 * @return An hx509 error code, see hx509_get_error_string().
2596 *
2597 * @ingroup hx509_cert
2598 */
2599
2600int
2601hx509_cert_set_friendly_name(hx509_cert cert, const char *name)
2602{
2603 if (cert->friendlyname)
2604 free(cert->friendlyname);
2605 cert->friendlyname = strdup(name);
2606 if (cert->friendlyname == NULL)
2607 return ENOMEM;
2608 return 0;
2609}
2610
2611/**
2612 * Get friendly name of the certificate.
2613 *
2614 * @param cert cert to get the friendly name from.
2615 *
2616 * @return an friendly name or NULL if there is. The friendly name is
2617 * only valid as long as the certificate is referenced.
2618 *
2619 * @ingroup hx509_cert
2620 */
2621
2622const char *
2623hx509_cert_get_friendly_name(hx509_cert cert)
2624{
2625 hx509_cert_attribute a;
2626 PKCS9_friendlyName n;
2627 size_t sz;
2628 int ret, i;
2629
2630 if (cert->friendlyname)
2631 return cert->friendlyname;
2632
2633 a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_friendlyName);
2634 if (a == NULL) {
2635 hx509_name name;
2636
2637 ret = hx509_cert_get_subject(cert, &name);
2638 if (ret)
2639 return NULL;
2640 ret = hx509_name_to_string(name, &cert->friendlyname);
2641 hx509_name_free(&name);
2642 if (ret)
2643 return NULL;
2644 return cert->friendlyname;
2645 }
2646
2647 ret = decode_PKCS9_friendlyName(a->data.data, a->data.length, &n, &sz);
2648 if (ret)
2649 return NULL;
2650
2651 if (n.len != 1) {
2652 free_PKCS9_friendlyName(&n);
2653 return NULL;
2654 }
2655
2656 cert->friendlyname = malloc(n.val[0].length + 1);
2657 if (cert->friendlyname == NULL) {
2658 free_PKCS9_friendlyName(&n);
2659 return NULL;
2660 }
2661
2662 for (i = 0; i < n.val[0].length; i++) {
2663 if (n.val[0].data[i] <= 0xff)
2664 cert->friendlyname[i] = n.val[0].data[i] & 0xff;
2665 else
2666 cert->friendlyname[i] = 'X';
2667 }
2668 cert->friendlyname[i] = '\0';
2669 free_PKCS9_friendlyName(&n);
2670
2671 return cert->friendlyname;
2672}
2673
2674void
2675_hx509_query_clear(hx509_query *q)
2676{
2677 memset(q, 0, sizeof(*q));
2678}
2679
2680/**
2681 * Allocate an query controller. Free using hx509_query_free().
2682 *
2683 * @param context A hx509 context.
2684 * @param q return pointer to a hx509_query.
2685 *
2686 * @return An hx509 error code, see hx509_get_error_string().
2687 *
2688 * @ingroup hx509_cert
2689 */
2690
2691int
2692hx509_query_alloc(hx509_context context, hx509_query **q)
2693{
2694 *q = calloc(1, sizeof(**q));
2695 if (*q == NULL)
2696 return ENOMEM;
2697 return 0;
2698}
2699
2700
2701/**
2702 * Set match options for the hx509 query controller.
2703 *
2704 * @param q query controller.
2705 * @param option options to control the query controller.
2706 *
2707 * @return An hx509 error code, see hx509_get_error_string().
2708 *
2709 * @ingroup hx509_cert
2710 */
2711
2712void
2713hx509_query_match_option(hx509_query *q, hx509_query_option option)
2714{
2715 switch(option) {
2716 case HX509_QUERY_OPTION_PRIVATE_KEY:
2717 q->match |= HX509_QUERY_PRIVATE_KEY;
2718 break;
2719 case HX509_QUERY_OPTION_KU_ENCIPHERMENT:
2720 q->match |= HX509_QUERY_KU_ENCIPHERMENT;
2721 break;
2722 case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE:
2723 q->match |= HX509_QUERY_KU_DIGITALSIGNATURE;
2724 break;
2725 case HX509_QUERY_OPTION_KU_KEYCERTSIGN:
2726 q->match |= HX509_QUERY_KU_KEYCERTSIGN;
2727 break;
2728 case HX509_QUERY_OPTION_END:
2729 default:
2730 break;
2731 }
2732}
2733
2734/**
2735 * Set the issuer and serial number of match in the query
2736 * controller. The function make copies of the isser and serial number.
2737 *
2738 * @param q a hx509 query controller
2739 * @param issuer issuer to search for
2740 * @param serialNumber the serialNumber of the issuer.
2741 *
2742 * @return An hx509 error code, see hx509_get_error_string().
2743 *
2744 * @ingroup hx509_cert
2745 */
2746
2747int
2748hx509_query_match_issuer_serial(hx509_query *q,
2749 const Name *issuer,
2750 const heim_integer *serialNumber)
2751{
2752 int ret;
2753 if (q->serial) {
2754 der_free_heim_integer(q->serial);
2755 free(q->serial);
2756 }
2757 q->serial = malloc(sizeof(*q->serial));
2758 if (q->serial == NULL)
2759 return ENOMEM;
2760 ret = der_copy_heim_integer(serialNumber, q->serial);
2761 if (ret) {
2762 free(q->serial);
2763 q->serial = NULL;
2764 return ret;
2765 }
2766 if (q->issuer_name) {
2767 free_Name(q->issuer_name);
2768 free(q->issuer_name);
2769 }
2770 q->issuer_name = malloc(sizeof(*q->issuer_name));
2771 if (q->issuer_name == NULL)
2772 return ENOMEM;
2773 ret = copy_Name(issuer, q->issuer_name);
2774 if (ret) {
2775 free(q->issuer_name);
2776 q->issuer_name = NULL;
2777 return ret;
2778 }
2779 q->match |= HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
2780 return 0;
2781}
2782
2783/**
2784 * Set the query controller to match on a friendly name
2785 *
2786 * @param q a hx509 query controller.
2787 * @param name a friendly name to match on
2788 *
2789 * @return An hx509 error code, see hx509_get_error_string().
2790 *
2791 * @ingroup hx509_cert
2792 */
2793
2794int
2795hx509_query_match_friendly_name(hx509_query *q, const char *name)
2796{
2797 if (q->friendlyname)
2798 free(q->friendlyname);
2799 q->friendlyname = strdup(name);
2800 if (q->friendlyname == NULL)
2801 return ENOMEM;
2802 q->match |= HX509_QUERY_MATCH_FRIENDLY_NAME;
2803 return 0;
2804}
2805
2806/**
2807 * Set the query controller to require an one specific EKU (extended
2808 * key usage). Any previous EKU matching is overwitten. If NULL is
2809 * passed in as the eku, the EKU requirement is reset.
2810 *
2811 * @param q a hx509 query controller.
2812 * @param eku an EKU to match on.
2813 *
2814 * @return An hx509 error code, see hx509_get_error_string().
2815 *
2816 * @ingroup hx509_cert
2817 */
2818
2819int
2820hx509_query_match_eku(hx509_query *q, const heim_oid *eku)
2821{
2822 int ret;
2823
2824 if (eku == NULL) {
2825 if (q->eku) {
2826 der_free_oid(q->eku);
2827 free(q->eku);
2828 q->eku = NULL;
2829 }
2830 q->match &= ~HX509_QUERY_MATCH_EKU;
2831 } else {
2832 if (q->eku) {
2833 der_free_oid(q->eku);
2834 } else {
2835 q->eku = calloc(1, sizeof(*q->eku));
2836 if (q->eku == NULL)
2837 return ENOMEM;
2838 }
2839 ret = der_copy_oid(eku, q->eku);
2840 if (ret) {
2841 free(q->eku);
2842 q->eku = NULL;
2843 return ret;
2844 }
2845 q->match |= HX509_QUERY_MATCH_EKU;
2846 }
2847 return 0;
2848}
2849
2850int
2851hx509_query_match_expr(hx509_context context, hx509_query *q, const char *expr)
2852{
2853 if (q->expr) {
2854 _hx509_expr_free(q->expr);
2855 q->expr = NULL;
2856 }
2857
2858 if (expr == NULL) {
2859 q->match &= ~HX509_QUERY_MATCH_EXPR;
2860 } else {
2861 q->expr = _hx509_expr_parse(expr);
2862 if (q->expr)
2863 q->match |= HX509_QUERY_MATCH_EXPR;
2864 }
2865
2866 return 0;
2867}
2868
2869/**
2870 * Set the query controller to match using a specific match function.
2871 *
2872 * @param q a hx509 query controller.
2873 * @param func function to use for matching, if the argument is NULL,
2874 * the match function is removed.
2875 * @param ctx context passed to the function.
2876 *
2877 * @return An hx509 error code, see hx509_get_error_string().
2878 *
2879 * @ingroup hx509_cert
2880 */
2881
2882int
2883hx509_query_match_cmp_func(hx509_query *q,
2884 int (*func)(hx509_context, hx509_cert, void *),
2885 void *ctx)
2886{
2887 if (func)
2888 q->match |= HX509_QUERY_MATCH_FUNCTION;
2889 else
2890 q->match &= ~HX509_QUERY_MATCH_FUNCTION;
2891 q->cmp_func = func;
2892 q->cmp_func_ctx = ctx;
2893 return 0;
2894}
2895
2896/**
2897 * Free the query controller.
2898 *
2899 * @param context A hx509 context.
2900 * @param q a pointer to the query controller.
2901 *
2902 * @ingroup hx509_cert
2903 */
2904
2905void
2906hx509_query_free(hx509_context context, hx509_query *q)
2907{
2908 if (q == NULL)
2909 return;
2910
2911 if (q->serial) {
2912 der_free_heim_integer(q->serial);
2913 free(q->serial);
2914 }
2915 if (q->issuer_name) {
2916 free_Name(q->issuer_name);
2917 free(q->issuer_name);
2918 }
2919 if (q->eku) {
2920 der_free_oid(q->eku);
2921 free(q->eku);
2922 }
2923 if (q->friendlyname)
2924 free(q->friendlyname);
2925 if (q->expr)
2926 _hx509_expr_free(q->expr);
2927
2928 memset(q, 0, sizeof(*q));
2929 free(q);
2930}
2931
2932int
2933_hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert cert)
2934{
2935 Certificate *c = _hx509_get_cert(cert);
2936 int ret, diff;
2937
2938 _hx509_query_statistic(context, 1, q);
2939
2940 if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) &&
2941 _hx509_cert_is_parent_cmp(q->subject, c, 0) != 0)
2942 return 0;
2943
2944 if ((q->match & HX509_QUERY_MATCH_CERTIFICATE) &&
2945 _hx509_Certificate_cmp(q->certificate, c) != 0)
2946 return 0;
2947
2948 if ((q->match & HX509_QUERY_MATCH_SERIALNUMBER)
2949 && der_heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0)
2950 return 0;
2951
2952 if (q->match & HX509_QUERY_MATCH_ISSUER_NAME) {
2953 ret = _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name, &diff);
2954 if (ret || diff)
2955 return 0;
2956 }
2957
2958 if (q->match & HX509_QUERY_MATCH_SUBJECT_NAME) {
2959 ret = _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name, &diff);
2960 if (ret || diff)
2961 return 0;
2962 }
2963
2964 if (q->match & HX509_QUERY_MATCH_SUBJECT_KEY_ID) {
2965 SubjectKeyIdentifier si;
2966
2967 ret = _hx509_find_extension_subject_key_id(c, &si);
2968 if (ret == 0) {
2969 if (der_heim_octet_string_cmp(&si, q->subject_id) != 0)
2970 ret = 1;
2971 free_SubjectKeyIdentifier(&si);
2972 }
2973 if (ret)
2974 return 0;
2975 }
2976 if ((q->match & HX509_QUERY_MATCH_ISSUER_ID))
2977 return 0;
2978 if ((q->match & HX509_QUERY_PRIVATE_KEY) &&
2979 _hx509_cert_private_key(cert) == NULL)
2980 return 0;
2981
2982 {
2983 unsigned ku = 0;
2984 if (q->match & HX509_QUERY_KU_DIGITALSIGNATURE)
2985 ku |= (1 << 0);
2986 if (q->match & HX509_QUERY_KU_NONREPUDIATION)
2987 ku |= (1 << 1);
2988 if (q->match & HX509_QUERY_KU_ENCIPHERMENT)
2989 ku |= (1 << 2);
2990 if (q->match & HX509_QUERY_KU_DATAENCIPHERMENT)
2991 ku |= (1 << 3);
2992 if (q->match & HX509_QUERY_KU_KEYAGREEMENT)
2993 ku |= (1 << 4);
2994 if (q->match & HX509_QUERY_KU_KEYCERTSIGN)
2995 ku |= (1 << 5);
2996 if (q->match & HX509_QUERY_KU_CRLSIGN)
2997 ku |= (1 << 6);
2998 if (ku && check_key_usage(context, c, ku, TRUE))
2999 return 0;
3000 }
3001 if ((q->match & HX509_QUERY_ANCHOR))
3002 return 0;
3003
3004 if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) {
3005 hx509_cert_attribute a;
3006
3007 a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_localKeyId);
3008 if (a == NULL)
3009 return 0;
3010 if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0)
3011 return 0;
3012 }
3013
3014 if (q->match & HX509_QUERY_NO_MATCH_PATH) {
3015 size_t i;
3016
3017 for (i = 0; i < q->path->len; i++)
3018 if (hx509_cert_cmp(q->path->val[i], cert) == 0)
3019 return 0;
3020 }
3021 if (q->match & HX509_QUERY_MATCH_FRIENDLY_NAME) {
3022 const char *name = hx509_cert_get_friendly_name(cert);
3023 if (name == NULL)
3024 return 0;
3025 if (strcasecmp(q->friendlyname, name) != 0)
3026 return 0;
3027 }
3028 if (q->match & HX509_QUERY_MATCH_FUNCTION) {
3029 ret = (*q->cmp_func)(context, cert, q->cmp_func_ctx);
3030 if (ret != 0)
3031 return 0;
3032 }
3033
3034 if (q->match & HX509_QUERY_MATCH_KEY_HASH_SHA1) {
3035 heim_octet_string os;
3036
3037 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
3038 os.length =
3039 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
3040
3041 ret = _hx509_verify_signature(context,
3042 NULL,
3043 hx509_signature_sha1(),
3044 &os,
3045 q->keyhash_sha1);
3046 if (ret != 0)
3047 return 0;
3048 }
3049
3050 if (q->match & HX509_QUERY_MATCH_TIME) {
3051 time_t t;
3052 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
3053 if (t > q->timenow)
3054 return 0;
3055 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
3056 if (t < q->timenow)
3057 return 0;
3058 }
3059
3060 /* If an EKU is required, check the cert for it. */
3061 if ((q->match & HX509_QUERY_MATCH_EKU) &&
3062 hx509_cert_check_eku(context, cert, q->eku, 0))
3063 return 0;
3064
3065 if ((q->match & HX509_QUERY_MATCH_EXPR)) {
3066 hx509_env env = NULL;
3067
3068 ret = _hx509_cert_to_env(context, cert, &env);
3069 if (ret)
3070 return 0;
3071
3072 ret = _hx509_expr_eval(context, env, q->expr);
3073 hx509_env_free(&env);
3074 if (ret == 0)
3075 return 0;
3076 }
3077
3078 if (q->match & ~HX509_QUERY_MASK)
3079 return 0;
3080
3081 return 1;
3082}
3083
3084/**
3085 * Set a statistic file for the query statistics.
3086 *
3087 * @param context A hx509 context.
3088 * @param fn statistics file name
3089 *
3090 * @ingroup hx509_cert
3091 */
3092
3093void
3094hx509_query_statistic_file(hx509_context context, const char *fn)
3095{
3096 if (context->querystat)
3097 free(context->querystat);
3098 context->querystat = strdup(fn);
3099}
3100
3101void
3102_hx509_query_statistic(hx509_context context, int type, const hx509_query *q)
3103{
3104 FILE *f;
3105 if (context->querystat == NULL)
3106 return;
3107 f = fopen(context->querystat, "a");
3108 if (f == NULL)
3109 return;
3110 rk_cloexec_file(f);
3111 fprintf(f, "%d %d\n", type, q->match);
3112 fclose(f);
3113}
3114
3115static const char *statname[] = {
3116 "find issuer cert",
3117 "match serialnumber",
3118 "match issuer name",
3119 "match subject name",
3120 "match subject key id",
3121 "match issuer id",
3122 "private key",
3123 "ku encipherment",
3124 "ku digitalsignature",
3125 "ku keycertsign",
3126 "ku crlsign",
3127 "ku nonrepudiation",
3128 "ku keyagreement",
3129 "ku dataencipherment",
3130 "anchor",
3131 "match certificate",
3132 "match local key id",
3133 "no match path",
3134 "match friendly name",
3135 "match function",
3136 "match key hash sha1",
3137 "match time"
3138};
3139
3140struct stat_el {
3141 unsigned long stats;
3142 unsigned int index;
3143};
3144
3145
3146static int
3147stat_sort(const void *a, const void *b)
3148{
3149 const struct stat_el *ae = a;
3150 const struct stat_el *be = b;
3151 return be->stats - ae->stats;
3152}
3153
3154/**
3155 * Unparse the statistics file and print the result on a FILE descriptor.
3156 *
3157 * @param context A hx509 context.
3158 * @param printtype tyep to print
3159 * @param out the FILE to write the data on.
3160 *
3161 * @ingroup hx509_cert
3162 */
3163
3164void
3165hx509_query_unparse_stats(hx509_context context, int printtype, FILE *out)
3166{
3167 rtbl_t t;
3168 FILE *f;
3169 int type, mask, i, num;
3170 unsigned long multiqueries = 0, totalqueries = 0;
3171 struct stat_el stats[32];
3172
3173 if (context->querystat == NULL)
3174 return;
3175 f = fopen(context->querystat, "r");
3176 if (f == NULL) {
3177 fprintf(out, "No statistic file %s: %s.\n",
3178 context->querystat, strerror(errno));
3179 return;
3180 }
3181 rk_cloexec_file(f);
3182
3183 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
3184 stats[i].index = i;
3185 stats[i].stats = 0;
3186 }
3187
3188 while (fscanf(f, "%d %d\n", &type, &mask) == 2) {
3189 if (type != printtype)
3190 continue;
3191 num = i = 0;
3192 while (mask && i < sizeof(stats)/sizeof(stats[0])) {
3193 if (mask & 1) {
3194 stats[i].stats++;
3195 num++;
3196 }
3197 mask = mask >>1 ;
3198 i++;
3199 }
3200 if (num > 1)
3201 multiqueries++;
3202 totalqueries++;
3203 }
3204 fclose(f);
3205
3206 qsort(stats, sizeof(stats)/sizeof(stats[0]), sizeof(stats[0]), stat_sort);
3207
3208 t = rtbl_create();
3209 if (t == NULL)
3210 errx(1, "out of memory");
3211
3212 rtbl_set_separator (t, " ");
3213
3214 rtbl_add_column_by_id (t, 0, "Name", 0);
3215 rtbl_add_column_by_id (t, 1, "Counter", 0);
3216
3217
3218 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
3219 char str[10];
3220
3221 if (stats[i].index < sizeof(statname)/sizeof(statname[0]))
3222 rtbl_add_column_entry_by_id (t, 0, statname[stats[i].index]);
3223 else {
3224 snprintf(str, sizeof(str), "%d", stats[i].index);
3225 rtbl_add_column_entry_by_id (t, 0, str);
3226 }
3227 snprintf(str, sizeof(str), "%lu", stats[i].stats);
3228 rtbl_add_column_entry_by_id (t, 1, str);
3229 }
3230
3231 rtbl_format(t, out);
3232 rtbl_destroy(t);
3233
3234 fprintf(out, "\nQueries: multi %lu total %lu\n",
3235 multiqueries, totalqueries);
3236}
3237
3238/**
3239 * Check the extended key usage on the hx509 certificate.
3240 *
3241 * @param context A hx509 context.
3242 * @param cert A hx509 context.
3243 * @param eku the EKU to check for
3244 * @param allow_any_eku if the any EKU is set, allow that to be a
3245 * substitute.
3246 *
3247 * @return An hx509 error code, see hx509_get_error_string().
3248 *
3249 * @ingroup hx509_cert
3250 */
3251
3252int
3253hx509_cert_check_eku(hx509_context context, hx509_cert cert,
3254 const heim_oid *eku, int allow_any_eku)
3255{
3256 ExtKeyUsage e;
3257 int ret, i;
3258
3259 ret = find_extension_eku(_hx509_get_cert(cert), &e);
3260 if (ret) {
3261 hx509_clear_error_string(context);
3262 return ret;
3263 }
3264
3265 for (i = 0; i < e.len; i++) {
3266 if (der_heim_oid_cmp(eku, &e.val[i]) == 0) {
3267 free_ExtKeyUsage(&e);
3268 return 0;
3269 }
3270 if (allow_any_eku) {
3271#if 0
3272 if (der_heim_oid_cmp(id_any_eku, &e.val[i]) == 0) {
3273 free_ExtKeyUsage(&e);
3274 return 0;
3275 }
3276#endif
3277 }
3278 }
3279 free_ExtKeyUsage(&e);
3280 hx509_clear_error_string(context);
3281 return HX509_CERTIFICATE_MISSING_EKU;
3282}
3283
3284int
3285_hx509_cert_get_keyusage(hx509_context context,
3286 hx509_cert c,
3287 KeyUsage *ku)
3288{
3289 Certificate *cert;
3290 const Extension *e;
3291 size_t size;
3292 int ret, i = 0;
3293
3294 memset(ku, 0, sizeof(*ku));
3295
3296 cert = _hx509_get_cert(c);
3297
3298 if (_hx509_cert_get_version(cert) < 3)
3299 return 0;
3300
3301 e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i);
3302 if (e == NULL)
3303 return HX509_KU_CERT_MISSING;
3304
3305 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, ku, &size);
3306 if (ret)
3307 return ret;
3308 return 0;
3309}
3310
3311int
3312_hx509_cert_get_eku(hx509_context context,
3313 hx509_cert cert,
3314 ExtKeyUsage *e)
3315{
3316 int ret;
3317
3318 memset(e, 0, sizeof(*e));
3319
3320 ret = find_extension_eku(_hx509_get_cert(cert), e);
3321 if (ret && ret != HX509_EXTENSION_NOT_FOUND) {
3322 hx509_clear_error_string(context);
3323 return ret;
3324 }
3325 return 0;
3326}
3327
3328/**
3329 * Encodes the hx509 certificate as a DER encode binary.
3330 *
3331 * @param context A hx509 context.
3332 * @param c the certificate to encode.
3333 * @param os the encode certificate, set to NULL, 0 on case of
3334 * error. Free the os->data with hx509_xfree().
3335 *
3336 * @return An hx509 error code, see hx509_get_error_string().
3337 *
3338 * @ingroup hx509_cert
3339 */
3340
3341int
3342hx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os)
3343{
3344 size_t size;
3345 int ret;
3346
3347 os->data = NULL;
3348 os->length = 0;
3349
3350 ASN1_MALLOC_ENCODE(Certificate, os->data, os->length,
3351 _hx509_get_cert(c), &size, ret);
3352 if (ret) {
3353 os->data = NULL;
3354 os->length = 0;
3355 return ret;
3356 }
3357 if (os->length != size)
3358 _hx509_abort("internal ASN.1 encoder error");
3359
3360 return ret;
3361}
3362
3363/*
3364 * Last to avoid lost __attribute__s due to #undef.
3365 */
3366
3367#undef __attribute__
3368#define __attribute__(X)
3369
3370void
3371_hx509_abort(const char *fmt, ...)
3372 __attribute__ ((noreturn, format (printf, 1, 2)))
3373{
3374 va_list ap;
3375 va_start(ap, fmt);
3376 vprintf(fmt, ap);
3377 va_end(ap);
3378 printf("\n");
3379 fflush(stdout);
3380 abort();
3381}
3382
3383/**
3384 * Free a data element allocated in the library.
3385 *
3386 * @param ptr data to be freed.
3387 *
3388 * @ingroup hx509_misc
3389 */
3390
3391void
3392hx509_xfree(void *ptr)
3393{
3394 free(ptr);
3395}
3396
3397/**
3398 *
3399 */
3400
3401int
3402_hx509_cert_to_env(hx509_context context, hx509_cert cert, hx509_env *env)
3403{
3404 ExtKeyUsage eku;
3405 hx509_name name;
3406 char *buf;
3407 int ret;
3408 hx509_env envcert = NULL;
3409
3410 *env = NULL;
3411
3412 /* version */
3413 asprintf(&buf, "%d", _hx509_cert_get_version(_hx509_get_cert(cert)));
3414 ret = hx509_env_add(context, &envcert, "version", buf);
3415 free(buf);
3416 if (ret)
3417 goto out;
3418
3419 /* subject */
3420 ret = hx509_cert_get_subject(cert, &name);
3421 if (ret)
3422 goto out;
3423
3424 ret = hx509_name_to_string(name, &buf);
3425 if (ret) {
3426 hx509_name_free(&name);
3427 goto out;
3428 }
3429
3430 ret = hx509_env_add(context, &envcert, "subject", buf);
3431 hx509_name_free(&name);
3432 if (ret)
3433 goto out;
3434
3435 /* issuer */
3436 ret = hx509_cert_get_issuer(cert, &name);
3437 if (ret)
3438 goto out;
3439
3440 ret = hx509_name_to_string(name, &buf);
3441 hx509_name_free(&name);
3442 if (ret)
3443 goto out;
3444
3445 ret = hx509_env_add(context, &envcert, "issuer", buf);
3446 hx509_xfree(buf);
3447 if (ret)
3448 goto out;
3449
3450 /* eku */
3451
3452 ret = _hx509_cert_get_eku(context, cert, &eku);
3453 if (ret == HX509_EXTENSION_NOT_FOUND)
3454 ;
3455 else if (ret != 0)
3456 goto out;
3457 else {
3458 int i;
3459 hx509_env enveku = NULL;
3460
3461 for (i = 0; i < eku.len; i++) {
3462
3463 ret = der_print_heim_oid(&eku.val[i], '.', &buf);
3464 if (ret) {
3465 free_ExtKeyUsage(&eku);
3466 hx509_env_free(&enveku);
3467 goto out;
3468 }
3469 ret = hx509_env_add(context, &enveku, buf, "oid-name-here");
3470 free(buf);
3471 if (ret) {
3472 free_ExtKeyUsage(&eku);
3473 hx509_env_free(&enveku);
3474 goto out;
3475 }
3476 }
3477 free_ExtKeyUsage(&eku);
3478
3479 ret = hx509_env_add_binding(context, &envcert, "eku", enveku);
3480 if (ret) {
3481 hx509_env_free(&enveku);
3482 goto out;
3483 }
3484 }
3485
3486 {
3487 Certificate *c = _hx509_get_cert(cert);
3488 heim_octet_string os, sig;
3489 hx509_env envhash = NULL;
3490
3491 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
3492 os.length =
3493 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
3494
3495 ret = _hx509_create_signature(context,
3496 NULL,
3497 hx509_signature_sha1(),
3498 &os,
3499 NULL,
3500 &sig);
3501 if (ret != 0)
3502 goto out;
3503
3504 ret = hex_encode(sig.data, sig.length, &buf);
3505 der_free_octet_string(&sig);
3506 if (ret < 0) {
3507 ret = ENOMEM;
3508 hx509_set_error_string(context, 0, ret,
3509 "Out of memory");
3510 goto out;
3511 }
3512
3513 ret = hx509_env_add(context, &envhash, "sha1", buf);
3514 free(buf);
3515 if (ret)
3516 goto out;
3517
3518 ret = hx509_env_add_binding(context, &envcert, "hash", envhash);
3519 if (ret) {
3520 hx509_env_free(&envhash);
3521 goto out;
3522 }
3523 }
3524
3525 ret = hx509_env_add_binding(context, env, "certificate", envcert);
3526 if (ret)
3527 goto out;
3528
3529 return 0;
3530
3531out:
3532 hx509_env_free(&envcert);
3533 return ret;
3534}
3535
3536/**
3537 * Print a simple representation of a certificate
3538 *
3539 * @param context A hx509 context, can be NULL
3540 * @param cert certificate to print
3541 * @param out the stdio output stream, if NULL, stdout is used
3542 *
3543 * @return An hx509 error code
3544 *
3545 * @ingroup hx509_cert
3546 */
3547
3548int
3549hx509_print_cert(hx509_context context, hx509_cert cert, FILE *out)
3550{
3551 hx509_name name;
3552 char *str;
3553 int ret;
3554
3555 if (out == NULL)
3556 out = stderr;
3557
3558 ret = hx509_cert_get_issuer(cert, &name);
3559 if (ret)
3560 return ret;
3561 hx509_name_to_string(name, &str);
3562 hx509_name_free(&name);
3563 fprintf(out, " issuer: \"%s\"\n", str);
3564 free(str);
3565
3566 ret = hx509_cert_get_subject(cert, &name);
3567 if (ret)
3568 return ret;
3569 hx509_name_to_string(name, &str);
3570 hx509_name_free(&name);
3571 fprintf(out, " subject: \"%s\"\n", str);
3572 free(str);
3573
3574 {
3575 heim_integer serialNumber;
3576
3577 ret = hx509_cert_get_serialnumber(cert, &serialNumber);
3578 if (ret)
3579 return ret;
3580 ret = der_print_hex_heim_integer(&serialNumber, &str);
3581 if (ret)
3582 return ret;
3583 der_free_heim_integer(&serialNumber);
3584 fprintf(out, " serial: %s\n", str);
3585 free(str);
3586 }
3587
3588 printf(" keyusage: ");
3589 ret = hx509_cert_keyusage_print(context, cert, &str);
3590 if (ret == 0) {
3591 fprintf(out, "%s\n", str);
3592 free(str);
3593 } else
3594 fprintf(out, "no");
3595
3596 return 0;
3597}
Note: See TracBrowser for help on using the repository browser.