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