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