1*b077aed3SPierre Pronchery /* 2*b077aed3SPierre Pronchery * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved. 3*b077aed3SPierre Pronchery * 4*b077aed3SPierre Pronchery * Licensed under the Apache License 2.0 (the "License"). You may not use 5*b077aed3SPierre Pronchery * this file except in compliance with the License. You can obtain a copy 6*b077aed3SPierre Pronchery * in the file LICENSE in the source distribution or at 7*b077aed3SPierre Pronchery * https://www.openssl.org/source/license.html 8*b077aed3SPierre Pronchery */ 9*b077aed3SPierre Pronchery 10*b077aed3SPierre Pronchery /* THIS ENGINE IS FOR TESTING PURPOSES ONLY. */ 11*b077aed3SPierre Pronchery 12*b077aed3SPierre Pronchery /* This file has quite some overlap with providers/implementations/storemgmt/file_store.c */ 13*b077aed3SPierre Pronchery 14*b077aed3SPierre Pronchery /* We need to use some engine deprecated APIs */ 15*b077aed3SPierre Pronchery #define OPENSSL_SUPPRESS_DEPRECATED 16*b077aed3SPierre Pronchery 17*b077aed3SPierre Pronchery #include <string.h> 18*b077aed3SPierre Pronchery #include <sys/stat.h> 19*b077aed3SPierre Pronchery #include <ctype.h> 20*b077aed3SPierre Pronchery #include <assert.h> 21*b077aed3SPierre Pronchery 22*b077aed3SPierre Pronchery #include <openssl/bio.h> 23*b077aed3SPierre Pronchery #include <openssl/dsa.h> /* For d2i_DSAPrivateKey */ 24*b077aed3SPierre Pronchery #include <openssl/err.h> 25*b077aed3SPierre Pronchery #include <openssl/evp.h> 26*b077aed3SPierre Pronchery #include <openssl/pem.h> 27*b077aed3SPierre Pronchery #include <openssl/pkcs12.h> /* For the PKCS8 stuff o.O */ 28*b077aed3SPierre Pronchery #include <openssl/rsa.h> /* For d2i_RSAPrivateKey */ 29*b077aed3SPierre Pronchery #include <openssl/safestack.h> 30*b077aed3SPierre Pronchery #include <openssl/store.h> 31*b077aed3SPierre Pronchery #include <openssl/ui.h> 32*b077aed3SPierre Pronchery #include <openssl/engine.h> 33*b077aed3SPierre Pronchery #include <openssl/x509.h> /* For the PKCS8 stuff o.O */ 34*b077aed3SPierre Pronchery #include "internal/asn1.h" /* For asn1_d2i_read_bio */ 35*b077aed3SPierre Pronchery #include "internal/o_dir.h" 36*b077aed3SPierre Pronchery #include "internal/cryptlib.h" 37*b077aed3SPierre Pronchery #include "crypto/ctype.h" /* For ossl_isdigit */ 38*b077aed3SPierre Pronchery #include "crypto/pem.h" /* For PVK and "blob" PEM headers */ 39*b077aed3SPierre Pronchery 40*b077aed3SPierre Pronchery #include "e_loader_attic_err.c" 41*b077aed3SPierre Pronchery 42*b077aed3SPierre Pronchery DEFINE_STACK_OF(OSSL_STORE_INFO) 43*b077aed3SPierre Pronchery 44*b077aed3SPierre Pronchery #ifdef _WIN32 45*b077aed3SPierre Pronchery # define stat _stat 46*b077aed3SPierre Pronchery #endif 47*b077aed3SPierre Pronchery 48*b077aed3SPierre Pronchery #ifndef S_ISDIR 49*b077aed3SPierre Pronchery # define S_ISDIR(a) (((a) & S_IFMT) == S_IFDIR) 50*b077aed3SPierre Pronchery #endif 51*b077aed3SPierre Pronchery 52*b077aed3SPierre Pronchery /*- 53*b077aed3SPierre Pronchery * Password prompting 54*b077aed3SPierre Pronchery * ------------------ 55*b077aed3SPierre Pronchery */ 56*b077aed3SPierre Pronchery 57*b077aed3SPierre Pronchery static char *file_get_pass(const UI_METHOD *ui_method, char *pass, 58*b077aed3SPierre Pronchery size_t maxsize, const char *desc, const char *info, 59*b077aed3SPierre Pronchery void *data) 60*b077aed3SPierre Pronchery { 61*b077aed3SPierre Pronchery UI *ui = UI_new(); 62*b077aed3SPierre Pronchery char *prompt = NULL; 63*b077aed3SPierre Pronchery 64*b077aed3SPierre Pronchery if (ui == NULL) { 65*b077aed3SPierre Pronchery ATTICerr(0, ERR_R_MALLOC_FAILURE); 66*b077aed3SPierre Pronchery return NULL; 67*b077aed3SPierre Pronchery } 68*b077aed3SPierre Pronchery 69*b077aed3SPierre Pronchery if (ui_method != NULL) 70*b077aed3SPierre Pronchery UI_set_method(ui, ui_method); 71*b077aed3SPierre Pronchery UI_add_user_data(ui, data); 72*b077aed3SPierre Pronchery 73*b077aed3SPierre Pronchery if ((prompt = UI_construct_prompt(ui, desc, info)) == NULL) { 74*b077aed3SPierre Pronchery ATTICerr(0, ERR_R_MALLOC_FAILURE); 75*b077aed3SPierre Pronchery pass = NULL; 76*b077aed3SPierre Pronchery } else if (UI_add_input_string(ui, prompt, UI_INPUT_FLAG_DEFAULT_PWD, 77*b077aed3SPierre Pronchery pass, 0, maxsize - 1) <= 0) { 78*b077aed3SPierre Pronchery ATTICerr(0, ERR_R_UI_LIB); 79*b077aed3SPierre Pronchery pass = NULL; 80*b077aed3SPierre Pronchery } else { 81*b077aed3SPierre Pronchery switch (UI_process(ui)) { 82*b077aed3SPierre Pronchery case -2: 83*b077aed3SPierre Pronchery ATTICerr(0, ATTIC_R_UI_PROCESS_INTERRUPTED_OR_CANCELLED); 84*b077aed3SPierre Pronchery pass = NULL; 85*b077aed3SPierre Pronchery break; 86*b077aed3SPierre Pronchery case -1: 87*b077aed3SPierre Pronchery ATTICerr(0, ERR_R_UI_LIB); 88*b077aed3SPierre Pronchery pass = NULL; 89*b077aed3SPierre Pronchery break; 90*b077aed3SPierre Pronchery default: 91*b077aed3SPierre Pronchery break; 92*b077aed3SPierre Pronchery } 93*b077aed3SPierre Pronchery } 94*b077aed3SPierre Pronchery 95*b077aed3SPierre Pronchery OPENSSL_free(prompt); 96*b077aed3SPierre Pronchery UI_free(ui); 97*b077aed3SPierre Pronchery return pass; 98*b077aed3SPierre Pronchery } 99*b077aed3SPierre Pronchery 100*b077aed3SPierre Pronchery struct pem_pass_data { 101*b077aed3SPierre Pronchery const UI_METHOD *ui_method; 102*b077aed3SPierre Pronchery void *data; 103*b077aed3SPierre Pronchery const char *prompt_desc; 104*b077aed3SPierre Pronchery const char *prompt_info; 105*b077aed3SPierre Pronchery }; 106*b077aed3SPierre Pronchery 107*b077aed3SPierre Pronchery static int file_fill_pem_pass_data(struct pem_pass_data *pass_data, 108*b077aed3SPierre Pronchery const char *desc, const char *info, 109*b077aed3SPierre Pronchery const UI_METHOD *ui_method, void *ui_data) 110*b077aed3SPierre Pronchery { 111*b077aed3SPierre Pronchery if (pass_data == NULL) 112*b077aed3SPierre Pronchery return 0; 113*b077aed3SPierre Pronchery pass_data->ui_method = ui_method; 114*b077aed3SPierre Pronchery pass_data->data = ui_data; 115*b077aed3SPierre Pronchery pass_data->prompt_desc = desc; 116*b077aed3SPierre Pronchery pass_data->prompt_info = info; 117*b077aed3SPierre Pronchery return 1; 118*b077aed3SPierre Pronchery } 119*b077aed3SPierre Pronchery 120*b077aed3SPierre Pronchery /* This is used anywhere a pem_password_cb is needed */ 121*b077aed3SPierre Pronchery static int file_get_pem_pass(char *buf, int num, int w, void *data) 122*b077aed3SPierre Pronchery { 123*b077aed3SPierre Pronchery struct pem_pass_data *pass_data = data; 124*b077aed3SPierre Pronchery char *pass = file_get_pass(pass_data->ui_method, buf, num, 125*b077aed3SPierre Pronchery pass_data->prompt_desc, pass_data->prompt_info, 126*b077aed3SPierre Pronchery pass_data->data); 127*b077aed3SPierre Pronchery 128*b077aed3SPierre Pronchery return pass == NULL ? 0 : strlen(pass); 129*b077aed3SPierre Pronchery } 130*b077aed3SPierre Pronchery 131*b077aed3SPierre Pronchery /* 132*b077aed3SPierre Pronchery * Check if |str| ends with |suffix| preceded by a space, and if it does, 133*b077aed3SPierre Pronchery * return the index of that space. If there is no such suffix in |str|, 134*b077aed3SPierre Pronchery * return -1. 135*b077aed3SPierre Pronchery * For |str| == "FOO BAR" and |suffix| == "BAR", the returned value is 3. 136*b077aed3SPierre Pronchery */ 137*b077aed3SPierre Pronchery static int check_suffix(const char *str, const char *suffix) 138*b077aed3SPierre Pronchery { 139*b077aed3SPierre Pronchery int str_len = strlen(str); 140*b077aed3SPierre Pronchery int suffix_len = strlen(suffix) + 1; 141*b077aed3SPierre Pronchery const char *p = NULL; 142*b077aed3SPierre Pronchery 143*b077aed3SPierre Pronchery if (suffix_len >= str_len) 144*b077aed3SPierre Pronchery return -1; 145*b077aed3SPierre Pronchery p = str + str_len - suffix_len; 146*b077aed3SPierre Pronchery if (*p != ' ' 147*b077aed3SPierre Pronchery || strcmp(p + 1, suffix) != 0) 148*b077aed3SPierre Pronchery return -1; 149*b077aed3SPierre Pronchery return p - str; 150*b077aed3SPierre Pronchery } 151*b077aed3SPierre Pronchery 152*b077aed3SPierre Pronchery /* 153*b077aed3SPierre Pronchery * EMBEDDED is a special type of OSSL_STORE_INFO, specially for the file 154*b077aed3SPierre Pronchery * handlers, so we define it internally. This uses the possibility to 155*b077aed3SPierre Pronchery * create an OSSL_STORE_INFO with a generic data pointer and arbitrary 156*b077aed3SPierre Pronchery * type number. 157*b077aed3SPierre Pronchery * 158*b077aed3SPierre Pronchery * This is used by a FILE_HANDLER's try_decode function to signal that it 159*b077aed3SPierre Pronchery * has decoded the incoming blob into a new blob, and that the attempted 160*b077aed3SPierre Pronchery * decoding should be immediately restarted with the new blob, using the 161*b077aed3SPierre Pronchery * new PEM name. 162*b077aed3SPierre Pronchery */ 163*b077aed3SPierre Pronchery /* Negative numbers are never used for public OSSL_STORE_INFO types */ 164*b077aed3SPierre Pronchery #define STORE_INFO_EMBEDDED -1 165*b077aed3SPierre Pronchery 166*b077aed3SPierre Pronchery /* This is the embedded data */ 167*b077aed3SPierre Pronchery struct embedded_st { 168*b077aed3SPierre Pronchery BUF_MEM *blob; 169*b077aed3SPierre Pronchery char *pem_name; 170*b077aed3SPierre Pronchery }; 171*b077aed3SPierre Pronchery 172*b077aed3SPierre Pronchery /* Helper functions */ 173*b077aed3SPierre Pronchery static struct embedded_st *get0_EMBEDDED(OSSL_STORE_INFO *info) 174*b077aed3SPierre Pronchery { 175*b077aed3SPierre Pronchery return OSSL_STORE_INFO_get0_data(STORE_INFO_EMBEDDED, info); 176*b077aed3SPierre Pronchery } 177*b077aed3SPierre Pronchery 178*b077aed3SPierre Pronchery static void store_info_free(OSSL_STORE_INFO *info) 179*b077aed3SPierre Pronchery { 180*b077aed3SPierre Pronchery struct embedded_st *data; 181*b077aed3SPierre Pronchery 182*b077aed3SPierre Pronchery if (info != NULL && (data = get0_EMBEDDED(info)) != NULL) { 183*b077aed3SPierre Pronchery BUF_MEM_free(data->blob); 184*b077aed3SPierre Pronchery OPENSSL_free(data->pem_name); 185*b077aed3SPierre Pronchery OPENSSL_free(data); 186*b077aed3SPierre Pronchery } 187*b077aed3SPierre Pronchery OSSL_STORE_INFO_free(info); 188*b077aed3SPierre Pronchery } 189*b077aed3SPierre Pronchery 190*b077aed3SPierre Pronchery static OSSL_STORE_INFO *new_EMBEDDED(const char *new_pem_name, 191*b077aed3SPierre Pronchery BUF_MEM *embedded) 192*b077aed3SPierre Pronchery { 193*b077aed3SPierre Pronchery OSSL_STORE_INFO *info = NULL; 194*b077aed3SPierre Pronchery struct embedded_st *data = NULL; 195*b077aed3SPierre Pronchery 196*b077aed3SPierre Pronchery if ((data = OPENSSL_zalloc(sizeof(*data))) == NULL 197*b077aed3SPierre Pronchery || (info = OSSL_STORE_INFO_new(STORE_INFO_EMBEDDED, data)) == NULL) { 198*b077aed3SPierre Pronchery ATTICerr(0, ERR_R_MALLOC_FAILURE); 199*b077aed3SPierre Pronchery OPENSSL_free(data); 200*b077aed3SPierre Pronchery return NULL; 201*b077aed3SPierre Pronchery } 202*b077aed3SPierre Pronchery 203*b077aed3SPierre Pronchery data->blob = embedded; 204*b077aed3SPierre Pronchery data->pem_name = 205*b077aed3SPierre Pronchery new_pem_name == NULL ? NULL : OPENSSL_strdup(new_pem_name); 206*b077aed3SPierre Pronchery 207*b077aed3SPierre Pronchery if (new_pem_name != NULL && data->pem_name == NULL) { 208*b077aed3SPierre Pronchery ATTICerr(0, ERR_R_MALLOC_FAILURE); 209*b077aed3SPierre Pronchery store_info_free(info); 210*b077aed3SPierre Pronchery info = NULL; 211*b077aed3SPierre Pronchery } 212*b077aed3SPierre Pronchery 213*b077aed3SPierre Pronchery return info; 214*b077aed3SPierre Pronchery } 215*b077aed3SPierre Pronchery 216*b077aed3SPierre Pronchery /*- 217*b077aed3SPierre Pronchery * The file scheme decoders 218*b077aed3SPierre Pronchery * ------------------------ 219*b077aed3SPierre Pronchery * 220*b077aed3SPierre Pronchery * Each possible data type has its own decoder, which either operates 221*b077aed3SPierre Pronchery * through a given PEM name, or attempts to decode to see if the blob 222*b077aed3SPierre Pronchery * it's given is decodable for its data type. The assumption is that 223*b077aed3SPierre Pronchery * only the correct data type will match the content. 224*b077aed3SPierre Pronchery */ 225*b077aed3SPierre Pronchery 226*b077aed3SPierre Pronchery /*- 227*b077aed3SPierre Pronchery * The try_decode function is called to check if the blob of data can 228*b077aed3SPierre Pronchery * be used by this handler, and if it can, decodes it into a supported 229*b077aed3SPierre Pronchery * OpenSSL type and returns a OSSL_STORE_INFO with the decoded data. 230*b077aed3SPierre Pronchery * Input: 231*b077aed3SPierre Pronchery * pem_name: If this blob comes from a PEM file, this holds 232*b077aed3SPierre Pronchery * the PEM name. If it comes from another type of 233*b077aed3SPierre Pronchery * file, this is NULL. 234*b077aed3SPierre Pronchery * pem_header: If this blob comes from a PEM file, this holds 235*b077aed3SPierre Pronchery * the PEM headers. If it comes from another type of 236*b077aed3SPierre Pronchery * file, this is NULL. 237*b077aed3SPierre Pronchery * blob: The blob of data to match with what this handler 238*b077aed3SPierre Pronchery * can use. 239*b077aed3SPierre Pronchery * len: The length of the blob. 240*b077aed3SPierre Pronchery * handler_ctx: For a handler marked repeatable, this pointer can 241*b077aed3SPierre Pronchery * be used to create a context for the handler. IT IS 242*b077aed3SPierre Pronchery * THE HANDLER'S RESPONSIBILITY TO CREATE AND DESTROY 243*b077aed3SPierre Pronchery * THIS CONTEXT APPROPRIATELY, i.e. create on first call 244*b077aed3SPierre Pronchery * and destroy when about to return NULL. 245*b077aed3SPierre Pronchery * matchcount: A pointer to an int to count matches for this data. 246*b077aed3SPierre Pronchery * Usually becomes 0 (no match) or 1 (match!), but may 247*b077aed3SPierre Pronchery * be higher in the (unlikely) event that the data matches 248*b077aed3SPierre Pronchery * more than one possibility. The int will always be 249*b077aed3SPierre Pronchery * zero when the function is called. 250*b077aed3SPierre Pronchery * ui_method: Application UI method for getting a password, pin 251*b077aed3SPierre Pronchery * or any other interactive data. 252*b077aed3SPierre Pronchery * ui_data: Application data to be passed to ui_method when 253*b077aed3SPierre Pronchery * it's called. 254*b077aed3SPierre Pronchery * libctx: The library context to be used if applicable 255*b077aed3SPierre Pronchery * propq: The property query string for any algorithm fetches 256*b077aed3SPierre Pronchery * Output: 257*b077aed3SPierre Pronchery * a OSSL_STORE_INFO 258*b077aed3SPierre Pronchery */ 259*b077aed3SPierre Pronchery typedef OSSL_STORE_INFO *(*file_try_decode_fn)(const char *pem_name, 260*b077aed3SPierre Pronchery const char *pem_header, 261*b077aed3SPierre Pronchery const unsigned char *blob, 262*b077aed3SPierre Pronchery size_t len, void **handler_ctx, 263*b077aed3SPierre Pronchery int *matchcount, 264*b077aed3SPierre Pronchery const UI_METHOD *ui_method, 265*b077aed3SPierre Pronchery void *ui_data, const char *uri, 266*b077aed3SPierre Pronchery OSSL_LIB_CTX *libctx, 267*b077aed3SPierre Pronchery const char *propq); 268*b077aed3SPierre Pronchery /* 269*b077aed3SPierre Pronchery * The eof function should return 1 if there's no more data to be found 270*b077aed3SPierre Pronchery * with the handler_ctx, otherwise 0. This is only used when the handler is 271*b077aed3SPierre Pronchery * marked repeatable. 272*b077aed3SPierre Pronchery */ 273*b077aed3SPierre Pronchery typedef int (*file_eof_fn)(void *handler_ctx); 274*b077aed3SPierre Pronchery /* 275*b077aed3SPierre Pronchery * The destroy_ctx function is used to destroy the handler_ctx that was 276*b077aed3SPierre Pronchery * initiated by a repeatable try_decode function. This is only used when 277*b077aed3SPierre Pronchery * the handler is marked repeatable. 278*b077aed3SPierre Pronchery */ 279*b077aed3SPierre Pronchery typedef void (*file_destroy_ctx_fn)(void **handler_ctx); 280*b077aed3SPierre Pronchery 281*b077aed3SPierre Pronchery typedef struct file_handler_st { 282*b077aed3SPierre Pronchery const char *name; 283*b077aed3SPierre Pronchery file_try_decode_fn try_decode; 284*b077aed3SPierre Pronchery file_eof_fn eof; 285*b077aed3SPierre Pronchery file_destroy_ctx_fn destroy_ctx; 286*b077aed3SPierre Pronchery 287*b077aed3SPierre Pronchery /* flags */ 288*b077aed3SPierre Pronchery int repeatable; 289*b077aed3SPierre Pronchery } FILE_HANDLER; 290*b077aed3SPierre Pronchery 291*b077aed3SPierre Pronchery /* 292*b077aed3SPierre Pronchery * PKCS#12 decoder. It operates by decoding all of the blob content, 293*b077aed3SPierre Pronchery * extracting all the interesting data from it and storing them internally, 294*b077aed3SPierre Pronchery * then serving them one piece at a time. 295*b077aed3SPierre Pronchery */ 296*b077aed3SPierre Pronchery static OSSL_STORE_INFO *try_decode_PKCS12(const char *pem_name, 297*b077aed3SPierre Pronchery const char *pem_header, 298*b077aed3SPierre Pronchery const unsigned char *blob, 299*b077aed3SPierre Pronchery size_t len, void **pctx, 300*b077aed3SPierre Pronchery int *matchcount, 301*b077aed3SPierre Pronchery const UI_METHOD *ui_method, 302*b077aed3SPierre Pronchery void *ui_data, const char *uri, 303*b077aed3SPierre Pronchery OSSL_LIB_CTX *libctx, 304*b077aed3SPierre Pronchery const char *propq) 305*b077aed3SPierre Pronchery { 306*b077aed3SPierre Pronchery OSSL_STORE_INFO *store_info = NULL; 307*b077aed3SPierre Pronchery STACK_OF(OSSL_STORE_INFO) *ctx = *pctx; 308*b077aed3SPierre Pronchery 309*b077aed3SPierre Pronchery if (ctx == NULL) { 310*b077aed3SPierre Pronchery /* Initial parsing */ 311*b077aed3SPierre Pronchery PKCS12 *p12; 312*b077aed3SPierre Pronchery 313*b077aed3SPierre Pronchery if (pem_name != NULL) 314*b077aed3SPierre Pronchery /* No match, there is no PEM PKCS12 tag */ 315*b077aed3SPierre Pronchery return NULL; 316*b077aed3SPierre Pronchery 317*b077aed3SPierre Pronchery if ((p12 = d2i_PKCS12(NULL, &blob, len)) != NULL) { 318*b077aed3SPierre Pronchery char *pass = NULL; 319*b077aed3SPierre Pronchery char tpass[PEM_BUFSIZE]; 320*b077aed3SPierre Pronchery EVP_PKEY *pkey = NULL; 321*b077aed3SPierre Pronchery X509 *cert = NULL; 322*b077aed3SPierre Pronchery STACK_OF(X509) *chain = NULL; 323*b077aed3SPierre Pronchery 324*b077aed3SPierre Pronchery *matchcount = 1; 325*b077aed3SPierre Pronchery 326*b077aed3SPierre Pronchery if (!PKCS12_mac_present(p12) 327*b077aed3SPierre Pronchery || PKCS12_verify_mac(p12, "", 0) 328*b077aed3SPierre Pronchery || PKCS12_verify_mac(p12, NULL, 0)) { 329*b077aed3SPierre Pronchery pass = ""; 330*b077aed3SPierre Pronchery } else { 331*b077aed3SPierre Pronchery if ((pass = file_get_pass(ui_method, tpass, PEM_BUFSIZE, 332*b077aed3SPierre Pronchery "PKCS12 import", uri, 333*b077aed3SPierre Pronchery ui_data)) == NULL) { 334*b077aed3SPierre Pronchery ATTICerr(0, ATTIC_R_PASSPHRASE_CALLBACK_ERROR); 335*b077aed3SPierre Pronchery goto p12_end; 336*b077aed3SPierre Pronchery } 337*b077aed3SPierre Pronchery if (!PKCS12_verify_mac(p12, pass, strlen(pass))) { 338*b077aed3SPierre Pronchery ATTICerr(0, ATTIC_R_ERROR_VERIFYING_PKCS12_MAC); 339*b077aed3SPierre Pronchery goto p12_end; 340*b077aed3SPierre Pronchery } 341*b077aed3SPierre Pronchery } 342*b077aed3SPierre Pronchery 343*b077aed3SPierre Pronchery if (PKCS12_parse(p12, pass, &pkey, &cert, &chain)) { 344*b077aed3SPierre Pronchery OSSL_STORE_INFO *osi_pkey = NULL; 345*b077aed3SPierre Pronchery OSSL_STORE_INFO *osi_cert = NULL; 346*b077aed3SPierre Pronchery OSSL_STORE_INFO *osi_ca = NULL; 347*b077aed3SPierre Pronchery int ok = 1; 348*b077aed3SPierre Pronchery 349*b077aed3SPierre Pronchery if ((ctx = sk_OSSL_STORE_INFO_new_null()) != NULL) { 350*b077aed3SPierre Pronchery if (pkey != NULL) { 351*b077aed3SPierre Pronchery if ((osi_pkey = OSSL_STORE_INFO_new_PKEY(pkey)) != NULL 352*b077aed3SPierre Pronchery /* clearing pkey here avoids case distinctions */ 353*b077aed3SPierre Pronchery && (pkey = NULL) == NULL 354*b077aed3SPierre Pronchery && sk_OSSL_STORE_INFO_push(ctx, osi_pkey) != 0) 355*b077aed3SPierre Pronchery osi_pkey = NULL; 356*b077aed3SPierre Pronchery else 357*b077aed3SPierre Pronchery ok = 0; 358*b077aed3SPierre Pronchery } 359*b077aed3SPierre Pronchery if (ok && cert != NULL) { 360*b077aed3SPierre Pronchery if ((osi_cert = OSSL_STORE_INFO_new_CERT(cert)) != NULL 361*b077aed3SPierre Pronchery /* clearing cert here avoids case distinctions */ 362*b077aed3SPierre Pronchery && (cert = NULL) == NULL 363*b077aed3SPierre Pronchery && sk_OSSL_STORE_INFO_push(ctx, osi_cert) != 0) 364*b077aed3SPierre Pronchery osi_cert = NULL; 365*b077aed3SPierre Pronchery else 366*b077aed3SPierre Pronchery ok = 0; 367*b077aed3SPierre Pronchery } 368*b077aed3SPierre Pronchery while (ok && sk_X509_num(chain) > 0) { 369*b077aed3SPierre Pronchery X509 *ca = sk_X509_value(chain, 0); 370*b077aed3SPierre Pronchery 371*b077aed3SPierre Pronchery if ((osi_ca = OSSL_STORE_INFO_new_CERT(ca)) != NULL 372*b077aed3SPierre Pronchery && sk_X509_shift(chain) != NULL 373*b077aed3SPierre Pronchery && sk_OSSL_STORE_INFO_push(ctx, osi_ca) != 0) 374*b077aed3SPierre Pronchery osi_ca = NULL; 375*b077aed3SPierre Pronchery else 376*b077aed3SPierre Pronchery ok = 0; 377*b077aed3SPierre Pronchery } 378*b077aed3SPierre Pronchery } 379*b077aed3SPierre Pronchery EVP_PKEY_free(pkey); 380*b077aed3SPierre Pronchery X509_free(cert); 381*b077aed3SPierre Pronchery sk_X509_pop_free(chain, X509_free); 382*b077aed3SPierre Pronchery store_info_free(osi_pkey); 383*b077aed3SPierre Pronchery store_info_free(osi_cert); 384*b077aed3SPierre Pronchery store_info_free(osi_ca); 385*b077aed3SPierre Pronchery if (!ok) { 386*b077aed3SPierre Pronchery sk_OSSL_STORE_INFO_pop_free(ctx, store_info_free); 387*b077aed3SPierre Pronchery ctx = NULL; 388*b077aed3SPierre Pronchery } 389*b077aed3SPierre Pronchery *pctx = ctx; 390*b077aed3SPierre Pronchery } 391*b077aed3SPierre Pronchery } 392*b077aed3SPierre Pronchery p12_end: 393*b077aed3SPierre Pronchery PKCS12_free(p12); 394*b077aed3SPierre Pronchery if (ctx == NULL) 395*b077aed3SPierre Pronchery return NULL; 396*b077aed3SPierre Pronchery } 397*b077aed3SPierre Pronchery 398*b077aed3SPierre Pronchery *matchcount = 1; 399*b077aed3SPierre Pronchery store_info = sk_OSSL_STORE_INFO_shift(ctx); 400*b077aed3SPierre Pronchery return store_info; 401*b077aed3SPierre Pronchery } 402*b077aed3SPierre Pronchery 403*b077aed3SPierre Pronchery static int eof_PKCS12(void *ctx_) 404*b077aed3SPierre Pronchery { 405*b077aed3SPierre Pronchery STACK_OF(OSSL_STORE_INFO) *ctx = ctx_; 406*b077aed3SPierre Pronchery 407*b077aed3SPierre Pronchery return ctx == NULL || sk_OSSL_STORE_INFO_num(ctx) == 0; 408*b077aed3SPierre Pronchery } 409*b077aed3SPierre Pronchery 410*b077aed3SPierre Pronchery static void destroy_ctx_PKCS12(void **pctx) 411*b077aed3SPierre Pronchery { 412*b077aed3SPierre Pronchery STACK_OF(OSSL_STORE_INFO) *ctx = *pctx; 413*b077aed3SPierre Pronchery 414*b077aed3SPierre Pronchery sk_OSSL_STORE_INFO_pop_free(ctx, store_info_free); 415*b077aed3SPierre Pronchery *pctx = NULL; 416*b077aed3SPierre Pronchery } 417*b077aed3SPierre Pronchery 418*b077aed3SPierre Pronchery static FILE_HANDLER PKCS12_handler = { 419*b077aed3SPierre Pronchery "PKCS12", 420*b077aed3SPierre Pronchery try_decode_PKCS12, 421*b077aed3SPierre Pronchery eof_PKCS12, 422*b077aed3SPierre Pronchery destroy_ctx_PKCS12, 423*b077aed3SPierre Pronchery 1 /* repeatable */ 424*b077aed3SPierre Pronchery }; 425*b077aed3SPierre Pronchery 426*b077aed3SPierre Pronchery /* 427*b077aed3SPierre Pronchery * Encrypted PKCS#8 decoder. It operates by just decrypting the given blob 428*b077aed3SPierre Pronchery * into a new blob, which is returned as an EMBEDDED STORE_INFO. The whole 429*b077aed3SPierre Pronchery * decoding process will then start over with the new blob. 430*b077aed3SPierre Pronchery */ 431*b077aed3SPierre Pronchery static OSSL_STORE_INFO *try_decode_PKCS8Encrypted(const char *pem_name, 432*b077aed3SPierre Pronchery const char *pem_header, 433*b077aed3SPierre Pronchery const unsigned char *blob, 434*b077aed3SPierre Pronchery size_t len, void **pctx, 435*b077aed3SPierre Pronchery int *matchcount, 436*b077aed3SPierre Pronchery const UI_METHOD *ui_method, 437*b077aed3SPierre Pronchery void *ui_data, 438*b077aed3SPierre Pronchery const char *uri, 439*b077aed3SPierre Pronchery OSSL_LIB_CTX *libctx, 440*b077aed3SPierre Pronchery const char *propq) 441*b077aed3SPierre Pronchery { 442*b077aed3SPierre Pronchery X509_SIG *p8 = NULL; 443*b077aed3SPierre Pronchery char kbuf[PEM_BUFSIZE]; 444*b077aed3SPierre Pronchery char *pass = NULL; 445*b077aed3SPierre Pronchery const X509_ALGOR *dalg = NULL; 446*b077aed3SPierre Pronchery const ASN1_OCTET_STRING *doct = NULL; 447*b077aed3SPierre Pronchery OSSL_STORE_INFO *store_info = NULL; 448*b077aed3SPierre Pronchery BUF_MEM *mem = NULL; 449*b077aed3SPierre Pronchery unsigned char *new_data = NULL; 450*b077aed3SPierre Pronchery int new_data_len; 451*b077aed3SPierre Pronchery 452*b077aed3SPierre Pronchery if (pem_name != NULL) { 453*b077aed3SPierre Pronchery if (strcmp(pem_name, PEM_STRING_PKCS8) != 0) 454*b077aed3SPierre Pronchery return NULL; 455*b077aed3SPierre Pronchery *matchcount = 1; 456*b077aed3SPierre Pronchery } 457*b077aed3SPierre Pronchery 458*b077aed3SPierre Pronchery if ((p8 = d2i_X509_SIG(NULL, &blob, len)) == NULL) 459*b077aed3SPierre Pronchery return NULL; 460*b077aed3SPierre Pronchery 461*b077aed3SPierre Pronchery *matchcount = 1; 462*b077aed3SPierre Pronchery 463*b077aed3SPierre Pronchery if ((mem = BUF_MEM_new()) == NULL) { 464*b077aed3SPierre Pronchery ATTICerr(0, ERR_R_MALLOC_FAILURE); 465*b077aed3SPierre Pronchery goto nop8; 466*b077aed3SPierre Pronchery } 467*b077aed3SPierre Pronchery 468*b077aed3SPierre Pronchery if ((pass = file_get_pass(ui_method, kbuf, PEM_BUFSIZE, 469*b077aed3SPierre Pronchery "PKCS8 decrypt pass phrase", uri, 470*b077aed3SPierre Pronchery ui_data)) == NULL) { 471*b077aed3SPierre Pronchery ATTICerr(0, ATTIC_R_BAD_PASSWORD_READ); 472*b077aed3SPierre Pronchery goto nop8; 473*b077aed3SPierre Pronchery } 474*b077aed3SPierre Pronchery 475*b077aed3SPierre Pronchery X509_SIG_get0(p8, &dalg, &doct); 476*b077aed3SPierre Pronchery if (!PKCS12_pbe_crypt(dalg, pass, strlen(pass), doct->data, doct->length, 477*b077aed3SPierre Pronchery &new_data, &new_data_len, 0)) 478*b077aed3SPierre Pronchery goto nop8; 479*b077aed3SPierre Pronchery 480*b077aed3SPierre Pronchery mem->data = (char *)new_data; 481*b077aed3SPierre Pronchery mem->max = mem->length = (size_t)new_data_len; 482*b077aed3SPierre Pronchery X509_SIG_free(p8); 483*b077aed3SPierre Pronchery p8 = NULL; 484*b077aed3SPierre Pronchery 485*b077aed3SPierre Pronchery store_info = new_EMBEDDED(PEM_STRING_PKCS8INF, mem); 486*b077aed3SPierre Pronchery if (store_info == NULL) { 487*b077aed3SPierre Pronchery ATTICerr(0, ERR_R_MALLOC_FAILURE); 488*b077aed3SPierre Pronchery goto nop8; 489*b077aed3SPierre Pronchery } 490*b077aed3SPierre Pronchery 491*b077aed3SPierre Pronchery return store_info; 492*b077aed3SPierre Pronchery nop8: 493*b077aed3SPierre Pronchery X509_SIG_free(p8); 494*b077aed3SPierre Pronchery BUF_MEM_free(mem); 495*b077aed3SPierre Pronchery return NULL; 496*b077aed3SPierre Pronchery } 497*b077aed3SPierre Pronchery 498*b077aed3SPierre Pronchery static FILE_HANDLER PKCS8Encrypted_handler = { 499*b077aed3SPierre Pronchery "PKCS8Encrypted", 500*b077aed3SPierre Pronchery try_decode_PKCS8Encrypted 501*b077aed3SPierre Pronchery }; 502*b077aed3SPierre Pronchery 503*b077aed3SPierre Pronchery /* 504*b077aed3SPierre Pronchery * Private key decoder. Decodes all sorts of private keys, both PKCS#8 505*b077aed3SPierre Pronchery * encoded ones and old style PEM ones (with the key type is encoded into 506*b077aed3SPierre Pronchery * the PEM name). 507*b077aed3SPierre Pronchery */ 508*b077aed3SPierre Pronchery static OSSL_STORE_INFO *try_decode_PrivateKey(const char *pem_name, 509*b077aed3SPierre Pronchery const char *pem_header, 510*b077aed3SPierre Pronchery const unsigned char *blob, 511*b077aed3SPierre Pronchery size_t len, void **pctx, 512*b077aed3SPierre Pronchery int *matchcount, 513*b077aed3SPierre Pronchery const UI_METHOD *ui_method, 514*b077aed3SPierre Pronchery void *ui_data, const char *uri, 515*b077aed3SPierre Pronchery OSSL_LIB_CTX *libctx, 516*b077aed3SPierre Pronchery const char *propq) 517*b077aed3SPierre Pronchery { 518*b077aed3SPierre Pronchery OSSL_STORE_INFO *store_info = NULL; 519*b077aed3SPierre Pronchery EVP_PKEY *pkey = NULL; 520*b077aed3SPierre Pronchery const EVP_PKEY_ASN1_METHOD *ameth = NULL; 521*b077aed3SPierre Pronchery 522*b077aed3SPierre Pronchery if (pem_name != NULL) { 523*b077aed3SPierre Pronchery if (strcmp(pem_name, PEM_STRING_PKCS8INF) == 0) { 524*b077aed3SPierre Pronchery PKCS8_PRIV_KEY_INFO *p8inf = 525*b077aed3SPierre Pronchery d2i_PKCS8_PRIV_KEY_INFO(NULL, &blob, len); 526*b077aed3SPierre Pronchery 527*b077aed3SPierre Pronchery *matchcount = 1; 528*b077aed3SPierre Pronchery if (p8inf != NULL) 529*b077aed3SPierre Pronchery pkey = EVP_PKCS82PKEY_ex(p8inf, libctx, propq); 530*b077aed3SPierre Pronchery PKCS8_PRIV_KEY_INFO_free(p8inf); 531*b077aed3SPierre Pronchery } else { 532*b077aed3SPierre Pronchery int slen; 533*b077aed3SPierre Pronchery int pkey_id; 534*b077aed3SPierre Pronchery 535*b077aed3SPierre Pronchery if ((slen = check_suffix(pem_name, "PRIVATE KEY")) > 0 536*b077aed3SPierre Pronchery && (ameth = EVP_PKEY_asn1_find_str(NULL, pem_name, 537*b077aed3SPierre Pronchery slen)) != NULL 538*b077aed3SPierre Pronchery && EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, 539*b077aed3SPierre Pronchery ameth)) { 540*b077aed3SPierre Pronchery *matchcount = 1; 541*b077aed3SPierre Pronchery pkey = d2i_PrivateKey_ex(pkey_id, NULL, &blob, len, 542*b077aed3SPierre Pronchery libctx, propq); 543*b077aed3SPierre Pronchery } 544*b077aed3SPierre Pronchery } 545*b077aed3SPierre Pronchery } else { 546*b077aed3SPierre Pronchery int i; 547*b077aed3SPierre Pronchery #ifndef OPENSSL_NO_ENGINE 548*b077aed3SPierre Pronchery ENGINE *curengine = ENGINE_get_first(); 549*b077aed3SPierre Pronchery 550*b077aed3SPierre Pronchery while (curengine != NULL) { 551*b077aed3SPierre Pronchery ENGINE_PKEY_ASN1_METHS_PTR asn1meths = 552*b077aed3SPierre Pronchery ENGINE_get_pkey_asn1_meths(curengine); 553*b077aed3SPierre Pronchery 554*b077aed3SPierre Pronchery if (asn1meths != NULL) { 555*b077aed3SPierre Pronchery const int *nids = NULL; 556*b077aed3SPierre Pronchery int nids_n = asn1meths(curengine, NULL, &nids, 0); 557*b077aed3SPierre Pronchery 558*b077aed3SPierre Pronchery for (i = 0; i < nids_n; i++) { 559*b077aed3SPierre Pronchery EVP_PKEY_ASN1_METHOD *ameth2 = NULL; 560*b077aed3SPierre Pronchery EVP_PKEY *tmp_pkey = NULL; 561*b077aed3SPierre Pronchery const unsigned char *tmp_blob = blob; 562*b077aed3SPierre Pronchery int pkey_id, pkey_flags; 563*b077aed3SPierre Pronchery 564*b077aed3SPierre Pronchery if (!asn1meths(curengine, &ameth2, NULL, nids[i]) 565*b077aed3SPierre Pronchery || !EVP_PKEY_asn1_get0_info(&pkey_id, NULL, 566*b077aed3SPierre Pronchery &pkey_flags, NULL, NULL, 567*b077aed3SPierre Pronchery ameth2) 568*b077aed3SPierre Pronchery || (pkey_flags & ASN1_PKEY_ALIAS) != 0) 569*b077aed3SPierre Pronchery continue; 570*b077aed3SPierre Pronchery 571*b077aed3SPierre Pronchery ERR_set_mark(); /* prevent flooding error queue */ 572*b077aed3SPierre Pronchery tmp_pkey = d2i_PrivateKey_ex(pkey_id, NULL, 573*b077aed3SPierre Pronchery &tmp_blob, len, 574*b077aed3SPierre Pronchery libctx, propq); 575*b077aed3SPierre Pronchery if (tmp_pkey != NULL) { 576*b077aed3SPierre Pronchery if (pkey != NULL) 577*b077aed3SPierre Pronchery EVP_PKEY_free(tmp_pkey); 578*b077aed3SPierre Pronchery else 579*b077aed3SPierre Pronchery pkey = tmp_pkey; 580*b077aed3SPierre Pronchery (*matchcount)++; 581*b077aed3SPierre Pronchery } 582*b077aed3SPierre Pronchery ERR_pop_to_mark(); 583*b077aed3SPierre Pronchery } 584*b077aed3SPierre Pronchery } 585*b077aed3SPierre Pronchery curengine = ENGINE_get_next(curengine); 586*b077aed3SPierre Pronchery } 587*b077aed3SPierre Pronchery #endif 588*b077aed3SPierre Pronchery 589*b077aed3SPierre Pronchery for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) { 590*b077aed3SPierre Pronchery EVP_PKEY *tmp_pkey = NULL; 591*b077aed3SPierre Pronchery const unsigned char *tmp_blob = blob; 592*b077aed3SPierre Pronchery int pkey_id, pkey_flags; 593*b077aed3SPierre Pronchery 594*b077aed3SPierre Pronchery ameth = EVP_PKEY_asn1_get0(i); 595*b077aed3SPierre Pronchery if (!EVP_PKEY_asn1_get0_info(&pkey_id, NULL, &pkey_flags, NULL, 596*b077aed3SPierre Pronchery NULL, ameth) 597*b077aed3SPierre Pronchery || (pkey_flags & ASN1_PKEY_ALIAS) != 0) 598*b077aed3SPierre Pronchery continue; 599*b077aed3SPierre Pronchery 600*b077aed3SPierre Pronchery ERR_set_mark(); /* prevent flooding error queue */ 601*b077aed3SPierre Pronchery tmp_pkey = d2i_PrivateKey_ex(pkey_id, NULL, &tmp_blob, len, 602*b077aed3SPierre Pronchery libctx, propq); 603*b077aed3SPierre Pronchery if (tmp_pkey != NULL) { 604*b077aed3SPierre Pronchery if (pkey != NULL) 605*b077aed3SPierre Pronchery EVP_PKEY_free(tmp_pkey); 606*b077aed3SPierre Pronchery else 607*b077aed3SPierre Pronchery pkey = tmp_pkey; 608*b077aed3SPierre Pronchery (*matchcount)++; 609*b077aed3SPierre Pronchery } 610*b077aed3SPierre Pronchery ERR_pop_to_mark(); 611*b077aed3SPierre Pronchery } 612*b077aed3SPierre Pronchery 613*b077aed3SPierre Pronchery if (*matchcount > 1) { 614*b077aed3SPierre Pronchery EVP_PKEY_free(pkey); 615*b077aed3SPierre Pronchery pkey = NULL; 616*b077aed3SPierre Pronchery } 617*b077aed3SPierre Pronchery } 618*b077aed3SPierre Pronchery if (pkey == NULL) 619*b077aed3SPierre Pronchery /* No match */ 620*b077aed3SPierre Pronchery return NULL; 621*b077aed3SPierre Pronchery 622*b077aed3SPierre Pronchery store_info = OSSL_STORE_INFO_new_PKEY(pkey); 623*b077aed3SPierre Pronchery if (store_info == NULL) 624*b077aed3SPierre Pronchery EVP_PKEY_free(pkey); 625*b077aed3SPierre Pronchery 626*b077aed3SPierre Pronchery return store_info; 627*b077aed3SPierre Pronchery } 628*b077aed3SPierre Pronchery 629*b077aed3SPierre Pronchery static FILE_HANDLER PrivateKey_handler = { 630*b077aed3SPierre Pronchery "PrivateKey", 631*b077aed3SPierre Pronchery try_decode_PrivateKey 632*b077aed3SPierre Pronchery }; 633*b077aed3SPierre Pronchery 634*b077aed3SPierre Pronchery /* 635*b077aed3SPierre Pronchery * Public key decoder. Only supports SubjectPublicKeyInfo formatted keys. 636*b077aed3SPierre Pronchery */ 637*b077aed3SPierre Pronchery static OSSL_STORE_INFO *try_decode_PUBKEY(const char *pem_name, 638*b077aed3SPierre Pronchery const char *pem_header, 639*b077aed3SPierre Pronchery const unsigned char *blob, 640*b077aed3SPierre Pronchery size_t len, void **pctx, 641*b077aed3SPierre Pronchery int *matchcount, 642*b077aed3SPierre Pronchery const UI_METHOD *ui_method, 643*b077aed3SPierre Pronchery void *ui_data, const char *uri, 644*b077aed3SPierre Pronchery OSSL_LIB_CTX *libctx, 645*b077aed3SPierre Pronchery const char *propq) 646*b077aed3SPierre Pronchery { 647*b077aed3SPierre Pronchery OSSL_STORE_INFO *store_info = NULL; 648*b077aed3SPierre Pronchery EVP_PKEY *pkey = NULL; 649*b077aed3SPierre Pronchery 650*b077aed3SPierre Pronchery if (pem_name != NULL) { 651*b077aed3SPierre Pronchery if (strcmp(pem_name, PEM_STRING_PUBLIC) != 0) 652*b077aed3SPierre Pronchery /* No match */ 653*b077aed3SPierre Pronchery return NULL; 654*b077aed3SPierre Pronchery *matchcount = 1; 655*b077aed3SPierre Pronchery } 656*b077aed3SPierre Pronchery 657*b077aed3SPierre Pronchery if ((pkey = d2i_PUBKEY(NULL, &blob, len)) != NULL) { 658*b077aed3SPierre Pronchery *matchcount = 1; 659*b077aed3SPierre Pronchery store_info = OSSL_STORE_INFO_new_PUBKEY(pkey); 660*b077aed3SPierre Pronchery } 661*b077aed3SPierre Pronchery 662*b077aed3SPierre Pronchery return store_info; 663*b077aed3SPierre Pronchery } 664*b077aed3SPierre Pronchery 665*b077aed3SPierre Pronchery static FILE_HANDLER PUBKEY_handler = { 666*b077aed3SPierre Pronchery "PUBKEY", 667*b077aed3SPierre Pronchery try_decode_PUBKEY 668*b077aed3SPierre Pronchery }; 669*b077aed3SPierre Pronchery 670*b077aed3SPierre Pronchery /* 671*b077aed3SPierre Pronchery * Key parameter decoder. 672*b077aed3SPierre Pronchery */ 673*b077aed3SPierre Pronchery static OSSL_STORE_INFO *try_decode_params(const char *pem_name, 674*b077aed3SPierre Pronchery const char *pem_header, 675*b077aed3SPierre Pronchery const unsigned char *blob, 676*b077aed3SPierre Pronchery size_t len, void **pctx, 677*b077aed3SPierre Pronchery int *matchcount, 678*b077aed3SPierre Pronchery const UI_METHOD *ui_method, 679*b077aed3SPierre Pronchery void *ui_data, const char *uri, 680*b077aed3SPierre Pronchery OSSL_LIB_CTX *libctx, 681*b077aed3SPierre Pronchery const char *propq) 682*b077aed3SPierre Pronchery { 683*b077aed3SPierre Pronchery OSSL_STORE_INFO *store_info = NULL; 684*b077aed3SPierre Pronchery EVP_PKEY *pkey = NULL; 685*b077aed3SPierre Pronchery const EVP_PKEY_ASN1_METHOD *ameth = NULL; 686*b077aed3SPierre Pronchery 687*b077aed3SPierre Pronchery if (pem_name != NULL) { 688*b077aed3SPierre Pronchery int slen; 689*b077aed3SPierre Pronchery int pkey_id; 690*b077aed3SPierre Pronchery 691*b077aed3SPierre Pronchery if ((slen = check_suffix(pem_name, "PARAMETERS")) > 0 692*b077aed3SPierre Pronchery && (ameth = EVP_PKEY_asn1_find_str(NULL, pem_name, slen)) != NULL 693*b077aed3SPierre Pronchery && EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, 694*b077aed3SPierre Pronchery ameth)) { 695*b077aed3SPierre Pronchery *matchcount = 1; 696*b077aed3SPierre Pronchery pkey = d2i_KeyParams(pkey_id, NULL, &blob, len); 697*b077aed3SPierre Pronchery } 698*b077aed3SPierre Pronchery } else { 699*b077aed3SPierre Pronchery int i; 700*b077aed3SPierre Pronchery 701*b077aed3SPierre Pronchery for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) { 702*b077aed3SPierre Pronchery EVP_PKEY *tmp_pkey = NULL; 703*b077aed3SPierre Pronchery const unsigned char *tmp_blob = blob; 704*b077aed3SPierre Pronchery int pkey_id, pkey_flags; 705*b077aed3SPierre Pronchery 706*b077aed3SPierre Pronchery ameth = EVP_PKEY_asn1_get0(i); 707*b077aed3SPierre Pronchery if (!EVP_PKEY_asn1_get0_info(&pkey_id, NULL, &pkey_flags, NULL, 708*b077aed3SPierre Pronchery NULL, ameth) 709*b077aed3SPierre Pronchery || (pkey_flags & ASN1_PKEY_ALIAS) != 0) 710*b077aed3SPierre Pronchery continue; 711*b077aed3SPierre Pronchery 712*b077aed3SPierre Pronchery ERR_set_mark(); /* prevent flooding error queue */ 713*b077aed3SPierre Pronchery 714*b077aed3SPierre Pronchery tmp_pkey = d2i_KeyParams(pkey_id, NULL, &tmp_blob, len); 715*b077aed3SPierre Pronchery 716*b077aed3SPierre Pronchery if (tmp_pkey != NULL) { 717*b077aed3SPierre Pronchery if (pkey != NULL) 718*b077aed3SPierre Pronchery EVP_PKEY_free(tmp_pkey); 719*b077aed3SPierre Pronchery else 720*b077aed3SPierre Pronchery pkey = tmp_pkey; 721*b077aed3SPierre Pronchery (*matchcount)++; 722*b077aed3SPierre Pronchery } 723*b077aed3SPierre Pronchery ERR_pop_to_mark(); 724*b077aed3SPierre Pronchery } 725*b077aed3SPierre Pronchery 726*b077aed3SPierre Pronchery if (*matchcount > 1) { 727*b077aed3SPierre Pronchery EVP_PKEY_free(pkey); 728*b077aed3SPierre Pronchery pkey = NULL; 729*b077aed3SPierre Pronchery } 730*b077aed3SPierre Pronchery } 731*b077aed3SPierre Pronchery if (pkey == NULL) 732*b077aed3SPierre Pronchery /* No match */ 733*b077aed3SPierre Pronchery return NULL; 734*b077aed3SPierre Pronchery 735*b077aed3SPierre Pronchery store_info = OSSL_STORE_INFO_new_PARAMS(pkey); 736*b077aed3SPierre Pronchery if (store_info == NULL) 737*b077aed3SPierre Pronchery EVP_PKEY_free(pkey); 738*b077aed3SPierre Pronchery 739*b077aed3SPierre Pronchery return store_info; 740*b077aed3SPierre Pronchery } 741*b077aed3SPierre Pronchery 742*b077aed3SPierre Pronchery static FILE_HANDLER params_handler = { 743*b077aed3SPierre Pronchery "params", 744*b077aed3SPierre Pronchery try_decode_params 745*b077aed3SPierre Pronchery }; 746*b077aed3SPierre Pronchery 747*b077aed3SPierre Pronchery /* 748*b077aed3SPierre Pronchery * X.509 certificate decoder. 749*b077aed3SPierre Pronchery */ 750*b077aed3SPierre Pronchery static OSSL_STORE_INFO *try_decode_X509Certificate(const char *pem_name, 751*b077aed3SPierre Pronchery const char *pem_header, 752*b077aed3SPierre Pronchery const unsigned char *blob, 753*b077aed3SPierre Pronchery size_t len, void **pctx, 754*b077aed3SPierre Pronchery int *matchcount, 755*b077aed3SPierre Pronchery const UI_METHOD *ui_method, 756*b077aed3SPierre Pronchery void *ui_data, 757*b077aed3SPierre Pronchery const char *uri, 758*b077aed3SPierre Pronchery OSSL_LIB_CTX *libctx, 759*b077aed3SPierre Pronchery const char *propq) 760*b077aed3SPierre Pronchery { 761*b077aed3SPierre Pronchery OSSL_STORE_INFO *store_info = NULL; 762*b077aed3SPierre Pronchery X509 *cert = NULL; 763*b077aed3SPierre Pronchery 764*b077aed3SPierre Pronchery /* 765*b077aed3SPierre Pronchery * In most cases, we can try to interpret the serialized data as a trusted 766*b077aed3SPierre Pronchery * cert (X509 + X509_AUX) and fall back to reading it as a normal cert 767*b077aed3SPierre Pronchery * (just X509), but if the PEM name specifically declares it as a trusted 768*b077aed3SPierre Pronchery * cert, then no fallback should be engaged. |ignore_trusted| tells if 769*b077aed3SPierre Pronchery * the fallback can be used (1) or not (0). 770*b077aed3SPierre Pronchery */ 771*b077aed3SPierre Pronchery int ignore_trusted = 1; 772*b077aed3SPierre Pronchery 773*b077aed3SPierre Pronchery if (pem_name != NULL) { 774*b077aed3SPierre Pronchery if (strcmp(pem_name, PEM_STRING_X509_TRUSTED) == 0) 775*b077aed3SPierre Pronchery ignore_trusted = 0; 776*b077aed3SPierre Pronchery else if (strcmp(pem_name, PEM_STRING_X509_OLD) != 0 777*b077aed3SPierre Pronchery && strcmp(pem_name, PEM_STRING_X509) != 0) 778*b077aed3SPierre Pronchery /* No match */ 779*b077aed3SPierre Pronchery return NULL; 780*b077aed3SPierre Pronchery *matchcount = 1; 781*b077aed3SPierre Pronchery } 782*b077aed3SPierre Pronchery 783*b077aed3SPierre Pronchery cert = X509_new_ex(libctx, propq); 784*b077aed3SPierre Pronchery if (cert == NULL) 785*b077aed3SPierre Pronchery return NULL; 786*b077aed3SPierre Pronchery 787*b077aed3SPierre Pronchery if ((d2i_X509_AUX(&cert, &blob, len)) != NULL 788*b077aed3SPierre Pronchery || (ignore_trusted && (d2i_X509(&cert, &blob, len)) != NULL)) { 789*b077aed3SPierre Pronchery *matchcount = 1; 790*b077aed3SPierre Pronchery store_info = OSSL_STORE_INFO_new_CERT(cert); 791*b077aed3SPierre Pronchery } 792*b077aed3SPierre Pronchery 793*b077aed3SPierre Pronchery if (store_info == NULL) 794*b077aed3SPierre Pronchery X509_free(cert); 795*b077aed3SPierre Pronchery 796*b077aed3SPierre Pronchery return store_info; 797*b077aed3SPierre Pronchery } 798*b077aed3SPierre Pronchery 799*b077aed3SPierre Pronchery static FILE_HANDLER X509Certificate_handler = { 800*b077aed3SPierre Pronchery "X509Certificate", 801*b077aed3SPierre Pronchery try_decode_X509Certificate 802*b077aed3SPierre Pronchery }; 803*b077aed3SPierre Pronchery 804*b077aed3SPierre Pronchery /* 805*b077aed3SPierre Pronchery * X.509 CRL decoder. 806*b077aed3SPierre Pronchery */ 807*b077aed3SPierre Pronchery static OSSL_STORE_INFO *try_decode_X509CRL(const char *pem_name, 808*b077aed3SPierre Pronchery const char *pem_header, 809*b077aed3SPierre Pronchery const unsigned char *blob, 810*b077aed3SPierre Pronchery size_t len, void **pctx, 811*b077aed3SPierre Pronchery int *matchcount, 812*b077aed3SPierre Pronchery const UI_METHOD *ui_method, 813*b077aed3SPierre Pronchery void *ui_data, const char *uri, 814*b077aed3SPierre Pronchery OSSL_LIB_CTX *libctx, 815*b077aed3SPierre Pronchery const char *propq) 816*b077aed3SPierre Pronchery { 817*b077aed3SPierre Pronchery OSSL_STORE_INFO *store_info = NULL; 818*b077aed3SPierre Pronchery X509_CRL *crl = NULL; 819*b077aed3SPierre Pronchery 820*b077aed3SPierre Pronchery if (pem_name != NULL) { 821*b077aed3SPierre Pronchery if (strcmp(pem_name, PEM_STRING_X509_CRL) != 0) 822*b077aed3SPierre Pronchery /* No match */ 823*b077aed3SPierre Pronchery return NULL; 824*b077aed3SPierre Pronchery *matchcount = 1; 825*b077aed3SPierre Pronchery } 826*b077aed3SPierre Pronchery 827*b077aed3SPierre Pronchery if ((crl = d2i_X509_CRL(NULL, &blob, len)) != NULL) { 828*b077aed3SPierre Pronchery *matchcount = 1; 829*b077aed3SPierre Pronchery store_info = OSSL_STORE_INFO_new_CRL(crl); 830*b077aed3SPierre Pronchery } 831*b077aed3SPierre Pronchery 832*b077aed3SPierre Pronchery if (store_info == NULL) 833*b077aed3SPierre Pronchery X509_CRL_free(crl); 834*b077aed3SPierre Pronchery 835*b077aed3SPierre Pronchery return store_info; 836*b077aed3SPierre Pronchery } 837*b077aed3SPierre Pronchery 838*b077aed3SPierre Pronchery static FILE_HANDLER X509CRL_handler = { 839*b077aed3SPierre Pronchery "X509CRL", 840*b077aed3SPierre Pronchery try_decode_X509CRL 841*b077aed3SPierre Pronchery }; 842*b077aed3SPierre Pronchery 843*b077aed3SPierre Pronchery /* 844*b077aed3SPierre Pronchery * To finish it all off, we collect all the handlers. 845*b077aed3SPierre Pronchery */ 846*b077aed3SPierre Pronchery static const FILE_HANDLER *file_handlers[] = { 847*b077aed3SPierre Pronchery &PKCS12_handler, 848*b077aed3SPierre Pronchery &PKCS8Encrypted_handler, 849*b077aed3SPierre Pronchery &X509Certificate_handler, 850*b077aed3SPierre Pronchery &X509CRL_handler, 851*b077aed3SPierre Pronchery ¶ms_handler, 852*b077aed3SPierre Pronchery &PUBKEY_handler, 853*b077aed3SPierre Pronchery &PrivateKey_handler, 854*b077aed3SPierre Pronchery }; 855*b077aed3SPierre Pronchery 856*b077aed3SPierre Pronchery 857*b077aed3SPierre Pronchery /*- 858*b077aed3SPierre Pronchery * The loader itself 859*b077aed3SPierre Pronchery * ----------------- 860*b077aed3SPierre Pronchery */ 861*b077aed3SPierre Pronchery 862*b077aed3SPierre Pronchery struct ossl_store_loader_ctx_st { 863*b077aed3SPierre Pronchery char *uri; /* The URI we currently try to load */ 864*b077aed3SPierre Pronchery enum { 865*b077aed3SPierre Pronchery is_raw = 0, 866*b077aed3SPierre Pronchery is_pem, 867*b077aed3SPierre Pronchery is_dir 868*b077aed3SPierre Pronchery } type; 869*b077aed3SPierre Pronchery int errcnt; 870*b077aed3SPierre Pronchery #define FILE_FLAG_SECMEM (1<<0) 871*b077aed3SPierre Pronchery #define FILE_FLAG_ATTACHED (1<<1) 872*b077aed3SPierre Pronchery unsigned int flags; 873*b077aed3SPierre Pronchery union { 874*b077aed3SPierre Pronchery struct { /* Used with is_raw and is_pem */ 875*b077aed3SPierre Pronchery BIO *file; 876*b077aed3SPierre Pronchery 877*b077aed3SPierre Pronchery /* 878*b077aed3SPierre Pronchery * The following are used when the handler is marked as 879*b077aed3SPierre Pronchery * repeatable 880*b077aed3SPierre Pronchery */ 881*b077aed3SPierre Pronchery const FILE_HANDLER *last_handler; 882*b077aed3SPierre Pronchery void *last_handler_ctx; 883*b077aed3SPierre Pronchery } file; 884*b077aed3SPierre Pronchery struct { /* Used with is_dir */ 885*b077aed3SPierre Pronchery OPENSSL_DIR_CTX *ctx; 886*b077aed3SPierre Pronchery int end_reached; 887*b077aed3SPierre Pronchery 888*b077aed3SPierre Pronchery /* 889*b077aed3SPierre Pronchery * When a search expression is given, these are filled in. 890*b077aed3SPierre Pronchery * |search_name| contains the file basename to look for. 891*b077aed3SPierre Pronchery * The string is exactly 8 characters long. 892*b077aed3SPierre Pronchery */ 893*b077aed3SPierre Pronchery char search_name[9]; 894*b077aed3SPierre Pronchery 895*b077aed3SPierre Pronchery /* 896*b077aed3SPierre Pronchery * The directory reading utility we have combines opening with 897*b077aed3SPierre Pronchery * reading the first name. To make sure we can detect the end 898*b077aed3SPierre Pronchery * at the right time, we read early and cache the name. 899*b077aed3SPierre Pronchery */ 900*b077aed3SPierre Pronchery const char *last_entry; 901*b077aed3SPierre Pronchery int last_errno; 902*b077aed3SPierre Pronchery } dir; 903*b077aed3SPierre Pronchery } _; 904*b077aed3SPierre Pronchery 905*b077aed3SPierre Pronchery /* Expected object type. May be unspecified */ 906*b077aed3SPierre Pronchery int expected_type; 907*b077aed3SPierre Pronchery 908*b077aed3SPierre Pronchery OSSL_LIB_CTX *libctx; 909*b077aed3SPierre Pronchery char *propq; 910*b077aed3SPierre Pronchery }; 911*b077aed3SPierre Pronchery 912*b077aed3SPierre Pronchery static void OSSL_STORE_LOADER_CTX_free(OSSL_STORE_LOADER_CTX *ctx) 913*b077aed3SPierre Pronchery { 914*b077aed3SPierre Pronchery if (ctx == NULL) 915*b077aed3SPierre Pronchery return; 916*b077aed3SPierre Pronchery 917*b077aed3SPierre Pronchery OPENSSL_free(ctx->propq); 918*b077aed3SPierre Pronchery OPENSSL_free(ctx->uri); 919*b077aed3SPierre Pronchery if (ctx->type != is_dir) { 920*b077aed3SPierre Pronchery if (ctx->_.file.last_handler != NULL) { 921*b077aed3SPierre Pronchery ctx->_.file.last_handler->destroy_ctx(&ctx->_.file.last_handler_ctx); 922*b077aed3SPierre Pronchery ctx->_.file.last_handler_ctx = NULL; 923*b077aed3SPierre Pronchery ctx->_.file.last_handler = NULL; 924*b077aed3SPierre Pronchery } 925*b077aed3SPierre Pronchery } 926*b077aed3SPierre Pronchery OPENSSL_free(ctx); 927*b077aed3SPierre Pronchery } 928*b077aed3SPierre Pronchery 929*b077aed3SPierre Pronchery static int file_find_type(OSSL_STORE_LOADER_CTX *ctx) 930*b077aed3SPierre Pronchery { 931*b077aed3SPierre Pronchery BIO *buff = NULL; 932*b077aed3SPierre Pronchery char peekbuf[4096] = { 0, }; 933*b077aed3SPierre Pronchery 934*b077aed3SPierre Pronchery if ((buff = BIO_new(BIO_f_buffer())) == NULL) 935*b077aed3SPierre Pronchery return 0; 936*b077aed3SPierre Pronchery 937*b077aed3SPierre Pronchery ctx->_.file.file = BIO_push(buff, ctx->_.file.file); 938*b077aed3SPierre Pronchery if (BIO_buffer_peek(ctx->_.file.file, peekbuf, sizeof(peekbuf) - 1) > 0) { 939*b077aed3SPierre Pronchery peekbuf[sizeof(peekbuf) - 1] = '\0'; 940*b077aed3SPierre Pronchery if (strstr(peekbuf, "-----BEGIN ") != NULL) 941*b077aed3SPierre Pronchery ctx->type = is_pem; 942*b077aed3SPierre Pronchery } 943*b077aed3SPierre Pronchery return 1; 944*b077aed3SPierre Pronchery } 945*b077aed3SPierre Pronchery 946*b077aed3SPierre Pronchery static OSSL_STORE_LOADER_CTX *file_open_ex 947*b077aed3SPierre Pronchery (const OSSL_STORE_LOADER *loader, const char *uri, 948*b077aed3SPierre Pronchery OSSL_LIB_CTX *libctx, const char *propq, 949*b077aed3SPierre Pronchery const UI_METHOD *ui_method, void *ui_data) 950*b077aed3SPierre Pronchery { 951*b077aed3SPierre Pronchery OSSL_STORE_LOADER_CTX *ctx = NULL; 952*b077aed3SPierre Pronchery struct stat st; 953*b077aed3SPierre Pronchery struct { 954*b077aed3SPierre Pronchery const char *path; 955*b077aed3SPierre Pronchery unsigned int check_absolute:1; 956*b077aed3SPierre Pronchery } path_data[2]; 957*b077aed3SPierre Pronchery size_t path_data_n = 0, i; 958*b077aed3SPierre Pronchery const char *path; 959*b077aed3SPierre Pronchery 960*b077aed3SPierre Pronchery /* 961*b077aed3SPierre Pronchery * First step, just take the URI as is. 962*b077aed3SPierre Pronchery */ 963*b077aed3SPierre Pronchery path_data[path_data_n].check_absolute = 0; 964*b077aed3SPierre Pronchery path_data[path_data_n++].path = uri; 965*b077aed3SPierre Pronchery 966*b077aed3SPierre Pronchery /* 967*b077aed3SPierre Pronchery * Second step, if the URI appears to start with the 'file' scheme, 968*b077aed3SPierre Pronchery * extract the path and make that the second path to check. 969*b077aed3SPierre Pronchery * There's a special case if the URI also contains an authority, then 970*b077aed3SPierre Pronchery * the full URI shouldn't be used as a path anywhere. 971*b077aed3SPierre Pronchery */ 972*b077aed3SPierre Pronchery if (OPENSSL_strncasecmp(uri, "file:", 5) == 0) { 973*b077aed3SPierre Pronchery const char *p = &uri[5]; 974*b077aed3SPierre Pronchery 975*b077aed3SPierre Pronchery if (strncmp(&uri[5], "//", 2) == 0) { 976*b077aed3SPierre Pronchery path_data_n--; /* Invalidate using the full URI */ 977*b077aed3SPierre Pronchery if (OPENSSL_strncasecmp(&uri[7], "localhost/", 10) == 0) { 978*b077aed3SPierre Pronchery p = &uri[16]; 979*b077aed3SPierre Pronchery } else if (uri[7] == '/') { 980*b077aed3SPierre Pronchery p = &uri[7]; 981*b077aed3SPierre Pronchery } else { 982*b077aed3SPierre Pronchery ATTICerr(0, ATTIC_R_URI_AUTHORITY_UNSUPPORTED); 983*b077aed3SPierre Pronchery return NULL; 984*b077aed3SPierre Pronchery } 985*b077aed3SPierre Pronchery } 986*b077aed3SPierre Pronchery 987*b077aed3SPierre Pronchery path_data[path_data_n].check_absolute = 1; 988*b077aed3SPierre Pronchery #ifdef _WIN32 989*b077aed3SPierre Pronchery /* Windows file: URIs with a drive letter start with a / */ 990*b077aed3SPierre Pronchery if (p[0] == '/' && p[2] == ':' && p[3] == '/') { 991*b077aed3SPierre Pronchery char c = tolower(p[1]); 992*b077aed3SPierre Pronchery 993*b077aed3SPierre Pronchery if (c >= 'a' && c <= 'z') { 994*b077aed3SPierre Pronchery p++; 995*b077aed3SPierre Pronchery /* We know it's absolute, so no need to check */ 996*b077aed3SPierre Pronchery path_data[path_data_n].check_absolute = 0; 997*b077aed3SPierre Pronchery } 998*b077aed3SPierre Pronchery } 999*b077aed3SPierre Pronchery #endif 1000*b077aed3SPierre Pronchery path_data[path_data_n++].path = p; 1001*b077aed3SPierre Pronchery } 1002*b077aed3SPierre Pronchery 1003*b077aed3SPierre Pronchery 1004*b077aed3SPierre Pronchery for (i = 0, path = NULL; path == NULL && i < path_data_n; i++) { 1005*b077aed3SPierre Pronchery /* 1006*b077aed3SPierre Pronchery * If the scheme "file" was an explicit part of the URI, the path must 1007*b077aed3SPierre Pronchery * be absolute. So says RFC 8089 1008*b077aed3SPierre Pronchery */ 1009*b077aed3SPierre Pronchery if (path_data[i].check_absolute && path_data[i].path[0] != '/') { 1010*b077aed3SPierre Pronchery ATTICerr(0, ATTIC_R_PATH_MUST_BE_ABSOLUTE); 1011*b077aed3SPierre Pronchery ERR_add_error_data(1, path_data[i].path); 1012*b077aed3SPierre Pronchery return NULL; 1013*b077aed3SPierre Pronchery } 1014*b077aed3SPierre Pronchery 1015*b077aed3SPierre Pronchery if (stat(path_data[i].path, &st) < 0) { 1016*b077aed3SPierre Pronchery ERR_raise_data(ERR_LIB_SYS, errno, 1017*b077aed3SPierre Pronchery "calling stat(%s)", 1018*b077aed3SPierre Pronchery path_data[i].path); 1019*b077aed3SPierre Pronchery } else { 1020*b077aed3SPierre Pronchery path = path_data[i].path; 1021*b077aed3SPierre Pronchery } 1022*b077aed3SPierre Pronchery } 1023*b077aed3SPierre Pronchery if (path == NULL) { 1024*b077aed3SPierre Pronchery return NULL; 1025*b077aed3SPierre Pronchery } 1026*b077aed3SPierre Pronchery 1027*b077aed3SPierre Pronchery /* Successfully found a working path */ 1028*b077aed3SPierre Pronchery 1029*b077aed3SPierre Pronchery ctx = OPENSSL_zalloc(sizeof(*ctx)); 1030*b077aed3SPierre Pronchery if (ctx == NULL) { 1031*b077aed3SPierre Pronchery ATTICerr(0, ERR_R_MALLOC_FAILURE); 1032*b077aed3SPierre Pronchery return NULL; 1033*b077aed3SPierre Pronchery } 1034*b077aed3SPierre Pronchery ctx->uri = OPENSSL_strdup(uri); 1035*b077aed3SPierre Pronchery if (ctx->uri == NULL) { 1036*b077aed3SPierre Pronchery ATTICerr(0, ERR_R_MALLOC_FAILURE); 1037*b077aed3SPierre Pronchery goto err; 1038*b077aed3SPierre Pronchery } 1039*b077aed3SPierre Pronchery 1040*b077aed3SPierre Pronchery if (S_ISDIR(st.st_mode)) { 1041*b077aed3SPierre Pronchery ctx->type = is_dir; 1042*b077aed3SPierre Pronchery ctx->_.dir.last_entry = OPENSSL_DIR_read(&ctx->_.dir.ctx, path); 1043*b077aed3SPierre Pronchery ctx->_.dir.last_errno = errno; 1044*b077aed3SPierre Pronchery if (ctx->_.dir.last_entry == NULL) { 1045*b077aed3SPierre Pronchery if (ctx->_.dir.last_errno != 0) { 1046*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_SYS, ctx->_.dir.last_errno); 1047*b077aed3SPierre Pronchery goto err; 1048*b077aed3SPierre Pronchery } 1049*b077aed3SPierre Pronchery ctx->_.dir.end_reached = 1; 1050*b077aed3SPierre Pronchery } 1051*b077aed3SPierre Pronchery } else if ((ctx->_.file.file = BIO_new_file(path, "rb")) == NULL 1052*b077aed3SPierre Pronchery || !file_find_type(ctx)) { 1053*b077aed3SPierre Pronchery BIO_free_all(ctx->_.file.file); 1054*b077aed3SPierre Pronchery goto err; 1055*b077aed3SPierre Pronchery } 1056*b077aed3SPierre Pronchery if (propq != NULL) { 1057*b077aed3SPierre Pronchery ctx->propq = OPENSSL_strdup(propq); 1058*b077aed3SPierre Pronchery if (ctx->propq == NULL) { 1059*b077aed3SPierre Pronchery ATTICerr(0, ERR_R_MALLOC_FAILURE); 1060*b077aed3SPierre Pronchery goto err; 1061*b077aed3SPierre Pronchery } 1062*b077aed3SPierre Pronchery } 1063*b077aed3SPierre Pronchery ctx->libctx = libctx; 1064*b077aed3SPierre Pronchery 1065*b077aed3SPierre Pronchery return ctx; 1066*b077aed3SPierre Pronchery err: 1067*b077aed3SPierre Pronchery OSSL_STORE_LOADER_CTX_free(ctx); 1068*b077aed3SPierre Pronchery return NULL; 1069*b077aed3SPierre Pronchery } 1070*b077aed3SPierre Pronchery 1071*b077aed3SPierre Pronchery static OSSL_STORE_LOADER_CTX *file_open 1072*b077aed3SPierre Pronchery (const OSSL_STORE_LOADER *loader, const char *uri, 1073*b077aed3SPierre Pronchery const UI_METHOD *ui_method, void *ui_data) 1074*b077aed3SPierre Pronchery { 1075*b077aed3SPierre Pronchery return file_open_ex(loader, uri, NULL, NULL, ui_method, ui_data); 1076*b077aed3SPierre Pronchery } 1077*b077aed3SPierre Pronchery 1078*b077aed3SPierre Pronchery static OSSL_STORE_LOADER_CTX *file_attach 1079*b077aed3SPierre Pronchery (const OSSL_STORE_LOADER *loader, BIO *bp, 1080*b077aed3SPierre Pronchery OSSL_LIB_CTX *libctx, const char *propq, 1081*b077aed3SPierre Pronchery const UI_METHOD *ui_method, void *ui_data) 1082*b077aed3SPierre Pronchery { 1083*b077aed3SPierre Pronchery OSSL_STORE_LOADER_CTX *ctx = NULL; 1084*b077aed3SPierre Pronchery 1085*b077aed3SPierre Pronchery if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL 1086*b077aed3SPierre Pronchery || (propq != NULL && (ctx->propq = OPENSSL_strdup(propq)) == NULL)) { 1087*b077aed3SPierre Pronchery ATTICerr(0, ERR_R_MALLOC_FAILURE); 1088*b077aed3SPierre Pronchery OSSL_STORE_LOADER_CTX_free(ctx); 1089*b077aed3SPierre Pronchery return NULL; 1090*b077aed3SPierre Pronchery } 1091*b077aed3SPierre Pronchery ctx->libctx = libctx; 1092*b077aed3SPierre Pronchery ctx->flags |= FILE_FLAG_ATTACHED; 1093*b077aed3SPierre Pronchery ctx->_.file.file = bp; 1094*b077aed3SPierre Pronchery if (!file_find_type(ctx)) { 1095*b077aed3SPierre Pronchery /* Safety measure */ 1096*b077aed3SPierre Pronchery ctx->_.file.file = NULL; 1097*b077aed3SPierre Pronchery goto err; 1098*b077aed3SPierre Pronchery } 1099*b077aed3SPierre Pronchery return ctx; 1100*b077aed3SPierre Pronchery err: 1101*b077aed3SPierre Pronchery OSSL_STORE_LOADER_CTX_free(ctx); 1102*b077aed3SPierre Pronchery return NULL; 1103*b077aed3SPierre Pronchery } 1104*b077aed3SPierre Pronchery 1105*b077aed3SPierre Pronchery static int file_ctrl(OSSL_STORE_LOADER_CTX *ctx, int cmd, va_list args) 1106*b077aed3SPierre Pronchery { 1107*b077aed3SPierre Pronchery int ret = 1; 1108*b077aed3SPierre Pronchery 1109*b077aed3SPierre Pronchery switch (cmd) { 1110*b077aed3SPierre Pronchery case OSSL_STORE_C_USE_SECMEM: 1111*b077aed3SPierre Pronchery { 1112*b077aed3SPierre Pronchery int on = *(va_arg(args, int *)); 1113*b077aed3SPierre Pronchery 1114*b077aed3SPierre Pronchery switch (on) { 1115*b077aed3SPierre Pronchery case 0: 1116*b077aed3SPierre Pronchery ctx->flags &= ~FILE_FLAG_SECMEM; 1117*b077aed3SPierre Pronchery break; 1118*b077aed3SPierre Pronchery case 1: 1119*b077aed3SPierre Pronchery ctx->flags |= FILE_FLAG_SECMEM; 1120*b077aed3SPierre Pronchery break; 1121*b077aed3SPierre Pronchery default: 1122*b077aed3SPierre Pronchery ATTICerr(0, ERR_R_PASSED_INVALID_ARGUMENT); 1123*b077aed3SPierre Pronchery ret = 0; 1124*b077aed3SPierre Pronchery break; 1125*b077aed3SPierre Pronchery } 1126*b077aed3SPierre Pronchery } 1127*b077aed3SPierre Pronchery break; 1128*b077aed3SPierre Pronchery default: 1129*b077aed3SPierre Pronchery break; 1130*b077aed3SPierre Pronchery } 1131*b077aed3SPierre Pronchery 1132*b077aed3SPierre Pronchery return ret; 1133*b077aed3SPierre Pronchery } 1134*b077aed3SPierre Pronchery 1135*b077aed3SPierre Pronchery static int file_expect(OSSL_STORE_LOADER_CTX *ctx, int expected) 1136*b077aed3SPierre Pronchery { 1137*b077aed3SPierre Pronchery ctx->expected_type = expected; 1138*b077aed3SPierre Pronchery return 1; 1139*b077aed3SPierre Pronchery } 1140*b077aed3SPierre Pronchery 1141*b077aed3SPierre Pronchery static int file_find(OSSL_STORE_LOADER_CTX *ctx, 1142*b077aed3SPierre Pronchery const OSSL_STORE_SEARCH *search) 1143*b077aed3SPierre Pronchery { 1144*b077aed3SPierre Pronchery /* 1145*b077aed3SPierre Pronchery * If ctx == NULL, the library is looking to know if this loader supports 1146*b077aed3SPierre Pronchery * the given search type. 1147*b077aed3SPierre Pronchery */ 1148*b077aed3SPierre Pronchery 1149*b077aed3SPierre Pronchery if (OSSL_STORE_SEARCH_get_type(search) == OSSL_STORE_SEARCH_BY_NAME) { 1150*b077aed3SPierre Pronchery unsigned long hash = 0; 1151*b077aed3SPierre Pronchery 1152*b077aed3SPierre Pronchery if (ctx == NULL) 1153*b077aed3SPierre Pronchery return 1; 1154*b077aed3SPierre Pronchery 1155*b077aed3SPierre Pronchery if (ctx->type != is_dir) { 1156*b077aed3SPierre Pronchery ATTICerr(0, ATTIC_R_SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES); 1157*b077aed3SPierre Pronchery return 0; 1158*b077aed3SPierre Pronchery } 1159*b077aed3SPierre Pronchery 1160*b077aed3SPierre Pronchery hash = X509_NAME_hash_ex(OSSL_STORE_SEARCH_get0_name(search), 1161*b077aed3SPierre Pronchery NULL, NULL, NULL); 1162*b077aed3SPierre Pronchery BIO_snprintf(ctx->_.dir.search_name, sizeof(ctx->_.dir.search_name), 1163*b077aed3SPierre Pronchery "%08lx", hash); 1164*b077aed3SPierre Pronchery return 1; 1165*b077aed3SPierre Pronchery } 1166*b077aed3SPierre Pronchery 1167*b077aed3SPierre Pronchery if (ctx != NULL) 1168*b077aed3SPierre Pronchery ATTICerr(0, ATTIC_R_UNSUPPORTED_SEARCH_TYPE); 1169*b077aed3SPierre Pronchery return 0; 1170*b077aed3SPierre Pronchery } 1171*b077aed3SPierre Pronchery 1172*b077aed3SPierre Pronchery static OSSL_STORE_INFO *file_load_try_decode(OSSL_STORE_LOADER_CTX *ctx, 1173*b077aed3SPierre Pronchery const char *pem_name, 1174*b077aed3SPierre Pronchery const char *pem_header, 1175*b077aed3SPierre Pronchery unsigned char *data, size_t len, 1176*b077aed3SPierre Pronchery const UI_METHOD *ui_method, 1177*b077aed3SPierre Pronchery void *ui_data, int *matchcount) 1178*b077aed3SPierre Pronchery { 1179*b077aed3SPierre Pronchery OSSL_STORE_INFO *result = NULL; 1180*b077aed3SPierre Pronchery BUF_MEM *new_mem = NULL; 1181*b077aed3SPierre Pronchery char *new_pem_name = NULL; 1182*b077aed3SPierre Pronchery int t = 0; 1183*b077aed3SPierre Pronchery 1184*b077aed3SPierre Pronchery again: 1185*b077aed3SPierre Pronchery { 1186*b077aed3SPierre Pronchery size_t i = 0; 1187*b077aed3SPierre Pronchery void *handler_ctx = NULL; 1188*b077aed3SPierre Pronchery const FILE_HANDLER **matching_handlers = 1189*b077aed3SPierre Pronchery OPENSSL_zalloc(sizeof(*matching_handlers) 1190*b077aed3SPierre Pronchery * OSSL_NELEM(file_handlers)); 1191*b077aed3SPierre Pronchery 1192*b077aed3SPierre Pronchery if (matching_handlers == NULL) { 1193*b077aed3SPierre Pronchery ATTICerr(0, ERR_R_MALLOC_FAILURE); 1194*b077aed3SPierre Pronchery goto err; 1195*b077aed3SPierre Pronchery } 1196*b077aed3SPierre Pronchery 1197*b077aed3SPierre Pronchery *matchcount = 0; 1198*b077aed3SPierre Pronchery for (i = 0; i < OSSL_NELEM(file_handlers); i++) { 1199*b077aed3SPierre Pronchery const FILE_HANDLER *handler = file_handlers[i]; 1200*b077aed3SPierre Pronchery int try_matchcount = 0; 1201*b077aed3SPierre Pronchery void *tmp_handler_ctx = NULL; 1202*b077aed3SPierre Pronchery OSSL_STORE_INFO *tmp_result; 1203*b077aed3SPierre Pronchery unsigned long err; 1204*b077aed3SPierre Pronchery 1205*b077aed3SPierre Pronchery ERR_set_mark(); 1206*b077aed3SPierre Pronchery tmp_result = 1207*b077aed3SPierre Pronchery handler->try_decode(pem_name, pem_header, data, len, 1208*b077aed3SPierre Pronchery &tmp_handler_ctx, &try_matchcount, 1209*b077aed3SPierre Pronchery ui_method, ui_data, ctx->uri, 1210*b077aed3SPierre Pronchery ctx->libctx, ctx->propq); 1211*b077aed3SPierre Pronchery /* avoid flooding error queue with low-level ASN.1 parse errors */ 1212*b077aed3SPierre Pronchery err = ERR_peek_last_error(); 1213*b077aed3SPierre Pronchery if (ERR_GET_LIB(err) == ERR_LIB_ASN1 1214*b077aed3SPierre Pronchery && ERR_GET_REASON(err) == ERR_R_NESTED_ASN1_ERROR) 1215*b077aed3SPierre Pronchery ERR_pop_to_mark(); 1216*b077aed3SPierre Pronchery else 1217*b077aed3SPierre Pronchery ERR_clear_last_mark(); 1218*b077aed3SPierre Pronchery 1219*b077aed3SPierre Pronchery if (try_matchcount > 0) { 1220*b077aed3SPierre Pronchery 1221*b077aed3SPierre Pronchery matching_handlers[*matchcount] = handler; 1222*b077aed3SPierre Pronchery 1223*b077aed3SPierre Pronchery if (handler_ctx) 1224*b077aed3SPierre Pronchery handler->destroy_ctx(&handler_ctx); 1225*b077aed3SPierre Pronchery handler_ctx = tmp_handler_ctx; 1226*b077aed3SPierre Pronchery 1227*b077aed3SPierre Pronchery if ((*matchcount += try_matchcount) > 1) { 1228*b077aed3SPierre Pronchery /* more than one match => ambiguous, kill any result */ 1229*b077aed3SPierre Pronchery store_info_free(result); 1230*b077aed3SPierre Pronchery store_info_free(tmp_result); 1231*b077aed3SPierre Pronchery if (handler->destroy_ctx != NULL) 1232*b077aed3SPierre Pronchery handler->destroy_ctx(&handler_ctx); 1233*b077aed3SPierre Pronchery handler_ctx = NULL; 1234*b077aed3SPierre Pronchery tmp_result = NULL; 1235*b077aed3SPierre Pronchery result = NULL; 1236*b077aed3SPierre Pronchery } 1237*b077aed3SPierre Pronchery if (result == NULL) 1238*b077aed3SPierre Pronchery result = tmp_result; 1239*b077aed3SPierre Pronchery if (result == NULL) /* e.g., PKCS#12 file decryption error */ 1240*b077aed3SPierre Pronchery break; 1241*b077aed3SPierre Pronchery } 1242*b077aed3SPierre Pronchery } 1243*b077aed3SPierre Pronchery 1244*b077aed3SPierre Pronchery if (result != NULL 1245*b077aed3SPierre Pronchery && *matchcount == 1 && matching_handlers[0]->repeatable) { 1246*b077aed3SPierre Pronchery ctx->_.file.last_handler = matching_handlers[0]; 1247*b077aed3SPierre Pronchery ctx->_.file.last_handler_ctx = handler_ctx; 1248*b077aed3SPierre Pronchery } 1249*b077aed3SPierre Pronchery 1250*b077aed3SPierre Pronchery OPENSSL_free(matching_handlers); 1251*b077aed3SPierre Pronchery } 1252*b077aed3SPierre Pronchery 1253*b077aed3SPierre Pronchery err: 1254*b077aed3SPierre Pronchery OPENSSL_free(new_pem_name); 1255*b077aed3SPierre Pronchery BUF_MEM_free(new_mem); 1256*b077aed3SPierre Pronchery 1257*b077aed3SPierre Pronchery if (result != NULL 1258*b077aed3SPierre Pronchery && (t = OSSL_STORE_INFO_get_type(result)) == STORE_INFO_EMBEDDED) { 1259*b077aed3SPierre Pronchery struct embedded_st *embedded = get0_EMBEDDED(result); 1260*b077aed3SPierre Pronchery 1261*b077aed3SPierre Pronchery /* "steal" the embedded data */ 1262*b077aed3SPierre Pronchery pem_name = new_pem_name = embedded->pem_name; 1263*b077aed3SPierre Pronchery new_mem = embedded->blob; 1264*b077aed3SPierre Pronchery data = (unsigned char *)new_mem->data; 1265*b077aed3SPierre Pronchery len = new_mem->length; 1266*b077aed3SPierre Pronchery embedded->pem_name = NULL; 1267*b077aed3SPierre Pronchery embedded->blob = NULL; 1268*b077aed3SPierre Pronchery 1269*b077aed3SPierre Pronchery store_info_free(result); 1270*b077aed3SPierre Pronchery result = NULL; 1271*b077aed3SPierre Pronchery goto again; 1272*b077aed3SPierre Pronchery } 1273*b077aed3SPierre Pronchery 1274*b077aed3SPierre Pronchery return result; 1275*b077aed3SPierre Pronchery } 1276*b077aed3SPierre Pronchery 1277*b077aed3SPierre Pronchery static OSSL_STORE_INFO *file_load_try_repeat(OSSL_STORE_LOADER_CTX *ctx, 1278*b077aed3SPierre Pronchery const UI_METHOD *ui_method, 1279*b077aed3SPierre Pronchery void *ui_data) 1280*b077aed3SPierre Pronchery { 1281*b077aed3SPierre Pronchery OSSL_STORE_INFO *result = NULL; 1282*b077aed3SPierre Pronchery int try_matchcount = 0; 1283*b077aed3SPierre Pronchery 1284*b077aed3SPierre Pronchery if (ctx->_.file.last_handler != NULL) { 1285*b077aed3SPierre Pronchery result = 1286*b077aed3SPierre Pronchery ctx->_.file.last_handler->try_decode(NULL, NULL, NULL, 0, 1287*b077aed3SPierre Pronchery &ctx->_.file.last_handler_ctx, 1288*b077aed3SPierre Pronchery &try_matchcount, 1289*b077aed3SPierre Pronchery ui_method, ui_data, ctx->uri, 1290*b077aed3SPierre Pronchery ctx->libctx, ctx->propq); 1291*b077aed3SPierre Pronchery 1292*b077aed3SPierre Pronchery if (result == NULL) { 1293*b077aed3SPierre Pronchery ctx->_.file.last_handler->destroy_ctx(&ctx->_.file.last_handler_ctx); 1294*b077aed3SPierre Pronchery ctx->_.file.last_handler_ctx = NULL; 1295*b077aed3SPierre Pronchery ctx->_.file.last_handler = NULL; 1296*b077aed3SPierre Pronchery } 1297*b077aed3SPierre Pronchery } 1298*b077aed3SPierre Pronchery return result; 1299*b077aed3SPierre Pronchery } 1300*b077aed3SPierre Pronchery 1301*b077aed3SPierre Pronchery static void pem_free_flag(void *pem_data, int secure, size_t num) 1302*b077aed3SPierre Pronchery { 1303*b077aed3SPierre Pronchery if (secure) 1304*b077aed3SPierre Pronchery OPENSSL_secure_clear_free(pem_data, num); 1305*b077aed3SPierre Pronchery else 1306*b077aed3SPierre Pronchery OPENSSL_free(pem_data); 1307*b077aed3SPierre Pronchery } 1308*b077aed3SPierre Pronchery static int file_read_pem(BIO *bp, char **pem_name, char **pem_header, 1309*b077aed3SPierre Pronchery unsigned char **data, long *len, 1310*b077aed3SPierre Pronchery const UI_METHOD *ui_method, void *ui_data, 1311*b077aed3SPierre Pronchery const char *uri, int secure) 1312*b077aed3SPierre Pronchery { 1313*b077aed3SPierre Pronchery int i = secure 1314*b077aed3SPierre Pronchery ? PEM_read_bio_ex(bp, pem_name, pem_header, data, len, 1315*b077aed3SPierre Pronchery PEM_FLAG_SECURE | PEM_FLAG_EAY_COMPATIBLE) 1316*b077aed3SPierre Pronchery : PEM_read_bio(bp, pem_name, pem_header, data, len); 1317*b077aed3SPierre Pronchery 1318*b077aed3SPierre Pronchery if (i <= 0) 1319*b077aed3SPierre Pronchery return 0; 1320*b077aed3SPierre Pronchery 1321*b077aed3SPierre Pronchery /* 1322*b077aed3SPierre Pronchery * 10 is the number of characters in "Proc-Type:", which 1323*b077aed3SPierre Pronchery * PEM_get_EVP_CIPHER_INFO() requires to be present. 1324*b077aed3SPierre Pronchery * If the PEM header has less characters than that, it's 1325*b077aed3SPierre Pronchery * not worth spending cycles on it. 1326*b077aed3SPierre Pronchery */ 1327*b077aed3SPierre Pronchery if (strlen(*pem_header) > 10) { 1328*b077aed3SPierre Pronchery EVP_CIPHER_INFO cipher; 1329*b077aed3SPierre Pronchery struct pem_pass_data pass_data; 1330*b077aed3SPierre Pronchery 1331*b077aed3SPierre Pronchery if (!PEM_get_EVP_CIPHER_INFO(*pem_header, &cipher) 1332*b077aed3SPierre Pronchery || !file_fill_pem_pass_data(&pass_data, "PEM pass phrase", uri, 1333*b077aed3SPierre Pronchery ui_method, ui_data) 1334*b077aed3SPierre Pronchery || !PEM_do_header(&cipher, *data, len, file_get_pem_pass, 1335*b077aed3SPierre Pronchery &pass_data)) { 1336*b077aed3SPierre Pronchery return 0; 1337*b077aed3SPierre Pronchery } 1338*b077aed3SPierre Pronchery } 1339*b077aed3SPierre Pronchery return 1; 1340*b077aed3SPierre Pronchery } 1341*b077aed3SPierre Pronchery 1342*b077aed3SPierre Pronchery static OSSL_STORE_INFO *file_try_read_msblob(BIO *bp, int *matchcount) 1343*b077aed3SPierre Pronchery { 1344*b077aed3SPierre Pronchery OSSL_STORE_INFO *result = NULL; 1345*b077aed3SPierre Pronchery int ispub = -1; 1346*b077aed3SPierre Pronchery 1347*b077aed3SPierre Pronchery { 1348*b077aed3SPierre Pronchery unsigned int magic = 0, bitlen = 0; 1349*b077aed3SPierre Pronchery int isdss = 0; 1350*b077aed3SPierre Pronchery unsigned char peekbuf[16] = { 0, }; 1351*b077aed3SPierre Pronchery const unsigned char *p = peekbuf; 1352*b077aed3SPierre Pronchery 1353*b077aed3SPierre Pronchery if (BIO_buffer_peek(bp, peekbuf, sizeof(peekbuf)) <= 0) 1354*b077aed3SPierre Pronchery return 0; 1355*b077aed3SPierre Pronchery if (ossl_do_blob_header(&p, sizeof(peekbuf), &magic, &bitlen, 1356*b077aed3SPierre Pronchery &isdss, &ispub) <= 0) 1357*b077aed3SPierre Pronchery return 0; 1358*b077aed3SPierre Pronchery } 1359*b077aed3SPierre Pronchery 1360*b077aed3SPierre Pronchery (*matchcount)++; 1361*b077aed3SPierre Pronchery 1362*b077aed3SPierre Pronchery { 1363*b077aed3SPierre Pronchery EVP_PKEY *tmp = ispub 1364*b077aed3SPierre Pronchery ? b2i_PublicKey_bio(bp) 1365*b077aed3SPierre Pronchery : b2i_PrivateKey_bio(bp); 1366*b077aed3SPierre Pronchery 1367*b077aed3SPierre Pronchery if (tmp == NULL 1368*b077aed3SPierre Pronchery || (result = OSSL_STORE_INFO_new_PKEY(tmp)) == NULL) { 1369*b077aed3SPierre Pronchery EVP_PKEY_free(tmp); 1370*b077aed3SPierre Pronchery return 0; 1371*b077aed3SPierre Pronchery } 1372*b077aed3SPierre Pronchery } 1373*b077aed3SPierre Pronchery 1374*b077aed3SPierre Pronchery return result; 1375*b077aed3SPierre Pronchery } 1376*b077aed3SPierre Pronchery 1377*b077aed3SPierre Pronchery static OSSL_STORE_INFO *file_try_read_PVK(BIO *bp, const UI_METHOD *ui_method, 1378*b077aed3SPierre Pronchery void *ui_data, const char *uri, 1379*b077aed3SPierre Pronchery int *matchcount) 1380*b077aed3SPierre Pronchery { 1381*b077aed3SPierre Pronchery OSSL_STORE_INFO *result = NULL; 1382*b077aed3SPierre Pronchery 1383*b077aed3SPierre Pronchery { 1384*b077aed3SPierre Pronchery unsigned int saltlen = 0, keylen = 0; 1385*b077aed3SPierre Pronchery unsigned char peekbuf[24] = { 0, }; 1386*b077aed3SPierre Pronchery const unsigned char *p = peekbuf; 1387*b077aed3SPierre Pronchery 1388*b077aed3SPierre Pronchery if (BIO_buffer_peek(bp, peekbuf, sizeof(peekbuf)) <= 0) 1389*b077aed3SPierre Pronchery return 0; 1390*b077aed3SPierre Pronchery if (!ossl_do_PVK_header(&p, sizeof(peekbuf), 0, &saltlen, &keylen)) 1391*b077aed3SPierre Pronchery return 0; 1392*b077aed3SPierre Pronchery } 1393*b077aed3SPierre Pronchery 1394*b077aed3SPierre Pronchery (*matchcount)++; 1395*b077aed3SPierre Pronchery 1396*b077aed3SPierre Pronchery { 1397*b077aed3SPierre Pronchery EVP_PKEY *tmp = NULL; 1398*b077aed3SPierre Pronchery struct pem_pass_data pass_data; 1399*b077aed3SPierre Pronchery 1400*b077aed3SPierre Pronchery if (!file_fill_pem_pass_data(&pass_data, "PVK pass phrase", uri, 1401*b077aed3SPierre Pronchery ui_method, ui_data) 1402*b077aed3SPierre Pronchery || (tmp = b2i_PVK_bio(bp, file_get_pem_pass, &pass_data)) == NULL 1403*b077aed3SPierre Pronchery || (result = OSSL_STORE_INFO_new_PKEY(tmp)) == NULL) { 1404*b077aed3SPierre Pronchery EVP_PKEY_free(tmp); 1405*b077aed3SPierre Pronchery return 0; 1406*b077aed3SPierre Pronchery } 1407*b077aed3SPierre Pronchery } 1408*b077aed3SPierre Pronchery 1409*b077aed3SPierre Pronchery return result; 1410*b077aed3SPierre Pronchery } 1411*b077aed3SPierre Pronchery 1412*b077aed3SPierre Pronchery static int file_read_asn1(BIO *bp, unsigned char **data, long *len) 1413*b077aed3SPierre Pronchery { 1414*b077aed3SPierre Pronchery BUF_MEM *mem = NULL; 1415*b077aed3SPierre Pronchery 1416*b077aed3SPierre Pronchery if (asn1_d2i_read_bio(bp, &mem) < 0) 1417*b077aed3SPierre Pronchery return 0; 1418*b077aed3SPierre Pronchery 1419*b077aed3SPierre Pronchery *data = (unsigned char *)mem->data; 1420*b077aed3SPierre Pronchery *len = (long)mem->length; 1421*b077aed3SPierre Pronchery OPENSSL_free(mem); 1422*b077aed3SPierre Pronchery 1423*b077aed3SPierre Pronchery return 1; 1424*b077aed3SPierre Pronchery } 1425*b077aed3SPierre Pronchery 1426*b077aed3SPierre Pronchery static int file_name_to_uri(OSSL_STORE_LOADER_CTX *ctx, const char *name, 1427*b077aed3SPierre Pronchery char **data) 1428*b077aed3SPierre Pronchery { 1429*b077aed3SPierre Pronchery assert(name != NULL); 1430*b077aed3SPierre Pronchery assert(data != NULL); 1431*b077aed3SPierre Pronchery { 1432*b077aed3SPierre Pronchery const char *pathsep = ossl_ends_with_dirsep(ctx->uri) ? "" : "/"; 1433*b077aed3SPierre Pronchery long calculated_length = strlen(ctx->uri) + strlen(pathsep) 1434*b077aed3SPierre Pronchery + strlen(name) + 1 /* \0 */; 1435*b077aed3SPierre Pronchery 1436*b077aed3SPierre Pronchery *data = OPENSSL_zalloc(calculated_length); 1437*b077aed3SPierre Pronchery if (*data == NULL) { 1438*b077aed3SPierre Pronchery ATTICerr(0, ERR_R_MALLOC_FAILURE); 1439*b077aed3SPierre Pronchery return 0; 1440*b077aed3SPierre Pronchery } 1441*b077aed3SPierre Pronchery 1442*b077aed3SPierre Pronchery OPENSSL_strlcat(*data, ctx->uri, calculated_length); 1443*b077aed3SPierre Pronchery OPENSSL_strlcat(*data, pathsep, calculated_length); 1444*b077aed3SPierre Pronchery OPENSSL_strlcat(*data, name, calculated_length); 1445*b077aed3SPierre Pronchery } 1446*b077aed3SPierre Pronchery return 1; 1447*b077aed3SPierre Pronchery } 1448*b077aed3SPierre Pronchery 1449*b077aed3SPierre Pronchery static int file_name_check(OSSL_STORE_LOADER_CTX *ctx, const char *name) 1450*b077aed3SPierre Pronchery { 1451*b077aed3SPierre Pronchery const char *p = NULL; 1452*b077aed3SPierre Pronchery size_t len = strlen(ctx->_.dir.search_name); 1453*b077aed3SPierre Pronchery 1454*b077aed3SPierre Pronchery /* If there are no search criteria, all names are accepted */ 1455*b077aed3SPierre Pronchery if (ctx->_.dir.search_name[0] == '\0') 1456*b077aed3SPierre Pronchery return 1; 1457*b077aed3SPierre Pronchery 1458*b077aed3SPierre Pronchery /* If the expected type isn't supported, no name is accepted */ 1459*b077aed3SPierre Pronchery if (ctx->expected_type != 0 1460*b077aed3SPierre Pronchery && ctx->expected_type != OSSL_STORE_INFO_CERT 1461*b077aed3SPierre Pronchery && ctx->expected_type != OSSL_STORE_INFO_CRL) 1462*b077aed3SPierre Pronchery return 0; 1463*b077aed3SPierre Pronchery 1464*b077aed3SPierre Pronchery /* 1465*b077aed3SPierre Pronchery * First, check the basename 1466*b077aed3SPierre Pronchery */ 1467*b077aed3SPierre Pronchery if (OPENSSL_strncasecmp(name, ctx->_.dir.search_name, len) != 0 1468*b077aed3SPierre Pronchery || name[len] != '.') 1469*b077aed3SPierre Pronchery return 0; 1470*b077aed3SPierre Pronchery p = &name[len + 1]; 1471*b077aed3SPierre Pronchery 1472*b077aed3SPierre Pronchery /* 1473*b077aed3SPierre Pronchery * Then, if the expected type is a CRL, check that the extension starts 1474*b077aed3SPierre Pronchery * with 'r' 1475*b077aed3SPierre Pronchery */ 1476*b077aed3SPierre Pronchery if (*p == 'r') { 1477*b077aed3SPierre Pronchery p++; 1478*b077aed3SPierre Pronchery if (ctx->expected_type != 0 1479*b077aed3SPierre Pronchery && ctx->expected_type != OSSL_STORE_INFO_CRL) 1480*b077aed3SPierre Pronchery return 0; 1481*b077aed3SPierre Pronchery } else if (ctx->expected_type == OSSL_STORE_INFO_CRL) { 1482*b077aed3SPierre Pronchery return 0; 1483*b077aed3SPierre Pronchery } 1484*b077aed3SPierre Pronchery 1485*b077aed3SPierre Pronchery /* 1486*b077aed3SPierre Pronchery * Last, check that the rest of the extension is a decimal number, at 1487*b077aed3SPierre Pronchery * least one digit long. 1488*b077aed3SPierre Pronchery */ 1489*b077aed3SPierre Pronchery if (!isdigit(*p)) 1490*b077aed3SPierre Pronchery return 0; 1491*b077aed3SPierre Pronchery while (isdigit(*p)) 1492*b077aed3SPierre Pronchery p++; 1493*b077aed3SPierre Pronchery 1494*b077aed3SPierre Pronchery #ifdef __VMS 1495*b077aed3SPierre Pronchery /* 1496*b077aed3SPierre Pronchery * One extra step here, check for a possible generation number. 1497*b077aed3SPierre Pronchery */ 1498*b077aed3SPierre Pronchery if (*p == ';') 1499*b077aed3SPierre Pronchery for (p++; *p != '\0'; p++) 1500*b077aed3SPierre Pronchery if (!ossl_isdigit(*p)) 1501*b077aed3SPierre Pronchery break; 1502*b077aed3SPierre Pronchery #endif 1503*b077aed3SPierre Pronchery 1504*b077aed3SPierre Pronchery /* 1505*b077aed3SPierre Pronchery * If we've reached the end of the string at this point, we've successfully 1506*b077aed3SPierre Pronchery * found a fitting file name. 1507*b077aed3SPierre Pronchery */ 1508*b077aed3SPierre Pronchery return *p == '\0'; 1509*b077aed3SPierre Pronchery } 1510*b077aed3SPierre Pronchery 1511*b077aed3SPierre Pronchery static int file_eof(OSSL_STORE_LOADER_CTX *ctx); 1512*b077aed3SPierre Pronchery static int file_error(OSSL_STORE_LOADER_CTX *ctx); 1513*b077aed3SPierre Pronchery static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx, 1514*b077aed3SPierre Pronchery const UI_METHOD *ui_method, 1515*b077aed3SPierre Pronchery void *ui_data) 1516*b077aed3SPierre Pronchery { 1517*b077aed3SPierre Pronchery OSSL_STORE_INFO *result = NULL; 1518*b077aed3SPierre Pronchery 1519*b077aed3SPierre Pronchery ctx->errcnt = 0; 1520*b077aed3SPierre Pronchery 1521*b077aed3SPierre Pronchery if (ctx->type == is_dir) { 1522*b077aed3SPierre Pronchery do { 1523*b077aed3SPierre Pronchery char *newname = NULL; 1524*b077aed3SPierre Pronchery 1525*b077aed3SPierre Pronchery if (ctx->_.dir.last_entry == NULL) { 1526*b077aed3SPierre Pronchery if (!ctx->_.dir.end_reached) { 1527*b077aed3SPierre Pronchery assert(ctx->_.dir.last_errno != 0); 1528*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_SYS, ctx->_.dir.last_errno); 1529*b077aed3SPierre Pronchery ctx->errcnt++; 1530*b077aed3SPierre Pronchery } 1531*b077aed3SPierre Pronchery return NULL; 1532*b077aed3SPierre Pronchery } 1533*b077aed3SPierre Pronchery 1534*b077aed3SPierre Pronchery if (ctx->_.dir.last_entry[0] != '.' 1535*b077aed3SPierre Pronchery && file_name_check(ctx, ctx->_.dir.last_entry) 1536*b077aed3SPierre Pronchery && !file_name_to_uri(ctx, ctx->_.dir.last_entry, &newname)) 1537*b077aed3SPierre Pronchery return NULL; 1538*b077aed3SPierre Pronchery 1539*b077aed3SPierre Pronchery /* 1540*b077aed3SPierre Pronchery * On the first call (with a NULL context), OPENSSL_DIR_read() 1541*b077aed3SPierre Pronchery * cares about the second argument. On the following calls, it 1542*b077aed3SPierre Pronchery * only cares that it isn't NULL. Therefore, we can safely give 1543*b077aed3SPierre Pronchery * it our URI here. 1544*b077aed3SPierre Pronchery */ 1545*b077aed3SPierre Pronchery ctx->_.dir.last_entry = OPENSSL_DIR_read(&ctx->_.dir.ctx, ctx->uri); 1546*b077aed3SPierre Pronchery ctx->_.dir.last_errno = errno; 1547*b077aed3SPierre Pronchery if (ctx->_.dir.last_entry == NULL && ctx->_.dir.last_errno == 0) 1548*b077aed3SPierre Pronchery ctx->_.dir.end_reached = 1; 1549*b077aed3SPierre Pronchery 1550*b077aed3SPierre Pronchery if (newname != NULL 1551*b077aed3SPierre Pronchery && (result = OSSL_STORE_INFO_new_NAME(newname)) == NULL) { 1552*b077aed3SPierre Pronchery OPENSSL_free(newname); 1553*b077aed3SPierre Pronchery ATTICerr(0, ERR_R_OSSL_STORE_LIB); 1554*b077aed3SPierre Pronchery return NULL; 1555*b077aed3SPierre Pronchery } 1556*b077aed3SPierre Pronchery } while (result == NULL && !file_eof(ctx)); 1557*b077aed3SPierre Pronchery } else { 1558*b077aed3SPierre Pronchery int matchcount = -1; 1559*b077aed3SPierre Pronchery 1560*b077aed3SPierre Pronchery again: 1561*b077aed3SPierre Pronchery result = file_load_try_repeat(ctx, ui_method, ui_data); 1562*b077aed3SPierre Pronchery if (result != NULL) 1563*b077aed3SPierre Pronchery return result; 1564*b077aed3SPierre Pronchery 1565*b077aed3SPierre Pronchery if (file_eof(ctx)) 1566*b077aed3SPierre Pronchery return NULL; 1567*b077aed3SPierre Pronchery 1568*b077aed3SPierre Pronchery do { 1569*b077aed3SPierre Pronchery char *pem_name = NULL; /* PEM record name */ 1570*b077aed3SPierre Pronchery char *pem_header = NULL; /* PEM record header */ 1571*b077aed3SPierre Pronchery unsigned char *data = NULL; /* DER encoded data */ 1572*b077aed3SPierre Pronchery long len = 0; /* DER encoded data length */ 1573*b077aed3SPierre Pronchery 1574*b077aed3SPierre Pronchery matchcount = -1; 1575*b077aed3SPierre Pronchery if (ctx->type == is_pem) { 1576*b077aed3SPierre Pronchery if (!file_read_pem(ctx->_.file.file, &pem_name, &pem_header, 1577*b077aed3SPierre Pronchery &data, &len, ui_method, ui_data, ctx->uri, 1578*b077aed3SPierre Pronchery (ctx->flags & FILE_FLAG_SECMEM) != 0)) { 1579*b077aed3SPierre Pronchery ctx->errcnt++; 1580*b077aed3SPierre Pronchery goto endloop; 1581*b077aed3SPierre Pronchery } 1582*b077aed3SPierre Pronchery } else { 1583*b077aed3SPierre Pronchery if ((result = file_try_read_msblob(ctx->_.file.file, 1584*b077aed3SPierre Pronchery &matchcount)) != NULL 1585*b077aed3SPierre Pronchery || (result = file_try_read_PVK(ctx->_.file.file, 1586*b077aed3SPierre Pronchery ui_method, ui_data, ctx->uri, 1587*b077aed3SPierre Pronchery &matchcount)) != NULL) 1588*b077aed3SPierre Pronchery goto endloop; 1589*b077aed3SPierre Pronchery 1590*b077aed3SPierre Pronchery if (!file_read_asn1(ctx->_.file.file, &data, &len)) { 1591*b077aed3SPierre Pronchery ctx->errcnt++; 1592*b077aed3SPierre Pronchery goto endloop; 1593*b077aed3SPierre Pronchery } 1594*b077aed3SPierre Pronchery } 1595*b077aed3SPierre Pronchery 1596*b077aed3SPierre Pronchery result = file_load_try_decode(ctx, pem_name, pem_header, data, len, 1597*b077aed3SPierre Pronchery ui_method, ui_data, &matchcount); 1598*b077aed3SPierre Pronchery 1599*b077aed3SPierre Pronchery if (result != NULL) 1600*b077aed3SPierre Pronchery goto endloop; 1601*b077aed3SPierre Pronchery 1602*b077aed3SPierre Pronchery /* 1603*b077aed3SPierre Pronchery * If a PEM name matches more than one handler, the handlers are 1604*b077aed3SPierre Pronchery * badly coded. 1605*b077aed3SPierre Pronchery */ 1606*b077aed3SPierre Pronchery if (!ossl_assert(pem_name == NULL || matchcount <= 1)) { 1607*b077aed3SPierre Pronchery ctx->errcnt++; 1608*b077aed3SPierre Pronchery goto endloop; 1609*b077aed3SPierre Pronchery } 1610*b077aed3SPierre Pronchery 1611*b077aed3SPierre Pronchery if (matchcount > 1) { 1612*b077aed3SPierre Pronchery ATTICerr(0, ATTIC_R_AMBIGUOUS_CONTENT_TYPE); 1613*b077aed3SPierre Pronchery } else if (matchcount == 1) { 1614*b077aed3SPierre Pronchery /* 1615*b077aed3SPierre Pronchery * If there are other errors on the stack, they already show 1616*b077aed3SPierre Pronchery * what the problem is. 1617*b077aed3SPierre Pronchery */ 1618*b077aed3SPierre Pronchery if (ERR_peek_error() == 0) { 1619*b077aed3SPierre Pronchery ATTICerr(0, ATTIC_R_UNSUPPORTED_CONTENT_TYPE); 1620*b077aed3SPierre Pronchery if (pem_name != NULL) 1621*b077aed3SPierre Pronchery ERR_add_error_data(3, "PEM type is '", pem_name, "'"); 1622*b077aed3SPierre Pronchery } 1623*b077aed3SPierre Pronchery } 1624*b077aed3SPierre Pronchery if (matchcount > 0) 1625*b077aed3SPierre Pronchery ctx->errcnt++; 1626*b077aed3SPierre Pronchery 1627*b077aed3SPierre Pronchery endloop: 1628*b077aed3SPierre Pronchery pem_free_flag(pem_name, (ctx->flags & FILE_FLAG_SECMEM) != 0, 0); 1629*b077aed3SPierre Pronchery pem_free_flag(pem_header, (ctx->flags & FILE_FLAG_SECMEM) != 0, 0); 1630*b077aed3SPierre Pronchery pem_free_flag(data, (ctx->flags & FILE_FLAG_SECMEM) != 0, len); 1631*b077aed3SPierre Pronchery } while (matchcount == 0 && !file_eof(ctx) && !file_error(ctx)); 1632*b077aed3SPierre Pronchery 1633*b077aed3SPierre Pronchery /* We bail out on ambiguity */ 1634*b077aed3SPierre Pronchery if (matchcount > 1) { 1635*b077aed3SPierre Pronchery store_info_free(result); 1636*b077aed3SPierre Pronchery return NULL; 1637*b077aed3SPierre Pronchery } 1638*b077aed3SPierre Pronchery 1639*b077aed3SPierre Pronchery if (result != NULL 1640*b077aed3SPierre Pronchery && ctx->expected_type != 0 1641*b077aed3SPierre Pronchery && ctx->expected_type != OSSL_STORE_INFO_get_type(result)) { 1642*b077aed3SPierre Pronchery store_info_free(result); 1643*b077aed3SPierre Pronchery goto again; 1644*b077aed3SPierre Pronchery } 1645*b077aed3SPierre Pronchery } 1646*b077aed3SPierre Pronchery 1647*b077aed3SPierre Pronchery return result; 1648*b077aed3SPierre Pronchery } 1649*b077aed3SPierre Pronchery 1650*b077aed3SPierre Pronchery static int file_error(OSSL_STORE_LOADER_CTX *ctx) 1651*b077aed3SPierre Pronchery { 1652*b077aed3SPierre Pronchery return ctx->errcnt > 0; 1653*b077aed3SPierre Pronchery } 1654*b077aed3SPierre Pronchery 1655*b077aed3SPierre Pronchery static int file_eof(OSSL_STORE_LOADER_CTX *ctx) 1656*b077aed3SPierre Pronchery { 1657*b077aed3SPierre Pronchery if (ctx->type == is_dir) 1658*b077aed3SPierre Pronchery return ctx->_.dir.end_reached; 1659*b077aed3SPierre Pronchery 1660*b077aed3SPierre Pronchery if (ctx->_.file.last_handler != NULL 1661*b077aed3SPierre Pronchery && !ctx->_.file.last_handler->eof(ctx->_.file.last_handler_ctx)) 1662*b077aed3SPierre Pronchery return 0; 1663*b077aed3SPierre Pronchery return BIO_eof(ctx->_.file.file); 1664*b077aed3SPierre Pronchery } 1665*b077aed3SPierre Pronchery 1666*b077aed3SPierre Pronchery static int file_close(OSSL_STORE_LOADER_CTX *ctx) 1667*b077aed3SPierre Pronchery { 1668*b077aed3SPierre Pronchery if ((ctx->flags & FILE_FLAG_ATTACHED) == 0) { 1669*b077aed3SPierre Pronchery if (ctx->type == is_dir) 1670*b077aed3SPierre Pronchery OPENSSL_DIR_end(&ctx->_.dir.ctx); 1671*b077aed3SPierre Pronchery else 1672*b077aed3SPierre Pronchery BIO_free_all(ctx->_.file.file); 1673*b077aed3SPierre Pronchery } else { 1674*b077aed3SPierre Pronchery /* 1675*b077aed3SPierre Pronchery * Because file_attach() called file_find_type(), we know that a 1676*b077aed3SPierre Pronchery * BIO_f_buffer() has been pushed on top of the regular BIO. 1677*b077aed3SPierre Pronchery */ 1678*b077aed3SPierre Pronchery BIO *buff = ctx->_.file.file; 1679*b077aed3SPierre Pronchery 1680*b077aed3SPierre Pronchery /* Detach buff */ 1681*b077aed3SPierre Pronchery (void)BIO_pop(ctx->_.file.file); 1682*b077aed3SPierre Pronchery /* Safety measure */ 1683*b077aed3SPierre Pronchery ctx->_.file.file = NULL; 1684*b077aed3SPierre Pronchery 1685*b077aed3SPierre Pronchery BIO_free(buff); 1686*b077aed3SPierre Pronchery } 1687*b077aed3SPierre Pronchery OSSL_STORE_LOADER_CTX_free(ctx); 1688*b077aed3SPierre Pronchery return 1; 1689*b077aed3SPierre Pronchery } 1690*b077aed3SPierre Pronchery 1691*b077aed3SPierre Pronchery /*- 1692*b077aed3SPierre Pronchery * ENGINE management 1693*b077aed3SPierre Pronchery */ 1694*b077aed3SPierre Pronchery 1695*b077aed3SPierre Pronchery static const char *loader_attic_id = "loader_attic"; 1696*b077aed3SPierre Pronchery static const char *loader_attic_name = "'file:' loader"; 1697*b077aed3SPierre Pronchery 1698*b077aed3SPierre Pronchery static OSSL_STORE_LOADER *loader_attic = NULL; 1699*b077aed3SPierre Pronchery 1700*b077aed3SPierre Pronchery static int loader_attic_init(ENGINE *e) 1701*b077aed3SPierre Pronchery { 1702*b077aed3SPierre Pronchery return 1; 1703*b077aed3SPierre Pronchery } 1704*b077aed3SPierre Pronchery 1705*b077aed3SPierre Pronchery 1706*b077aed3SPierre Pronchery static int loader_attic_finish(ENGINE *e) 1707*b077aed3SPierre Pronchery { 1708*b077aed3SPierre Pronchery return 1; 1709*b077aed3SPierre Pronchery } 1710*b077aed3SPierre Pronchery 1711*b077aed3SPierre Pronchery 1712*b077aed3SPierre Pronchery static int loader_attic_destroy(ENGINE *e) 1713*b077aed3SPierre Pronchery { 1714*b077aed3SPierre Pronchery OSSL_STORE_LOADER *loader = OSSL_STORE_unregister_loader("file"); 1715*b077aed3SPierre Pronchery 1716*b077aed3SPierre Pronchery if (loader == NULL) 1717*b077aed3SPierre Pronchery return 0; 1718*b077aed3SPierre Pronchery 1719*b077aed3SPierre Pronchery ERR_unload_ATTIC_strings(); 1720*b077aed3SPierre Pronchery OSSL_STORE_LOADER_free(loader); 1721*b077aed3SPierre Pronchery return 1; 1722*b077aed3SPierre Pronchery } 1723*b077aed3SPierre Pronchery 1724*b077aed3SPierre Pronchery static int bind_loader_attic(ENGINE *e) 1725*b077aed3SPierre Pronchery { 1726*b077aed3SPierre Pronchery 1727*b077aed3SPierre Pronchery /* Ensure the ATTIC error handling is set up on best effort basis */ 1728*b077aed3SPierre Pronchery ERR_load_ATTIC_strings(); 1729*b077aed3SPierre Pronchery 1730*b077aed3SPierre Pronchery if (/* Create the OSSL_STORE_LOADER */ 1731*b077aed3SPierre Pronchery (loader_attic = OSSL_STORE_LOADER_new(e, "file")) == NULL 1732*b077aed3SPierre Pronchery || !OSSL_STORE_LOADER_set_open_ex(loader_attic, file_open_ex) 1733*b077aed3SPierre Pronchery || !OSSL_STORE_LOADER_set_open(loader_attic, file_open) 1734*b077aed3SPierre Pronchery || !OSSL_STORE_LOADER_set_attach(loader_attic, file_attach) 1735*b077aed3SPierre Pronchery || !OSSL_STORE_LOADER_set_ctrl(loader_attic, file_ctrl) 1736*b077aed3SPierre Pronchery || !OSSL_STORE_LOADER_set_expect(loader_attic, file_expect) 1737*b077aed3SPierre Pronchery || !OSSL_STORE_LOADER_set_find(loader_attic, file_find) 1738*b077aed3SPierre Pronchery || !OSSL_STORE_LOADER_set_load(loader_attic, file_load) 1739*b077aed3SPierre Pronchery || !OSSL_STORE_LOADER_set_eof(loader_attic, file_eof) 1740*b077aed3SPierre Pronchery || !OSSL_STORE_LOADER_set_error(loader_attic, file_error) 1741*b077aed3SPierre Pronchery || !OSSL_STORE_LOADER_set_close(loader_attic, file_close) 1742*b077aed3SPierre Pronchery /* Init the engine itself */ 1743*b077aed3SPierre Pronchery || !ENGINE_set_id(e, loader_attic_id) 1744*b077aed3SPierre Pronchery || !ENGINE_set_name(e, loader_attic_name) 1745*b077aed3SPierre Pronchery || !ENGINE_set_destroy_function(e, loader_attic_destroy) 1746*b077aed3SPierre Pronchery || !ENGINE_set_init_function(e, loader_attic_init) 1747*b077aed3SPierre Pronchery || !ENGINE_set_finish_function(e, loader_attic_finish) 1748*b077aed3SPierre Pronchery /* Finally, register the method with libcrypto */ 1749*b077aed3SPierre Pronchery || !OSSL_STORE_register_loader(loader_attic)) { 1750*b077aed3SPierre Pronchery OSSL_STORE_LOADER_free(loader_attic); 1751*b077aed3SPierre Pronchery loader_attic = NULL; 1752*b077aed3SPierre Pronchery ATTICerr(0, ATTIC_R_INIT_FAILED); 1753*b077aed3SPierre Pronchery return 0; 1754*b077aed3SPierre Pronchery } 1755*b077aed3SPierre Pronchery 1756*b077aed3SPierre Pronchery return 1; 1757*b077aed3SPierre Pronchery } 1758*b077aed3SPierre Pronchery 1759*b077aed3SPierre Pronchery #ifdef OPENSSL_NO_DYNAMIC_ENGINE 1760*b077aed3SPierre Pronchery # error "Only allowed as dynamically shared object" 1761*b077aed3SPierre Pronchery #endif 1762*b077aed3SPierre Pronchery 1763*b077aed3SPierre Pronchery static int bind_helper(ENGINE *e, const char *id) 1764*b077aed3SPierre Pronchery { 1765*b077aed3SPierre Pronchery if (id && (strcmp(id, loader_attic_id) != 0)) 1766*b077aed3SPierre Pronchery return 0; 1767*b077aed3SPierre Pronchery if (!bind_loader_attic(e)) 1768*b077aed3SPierre Pronchery return 0; 1769*b077aed3SPierre Pronchery return 1; 1770*b077aed3SPierre Pronchery } 1771*b077aed3SPierre Pronchery 1772*b077aed3SPierre Pronchery IMPLEMENT_DYNAMIC_CHECK_FN() 1773*b077aed3SPierre Pronchery IMPLEMENT_DYNAMIC_BIND_FN(bind_helper) 1774