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