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