1/* 2 * Copyright 2018-2022 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10#include <openssl/store.h> 11#include "internal/cryptlib.h" 12#include "crypto/x509.h" 13#include "x509_local.h" 14 15/* Generic object loader, given expected type and criterion */ 16static int cache_objects(X509_LOOKUP *lctx, const char *uri, 17 const OSSL_STORE_SEARCH *criterion, 18 int depth, OSSL_LIB_CTX *libctx, const char *propq) 19{ 20 int ok = 0; 21 OSSL_STORE_CTX *ctx = NULL; 22 X509_STORE *xstore = X509_LOOKUP_get_store(lctx); 23 24 if ((ctx = OSSL_STORE_open_ex(uri, libctx, propq, NULL, NULL, NULL, 25 NULL, NULL)) == NULL) 26 return 0; 27 28 /* 29 * We try to set the criterion, but don't care if it was valid or not. 30 * For a OSSL_STORE, it merely serves as an optimization, the expectation 31 * being that if the criterion couldn't be used, we will get *everything* 32 * from the container that the URI represents rather than the subset that 33 * the criterion indicates, so the biggest harm is that we cache more 34 * objects certs and CRLs than we may expect, but that's ok. 35 * 36 * Specifically for OpenSSL's own file: scheme, the only workable 37 * criterion is the BY_NAME one, which it can only apply on directories, 38 * but it's possible that the URI is a single file rather than a directory, 39 * and in that case, the BY_NAME criterion is pointless. 40 * 41 * We could very simply not apply any criterion at all here, and just let 42 * the code that selects certs and CRLs from the cached objects do its job, 43 * but it's a nice optimization when it can be applied (such as on an 44 * actual directory with a thousand CA certs). 45 */ 46 if (criterion != NULL) 47 OSSL_STORE_find(ctx, criterion); 48 49 for (;;) { 50 OSSL_STORE_INFO *info = OSSL_STORE_load(ctx); 51 int infotype; 52 53 /* NULL means error or "end of file". Either way, we break. */ 54 if (info == NULL) 55 break; 56 57 infotype = OSSL_STORE_INFO_get_type(info); 58 ok = 0; 59 60 if (infotype == OSSL_STORE_INFO_NAME) { 61 /* 62 * This is an entry in the "directory" represented by the current 63 * uri. if |depth| allows, dive into it. 64 */ 65 if (depth > 0) 66 ok = cache_objects(lctx, OSSL_STORE_INFO_get0_NAME(info), 67 criterion, depth - 1, libctx, propq); 68 } else { 69 /* 70 * We know that X509_STORE_add_{cert|crl} increments the object's 71 * refcount, so we can safely use OSSL_STORE_INFO_get0_{cert,crl} 72 * to get them. 73 */ 74 switch (infotype) { 75 case OSSL_STORE_INFO_CERT: 76 ok = X509_STORE_add_cert(xstore, 77 OSSL_STORE_INFO_get0_CERT(info)); 78 break; 79 case OSSL_STORE_INFO_CRL: 80 ok = X509_STORE_add_crl(xstore, 81 OSSL_STORE_INFO_get0_CRL(info)); 82 break; 83 } 84 } 85 86 OSSL_STORE_INFO_free(info); 87 if (!ok) 88 break; 89 } 90 OSSL_STORE_close(ctx); 91 92 return ok; 93} 94 95 96/* Because OPENSSL_free is a macro and for C type match */ 97static void free_uri(OPENSSL_STRING data) 98{ 99 OPENSSL_free(data); 100} 101 102static void by_store_free(X509_LOOKUP *ctx) 103{ 104 STACK_OF(OPENSSL_STRING) *uris = X509_LOOKUP_get_method_data(ctx); 105 sk_OPENSSL_STRING_pop_free(uris, free_uri); 106} 107 108static int by_store_ctrl_ex(X509_LOOKUP *ctx, int cmd, const char *argp, 109 long argl, char **retp, OSSL_LIB_CTX *libctx, 110 const char *propq) 111{ 112 switch (cmd) { 113 case X509_L_ADD_STORE: 114 /* If no URI is given, use the default cert dir as default URI */ 115 if (argp == NULL) 116 argp = ossl_safe_getenv(X509_get_default_cert_dir_env()); 117 if (argp == NULL) 118 argp = X509_get_default_cert_dir(); 119 120 { 121 STACK_OF(OPENSSL_STRING) *uris = X509_LOOKUP_get_method_data(ctx); 122 char *data = OPENSSL_strdup(argp); 123 124 if (data == NULL) { 125 return 0; 126 } 127 if (uris == NULL) { 128 uris = sk_OPENSSL_STRING_new_null(); 129 X509_LOOKUP_set_method_data(ctx, uris); 130 } 131 return sk_OPENSSL_STRING_push(uris, data) > 0; 132 } 133 case X509_L_LOAD_STORE: 134 /* This is a shortcut for quick loading of specific containers */ 135 return cache_objects(ctx, argp, NULL, 0, libctx, propq); 136 } 137 138 return 0; 139} 140 141static int by_store_ctrl(X509_LOOKUP *ctx, int cmd, 142 const char *argp, long argl, char **retp) 143{ 144 return by_store_ctrl_ex(ctx, cmd, argp, argl, retp, NULL, NULL); 145} 146 147static int by_store(X509_LOOKUP *ctx, X509_LOOKUP_TYPE type, 148 const OSSL_STORE_SEARCH *criterion, X509_OBJECT *ret, 149 OSSL_LIB_CTX *libctx, const char *propq) 150{ 151 STACK_OF(OPENSSL_STRING) *uris = X509_LOOKUP_get_method_data(ctx); 152 int i; 153 int ok = 0; 154 155 for (i = 0; i < sk_OPENSSL_STRING_num(uris); i++) { 156 ok = cache_objects(ctx, sk_OPENSSL_STRING_value(uris, i), criterion, 157 1 /* depth */, libctx, propq); 158 159 if (ok) 160 break; 161 } 162 return ok; 163} 164 165static int by_store_subject_ex(X509_LOOKUP *ctx, X509_LOOKUP_TYPE type, 166 const X509_NAME *name, X509_OBJECT *ret, 167 OSSL_LIB_CTX *libctx, const char *propq) 168{ 169 OSSL_STORE_SEARCH *criterion = 170 OSSL_STORE_SEARCH_by_name((X509_NAME *)name); /* won't modify it */ 171 int ok = by_store(ctx, type, criterion, ret, libctx, propq); 172 STACK_OF(X509_OBJECT) *store_objects = 173 X509_STORE_get0_objects(X509_LOOKUP_get_store(ctx)); 174 X509_OBJECT *tmp = NULL; 175 176 OSSL_STORE_SEARCH_free(criterion); 177 178 if (ok) 179 tmp = X509_OBJECT_retrieve_by_subject(store_objects, type, name); 180 181 ok = 0; 182 if (tmp != NULL) { 183 /* 184 * This could also be done like this: 185 * 186 * if (tmp != NULL) { 187 * *ret = *tmp; 188 * ok = 1; 189 * } 190 * 191 * However, we want to exercise the documented API to the max, so 192 * we do it the hard way. 193 * 194 * To be noted is that X509_OBJECT_set1_* increment the refcount, 195 * but so does X509_STORE_CTX_get_by_subject upon return of this 196 * function, so we must ensure the refcount is decremented 197 * before we return, or we will get a refcount leak. We cannot do 198 * this with X509_OBJECT_free(), though, as that will free a bit 199 * too much. 200 */ 201 switch (type) { 202 case X509_LU_X509: 203 ok = X509_OBJECT_set1_X509(ret, tmp->data.x509); 204 if (ok) 205 X509_free(tmp->data.x509); 206 break; 207 case X509_LU_CRL: 208 ok = X509_OBJECT_set1_X509_CRL(ret, tmp->data.crl); 209 if (ok) 210 X509_CRL_free(tmp->data.crl); 211 break; 212 case X509_LU_NONE: 213 break; 214 } 215 } 216 return ok; 217} 218 219static int by_store_subject(X509_LOOKUP *ctx, X509_LOOKUP_TYPE type, 220 const X509_NAME *name, X509_OBJECT *ret) 221{ 222 return by_store_subject_ex(ctx, type, name, ret, NULL, NULL); 223} 224 225/* 226 * We lack the implementations for get_by_issuer_serial, get_by_fingerprint 227 * and get_by_alias. There's simply not enough support in the X509_LOOKUP 228 * or X509_STORE APIs. 229 */ 230 231static X509_LOOKUP_METHOD x509_store_lookup = { 232 "Load certs from STORE URIs", 233 NULL, /* new_item */ 234 by_store_free, /* free */ 235 NULL, /* init */ 236 NULL, /* shutdown */ 237 by_store_ctrl, /* ctrl */ 238 by_store_subject, /* get_by_subject */ 239 NULL, /* get_by_issuer_serial */ 240 NULL, /* get_by_fingerprint */ 241 NULL, /* get_by_alias */ 242 by_store_subject_ex, 243 by_store_ctrl_ex 244}; 245 246X509_LOOKUP_METHOD *X509_LOOKUP_store(void) 247{ 248 return &x509_store_lookup; 249} 250