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