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