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