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