1178825Sdfr/* 2233294Sstas * Copyright (c) 2004 - 2007 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 5178825Sdfr * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 9178825Sdfr * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 12178825Sdfr * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 16178825Sdfr * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 20178825Sdfr * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 32178825Sdfr */ 33178825Sdfr 34178825Sdfr#include "hx_locl.h" 35178825Sdfr#include "crypto-headers.h" 36178825Sdfr#include <rtbl.h> 37178825Sdfr 38178825Sdfr/** 39178825Sdfr * @page page_cert The basic certificate 40178825Sdfr * 41178825Sdfr * The basic hx509 cerificate object in hx509 is hx509_cert. The 42178825Sdfr * hx509_cert object is representing one X509/PKIX certificate and 43178825Sdfr * associated attributes; like private key, friendly name, etc. 44178825Sdfr * 45178825Sdfr * A hx509_cert object is usully found via the keyset interfaces (@ref 46178825Sdfr * page_keyset), but its also possible to create a certificate 47178825Sdfr * directly from a parsed object with hx509_cert_init() and 48178825Sdfr * hx509_cert_init_data(). 49178825Sdfr * 50178825Sdfr * See the library functions here: @ref hx509_cert 51178825Sdfr */ 52178825Sdfr 53178825Sdfrstruct hx509_verify_ctx_data { 54178825Sdfr hx509_certs trust_anchors; 55178825Sdfr int flags; 56178825Sdfr#define HX509_VERIFY_CTX_F_TIME_SET 1 57178825Sdfr#define HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE 2 58178825Sdfr#define HX509_VERIFY_CTX_F_REQUIRE_RFC3280 4 59178825Sdfr#define HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS 8 60178825Sdfr#define HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS 16 61233294Sstas#define HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK 32 62178825Sdfr time_t time_now; 63178825Sdfr unsigned int max_depth; 64178825Sdfr#define HX509_VERIFY_MAX_DEPTH 30 65178825Sdfr hx509_revoke_ctx revoke_ctx; 66178825Sdfr}; 67178825Sdfr 68178825Sdfr#define REQUIRE_RFC3280(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_REQUIRE_RFC3280) 69178825Sdfr#define CHECK_TA(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS) 70178825Sdfr#define ALLOW_DEF_TA(ctx) (((ctx)->flags & HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS) == 0) 71178825Sdfr 72178825Sdfrstruct _hx509_cert_attrs { 73178825Sdfr size_t len; 74178825Sdfr hx509_cert_attribute *val; 75178825Sdfr}; 76178825Sdfr 77178825Sdfrstruct hx509_cert_data { 78178825Sdfr unsigned int ref; 79178825Sdfr char *friendlyname; 80178825Sdfr Certificate *data; 81178825Sdfr hx509_private_key private_key; 82178825Sdfr struct _hx509_cert_attrs attrs; 83178825Sdfr hx509_name basename; 84178825Sdfr _hx509_cert_release_func release; 85178825Sdfr void *ctx; 86178825Sdfr}; 87178825Sdfr 88178825Sdfrtypedef struct hx509_name_constraints { 89178825Sdfr NameConstraints *val; 90178825Sdfr size_t len; 91178825Sdfr} hx509_name_constraints; 92178825Sdfr 93178825Sdfr#define GeneralSubtrees_SET(g,var) \ 94178825Sdfr (g)->len = (var)->len, (g)->val = (var)->val; 95178825Sdfr 96178825Sdfr/** 97178825Sdfr * Creates a hx509 context that most functions in the library 98178825Sdfr * uses. The context is only allowed to be used by one thread at each 99178825Sdfr * moment. Free the context with hx509_context_free(). 100178825Sdfr * 101178825Sdfr * @param context Returns a pointer to new hx509 context. 102178825Sdfr * 103178825Sdfr * @return Returns an hx509 error code. 104178825Sdfr * 105178825Sdfr * @ingroup hx509 106178825Sdfr */ 107178825Sdfr 108178825Sdfrint 109178825Sdfrhx509_context_init(hx509_context *context) 110178825Sdfr{ 111178825Sdfr *context = calloc(1, sizeof(**context)); 112178825Sdfr if (*context == NULL) 113178825Sdfr return ENOMEM; 114178825Sdfr 115178825Sdfr _hx509_ks_null_register(*context); 116178825Sdfr _hx509_ks_mem_register(*context); 117178825Sdfr _hx509_ks_file_register(*context); 118178825Sdfr _hx509_ks_pkcs12_register(*context); 119178825Sdfr _hx509_ks_pkcs11_register(*context); 120178825Sdfr _hx509_ks_dir_register(*context); 121178825Sdfr _hx509_ks_keychain_register(*context); 122178825Sdfr 123178825Sdfr ENGINE_add_conf_module(); 124178825Sdfr OpenSSL_add_all_algorithms(); 125178825Sdfr 126178825Sdfr (*context)->ocsp_time_diff = HX509_DEFAULT_OCSP_TIME_DIFF; 127178825Sdfr 128178825Sdfr initialize_hx_error_table_r(&(*context)->et_list); 129178825Sdfr initialize_asn1_error_table_r(&(*context)->et_list); 130178825Sdfr 131178825Sdfr#ifdef HX509_DEFAULT_ANCHORS 132178825Sdfr (void)hx509_certs_init(*context, HX509_DEFAULT_ANCHORS, 0, 133178825Sdfr NULL, &(*context)->default_trust_anchors); 134178825Sdfr#endif 135178825Sdfr 136178825Sdfr return 0; 137178825Sdfr} 138178825Sdfr 139178825Sdfr/** 140178825Sdfr * Selects if the hx509_revoke_verify() function is going to require 141233294Sstas * the existans of a revokation method (OCSP, CRL) or not. Note that 142178825Sdfr * hx509_verify_path(), hx509_cms_verify_signed(), and other function 143178825Sdfr * call hx509_revoke_verify(). 144233294Sstas * 145178825Sdfr * @param context hx509 context to change the flag for. 146178825Sdfr * @param flag zero, revokation method required, non zero missing 147178825Sdfr * revokation method ok 148178825Sdfr * 149178825Sdfr * @ingroup hx509_verify 150178825Sdfr */ 151178825Sdfr 152178825Sdfrvoid 153178825Sdfrhx509_context_set_missing_revoke(hx509_context context, int flag) 154178825Sdfr{ 155178825Sdfr if (flag) 156178825Sdfr context->flags |= HX509_CTX_VERIFY_MISSING_OK; 157178825Sdfr else 158178825Sdfr context->flags &= ~HX509_CTX_VERIFY_MISSING_OK; 159178825Sdfr} 160178825Sdfr 161178825Sdfr/** 162178825Sdfr * Free the context allocated by hx509_context_init(). 163233294Sstas * 164178825Sdfr * @param context context to be freed. 165178825Sdfr * 166178825Sdfr * @ingroup hx509 167178825Sdfr */ 168178825Sdfr 169178825Sdfrvoid 170178825Sdfrhx509_context_free(hx509_context *context) 171178825Sdfr{ 172178825Sdfr hx509_clear_error_string(*context); 173178825Sdfr if ((*context)->ks_ops) { 174178825Sdfr free((*context)->ks_ops); 175178825Sdfr (*context)->ks_ops = NULL; 176178825Sdfr } 177178825Sdfr (*context)->ks_num_ops = 0; 178178825Sdfr free_error_table ((*context)->et_list); 179178825Sdfr if ((*context)->querystat) 180178825Sdfr free((*context)->querystat); 181178825Sdfr memset(*context, 0, sizeof(**context)); 182178825Sdfr free(*context); 183178825Sdfr *context = NULL; 184178825Sdfr} 185178825Sdfr 186178825Sdfr/* 187178825Sdfr * 188178825Sdfr */ 189178825Sdfr 190178825SdfrCertificate * 191178825Sdfr_hx509_get_cert(hx509_cert cert) 192178825Sdfr{ 193178825Sdfr return cert->data; 194178825Sdfr} 195178825Sdfr 196178825Sdfr/* 197178825Sdfr * 198178825Sdfr */ 199178825Sdfr 200178825Sdfrint 201178825Sdfr_hx509_cert_get_version(const Certificate *t) 202178825Sdfr{ 203178825Sdfr return t->tbsCertificate.version ? *t->tbsCertificate.version + 1 : 1; 204178825Sdfr} 205178825Sdfr 206178825Sdfr/** 207178825Sdfr * Allocate and init an hx509 certificate object from the decoded 208233294Sstas * certificate `c��. 209178825Sdfr * 210178825Sdfr * @param context A hx509 context. 211178825Sdfr * @param c 212178825Sdfr * @param cert 213178825Sdfr * 214178825Sdfr * @return Returns an hx509 error code. 215178825Sdfr * 216178825Sdfr * @ingroup hx509_cert 217178825Sdfr */ 218178825Sdfr 219178825Sdfrint 220178825Sdfrhx509_cert_init(hx509_context context, const Certificate *c, hx509_cert *cert) 221178825Sdfr{ 222178825Sdfr int ret; 223178825Sdfr 224178825Sdfr *cert = malloc(sizeof(**cert)); 225178825Sdfr if (*cert == NULL) 226178825Sdfr return ENOMEM; 227178825Sdfr (*cert)->ref = 1; 228178825Sdfr (*cert)->friendlyname = NULL; 229178825Sdfr (*cert)->attrs.len = 0; 230178825Sdfr (*cert)->attrs.val = NULL; 231178825Sdfr (*cert)->private_key = NULL; 232178825Sdfr (*cert)->basename = NULL; 233178825Sdfr (*cert)->release = NULL; 234178825Sdfr (*cert)->ctx = NULL; 235178825Sdfr 236178825Sdfr (*cert)->data = calloc(1, sizeof(*(*cert)->data)); 237178825Sdfr if ((*cert)->data == NULL) { 238178825Sdfr free(*cert); 239178825Sdfr return ENOMEM; 240178825Sdfr } 241178825Sdfr ret = copy_Certificate(c, (*cert)->data); 242178825Sdfr if (ret) { 243178825Sdfr free((*cert)->data); 244178825Sdfr free(*cert); 245178825Sdfr *cert = NULL; 246178825Sdfr } 247178825Sdfr return ret; 248178825Sdfr} 249178825Sdfr 250178825Sdfr/** 251178825Sdfr * Just like hx509_cert_init(), but instead of a decode certificate 252178825Sdfr * takes an pointer and length to a memory region that contains a 253178825Sdfr * DER/BER encoded certificate. 254178825Sdfr * 255178825Sdfr * If the memory region doesn't contain just the certificate and 256178825Sdfr * nothing more the function will fail with 257178825Sdfr * HX509_EXTRA_DATA_AFTER_STRUCTURE. 258178825Sdfr * 259178825Sdfr * @param context A hx509 context. 260178825Sdfr * @param ptr pointer to memory region containing encoded certificate. 261178825Sdfr * @param len length of memory region. 262178825Sdfr * @param cert a return pointer to a hx509 certificate object, will 263178825Sdfr * contain NULL on error. 264178825Sdfr * 265178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 266178825Sdfr * 267178825Sdfr * @ingroup hx509_cert 268178825Sdfr */ 269178825Sdfr 270178825Sdfrint 271233294Sstashx509_cert_init_data(hx509_context context, 272178825Sdfr const void *ptr, 273178825Sdfr size_t len, 274178825Sdfr hx509_cert *cert) 275178825Sdfr{ 276178825Sdfr Certificate t; 277178825Sdfr size_t size; 278178825Sdfr int ret; 279178825Sdfr 280178825Sdfr ret = decode_Certificate(ptr, len, &t, &size); 281178825Sdfr if (ret) { 282178825Sdfr hx509_set_error_string(context, 0, ret, "Failed to decode certificate"); 283178825Sdfr return ret; 284178825Sdfr } 285178825Sdfr if (size != len) { 286233294Sstas free_Certificate(&t); 287178825Sdfr hx509_set_error_string(context, 0, HX509_EXTRA_DATA_AFTER_STRUCTURE, 288178825Sdfr "Extra data after certificate"); 289178825Sdfr return HX509_EXTRA_DATA_AFTER_STRUCTURE; 290178825Sdfr } 291178825Sdfr 292178825Sdfr ret = hx509_cert_init(context, &t, cert); 293178825Sdfr free_Certificate(&t); 294178825Sdfr return ret; 295178825Sdfr} 296178825Sdfr 297178825Sdfrvoid 298233294Sstas_hx509_cert_set_release(hx509_cert cert, 299178825Sdfr _hx509_cert_release_func release, 300178825Sdfr void *ctx) 301178825Sdfr{ 302178825Sdfr cert->release = release; 303178825Sdfr cert->ctx = ctx; 304178825Sdfr} 305178825Sdfr 306178825Sdfr 307178825Sdfr/* Doesn't make a copy of `private_key'. */ 308178825Sdfr 309178825Sdfrint 310178825Sdfr_hx509_cert_assign_key(hx509_cert cert, hx509_private_key private_key) 311178825Sdfr{ 312178825Sdfr if (cert->private_key) 313233294Sstas hx509_private_key_free(&cert->private_key); 314178825Sdfr cert->private_key = _hx509_private_key_ref(private_key); 315178825Sdfr return 0; 316178825Sdfr} 317178825Sdfr 318178825Sdfr/** 319178825Sdfr * Free reference to the hx509 certificate object, if the refcounter 320178825Sdfr * reaches 0, the object if freed. Its allowed to pass in NULL. 321178825Sdfr * 322178825Sdfr * @param cert the cert to free. 323178825Sdfr * 324178825Sdfr * @ingroup hx509_cert 325178825Sdfr */ 326178825Sdfr 327178825Sdfrvoid 328178825Sdfrhx509_cert_free(hx509_cert cert) 329178825Sdfr{ 330233294Sstas size_t i; 331178825Sdfr 332178825Sdfr if (cert == NULL) 333178825Sdfr return; 334178825Sdfr 335178825Sdfr if (cert->ref <= 0) 336178825Sdfr _hx509_abort("cert refcount <= 0 on free"); 337178825Sdfr if (--cert->ref > 0) 338178825Sdfr return; 339178825Sdfr 340178825Sdfr if (cert->release) 341178825Sdfr (cert->release)(cert, cert->ctx); 342178825Sdfr 343178825Sdfr if (cert->private_key) 344233294Sstas hx509_private_key_free(&cert->private_key); 345178825Sdfr 346178825Sdfr free_Certificate(cert->data); 347178825Sdfr free(cert->data); 348178825Sdfr 349178825Sdfr for (i = 0; i < cert->attrs.len; i++) { 350178825Sdfr der_free_octet_string(&cert->attrs.val[i]->data); 351178825Sdfr der_free_oid(&cert->attrs.val[i]->oid); 352178825Sdfr free(cert->attrs.val[i]); 353178825Sdfr } 354178825Sdfr free(cert->attrs.val); 355178825Sdfr free(cert->friendlyname); 356178825Sdfr if (cert->basename) 357178825Sdfr hx509_name_free(&cert->basename); 358233294Sstas memset(cert, 0, sizeof(*cert)); 359178825Sdfr free(cert); 360178825Sdfr} 361178825Sdfr 362178825Sdfr/** 363178825Sdfr * Add a reference to a hx509 certificate object. 364178825Sdfr * 365178825Sdfr * @param cert a pointer to an hx509 certificate object. 366178825Sdfr * 367178825Sdfr * @return the same object as is passed in. 368178825Sdfr * 369178825Sdfr * @ingroup hx509_cert 370178825Sdfr */ 371178825Sdfr 372178825Sdfrhx509_cert 373178825Sdfrhx509_cert_ref(hx509_cert cert) 374178825Sdfr{ 375178825Sdfr if (cert == NULL) 376178825Sdfr return NULL; 377178825Sdfr if (cert->ref <= 0) 378178825Sdfr _hx509_abort("cert refcount <= 0"); 379178825Sdfr cert->ref++; 380178825Sdfr if (cert->ref == 0) 381178825Sdfr _hx509_abort("cert refcount == 0"); 382178825Sdfr return cert; 383178825Sdfr} 384178825Sdfr 385178825Sdfr/** 386178825Sdfr * Allocate an verification context that is used fo control the 387233294Sstas * verification process. 388178825Sdfr * 389178825Sdfr * @param context A hx509 context. 390178825Sdfr * @param ctx returns a pointer to a hx509_verify_ctx object. 391178825Sdfr * 392178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 393178825Sdfr * 394178825Sdfr * @ingroup hx509_verify 395178825Sdfr */ 396178825Sdfr 397178825Sdfrint 398178825Sdfrhx509_verify_init_ctx(hx509_context context, hx509_verify_ctx *ctx) 399178825Sdfr{ 400178825Sdfr hx509_verify_ctx c; 401178825Sdfr 402178825Sdfr c = calloc(1, sizeof(*c)); 403178825Sdfr if (c == NULL) 404178825Sdfr return ENOMEM; 405178825Sdfr 406178825Sdfr c->max_depth = HX509_VERIFY_MAX_DEPTH; 407178825Sdfr 408178825Sdfr *ctx = c; 409233294Sstas 410178825Sdfr return 0; 411178825Sdfr} 412178825Sdfr 413178825Sdfr/** 414178825Sdfr * Free an hx509 verification context. 415178825Sdfr * 416178825Sdfr * @param ctx the context to be freed. 417178825Sdfr * 418178825Sdfr * @ingroup hx509_verify 419178825Sdfr */ 420178825Sdfr 421178825Sdfrvoid 422178825Sdfrhx509_verify_destroy_ctx(hx509_verify_ctx ctx) 423178825Sdfr{ 424178825Sdfr if (ctx) { 425178825Sdfr hx509_certs_free(&ctx->trust_anchors); 426178825Sdfr hx509_revoke_free(&ctx->revoke_ctx); 427178825Sdfr memset(ctx, 0, sizeof(*ctx)); 428178825Sdfr } 429178825Sdfr free(ctx); 430178825Sdfr} 431178825Sdfr 432178825Sdfr/** 433178825Sdfr * Set the trust anchors in the verification context, makes an 434178825Sdfr * reference to the keyset, so the consumer can free the keyset 435178825Sdfr * independent of the destruction of the verification context (ctx). 436233294Sstas * If there already is a keyset attached, it's released. 437178825Sdfr * 438178825Sdfr * @param ctx a verification context 439178825Sdfr * @param set a keyset containing the trust anchors. 440178825Sdfr * 441178825Sdfr * @ingroup hx509_verify 442178825Sdfr */ 443178825Sdfr 444178825Sdfrvoid 445178825Sdfrhx509_verify_attach_anchors(hx509_verify_ctx ctx, hx509_certs set) 446178825Sdfr{ 447233294Sstas if (ctx->trust_anchors) 448233294Sstas hx509_certs_free(&ctx->trust_anchors); 449233294Sstas ctx->trust_anchors = hx509_certs_ref(set); 450178825Sdfr} 451178825Sdfr 452178825Sdfr/** 453178825Sdfr * Attach an revocation context to the verfication context, , makes an 454178825Sdfr * reference to the revoke context, so the consumer can free the 455178825Sdfr * revoke context independent of the destruction of the verification 456178825Sdfr * context. If there is no revoke context, the verification process is 457178825Sdfr * NOT going to check any verification status. 458178825Sdfr * 459178825Sdfr * @param ctx a verification context. 460178825Sdfr * @param revoke_ctx a revoke context. 461178825Sdfr * 462178825Sdfr * @ingroup hx509_verify 463178825Sdfr */ 464178825Sdfr 465178825Sdfrvoid 466178825Sdfrhx509_verify_attach_revoke(hx509_verify_ctx ctx, hx509_revoke_ctx revoke_ctx) 467178825Sdfr{ 468178825Sdfr if (ctx->revoke_ctx) 469178825Sdfr hx509_revoke_free(&ctx->revoke_ctx); 470178825Sdfr ctx->revoke_ctx = _hx509_revoke_ref(revoke_ctx); 471178825Sdfr} 472178825Sdfr 473178825Sdfr/** 474178825Sdfr * Set the clock time the the verification process is going to 475178825Sdfr * use. Used to check certificate in the past and future time. If not 476178825Sdfr * set the current time will be used. 477178825Sdfr * 478178825Sdfr * @param ctx a verification context. 479178825Sdfr * @param t the time the verifiation is using. 480178825Sdfr * 481178825Sdfr * 482178825Sdfr * @ingroup hx509_verify 483178825Sdfr */ 484178825Sdfr 485178825Sdfrvoid 486178825Sdfrhx509_verify_set_time(hx509_verify_ctx ctx, time_t t) 487178825Sdfr{ 488178825Sdfr ctx->flags |= HX509_VERIFY_CTX_F_TIME_SET; 489178825Sdfr ctx->time_now = t; 490178825Sdfr} 491178825Sdfr 492233294Sstastime_t 493233294Sstas_hx509_verify_get_time(hx509_verify_ctx ctx) 494233294Sstas{ 495233294Sstas return ctx->time_now; 496233294Sstas} 497233294Sstas 498178825Sdfr/** 499178825Sdfr * Set the maximum depth of the certificate chain that the path 500178825Sdfr * builder is going to try. 501178825Sdfr * 502178825Sdfr * @param ctx a verification context 503178825Sdfr * @param max_depth maxium depth of the certificate chain, include 504178825Sdfr * trust anchor. 505178825Sdfr * 506178825Sdfr * @ingroup hx509_verify 507178825Sdfr */ 508178825Sdfr 509178825Sdfrvoid 510178825Sdfrhx509_verify_set_max_depth(hx509_verify_ctx ctx, unsigned int max_depth) 511178825Sdfr{ 512178825Sdfr ctx->max_depth = max_depth; 513178825Sdfr} 514178825Sdfr 515178825Sdfr/** 516178825Sdfr * Allow or deny the use of proxy certificates 517178825Sdfr * 518178825Sdfr * @param ctx a verification context 519178825Sdfr * @param boolean if non zero, allow proxy certificates. 520178825Sdfr * 521178825Sdfr * @ingroup hx509_verify 522178825Sdfr */ 523178825Sdfr 524178825Sdfrvoid 525178825Sdfrhx509_verify_set_proxy_certificate(hx509_verify_ctx ctx, int boolean) 526178825Sdfr{ 527178825Sdfr if (boolean) 528178825Sdfr ctx->flags |= HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE; 529178825Sdfr else 530178825Sdfr ctx->flags &= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE; 531178825Sdfr} 532178825Sdfr 533178825Sdfr/** 534178825Sdfr * Select strict RFC3280 verification of certificiates. This means 535178825Sdfr * checking key usage on CA certificates, this will make version 1 536178825Sdfr * certificiates unuseable. 537178825Sdfr * 538178825Sdfr * @param ctx a verification context 539178825Sdfr * @param boolean if non zero, use strict verification. 540178825Sdfr * 541178825Sdfr * @ingroup hx509_verify 542178825Sdfr */ 543178825Sdfr 544178825Sdfrvoid 545178825Sdfrhx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx, int boolean) 546178825Sdfr{ 547178825Sdfr if (boolean) 548178825Sdfr ctx->flags |= HX509_VERIFY_CTX_F_REQUIRE_RFC3280; 549178825Sdfr else 550178825Sdfr ctx->flags &= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280; 551178825Sdfr} 552178825Sdfr 553178825Sdfr/** 554178825Sdfr * Allow using the operating system builtin trust anchors if no other 555178825Sdfr * trust anchors are configured. 556178825Sdfr * 557178825Sdfr * @param ctx a verification context 558178825Sdfr * @param boolean if non zero, useing the operating systems builtin 559178825Sdfr * trust anchors. 560178825Sdfr * 561178825Sdfr * 562178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 563178825Sdfr * 564178825Sdfr * @ingroup hx509_cert 565178825Sdfr */ 566178825Sdfr 567178825Sdfrvoid 568178825Sdfrhx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx, int boolean) 569178825Sdfr{ 570178825Sdfr if (boolean) 571178825Sdfr ctx->flags &= ~HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS; 572178825Sdfr else 573178825Sdfr ctx->flags |= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS; 574178825Sdfr} 575178825Sdfr 576233294Sstasvoid 577233294Sstashx509_verify_ctx_f_allow_best_before_signature_algs(hx509_context ctx, 578233294Sstas int boolean) 579233294Sstas{ 580233294Sstas if (boolean) 581233294Sstas ctx->flags &= ~HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK; 582233294Sstas else 583233294Sstas ctx->flags |= HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK; 584233294Sstas} 585233294Sstas 586178825Sdfrstatic const Extension * 587233294Sstasfind_extension(const Certificate *cert, const heim_oid *oid, size_t *idx) 588178825Sdfr{ 589178825Sdfr const TBSCertificate *c = &cert->tbsCertificate; 590178825Sdfr 591178825Sdfr if (c->version == NULL || *c->version < 2 || c->extensions == NULL) 592178825Sdfr return NULL; 593233294Sstas 594178825Sdfr for (;*idx < c->extensions->len; (*idx)++) { 595178825Sdfr if (der_heim_oid_cmp(&c->extensions->val[*idx].extnID, oid) == 0) 596178825Sdfr return &c->extensions->val[(*idx)++]; 597178825Sdfr } 598178825Sdfr return NULL; 599178825Sdfr} 600178825Sdfr 601178825Sdfrstatic int 602233294Sstasfind_extension_auth_key_id(const Certificate *subject, 603178825Sdfr AuthorityKeyIdentifier *ai) 604178825Sdfr{ 605178825Sdfr const Extension *e; 606178825Sdfr size_t size; 607233294Sstas size_t i = 0; 608178825Sdfr 609178825Sdfr memset(ai, 0, sizeof(*ai)); 610178825Sdfr 611233294Sstas e = find_extension(subject, &asn1_oid_id_x509_ce_authorityKeyIdentifier, &i); 612178825Sdfr if (e == NULL) 613178825Sdfr return HX509_EXTENSION_NOT_FOUND; 614233294Sstas 615233294Sstas return decode_AuthorityKeyIdentifier(e->extnValue.data, 616233294Sstas e->extnValue.length, 617178825Sdfr ai, &size); 618178825Sdfr} 619178825Sdfr 620178825Sdfrint 621178825Sdfr_hx509_find_extension_subject_key_id(const Certificate *issuer, 622178825Sdfr SubjectKeyIdentifier *si) 623178825Sdfr{ 624178825Sdfr const Extension *e; 625178825Sdfr size_t size; 626233294Sstas size_t i = 0; 627178825Sdfr 628178825Sdfr memset(si, 0, sizeof(*si)); 629178825Sdfr 630233294Sstas e = find_extension(issuer, &asn1_oid_id_x509_ce_subjectKeyIdentifier, &i); 631178825Sdfr if (e == NULL) 632178825Sdfr return HX509_EXTENSION_NOT_FOUND; 633233294Sstas 634233294Sstas return decode_SubjectKeyIdentifier(e->extnValue.data, 635178825Sdfr e->extnValue.length, 636178825Sdfr si, &size); 637178825Sdfr} 638178825Sdfr 639178825Sdfrstatic int 640233294Sstasfind_extension_name_constraints(const Certificate *subject, 641178825Sdfr NameConstraints *nc) 642178825Sdfr{ 643178825Sdfr const Extension *e; 644178825Sdfr size_t size; 645233294Sstas size_t i = 0; 646178825Sdfr 647178825Sdfr memset(nc, 0, sizeof(*nc)); 648178825Sdfr 649233294Sstas e = find_extension(subject, &asn1_oid_id_x509_ce_nameConstraints, &i); 650178825Sdfr if (e == NULL) 651178825Sdfr return HX509_EXTENSION_NOT_FOUND; 652233294Sstas 653233294Sstas return decode_NameConstraints(e->extnValue.data, 654233294Sstas e->extnValue.length, 655178825Sdfr nc, &size); 656178825Sdfr} 657178825Sdfr 658178825Sdfrstatic int 659233294Sstasfind_extension_subject_alt_name(const Certificate *cert, size_t *i, 660178825Sdfr GeneralNames *sa) 661178825Sdfr{ 662178825Sdfr const Extension *e; 663178825Sdfr size_t size; 664178825Sdfr 665178825Sdfr memset(sa, 0, sizeof(*sa)); 666178825Sdfr 667233294Sstas e = find_extension(cert, &asn1_oid_id_x509_ce_subjectAltName, i); 668178825Sdfr if (e == NULL) 669178825Sdfr return HX509_EXTENSION_NOT_FOUND; 670233294Sstas 671233294Sstas return decode_GeneralNames(e->extnValue.data, 672178825Sdfr e->extnValue.length, 673178825Sdfr sa, &size); 674178825Sdfr} 675178825Sdfr 676178825Sdfrstatic int 677178825Sdfrfind_extension_eku(const Certificate *cert, ExtKeyUsage *eku) 678178825Sdfr{ 679178825Sdfr const Extension *e; 680178825Sdfr size_t size; 681233294Sstas size_t i = 0; 682178825Sdfr 683178825Sdfr memset(eku, 0, sizeof(*eku)); 684178825Sdfr 685233294Sstas e = find_extension(cert, &asn1_oid_id_x509_ce_extKeyUsage, &i); 686178825Sdfr if (e == NULL) 687178825Sdfr return HX509_EXTENSION_NOT_FOUND; 688233294Sstas 689233294Sstas return decode_ExtKeyUsage(e->extnValue.data, 690178825Sdfr e->extnValue.length, 691178825Sdfr eku, &size); 692178825Sdfr} 693178825Sdfr 694178825Sdfrstatic int 695178825Sdfradd_to_list(hx509_octet_string_list *list, const heim_octet_string *entry) 696178825Sdfr{ 697178825Sdfr void *p; 698178825Sdfr int ret; 699178825Sdfr 700178825Sdfr p = realloc(list->val, (list->len + 1) * sizeof(list->val[0])); 701178825Sdfr if (p == NULL) 702178825Sdfr return ENOMEM; 703178825Sdfr list->val = p; 704178825Sdfr ret = der_copy_octet_string(entry, &list->val[list->len]); 705178825Sdfr if (ret) 706178825Sdfr return ret; 707178825Sdfr list->len++; 708178825Sdfr return 0; 709178825Sdfr} 710178825Sdfr 711178825Sdfr/** 712178825Sdfr * Free a list of octet strings returned by another hx509 library 713178825Sdfr * function. 714178825Sdfr * 715178825Sdfr * @param list list to be freed. 716178825Sdfr * 717178825Sdfr * @ingroup hx509_misc 718178825Sdfr */ 719178825Sdfr 720178825Sdfrvoid 721178825Sdfrhx509_free_octet_string_list(hx509_octet_string_list *list) 722178825Sdfr{ 723233294Sstas size_t i; 724178825Sdfr for (i = 0; i < list->len; i++) 725178825Sdfr der_free_octet_string(&list->val[i]); 726178825Sdfr free(list->val); 727178825Sdfr list->val = NULL; 728178825Sdfr list->len = 0; 729178825Sdfr} 730178825Sdfr 731178825Sdfr/** 732178825Sdfr * Return a list of subjectAltNames specified by oid in the 733233294Sstas * certificate. On error the 734178825Sdfr * 735178825Sdfr * The returned list of octet string should be freed with 736178825Sdfr * hx509_free_octet_string_list(). 737178825Sdfr * 738178825Sdfr * @param context A hx509 context. 739178825Sdfr * @param cert a hx509 certificate object. 740178825Sdfr * @param oid an oid to for SubjectAltName. 741178825Sdfr * @param list list of matching SubjectAltName. 742178825Sdfr * 743178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 744178825Sdfr * 745178825Sdfr * @ingroup hx509_cert 746178825Sdfr */ 747178825Sdfr 748178825Sdfrint 749178825Sdfrhx509_cert_find_subjectAltName_otherName(hx509_context context, 750178825Sdfr hx509_cert cert, 751178825Sdfr const heim_oid *oid, 752178825Sdfr hx509_octet_string_list *list) 753178825Sdfr{ 754178825Sdfr GeneralNames sa; 755233294Sstas int ret; 756233294Sstas size_t i, j; 757178825Sdfr 758178825Sdfr list->val = NULL; 759178825Sdfr list->len = 0; 760178825Sdfr 761178825Sdfr i = 0; 762178825Sdfr while (1) { 763178825Sdfr ret = find_extension_subject_alt_name(_hx509_get_cert(cert), &i, &sa); 764178825Sdfr i++; 765178825Sdfr if (ret == HX509_EXTENSION_NOT_FOUND) { 766233294Sstas return 0; 767178825Sdfr } else if (ret != 0) { 768178825Sdfr hx509_set_error_string(context, 0, ret, "Error searching for SAN"); 769178825Sdfr hx509_free_octet_string_list(list); 770178825Sdfr return ret; 771178825Sdfr } 772178825Sdfr 773178825Sdfr for (j = 0; j < sa.len; j++) { 774178825Sdfr if (sa.val[j].element == choice_GeneralName_otherName && 775233294Sstas der_heim_oid_cmp(&sa.val[j].u.otherName.type_id, oid) == 0) 776178825Sdfr { 777178825Sdfr ret = add_to_list(list, &sa.val[j].u.otherName.value); 778178825Sdfr if (ret) { 779233294Sstas hx509_set_error_string(context, 0, ret, 780178825Sdfr "Error adding an exra SAN to " 781178825Sdfr "return list"); 782178825Sdfr hx509_free_octet_string_list(list); 783178825Sdfr free_GeneralNames(&sa); 784178825Sdfr return ret; 785178825Sdfr } 786178825Sdfr } 787178825Sdfr } 788178825Sdfr free_GeneralNames(&sa); 789178825Sdfr } 790178825Sdfr} 791178825Sdfr 792178825Sdfr 793178825Sdfrstatic int 794233294Sstascheck_key_usage(hx509_context context, const Certificate *cert, 795178825Sdfr unsigned flags, int req_present) 796178825Sdfr{ 797178825Sdfr const Extension *e; 798178825Sdfr KeyUsage ku; 799178825Sdfr size_t size; 800233294Sstas int ret; 801233294Sstas size_t i = 0; 802178825Sdfr unsigned ku_flags; 803178825Sdfr 804178825Sdfr if (_hx509_cert_get_version(cert) < 3) 805178825Sdfr return 0; 806178825Sdfr 807233294Sstas e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i); 808178825Sdfr if (e == NULL) { 809178825Sdfr if (req_present) { 810178825Sdfr hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING, 811178825Sdfr "Required extension key " 812178825Sdfr "usage missing from certifiate"); 813178825Sdfr return HX509_KU_CERT_MISSING; 814178825Sdfr } 815178825Sdfr return 0; 816178825Sdfr } 817233294Sstas 818178825Sdfr ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, &ku, &size); 819178825Sdfr if (ret) 820178825Sdfr return ret; 821178825Sdfr ku_flags = KeyUsage2int(ku); 822178825Sdfr if ((ku_flags & flags) != flags) { 823178825Sdfr unsigned missing = (~ku_flags) & flags; 824178825Sdfr char buf[256], *name; 825178825Sdfr 826178825Sdfr unparse_flags(missing, asn1_KeyUsage_units(), buf, sizeof(buf)); 827178825Sdfr _hx509_unparse_Name(&cert->tbsCertificate.subject, &name); 828178825Sdfr hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING, 829178825Sdfr "Key usage %s required but missing " 830178825Sdfr "from certifiate %s", buf, name); 831178825Sdfr free(name); 832178825Sdfr return HX509_KU_CERT_MISSING; 833178825Sdfr } 834178825Sdfr return 0; 835178825Sdfr} 836178825Sdfr 837178825Sdfr/* 838178825Sdfr * Return 0 on matching key usage 'flags' for 'cert', otherwise return 839178825Sdfr * an error code. If 'req_present' the existance is required of the 840178825Sdfr * KeyUsage extension. 841178825Sdfr */ 842178825Sdfr 843178825Sdfrint 844233294Sstas_hx509_check_key_usage(hx509_context context, hx509_cert cert, 845178825Sdfr unsigned flags, int req_present) 846178825Sdfr{ 847178825Sdfr return check_key_usage(context, _hx509_get_cert(cert), flags, req_present); 848178825Sdfr} 849178825Sdfr 850178825Sdfrenum certtype { PROXY_CERT, EE_CERT, CA_CERT }; 851178825Sdfr 852178825Sdfrstatic int 853233294Sstascheck_basic_constraints(hx509_context context, const Certificate *cert, 854233294Sstas enum certtype type, size_t depth) 855178825Sdfr{ 856178825Sdfr BasicConstraints bc; 857178825Sdfr const Extension *e; 858178825Sdfr size_t size; 859233294Sstas int ret; 860233294Sstas size_t i = 0; 861178825Sdfr 862178825Sdfr if (_hx509_cert_get_version(cert) < 3) 863178825Sdfr return 0; 864178825Sdfr 865233294Sstas e = find_extension(cert, &asn1_oid_id_x509_ce_basicConstraints, &i); 866178825Sdfr if (e == NULL) { 867178825Sdfr switch(type) { 868178825Sdfr case PROXY_CERT: 869178825Sdfr case EE_CERT: 870178825Sdfr return 0; 871178825Sdfr case CA_CERT: { 872178825Sdfr char *name; 873178825Sdfr ret = _hx509_unparse_Name(&cert->tbsCertificate.subject, &name); 874178825Sdfr assert(ret == 0); 875178825Sdfr hx509_set_error_string(context, 0, HX509_EXTENSION_NOT_FOUND, 876178825Sdfr "basicConstraints missing from " 877178825Sdfr "CA certifiacte %s", name); 878178825Sdfr free(name); 879178825Sdfr return HX509_EXTENSION_NOT_FOUND; 880178825Sdfr } 881178825Sdfr } 882178825Sdfr } 883233294Sstas 884233294Sstas ret = decode_BasicConstraints(e->extnValue.data, 885178825Sdfr e->extnValue.length, &bc, 886178825Sdfr &size); 887178825Sdfr if (ret) 888178825Sdfr return ret; 889178825Sdfr switch(type) { 890178825Sdfr case PROXY_CERT: 891178825Sdfr if (bc.cA != NULL && *bc.cA) 892178825Sdfr ret = HX509_PARENT_IS_CA; 893178825Sdfr break; 894178825Sdfr case EE_CERT: 895178825Sdfr ret = 0; 896178825Sdfr break; 897178825Sdfr case CA_CERT: 898178825Sdfr if (bc.cA == NULL || !*bc.cA) 899178825Sdfr ret = HX509_PARENT_NOT_CA; 900178825Sdfr else if (bc.pathLenConstraint) 901178825Sdfr if (depth - 1 > *bc.pathLenConstraint) 902178825Sdfr ret = HX509_CA_PATH_TOO_DEEP; 903178825Sdfr break; 904178825Sdfr } 905178825Sdfr free_BasicConstraints(&bc); 906178825Sdfr return ret; 907178825Sdfr} 908178825Sdfr 909178825Sdfrint 910178825Sdfr_hx509_cert_is_parent_cmp(const Certificate *subject, 911178825Sdfr const Certificate *issuer, 912178825Sdfr int allow_self_signed) 913178825Sdfr{ 914178825Sdfr int diff; 915178825Sdfr AuthorityKeyIdentifier ai; 916178825Sdfr SubjectKeyIdentifier si; 917233294Sstas int ret_ai, ret_si, ret; 918178825Sdfr 919233294Sstas ret = _hx509_name_cmp(&issuer->tbsCertificate.subject, 920233294Sstas &subject->tbsCertificate.issuer, 921233294Sstas &diff); 922233294Sstas if (ret) 923233294Sstas return ret; 924178825Sdfr if (diff) 925178825Sdfr return diff; 926233294Sstas 927178825Sdfr memset(&ai, 0, sizeof(ai)); 928178825Sdfr memset(&si, 0, sizeof(si)); 929178825Sdfr 930178825Sdfr /* 931178825Sdfr * Try to find AuthorityKeyIdentifier, if it's not present in the 932178825Sdfr * subject certificate nor the parent. 933178825Sdfr */ 934178825Sdfr 935178825Sdfr ret_ai = find_extension_auth_key_id(subject, &ai); 936178825Sdfr if (ret_ai && ret_ai != HX509_EXTENSION_NOT_FOUND) 937178825Sdfr return 1; 938178825Sdfr ret_si = _hx509_find_extension_subject_key_id(issuer, &si); 939178825Sdfr if (ret_si && ret_si != HX509_EXTENSION_NOT_FOUND) 940178825Sdfr return -1; 941178825Sdfr 942178825Sdfr if (ret_si && ret_ai) 943178825Sdfr goto out; 944178825Sdfr if (ret_ai) 945178825Sdfr goto out; 946178825Sdfr if (ret_si) { 947178825Sdfr if (allow_self_signed) { 948178825Sdfr diff = 0; 949178825Sdfr goto out; 950178825Sdfr } else if (ai.keyIdentifier) { 951178825Sdfr diff = -1; 952178825Sdfr goto out; 953178825Sdfr } 954178825Sdfr } 955233294Sstas 956178825Sdfr if (ai.keyIdentifier == NULL) { 957178825Sdfr Name name; 958178825Sdfr 959178825Sdfr if (ai.authorityCertIssuer == NULL) 960178825Sdfr return -1; 961178825Sdfr if (ai.authorityCertSerialNumber == NULL) 962178825Sdfr return -1; 963178825Sdfr 964233294Sstas diff = der_heim_integer_cmp(ai.authorityCertSerialNumber, 965178825Sdfr &issuer->tbsCertificate.serialNumber); 966178825Sdfr if (diff) 967178825Sdfr return diff; 968178825Sdfr if (ai.authorityCertIssuer->len != 1) 969178825Sdfr return -1; 970178825Sdfr if (ai.authorityCertIssuer->val[0].element != choice_GeneralName_directoryName) 971178825Sdfr return -1; 972233294Sstas 973233294Sstas name.element = 974178825Sdfr ai.authorityCertIssuer->val[0].u.directoryName.element; 975233294Sstas name.u.rdnSequence = 976178825Sdfr ai.authorityCertIssuer->val[0].u.directoryName.u.rdnSequence; 977178825Sdfr 978233294Sstas ret = _hx509_name_cmp(&issuer->tbsCertificate.subject, 979233294Sstas &name, 980233294Sstas &diff); 981233294Sstas if (ret) 982233294Sstas return ret; 983178825Sdfr if (diff) 984178825Sdfr return diff; 985178825Sdfr diff = 0; 986178825Sdfr } else 987178825Sdfr diff = der_heim_octet_string_cmp(ai.keyIdentifier, &si); 988178825Sdfr if (diff) 989178825Sdfr goto out; 990178825Sdfr 991178825Sdfr out: 992178825Sdfr free_AuthorityKeyIdentifier(&ai); 993178825Sdfr free_SubjectKeyIdentifier(&si); 994178825Sdfr return diff; 995178825Sdfr} 996178825Sdfr 997178825Sdfrstatic int 998178825Sdfrcertificate_is_anchor(hx509_context context, 999178825Sdfr hx509_certs trust_anchors, 1000178825Sdfr const hx509_cert cert) 1001178825Sdfr{ 1002178825Sdfr hx509_query q; 1003178825Sdfr hx509_cert c; 1004178825Sdfr int ret; 1005178825Sdfr 1006178825Sdfr if (trust_anchors == NULL) 1007178825Sdfr return 0; 1008178825Sdfr 1009178825Sdfr _hx509_query_clear(&q); 1010178825Sdfr 1011178825Sdfr q.match = HX509_QUERY_MATCH_CERTIFICATE; 1012178825Sdfr q.certificate = _hx509_get_cert(cert); 1013178825Sdfr 1014178825Sdfr ret = hx509_certs_find(context, trust_anchors, &q, &c); 1015178825Sdfr if (ret == 0) 1016178825Sdfr hx509_cert_free(c); 1017178825Sdfr return ret == 0; 1018178825Sdfr} 1019178825Sdfr 1020178825Sdfrstatic int 1021233294Sstascertificate_is_self_signed(hx509_context context, 1022233294Sstas const Certificate *cert, 1023233294Sstas int *self_signed) 1024178825Sdfr{ 1025233294Sstas int ret, diff; 1026233294Sstas ret = _hx509_name_cmp(&cert->tbsCertificate.subject, 1027233294Sstas &cert->tbsCertificate.issuer, &diff); 1028233294Sstas *self_signed = (diff == 0); 1029233294Sstas if (ret) { 1030233294Sstas hx509_set_error_string(context, 0, ret, 1031233294Sstas "Failed to check if self signed"); 1032233294Sstas } else 1033233294Sstas ret = _hx509_self_signed_valid(context, &cert->signatureAlgorithm); 1034233294Sstas 1035233294Sstas return ret; 1036178825Sdfr} 1037178825Sdfr 1038178825Sdfr/* 1039178825Sdfr * The subjectName is "null" when it's empty set of relative DBs. 1040178825Sdfr */ 1041178825Sdfr 1042178825Sdfrstatic int 1043178825Sdfrsubject_null_p(const Certificate *c) 1044178825Sdfr{ 1045178825Sdfr return c->tbsCertificate.subject.u.rdnSequence.len == 0; 1046178825Sdfr} 1047178825Sdfr 1048178825Sdfr 1049178825Sdfrstatic int 1050178825Sdfrfind_parent(hx509_context context, 1051178825Sdfr time_t time_now, 1052178825Sdfr hx509_certs trust_anchors, 1053178825Sdfr hx509_path *path, 1054233294Sstas hx509_certs pool, 1055178825Sdfr hx509_cert current, 1056178825Sdfr hx509_cert *parent) 1057178825Sdfr{ 1058178825Sdfr AuthorityKeyIdentifier ai; 1059178825Sdfr hx509_query q; 1060178825Sdfr int ret; 1061178825Sdfr 1062178825Sdfr *parent = NULL; 1063178825Sdfr memset(&ai, 0, sizeof(ai)); 1064233294Sstas 1065178825Sdfr _hx509_query_clear(&q); 1066178825Sdfr 1067178825Sdfr if (!subject_null_p(current->data)) { 1068178825Sdfr q.match |= HX509_QUERY_FIND_ISSUER_CERT; 1069178825Sdfr q.subject = _hx509_get_cert(current); 1070178825Sdfr } else { 1071178825Sdfr ret = find_extension_auth_key_id(current->data, &ai); 1072178825Sdfr if (ret) { 1073178825Sdfr hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED, 1074178825Sdfr "Subjectless certificate missing AuthKeyID"); 1075178825Sdfr return HX509_CERTIFICATE_MALFORMED; 1076178825Sdfr } 1077178825Sdfr 1078178825Sdfr if (ai.keyIdentifier == NULL) { 1079178825Sdfr free_AuthorityKeyIdentifier(&ai); 1080178825Sdfr hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED, 1081178825Sdfr "Subjectless certificate missing keyIdentifier " 1082178825Sdfr "inside AuthKeyID"); 1083178825Sdfr return HX509_CERTIFICATE_MALFORMED; 1084178825Sdfr } 1085178825Sdfr 1086178825Sdfr q.subject_id = ai.keyIdentifier; 1087178825Sdfr q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID; 1088178825Sdfr } 1089178825Sdfr 1090178825Sdfr q.path = path; 1091178825Sdfr q.match |= HX509_QUERY_NO_MATCH_PATH; 1092178825Sdfr 1093178825Sdfr if (pool) { 1094178825Sdfr q.timenow = time_now; 1095178825Sdfr q.match |= HX509_QUERY_MATCH_TIME; 1096178825Sdfr 1097178825Sdfr ret = hx509_certs_find(context, pool, &q, parent); 1098178825Sdfr if (ret == 0) { 1099178825Sdfr free_AuthorityKeyIdentifier(&ai); 1100178825Sdfr return 0; 1101178825Sdfr } 1102178825Sdfr q.match &= ~HX509_QUERY_MATCH_TIME; 1103178825Sdfr } 1104178825Sdfr 1105178825Sdfr if (trust_anchors) { 1106178825Sdfr ret = hx509_certs_find(context, trust_anchors, &q, parent); 1107178825Sdfr if (ret == 0) { 1108178825Sdfr free_AuthorityKeyIdentifier(&ai); 1109178825Sdfr return ret; 1110178825Sdfr } 1111178825Sdfr } 1112178825Sdfr free_AuthorityKeyIdentifier(&ai); 1113178825Sdfr 1114178825Sdfr { 1115178825Sdfr hx509_name name; 1116178825Sdfr char *str; 1117178825Sdfr 1118178825Sdfr ret = hx509_cert_get_subject(current, &name); 1119178825Sdfr if (ret) { 1120178825Sdfr hx509_clear_error_string(context); 1121178825Sdfr return HX509_ISSUER_NOT_FOUND; 1122178825Sdfr } 1123178825Sdfr ret = hx509_name_to_string(name, &str); 1124178825Sdfr hx509_name_free(&name); 1125178825Sdfr if (ret) { 1126178825Sdfr hx509_clear_error_string(context); 1127178825Sdfr return HX509_ISSUER_NOT_FOUND; 1128178825Sdfr } 1129233294Sstas 1130178825Sdfr hx509_set_error_string(context, 0, HX509_ISSUER_NOT_FOUND, 1131178825Sdfr "Failed to find issuer for " 1132178825Sdfr "certificate with subject: '%s'", str); 1133178825Sdfr free(str); 1134178825Sdfr } 1135178825Sdfr return HX509_ISSUER_NOT_FOUND; 1136178825Sdfr} 1137178825Sdfr 1138178825Sdfr/* 1139178825Sdfr * 1140178825Sdfr */ 1141178825Sdfr 1142178825Sdfrstatic int 1143233294Sstasis_proxy_cert(hx509_context context, 1144233294Sstas const Certificate *cert, 1145178825Sdfr ProxyCertInfo *rinfo) 1146178825Sdfr{ 1147178825Sdfr ProxyCertInfo info; 1148178825Sdfr const Extension *e; 1149178825Sdfr size_t size; 1150233294Sstas int ret; 1151233294Sstas size_t i = 0; 1152178825Sdfr 1153178825Sdfr if (rinfo) 1154178825Sdfr memset(rinfo, 0, sizeof(*rinfo)); 1155178825Sdfr 1156233294Sstas e = find_extension(cert, &asn1_oid_id_pkix_pe_proxyCertInfo, &i); 1157178825Sdfr if (e == NULL) { 1158178825Sdfr hx509_clear_error_string(context); 1159178825Sdfr return HX509_EXTENSION_NOT_FOUND; 1160178825Sdfr } 1161178825Sdfr 1162233294Sstas ret = decode_ProxyCertInfo(e->extnValue.data, 1163233294Sstas e->extnValue.length, 1164178825Sdfr &info, 1165178825Sdfr &size); 1166178825Sdfr if (ret) { 1167178825Sdfr hx509_clear_error_string(context); 1168178825Sdfr return ret; 1169178825Sdfr } 1170178825Sdfr if (size != e->extnValue.length) { 1171178825Sdfr free_ProxyCertInfo(&info); 1172178825Sdfr hx509_clear_error_string(context); 1173233294Sstas return HX509_EXTRA_DATA_AFTER_STRUCTURE; 1174178825Sdfr } 1175178825Sdfr if (rinfo == NULL) 1176178825Sdfr free_ProxyCertInfo(&info); 1177178825Sdfr else 1178178825Sdfr *rinfo = info; 1179178825Sdfr 1180178825Sdfr return 0; 1181178825Sdfr} 1182178825Sdfr 1183178825Sdfr/* 1184178825Sdfr * Path operations are like MEMORY based keyset, but with exposed 1185178825Sdfr * internal so we can do easy searches. 1186178825Sdfr */ 1187178825Sdfr 1188178825Sdfrint 1189178825Sdfr_hx509_path_append(hx509_context context, hx509_path *path, hx509_cert cert) 1190178825Sdfr{ 1191178825Sdfr hx509_cert *val; 1192178825Sdfr val = realloc(path->val, (path->len + 1) * sizeof(path->val[0])); 1193178825Sdfr if (val == NULL) { 1194178825Sdfr hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 1195178825Sdfr return ENOMEM; 1196178825Sdfr } 1197178825Sdfr 1198178825Sdfr path->val = val; 1199178825Sdfr path->val[path->len] = hx509_cert_ref(cert); 1200178825Sdfr path->len++; 1201178825Sdfr 1202178825Sdfr return 0; 1203178825Sdfr} 1204178825Sdfr 1205178825Sdfrvoid 1206178825Sdfr_hx509_path_free(hx509_path *path) 1207178825Sdfr{ 1208178825Sdfr unsigned i; 1209233294Sstas 1210178825Sdfr for (i = 0; i < path->len; i++) 1211178825Sdfr hx509_cert_free(path->val[i]); 1212178825Sdfr free(path->val); 1213178825Sdfr path->val = NULL; 1214178825Sdfr path->len = 0; 1215178825Sdfr} 1216178825Sdfr 1217178825Sdfr/* 1218178825Sdfr * Find path by looking up issuer for the top certificate and continue 1219178825Sdfr * until an anchor certificate is found or max limit is found. A 1220178825Sdfr * certificate never included twice in the path. 1221178825Sdfr * 1222178825Sdfr * If the trust anchors are not given, calculate optimistic path, just 1223178825Sdfr * follow the chain upward until we no longer find a parent or we hit 1224178825Sdfr * the max path limit. In this case, a failure will always be returned 1225178825Sdfr * depending on what error condition is hit first. 1226178825Sdfr * 1227178825Sdfr * The path includes a path from the top certificate to the anchor 1228178825Sdfr * certificate. 1229178825Sdfr * 1230233294Sstas * The caller needs to free `path�� both on successful built path and 1231178825Sdfr * failure. 1232178825Sdfr */ 1233178825Sdfr 1234178825Sdfrint 1235178825Sdfr_hx509_calculate_path(hx509_context context, 1236178825Sdfr int flags, 1237178825Sdfr time_t time_now, 1238178825Sdfr hx509_certs anchors, 1239178825Sdfr unsigned int max_depth, 1240178825Sdfr hx509_cert cert, 1241178825Sdfr hx509_certs pool, 1242178825Sdfr hx509_path *path) 1243178825Sdfr{ 1244178825Sdfr hx509_cert parent, current; 1245178825Sdfr int ret; 1246178825Sdfr 1247178825Sdfr if (max_depth == 0) 1248178825Sdfr max_depth = HX509_VERIFY_MAX_DEPTH; 1249178825Sdfr 1250178825Sdfr ret = _hx509_path_append(context, path, cert); 1251178825Sdfr if (ret) 1252178825Sdfr return ret; 1253178825Sdfr 1254178825Sdfr current = hx509_cert_ref(cert); 1255178825Sdfr 1256178825Sdfr while (!certificate_is_anchor(context, anchors, current)) { 1257178825Sdfr 1258233294Sstas ret = find_parent(context, time_now, anchors, path, 1259178825Sdfr pool, current, &parent); 1260178825Sdfr hx509_cert_free(current); 1261178825Sdfr if (ret) 1262178825Sdfr return ret; 1263178825Sdfr 1264178825Sdfr ret = _hx509_path_append(context, path, parent); 1265178825Sdfr if (ret) 1266178825Sdfr return ret; 1267178825Sdfr current = parent; 1268178825Sdfr 1269178825Sdfr if (path->len > max_depth) { 1270178825Sdfr hx509_cert_free(current); 1271178825Sdfr hx509_set_error_string(context, 0, HX509_PATH_TOO_LONG, 1272178825Sdfr "Path too long while bulding " 1273178825Sdfr "certificate chain"); 1274178825Sdfr return HX509_PATH_TOO_LONG; 1275178825Sdfr } 1276178825Sdfr } 1277178825Sdfr 1278233294Sstas if ((flags & HX509_CALCULATE_PATH_NO_ANCHOR) && 1279233294Sstas path->len > 0 && 1280178825Sdfr certificate_is_anchor(context, anchors, path->val[path->len - 1])) 1281178825Sdfr { 1282178825Sdfr hx509_cert_free(path->val[path->len - 1]); 1283178825Sdfr path->len--; 1284178825Sdfr } 1285178825Sdfr 1286178825Sdfr hx509_cert_free(current); 1287178825Sdfr return 0; 1288178825Sdfr} 1289178825Sdfr 1290178825Sdfrint 1291178825Sdfr_hx509_AlgorithmIdentifier_cmp(const AlgorithmIdentifier *p, 1292178825Sdfr const AlgorithmIdentifier *q) 1293178825Sdfr{ 1294178825Sdfr int diff; 1295178825Sdfr diff = der_heim_oid_cmp(&p->algorithm, &q->algorithm); 1296178825Sdfr if (diff) 1297178825Sdfr return diff; 1298178825Sdfr if (p->parameters) { 1299178825Sdfr if (q->parameters) 1300178825Sdfr return heim_any_cmp(p->parameters, 1301178825Sdfr q->parameters); 1302178825Sdfr else 1303178825Sdfr return 1; 1304178825Sdfr } else { 1305178825Sdfr if (q->parameters) 1306178825Sdfr return -1; 1307178825Sdfr else 1308178825Sdfr return 0; 1309178825Sdfr } 1310178825Sdfr} 1311178825Sdfr 1312178825Sdfrint 1313178825Sdfr_hx509_Certificate_cmp(const Certificate *p, const Certificate *q) 1314178825Sdfr{ 1315178825Sdfr int diff; 1316178825Sdfr diff = der_heim_bit_string_cmp(&p->signatureValue, &q->signatureValue); 1317178825Sdfr if (diff) 1318178825Sdfr return diff; 1319233294Sstas diff = _hx509_AlgorithmIdentifier_cmp(&p->signatureAlgorithm, 1320178825Sdfr &q->signatureAlgorithm); 1321178825Sdfr if (diff) 1322178825Sdfr return diff; 1323178825Sdfr diff = der_heim_octet_string_cmp(&p->tbsCertificate._save, 1324178825Sdfr &q->tbsCertificate._save); 1325178825Sdfr return diff; 1326178825Sdfr} 1327178825Sdfr 1328178825Sdfr/** 1329178825Sdfr * Compare to hx509 certificate object, useful for sorting. 1330178825Sdfr * 1331178825Sdfr * @param p a hx509 certificate object. 1332178825Sdfr * @param q a hx509 certificate object. 1333178825Sdfr * 1334178825Sdfr * @return 0 the objects are the same, returns > 0 is p is "larger" 1335178825Sdfr * then q, < 0 if p is "smaller" then q. 1336178825Sdfr * 1337178825Sdfr * @ingroup hx509_cert 1338178825Sdfr */ 1339178825Sdfr 1340178825Sdfrint 1341178825Sdfrhx509_cert_cmp(hx509_cert p, hx509_cert q) 1342178825Sdfr{ 1343178825Sdfr return _hx509_Certificate_cmp(p->data, q->data); 1344178825Sdfr} 1345178825Sdfr 1346178825Sdfr/** 1347178825Sdfr * Return the name of the issuer of the hx509 certificate. 1348178825Sdfr * 1349178825Sdfr * @param p a hx509 certificate object. 1350178825Sdfr * @param name a pointer to a hx509 name, should be freed by 1351178825Sdfr * hx509_name_free(). 1352178825Sdfr * 1353178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 1354178825Sdfr * 1355178825Sdfr * @ingroup hx509_cert 1356178825Sdfr */ 1357178825Sdfr 1358178825Sdfrint 1359178825Sdfrhx509_cert_get_issuer(hx509_cert p, hx509_name *name) 1360178825Sdfr{ 1361178825Sdfr return _hx509_name_from_Name(&p->data->tbsCertificate.issuer, name); 1362178825Sdfr} 1363178825Sdfr 1364178825Sdfr/** 1365178825Sdfr * Return the name of the subject of the hx509 certificate. 1366178825Sdfr * 1367178825Sdfr * @param p a hx509 certificate object. 1368178825Sdfr * @param name a pointer to a hx509 name, should be freed by 1369178825Sdfr * hx509_name_free(). See also hx509_cert_get_base_subject(). 1370178825Sdfr * 1371178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 1372178825Sdfr * 1373178825Sdfr * @ingroup hx509_cert 1374178825Sdfr */ 1375178825Sdfr 1376178825Sdfrint 1377178825Sdfrhx509_cert_get_subject(hx509_cert p, hx509_name *name) 1378178825Sdfr{ 1379178825Sdfr return _hx509_name_from_Name(&p->data->tbsCertificate.subject, name); 1380178825Sdfr} 1381178825Sdfr 1382178825Sdfr/** 1383178825Sdfr * Return the name of the base subject of the hx509 certificate. If 1384178825Sdfr * the certiicate is a verified proxy certificate, the this function 1385178825Sdfr * return the base certificate (root of the proxy chain). If the proxy 1386178825Sdfr * certificate is not verified with the base certificate 1387178825Sdfr * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned. 1388178825Sdfr * 1389178825Sdfr * @param context a hx509 context. 1390178825Sdfr * @param c a hx509 certificate object. 1391178825Sdfr * @param name a pointer to a hx509 name, should be freed by 1392178825Sdfr * hx509_name_free(). See also hx509_cert_get_subject(). 1393178825Sdfr * 1394178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 1395178825Sdfr * 1396178825Sdfr * @ingroup hx509_cert 1397178825Sdfr */ 1398178825Sdfr 1399178825Sdfrint 1400178825Sdfrhx509_cert_get_base_subject(hx509_context context, hx509_cert c, 1401178825Sdfr hx509_name *name) 1402178825Sdfr{ 1403178825Sdfr if (c->basename) 1404178825Sdfr return hx509_name_copy(context, c->basename, name); 1405178825Sdfr if (is_proxy_cert(context, c->data, NULL) == 0) { 1406178825Sdfr int ret = HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED; 1407178825Sdfr hx509_set_error_string(context, 0, ret, 1408178825Sdfr "Proxy certificate have not been " 1409178825Sdfr "canonicalize yet, no base name"); 1410178825Sdfr return ret; 1411178825Sdfr } 1412178825Sdfr return _hx509_name_from_Name(&c->data->tbsCertificate.subject, name); 1413178825Sdfr} 1414178825Sdfr 1415178825Sdfr/** 1416178825Sdfr * Get serial number of the certificate. 1417178825Sdfr * 1418178825Sdfr * @param p a hx509 certificate object. 1419178825Sdfr * @param i serial number, should be freed ith der_free_heim_integer(). 1420178825Sdfr * 1421178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 1422178825Sdfr * 1423178825Sdfr * @ingroup hx509_cert 1424178825Sdfr */ 1425178825Sdfr 1426178825Sdfrint 1427178825Sdfrhx509_cert_get_serialnumber(hx509_cert p, heim_integer *i) 1428178825Sdfr{ 1429178825Sdfr return der_copy_heim_integer(&p->data->tbsCertificate.serialNumber, i); 1430178825Sdfr} 1431178825Sdfr 1432178825Sdfr/** 1433178825Sdfr * Get notBefore time of the certificate. 1434178825Sdfr * 1435178825Sdfr * @param p a hx509 certificate object. 1436178825Sdfr * 1437178825Sdfr * @return return not before time 1438178825Sdfr * 1439178825Sdfr * @ingroup hx509_cert 1440178825Sdfr */ 1441178825Sdfr 1442178825Sdfrtime_t 1443178825Sdfrhx509_cert_get_notBefore(hx509_cert p) 1444178825Sdfr{ 1445178825Sdfr return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notBefore); 1446178825Sdfr} 1447178825Sdfr 1448178825Sdfr/** 1449178825Sdfr * Get notAfter time of the certificate. 1450178825Sdfr * 1451178825Sdfr * @param p a hx509 certificate object. 1452178825Sdfr * 1453178825Sdfr * @return return not after time. 1454178825Sdfr * 1455178825Sdfr * @ingroup hx509_cert 1456178825Sdfr */ 1457178825Sdfr 1458178825Sdfrtime_t 1459178825Sdfrhx509_cert_get_notAfter(hx509_cert p) 1460178825Sdfr{ 1461178825Sdfr return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notAfter); 1462178825Sdfr} 1463178825Sdfr 1464178825Sdfr/** 1465178825Sdfr * Get the SubjectPublicKeyInfo structure from the hx509 certificate. 1466178825Sdfr * 1467178825Sdfr * @param context a hx509 context. 1468178825Sdfr * @param p a hx509 certificate object. 1469178825Sdfr * @param spki SubjectPublicKeyInfo, should be freed with 1470178825Sdfr * free_SubjectPublicKeyInfo(). 1471178825Sdfr * 1472178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 1473178825Sdfr * 1474178825Sdfr * @ingroup hx509_cert 1475178825Sdfr */ 1476178825Sdfr 1477178825Sdfrint 1478178825Sdfrhx509_cert_get_SPKI(hx509_context context, hx509_cert p, SubjectPublicKeyInfo *spki) 1479178825Sdfr{ 1480178825Sdfr int ret; 1481178825Sdfr 1482178825Sdfr ret = copy_SubjectPublicKeyInfo(&p->data->tbsCertificate.subjectPublicKeyInfo, spki); 1483178825Sdfr if (ret) 1484178825Sdfr hx509_set_error_string(context, 0, ret, "Failed to copy SPKI"); 1485178825Sdfr return ret; 1486178825Sdfr} 1487178825Sdfr 1488178825Sdfr/** 1489178825Sdfr * Get the AlgorithmIdentifier from the hx509 certificate. 1490178825Sdfr * 1491178825Sdfr * @param context a hx509 context. 1492178825Sdfr * @param p a hx509 certificate object. 1493178825Sdfr * @param alg AlgorithmIdentifier, should be freed with 1494233294Sstas * free_AlgorithmIdentifier(). The algorithmidentifier is 1495233294Sstas * typicly rsaEncryption, or id-ecPublicKey, or some other 1496233294Sstas * public key mechanism. 1497178825Sdfr * 1498178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 1499178825Sdfr * 1500178825Sdfr * @ingroup hx509_cert 1501178825Sdfr */ 1502178825Sdfr 1503178825Sdfrint 1504178825Sdfrhx509_cert_get_SPKI_AlgorithmIdentifier(hx509_context context, 1505233294Sstas hx509_cert p, 1506178825Sdfr AlgorithmIdentifier *alg) 1507178825Sdfr{ 1508178825Sdfr int ret; 1509178825Sdfr 1510178825Sdfr ret = copy_AlgorithmIdentifier(&p->data->tbsCertificate.subjectPublicKeyInfo.algorithm, alg); 1511178825Sdfr if (ret) 1512178825Sdfr hx509_set_error_string(context, 0, ret, 1513178825Sdfr "Failed to copy SPKI AlgorithmIdentifier"); 1514178825Sdfr return ret; 1515178825Sdfr} 1516178825Sdfr 1517233294Sstasstatic int 1518233294Sstasget_x_unique_id(hx509_context context, const char *name, 1519233294Sstas const heim_bit_string *cert, heim_bit_string *subject) 1520233294Sstas{ 1521233294Sstas int ret; 1522178825Sdfr 1523233294Sstas if (cert == NULL) { 1524233294Sstas ret = HX509_EXTENSION_NOT_FOUND; 1525233294Sstas hx509_set_error_string(context, 0, ret, "%s unique id doesn't exists", name); 1526233294Sstas return ret; 1527233294Sstas } 1528233294Sstas ret = der_copy_bit_string(cert, subject); 1529233294Sstas if (ret) { 1530233294Sstas hx509_set_error_string(context, 0, ret, "malloc out of memory", name); 1531233294Sstas return ret; 1532233294Sstas } 1533233294Sstas return 0; 1534233294Sstas} 1535233294Sstas 1536233294Sstas/** 1537233294Sstas * Get a copy of the Issuer Unique ID 1538233294Sstas * 1539233294Sstas * @param context a hx509_context 1540233294Sstas * @param p a hx509 certificate 1541233294Sstas * @param issuer the issuer id returned, free with der_free_bit_string() 1542233294Sstas * 1543233294Sstas * @return An hx509 error code, see hx509_get_error_string(). The 1544233294Sstas * error code HX509_EXTENSION_NOT_FOUND is returned if the certificate 1545233294Sstas * doesn't have a issuerUniqueID 1546233294Sstas * 1547233294Sstas * @ingroup hx509_cert 1548233294Sstas */ 1549233294Sstas 1550233294Sstasint 1551233294Sstashx509_cert_get_issuer_unique_id(hx509_context context, hx509_cert p, heim_bit_string *issuer) 1552233294Sstas{ 1553233294Sstas return get_x_unique_id(context, "issuer", p->data->tbsCertificate.issuerUniqueID, issuer); 1554233294Sstas} 1555233294Sstas 1556233294Sstas/** 1557233294Sstas * Get a copy of the Subect Unique ID 1558233294Sstas * 1559233294Sstas * @param context a hx509_context 1560233294Sstas * @param p a hx509 certificate 1561233294Sstas * @param subject the subject id returned, free with der_free_bit_string() 1562233294Sstas * 1563233294Sstas * @return An hx509 error code, see hx509_get_error_string(). The 1564233294Sstas * error code HX509_EXTENSION_NOT_FOUND is returned if the certificate 1565233294Sstas * doesn't have a subjectUniqueID 1566233294Sstas * 1567233294Sstas * @ingroup hx509_cert 1568233294Sstas */ 1569233294Sstas 1570233294Sstasint 1571233294Sstashx509_cert_get_subject_unique_id(hx509_context context, hx509_cert p, heim_bit_string *subject) 1572233294Sstas{ 1573233294Sstas return get_x_unique_id(context, "subject", p->data->tbsCertificate.subjectUniqueID, subject); 1574233294Sstas} 1575233294Sstas 1576233294Sstas 1577178825Sdfrhx509_private_key 1578178825Sdfr_hx509_cert_private_key(hx509_cert p) 1579178825Sdfr{ 1580178825Sdfr return p->private_key; 1581178825Sdfr} 1582178825Sdfr 1583178825Sdfrint 1584178825Sdfrhx509_cert_have_private_key(hx509_cert p) 1585178825Sdfr{ 1586178825Sdfr return p->private_key ? 1 : 0; 1587178825Sdfr} 1588178825Sdfr 1589178825Sdfr 1590178825Sdfrint 1591178825Sdfr_hx509_cert_private_key_exportable(hx509_cert p) 1592178825Sdfr{ 1593178825Sdfr if (p->private_key == NULL) 1594178825Sdfr return 0; 1595178825Sdfr return _hx509_private_key_exportable(p->private_key); 1596178825Sdfr} 1597178825Sdfr 1598178825Sdfrint 1599178825Sdfr_hx509_cert_private_decrypt(hx509_context context, 1600178825Sdfr const heim_octet_string *ciphertext, 1601178825Sdfr const heim_oid *encryption_oid, 1602178825Sdfr hx509_cert p, 1603178825Sdfr heim_octet_string *cleartext) 1604178825Sdfr{ 1605178825Sdfr cleartext->data = NULL; 1606178825Sdfr cleartext->length = 0; 1607178825Sdfr 1608178825Sdfr if (p->private_key == NULL) { 1609178825Sdfr hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING, 1610178825Sdfr "Private key missing"); 1611178825Sdfr return HX509_PRIVATE_KEY_MISSING; 1612178825Sdfr } 1613178825Sdfr 1614233294Sstas return hx509_private_key_private_decrypt(context, 1615178825Sdfr ciphertext, 1616178825Sdfr encryption_oid, 1617233294Sstas p->private_key, 1618178825Sdfr cleartext); 1619178825Sdfr} 1620178825Sdfr 1621178825Sdfrint 1622233294Sstashx509_cert_public_encrypt(hx509_context context, 1623178825Sdfr const heim_octet_string *cleartext, 1624178825Sdfr const hx509_cert p, 1625178825Sdfr heim_oid *encryption_oid, 1626178825Sdfr heim_octet_string *ciphertext) 1627178825Sdfr{ 1628178825Sdfr return _hx509_public_encrypt(context, 1629178825Sdfr cleartext, p->data, 1630178825Sdfr encryption_oid, ciphertext); 1631178825Sdfr} 1632178825Sdfr 1633178825Sdfr/* 1634178825Sdfr * 1635178825Sdfr */ 1636178825Sdfr 1637178825Sdfrtime_t 1638178825Sdfr_hx509_Time2time_t(const Time *t) 1639178825Sdfr{ 1640178825Sdfr switch(t->element) { 1641178825Sdfr case choice_Time_utcTime: 1642178825Sdfr return t->u.utcTime; 1643178825Sdfr case choice_Time_generalTime: 1644178825Sdfr return t->u.generalTime; 1645178825Sdfr } 1646178825Sdfr return 0; 1647178825Sdfr} 1648178825Sdfr 1649178825Sdfr/* 1650178825Sdfr * 1651178825Sdfr */ 1652178825Sdfr 1653178825Sdfrstatic int 1654178825Sdfrinit_name_constraints(hx509_name_constraints *nc) 1655178825Sdfr{ 1656178825Sdfr memset(nc, 0, sizeof(*nc)); 1657178825Sdfr return 0; 1658178825Sdfr} 1659178825Sdfr 1660178825Sdfrstatic int 1661178825Sdfradd_name_constraints(hx509_context context, const Certificate *c, int not_ca, 1662178825Sdfr hx509_name_constraints *nc) 1663178825Sdfr{ 1664178825Sdfr NameConstraints tnc; 1665178825Sdfr int ret; 1666178825Sdfr 1667178825Sdfr ret = find_extension_name_constraints(c, &tnc); 1668178825Sdfr if (ret == HX509_EXTENSION_NOT_FOUND) 1669178825Sdfr return 0; 1670178825Sdfr else if (ret) { 1671178825Sdfr hx509_set_error_string(context, 0, ret, "Failed getting NameConstraints"); 1672178825Sdfr return ret; 1673178825Sdfr } else if (not_ca) { 1674178825Sdfr ret = HX509_VERIFY_CONSTRAINTS; 1675178825Sdfr hx509_set_error_string(context, 0, ret, "Not a CA and " 1676178825Sdfr "have NameConstraints"); 1677178825Sdfr } else { 1678178825Sdfr NameConstraints *val; 1679178825Sdfr val = realloc(nc->val, sizeof(nc->val[0]) * (nc->len + 1)); 1680178825Sdfr if (val == NULL) { 1681178825Sdfr hx509_clear_error_string(context); 1682178825Sdfr ret = ENOMEM; 1683178825Sdfr goto out; 1684178825Sdfr } 1685178825Sdfr nc->val = val; 1686178825Sdfr ret = copy_NameConstraints(&tnc, &nc->val[nc->len]); 1687178825Sdfr if (ret) { 1688178825Sdfr hx509_clear_error_string(context); 1689178825Sdfr goto out; 1690178825Sdfr } 1691178825Sdfr nc->len += 1; 1692178825Sdfr } 1693178825Sdfrout: 1694178825Sdfr free_NameConstraints(&tnc); 1695178825Sdfr return ret; 1696178825Sdfr} 1697178825Sdfr 1698178825Sdfrstatic int 1699178825Sdfrmatch_RDN(const RelativeDistinguishedName *c, 1700178825Sdfr const RelativeDistinguishedName *n) 1701178825Sdfr{ 1702233294Sstas size_t i; 1703178825Sdfr 1704178825Sdfr if (c->len != n->len) 1705178825Sdfr return HX509_NAME_CONSTRAINT_ERROR; 1706233294Sstas 1707178825Sdfr for (i = 0; i < n->len; i++) { 1708233294Sstas int diff, ret; 1709233294Sstas 1710178825Sdfr if (der_heim_oid_cmp(&c->val[i].type, &n->val[i].type) != 0) 1711178825Sdfr return HX509_NAME_CONSTRAINT_ERROR; 1712233294Sstas ret = _hx509_name_ds_cmp(&c->val[i].value, &n->val[i].value, &diff); 1713233294Sstas if (ret) 1714233294Sstas return ret; 1715233294Sstas if (diff != 0) 1716178825Sdfr return HX509_NAME_CONSTRAINT_ERROR; 1717178825Sdfr } 1718178825Sdfr return 0; 1719178825Sdfr} 1720178825Sdfr 1721178825Sdfrstatic int 1722178825Sdfrmatch_X501Name(const Name *c, const Name *n) 1723178825Sdfr{ 1724233294Sstas size_t i; 1725233294Sstas int ret; 1726178825Sdfr 1727178825Sdfr if (c->element != choice_Name_rdnSequence 1728178825Sdfr || n->element != choice_Name_rdnSequence) 1729178825Sdfr return 0; 1730178825Sdfr if (c->u.rdnSequence.len > n->u.rdnSequence.len) 1731178825Sdfr return HX509_NAME_CONSTRAINT_ERROR; 1732178825Sdfr for (i = 0; i < c->u.rdnSequence.len; i++) { 1733178825Sdfr ret = match_RDN(&c->u.rdnSequence.val[i], &n->u.rdnSequence.val[i]); 1734178825Sdfr if (ret) 1735178825Sdfr return ret; 1736178825Sdfr } 1737178825Sdfr return 0; 1738233294Sstas} 1739178825Sdfr 1740178825Sdfr 1741178825Sdfrstatic int 1742178825Sdfrmatch_general_name(const GeneralName *c, const GeneralName *n, int *match) 1743178825Sdfr{ 1744233294Sstas /* 1745178825Sdfr * Name constraints only apply to the same name type, see RFC3280, 1746178825Sdfr * 4.2.1.11. 1747178825Sdfr */ 1748178825Sdfr assert(c->element == n->element); 1749178825Sdfr 1750178825Sdfr switch(c->element) { 1751178825Sdfr case choice_GeneralName_otherName: 1752178825Sdfr if (der_heim_oid_cmp(&c->u.otherName.type_id, 1753178825Sdfr &n->u.otherName.type_id) != 0) 1754178825Sdfr return HX509_NAME_CONSTRAINT_ERROR; 1755178825Sdfr if (heim_any_cmp(&c->u.otherName.value, 1756178825Sdfr &n->u.otherName.value) != 0) 1757178825Sdfr return HX509_NAME_CONSTRAINT_ERROR; 1758178825Sdfr *match = 1; 1759178825Sdfr return 0; 1760178825Sdfr case choice_GeneralName_rfc822Name: { 1761178825Sdfr const char *s; 1762178825Sdfr size_t len1, len2; 1763233294Sstas s = memchr(c->u.rfc822Name.data, '@', c->u.rfc822Name.length); 1764178825Sdfr if (s) { 1765233294Sstas if (der_printable_string_cmp(&c->u.rfc822Name, &n->u.rfc822Name) != 0) 1766178825Sdfr return HX509_NAME_CONSTRAINT_ERROR; 1767178825Sdfr } else { 1768233294Sstas s = memchr(n->u.rfc822Name.data, '@', n->u.rfc822Name.length); 1769178825Sdfr if (s == NULL) 1770178825Sdfr return HX509_NAME_CONSTRAINT_ERROR; 1771233294Sstas len1 = c->u.rfc822Name.length; 1772233294Sstas len2 = n->u.rfc822Name.length - 1773233294Sstas (s - ((char *)n->u.rfc822Name.data)); 1774178825Sdfr if (len1 > len2) 1775178825Sdfr return HX509_NAME_CONSTRAINT_ERROR; 1776233294Sstas if (memcmp(s + 1 + len2 - len1, c->u.rfc822Name.data, len1) != 0) 1777178825Sdfr return HX509_NAME_CONSTRAINT_ERROR; 1778178825Sdfr if (len1 < len2 && s[len2 - len1 + 1] != '.') 1779178825Sdfr return HX509_NAME_CONSTRAINT_ERROR; 1780178825Sdfr } 1781178825Sdfr *match = 1; 1782178825Sdfr return 0; 1783178825Sdfr } 1784178825Sdfr case choice_GeneralName_dNSName: { 1785178825Sdfr size_t lenc, lenn; 1786233294Sstas char *ptr; 1787178825Sdfr 1788233294Sstas lenc = c->u.dNSName.length; 1789233294Sstas lenn = n->u.dNSName.length; 1790178825Sdfr if (lenc > lenn) 1791178825Sdfr return HX509_NAME_CONSTRAINT_ERROR; 1792233294Sstas ptr = n->u.dNSName.data; 1793233294Sstas if (memcmp(&ptr[lenn - lenc], c->u.dNSName.data, lenc) != 0) 1794178825Sdfr return HX509_NAME_CONSTRAINT_ERROR; 1795233294Sstas if (lenn != lenc && ptr[lenn - lenc - 1] != '.') 1796178825Sdfr return HX509_NAME_CONSTRAINT_ERROR; 1797178825Sdfr *match = 1; 1798178825Sdfr return 0; 1799178825Sdfr } 1800178825Sdfr case choice_GeneralName_directoryName: { 1801178825Sdfr Name c_name, n_name; 1802178825Sdfr int ret; 1803178825Sdfr 1804178825Sdfr c_name._save.data = NULL; 1805178825Sdfr c_name._save.length = 0; 1806178825Sdfr c_name.element = c->u.directoryName.element; 1807178825Sdfr c_name.u.rdnSequence = c->u.directoryName.u.rdnSequence; 1808178825Sdfr 1809178825Sdfr n_name._save.data = NULL; 1810178825Sdfr n_name._save.length = 0; 1811178825Sdfr n_name.element = n->u.directoryName.element; 1812178825Sdfr n_name.u.rdnSequence = n->u.directoryName.u.rdnSequence; 1813178825Sdfr 1814178825Sdfr ret = match_X501Name(&c_name, &n_name); 1815178825Sdfr if (ret == 0) 1816178825Sdfr *match = 1; 1817178825Sdfr return ret; 1818178825Sdfr } 1819178825Sdfr case choice_GeneralName_uniformResourceIdentifier: 1820178825Sdfr case choice_GeneralName_iPAddress: 1821178825Sdfr case choice_GeneralName_registeredID: 1822178825Sdfr default: 1823178825Sdfr return HX509_NAME_CONSTRAINT_ERROR; 1824178825Sdfr } 1825178825Sdfr} 1826178825Sdfr 1827178825Sdfrstatic int 1828233294Sstasmatch_alt_name(const GeneralName *n, const Certificate *c, 1829178825Sdfr int *same, int *match) 1830178825Sdfr{ 1831178825Sdfr GeneralNames sa; 1832233294Sstas int ret; 1833233294Sstas size_t i, j; 1834178825Sdfr 1835178825Sdfr i = 0; 1836178825Sdfr do { 1837178825Sdfr ret = find_extension_subject_alt_name(c, &i, &sa); 1838178825Sdfr if (ret == HX509_EXTENSION_NOT_FOUND) { 1839178825Sdfr ret = 0; 1840178825Sdfr break; 1841178825Sdfr } else if (ret != 0) 1842178825Sdfr break; 1843178825Sdfr 1844178825Sdfr for (j = 0; j < sa.len; j++) { 1845178825Sdfr if (n->element == sa.val[j].element) { 1846178825Sdfr *same = 1; 1847178825Sdfr ret = match_general_name(n, &sa.val[j], match); 1848178825Sdfr } 1849178825Sdfr } 1850178825Sdfr free_GeneralNames(&sa); 1851178825Sdfr } while (1); 1852178825Sdfr return ret; 1853178825Sdfr} 1854178825Sdfr 1855178825Sdfr 1856178825Sdfrstatic int 1857178825Sdfrmatch_tree(const GeneralSubtrees *t, const Certificate *c, int *match) 1858178825Sdfr{ 1859178825Sdfr int name, alt_name, same; 1860178825Sdfr unsigned int i; 1861178825Sdfr int ret = 0; 1862178825Sdfr 1863178825Sdfr name = alt_name = same = *match = 0; 1864178825Sdfr for (i = 0; i < t->len; i++) { 1865178825Sdfr if (t->val[i].minimum && t->val[i].maximum) 1866178825Sdfr return HX509_RANGE; 1867178825Sdfr 1868178825Sdfr /* 1869178825Sdfr * If the constraint apply to directoryNames, test is with 1870178825Sdfr * subjectName of the certificate if the certificate have a 1871178825Sdfr * non-null (empty) subjectName. 1872178825Sdfr */ 1873178825Sdfr 1874178825Sdfr if (t->val[i].base.element == choice_GeneralName_directoryName 1875178825Sdfr && !subject_null_p(c)) 1876178825Sdfr { 1877178825Sdfr GeneralName certname; 1878233294Sstas 1879178825Sdfr memset(&certname, 0, sizeof(certname)); 1880178825Sdfr certname.element = choice_GeneralName_directoryName; 1881233294Sstas certname.u.directoryName.element = 1882178825Sdfr c->tbsCertificate.subject.element; 1883233294Sstas certname.u.directoryName.u.rdnSequence = 1884178825Sdfr c->tbsCertificate.subject.u.rdnSequence; 1885233294Sstas 1886178825Sdfr ret = match_general_name(&t->val[i].base, &certname, &name); 1887178825Sdfr } 1888178825Sdfr 1889178825Sdfr /* Handle subjectAltNames, this is icky since they 1890178825Sdfr * restrictions only apply if the subjectAltName is of the 1891178825Sdfr * same type. So if there have been a match of type, require 1892178825Sdfr * altname to be set. 1893178825Sdfr */ 1894178825Sdfr ret = match_alt_name(&t->val[i].base, c, &same, &alt_name); 1895178825Sdfr } 1896178825Sdfr if (name && (!same || alt_name)) 1897178825Sdfr *match = 1; 1898178825Sdfr return ret; 1899178825Sdfr} 1900178825Sdfr 1901178825Sdfrstatic int 1902233294Sstascheck_name_constraints(hx509_context context, 1903178825Sdfr const hx509_name_constraints *nc, 1904178825Sdfr const Certificate *c) 1905178825Sdfr{ 1906178825Sdfr int match, ret; 1907233294Sstas size_t i; 1908178825Sdfr 1909178825Sdfr for (i = 0 ; i < nc->len; i++) { 1910178825Sdfr GeneralSubtrees gs; 1911178825Sdfr 1912178825Sdfr if (nc->val[i].permittedSubtrees) { 1913178825Sdfr GeneralSubtrees_SET(&gs, nc->val[i].permittedSubtrees); 1914178825Sdfr ret = match_tree(&gs, c, &match); 1915178825Sdfr if (ret) { 1916178825Sdfr hx509_clear_error_string(context); 1917178825Sdfr return ret; 1918178825Sdfr } 1919178825Sdfr /* allow null subjectNames, they wont matches anything */ 1920178825Sdfr if (match == 0 && !subject_null_p(c)) { 1921178825Sdfr hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS, 1922178825Sdfr "Error verify constraints, " 1923178825Sdfr "certificate didn't match any " 1924178825Sdfr "permitted subtree"); 1925178825Sdfr return HX509_VERIFY_CONSTRAINTS; 1926178825Sdfr } 1927178825Sdfr } 1928178825Sdfr if (nc->val[i].excludedSubtrees) { 1929178825Sdfr GeneralSubtrees_SET(&gs, nc->val[i].excludedSubtrees); 1930178825Sdfr ret = match_tree(&gs, c, &match); 1931178825Sdfr if (ret) { 1932178825Sdfr hx509_clear_error_string(context); 1933178825Sdfr return ret; 1934178825Sdfr } 1935178825Sdfr if (match) { 1936178825Sdfr hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS, 1937178825Sdfr "Error verify constraints, " 1938178825Sdfr "certificate included in excluded " 1939178825Sdfr "subtree"); 1940178825Sdfr return HX509_VERIFY_CONSTRAINTS; 1941178825Sdfr } 1942178825Sdfr } 1943178825Sdfr } 1944178825Sdfr return 0; 1945178825Sdfr} 1946178825Sdfr 1947178825Sdfrstatic void 1948178825Sdfrfree_name_constraints(hx509_name_constraints *nc) 1949178825Sdfr{ 1950233294Sstas size_t i; 1951178825Sdfr 1952178825Sdfr for (i = 0 ; i < nc->len; i++) 1953178825Sdfr free_NameConstraints(&nc->val[i]); 1954178825Sdfr free(nc->val); 1955178825Sdfr} 1956178825Sdfr 1957178825Sdfr/** 1958178825Sdfr * Build and verify the path for the certificate to the trust anchor 1959178825Sdfr * specified in the verify context. The path is constructed from the 1960178825Sdfr * certificate, the pool and the trust anchors. 1961178825Sdfr * 1962178825Sdfr * @param context A hx509 context. 1963178825Sdfr * @param ctx A hx509 verification context. 1964178825Sdfr * @param cert the certificate to build the path from. 1965178825Sdfr * @param pool A keyset of certificates to build the chain from. 1966178825Sdfr * 1967178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 1968178825Sdfr * 1969178825Sdfr * @ingroup hx509_verify 1970178825Sdfr */ 1971178825Sdfr 1972178825Sdfrint 1973178825Sdfrhx509_verify_path(hx509_context context, 1974178825Sdfr hx509_verify_ctx ctx, 1975178825Sdfr hx509_cert cert, 1976178825Sdfr hx509_certs pool) 1977178825Sdfr{ 1978178825Sdfr hx509_name_constraints nc; 1979178825Sdfr hx509_path path; 1980233294Sstas int ret, proxy_cert_depth, selfsigned_depth, diff; 1981233294Sstas size_t i, k; 1982178825Sdfr enum certtype type; 1983178825Sdfr Name proxy_issuer; 1984178825Sdfr hx509_certs anchors = NULL; 1985178825Sdfr 1986178825Sdfr memset(&proxy_issuer, 0, sizeof(proxy_issuer)); 1987178825Sdfr 1988178825Sdfr ret = init_name_constraints(&nc); 1989233294Sstas if (ret) 1990178825Sdfr return ret; 1991178825Sdfr 1992178825Sdfr path.val = NULL; 1993178825Sdfr path.len = 0; 1994178825Sdfr 1995178825Sdfr if ((ctx->flags & HX509_VERIFY_CTX_F_TIME_SET) == 0) 1996178825Sdfr ctx->time_now = time(NULL); 1997178825Sdfr 1998178825Sdfr /* 1999178825Sdfr * 2000178825Sdfr */ 2001178825Sdfr if (ctx->trust_anchors) 2002233294Sstas anchors = hx509_certs_ref(ctx->trust_anchors); 2003178825Sdfr else if (context->default_trust_anchors && ALLOW_DEF_TA(ctx)) 2004233294Sstas anchors = hx509_certs_ref(context->default_trust_anchors); 2005178825Sdfr else { 2006178825Sdfr ret = hx509_certs_init(context, "MEMORY:no-TA", 0, NULL, &anchors); 2007178825Sdfr if (ret) 2008178825Sdfr goto out; 2009178825Sdfr } 2010178825Sdfr 2011178825Sdfr /* 2012178825Sdfr * Calculate the path from the certificate user presented to the 2013178825Sdfr * to an anchor. 2014178825Sdfr */ 2015178825Sdfr ret = _hx509_calculate_path(context, 0, ctx->time_now, 2016178825Sdfr anchors, ctx->max_depth, 2017178825Sdfr cert, pool, &path); 2018178825Sdfr if (ret) 2019178825Sdfr goto out; 2020178825Sdfr 2021178825Sdfr /* 2022178825Sdfr * Check CA and proxy certificate chain from the top of the 2023178825Sdfr * certificate chain. Also check certificate is valid with respect 2024178825Sdfr * to the current time. 2025178825Sdfr * 2026178825Sdfr */ 2027178825Sdfr 2028178825Sdfr proxy_cert_depth = 0; 2029178825Sdfr selfsigned_depth = 0; 2030178825Sdfr 2031178825Sdfr if (ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE) 2032178825Sdfr type = PROXY_CERT; 2033178825Sdfr else 2034178825Sdfr type = EE_CERT; 2035178825Sdfr 2036178825Sdfr for (i = 0; i < path.len; i++) { 2037178825Sdfr Certificate *c; 2038178825Sdfr time_t t; 2039178825Sdfr 2040178825Sdfr c = _hx509_get_cert(path.val[i]); 2041233294Sstas 2042178825Sdfr /* 2043178825Sdfr * Lets do some basic check on issuer like 2044178825Sdfr * keyUsage.keyCertSign and basicConstraints.cA bit depending 2045178825Sdfr * on what type of certificate this is. 2046178825Sdfr */ 2047178825Sdfr 2048178825Sdfr switch (type) { 2049178825Sdfr case CA_CERT: 2050233294Sstas 2051178825Sdfr /* XXX make constants for keyusage */ 2052178825Sdfr ret = check_key_usage(context, c, 1 << 5, 2053178825Sdfr REQUIRE_RFC3280(ctx) ? TRUE : FALSE); 2054178825Sdfr if (ret) { 2055178825Sdfr hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 2056178825Sdfr "Key usage missing from CA certificate"); 2057178825Sdfr goto out; 2058178825Sdfr } 2059178825Sdfr 2060233294Sstas /* self signed cert doesn't add to path length */ 2061233294Sstas if (i + 1 != path.len) { 2062233294Sstas int selfsigned; 2063178825Sdfr 2064233294Sstas ret = certificate_is_self_signed(context, c, &selfsigned); 2065233294Sstas if (ret) 2066233294Sstas goto out; 2067233294Sstas if (selfsigned) 2068233294Sstas selfsigned_depth++; 2069233294Sstas } 2070233294Sstas 2071178825Sdfr break; 2072178825Sdfr case PROXY_CERT: { 2073233294Sstas ProxyCertInfo info; 2074178825Sdfr 2075178825Sdfr if (is_proxy_cert(context, c, &info) == 0) { 2076233294Sstas size_t j; 2077178825Sdfr 2078178825Sdfr if (info.pCPathLenConstraint != NULL && 2079178825Sdfr *info.pCPathLenConstraint < i) 2080178825Sdfr { 2081178825Sdfr free_ProxyCertInfo(&info); 2082178825Sdfr ret = HX509_PATH_TOO_LONG; 2083178825Sdfr hx509_set_error_string(context, 0, ret, 2084178825Sdfr "Proxy certificate chain " 2085178825Sdfr "longer then allowed"); 2086178825Sdfr goto out; 2087178825Sdfr } 2088178825Sdfr /* XXX MUST check info.proxyPolicy */ 2089178825Sdfr free_ProxyCertInfo(&info); 2090233294Sstas 2091178825Sdfr j = 0; 2092233294Sstas if (find_extension(c, &asn1_oid_id_x509_ce_subjectAltName, &j)) { 2093178825Sdfr ret = HX509_PROXY_CERT_INVALID; 2094233294Sstas hx509_set_error_string(context, 0, ret, 2095178825Sdfr "Proxy certificate have explicity " 2096178825Sdfr "forbidden subjectAltName"); 2097178825Sdfr goto out; 2098178825Sdfr } 2099178825Sdfr 2100178825Sdfr j = 0; 2101233294Sstas if (find_extension(c, &asn1_oid_id_x509_ce_issuerAltName, &j)) { 2102178825Sdfr ret = HX509_PROXY_CERT_INVALID; 2103233294Sstas hx509_set_error_string(context, 0, ret, 2104178825Sdfr "Proxy certificate have explicity " 2105178825Sdfr "forbidden issuerAltName"); 2106178825Sdfr goto out; 2107178825Sdfr } 2108233294Sstas 2109233294Sstas /* 2110178825Sdfr * The subject name of the proxy certificate should be 2111178825Sdfr * CN=XXX,<proxy issuer>, prune of CN and check if its 2112178825Sdfr * the same over the whole chain of proxy certs and 2113178825Sdfr * then check with the EE cert when we get to it. 2114178825Sdfr */ 2115178825Sdfr 2116178825Sdfr if (proxy_cert_depth) { 2117233294Sstas ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.subject, &diff); 2118178825Sdfr if (ret) { 2119233294Sstas hx509_set_error_string(context, 0, ret, "Out of memory"); 2120233294Sstas goto out; 2121233294Sstas } 2122233294Sstas if (diff) { 2123178825Sdfr ret = HX509_PROXY_CERT_NAME_WRONG; 2124178825Sdfr hx509_set_error_string(context, 0, ret, 2125178825Sdfr "Base proxy name not right"); 2126178825Sdfr goto out; 2127178825Sdfr } 2128178825Sdfr } 2129178825Sdfr 2130178825Sdfr free_Name(&proxy_issuer); 2131178825Sdfr 2132178825Sdfr ret = copy_Name(&c->tbsCertificate.subject, &proxy_issuer); 2133178825Sdfr if (ret) { 2134178825Sdfr hx509_clear_error_string(context); 2135178825Sdfr goto out; 2136178825Sdfr } 2137178825Sdfr 2138178825Sdfr j = proxy_issuer.u.rdnSequence.len; 2139233294Sstas if (proxy_issuer.u.rdnSequence.len < 2 2140178825Sdfr || proxy_issuer.u.rdnSequence.val[j - 1].len > 1 2141178825Sdfr || der_heim_oid_cmp(&proxy_issuer.u.rdnSequence.val[j - 1].val[0].type, 2142233294Sstas &asn1_oid_id_at_commonName)) 2143178825Sdfr { 2144178825Sdfr ret = HX509_PROXY_CERT_NAME_WRONG; 2145178825Sdfr hx509_set_error_string(context, 0, ret, 2146178825Sdfr "Proxy name too short or " 2147178825Sdfr "does not have Common name " 2148178825Sdfr "at the top"); 2149178825Sdfr goto out; 2150178825Sdfr } 2151178825Sdfr 2152178825Sdfr free_RelativeDistinguishedName(&proxy_issuer.u.rdnSequence.val[j - 1]); 2153178825Sdfr proxy_issuer.u.rdnSequence.len -= 1; 2154178825Sdfr 2155233294Sstas ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.issuer, &diff); 2156233294Sstas if (ret) { 2157233294Sstas hx509_set_error_string(context, 0, ret, "Out of memory"); 2158233294Sstas goto out; 2159233294Sstas } 2160233294Sstas if (diff != 0) { 2161178825Sdfr ret = HX509_PROXY_CERT_NAME_WRONG; 2162178825Sdfr hx509_set_error_string(context, 0, ret, 2163178825Sdfr "Proxy issuer name not as expected"); 2164178825Sdfr goto out; 2165178825Sdfr } 2166178825Sdfr 2167178825Sdfr break; 2168178825Sdfr } else { 2169233294Sstas /* 2170178825Sdfr * Now we are done with the proxy certificates, this 2171178825Sdfr * cert was an EE cert and we we will fall though to 2172178825Sdfr * EE checking below. 2173178825Sdfr */ 2174178825Sdfr type = EE_CERT; 2175178825Sdfr /* FALLTHOUGH */ 2176178825Sdfr } 2177178825Sdfr } 2178178825Sdfr case EE_CERT: 2179178825Sdfr /* 2180178825Sdfr * If there where any proxy certificates in the chain 2181178825Sdfr * (proxy_cert_depth > 0), check that the proxy issuer 2182178825Sdfr * matched proxy certificates "base" subject. 2183178825Sdfr */ 2184178825Sdfr if (proxy_cert_depth) { 2185178825Sdfr 2186178825Sdfr ret = _hx509_name_cmp(&proxy_issuer, 2187233294Sstas &c->tbsCertificate.subject, &diff); 2188178825Sdfr if (ret) { 2189233294Sstas hx509_set_error_string(context, 0, ret, "out of memory"); 2190233294Sstas goto out; 2191233294Sstas } 2192233294Sstas if (diff) { 2193178825Sdfr ret = HX509_PROXY_CERT_NAME_WRONG; 2194178825Sdfr hx509_clear_error_string(context); 2195178825Sdfr goto out; 2196178825Sdfr } 2197178825Sdfr if (cert->basename) 2198178825Sdfr hx509_name_free(&cert->basename); 2199233294Sstas 2200178825Sdfr ret = _hx509_name_from_Name(&proxy_issuer, &cert->basename); 2201178825Sdfr if (ret) { 2202178825Sdfr hx509_clear_error_string(context); 2203178825Sdfr goto out; 2204178825Sdfr } 2205178825Sdfr } 2206178825Sdfr 2207178825Sdfr break; 2208178825Sdfr } 2209178825Sdfr 2210233294Sstas ret = check_basic_constraints(context, c, type, 2211178825Sdfr i - proxy_cert_depth - selfsigned_depth); 2212178825Sdfr if (ret) 2213178825Sdfr goto out; 2214233294Sstas 2215178825Sdfr /* 2216178825Sdfr * Don't check the trust anchors expiration time since they 2217178825Sdfr * are transported out of band, from RFC3820. 2218178825Sdfr */ 2219178825Sdfr if (i + 1 != path.len || CHECK_TA(ctx)) { 2220178825Sdfr 2221178825Sdfr t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore); 2222178825Sdfr if (t > ctx->time_now) { 2223178825Sdfr ret = HX509_CERT_USED_BEFORE_TIME; 2224178825Sdfr hx509_clear_error_string(context); 2225178825Sdfr goto out; 2226178825Sdfr } 2227178825Sdfr t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter); 2228178825Sdfr if (t < ctx->time_now) { 2229178825Sdfr ret = HX509_CERT_USED_AFTER_TIME; 2230178825Sdfr hx509_clear_error_string(context); 2231178825Sdfr goto out; 2232178825Sdfr } 2233178825Sdfr } 2234178825Sdfr 2235178825Sdfr if (type == EE_CERT) 2236178825Sdfr type = CA_CERT; 2237178825Sdfr else if (type == PROXY_CERT) 2238178825Sdfr proxy_cert_depth++; 2239178825Sdfr } 2240178825Sdfr 2241178825Sdfr /* 2242178825Sdfr * Verify constraints, do this backward so path constraints are 2243178825Sdfr * checked in the right order. 2244178825Sdfr */ 2245178825Sdfr 2246233294Sstas for (ret = 0, k = path.len; k > 0; k--) { 2247178825Sdfr Certificate *c; 2248233294Sstas int selfsigned; 2249233294Sstas i = k - 1; 2250178825Sdfr 2251178825Sdfr c = _hx509_get_cert(path.val[i]); 2252178825Sdfr 2253233294Sstas ret = certificate_is_self_signed(context, c, &selfsigned); 2254233294Sstas if (ret) 2255233294Sstas goto out; 2256233294Sstas 2257178825Sdfr /* verify name constraints, not for selfsigned and anchor */ 2258233294Sstas if (!selfsigned || i + 1 != path.len) { 2259178825Sdfr ret = check_name_constraints(context, &nc, c); 2260178825Sdfr if (ret) { 2261178825Sdfr goto out; 2262178825Sdfr } 2263178825Sdfr } 2264178825Sdfr ret = add_name_constraints(context, c, i == 0, &nc); 2265178825Sdfr if (ret) 2266178825Sdfr goto out; 2267178825Sdfr 2268178825Sdfr /* XXX verify all other silly constraints */ 2269178825Sdfr 2270178825Sdfr } 2271178825Sdfr 2272178825Sdfr /* 2273178825Sdfr * Verify that no certificates has been revoked. 2274178825Sdfr */ 2275178825Sdfr 2276178825Sdfr if (ctx->revoke_ctx) { 2277178825Sdfr hx509_certs certs; 2278178825Sdfr 2279178825Sdfr ret = hx509_certs_init(context, "MEMORY:revoke-certs", 0, 2280178825Sdfr NULL, &certs); 2281178825Sdfr if (ret) 2282178825Sdfr goto out; 2283178825Sdfr 2284178825Sdfr for (i = 0; i < path.len; i++) { 2285178825Sdfr ret = hx509_certs_add(context, certs, path.val[i]); 2286178825Sdfr if (ret) { 2287178825Sdfr hx509_certs_free(&certs); 2288178825Sdfr goto out; 2289178825Sdfr } 2290178825Sdfr } 2291178825Sdfr ret = hx509_certs_merge(context, certs, pool); 2292178825Sdfr if (ret) { 2293178825Sdfr hx509_certs_free(&certs); 2294178825Sdfr goto out; 2295178825Sdfr } 2296178825Sdfr 2297178825Sdfr for (i = 0; i < path.len - 1; i++) { 2298233294Sstas size_t parent = (i < path.len - 1) ? i + 1 : i; 2299178825Sdfr 2300178825Sdfr ret = hx509_revoke_verify(context, 2301233294Sstas ctx->revoke_ctx, 2302178825Sdfr certs, 2303178825Sdfr ctx->time_now, 2304178825Sdfr path.val[i], 2305178825Sdfr path.val[parent]); 2306178825Sdfr if (ret) { 2307178825Sdfr hx509_certs_free(&certs); 2308178825Sdfr goto out; 2309178825Sdfr } 2310178825Sdfr } 2311178825Sdfr hx509_certs_free(&certs); 2312178825Sdfr } 2313178825Sdfr 2314178825Sdfr /* 2315178825Sdfr * Verify signatures, do this backward so public key working 2316178825Sdfr * parameter is passed up from the anchor up though the chain. 2317178825Sdfr */ 2318178825Sdfr 2319233294Sstas for (k = path.len; k > 0; k--) { 2320233294Sstas hx509_cert signer; 2321233294Sstas Certificate *c; 2322233294Sstas i = k - 1; 2323178825Sdfr 2324178825Sdfr c = _hx509_get_cert(path.val[i]); 2325178825Sdfr 2326178825Sdfr /* is last in chain (trust anchor) */ 2327178825Sdfr if (i + 1 == path.len) { 2328233294Sstas int selfsigned; 2329178825Sdfr 2330233294Sstas signer = path.val[i]; 2331233294Sstas 2332233294Sstas ret = certificate_is_self_signed(context, signer->data, &selfsigned); 2333233294Sstas if (ret) 2334233294Sstas goto out; 2335233294Sstas 2336178825Sdfr /* if trust anchor is not self signed, don't check sig */ 2337233294Sstas if (!selfsigned) 2338178825Sdfr continue; 2339178825Sdfr } else { 2340178825Sdfr /* take next certificate in chain */ 2341233294Sstas signer = path.val[i + 1]; 2342178825Sdfr } 2343178825Sdfr 2344178825Sdfr /* verify signatureValue */ 2345178825Sdfr ret = _hx509_verify_signature_bitstring(context, 2346178825Sdfr signer, 2347178825Sdfr &c->signatureAlgorithm, 2348178825Sdfr &c->tbsCertificate._save, 2349178825Sdfr &c->signatureValue); 2350178825Sdfr if (ret) { 2351178825Sdfr hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 2352178825Sdfr "Failed to verify signature of certificate"); 2353178825Sdfr goto out; 2354178825Sdfr } 2355233294Sstas /* 2356233294Sstas * Verify that the sigature algorithm "best-before" date is 2357233294Sstas * before the creation date of the certificate, do this for 2358233294Sstas * trust anchors too, since any trust anchor that is created 2359233294Sstas * after a algorithm is known to be bad deserved to be invalid. 2360233294Sstas * 2361233294Sstas * Skip the leaf certificate for now... 2362233294Sstas */ 2363233294Sstas 2364233294Sstas if (i != 0 && (ctx->flags & HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK) == 0) { 2365233294Sstas time_t notBefore = 2366233294Sstas _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore); 2367233294Sstas ret = _hx509_signature_best_before(context, 2368233294Sstas &c->signatureAlgorithm, 2369233294Sstas notBefore); 2370233294Sstas if (ret) 2371233294Sstas goto out; 2372233294Sstas } 2373178825Sdfr } 2374178825Sdfr 2375178825Sdfrout: 2376178825Sdfr hx509_certs_free(&anchors); 2377178825Sdfr free_Name(&proxy_issuer); 2378178825Sdfr free_name_constraints(&nc); 2379178825Sdfr _hx509_path_free(&path); 2380178825Sdfr 2381178825Sdfr return ret; 2382178825Sdfr} 2383178825Sdfr 2384178825Sdfr/** 2385178825Sdfr * Verify a signature made using the private key of an certificate. 2386178825Sdfr * 2387178825Sdfr * @param context A hx509 context. 2388178825Sdfr * @param signer the certificate that made the signature. 2389178825Sdfr * @param alg algorthm that was used to sign the data. 2390178825Sdfr * @param data the data that was signed. 2391178825Sdfr * @param sig the sigature to verify. 2392178825Sdfr * 2393178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 2394178825Sdfr * 2395178825Sdfr * @ingroup hx509_crypto 2396178825Sdfr */ 2397178825Sdfr 2398178825Sdfrint 2399178825Sdfrhx509_verify_signature(hx509_context context, 2400178825Sdfr const hx509_cert signer, 2401178825Sdfr const AlgorithmIdentifier *alg, 2402178825Sdfr const heim_octet_string *data, 2403178825Sdfr const heim_octet_string *sig) 2404178825Sdfr{ 2405233294Sstas return _hx509_verify_signature(context, signer, alg, data, sig); 2406178825Sdfr} 2407178825Sdfr 2408233294Sstasint 2409233294Sstas_hx509_verify_signature_bitstring(hx509_context context, 2410233294Sstas const hx509_cert signer, 2411233294Sstas const AlgorithmIdentifier *alg, 2412233294Sstas const heim_octet_string *data, 2413233294Sstas const heim_bit_string *sig) 2414233294Sstas{ 2415233294Sstas heim_octet_string os; 2416178825Sdfr 2417233294Sstas if (sig->length & 7) { 2418233294Sstas hx509_set_error_string(context, 0, HX509_CRYPTO_SIG_INVALID_FORMAT, 2419233294Sstas "signature not multiple of 8 bits"); 2420233294Sstas return HX509_CRYPTO_SIG_INVALID_FORMAT; 2421233294Sstas } 2422233294Sstas 2423233294Sstas os.data = sig->data; 2424233294Sstas os.length = sig->length / 8; 2425233294Sstas 2426233294Sstas return _hx509_verify_signature(context, signer, alg, data, &os); 2427233294Sstas} 2428233294Sstas 2429233294Sstas 2430233294Sstas 2431178825Sdfr/** 2432178825Sdfr * Verify that the certificate is allowed to be used for the hostname 2433178825Sdfr * and address. 2434178825Sdfr * 2435178825Sdfr * @param context A hx509 context. 2436178825Sdfr * @param cert the certificate to match with 2437178825Sdfr * @param flags Flags to modify the behavior: 2438178825Sdfr * - HX509_VHN_F_ALLOW_NO_MATCH no match is ok 2439178825Sdfr * @param type type of hostname: 2440178825Sdfr * - HX509_HN_HOSTNAME for plain hostname. 2441178825Sdfr * - HX509_HN_DNSSRV for DNS SRV names. 2442178825Sdfr * @param hostname the hostname to check 2443178825Sdfr * @param sa address of the host 2444178825Sdfr * @param sa_size length of address 2445178825Sdfr * 2446178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 2447178825Sdfr * 2448178825Sdfr * @ingroup hx509_cert 2449178825Sdfr */ 2450178825Sdfr 2451178825Sdfrint 2452178825Sdfrhx509_verify_hostname(hx509_context context, 2453178825Sdfr const hx509_cert cert, 2454178825Sdfr int flags, 2455178825Sdfr hx509_hostname_type type, 2456178825Sdfr const char *hostname, 2457178825Sdfr const struct sockaddr *sa, 2458233294Sstas /* XXX krb5_socklen_t */ int sa_size) 2459178825Sdfr{ 2460178825Sdfr GeneralNames san; 2461233294Sstas const Name *name; 2462233294Sstas int ret; 2463233294Sstas size_t i, j, k; 2464178825Sdfr 2465178825Sdfr if (sa && sa_size <= 0) 2466178825Sdfr return EINVAL; 2467178825Sdfr 2468178825Sdfr memset(&san, 0, sizeof(san)); 2469178825Sdfr 2470178825Sdfr i = 0; 2471178825Sdfr do { 2472178825Sdfr ret = find_extension_subject_alt_name(cert->data, &i, &san); 2473233294Sstas if (ret == HX509_EXTENSION_NOT_FOUND) 2474178825Sdfr break; 2475233294Sstas else if (ret != 0) 2476233294Sstas return HX509_PARSING_NAME_FAILED; 2477178825Sdfr 2478178825Sdfr for (j = 0; j < san.len; j++) { 2479178825Sdfr switch (san.val[j].element) { 2480233294Sstas case choice_GeneralName_dNSName: { 2481233294Sstas heim_printable_string hn; 2482233294Sstas hn.data = rk_UNCONST(hostname); 2483233294Sstas hn.length = strlen(hostname); 2484233294Sstas 2485233294Sstas if (der_printable_string_cmp(&san.val[j].u.dNSName, &hn) == 0) { 2486178825Sdfr free_GeneralNames(&san); 2487178825Sdfr return 0; 2488178825Sdfr } 2489178825Sdfr break; 2490233294Sstas } 2491178825Sdfr default: 2492178825Sdfr break; 2493178825Sdfr } 2494178825Sdfr } 2495178825Sdfr free_GeneralNames(&san); 2496178825Sdfr } while (1); 2497178825Sdfr 2498233294Sstas name = &cert->data->tbsCertificate.subject; 2499178825Sdfr 2500233294Sstas /* Find first CN= in the name, and try to match the hostname on that */ 2501233294Sstas for (ret = 0, k = name->u.rdnSequence.len; ret == 0 && k > 0; k--) { 2502233294Sstas i = k - 1; 2503233294Sstas for (j = 0; ret == 0 && j < name->u.rdnSequence.val[i].len; j++) { 2504233294Sstas AttributeTypeAndValue *n = &name->u.rdnSequence.val[i].val[j]; 2505178825Sdfr 2506233294Sstas if (der_heim_oid_cmp(&n->type, &asn1_oid_id_at_commonName) == 0) { 2507233294Sstas DirectoryString *ds = &n->value; 2508233294Sstas switch (ds->element) { 2509233294Sstas case choice_DirectoryString_printableString: { 2510233294Sstas heim_printable_string hn; 2511233294Sstas hn.data = rk_UNCONST(hostname); 2512233294Sstas hn.length = strlen(hostname); 2513233294Sstas 2514233294Sstas if (der_printable_string_cmp(&ds->u.printableString, &hn) == 0) 2515233294Sstas return 0; 2516233294Sstas break; 2517233294Sstas } 2518233294Sstas case choice_DirectoryString_ia5String: { 2519233294Sstas heim_ia5_string hn; 2520233294Sstas hn.data = rk_UNCONST(hostname); 2521233294Sstas hn.length = strlen(hostname); 2522233294Sstas 2523233294Sstas if (der_ia5_string_cmp(&ds->u.ia5String, &hn) == 0) 2524233294Sstas return 0; 2525233294Sstas break; 2526233294Sstas } 2527233294Sstas case choice_DirectoryString_utf8String: 2528233294Sstas if (strcasecmp(ds->u.utf8String, hostname) == 0) 2529233294Sstas return 0; 2530233294Sstas default: 2531233294Sstas break; 2532233294Sstas } 2533233294Sstas ret = HX509_NAME_CONSTRAINT_ERROR; 2534178825Sdfr } 2535178825Sdfr } 2536178825Sdfr } 2537178825Sdfr 2538178825Sdfr if ((flags & HX509_VHN_F_ALLOW_NO_MATCH) == 0) 2539178825Sdfr ret = HX509_NAME_CONSTRAINT_ERROR; 2540178825Sdfr 2541178825Sdfr return ret; 2542178825Sdfr} 2543178825Sdfr 2544178825Sdfrint 2545178825Sdfr_hx509_set_cert_attribute(hx509_context context, 2546233294Sstas hx509_cert cert, 2547233294Sstas const heim_oid *oid, 2548178825Sdfr const heim_octet_string *attr) 2549178825Sdfr{ 2550178825Sdfr hx509_cert_attribute a; 2551178825Sdfr void *d; 2552178825Sdfr 2553178825Sdfr if (hx509_cert_get_attribute(cert, oid) != NULL) 2554178825Sdfr return 0; 2555178825Sdfr 2556233294Sstas d = realloc(cert->attrs.val, 2557178825Sdfr sizeof(cert->attrs.val[0]) * (cert->attrs.len + 1)); 2558178825Sdfr if (d == NULL) { 2559178825Sdfr hx509_clear_error_string(context); 2560178825Sdfr return ENOMEM; 2561178825Sdfr } 2562178825Sdfr cert->attrs.val = d; 2563178825Sdfr 2564178825Sdfr a = malloc(sizeof(*a)); 2565178825Sdfr if (a == NULL) 2566178825Sdfr return ENOMEM; 2567178825Sdfr 2568178825Sdfr der_copy_octet_string(attr, &a->data); 2569178825Sdfr der_copy_oid(oid, &a->oid); 2570233294Sstas 2571178825Sdfr cert->attrs.val[cert->attrs.len] = a; 2572178825Sdfr cert->attrs.len++; 2573178825Sdfr 2574178825Sdfr return 0; 2575178825Sdfr} 2576178825Sdfr 2577178825Sdfr/** 2578178825Sdfr * Get an external attribute for the certificate, examples are 2579178825Sdfr * friendly name and id. 2580178825Sdfr * 2581178825Sdfr * @param cert hx509 certificate object to search 2582178825Sdfr * @param oid an oid to search for. 2583178825Sdfr * 2584178825Sdfr * @return an hx509_cert_attribute, only valid as long as the 2585178825Sdfr * certificate is referenced. 2586178825Sdfr * 2587178825Sdfr * @ingroup hx509_cert 2588178825Sdfr */ 2589178825Sdfr 2590178825Sdfrhx509_cert_attribute 2591178825Sdfrhx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid) 2592178825Sdfr{ 2593233294Sstas size_t i; 2594178825Sdfr for (i = 0; i < cert->attrs.len; i++) 2595178825Sdfr if (der_heim_oid_cmp(oid, &cert->attrs.val[i]->oid) == 0) 2596178825Sdfr return cert->attrs.val[i]; 2597178825Sdfr return NULL; 2598178825Sdfr} 2599178825Sdfr 2600178825Sdfr/** 2601178825Sdfr * Set the friendly name on the certificate. 2602178825Sdfr * 2603178825Sdfr * @param cert The certificate to set the friendly name on 2604178825Sdfr * @param name Friendly name. 2605178825Sdfr * 2606178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 2607178825Sdfr * 2608178825Sdfr * @ingroup hx509_cert 2609178825Sdfr */ 2610178825Sdfr 2611178825Sdfrint 2612178825Sdfrhx509_cert_set_friendly_name(hx509_cert cert, const char *name) 2613178825Sdfr{ 2614178825Sdfr if (cert->friendlyname) 2615178825Sdfr free(cert->friendlyname); 2616178825Sdfr cert->friendlyname = strdup(name); 2617178825Sdfr if (cert->friendlyname == NULL) 2618178825Sdfr return ENOMEM; 2619178825Sdfr return 0; 2620178825Sdfr} 2621178825Sdfr 2622178825Sdfr/** 2623178825Sdfr * Get friendly name of the certificate. 2624178825Sdfr * 2625178825Sdfr * @param cert cert to get the friendly name from. 2626178825Sdfr * 2627178825Sdfr * @return an friendly name or NULL if there is. The friendly name is 2628178825Sdfr * only valid as long as the certificate is referenced. 2629178825Sdfr * 2630178825Sdfr * @ingroup hx509_cert 2631178825Sdfr */ 2632178825Sdfr 2633178825Sdfrconst char * 2634178825Sdfrhx509_cert_get_friendly_name(hx509_cert cert) 2635178825Sdfr{ 2636178825Sdfr hx509_cert_attribute a; 2637178825Sdfr PKCS9_friendlyName n; 2638178825Sdfr size_t sz; 2639233294Sstas int ret; 2640233294Sstas size_t i; 2641178825Sdfr 2642178825Sdfr if (cert->friendlyname) 2643178825Sdfr return cert->friendlyname; 2644178825Sdfr 2645233294Sstas a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_friendlyName); 2646178825Sdfr if (a == NULL) { 2647233294Sstas hx509_name name; 2648233294Sstas 2649233294Sstas ret = hx509_cert_get_subject(cert, &name); 2650233294Sstas if (ret) 2651233294Sstas return NULL; 2652233294Sstas ret = hx509_name_to_string(name, &cert->friendlyname); 2653233294Sstas hx509_name_free(&name); 2654233294Sstas if (ret) 2655233294Sstas return NULL; 2656233294Sstas return cert->friendlyname; 2657178825Sdfr } 2658178825Sdfr 2659178825Sdfr ret = decode_PKCS9_friendlyName(a->data.data, a->data.length, &n, &sz); 2660178825Sdfr if (ret) 2661178825Sdfr return NULL; 2662233294Sstas 2663178825Sdfr if (n.len != 1) { 2664178825Sdfr free_PKCS9_friendlyName(&n); 2665178825Sdfr return NULL; 2666178825Sdfr } 2667233294Sstas 2668178825Sdfr cert->friendlyname = malloc(n.val[0].length + 1); 2669178825Sdfr if (cert->friendlyname == NULL) { 2670178825Sdfr free_PKCS9_friendlyName(&n); 2671178825Sdfr return NULL; 2672178825Sdfr } 2673233294Sstas 2674178825Sdfr for (i = 0; i < n.val[0].length; i++) { 2675178825Sdfr if (n.val[0].data[i] <= 0xff) 2676178825Sdfr cert->friendlyname[i] = n.val[0].data[i] & 0xff; 2677178825Sdfr else 2678178825Sdfr cert->friendlyname[i] = 'X'; 2679178825Sdfr } 2680178825Sdfr cert->friendlyname[i] = '\0'; 2681178825Sdfr free_PKCS9_friendlyName(&n); 2682178825Sdfr 2683178825Sdfr return cert->friendlyname; 2684178825Sdfr} 2685178825Sdfr 2686178825Sdfrvoid 2687178825Sdfr_hx509_query_clear(hx509_query *q) 2688178825Sdfr{ 2689178825Sdfr memset(q, 0, sizeof(*q)); 2690178825Sdfr} 2691178825Sdfr 2692178825Sdfr/** 2693178825Sdfr * Allocate an query controller. Free using hx509_query_free(). 2694178825Sdfr * 2695178825Sdfr * @param context A hx509 context. 2696178825Sdfr * @param q return pointer to a hx509_query. 2697178825Sdfr * 2698178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 2699178825Sdfr * 2700178825Sdfr * @ingroup hx509_cert 2701178825Sdfr */ 2702178825Sdfr 2703178825Sdfrint 2704178825Sdfrhx509_query_alloc(hx509_context context, hx509_query **q) 2705178825Sdfr{ 2706178825Sdfr *q = calloc(1, sizeof(**q)); 2707178825Sdfr if (*q == NULL) 2708178825Sdfr return ENOMEM; 2709178825Sdfr return 0; 2710178825Sdfr} 2711178825Sdfr 2712233294Sstas 2713178825Sdfr/** 2714178825Sdfr * Set match options for the hx509 query controller. 2715178825Sdfr * 2716178825Sdfr * @param q query controller. 2717178825Sdfr * @param option options to control the query controller. 2718178825Sdfr * 2719178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 2720178825Sdfr * 2721178825Sdfr * @ingroup hx509_cert 2722178825Sdfr */ 2723178825Sdfr 2724178825Sdfrvoid 2725178825Sdfrhx509_query_match_option(hx509_query *q, hx509_query_option option) 2726178825Sdfr{ 2727178825Sdfr switch(option) { 2728178825Sdfr case HX509_QUERY_OPTION_PRIVATE_KEY: 2729178825Sdfr q->match |= HX509_QUERY_PRIVATE_KEY; 2730178825Sdfr break; 2731178825Sdfr case HX509_QUERY_OPTION_KU_ENCIPHERMENT: 2732178825Sdfr q->match |= HX509_QUERY_KU_ENCIPHERMENT; 2733178825Sdfr break; 2734178825Sdfr case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE: 2735178825Sdfr q->match |= HX509_QUERY_KU_DIGITALSIGNATURE; 2736178825Sdfr break; 2737178825Sdfr case HX509_QUERY_OPTION_KU_KEYCERTSIGN: 2738178825Sdfr q->match |= HX509_QUERY_KU_KEYCERTSIGN; 2739178825Sdfr break; 2740178825Sdfr case HX509_QUERY_OPTION_END: 2741178825Sdfr default: 2742178825Sdfr break; 2743178825Sdfr } 2744178825Sdfr} 2745178825Sdfr 2746178825Sdfr/** 2747178825Sdfr * Set the issuer and serial number of match in the query 2748178825Sdfr * controller. The function make copies of the isser and serial number. 2749178825Sdfr * 2750178825Sdfr * @param q a hx509 query controller 2751178825Sdfr * @param issuer issuer to search for 2752178825Sdfr * @param serialNumber the serialNumber of the issuer. 2753178825Sdfr * 2754178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 2755178825Sdfr * 2756178825Sdfr * @ingroup hx509_cert 2757178825Sdfr */ 2758178825Sdfr 2759178825Sdfrint 2760178825Sdfrhx509_query_match_issuer_serial(hx509_query *q, 2761233294Sstas const Name *issuer, 2762178825Sdfr const heim_integer *serialNumber) 2763178825Sdfr{ 2764178825Sdfr int ret; 2765178825Sdfr if (q->serial) { 2766178825Sdfr der_free_heim_integer(q->serial); 2767178825Sdfr free(q->serial); 2768178825Sdfr } 2769178825Sdfr q->serial = malloc(sizeof(*q->serial)); 2770178825Sdfr if (q->serial == NULL) 2771178825Sdfr return ENOMEM; 2772178825Sdfr ret = der_copy_heim_integer(serialNumber, q->serial); 2773178825Sdfr if (ret) { 2774178825Sdfr free(q->serial); 2775178825Sdfr q->serial = NULL; 2776178825Sdfr return ret; 2777178825Sdfr } 2778178825Sdfr if (q->issuer_name) { 2779178825Sdfr free_Name(q->issuer_name); 2780178825Sdfr free(q->issuer_name); 2781178825Sdfr } 2782178825Sdfr q->issuer_name = malloc(sizeof(*q->issuer_name)); 2783178825Sdfr if (q->issuer_name == NULL) 2784178825Sdfr return ENOMEM; 2785178825Sdfr ret = copy_Name(issuer, q->issuer_name); 2786178825Sdfr if (ret) { 2787178825Sdfr free(q->issuer_name); 2788178825Sdfr q->issuer_name = NULL; 2789178825Sdfr return ret; 2790178825Sdfr } 2791178825Sdfr q->match |= HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME; 2792178825Sdfr return 0; 2793178825Sdfr} 2794178825Sdfr 2795178825Sdfr/** 2796178825Sdfr * Set the query controller to match on a friendly name 2797178825Sdfr * 2798178825Sdfr * @param q a hx509 query controller. 2799178825Sdfr * @param name a friendly name to match on 2800178825Sdfr * 2801178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 2802178825Sdfr * 2803178825Sdfr * @ingroup hx509_cert 2804178825Sdfr */ 2805178825Sdfr 2806178825Sdfrint 2807178825Sdfrhx509_query_match_friendly_name(hx509_query *q, const char *name) 2808178825Sdfr{ 2809178825Sdfr if (q->friendlyname) 2810178825Sdfr free(q->friendlyname); 2811178825Sdfr q->friendlyname = strdup(name); 2812178825Sdfr if (q->friendlyname == NULL) 2813178825Sdfr return ENOMEM; 2814178825Sdfr q->match |= HX509_QUERY_MATCH_FRIENDLY_NAME; 2815178825Sdfr return 0; 2816178825Sdfr} 2817178825Sdfr 2818178825Sdfr/** 2819233294Sstas * Set the query controller to require an one specific EKU (extended 2820233294Sstas * key usage). Any previous EKU matching is overwitten. If NULL is 2821233294Sstas * passed in as the eku, the EKU requirement is reset. 2822233294Sstas * 2823233294Sstas * @param q a hx509 query controller. 2824233294Sstas * @param eku an EKU to match on. 2825233294Sstas * 2826233294Sstas * @return An hx509 error code, see hx509_get_error_string(). 2827233294Sstas * 2828233294Sstas * @ingroup hx509_cert 2829233294Sstas */ 2830233294Sstas 2831233294Sstasint 2832233294Sstashx509_query_match_eku(hx509_query *q, const heim_oid *eku) 2833233294Sstas{ 2834233294Sstas int ret; 2835233294Sstas 2836233294Sstas if (eku == NULL) { 2837233294Sstas if (q->eku) { 2838233294Sstas der_free_oid(q->eku); 2839233294Sstas free(q->eku); 2840233294Sstas q->eku = NULL; 2841233294Sstas } 2842233294Sstas q->match &= ~HX509_QUERY_MATCH_EKU; 2843233294Sstas } else { 2844233294Sstas if (q->eku) { 2845233294Sstas der_free_oid(q->eku); 2846233294Sstas } else { 2847233294Sstas q->eku = calloc(1, sizeof(*q->eku)); 2848233294Sstas if (q->eku == NULL) 2849233294Sstas return ENOMEM; 2850233294Sstas } 2851233294Sstas ret = der_copy_oid(eku, q->eku); 2852233294Sstas if (ret) { 2853233294Sstas free(q->eku); 2854233294Sstas q->eku = NULL; 2855233294Sstas return ret; 2856233294Sstas } 2857233294Sstas q->match |= HX509_QUERY_MATCH_EKU; 2858233294Sstas } 2859233294Sstas return 0; 2860233294Sstas} 2861233294Sstas 2862233294Sstasint 2863233294Sstashx509_query_match_expr(hx509_context context, hx509_query *q, const char *expr) 2864233294Sstas{ 2865233294Sstas if (q->expr) { 2866233294Sstas _hx509_expr_free(q->expr); 2867233294Sstas q->expr = NULL; 2868233294Sstas } 2869233294Sstas 2870233294Sstas if (expr == NULL) { 2871233294Sstas q->match &= ~HX509_QUERY_MATCH_EXPR; 2872233294Sstas } else { 2873233294Sstas q->expr = _hx509_expr_parse(expr); 2874233294Sstas if (q->expr) 2875233294Sstas q->match |= HX509_QUERY_MATCH_EXPR; 2876233294Sstas } 2877233294Sstas 2878233294Sstas return 0; 2879233294Sstas} 2880233294Sstas 2881233294Sstas/** 2882178825Sdfr * Set the query controller to match using a specific match function. 2883178825Sdfr * 2884178825Sdfr * @param q a hx509 query controller. 2885178825Sdfr * @param func function to use for matching, if the argument is NULL, 2886178825Sdfr * the match function is removed. 2887178825Sdfr * @param ctx context passed to the function. 2888178825Sdfr * 2889178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 2890178825Sdfr * 2891178825Sdfr * @ingroup hx509_cert 2892178825Sdfr */ 2893178825Sdfr 2894178825Sdfrint 2895178825Sdfrhx509_query_match_cmp_func(hx509_query *q, 2896233294Sstas int (*func)(hx509_context, hx509_cert, void *), 2897178825Sdfr void *ctx) 2898178825Sdfr{ 2899178825Sdfr if (func) 2900178825Sdfr q->match |= HX509_QUERY_MATCH_FUNCTION; 2901178825Sdfr else 2902178825Sdfr q->match &= ~HX509_QUERY_MATCH_FUNCTION; 2903178825Sdfr q->cmp_func = func; 2904178825Sdfr q->cmp_func_ctx = ctx; 2905178825Sdfr return 0; 2906178825Sdfr} 2907178825Sdfr 2908178825Sdfr/** 2909178825Sdfr * Free the query controller. 2910178825Sdfr * 2911178825Sdfr * @param context A hx509 context. 2912178825Sdfr * @param q a pointer to the query controller. 2913178825Sdfr * 2914178825Sdfr * @ingroup hx509_cert 2915178825Sdfr */ 2916178825Sdfr 2917178825Sdfrvoid 2918178825Sdfrhx509_query_free(hx509_context context, hx509_query *q) 2919178825Sdfr{ 2920233294Sstas if (q == NULL) 2921233294Sstas return; 2922233294Sstas 2923178825Sdfr if (q->serial) { 2924178825Sdfr der_free_heim_integer(q->serial); 2925178825Sdfr free(q->serial); 2926178825Sdfr } 2927178825Sdfr if (q->issuer_name) { 2928178825Sdfr free_Name(q->issuer_name); 2929178825Sdfr free(q->issuer_name); 2930178825Sdfr } 2931233294Sstas if (q->eku) { 2932233294Sstas der_free_oid(q->eku); 2933233294Sstas free(q->eku); 2934233294Sstas } 2935233294Sstas if (q->friendlyname) 2936178825Sdfr free(q->friendlyname); 2937233294Sstas if (q->expr) 2938233294Sstas _hx509_expr_free(q->expr); 2939233294Sstas 2940233294Sstas memset(q, 0, sizeof(*q)); 2941178825Sdfr free(q); 2942178825Sdfr} 2943178825Sdfr 2944178825Sdfrint 2945178825Sdfr_hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert cert) 2946178825Sdfr{ 2947178825Sdfr Certificate *c = _hx509_get_cert(cert); 2948233294Sstas int ret, diff; 2949178825Sdfr 2950178825Sdfr _hx509_query_statistic(context, 1, q); 2951178825Sdfr 2952178825Sdfr if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) && 2953178825Sdfr _hx509_cert_is_parent_cmp(q->subject, c, 0) != 0) 2954178825Sdfr return 0; 2955178825Sdfr 2956178825Sdfr if ((q->match & HX509_QUERY_MATCH_CERTIFICATE) && 2957178825Sdfr _hx509_Certificate_cmp(q->certificate, c) != 0) 2958178825Sdfr return 0; 2959178825Sdfr 2960178825Sdfr if ((q->match & HX509_QUERY_MATCH_SERIALNUMBER) 2961178825Sdfr && der_heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0) 2962178825Sdfr return 0; 2963178825Sdfr 2964233294Sstas if (q->match & HX509_QUERY_MATCH_ISSUER_NAME) { 2965233294Sstas ret = _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name, &diff); 2966233294Sstas if (ret || diff) 2967233294Sstas return 0; 2968233294Sstas } 2969178825Sdfr 2970233294Sstas if (q->match & HX509_QUERY_MATCH_SUBJECT_NAME) { 2971233294Sstas ret = _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name, &diff); 2972233294Sstas if (ret || diff) 2973233294Sstas return 0; 2974233294Sstas } 2975178825Sdfr 2976178825Sdfr if (q->match & HX509_QUERY_MATCH_SUBJECT_KEY_ID) { 2977178825Sdfr SubjectKeyIdentifier si; 2978178825Sdfr 2979178825Sdfr ret = _hx509_find_extension_subject_key_id(c, &si); 2980178825Sdfr if (ret == 0) { 2981178825Sdfr if (der_heim_octet_string_cmp(&si, q->subject_id) != 0) 2982178825Sdfr ret = 1; 2983178825Sdfr free_SubjectKeyIdentifier(&si); 2984178825Sdfr } 2985178825Sdfr if (ret) 2986178825Sdfr return 0; 2987178825Sdfr } 2988178825Sdfr if ((q->match & HX509_QUERY_MATCH_ISSUER_ID)) 2989178825Sdfr return 0; 2990233294Sstas if ((q->match & HX509_QUERY_PRIVATE_KEY) && 2991178825Sdfr _hx509_cert_private_key(cert) == NULL) 2992178825Sdfr return 0; 2993178825Sdfr 2994178825Sdfr { 2995178825Sdfr unsigned ku = 0; 2996178825Sdfr if (q->match & HX509_QUERY_KU_DIGITALSIGNATURE) 2997178825Sdfr ku |= (1 << 0); 2998178825Sdfr if (q->match & HX509_QUERY_KU_NONREPUDIATION) 2999178825Sdfr ku |= (1 << 1); 3000178825Sdfr if (q->match & HX509_QUERY_KU_ENCIPHERMENT) 3001178825Sdfr ku |= (1 << 2); 3002178825Sdfr if (q->match & HX509_QUERY_KU_DATAENCIPHERMENT) 3003178825Sdfr ku |= (1 << 3); 3004178825Sdfr if (q->match & HX509_QUERY_KU_KEYAGREEMENT) 3005178825Sdfr ku |= (1 << 4); 3006178825Sdfr if (q->match & HX509_QUERY_KU_KEYCERTSIGN) 3007178825Sdfr ku |= (1 << 5); 3008178825Sdfr if (q->match & HX509_QUERY_KU_CRLSIGN) 3009178825Sdfr ku |= (1 << 6); 3010178825Sdfr if (ku && check_key_usage(context, c, ku, TRUE)) 3011178825Sdfr return 0; 3012178825Sdfr } 3013178825Sdfr if ((q->match & HX509_QUERY_ANCHOR)) 3014178825Sdfr return 0; 3015178825Sdfr 3016178825Sdfr if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) { 3017178825Sdfr hx509_cert_attribute a; 3018178825Sdfr 3019233294Sstas a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_localKeyId); 3020178825Sdfr if (a == NULL) 3021178825Sdfr return 0; 3022178825Sdfr if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0) 3023178825Sdfr return 0; 3024178825Sdfr } 3025178825Sdfr 3026178825Sdfr if (q->match & HX509_QUERY_NO_MATCH_PATH) { 3027178825Sdfr size_t i; 3028178825Sdfr 3029178825Sdfr for (i = 0; i < q->path->len; i++) 3030178825Sdfr if (hx509_cert_cmp(q->path->val[i], cert) == 0) 3031178825Sdfr return 0; 3032178825Sdfr } 3033178825Sdfr if (q->match & HX509_QUERY_MATCH_FRIENDLY_NAME) { 3034178825Sdfr const char *name = hx509_cert_get_friendly_name(cert); 3035178825Sdfr if (name == NULL) 3036178825Sdfr return 0; 3037178825Sdfr if (strcasecmp(q->friendlyname, name) != 0) 3038178825Sdfr return 0; 3039178825Sdfr } 3040178825Sdfr if (q->match & HX509_QUERY_MATCH_FUNCTION) { 3041233294Sstas ret = (*q->cmp_func)(context, cert, q->cmp_func_ctx); 3042178825Sdfr if (ret != 0) 3043178825Sdfr return 0; 3044178825Sdfr } 3045178825Sdfr 3046178825Sdfr if (q->match & HX509_QUERY_MATCH_KEY_HASH_SHA1) { 3047178825Sdfr heim_octet_string os; 3048178825Sdfr 3049178825Sdfr os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; 3050233294Sstas os.length = 3051178825Sdfr c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8; 3052178825Sdfr 3053178825Sdfr ret = _hx509_verify_signature(context, 3054178825Sdfr NULL, 3055178825Sdfr hx509_signature_sha1(), 3056178825Sdfr &os, 3057178825Sdfr q->keyhash_sha1); 3058178825Sdfr if (ret != 0) 3059178825Sdfr return 0; 3060178825Sdfr } 3061178825Sdfr 3062178825Sdfr if (q->match & HX509_QUERY_MATCH_TIME) { 3063178825Sdfr time_t t; 3064178825Sdfr t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore); 3065178825Sdfr if (t > q->timenow) 3066178825Sdfr return 0; 3067178825Sdfr t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter); 3068178825Sdfr if (t < q->timenow) 3069178825Sdfr return 0; 3070178825Sdfr } 3071178825Sdfr 3072233294Sstas /* If an EKU is required, check the cert for it. */ 3073233294Sstas if ((q->match & HX509_QUERY_MATCH_EKU) && 3074233294Sstas hx509_cert_check_eku(context, cert, q->eku, 0)) 3075233294Sstas return 0; 3076233294Sstas 3077233294Sstas if ((q->match & HX509_QUERY_MATCH_EXPR)) { 3078233294Sstas hx509_env env = NULL; 3079233294Sstas 3080233294Sstas ret = _hx509_cert_to_env(context, cert, &env); 3081233294Sstas if (ret) 3082233294Sstas return 0; 3083233294Sstas 3084233294Sstas ret = _hx509_expr_eval(context, env, q->expr); 3085233294Sstas hx509_env_free(&env); 3086233294Sstas if (ret == 0) 3087233294Sstas return 0; 3088233294Sstas } 3089233294Sstas 3090178825Sdfr if (q->match & ~HX509_QUERY_MASK) 3091178825Sdfr return 0; 3092178825Sdfr 3093178825Sdfr return 1; 3094178825Sdfr} 3095178825Sdfr 3096178825Sdfr/** 3097178825Sdfr * Set a statistic file for the query statistics. 3098178825Sdfr * 3099178825Sdfr * @param context A hx509 context. 3100178825Sdfr * @param fn statistics file name 3101178825Sdfr * 3102178825Sdfr * @ingroup hx509_cert 3103178825Sdfr */ 3104178825Sdfr 3105178825Sdfrvoid 3106178825Sdfrhx509_query_statistic_file(hx509_context context, const char *fn) 3107178825Sdfr{ 3108178825Sdfr if (context->querystat) 3109178825Sdfr free(context->querystat); 3110178825Sdfr context->querystat = strdup(fn); 3111178825Sdfr} 3112178825Sdfr 3113178825Sdfrvoid 3114178825Sdfr_hx509_query_statistic(hx509_context context, int type, const hx509_query *q) 3115178825Sdfr{ 3116178825Sdfr FILE *f; 3117178825Sdfr if (context->querystat == NULL) 3118178825Sdfr return; 3119178825Sdfr f = fopen(context->querystat, "a"); 3120178825Sdfr if (f == NULL) 3121178825Sdfr return; 3122233294Sstas rk_cloexec_file(f); 3123178825Sdfr fprintf(f, "%d %d\n", type, q->match); 3124178825Sdfr fclose(f); 3125178825Sdfr} 3126178825Sdfr 3127178825Sdfrstatic const char *statname[] = { 3128178825Sdfr "find issuer cert", 3129178825Sdfr "match serialnumber", 3130178825Sdfr "match issuer name", 3131178825Sdfr "match subject name", 3132178825Sdfr "match subject key id", 3133178825Sdfr "match issuer id", 3134178825Sdfr "private key", 3135178825Sdfr "ku encipherment", 3136178825Sdfr "ku digitalsignature", 3137178825Sdfr "ku keycertsign", 3138178825Sdfr "ku crlsign", 3139178825Sdfr "ku nonrepudiation", 3140178825Sdfr "ku keyagreement", 3141178825Sdfr "ku dataencipherment", 3142178825Sdfr "anchor", 3143178825Sdfr "match certificate", 3144178825Sdfr "match local key id", 3145178825Sdfr "no match path", 3146178825Sdfr "match friendly name", 3147178825Sdfr "match function", 3148178825Sdfr "match key hash sha1", 3149178825Sdfr "match time" 3150178825Sdfr}; 3151178825Sdfr 3152178825Sdfrstruct stat_el { 3153178825Sdfr unsigned long stats; 3154178825Sdfr unsigned int index; 3155178825Sdfr}; 3156178825Sdfr 3157178825Sdfr 3158178825Sdfrstatic int 3159178825Sdfrstat_sort(const void *a, const void *b) 3160178825Sdfr{ 3161178825Sdfr const struct stat_el *ae = a; 3162178825Sdfr const struct stat_el *be = b; 3163178825Sdfr return be->stats - ae->stats; 3164178825Sdfr} 3165178825Sdfr 3166178825Sdfr/** 3167178825Sdfr * Unparse the statistics file and print the result on a FILE descriptor. 3168178825Sdfr * 3169178825Sdfr * @param context A hx509 context. 3170178825Sdfr * @param printtype tyep to print 3171178825Sdfr * @param out the FILE to write the data on. 3172178825Sdfr * 3173178825Sdfr * @ingroup hx509_cert 3174178825Sdfr */ 3175178825Sdfr 3176178825Sdfrvoid 3177178825Sdfrhx509_query_unparse_stats(hx509_context context, int printtype, FILE *out) 3178178825Sdfr{ 3179178825Sdfr rtbl_t t; 3180178825Sdfr FILE *f; 3181233294Sstas int type, mask, num; 3182233294Sstas size_t i; 3183178825Sdfr unsigned long multiqueries = 0, totalqueries = 0; 3184178825Sdfr struct stat_el stats[32]; 3185178825Sdfr 3186178825Sdfr if (context->querystat == NULL) 3187178825Sdfr return; 3188178825Sdfr f = fopen(context->querystat, "r"); 3189178825Sdfr if (f == NULL) { 3190233294Sstas fprintf(out, "No statistic file %s: %s.\n", 3191178825Sdfr context->querystat, strerror(errno)); 3192178825Sdfr return; 3193178825Sdfr } 3194233294Sstas rk_cloexec_file(f); 3195233294Sstas 3196178825Sdfr for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) { 3197178825Sdfr stats[i].index = i; 3198178825Sdfr stats[i].stats = 0; 3199178825Sdfr } 3200178825Sdfr 3201178825Sdfr while (fscanf(f, "%d %d\n", &type, &mask) == 2) { 3202178825Sdfr if (type != printtype) 3203178825Sdfr continue; 3204178825Sdfr num = i = 0; 3205178825Sdfr while (mask && i < sizeof(stats)/sizeof(stats[0])) { 3206178825Sdfr if (mask & 1) { 3207178825Sdfr stats[i].stats++; 3208178825Sdfr num++; 3209178825Sdfr } 3210178825Sdfr mask = mask >>1 ; 3211178825Sdfr i++; 3212178825Sdfr } 3213178825Sdfr if (num > 1) 3214178825Sdfr multiqueries++; 3215178825Sdfr totalqueries++; 3216178825Sdfr } 3217178825Sdfr fclose(f); 3218178825Sdfr 3219178825Sdfr qsort(stats, sizeof(stats)/sizeof(stats[0]), sizeof(stats[0]), stat_sort); 3220178825Sdfr 3221178825Sdfr t = rtbl_create(); 3222178825Sdfr if (t == NULL) 3223178825Sdfr errx(1, "out of memory"); 3224178825Sdfr 3225178825Sdfr rtbl_set_separator (t, " "); 3226233294Sstas 3227178825Sdfr rtbl_add_column_by_id (t, 0, "Name", 0); 3228178825Sdfr rtbl_add_column_by_id (t, 1, "Counter", 0); 3229178825Sdfr 3230178825Sdfr 3231178825Sdfr for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) { 3232178825Sdfr char str[10]; 3233178825Sdfr 3234233294Sstas if (stats[i].index < sizeof(statname)/sizeof(statname[0])) 3235178825Sdfr rtbl_add_column_entry_by_id (t, 0, statname[stats[i].index]); 3236178825Sdfr else { 3237178825Sdfr snprintf(str, sizeof(str), "%d", stats[i].index); 3238178825Sdfr rtbl_add_column_entry_by_id (t, 0, str); 3239178825Sdfr } 3240178825Sdfr snprintf(str, sizeof(str), "%lu", stats[i].stats); 3241178825Sdfr rtbl_add_column_entry_by_id (t, 1, str); 3242178825Sdfr } 3243178825Sdfr 3244178825Sdfr rtbl_format(t, out); 3245178825Sdfr rtbl_destroy(t); 3246178825Sdfr 3247233294Sstas fprintf(out, "\nQueries: multi %lu total %lu\n", 3248178825Sdfr multiqueries, totalqueries); 3249178825Sdfr} 3250178825Sdfr 3251178825Sdfr/** 3252178825Sdfr * Check the extended key usage on the hx509 certificate. 3253178825Sdfr * 3254178825Sdfr * @param context A hx509 context. 3255178825Sdfr * @param cert A hx509 context. 3256178825Sdfr * @param eku the EKU to check for 3257178825Sdfr * @param allow_any_eku if the any EKU is set, allow that to be a 3258178825Sdfr * substitute. 3259178825Sdfr * 3260178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 3261178825Sdfr * 3262178825Sdfr * @ingroup hx509_cert 3263178825Sdfr */ 3264178825Sdfr 3265178825Sdfrint 3266178825Sdfrhx509_cert_check_eku(hx509_context context, hx509_cert cert, 3267178825Sdfr const heim_oid *eku, int allow_any_eku) 3268178825Sdfr{ 3269178825Sdfr ExtKeyUsage e; 3270233294Sstas int ret; 3271233294Sstas size_t i; 3272178825Sdfr 3273178825Sdfr ret = find_extension_eku(_hx509_get_cert(cert), &e); 3274178825Sdfr if (ret) { 3275178825Sdfr hx509_clear_error_string(context); 3276178825Sdfr return ret; 3277178825Sdfr } 3278178825Sdfr 3279178825Sdfr for (i = 0; i < e.len; i++) { 3280178825Sdfr if (der_heim_oid_cmp(eku, &e.val[i]) == 0) { 3281178825Sdfr free_ExtKeyUsage(&e); 3282178825Sdfr return 0; 3283178825Sdfr } 3284178825Sdfr if (allow_any_eku) { 3285178825Sdfr#if 0 3286178825Sdfr if (der_heim_oid_cmp(id_any_eku, &e.val[i]) == 0) { 3287178825Sdfr free_ExtKeyUsage(&e); 3288178825Sdfr return 0; 3289178825Sdfr } 3290178825Sdfr#endif 3291178825Sdfr } 3292178825Sdfr } 3293178825Sdfr free_ExtKeyUsage(&e); 3294178825Sdfr hx509_clear_error_string(context); 3295178825Sdfr return HX509_CERTIFICATE_MISSING_EKU; 3296178825Sdfr} 3297178825Sdfr 3298178825Sdfrint 3299178825Sdfr_hx509_cert_get_keyusage(hx509_context context, 3300178825Sdfr hx509_cert c, 3301178825Sdfr KeyUsage *ku) 3302178825Sdfr{ 3303178825Sdfr Certificate *cert; 3304178825Sdfr const Extension *e; 3305178825Sdfr size_t size; 3306233294Sstas int ret; 3307233294Sstas size_t i = 0; 3308178825Sdfr 3309178825Sdfr memset(ku, 0, sizeof(*ku)); 3310178825Sdfr 3311178825Sdfr cert = _hx509_get_cert(c); 3312178825Sdfr 3313178825Sdfr if (_hx509_cert_get_version(cert) < 3) 3314178825Sdfr return 0; 3315178825Sdfr 3316233294Sstas e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i); 3317178825Sdfr if (e == NULL) 3318178825Sdfr return HX509_KU_CERT_MISSING; 3319233294Sstas 3320178825Sdfr ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, ku, &size); 3321178825Sdfr if (ret) 3322178825Sdfr return ret; 3323178825Sdfr return 0; 3324178825Sdfr} 3325178825Sdfr 3326178825Sdfrint 3327178825Sdfr_hx509_cert_get_eku(hx509_context context, 3328178825Sdfr hx509_cert cert, 3329178825Sdfr ExtKeyUsage *e) 3330178825Sdfr{ 3331178825Sdfr int ret; 3332178825Sdfr 3333178825Sdfr memset(e, 0, sizeof(*e)); 3334178825Sdfr 3335178825Sdfr ret = find_extension_eku(_hx509_get_cert(cert), e); 3336178825Sdfr if (ret && ret != HX509_EXTENSION_NOT_FOUND) { 3337178825Sdfr hx509_clear_error_string(context); 3338178825Sdfr return ret; 3339178825Sdfr } 3340178825Sdfr return 0; 3341178825Sdfr} 3342178825Sdfr 3343178825Sdfr/** 3344178825Sdfr * Encodes the hx509 certificate as a DER encode binary. 3345178825Sdfr * 3346178825Sdfr * @param context A hx509 context. 3347178825Sdfr * @param c the certificate to encode. 3348178825Sdfr * @param os the encode certificate, set to NULL, 0 on case of 3349233294Sstas * error. Free the os->data with hx509_xfree(). 3350178825Sdfr * 3351178825Sdfr * @return An hx509 error code, see hx509_get_error_string(). 3352178825Sdfr * 3353178825Sdfr * @ingroup hx509_cert 3354178825Sdfr */ 3355178825Sdfr 3356178825Sdfrint 3357178825Sdfrhx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os) 3358178825Sdfr{ 3359178825Sdfr size_t size; 3360178825Sdfr int ret; 3361178825Sdfr 3362178825Sdfr os->data = NULL; 3363178825Sdfr os->length = 0; 3364178825Sdfr 3365233294Sstas ASN1_MALLOC_ENCODE(Certificate, os->data, os->length, 3366178825Sdfr _hx509_get_cert(c), &size, ret); 3367178825Sdfr if (ret) { 3368178825Sdfr os->data = NULL; 3369178825Sdfr os->length = 0; 3370178825Sdfr return ret; 3371178825Sdfr } 3372178825Sdfr if (os->length != size) 3373178825Sdfr _hx509_abort("internal ASN.1 encoder error"); 3374178825Sdfr 3375178825Sdfr return ret; 3376178825Sdfr} 3377178825Sdfr 3378178825Sdfr/* 3379178825Sdfr * Last to avoid lost __attribute__s due to #undef. 3380178825Sdfr */ 3381178825Sdfr 3382178825Sdfr#undef __attribute__ 3383178825Sdfr#define __attribute__(X) 3384178825Sdfr 3385178825Sdfrvoid 3386178825Sdfr_hx509_abort(const char *fmt, ...) 3387178825Sdfr __attribute__ ((noreturn, format (printf, 1, 2))) 3388178825Sdfr{ 3389178825Sdfr va_list ap; 3390178825Sdfr va_start(ap, fmt); 3391178825Sdfr vprintf(fmt, ap); 3392178825Sdfr va_end(ap); 3393178825Sdfr printf("\n"); 3394178825Sdfr fflush(stdout); 3395178825Sdfr abort(); 3396178825Sdfr} 3397178825Sdfr 3398178825Sdfr/** 3399178825Sdfr * Free a data element allocated in the library. 3400178825Sdfr * 3401178825Sdfr * @param ptr data to be freed. 3402178825Sdfr * 3403178825Sdfr * @ingroup hx509_misc 3404178825Sdfr */ 3405178825Sdfr 3406178825Sdfrvoid 3407178825Sdfrhx509_xfree(void *ptr) 3408178825Sdfr{ 3409178825Sdfr free(ptr); 3410178825Sdfr} 3411233294Sstas 3412233294Sstas/** 3413233294Sstas * 3414233294Sstas */ 3415233294Sstas 3416233294Sstasint 3417233294Sstas_hx509_cert_to_env(hx509_context context, hx509_cert cert, hx509_env *env) 3418233294Sstas{ 3419233294Sstas ExtKeyUsage eku; 3420233294Sstas hx509_name name; 3421233294Sstas char *buf; 3422233294Sstas int ret; 3423233294Sstas hx509_env envcert = NULL; 3424233294Sstas 3425233294Sstas *env = NULL; 3426233294Sstas 3427233294Sstas /* version */ 3428233294Sstas asprintf(&buf, "%d", _hx509_cert_get_version(_hx509_get_cert(cert))); 3429233294Sstas ret = hx509_env_add(context, &envcert, "version", buf); 3430233294Sstas free(buf); 3431233294Sstas if (ret) 3432233294Sstas goto out; 3433233294Sstas 3434233294Sstas /* subject */ 3435233294Sstas ret = hx509_cert_get_subject(cert, &name); 3436233294Sstas if (ret) 3437233294Sstas goto out; 3438233294Sstas 3439233294Sstas ret = hx509_name_to_string(name, &buf); 3440233294Sstas if (ret) { 3441233294Sstas hx509_name_free(&name); 3442233294Sstas goto out; 3443233294Sstas } 3444233294Sstas 3445233294Sstas ret = hx509_env_add(context, &envcert, "subject", buf); 3446233294Sstas hx509_name_free(&name); 3447233294Sstas if (ret) 3448233294Sstas goto out; 3449233294Sstas 3450233294Sstas /* issuer */ 3451233294Sstas ret = hx509_cert_get_issuer(cert, &name); 3452233294Sstas if (ret) 3453233294Sstas goto out; 3454233294Sstas 3455233294Sstas ret = hx509_name_to_string(name, &buf); 3456233294Sstas hx509_name_free(&name); 3457233294Sstas if (ret) 3458233294Sstas goto out; 3459233294Sstas 3460233294Sstas ret = hx509_env_add(context, &envcert, "issuer", buf); 3461233294Sstas hx509_xfree(buf); 3462233294Sstas if (ret) 3463233294Sstas goto out; 3464233294Sstas 3465233294Sstas /* eku */ 3466233294Sstas 3467233294Sstas ret = _hx509_cert_get_eku(context, cert, &eku); 3468233294Sstas if (ret == HX509_EXTENSION_NOT_FOUND) 3469233294Sstas ; 3470233294Sstas else if (ret != 0) 3471233294Sstas goto out; 3472233294Sstas else { 3473233294Sstas size_t i; 3474233294Sstas hx509_env enveku = NULL; 3475233294Sstas 3476233294Sstas for (i = 0; i < eku.len; i++) { 3477233294Sstas 3478233294Sstas ret = der_print_heim_oid(&eku.val[i], '.', &buf); 3479233294Sstas if (ret) { 3480233294Sstas free_ExtKeyUsage(&eku); 3481233294Sstas hx509_env_free(&enveku); 3482233294Sstas goto out; 3483233294Sstas } 3484233294Sstas ret = hx509_env_add(context, &enveku, buf, "oid-name-here"); 3485233294Sstas free(buf); 3486233294Sstas if (ret) { 3487233294Sstas free_ExtKeyUsage(&eku); 3488233294Sstas hx509_env_free(&enveku); 3489233294Sstas goto out; 3490233294Sstas } 3491233294Sstas } 3492233294Sstas free_ExtKeyUsage(&eku); 3493233294Sstas 3494233294Sstas ret = hx509_env_add_binding(context, &envcert, "eku", enveku); 3495233294Sstas if (ret) { 3496233294Sstas hx509_env_free(&enveku); 3497233294Sstas goto out; 3498233294Sstas } 3499233294Sstas } 3500233294Sstas 3501233294Sstas { 3502233294Sstas Certificate *c = _hx509_get_cert(cert); 3503233294Sstas heim_octet_string os, sig; 3504233294Sstas hx509_env envhash = NULL; 3505233294Sstas 3506233294Sstas os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; 3507233294Sstas os.length = 3508233294Sstas c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8; 3509233294Sstas 3510233294Sstas ret = _hx509_create_signature(context, 3511233294Sstas NULL, 3512233294Sstas hx509_signature_sha1(), 3513233294Sstas &os, 3514233294Sstas NULL, 3515233294Sstas &sig); 3516233294Sstas if (ret != 0) 3517233294Sstas goto out; 3518233294Sstas 3519233294Sstas ret = hex_encode(sig.data, sig.length, &buf); 3520233294Sstas der_free_octet_string(&sig); 3521233294Sstas if (ret < 0) { 3522233294Sstas ret = ENOMEM; 3523233294Sstas hx509_set_error_string(context, 0, ret, 3524233294Sstas "Out of memory"); 3525233294Sstas goto out; 3526233294Sstas } 3527233294Sstas 3528233294Sstas ret = hx509_env_add(context, &envhash, "sha1", buf); 3529233294Sstas free(buf); 3530233294Sstas if (ret) 3531233294Sstas goto out; 3532233294Sstas 3533233294Sstas ret = hx509_env_add_binding(context, &envcert, "hash", envhash); 3534233294Sstas if (ret) { 3535233294Sstas hx509_env_free(&envhash); 3536233294Sstas goto out; 3537233294Sstas } 3538233294Sstas } 3539233294Sstas 3540233294Sstas ret = hx509_env_add_binding(context, env, "certificate", envcert); 3541233294Sstas if (ret) 3542233294Sstas goto out; 3543233294Sstas 3544233294Sstas return 0; 3545233294Sstas 3546233294Sstasout: 3547233294Sstas hx509_env_free(&envcert); 3548233294Sstas return ret; 3549233294Sstas} 3550233294Sstas 3551233294Sstas/** 3552233294Sstas * Print a simple representation of a certificate 3553233294Sstas * 3554233294Sstas * @param context A hx509 context, can be NULL 3555233294Sstas * @param cert certificate to print 3556233294Sstas * @param out the stdio output stream, if NULL, stdout is used 3557233294Sstas * 3558233294Sstas * @return An hx509 error code 3559233294Sstas * 3560233294Sstas * @ingroup hx509_cert 3561233294Sstas */ 3562233294Sstas 3563233294Sstasint 3564233294Sstashx509_print_cert(hx509_context context, hx509_cert cert, FILE *out) 3565233294Sstas{ 3566233294Sstas hx509_name name; 3567233294Sstas char *str; 3568233294Sstas int ret; 3569233294Sstas 3570233294Sstas if (out == NULL) 3571233294Sstas out = stderr; 3572233294Sstas 3573233294Sstas ret = hx509_cert_get_issuer(cert, &name); 3574233294Sstas if (ret) 3575233294Sstas return ret; 3576233294Sstas hx509_name_to_string(name, &str); 3577233294Sstas hx509_name_free(&name); 3578233294Sstas fprintf(out, " issuer: \"%s\"\n", str); 3579233294Sstas free(str); 3580233294Sstas 3581233294Sstas ret = hx509_cert_get_subject(cert, &name); 3582233294Sstas if (ret) 3583233294Sstas return ret; 3584233294Sstas hx509_name_to_string(name, &str); 3585233294Sstas hx509_name_free(&name); 3586233294Sstas fprintf(out, " subject: \"%s\"\n", str); 3587233294Sstas free(str); 3588233294Sstas 3589233294Sstas { 3590233294Sstas heim_integer serialNumber; 3591233294Sstas 3592233294Sstas ret = hx509_cert_get_serialnumber(cert, &serialNumber); 3593233294Sstas if (ret) 3594233294Sstas return ret; 3595233294Sstas ret = der_print_hex_heim_integer(&serialNumber, &str); 3596233294Sstas if (ret) 3597233294Sstas return ret; 3598233294Sstas der_free_heim_integer(&serialNumber); 3599233294Sstas fprintf(out, " serial: %s\n", str); 3600233294Sstas free(str); 3601233294Sstas } 3602233294Sstas 3603233294Sstas printf(" keyusage: "); 3604233294Sstas ret = hx509_cert_keyusage_print(context, cert, &str); 3605233294Sstas if (ret == 0) { 3606233294Sstas fprintf(out, "%s\n", str); 3607233294Sstas free(str); 3608233294Sstas } else 3609233294Sstas fprintf(out, "no"); 3610233294Sstas 3611233294Sstas return 0; 3612233294Sstas} 3613