Path: blob/main/crypto/openssl/engines/e_loader_attic.c
106594 views
/*1* Copyright 2016-2025 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the Apache License 2.0 (the "License"). You may not use4* this file except in compliance with the License. You can obtain a copy5* in the file LICENSE in the source distribution or at6* https://www.openssl.org/source/license.html7*/89/* THIS ENGINE IS FOR TESTING PURPOSES ONLY. */1011/* This file has quite some overlap with providers/implementations/storemgmt/file_store.c */1213/* We need to use some engine deprecated APIs */14#define OPENSSL_SUPPRESS_DEPRECATED1516#include "internal/e_os.h" /* for stat */17#include <string.h>18#include <sys/stat.h>19#include <ctype.h>20#include <assert.h>2122#include <openssl/bio.h>23#include <openssl/dsa.h> /* For d2i_DSAPrivateKey */24#include <openssl/err.h>25#include <openssl/evp.h>26#include <openssl/pem.h>27#include <openssl/pkcs12.h> /* For the PKCS8 stuff o.O */28#include <openssl/rsa.h> /* For d2i_RSAPrivateKey */29#include <openssl/safestack.h>30#include <openssl/store.h>31#include <openssl/ui.h>32#include <openssl/engine.h>33#include <openssl/x509.h> /* For the PKCS8 stuff o.O */34#include "internal/asn1.h" /* For asn1_d2i_read_bio */35#include "internal/o_dir.h"36#include "internal/cryptlib.h"37#include "crypto/ctype.h" /* For ossl_isdigit */38#include "crypto/pem.h" /* For PVK and "blob" PEM headers */3940/* clang-format off */41#include "e_loader_attic_err.c"42/* clang-format on */4344DEFINE_STACK_OF(OSSL_STORE_INFO)4546#ifndef S_ISDIR47#define S_ISDIR(a) (((a) & S_IFMT) == S_IFDIR)48#endif4950/*-51* Password prompting52* ------------------53*/5455static char *file_get_pass(const UI_METHOD *ui_method, char *pass,56size_t maxsize, const char *desc, const char *info,57void *data)58{59UI *ui = UI_new();60char *prompt = NULL;6162if (ui == NULL) {63ATTICerr(0, ERR_R_UI_LIB);64return NULL;65}6667if (ui_method != NULL)68UI_set_method(ui, ui_method);69UI_add_user_data(ui, data);7071if ((prompt = UI_construct_prompt(ui, desc, info)) == NULL) {72ATTICerr(0, ERR_R_UI_LIB);73pass = NULL;74} else if (UI_add_input_string(ui, prompt, UI_INPUT_FLAG_DEFAULT_PWD,75pass, 0, maxsize - 1)76<= 0) {77ATTICerr(0, ERR_R_UI_LIB);78pass = NULL;79} else {80switch (UI_process(ui)) {81case -2:82ATTICerr(0, ATTIC_R_UI_PROCESS_INTERRUPTED_OR_CANCELLED);83pass = NULL;84break;85case -1:86ATTICerr(0, ERR_R_UI_LIB);87pass = NULL;88break;89default:90break;91}92}9394OPENSSL_free(prompt);95UI_free(ui);96return pass;97}9899struct pem_pass_data {100const UI_METHOD *ui_method;101void *data;102const char *prompt_desc;103const char *prompt_info;104};105106static int file_fill_pem_pass_data(struct pem_pass_data *pass_data,107const char *desc, const char *info,108const UI_METHOD *ui_method, void *ui_data)109{110if (pass_data == NULL)111return 0;112pass_data->ui_method = ui_method;113pass_data->data = ui_data;114pass_data->prompt_desc = desc;115pass_data->prompt_info = info;116return 1;117}118119/* This is used anywhere a pem_password_cb is needed */120static int file_get_pem_pass(char *buf, int num, int w, void *data)121{122struct pem_pass_data *pass_data = data;123char *pass = file_get_pass(pass_data->ui_method, buf, num,124pass_data->prompt_desc, pass_data->prompt_info,125pass_data->data);126127return pass == NULL ? 0 : strlen(pass);128}129130/*131* Check if |str| ends with |suffix| preceded by a space, and if it does,132* return the index of that space. If there is no such suffix in |str|,133* return -1.134* For |str| == "FOO BAR" and |suffix| == "BAR", the returned value is 3.135*/136static int check_suffix(const char *str, const char *suffix)137{138int str_len = strlen(str);139int suffix_len = strlen(suffix) + 1;140const char *p = NULL;141142if (suffix_len >= str_len)143return -1;144p = str + str_len - suffix_len;145if (*p != ' '146|| strcmp(p + 1, suffix) != 0)147return -1;148return p - str;149}150151/*152* EMBEDDED is a special type of OSSL_STORE_INFO, specially for the file153* handlers, so we define it internally. This uses the possibility to154* create an OSSL_STORE_INFO with a generic data pointer and arbitrary155* type number.156*157* This is used by a FILE_HANDLER's try_decode function to signal that it158* has decoded the incoming blob into a new blob, and that the attempted159* decoding should be immediately restarted with the new blob, using the160* new PEM name.161*/162/* Negative numbers are never used for public OSSL_STORE_INFO types */163#define STORE_INFO_EMBEDDED -1164165/* This is the embedded data */166struct embedded_st {167BUF_MEM *blob;168char *pem_name;169};170171/* Helper functions */172static struct embedded_st *get0_EMBEDDED(OSSL_STORE_INFO *info)173{174return OSSL_STORE_INFO_get0_data(STORE_INFO_EMBEDDED, info);175}176177static void store_info_free(OSSL_STORE_INFO *info)178{179struct embedded_st *data;180181if (info != NULL && (data = get0_EMBEDDED(info)) != NULL) {182BUF_MEM_free(data->blob);183OPENSSL_free(data->pem_name);184OPENSSL_free(data);185}186OSSL_STORE_INFO_free(info);187}188189static OSSL_STORE_INFO *new_EMBEDDED(const char *new_pem_name,190BUF_MEM *embedded)191{192OSSL_STORE_INFO *info = NULL;193struct embedded_st *data = NULL;194195if ((data = OPENSSL_zalloc(sizeof(*data))) == NULL)196return NULL;197if ((info = OSSL_STORE_INFO_new(STORE_INFO_EMBEDDED, data)) == NULL) {198ATTICerr(0, ERR_R_OSSL_STORE_LIB);199OPENSSL_free(data);200return NULL;201}202203data->blob = embedded;204data->pem_name = new_pem_name == NULL ? NULL : OPENSSL_strdup(new_pem_name);205206if (new_pem_name != NULL && data->pem_name == NULL) {207store_info_free(info);208info = NULL;209}210211return info;212}213214/*-215* The file scheme decoders216* ------------------------217*218* Each possible data type has its own decoder, which either operates219* through a given PEM name, or attempts to decode to see if the blob220* it's given is decodable for its data type. The assumption is that221* only the correct data type will match the content.222*/223224/*-225* The try_decode function is called to check if the blob of data can226* be used by this handler, and if it can, decodes it into a supported227* OpenSSL type and returns an OSSL_STORE_INFO with the decoded data.228* Input:229* pem_name: If this blob comes from a PEM file, this holds230* the PEM name. If it comes from another type of231* file, this is NULL.232* pem_header: If this blob comes from a PEM file, this holds233* the PEM headers. If it comes from another type of234* file, this is NULL.235* blob: The blob of data to match with what this handler236* can use.237* len: The length of the blob.238* handler_ctx: For a handler marked repeatable, this pointer can239* be used to create a context for the handler. IT IS240* THE HANDLER'S RESPONSIBILITY TO CREATE AND DESTROY241* THIS CONTEXT APPROPRIATELY, i.e. create on first call242* and destroy when about to return NULL.243* matchcount: A pointer to an int to count matches for this data.244* Usually becomes 0 (no match) or 1 (match!), but may245* be higher in the (unlikely) event that the data matches246* more than one possibility. The int will always be247* zero when the function is called.248* ui_method: Application UI method for getting a password, pin249* or any other interactive data.250* ui_data: Application data to be passed to ui_method when251* it's called.252* libctx: The library context to be used if applicable253* propq: The property query string for any algorithm fetches254* Output:255* an OSSL_STORE_INFO256*/257typedef OSSL_STORE_INFO *(*file_try_decode_fn)(const char *pem_name,258const char *pem_header,259const unsigned char *blob,260size_t len, void **handler_ctx,261int *matchcount,262const UI_METHOD *ui_method,263void *ui_data, const char *uri,264OSSL_LIB_CTX *libctx,265const char *propq);266/*267* The eof function should return 1 if there's no more data to be found268* with the handler_ctx, otherwise 0. This is only used when the handler is269* marked repeatable.270*/271typedef int (*file_eof_fn)(void *handler_ctx);272/*273* The destroy_ctx function is used to destroy the handler_ctx that was274* initiated by a repeatable try_decode function. This is only used when275* the handler is marked repeatable.276*/277typedef void (*file_destroy_ctx_fn)(void **handler_ctx);278279typedef struct file_handler_st {280const char *name;281file_try_decode_fn try_decode;282file_eof_fn eof;283file_destroy_ctx_fn destroy_ctx;284285/* flags */286int repeatable;287} FILE_HANDLER;288289/*290* PKCS#12 decoder. It operates by decoding all of the blob content,291* extracting all the interesting data from it and storing them internally,292* then serving them one piece at a time.293*/294static OSSL_STORE_INFO *try_decode_PKCS12(const char *pem_name,295const char *pem_header,296const unsigned char *blob,297size_t len, void **pctx,298int *matchcount,299const UI_METHOD *ui_method,300void *ui_data, const char *uri,301OSSL_LIB_CTX *libctx,302const char *propq)303{304OSSL_STORE_INFO *store_info = NULL;305STACK_OF(OSSL_STORE_INFO) *ctx = *pctx;306307if (ctx == NULL) {308/* Initial parsing */309PKCS12 *p12;310311if (pem_name != NULL)312/* No match, there is no PEM PKCS12 tag */313return NULL;314315if ((p12 = d2i_PKCS12(NULL, &blob, len)) != NULL) {316char *pass = NULL;317char tpass[PEM_BUFSIZE];318EVP_PKEY *pkey = NULL;319X509 *cert = NULL;320STACK_OF(X509) *chain = NULL;321322*matchcount = 1;323324if (!PKCS12_mac_present(p12)325|| PKCS12_verify_mac(p12, "", 0)326|| PKCS12_verify_mac(p12, NULL, 0)) {327pass = "";328} else {329if ((pass = file_get_pass(ui_method, tpass, PEM_BUFSIZE,330"PKCS12 import", uri,331ui_data))332== NULL) {333ATTICerr(0, ATTIC_R_PASSPHRASE_CALLBACK_ERROR);334goto p12_end;335}336if (!PKCS12_verify_mac(p12, pass, strlen(pass))) {337ATTICerr(0, ATTIC_R_ERROR_VERIFYING_PKCS12_MAC);338goto p12_end;339}340}341342if (PKCS12_parse(p12, pass, &pkey, &cert, &chain)) {343OSSL_STORE_INFO *osi_pkey = NULL;344OSSL_STORE_INFO *osi_cert = NULL;345OSSL_STORE_INFO *osi_ca = NULL;346int ok = 1;347348if ((ctx = sk_OSSL_STORE_INFO_new_null()) != NULL) {349if (pkey != NULL) {350if ((osi_pkey = OSSL_STORE_INFO_new_PKEY(pkey)) != NULL351/* clearing pkey here avoids case distinctions */352&& (pkey = NULL) == NULL353&& sk_OSSL_STORE_INFO_push(ctx, osi_pkey) != 0)354osi_pkey = NULL;355else356ok = 0;357}358if (ok && cert != NULL) {359if ((osi_cert = OSSL_STORE_INFO_new_CERT(cert)) != NULL360/* clearing cert here avoids case distinctions */361&& (cert = NULL) == NULL362&& sk_OSSL_STORE_INFO_push(ctx, osi_cert) != 0)363osi_cert = NULL;364else365ok = 0;366}367while (ok && sk_X509_num(chain) > 0) {368X509 *ca = sk_X509_value(chain, 0);369370if ((osi_ca = OSSL_STORE_INFO_new_CERT(ca)) != NULL371&& sk_X509_shift(chain) != NULL372&& sk_OSSL_STORE_INFO_push(ctx, osi_ca) != 0)373osi_ca = NULL;374else375ok = 0;376}377}378EVP_PKEY_free(pkey);379X509_free(cert);380OSSL_STACK_OF_X509_free(chain);381store_info_free(osi_pkey);382store_info_free(osi_cert);383store_info_free(osi_ca);384if (!ok) {385sk_OSSL_STORE_INFO_pop_free(ctx, store_info_free);386ctx = NULL;387}388*pctx = ctx;389}390}391p12_end:392PKCS12_free(p12);393if (ctx == NULL)394return NULL;395}396397*matchcount = 1;398store_info = sk_OSSL_STORE_INFO_shift(ctx);399return store_info;400}401402static int eof_PKCS12(void *ctx_)403{404STACK_OF(OSSL_STORE_INFO) *ctx = ctx_;405406return ctx == NULL || sk_OSSL_STORE_INFO_num(ctx) == 0;407}408409static void destroy_ctx_PKCS12(void **pctx)410{411STACK_OF(OSSL_STORE_INFO) *ctx = *pctx;412413sk_OSSL_STORE_INFO_pop_free(ctx, store_info_free);414*pctx = NULL;415}416417static FILE_HANDLER PKCS12_handler = {418"PKCS12",419try_decode_PKCS12,420eof_PKCS12,421destroy_ctx_PKCS12,4221 /* repeatable */423};424425/*426* Encrypted PKCS#8 decoder. It operates by just decrypting the given blob427* into a new blob, which is returned as an EMBEDDED STORE_INFO. The whole428* decoding process will then start over with the new blob.429*/430static OSSL_STORE_INFO *try_decode_PKCS8Encrypted(const char *pem_name,431const char *pem_header,432const unsigned char *blob,433size_t len, void **pctx,434int *matchcount,435const UI_METHOD *ui_method,436void *ui_data,437const char *uri,438OSSL_LIB_CTX *libctx,439const char *propq)440{441X509_SIG *p8 = NULL;442char kbuf[PEM_BUFSIZE];443char *pass = NULL;444const X509_ALGOR *dalg = NULL;445const ASN1_OCTET_STRING *doct = NULL;446OSSL_STORE_INFO *store_info = NULL;447BUF_MEM *mem = NULL;448unsigned char *new_data = NULL;449int new_data_len;450451if (pem_name != NULL) {452if (strcmp(pem_name, PEM_STRING_PKCS8) != 0)453return NULL;454*matchcount = 1;455}456457if ((p8 = d2i_X509_SIG(NULL, &blob, len)) == NULL)458return NULL;459460*matchcount = 1;461462if ((mem = BUF_MEM_new()) == NULL) {463ATTICerr(0, ERR_R_BUF_LIB);464goto nop8;465}466467if ((pass = file_get_pass(ui_method, kbuf, PEM_BUFSIZE,468"PKCS8 decrypt pass phrase", uri,469ui_data))470== NULL) {471ATTICerr(0, ATTIC_R_BAD_PASSWORD_READ);472goto nop8;473}474475X509_SIG_get0(p8, &dalg, &doct);476if (!PKCS12_pbe_crypt(dalg, pass, strlen(pass), doct->data, doct->length,477&new_data, &new_data_len, 0))478goto nop8;479480mem->data = (char *)new_data;481mem->max = mem->length = (size_t)new_data_len;482X509_SIG_free(p8);483p8 = NULL;484485store_info = new_EMBEDDED(PEM_STRING_PKCS8INF, mem);486if (store_info == NULL) {487ATTICerr(0, ERR_R_OSSL_STORE_LIB);488goto nop8;489}490491return store_info;492nop8:493X509_SIG_free(p8);494BUF_MEM_free(mem);495return NULL;496}497498static FILE_HANDLER PKCS8Encrypted_handler = {499"PKCS8Encrypted",500try_decode_PKCS8Encrypted501};502503/*504* Private key decoder. Decodes all sorts of private keys, both PKCS#8505* encoded ones and old style PEM ones (with the key type is encoded into506* the PEM name).507*/508static OSSL_STORE_INFO *try_decode_PrivateKey(const char *pem_name,509const char *pem_header,510const unsigned char *blob,511size_t len, void **pctx,512int *matchcount,513const UI_METHOD *ui_method,514void *ui_data, const char *uri,515OSSL_LIB_CTX *libctx,516const char *propq)517{518OSSL_STORE_INFO *store_info = NULL;519EVP_PKEY *pkey = NULL;520const EVP_PKEY_ASN1_METHOD *ameth = NULL;521522if (pem_name != NULL) {523if (strcmp(pem_name, PEM_STRING_PKCS8INF) == 0) {524PKCS8_PRIV_KEY_INFO *p8inf = d2i_PKCS8_PRIV_KEY_INFO(NULL, &blob, len);525526*matchcount = 1;527if (p8inf != NULL)528pkey = EVP_PKCS82PKEY_ex(p8inf, libctx, propq);529PKCS8_PRIV_KEY_INFO_free(p8inf);530} else {531int slen;532int pkey_id;533534if ((slen = check_suffix(pem_name, "PRIVATE KEY")) > 0535&& (ameth = EVP_PKEY_asn1_find_str(NULL, pem_name,536slen))537!= NULL538&& EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL,539ameth)) {540*matchcount = 1;541pkey = d2i_PrivateKey_ex(pkey_id, NULL, &blob, len,542libctx, propq);543}544}545} else {546int i;547#ifndef OPENSSL_NO_ENGINE548ENGINE *curengine = ENGINE_get_first();549550while (curengine != NULL) {551ENGINE_PKEY_ASN1_METHS_PTR asn1meths = ENGINE_get_pkey_asn1_meths(curengine);552553if (asn1meths != NULL) {554const int *nids = NULL;555int nids_n = asn1meths(curengine, NULL, &nids, 0);556557for (i = 0; i < nids_n; i++) {558EVP_PKEY_ASN1_METHOD *ameth2 = NULL;559EVP_PKEY *tmp_pkey = NULL;560const unsigned char *tmp_blob = blob;561int pkey_id, pkey_flags;562563if (!asn1meths(curengine, &ameth2, NULL, nids[i])564|| !EVP_PKEY_asn1_get0_info(&pkey_id, NULL,565&pkey_flags, NULL, NULL,566ameth2)567|| (pkey_flags & ASN1_PKEY_ALIAS) != 0)568continue;569570ERR_set_mark(); /* prevent flooding error queue */571tmp_pkey = d2i_PrivateKey_ex(pkey_id, NULL,572&tmp_blob, len,573libctx, propq);574if (tmp_pkey != NULL) {575if (pkey != NULL)576EVP_PKEY_free(tmp_pkey);577else578pkey = tmp_pkey;579(*matchcount)++;580}581ERR_pop_to_mark();582}583}584curengine = ENGINE_get_next(curengine);585}586#endif587588for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) {589EVP_PKEY *tmp_pkey = NULL;590const unsigned char *tmp_blob = blob;591int pkey_id, pkey_flags;592593ameth = EVP_PKEY_asn1_get0(i);594if (!EVP_PKEY_asn1_get0_info(&pkey_id, NULL, &pkey_flags, NULL,595NULL, ameth)596|| (pkey_flags & ASN1_PKEY_ALIAS) != 0)597continue;598599ERR_set_mark(); /* prevent flooding error queue */600tmp_pkey = d2i_PrivateKey_ex(pkey_id, NULL, &tmp_blob, len,601libctx, propq);602if (tmp_pkey != NULL) {603if (pkey != NULL)604EVP_PKEY_free(tmp_pkey);605else606pkey = tmp_pkey;607(*matchcount)++;608}609ERR_pop_to_mark();610}611612if (*matchcount > 1) {613EVP_PKEY_free(pkey);614pkey = NULL;615}616}617if (pkey == NULL)618/* No match */619return NULL;620621store_info = OSSL_STORE_INFO_new_PKEY(pkey);622if (store_info == NULL)623EVP_PKEY_free(pkey);624625return store_info;626}627628static FILE_HANDLER PrivateKey_handler = {629"PrivateKey",630try_decode_PrivateKey631};632633/*634* Public key decoder. Only supports SubjectPublicKeyInfo formatted keys.635*/636static OSSL_STORE_INFO *try_decode_PUBKEY(const char *pem_name,637const char *pem_header,638const unsigned char *blob,639size_t len, void **pctx,640int *matchcount,641const UI_METHOD *ui_method,642void *ui_data, const char *uri,643OSSL_LIB_CTX *libctx,644const char *propq)645{646OSSL_STORE_INFO *store_info = NULL;647EVP_PKEY *pkey = NULL;648649if (pem_name != NULL) {650if (strcmp(pem_name, PEM_STRING_PUBLIC) != 0)651/* No match */652return NULL;653*matchcount = 1;654}655656if ((pkey = d2i_PUBKEY(NULL, &blob, len)) != NULL) {657*matchcount = 1;658store_info = OSSL_STORE_INFO_new_PUBKEY(pkey);659}660661return store_info;662}663664static FILE_HANDLER PUBKEY_handler = {665"PUBKEY",666try_decode_PUBKEY667};668669/*670* Key parameter decoder.671*/672static OSSL_STORE_INFO *try_decode_params(const char *pem_name,673const char *pem_header,674const unsigned char *blob,675size_t len, void **pctx,676int *matchcount,677const UI_METHOD *ui_method,678void *ui_data, const char *uri,679OSSL_LIB_CTX *libctx,680const char *propq)681{682OSSL_STORE_INFO *store_info = NULL;683EVP_PKEY *pkey = NULL;684const EVP_PKEY_ASN1_METHOD *ameth = NULL;685686if (pem_name != NULL) {687int slen;688int pkey_id;689690if ((slen = check_suffix(pem_name, "PARAMETERS")) > 0691&& (ameth = EVP_PKEY_asn1_find_str(NULL, pem_name, slen)) != NULL692&& EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL,693ameth)) {694*matchcount = 1;695pkey = d2i_KeyParams(pkey_id, NULL, &blob, len);696}697} else {698int i;699700for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) {701EVP_PKEY *tmp_pkey = NULL;702const unsigned char *tmp_blob = blob;703int pkey_id, pkey_flags;704705ameth = EVP_PKEY_asn1_get0(i);706if (!EVP_PKEY_asn1_get0_info(&pkey_id, NULL, &pkey_flags, NULL,707NULL, ameth)708|| (pkey_flags & ASN1_PKEY_ALIAS) != 0)709continue;710711ERR_set_mark(); /* prevent flooding error queue */712713tmp_pkey = d2i_KeyParams(pkey_id, NULL, &tmp_blob, len);714715if (tmp_pkey != NULL) {716if (pkey != NULL)717EVP_PKEY_free(tmp_pkey);718else719pkey = tmp_pkey;720(*matchcount)++;721}722ERR_pop_to_mark();723}724725if (*matchcount > 1) {726EVP_PKEY_free(pkey);727pkey = NULL;728}729}730if (pkey == NULL)731/* No match */732return NULL;733734store_info = OSSL_STORE_INFO_new_PARAMS(pkey);735if (store_info == NULL)736EVP_PKEY_free(pkey);737738return store_info;739}740741static FILE_HANDLER params_handler = {742"params",743try_decode_params744};745746/*747* X.509 certificate decoder.748*/749static OSSL_STORE_INFO *try_decode_X509Certificate(const char *pem_name,750const char *pem_header,751const unsigned char *blob,752size_t len, void **pctx,753int *matchcount,754const UI_METHOD *ui_method,755void *ui_data,756const char *uri,757OSSL_LIB_CTX *libctx,758const char *propq)759{760OSSL_STORE_INFO *store_info = NULL;761X509 *cert = NULL;762763/*764* In most cases, we can try to interpret the serialized data as a trusted765* cert (X509 + X509_AUX) and fall back to reading it as a normal cert766* (just X509), but if the PEM name specifically declares it as a trusted767* cert, then no fallback should be engaged. |ignore_trusted| tells if768* the fallback can be used (1) or not (0).769*/770int ignore_trusted = 1;771772if (pem_name != NULL) {773if (strcmp(pem_name, PEM_STRING_X509_TRUSTED) == 0)774ignore_trusted = 0;775else if (strcmp(pem_name, PEM_STRING_X509_OLD) != 0776&& strcmp(pem_name, PEM_STRING_X509) != 0)777/* No match */778return NULL;779*matchcount = 1;780}781782cert = X509_new_ex(libctx, propq);783if (cert == NULL)784return NULL;785786if ((d2i_X509_AUX(&cert, &blob, len)) != NULL787|| (ignore_trusted && (d2i_X509(&cert, &blob, len)) != NULL)) {788*matchcount = 1;789store_info = OSSL_STORE_INFO_new_CERT(cert);790}791792if (store_info == NULL)793X509_free(cert);794795return store_info;796}797798static FILE_HANDLER X509Certificate_handler = {799"X509Certificate",800try_decode_X509Certificate801};802803/*804* X.509 CRL decoder.805*/806static OSSL_STORE_INFO *try_decode_X509CRL(const char *pem_name,807const char *pem_header,808const unsigned char *blob,809size_t len, void **pctx,810int *matchcount,811const UI_METHOD *ui_method,812void *ui_data, const char *uri,813OSSL_LIB_CTX *libctx,814const char *propq)815{816OSSL_STORE_INFO *store_info = NULL;817X509_CRL *crl = NULL;818819if (pem_name != NULL) {820if (strcmp(pem_name, PEM_STRING_X509_CRL) != 0)821/* No match */822return NULL;823*matchcount = 1;824}825826if ((crl = d2i_X509_CRL(NULL, &blob, len)) != NULL) {827*matchcount = 1;828store_info = OSSL_STORE_INFO_new_CRL(crl);829}830831if (store_info == NULL)832X509_CRL_free(crl);833834return store_info;835}836837static FILE_HANDLER X509CRL_handler = {838"X509CRL",839try_decode_X509CRL840};841842/*843* To finish it all off, we collect all the handlers.844*/845static const FILE_HANDLER *file_handlers[] = {846&PKCS12_handler,847&PKCS8Encrypted_handler,848&X509Certificate_handler,849&X509CRL_handler,850¶ms_handler,851&PUBKEY_handler,852&PrivateKey_handler,853};854855/*-856* The loader itself857* -----------------858*/859860struct ossl_store_loader_ctx_st {861char *uri; /* The URI we currently try to load */862enum {863is_raw = 0,864is_pem,865is_dir866} type;867int errcnt;868#define FILE_FLAG_SECMEM (1 << 0)869#define FILE_FLAG_ATTACHED (1 << 1)870unsigned int flags;871union {872struct { /* Used with is_raw and is_pem */873BIO *file;874875/*876* The following are used when the handler is marked as877* repeatable878*/879const FILE_HANDLER *last_handler;880void *last_handler_ctx;881} file;882struct { /* Used with is_dir */883OPENSSL_DIR_CTX *ctx;884int end_reached;885886/*887* When a search expression is given, these are filled in.888* |search_name| contains the file basename to look for.889* The string is exactly 8 characters long.890*/891char search_name[9];892893/*894* The directory reading utility we have combines opening with895* reading the first name. To make sure we can detect the end896* at the right time, we read early and cache the name.897*/898const char *last_entry;899int last_errno;900} dir;901} _;902903/* Expected object type. May be unspecified */904int expected_type;905906OSSL_LIB_CTX *libctx;907char *propq;908};909910static void OSSL_STORE_LOADER_CTX_free(OSSL_STORE_LOADER_CTX *ctx)911{912if (ctx == NULL)913return;914915OPENSSL_free(ctx->propq);916OPENSSL_free(ctx->uri);917if (ctx->type != is_dir) {918if (ctx->_.file.last_handler != NULL) {919ctx->_.file.last_handler->destroy_ctx(&ctx->_.file.last_handler_ctx);920ctx->_.file.last_handler_ctx = NULL;921ctx->_.file.last_handler = NULL;922}923}924OPENSSL_free(ctx);925}926927static int file_find_type(OSSL_STORE_LOADER_CTX *ctx)928{929BIO *buff = NULL;930char peekbuf[4096] = {9310,932};933934if ((buff = BIO_new(BIO_f_buffer())) == NULL)935return 0;936937ctx->_.file.file = BIO_push(buff, ctx->_.file.file);938if (BIO_buffer_peek(ctx->_.file.file, peekbuf, sizeof(peekbuf) - 1) > 0) {939peekbuf[sizeof(peekbuf) - 1] = '\0';940if (strstr(peekbuf, "-----BEGIN ") != NULL)941ctx->type = is_pem;942}943return 1;944}945946static OSSL_STORE_LOADER_CTX *file_open_ex(const OSSL_STORE_LOADER *loader, const char *uri,947OSSL_LIB_CTX *libctx, const char *propq,948const UI_METHOD *ui_method, void *ui_data)949{950OSSL_STORE_LOADER_CTX *ctx = NULL;951struct stat st;952struct {953const char *path;954unsigned int check_absolute : 1;955} path_data[2];956size_t path_data_n = 0, i;957const char *path, *p = uri, *q;958959/*960* First step, just take the URI as is.961*/962path_data[path_data_n].check_absolute = 0;963path_data[path_data_n++].path = uri;964965/*966* Second step, if the URI appears to start with the "file" scheme,967* extract the path and make that the second path to check.968* There's a special case if the URI also contains an authority, then969* the full URI shouldn't be used as a path anywhere.970*/971if (CHECK_AND_SKIP_CASE_PREFIX(p, "file:")) {972q = p;973if (CHECK_AND_SKIP_PREFIX(q, "//")) {974path_data_n--; /* Invalidate using the full URI */975if (CHECK_AND_SKIP_CASE_PREFIX(q, "localhost/")976|| CHECK_AND_SKIP_PREFIX(q, "/")) {977p = q - 1;978} else {979ATTICerr(0, ATTIC_R_URI_AUTHORITY_UNSUPPORTED);980return NULL;981}982}983984path_data[path_data_n].check_absolute = 1;985#ifdef _WIN32986/* Windows "file:" URIs with a drive letter start with a '/' */987if (p[0] == '/' && p[2] == ':' && p[3] == '/') {988char c = tolower((unsigned char)p[1]);989990if (c >= 'a' && c <= 'z') {991p++;992/* We know it's absolute, so no need to check */993path_data[path_data_n].check_absolute = 0;994}995}996#endif997path_data[path_data_n++].path = p;998}9991000for (i = 0, path = NULL; path == NULL && i < path_data_n; i++) {1001/*1002* If the scheme "file" was an explicit part of the URI, the path must1003* be absolute. So says RFC 80891004*/1005if (path_data[i].check_absolute && path_data[i].path[0] != '/') {1006ATTICerr(0, ATTIC_R_PATH_MUST_BE_ABSOLUTE);1007ERR_add_error_data(1, path_data[i].path);1008return NULL;1009}10101011if (stat(path_data[i].path, &st) < 0) {1012ERR_raise_data(ERR_LIB_SYS, errno,1013"calling stat(%s)",1014path_data[i].path);1015} else {1016path = path_data[i].path;1017}1018}1019if (path == NULL) {1020return NULL;1021}10221023/* Successfully found a working path */10241025ctx = OPENSSL_zalloc(sizeof(*ctx));1026if (ctx == NULL)1027return NULL;1028ctx->uri = OPENSSL_strdup(uri);1029if (ctx->uri == NULL)1030goto err;10311032if (S_ISDIR(st.st_mode)) {1033ctx->type = is_dir;1034ctx->_.dir.last_entry = OPENSSL_DIR_read(&ctx->_.dir.ctx, path);1035ctx->_.dir.last_errno = errno;1036if (ctx->_.dir.last_entry == NULL) {1037if (ctx->_.dir.last_errno != 0) {1038ERR_raise(ERR_LIB_SYS, ctx->_.dir.last_errno);1039goto err;1040}1041ctx->_.dir.end_reached = 1;1042}1043} else if ((ctx->_.file.file = BIO_new_file(path, "rb")) == NULL1044|| !file_find_type(ctx)) {1045BIO_free_all(ctx->_.file.file);1046goto err;1047}1048if (propq != NULL) {1049ctx->propq = OPENSSL_strdup(propq);1050if (ctx->propq == NULL)1051goto err;1052}1053ctx->libctx = libctx;10541055return ctx;1056err:1057OSSL_STORE_LOADER_CTX_free(ctx);1058return NULL;1059}10601061static OSSL_STORE_LOADER_CTX *file_open(const OSSL_STORE_LOADER *loader, const char *uri,1062const UI_METHOD *ui_method, void *ui_data)1063{1064return file_open_ex(loader, uri, NULL, NULL, ui_method, ui_data);1065}10661067static OSSL_STORE_LOADER_CTX *file_attach(const OSSL_STORE_LOADER *loader, BIO *bp,1068OSSL_LIB_CTX *libctx, const char *propq,1069const UI_METHOD *ui_method, void *ui_data)1070{1071OSSL_STORE_LOADER_CTX *ctx = NULL;10721073if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL1074|| (propq != NULL && (ctx->propq = OPENSSL_strdup(propq)) == NULL)) {1075OSSL_STORE_LOADER_CTX_free(ctx);1076return NULL;1077}1078ctx->libctx = libctx;1079ctx->flags |= FILE_FLAG_ATTACHED;1080ctx->_.file.file = bp;1081if (!file_find_type(ctx)) {1082/* Safety measure */1083ctx->_.file.file = NULL;1084goto err;1085}1086return ctx;1087err:1088OSSL_STORE_LOADER_CTX_free(ctx);1089return NULL;1090}10911092static int file_ctrl(OSSL_STORE_LOADER_CTX *ctx, int cmd, va_list args)1093{1094int ret = 1;10951096switch (cmd) {1097case OSSL_STORE_C_USE_SECMEM: {1098int on = *(va_arg(args, int *));10991100switch (on) {1101case 0:1102ctx->flags &= ~FILE_FLAG_SECMEM;1103break;1104case 1:1105ctx->flags |= FILE_FLAG_SECMEM;1106break;1107default:1108ATTICerr(0, ERR_R_PASSED_INVALID_ARGUMENT);1109ret = 0;1110break;1111}1112} break;1113default:1114break;1115}11161117return ret;1118}11191120static int file_expect(OSSL_STORE_LOADER_CTX *ctx, int expected)1121{1122ctx->expected_type = expected;1123return 1;1124}11251126static int file_find(OSSL_STORE_LOADER_CTX *ctx,1127const OSSL_STORE_SEARCH *search)1128{1129/*1130* If ctx == NULL, the library is looking to know if this loader supports1131* the given search type.1132*/11331134if (OSSL_STORE_SEARCH_get_type(search) == OSSL_STORE_SEARCH_BY_NAME) {1135unsigned long hash = 0;11361137if (ctx == NULL)1138return 1;11391140if (ctx->type != is_dir) {1141ATTICerr(0, ATTIC_R_SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES);1142return 0;1143}11441145hash = X509_NAME_hash_ex(OSSL_STORE_SEARCH_get0_name(search),1146NULL, NULL, NULL);1147BIO_snprintf(ctx->_.dir.search_name, sizeof(ctx->_.dir.search_name),1148"%08lx", hash);1149return 1;1150}11511152if (ctx != NULL)1153ATTICerr(0, ATTIC_R_UNSUPPORTED_SEARCH_TYPE);1154return 0;1155}11561157static OSSL_STORE_INFO *file_load_try_decode(OSSL_STORE_LOADER_CTX *ctx,1158const char *pem_name,1159const char *pem_header,1160unsigned char *data, size_t len,1161const UI_METHOD *ui_method,1162void *ui_data, int *matchcount)1163{1164OSSL_STORE_INFO *result = NULL;1165BUF_MEM *new_mem = NULL;1166char *new_pem_name = NULL;1167int t = 0;11681169again: {1170size_t i = 0;1171void *handler_ctx = NULL;1172const FILE_HANDLER **matching_handlers = OPENSSL_zalloc(sizeof(*matching_handlers)1173* OSSL_NELEM(file_handlers));11741175if (matching_handlers == NULL)1176goto err;11771178*matchcount = 0;1179for (i = 0; i < OSSL_NELEM(file_handlers); i++) {1180const FILE_HANDLER *handler = file_handlers[i];1181int try_matchcount = 0;1182void *tmp_handler_ctx = NULL;1183OSSL_STORE_INFO *tmp_result;1184unsigned long err;11851186ERR_set_mark();1187tmp_result = handler->try_decode(pem_name, pem_header, data, len,1188&tmp_handler_ctx, &try_matchcount,1189ui_method, ui_data, ctx->uri,1190ctx->libctx, ctx->propq);1191/* avoid flooding error queue with low-level ASN.1 parse errors */1192err = ERR_peek_last_error();1193if (ERR_GET_LIB(err) == ERR_LIB_ASN11194&& ERR_GET_REASON(err) == ERR_R_NESTED_ASN1_ERROR)1195ERR_pop_to_mark();1196else1197ERR_clear_last_mark();11981199if (try_matchcount > 0) {12001201matching_handlers[*matchcount] = handler;12021203if (handler_ctx)1204handler->destroy_ctx(&handler_ctx);1205handler_ctx = tmp_handler_ctx;12061207if ((*matchcount += try_matchcount) > 1) {1208/* more than one match => ambiguous, kill any result */1209store_info_free(result);1210store_info_free(tmp_result);1211if (handler->destroy_ctx != NULL)1212handler->destroy_ctx(&handler_ctx);1213handler_ctx = NULL;1214tmp_result = NULL;1215result = NULL;1216}1217if (result == NULL)1218result = tmp_result;1219if (result == NULL) /* e.g., PKCS#12 file decryption error */1220break;1221}1222}12231224if (result != NULL1225&& *matchcount == 1 && matching_handlers[0]->repeatable) {1226ctx->_.file.last_handler = matching_handlers[0];1227ctx->_.file.last_handler_ctx = handler_ctx;1228}12291230OPENSSL_free(matching_handlers);1231}12321233err:1234OPENSSL_free(new_pem_name);1235BUF_MEM_free(new_mem);12361237if (result != NULL1238&& (t = OSSL_STORE_INFO_get_type(result)) == STORE_INFO_EMBEDDED) {1239struct embedded_st *embedded = get0_EMBEDDED(result);12401241/* "steal" the embedded data */1242pem_name = new_pem_name = embedded->pem_name;1243new_mem = embedded->blob;1244data = (unsigned char *)new_mem->data;1245len = new_mem->length;1246embedded->pem_name = NULL;1247embedded->blob = NULL;12481249store_info_free(result);1250result = NULL;1251goto again;1252}12531254return result;1255}12561257static OSSL_STORE_INFO *file_load_try_repeat(OSSL_STORE_LOADER_CTX *ctx,1258const UI_METHOD *ui_method,1259void *ui_data)1260{1261OSSL_STORE_INFO *result = NULL;1262int try_matchcount = 0;12631264if (ctx->_.file.last_handler != NULL) {1265result = ctx->_.file.last_handler->try_decode(NULL, NULL, NULL, 0,1266&ctx->_.file.last_handler_ctx,1267&try_matchcount,1268ui_method, ui_data, ctx->uri,1269ctx->libctx, ctx->propq);12701271if (result == NULL) {1272ctx->_.file.last_handler->destroy_ctx(&ctx->_.file.last_handler_ctx);1273ctx->_.file.last_handler_ctx = NULL;1274ctx->_.file.last_handler = NULL;1275}1276}1277return result;1278}12791280static void pem_free_flag(void *pem_data, int secure, size_t num)1281{1282if (secure)1283OPENSSL_secure_clear_free(pem_data, num);1284else1285OPENSSL_free(pem_data);1286}1287static int file_read_pem(BIO *bp, char **pem_name, char **pem_header,1288unsigned char **data, long *len,1289const UI_METHOD *ui_method, void *ui_data,1290const char *uri, int secure)1291{1292int i = secure1293? PEM_read_bio_ex(bp, pem_name, pem_header, data, len,1294PEM_FLAG_SECURE | PEM_FLAG_EAY_COMPATIBLE)1295: PEM_read_bio(bp, pem_name, pem_header, data, len);12961297if (i <= 0)1298return 0;12991300/*1301* 10 is the number of characters in "Proc-Type:", which1302* PEM_get_EVP_CIPHER_INFO() requires to be present.1303* If the PEM header has less characters than that, it's1304* not worth spending cycles on it.1305*/1306if (strlen(*pem_header) > 10) {1307EVP_CIPHER_INFO cipher;1308struct pem_pass_data pass_data;13091310if (!PEM_get_EVP_CIPHER_INFO(*pem_header, &cipher)1311|| !file_fill_pem_pass_data(&pass_data, "PEM pass phrase", uri,1312ui_method, ui_data)1313|| !PEM_do_header(&cipher, *data, len, file_get_pem_pass,1314&pass_data)) {1315return 0;1316}1317}1318return 1;1319}13201321static OSSL_STORE_INFO *file_try_read_msblob(BIO *bp, int *matchcount)1322{1323OSSL_STORE_INFO *result = NULL;1324int ispub = -1;13251326{1327unsigned int magic = 0, bitlen = 0;1328int isdss = 0;1329unsigned char peekbuf[16] = {13300,1331};1332const unsigned char *p = peekbuf;13331334if (BIO_buffer_peek(bp, peekbuf, sizeof(peekbuf)) <= 0)1335return 0;1336if (ossl_do_blob_header(&p, sizeof(peekbuf), &magic, &bitlen,1337&isdss, &ispub)1338<= 0)1339return 0;1340}13411342(*matchcount)++;13431344{1345EVP_PKEY *tmp = ispub1346? b2i_PublicKey_bio(bp)1347: b2i_PrivateKey_bio(bp);13481349if (tmp == NULL1350|| (result = OSSL_STORE_INFO_new_PKEY(tmp)) == NULL) {1351EVP_PKEY_free(tmp);1352return 0;1353}1354}13551356return result;1357}13581359static OSSL_STORE_INFO *file_try_read_PVK(BIO *bp, const UI_METHOD *ui_method,1360void *ui_data, const char *uri,1361int *matchcount)1362{1363OSSL_STORE_INFO *result = NULL;13641365{1366unsigned int saltlen = 0, keylen = 0;1367int isdss = -1;1368unsigned char peekbuf[24] = {13690,1370};1371const unsigned char *p = peekbuf;13721373if (BIO_buffer_peek(bp, peekbuf, sizeof(peekbuf)) <= 0)1374return 0;1375if (!ossl_do_PVK_header(&p, sizeof(peekbuf), 0, &isdss, &saltlen, &keylen))1376return 0;1377}13781379(*matchcount)++;13801381{1382EVP_PKEY *tmp = NULL;1383struct pem_pass_data pass_data;13841385if (!file_fill_pem_pass_data(&pass_data, "PVK pass phrase", uri,1386ui_method, ui_data)1387|| (tmp = b2i_PVK_bio(bp, file_get_pem_pass, &pass_data)) == NULL1388|| (result = OSSL_STORE_INFO_new_PKEY(tmp)) == NULL) {1389EVP_PKEY_free(tmp);1390return 0;1391}1392}13931394return result;1395}13961397static int file_read_asn1(BIO *bp, unsigned char **data, long *len)1398{1399BUF_MEM *mem = NULL;14001401if (asn1_d2i_read_bio(bp, &mem) < 0)1402return 0;14031404*data = (unsigned char *)mem->data;1405*len = (long)mem->length;1406OPENSSL_free(mem);14071408return 1;1409}14101411static int file_name_to_uri(OSSL_STORE_LOADER_CTX *ctx, const char *name,1412char **data)1413{1414assert(name != NULL);1415assert(data != NULL);1416{1417const char *pathsep = ossl_ends_with_dirsep(ctx->uri) ? "" : "/";1418long calculated_length = strlen(ctx->uri) + strlen(pathsep)1419+ strlen(name) + 1 /* \0 */;14201421*data = OPENSSL_zalloc(calculated_length);1422if (*data == NULL)1423return 0;14241425OPENSSL_strlcat(*data, ctx->uri, calculated_length);1426OPENSSL_strlcat(*data, pathsep, calculated_length);1427OPENSSL_strlcat(*data, name, calculated_length);1428}1429return 1;1430}14311432static int file_name_check(OSSL_STORE_LOADER_CTX *ctx, const char *name)1433{1434const char *p = NULL;1435size_t len = strlen(ctx->_.dir.search_name);14361437/* If there are no search criteria, all names are accepted */1438if (ctx->_.dir.search_name[0] == '\0')1439return 1;14401441/* If the expected type isn't supported, no name is accepted */1442if (ctx->expected_type != 01443&& ctx->expected_type != OSSL_STORE_INFO_CERT1444&& ctx->expected_type != OSSL_STORE_INFO_CRL)1445return 0;14461447/*1448* First, check the basename1449*/1450if (OPENSSL_strncasecmp(name, ctx->_.dir.search_name, len) != 01451|| name[len] != '.')1452return 0;1453p = &name[len + 1];14541455/*1456* Then, if the expected type is a CRL, check that the extension starts1457* with 'r'1458*/1459if (*p == 'r') {1460p++;1461if (ctx->expected_type != 01462&& ctx->expected_type != OSSL_STORE_INFO_CRL)1463return 0;1464} else if (ctx->expected_type == OSSL_STORE_INFO_CRL) {1465return 0;1466}14671468/*1469* Last, check that the rest of the extension is a decimal number, at1470* least one digit long.1471*/1472if (!isdigit((unsigned char)*p))1473return 0;1474while (isdigit((unsigned char)*p))1475p++;14761477#ifdef __VMS1478/*1479* One extra step here, check for a possible generation number.1480*/1481if (*p == ';')1482for (p++; *p != '\0'; p++)1483if (!ossl_isdigit(*p))1484break;1485#endif14861487/*1488* If we've reached the end of the string at this point, we've successfully1489* found a fitting file name.1490*/1491return *p == '\0';1492}14931494static int file_eof(OSSL_STORE_LOADER_CTX *ctx);1495static int file_error(OSSL_STORE_LOADER_CTX *ctx);1496static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx,1497const UI_METHOD *ui_method,1498void *ui_data)1499{1500OSSL_STORE_INFO *result = NULL;15011502ctx->errcnt = 0;15031504if (ctx->type == is_dir) {1505do {1506char *newname = NULL;15071508if (ctx->_.dir.last_entry == NULL) {1509if (!ctx->_.dir.end_reached) {1510assert(ctx->_.dir.last_errno != 0);1511ERR_raise(ERR_LIB_SYS, ctx->_.dir.last_errno);1512ctx->errcnt++;1513}1514return NULL;1515}15161517if (ctx->_.dir.last_entry[0] != '.'1518&& file_name_check(ctx, ctx->_.dir.last_entry)1519&& !file_name_to_uri(ctx, ctx->_.dir.last_entry, &newname))1520return NULL;15211522/*1523* On the first call (with a NULL context), OPENSSL_DIR_read()1524* cares about the second argument. On the following calls, it1525* only cares that it isn't NULL. Therefore, we can safely give1526* it our URI here.1527*/1528ctx->_.dir.last_entry = OPENSSL_DIR_read(&ctx->_.dir.ctx, ctx->uri);1529ctx->_.dir.last_errno = errno;1530if (ctx->_.dir.last_entry == NULL && ctx->_.dir.last_errno == 0)1531ctx->_.dir.end_reached = 1;15321533if (newname != NULL1534&& (result = OSSL_STORE_INFO_new_NAME(newname)) == NULL) {1535OPENSSL_free(newname);1536ATTICerr(0, ERR_R_OSSL_STORE_LIB);1537return NULL;1538}1539} while (result == NULL && !file_eof(ctx));1540} else {1541int matchcount = -1;15421543again:1544result = file_load_try_repeat(ctx, ui_method, ui_data);1545if (result != NULL)1546return result;15471548if (file_eof(ctx))1549return NULL;15501551do {1552char *pem_name = NULL; /* PEM record name */1553char *pem_header = NULL; /* PEM record header */1554unsigned char *data = NULL; /* DER encoded data */1555long len = 0; /* DER encoded data length */15561557matchcount = -1;1558if (ctx->type == is_pem) {1559if (!file_read_pem(ctx->_.file.file, &pem_name, &pem_header,1560&data, &len, ui_method, ui_data, ctx->uri,1561(ctx->flags & FILE_FLAG_SECMEM) != 0)) {1562ctx->errcnt++;1563goto endloop;1564}1565} else {1566if ((result = file_try_read_msblob(ctx->_.file.file,1567&matchcount))1568!= NULL1569|| (result = file_try_read_PVK(ctx->_.file.file,1570ui_method, ui_data, ctx->uri,1571&matchcount))1572!= NULL)1573goto endloop;15741575if (!file_read_asn1(ctx->_.file.file, &data, &len)) {1576ctx->errcnt++;1577goto endloop;1578}1579}15801581result = file_load_try_decode(ctx, pem_name, pem_header, data, len,1582ui_method, ui_data, &matchcount);15831584if (result != NULL)1585goto endloop;15861587/*1588* If a PEM name matches more than one handler, the handlers are1589* badly coded.1590*/1591if (!ossl_assert(pem_name == NULL || matchcount <= 1)) {1592ctx->errcnt++;1593goto endloop;1594}15951596if (matchcount > 1) {1597ATTICerr(0, ATTIC_R_AMBIGUOUS_CONTENT_TYPE);1598} else if (matchcount == 1) {1599/*1600* If there are other errors on the stack, they already show1601* what the problem is.1602*/1603if (ERR_peek_error() == 0) {1604ATTICerr(0, ATTIC_R_UNSUPPORTED_CONTENT_TYPE);1605if (pem_name != NULL)1606ERR_add_error_data(3, "PEM type is '", pem_name, "'");1607}1608}1609if (matchcount > 0)1610ctx->errcnt++;16111612endloop:1613pem_free_flag(pem_name, (ctx->flags & FILE_FLAG_SECMEM) != 0, 0);1614pem_free_flag(pem_header, (ctx->flags & FILE_FLAG_SECMEM) != 0, 0);1615pem_free_flag(data, (ctx->flags & FILE_FLAG_SECMEM) != 0, len);1616} while (matchcount == 0 && !file_eof(ctx) && !file_error(ctx));16171618/* We bail out on ambiguity */1619if (matchcount > 1) {1620store_info_free(result);1621return NULL;1622}16231624if (result != NULL1625&& ctx->expected_type != 01626&& ctx->expected_type != OSSL_STORE_INFO_get_type(result)) {1627store_info_free(result);1628goto again;1629}1630}16311632return result;1633}16341635static int file_error(OSSL_STORE_LOADER_CTX *ctx)1636{1637return ctx->errcnt > 0;1638}16391640static int file_eof(OSSL_STORE_LOADER_CTX *ctx)1641{1642if (ctx->type == is_dir)1643return ctx->_.dir.end_reached;16441645if (ctx->_.file.last_handler != NULL1646&& !ctx->_.file.last_handler->eof(ctx->_.file.last_handler_ctx))1647return 0;1648return BIO_eof(ctx->_.file.file);1649}16501651static int file_close(OSSL_STORE_LOADER_CTX *ctx)1652{1653if ((ctx->flags & FILE_FLAG_ATTACHED) == 0) {1654if (ctx->type == is_dir)1655OPENSSL_DIR_end(&ctx->_.dir.ctx);1656else1657BIO_free_all(ctx->_.file.file);1658} else {1659/*1660* Because file_attach() called file_find_type(), we know that a1661* BIO_f_buffer() has been pushed on top of the regular BIO.1662*/1663BIO *buff = ctx->_.file.file;16641665/* Detach buff */1666(void)BIO_pop(ctx->_.file.file);1667/* Safety measure */1668ctx->_.file.file = NULL;16691670BIO_free(buff);1671}1672OSSL_STORE_LOADER_CTX_free(ctx);1673return 1;1674}16751676/*-1677* ENGINE management1678*/16791680static const char *loader_attic_id = "loader_attic";1681static const char *loader_attic_name = "'file:' loader";16821683static OSSL_STORE_LOADER *loader_attic = NULL;16841685static int loader_attic_init(ENGINE *e)1686{1687return 1;1688}16891690static int loader_attic_finish(ENGINE *e)1691{1692return 1;1693}16941695static int loader_attic_destroy(ENGINE *e)1696{1697OSSL_STORE_LOADER *loader = OSSL_STORE_unregister_loader("file");16981699if (loader == NULL)1700return 0;17011702ERR_unload_ATTIC_strings();1703OSSL_STORE_LOADER_free(loader);1704return 1;1705}17061707static int bind_loader_attic(ENGINE *e)1708{17091710/* Ensure the ATTIC error handling is set up on best effort basis */1711ERR_load_ATTIC_strings();17121713if (/* Create the OSSL_STORE_LOADER */1714(loader_attic = OSSL_STORE_LOADER_new(e, "file")) == NULL1715|| !OSSL_STORE_LOADER_set_open_ex(loader_attic, file_open_ex)1716|| !OSSL_STORE_LOADER_set_open(loader_attic, file_open)1717|| !OSSL_STORE_LOADER_set_attach(loader_attic, file_attach)1718|| !OSSL_STORE_LOADER_set_ctrl(loader_attic, file_ctrl)1719|| !OSSL_STORE_LOADER_set_expect(loader_attic, file_expect)1720|| !OSSL_STORE_LOADER_set_find(loader_attic, file_find)1721|| !OSSL_STORE_LOADER_set_load(loader_attic, file_load)1722|| !OSSL_STORE_LOADER_set_eof(loader_attic, file_eof)1723|| !OSSL_STORE_LOADER_set_error(loader_attic, file_error)1724|| !OSSL_STORE_LOADER_set_close(loader_attic, file_close)1725/* Init the engine itself */1726|| !ENGINE_set_id(e, loader_attic_id)1727|| !ENGINE_set_name(e, loader_attic_name)1728|| !ENGINE_set_destroy_function(e, loader_attic_destroy)1729|| !ENGINE_set_init_function(e, loader_attic_init)1730|| !ENGINE_set_finish_function(e, loader_attic_finish)1731/* Finally, register the method with libcrypto */1732|| !OSSL_STORE_register_loader(loader_attic)) {1733OSSL_STORE_LOADER_free(loader_attic);1734loader_attic = NULL;1735ATTICerr(0, ATTIC_R_INIT_FAILED);1736return 0;1737}17381739return 1;1740}17411742#ifdef OPENSSL_NO_DYNAMIC_ENGINE1743#error "Only allowed as dynamically shared object"1744#endif17451746static int bind_helper(ENGINE *e, const char *id)1747{1748if (id && (strcmp(id, loader_attic_id) != 0))1749return 0;1750if (!bind_loader_attic(e))1751return 0;1752return 1;1753}17541755IMPLEMENT_DYNAMIC_CHECK_FN()1756IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)175717581759