Path: blob/main/crypto/openssl/engines/e_loader_attic.c
34865 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#include "e_loader_attic_err.c"4142DEFINE_STACK_OF(OSSL_STORE_INFO)4344#ifndef S_ISDIR45# define S_ISDIR(a) (((a) & S_IFMT) == S_IFDIR)46#endif4748/*-49* Password prompting50* ------------------51*/5253static char *file_get_pass(const UI_METHOD *ui_method, char *pass,54size_t maxsize, const char *desc, const char *info,55void *data)56{57UI *ui = UI_new();58char *prompt = NULL;5960if (ui == NULL) {61ATTICerr(0, ERR_R_UI_LIB);62return NULL;63}6465if (ui_method != NULL)66UI_set_method(ui, ui_method);67UI_add_user_data(ui, data);6869if ((prompt = UI_construct_prompt(ui, desc, info)) == NULL) {70ATTICerr(0, ERR_R_UI_LIB);71pass = NULL;72} else if (UI_add_input_string(ui, prompt, UI_INPUT_FLAG_DEFAULT_PWD,73pass, 0, maxsize - 1) <= 0) {74ATTICerr(0, ERR_R_UI_LIB);75pass = NULL;76} else {77switch (UI_process(ui)) {78case -2:79ATTICerr(0, ATTIC_R_UI_PROCESS_INTERRUPTED_OR_CANCELLED);80pass = NULL;81break;82case -1:83ATTICerr(0, ERR_R_UI_LIB);84pass = NULL;85break;86default:87break;88}89}9091OPENSSL_free(prompt);92UI_free(ui);93return pass;94}9596struct pem_pass_data {97const UI_METHOD *ui_method;98void *data;99const char *prompt_desc;100const char *prompt_info;101};102103static int file_fill_pem_pass_data(struct pem_pass_data *pass_data,104const char *desc, const char *info,105const UI_METHOD *ui_method, void *ui_data)106{107if (pass_data == NULL)108return 0;109pass_data->ui_method = ui_method;110pass_data->data = ui_data;111pass_data->prompt_desc = desc;112pass_data->prompt_info = info;113return 1;114}115116/* This is used anywhere a pem_password_cb is needed */117static int file_get_pem_pass(char *buf, int num, int w, void *data)118{119struct pem_pass_data *pass_data = data;120char *pass = file_get_pass(pass_data->ui_method, buf, num,121pass_data->prompt_desc, pass_data->prompt_info,122pass_data->data);123124return pass == NULL ? 0 : strlen(pass);125}126127/*128* Check if |str| ends with |suffix| preceded by a space, and if it does,129* return the index of that space. If there is no such suffix in |str|,130* return -1.131* For |str| == "FOO BAR" and |suffix| == "BAR", the returned value is 3.132*/133static int check_suffix(const char *str, const char *suffix)134{135int str_len = strlen(str);136int suffix_len = strlen(suffix) + 1;137const char *p = NULL;138139if (suffix_len >= str_len)140return -1;141p = str + str_len - suffix_len;142if (*p != ' '143|| strcmp(p + 1, suffix) != 0)144return -1;145return p - str;146}147148/*149* EMBEDDED is a special type of OSSL_STORE_INFO, specially for the file150* handlers, so we define it internally. This uses the possibility to151* create an OSSL_STORE_INFO with a generic data pointer and arbitrary152* type number.153*154* This is used by a FILE_HANDLER's try_decode function to signal that it155* has decoded the incoming blob into a new blob, and that the attempted156* decoding should be immediately restarted with the new blob, using the157* new PEM name.158*/159/* Negative numbers are never used for public OSSL_STORE_INFO types */160#define STORE_INFO_EMBEDDED -1161162/* This is the embedded data */163struct embedded_st {164BUF_MEM *blob;165char *pem_name;166};167168/* Helper functions */169static struct embedded_st *get0_EMBEDDED(OSSL_STORE_INFO *info)170{171return OSSL_STORE_INFO_get0_data(STORE_INFO_EMBEDDED, info);172}173174static void store_info_free(OSSL_STORE_INFO *info)175{176struct embedded_st *data;177178if (info != NULL && (data = get0_EMBEDDED(info)) != NULL) {179BUF_MEM_free(data->blob);180OPENSSL_free(data->pem_name);181OPENSSL_free(data);182}183OSSL_STORE_INFO_free(info);184}185186static OSSL_STORE_INFO *new_EMBEDDED(const char *new_pem_name,187BUF_MEM *embedded)188{189OSSL_STORE_INFO *info = NULL;190struct embedded_st *data = NULL;191192if ((data = OPENSSL_zalloc(sizeof(*data))) == NULL)193return NULL;194if ((info = OSSL_STORE_INFO_new(STORE_INFO_EMBEDDED, data)) == NULL) {195ATTICerr(0, ERR_R_OSSL_STORE_LIB);196OPENSSL_free(data);197return NULL;198}199200data->blob = embedded;201data->pem_name =202new_pem_name == NULL ? NULL : OPENSSL_strdup(new_pem_name);203204if (new_pem_name != NULL && data->pem_name == NULL) {205store_info_free(info);206info = NULL;207}208209return info;210}211212/*-213* The file scheme decoders214* ------------------------215*216* Each possible data type has its own decoder, which either operates217* through a given PEM name, or attempts to decode to see if the blob218* it's given is decodable for its data type. The assumption is that219* only the correct data type will match the content.220*/221222/*-223* The try_decode function is called to check if the blob of data can224* be used by this handler, and if it can, decodes it into a supported225* OpenSSL type and returns an OSSL_STORE_INFO with the decoded data.226* Input:227* pem_name: If this blob comes from a PEM file, this holds228* the PEM name. If it comes from another type of229* file, this is NULL.230* pem_header: If this blob comes from a PEM file, this holds231* the PEM headers. If it comes from another type of232* file, this is NULL.233* blob: The blob of data to match with what this handler234* can use.235* len: The length of the blob.236* handler_ctx: For a handler marked repeatable, this pointer can237* be used to create a context for the handler. IT IS238* THE HANDLER'S RESPONSIBILITY TO CREATE AND DESTROY239* THIS CONTEXT APPROPRIATELY, i.e. create on first call240* and destroy when about to return NULL.241* matchcount: A pointer to an int to count matches for this data.242* Usually becomes 0 (no match) or 1 (match!), but may243* be higher in the (unlikely) event that the data matches244* more than one possibility. The int will always be245* zero when the function is called.246* ui_method: Application UI method for getting a password, pin247* or any other interactive data.248* ui_data: Application data to be passed to ui_method when249* it's called.250* libctx: The library context to be used if applicable251* propq: The property query string for any algorithm fetches252* Output:253* an OSSL_STORE_INFO254*/255typedef OSSL_STORE_INFO *(*file_try_decode_fn)(const char *pem_name,256const char *pem_header,257const unsigned char *blob,258size_t len, void **handler_ctx,259int *matchcount,260const UI_METHOD *ui_method,261void *ui_data, const char *uri,262OSSL_LIB_CTX *libctx,263const char *propq);264/*265* The eof function should return 1 if there's no more data to be found266* with the handler_ctx, otherwise 0. This is only used when the handler is267* marked repeatable.268*/269typedef int (*file_eof_fn)(void *handler_ctx);270/*271* The destroy_ctx function is used to destroy the handler_ctx that was272* initiated by a repeatable try_decode function. This is only used when273* the handler is marked repeatable.274*/275typedef void (*file_destroy_ctx_fn)(void **handler_ctx);276277typedef struct file_handler_st {278const char *name;279file_try_decode_fn try_decode;280file_eof_fn eof;281file_destroy_ctx_fn destroy_ctx;282283/* flags */284int repeatable;285} FILE_HANDLER;286287/*288* PKCS#12 decoder. It operates by decoding all of the blob content,289* extracting all the interesting data from it and storing them internally,290* then serving them one piece at a time.291*/292static OSSL_STORE_INFO *try_decode_PKCS12(const char *pem_name,293const char *pem_header,294const unsigned char *blob,295size_t len, void **pctx,296int *matchcount,297const UI_METHOD *ui_method,298void *ui_data, const char *uri,299OSSL_LIB_CTX *libctx,300const char *propq)301{302OSSL_STORE_INFO *store_info = NULL;303STACK_OF(OSSL_STORE_INFO) *ctx = *pctx;304305if (ctx == NULL) {306/* Initial parsing */307PKCS12 *p12;308309if (pem_name != NULL)310/* No match, there is no PEM PKCS12 tag */311return NULL;312313if ((p12 = d2i_PKCS12(NULL, &blob, len)) != NULL) {314char *pass = NULL;315char tpass[PEM_BUFSIZE];316EVP_PKEY *pkey = NULL;317X509 *cert = NULL;318STACK_OF(X509) *chain = NULL;319320*matchcount = 1;321322if (!PKCS12_mac_present(p12)323|| PKCS12_verify_mac(p12, "", 0)324|| PKCS12_verify_mac(p12, NULL, 0)) {325pass = "";326} else {327if ((pass = file_get_pass(ui_method, tpass, PEM_BUFSIZE,328"PKCS12 import", uri,329ui_data)) == NULL) {330ATTICerr(0, ATTIC_R_PASSPHRASE_CALLBACK_ERROR);331goto p12_end;332}333if (!PKCS12_verify_mac(p12, pass, strlen(pass))) {334ATTICerr(0, ATTIC_R_ERROR_VERIFYING_PKCS12_MAC);335goto p12_end;336}337}338339if (PKCS12_parse(p12, pass, &pkey, &cert, &chain)) {340OSSL_STORE_INFO *osi_pkey = NULL;341OSSL_STORE_INFO *osi_cert = NULL;342OSSL_STORE_INFO *osi_ca = NULL;343int ok = 1;344345if ((ctx = sk_OSSL_STORE_INFO_new_null()) != NULL) {346if (pkey != NULL) {347if ((osi_pkey = OSSL_STORE_INFO_new_PKEY(pkey)) != NULL348/* clearing pkey here avoids case distinctions */349&& (pkey = NULL) == NULL350&& sk_OSSL_STORE_INFO_push(ctx, osi_pkey) != 0)351osi_pkey = NULL;352else353ok = 0;354}355if (ok && cert != NULL) {356if ((osi_cert = OSSL_STORE_INFO_new_CERT(cert)) != NULL357/* clearing cert here avoids case distinctions */358&& (cert = NULL) == NULL359&& sk_OSSL_STORE_INFO_push(ctx, osi_cert) != 0)360osi_cert = NULL;361else362ok = 0;363}364while (ok && sk_X509_num(chain) > 0) {365X509 *ca = sk_X509_value(chain, 0);366367if ((osi_ca = OSSL_STORE_INFO_new_CERT(ca)) != NULL368&& sk_X509_shift(chain) != NULL369&& sk_OSSL_STORE_INFO_push(ctx, osi_ca) != 0)370osi_ca = NULL;371else372ok = 0;373}374}375EVP_PKEY_free(pkey);376X509_free(cert);377OSSL_STACK_OF_X509_free(chain);378store_info_free(osi_pkey);379store_info_free(osi_cert);380store_info_free(osi_ca);381if (!ok) {382sk_OSSL_STORE_INFO_pop_free(ctx, store_info_free);383ctx = NULL;384}385*pctx = ctx;386}387}388p12_end:389PKCS12_free(p12);390if (ctx == NULL)391return NULL;392}393394*matchcount = 1;395store_info = sk_OSSL_STORE_INFO_shift(ctx);396return store_info;397}398399static int eof_PKCS12(void *ctx_)400{401STACK_OF(OSSL_STORE_INFO) *ctx = ctx_;402403return ctx == NULL || sk_OSSL_STORE_INFO_num(ctx) == 0;404}405406static void destroy_ctx_PKCS12(void **pctx)407{408STACK_OF(OSSL_STORE_INFO) *ctx = *pctx;409410sk_OSSL_STORE_INFO_pop_free(ctx, store_info_free);411*pctx = NULL;412}413414static FILE_HANDLER PKCS12_handler = {415"PKCS12",416try_decode_PKCS12,417eof_PKCS12,418destroy_ctx_PKCS12,4191 /* repeatable */420};421422/*423* Encrypted PKCS#8 decoder. It operates by just decrypting the given blob424* into a new blob, which is returned as an EMBEDDED STORE_INFO. The whole425* decoding process will then start over with the new blob.426*/427static OSSL_STORE_INFO *try_decode_PKCS8Encrypted(const char *pem_name,428const char *pem_header,429const unsigned char *blob,430size_t len, void **pctx,431int *matchcount,432const UI_METHOD *ui_method,433void *ui_data,434const char *uri,435OSSL_LIB_CTX *libctx,436const char *propq)437{438X509_SIG *p8 = NULL;439char kbuf[PEM_BUFSIZE];440char *pass = NULL;441const X509_ALGOR *dalg = NULL;442const ASN1_OCTET_STRING *doct = NULL;443OSSL_STORE_INFO *store_info = NULL;444BUF_MEM *mem = NULL;445unsigned char *new_data = NULL;446int new_data_len;447448if (pem_name != NULL) {449if (strcmp(pem_name, PEM_STRING_PKCS8) != 0)450return NULL;451*matchcount = 1;452}453454if ((p8 = d2i_X509_SIG(NULL, &blob, len)) == NULL)455return NULL;456457*matchcount = 1;458459if ((mem = BUF_MEM_new()) == NULL) {460ATTICerr(0, ERR_R_BUF_LIB);461goto nop8;462}463464if ((pass = file_get_pass(ui_method, kbuf, PEM_BUFSIZE,465"PKCS8 decrypt pass phrase", uri,466ui_data)) == NULL) {467ATTICerr(0, ATTIC_R_BAD_PASSWORD_READ);468goto nop8;469}470471X509_SIG_get0(p8, &dalg, &doct);472if (!PKCS12_pbe_crypt(dalg, pass, strlen(pass), doct->data, doct->length,473&new_data, &new_data_len, 0))474goto nop8;475476mem->data = (char *)new_data;477mem->max = mem->length = (size_t)new_data_len;478X509_SIG_free(p8);479p8 = NULL;480481store_info = new_EMBEDDED(PEM_STRING_PKCS8INF, mem);482if (store_info == NULL) {483ATTICerr(0, ERR_R_OSSL_STORE_LIB);484goto nop8;485}486487return store_info;488nop8:489X509_SIG_free(p8);490BUF_MEM_free(mem);491return NULL;492}493494static FILE_HANDLER PKCS8Encrypted_handler = {495"PKCS8Encrypted",496try_decode_PKCS8Encrypted497};498499/*500* Private key decoder. Decodes all sorts of private keys, both PKCS#8501* encoded ones and old style PEM ones (with the key type is encoded into502* the PEM name).503*/504static OSSL_STORE_INFO *try_decode_PrivateKey(const char *pem_name,505const char *pem_header,506const unsigned char *blob,507size_t len, void **pctx,508int *matchcount,509const UI_METHOD *ui_method,510void *ui_data, const char *uri,511OSSL_LIB_CTX *libctx,512const char *propq)513{514OSSL_STORE_INFO *store_info = NULL;515EVP_PKEY *pkey = NULL;516const EVP_PKEY_ASN1_METHOD *ameth = NULL;517518if (pem_name != NULL) {519if (strcmp(pem_name, PEM_STRING_PKCS8INF) == 0) {520PKCS8_PRIV_KEY_INFO *p8inf =521d2i_PKCS8_PRIV_KEY_INFO(NULL, &blob, len);522523*matchcount = 1;524if (p8inf != NULL)525pkey = EVP_PKCS82PKEY_ex(p8inf, libctx, propq);526PKCS8_PRIV_KEY_INFO_free(p8inf);527} else {528int slen;529int pkey_id;530531if ((slen = check_suffix(pem_name, "PRIVATE KEY")) > 0532&& (ameth = EVP_PKEY_asn1_find_str(NULL, pem_name,533slen)) != NULL534&& EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL,535ameth)) {536*matchcount = 1;537pkey = d2i_PrivateKey_ex(pkey_id, NULL, &blob, len,538libctx, propq);539}540}541} else {542int i;543#ifndef OPENSSL_NO_ENGINE544ENGINE *curengine = ENGINE_get_first();545546while (curengine != NULL) {547ENGINE_PKEY_ASN1_METHS_PTR asn1meths =548ENGINE_get_pkey_asn1_meths(curengine);549550if (asn1meths != NULL) {551const int *nids = NULL;552int nids_n = asn1meths(curengine, NULL, &nids, 0);553554for (i = 0; i < nids_n; i++) {555EVP_PKEY_ASN1_METHOD *ameth2 = NULL;556EVP_PKEY *tmp_pkey = NULL;557const unsigned char *tmp_blob = blob;558int pkey_id, pkey_flags;559560if (!asn1meths(curengine, &ameth2, NULL, nids[i])561|| !EVP_PKEY_asn1_get0_info(&pkey_id, NULL,562&pkey_flags, NULL, NULL,563ameth2)564|| (pkey_flags & ASN1_PKEY_ALIAS) != 0)565continue;566567ERR_set_mark(); /* prevent flooding error queue */568tmp_pkey = d2i_PrivateKey_ex(pkey_id, NULL,569&tmp_blob, len,570libctx, propq);571if (tmp_pkey != NULL) {572if (pkey != NULL)573EVP_PKEY_free(tmp_pkey);574else575pkey = tmp_pkey;576(*matchcount)++;577}578ERR_pop_to_mark();579}580}581curengine = ENGINE_get_next(curengine);582}583#endif584585for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) {586EVP_PKEY *tmp_pkey = NULL;587const unsigned char *tmp_blob = blob;588int pkey_id, pkey_flags;589590ameth = EVP_PKEY_asn1_get0(i);591if (!EVP_PKEY_asn1_get0_info(&pkey_id, NULL, &pkey_flags, NULL,592NULL, ameth)593|| (pkey_flags & ASN1_PKEY_ALIAS) != 0)594continue;595596ERR_set_mark(); /* prevent flooding error queue */597tmp_pkey = d2i_PrivateKey_ex(pkey_id, NULL, &tmp_blob, len,598libctx, propq);599if (tmp_pkey != NULL) {600if (pkey != NULL)601EVP_PKEY_free(tmp_pkey);602else603pkey = tmp_pkey;604(*matchcount)++;605}606ERR_pop_to_mark();607}608609if (*matchcount > 1) {610EVP_PKEY_free(pkey);611pkey = NULL;612}613}614if (pkey == NULL)615/* No match */616return NULL;617618store_info = OSSL_STORE_INFO_new_PKEY(pkey);619if (store_info == NULL)620EVP_PKEY_free(pkey);621622return store_info;623}624625static FILE_HANDLER PrivateKey_handler = {626"PrivateKey",627try_decode_PrivateKey628};629630/*631* Public key decoder. Only supports SubjectPublicKeyInfo formatted keys.632*/633static OSSL_STORE_INFO *try_decode_PUBKEY(const char *pem_name,634const char *pem_header,635const unsigned char *blob,636size_t len, void **pctx,637int *matchcount,638const UI_METHOD *ui_method,639void *ui_data, const char *uri,640OSSL_LIB_CTX *libctx,641const char *propq)642{643OSSL_STORE_INFO *store_info = NULL;644EVP_PKEY *pkey = NULL;645646if (pem_name != NULL) {647if (strcmp(pem_name, PEM_STRING_PUBLIC) != 0)648/* No match */649return NULL;650*matchcount = 1;651}652653if ((pkey = d2i_PUBKEY(NULL, &blob, len)) != NULL) {654*matchcount = 1;655store_info = OSSL_STORE_INFO_new_PUBKEY(pkey);656}657658return store_info;659}660661static FILE_HANDLER PUBKEY_handler = {662"PUBKEY",663try_decode_PUBKEY664};665666/*667* Key parameter decoder.668*/669static OSSL_STORE_INFO *try_decode_params(const char *pem_name,670const char *pem_header,671const unsigned char *blob,672size_t len, void **pctx,673int *matchcount,674const UI_METHOD *ui_method,675void *ui_data, const char *uri,676OSSL_LIB_CTX *libctx,677const char *propq)678{679OSSL_STORE_INFO *store_info = NULL;680EVP_PKEY *pkey = NULL;681const EVP_PKEY_ASN1_METHOD *ameth = NULL;682683if (pem_name != NULL) {684int slen;685int pkey_id;686687if ((slen = check_suffix(pem_name, "PARAMETERS")) > 0688&& (ameth = EVP_PKEY_asn1_find_str(NULL, pem_name, slen)) != NULL689&& EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL,690ameth)) {691*matchcount = 1;692pkey = d2i_KeyParams(pkey_id, NULL, &blob, len);693}694} else {695int i;696697for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) {698EVP_PKEY *tmp_pkey = NULL;699const unsigned char *tmp_blob = blob;700int pkey_id, pkey_flags;701702ameth = EVP_PKEY_asn1_get0(i);703if (!EVP_PKEY_asn1_get0_info(&pkey_id, NULL, &pkey_flags, NULL,704NULL, ameth)705|| (pkey_flags & ASN1_PKEY_ALIAS) != 0)706continue;707708ERR_set_mark(); /* prevent flooding error queue */709710tmp_pkey = d2i_KeyParams(pkey_id, NULL, &tmp_blob, len);711712if (tmp_pkey != NULL) {713if (pkey != NULL)714EVP_PKEY_free(tmp_pkey);715else716pkey = tmp_pkey;717(*matchcount)++;718}719ERR_pop_to_mark();720}721722if (*matchcount > 1) {723EVP_PKEY_free(pkey);724pkey = NULL;725}726}727if (pkey == NULL)728/* No match */729return NULL;730731store_info = OSSL_STORE_INFO_new_PARAMS(pkey);732if (store_info == NULL)733EVP_PKEY_free(pkey);734735return store_info;736}737738static FILE_HANDLER params_handler = {739"params",740try_decode_params741};742743/*744* X.509 certificate decoder.745*/746static OSSL_STORE_INFO *try_decode_X509Certificate(const char *pem_name,747const char *pem_header,748const unsigned char *blob,749size_t len, void **pctx,750int *matchcount,751const UI_METHOD *ui_method,752void *ui_data,753const char *uri,754OSSL_LIB_CTX *libctx,755const char *propq)756{757OSSL_STORE_INFO *store_info = NULL;758X509 *cert = NULL;759760/*761* In most cases, we can try to interpret the serialized data as a trusted762* cert (X509 + X509_AUX) and fall back to reading it as a normal cert763* (just X509), but if the PEM name specifically declares it as a trusted764* cert, then no fallback should be engaged. |ignore_trusted| tells if765* the fallback can be used (1) or not (0).766*/767int ignore_trusted = 1;768769if (pem_name != NULL) {770if (strcmp(pem_name, PEM_STRING_X509_TRUSTED) == 0)771ignore_trusted = 0;772else if (strcmp(pem_name, PEM_STRING_X509_OLD) != 0773&& strcmp(pem_name, PEM_STRING_X509) != 0)774/* No match */775return NULL;776*matchcount = 1;777}778779cert = X509_new_ex(libctx, propq);780if (cert == NULL)781return NULL;782783if ((d2i_X509_AUX(&cert, &blob, len)) != NULL784|| (ignore_trusted && (d2i_X509(&cert, &blob, len)) != NULL)) {785*matchcount = 1;786store_info = OSSL_STORE_INFO_new_CERT(cert);787}788789if (store_info == NULL)790X509_free(cert);791792return store_info;793}794795static FILE_HANDLER X509Certificate_handler = {796"X509Certificate",797try_decode_X509Certificate798};799800/*801* X.509 CRL decoder.802*/803static OSSL_STORE_INFO *try_decode_X509CRL(const char *pem_name,804const char *pem_header,805const unsigned char *blob,806size_t len, void **pctx,807int *matchcount,808const UI_METHOD *ui_method,809void *ui_data, const char *uri,810OSSL_LIB_CTX *libctx,811const char *propq)812{813OSSL_STORE_INFO *store_info = NULL;814X509_CRL *crl = NULL;815816if (pem_name != NULL) {817if (strcmp(pem_name, PEM_STRING_X509_CRL) != 0)818/* No match */819return NULL;820*matchcount = 1;821}822823if ((crl = d2i_X509_CRL(NULL, &blob, len)) != NULL) {824*matchcount = 1;825store_info = OSSL_STORE_INFO_new_CRL(crl);826}827828if (store_info == NULL)829X509_CRL_free(crl);830831return store_info;832}833834static FILE_HANDLER X509CRL_handler = {835"X509CRL",836try_decode_X509CRL837};838839/*840* To finish it all off, we collect all the handlers.841*/842static const FILE_HANDLER *file_handlers[] = {843&PKCS12_handler,844&PKCS8Encrypted_handler,845&X509Certificate_handler,846&X509CRL_handler,847¶ms_handler,848&PUBKEY_handler,849&PrivateKey_handler,850};851852853/*-854* The loader itself855* -----------------856*/857858struct ossl_store_loader_ctx_st {859char *uri; /* The URI we currently try to load */860enum {861is_raw = 0,862is_pem,863is_dir864} type;865int errcnt;866#define FILE_FLAG_SECMEM (1<<0)867#define FILE_FLAG_ATTACHED (1<<1)868unsigned int flags;869union {870struct { /* Used with is_raw and is_pem */871BIO *file;872873/*874* The following are used when the handler is marked as875* repeatable876*/877const FILE_HANDLER *last_handler;878void *last_handler_ctx;879} file;880struct { /* Used with is_dir */881OPENSSL_DIR_CTX *ctx;882int end_reached;883884/*885* When a search expression is given, these are filled in.886* |search_name| contains the file basename to look for.887* The string is exactly 8 characters long.888*/889char search_name[9];890891/*892* The directory reading utility we have combines opening with893* reading the first name. To make sure we can detect the end894* at the right time, we read early and cache the name.895*/896const char *last_entry;897int last_errno;898} dir;899} _;900901/* Expected object type. May be unspecified */902int expected_type;903904OSSL_LIB_CTX *libctx;905char *propq;906};907908static void OSSL_STORE_LOADER_CTX_free(OSSL_STORE_LOADER_CTX *ctx)909{910if (ctx == NULL)911return;912913OPENSSL_free(ctx->propq);914OPENSSL_free(ctx->uri);915if (ctx->type != is_dir) {916if (ctx->_.file.last_handler != NULL) {917ctx->_.file.last_handler->destroy_ctx(&ctx->_.file.last_handler_ctx);918ctx->_.file.last_handler_ctx = NULL;919ctx->_.file.last_handler = NULL;920}921}922OPENSSL_free(ctx);923}924925static int file_find_type(OSSL_STORE_LOADER_CTX *ctx)926{927BIO *buff = NULL;928char peekbuf[4096] = { 0, };929930if ((buff = BIO_new(BIO_f_buffer())) == NULL)931return 0;932933ctx->_.file.file = BIO_push(buff, ctx->_.file.file);934if (BIO_buffer_peek(ctx->_.file.file, peekbuf, sizeof(peekbuf) - 1) > 0) {935peekbuf[sizeof(peekbuf) - 1] = '\0';936if (strstr(peekbuf, "-----BEGIN ") != NULL)937ctx->type = is_pem;938}939return 1;940}941942static OSSL_STORE_LOADER_CTX *file_open_ex943(const OSSL_STORE_LOADER *loader, const char *uri,944OSSL_LIB_CTX *libctx, const char *propq,945const UI_METHOD *ui_method, void *ui_data)946{947OSSL_STORE_LOADER_CTX *ctx = NULL;948struct stat st;949struct {950const char *path;951unsigned int check_absolute:1;952} path_data[2];953size_t path_data_n = 0, i;954const char *path, *p = uri, *q;955956/*957* First step, just take the URI as is.958*/959path_data[path_data_n].check_absolute = 0;960path_data[path_data_n++].path = uri;961962/*963* Second step, if the URI appears to start with the "file" scheme,964* extract the path and make that the second path to check.965* There's a special case if the URI also contains an authority, then966* the full URI shouldn't be used as a path anywhere.967*/968if (CHECK_AND_SKIP_CASE_PREFIX(p, "file:")) {969q = p;970if (CHECK_AND_SKIP_PREFIX(q, "//")) {971path_data_n--; /* Invalidate using the full URI */972if (CHECK_AND_SKIP_CASE_PREFIX(q, "localhost/")973|| CHECK_AND_SKIP_PREFIX(q, "/")) {974p = q - 1;975} else {976ATTICerr(0, ATTIC_R_URI_AUTHORITY_UNSUPPORTED);977return NULL;978}979}980981path_data[path_data_n].check_absolute = 1;982#ifdef _WIN32983/* Windows "file:" URIs with a drive letter start with a '/' */984if (p[0] == '/' && p[2] == ':' && p[3] == '/') {985char c = tolower((unsigned char)p[1]);986987if (c >= 'a' && c <= 'z') {988p++;989/* We know it's absolute, so no need to check */990path_data[path_data_n].check_absolute = 0;991}992}993#endif994path_data[path_data_n++].path = p;995}996997998for (i = 0, path = NULL; path == NULL && i < path_data_n; i++) {999/*1000* If the scheme "file" was an explicit part of the URI, the path must1001* be absolute. So says RFC 80891002*/1003if (path_data[i].check_absolute && path_data[i].path[0] != '/') {1004ATTICerr(0, ATTIC_R_PATH_MUST_BE_ABSOLUTE);1005ERR_add_error_data(1, path_data[i].path);1006return NULL;1007}10081009if (stat(path_data[i].path, &st) < 0) {1010ERR_raise_data(ERR_LIB_SYS, errno,1011"calling stat(%s)",1012path_data[i].path);1013} else {1014path = path_data[i].path;1015}1016}1017if (path == NULL) {1018return NULL;1019}10201021/* Successfully found a working path */10221023ctx = OPENSSL_zalloc(sizeof(*ctx));1024if (ctx == NULL)1025return NULL;1026ctx->uri = OPENSSL_strdup(uri);1027if (ctx->uri == NULL)1028goto err;10291030if (S_ISDIR(st.st_mode)) {1031ctx->type = is_dir;1032ctx->_.dir.last_entry = OPENSSL_DIR_read(&ctx->_.dir.ctx, path);1033ctx->_.dir.last_errno = errno;1034if (ctx->_.dir.last_entry == NULL) {1035if (ctx->_.dir.last_errno != 0) {1036ERR_raise(ERR_LIB_SYS, ctx->_.dir.last_errno);1037goto err;1038}1039ctx->_.dir.end_reached = 1;1040}1041} else if ((ctx->_.file.file = BIO_new_file(path, "rb")) == NULL1042|| !file_find_type(ctx)) {1043BIO_free_all(ctx->_.file.file);1044goto err;1045}1046if (propq != NULL) {1047ctx->propq = OPENSSL_strdup(propq);1048if (ctx->propq == NULL)1049goto err;1050}1051ctx->libctx = libctx;10521053return ctx;1054err:1055OSSL_STORE_LOADER_CTX_free(ctx);1056return NULL;1057}10581059static OSSL_STORE_LOADER_CTX *file_open1060(const OSSL_STORE_LOADER *loader, const char *uri,1061const UI_METHOD *ui_method, void *ui_data)1062{1063return file_open_ex(loader, uri, NULL, NULL, ui_method, ui_data);1064}10651066static OSSL_STORE_LOADER_CTX *file_attach1067(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:1098{1099int on = *(va_arg(args, int *));11001101switch (on) {1102case 0:1103ctx->flags &= ~FILE_FLAG_SECMEM;1104break;1105case 1:1106ctx->flags |= FILE_FLAG_SECMEM;1107break;1108default:1109ATTICerr(0, ERR_R_PASSED_INVALID_ARGUMENT);1110ret = 0;1111break;1112}1113}1114break;1115default:1116break;1117}11181119return ret;1120}11211122static int file_expect(OSSL_STORE_LOADER_CTX *ctx, int expected)1123{1124ctx->expected_type = expected;1125return 1;1126}11271128static int file_find(OSSL_STORE_LOADER_CTX *ctx,1129const OSSL_STORE_SEARCH *search)1130{1131/*1132* If ctx == NULL, the library is looking to know if this loader supports1133* the given search type.1134*/11351136if (OSSL_STORE_SEARCH_get_type(search) == OSSL_STORE_SEARCH_BY_NAME) {1137unsigned long hash = 0;11381139if (ctx == NULL)1140return 1;11411142if (ctx->type != is_dir) {1143ATTICerr(0, ATTIC_R_SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES);1144return 0;1145}11461147hash = X509_NAME_hash_ex(OSSL_STORE_SEARCH_get0_name(search),1148NULL, NULL, NULL);1149BIO_snprintf(ctx->_.dir.search_name, sizeof(ctx->_.dir.search_name),1150"%08lx", hash);1151return 1;1152}11531154if (ctx != NULL)1155ATTICerr(0, ATTIC_R_UNSUPPORTED_SEARCH_TYPE);1156return 0;1157}11581159static OSSL_STORE_INFO *file_load_try_decode(OSSL_STORE_LOADER_CTX *ctx,1160const char *pem_name,1161const char *pem_header,1162unsigned char *data, size_t len,1163const UI_METHOD *ui_method,1164void *ui_data, int *matchcount)1165{1166OSSL_STORE_INFO *result = NULL;1167BUF_MEM *new_mem = NULL;1168char *new_pem_name = NULL;1169int t = 0;11701171again:1172{1173size_t i = 0;1174void *handler_ctx = NULL;1175const FILE_HANDLER **matching_handlers =1176OPENSSL_zalloc(sizeof(*matching_handlers)1177* OSSL_NELEM(file_handlers));11781179if (matching_handlers == NULL)1180goto err;11811182*matchcount = 0;1183for (i = 0; i < OSSL_NELEM(file_handlers); i++) {1184const FILE_HANDLER *handler = file_handlers[i];1185int try_matchcount = 0;1186void *tmp_handler_ctx = NULL;1187OSSL_STORE_INFO *tmp_result;1188unsigned long err;11891190ERR_set_mark();1191tmp_result =1192handler->try_decode(pem_name, pem_header, data, len,1193&tmp_handler_ctx, &try_matchcount,1194ui_method, ui_data, ctx->uri,1195ctx->libctx, ctx->propq);1196/* avoid flooding error queue with low-level ASN.1 parse errors */1197err = ERR_peek_last_error();1198if (ERR_GET_LIB(err) == ERR_LIB_ASN11199&& ERR_GET_REASON(err) == ERR_R_NESTED_ASN1_ERROR)1200ERR_pop_to_mark();1201else1202ERR_clear_last_mark();12031204if (try_matchcount > 0) {12051206matching_handlers[*matchcount] = handler;12071208if (handler_ctx)1209handler->destroy_ctx(&handler_ctx);1210handler_ctx = tmp_handler_ctx;12111212if ((*matchcount += try_matchcount) > 1) {1213/* more than one match => ambiguous, kill any result */1214store_info_free(result);1215store_info_free(tmp_result);1216if (handler->destroy_ctx != NULL)1217handler->destroy_ctx(&handler_ctx);1218handler_ctx = NULL;1219tmp_result = NULL;1220result = NULL;1221}1222if (result == NULL)1223result = tmp_result;1224if (result == NULL) /* e.g., PKCS#12 file decryption error */1225break;1226}1227}12281229if (result != NULL1230&& *matchcount == 1 && matching_handlers[0]->repeatable) {1231ctx->_.file.last_handler = matching_handlers[0];1232ctx->_.file.last_handler_ctx = handler_ctx;1233}12341235OPENSSL_free(matching_handlers);1236}12371238err:1239OPENSSL_free(new_pem_name);1240BUF_MEM_free(new_mem);12411242if (result != NULL1243&& (t = OSSL_STORE_INFO_get_type(result)) == STORE_INFO_EMBEDDED) {1244struct embedded_st *embedded = get0_EMBEDDED(result);12451246/* "steal" the embedded data */1247pem_name = new_pem_name = embedded->pem_name;1248new_mem = embedded->blob;1249data = (unsigned char *)new_mem->data;1250len = new_mem->length;1251embedded->pem_name = NULL;1252embedded->blob = NULL;12531254store_info_free(result);1255result = NULL;1256goto again;1257}12581259return result;1260}12611262static OSSL_STORE_INFO *file_load_try_repeat(OSSL_STORE_LOADER_CTX *ctx,1263const UI_METHOD *ui_method,1264void *ui_data)1265{1266OSSL_STORE_INFO *result = NULL;1267int try_matchcount = 0;12681269if (ctx->_.file.last_handler != NULL) {1270result =1271ctx->_.file.last_handler->try_decode(NULL, NULL, NULL, 0,1272&ctx->_.file.last_handler_ctx,1273&try_matchcount,1274ui_method, ui_data, ctx->uri,1275ctx->libctx, ctx->propq);12761277if (result == NULL) {1278ctx->_.file.last_handler->destroy_ctx(&ctx->_.file.last_handler_ctx);1279ctx->_.file.last_handler_ctx = NULL;1280ctx->_.file.last_handler = NULL;1281}1282}1283return result;1284}12851286static void pem_free_flag(void *pem_data, int secure, size_t num)1287{1288if (secure)1289OPENSSL_secure_clear_free(pem_data, num);1290else1291OPENSSL_free(pem_data);1292}1293static int file_read_pem(BIO *bp, char **pem_name, char **pem_header,1294unsigned char **data, long *len,1295const UI_METHOD *ui_method, void *ui_data,1296const char *uri, int secure)1297{1298int i = secure1299? PEM_read_bio_ex(bp, pem_name, pem_header, data, len,1300PEM_FLAG_SECURE | PEM_FLAG_EAY_COMPATIBLE)1301: PEM_read_bio(bp, pem_name, pem_header, data, len);13021303if (i <= 0)1304return 0;13051306/*1307* 10 is the number of characters in "Proc-Type:", which1308* PEM_get_EVP_CIPHER_INFO() requires to be present.1309* If the PEM header has less characters than that, it's1310* not worth spending cycles on it.1311*/1312if (strlen(*pem_header) > 10) {1313EVP_CIPHER_INFO cipher;1314struct pem_pass_data pass_data;13151316if (!PEM_get_EVP_CIPHER_INFO(*pem_header, &cipher)1317|| !file_fill_pem_pass_data(&pass_data, "PEM pass phrase", uri,1318ui_method, ui_data)1319|| !PEM_do_header(&cipher, *data, len, file_get_pem_pass,1320&pass_data)) {1321return 0;1322}1323}1324return 1;1325}13261327static OSSL_STORE_INFO *file_try_read_msblob(BIO *bp, int *matchcount)1328{1329OSSL_STORE_INFO *result = NULL;1330int ispub = -1;13311332{1333unsigned int magic = 0, bitlen = 0;1334int isdss = 0;1335unsigned char peekbuf[16] = { 0, };1336const unsigned char *p = peekbuf;13371338if (BIO_buffer_peek(bp, peekbuf, sizeof(peekbuf)) <= 0)1339return 0;1340if (ossl_do_blob_header(&p, sizeof(peekbuf), &magic, &bitlen,1341&isdss, &ispub) <= 0)1342return 0;1343}13441345(*matchcount)++;13461347{1348EVP_PKEY *tmp = ispub1349? b2i_PublicKey_bio(bp)1350: b2i_PrivateKey_bio(bp);13511352if (tmp == NULL1353|| (result = OSSL_STORE_INFO_new_PKEY(tmp)) == NULL) {1354EVP_PKEY_free(tmp);1355return 0;1356}1357}13581359return result;1360}13611362static OSSL_STORE_INFO *file_try_read_PVK(BIO *bp, const UI_METHOD *ui_method,1363void *ui_data, const char *uri,1364int *matchcount)1365{1366OSSL_STORE_INFO *result = NULL;13671368{1369unsigned int saltlen = 0, keylen = 0;1370int isdss = -1;1371unsigned char peekbuf[24] = { 0, };1372const unsigned char *p = peekbuf;13731374if (BIO_buffer_peek(bp, peekbuf, sizeof(peekbuf)) <= 0)1375return 0;1376if (!ossl_do_PVK_header(&p, sizeof(peekbuf), 0, &isdss, &saltlen, &keylen))1377return 0;1378}13791380(*matchcount)++;13811382{1383EVP_PKEY *tmp = NULL;1384struct pem_pass_data pass_data;13851386if (!file_fill_pem_pass_data(&pass_data, "PVK pass phrase", uri,1387ui_method, ui_data)1388|| (tmp = b2i_PVK_bio(bp, file_get_pem_pass, &pass_data)) == NULL1389|| (result = OSSL_STORE_INFO_new_PKEY(tmp)) == NULL) {1390EVP_PKEY_free(tmp);1391return 0;1392}1393}13941395return result;1396}13971398static int file_read_asn1(BIO *bp, unsigned char **data, long *len)1399{1400BUF_MEM *mem = NULL;14011402if (asn1_d2i_read_bio(bp, &mem) < 0)1403return 0;14041405*data = (unsigned char *)mem->data;1406*len = (long)mem->length;1407OPENSSL_free(mem);14081409return 1;1410}14111412static int file_name_to_uri(OSSL_STORE_LOADER_CTX *ctx, const char *name,1413char **data)1414{1415assert(name != NULL);1416assert(data != NULL);1417{1418const char *pathsep = ossl_ends_with_dirsep(ctx->uri) ? "" : "/";1419long calculated_length = strlen(ctx->uri) + strlen(pathsep)1420+ strlen(name) + 1 /* \0 */;14211422*data = OPENSSL_zalloc(calculated_length);1423if (*data == NULL)1424return 0;14251426OPENSSL_strlcat(*data, ctx->uri, calculated_length);1427OPENSSL_strlcat(*data, pathsep, calculated_length);1428OPENSSL_strlcat(*data, name, calculated_length);1429}1430return 1;1431}14321433static int file_name_check(OSSL_STORE_LOADER_CTX *ctx, const char *name)1434{1435const char *p = NULL;1436size_t len = strlen(ctx->_.dir.search_name);14371438/* If there are no search criteria, all names are accepted */1439if (ctx->_.dir.search_name[0] == '\0')1440return 1;14411442/* If the expected type isn't supported, no name is accepted */1443if (ctx->expected_type != 01444&& ctx->expected_type != OSSL_STORE_INFO_CERT1445&& ctx->expected_type != OSSL_STORE_INFO_CRL)1446return 0;14471448/*1449* First, check the basename1450*/1451if (OPENSSL_strncasecmp(name, ctx->_.dir.search_name, len) != 01452|| name[len] != '.')1453return 0;1454p = &name[len + 1];14551456/*1457* Then, if the expected type is a CRL, check that the extension starts1458* with 'r'1459*/1460if (*p == 'r') {1461p++;1462if (ctx->expected_type != 01463&& ctx->expected_type != OSSL_STORE_INFO_CRL)1464return 0;1465} else if (ctx->expected_type == OSSL_STORE_INFO_CRL) {1466return 0;1467}14681469/*1470* Last, check that the rest of the extension is a decimal number, at1471* least one digit long.1472*/1473if (!isdigit((unsigned char)*p))1474return 0;1475while (isdigit((unsigned char)*p))1476p++;14771478#ifdef __VMS1479/*1480* One extra step here, check for a possible generation number.1481*/1482if (*p == ';')1483for (p++; *p != '\0'; p++)1484if (!ossl_isdigit(*p))1485break;1486#endif14871488/*1489* If we've reached the end of the string at this point, we've successfully1490* found a fitting file name.1491*/1492return *p == '\0';1493}14941495static int file_eof(OSSL_STORE_LOADER_CTX *ctx);1496static int file_error(OSSL_STORE_LOADER_CTX *ctx);1497static OSSL_STORE_INFO *file_load(OSSL_STORE_LOADER_CTX *ctx,1498const UI_METHOD *ui_method,1499void *ui_data)1500{1501OSSL_STORE_INFO *result = NULL;15021503ctx->errcnt = 0;15041505if (ctx->type == is_dir) {1506do {1507char *newname = NULL;15081509if (ctx->_.dir.last_entry == NULL) {1510if (!ctx->_.dir.end_reached) {1511assert(ctx->_.dir.last_errno != 0);1512ERR_raise(ERR_LIB_SYS, ctx->_.dir.last_errno);1513ctx->errcnt++;1514}1515return NULL;1516}15171518if (ctx->_.dir.last_entry[0] != '.'1519&& file_name_check(ctx, ctx->_.dir.last_entry)1520&& !file_name_to_uri(ctx, ctx->_.dir.last_entry, &newname))1521return NULL;15221523/*1524* On the first call (with a NULL context), OPENSSL_DIR_read()1525* cares about the second argument. On the following calls, it1526* only cares that it isn't NULL. Therefore, we can safely give1527* it our URI here.1528*/1529ctx->_.dir.last_entry = OPENSSL_DIR_read(&ctx->_.dir.ctx, ctx->uri);1530ctx->_.dir.last_errno = errno;1531if (ctx->_.dir.last_entry == NULL && ctx->_.dir.last_errno == 0)1532ctx->_.dir.end_reached = 1;15331534if (newname != NULL1535&& (result = OSSL_STORE_INFO_new_NAME(newname)) == NULL) {1536OPENSSL_free(newname);1537ATTICerr(0, ERR_R_OSSL_STORE_LIB);1538return NULL;1539}1540} while (result == NULL && !file_eof(ctx));1541} else {1542int matchcount = -1;15431544again:1545result = file_load_try_repeat(ctx, ui_method, ui_data);1546if (result != NULL)1547return result;15481549if (file_eof(ctx))1550return NULL;15511552do {1553char *pem_name = NULL; /* PEM record name */1554char *pem_header = NULL; /* PEM record header */1555unsigned char *data = NULL; /* DER encoded data */1556long len = 0; /* DER encoded data length */15571558matchcount = -1;1559if (ctx->type == is_pem) {1560if (!file_read_pem(ctx->_.file.file, &pem_name, &pem_header,1561&data, &len, ui_method, ui_data, ctx->uri,1562(ctx->flags & FILE_FLAG_SECMEM) != 0)) {1563ctx->errcnt++;1564goto endloop;1565}1566} else {1567if ((result = file_try_read_msblob(ctx->_.file.file,1568&matchcount)) != NULL1569|| (result = file_try_read_PVK(ctx->_.file.file,1570ui_method, ui_data, ctx->uri,1571&matchcount)) != NULL)1572goto endloop;15731574if (!file_read_asn1(ctx->_.file.file, &data, &len)) {1575ctx->errcnt++;1576goto endloop;1577}1578}15791580result = file_load_try_decode(ctx, pem_name, pem_header, data, len,1581ui_method, ui_data, &matchcount);15821583if (result != NULL)1584goto endloop;15851586/*1587* If a PEM name matches more than one handler, the handlers are1588* badly coded.1589*/1590if (!ossl_assert(pem_name == NULL || matchcount <= 1)) {1591ctx->errcnt++;1592goto endloop;1593}15941595if (matchcount > 1) {1596ATTICerr(0, ATTIC_R_AMBIGUOUS_CONTENT_TYPE);1597} else if (matchcount == 1) {1598/*1599* If there are other errors on the stack, they already show1600* what the problem is.1601*/1602if (ERR_peek_error() == 0) {1603ATTICerr(0, ATTIC_R_UNSUPPORTED_CONTENT_TYPE);1604if (pem_name != NULL)1605ERR_add_error_data(3, "PEM type is '", pem_name, "'");1606}1607}1608if (matchcount > 0)1609ctx->errcnt++;16101611endloop:1612pem_free_flag(pem_name, (ctx->flags & FILE_FLAG_SECMEM) != 0, 0);1613pem_free_flag(pem_header, (ctx->flags & FILE_FLAG_SECMEM) != 0, 0);1614pem_free_flag(data, (ctx->flags & FILE_FLAG_SECMEM) != 0, len);1615} while (matchcount == 0 && !file_eof(ctx) && !file_error(ctx));16161617/* We bail out on ambiguity */1618if (matchcount > 1) {1619store_info_free(result);1620return NULL;1621}16221623if (result != NULL1624&& ctx->expected_type != 01625&& ctx->expected_type != OSSL_STORE_INFO_get_type(result)) {1626store_info_free(result);1627goto again;1628}1629}16301631return result;1632}16331634static int file_error(OSSL_STORE_LOADER_CTX *ctx)1635{1636return ctx->errcnt > 0;1637}16381639static int file_eof(OSSL_STORE_LOADER_CTX *ctx)1640{1641if (ctx->type == is_dir)1642return ctx->_.dir.end_reached;16431644if (ctx->_.file.last_handler != NULL1645&& !ctx->_.file.last_handler->eof(ctx->_.file.last_handler_ctx))1646return 0;1647return BIO_eof(ctx->_.file.file);1648}16491650static int file_close(OSSL_STORE_LOADER_CTX *ctx)1651{1652if ((ctx->flags & FILE_FLAG_ATTACHED) == 0) {1653if (ctx->type == is_dir)1654OPENSSL_DIR_end(&ctx->_.dir.ctx);1655else1656BIO_free_all(ctx->_.file.file);1657} else {1658/*1659* Because file_attach() called file_find_type(), we know that a1660* BIO_f_buffer() has been pushed on top of the regular BIO.1661*/1662BIO *buff = ctx->_.file.file;16631664/* Detach buff */1665(void)BIO_pop(ctx->_.file.file);1666/* Safety measure */1667ctx->_.file.file = NULL;16681669BIO_free(buff);1670}1671OSSL_STORE_LOADER_CTX_free(ctx);1672return 1;1673}16741675/*-1676* ENGINE management1677*/16781679static const char *loader_attic_id = "loader_attic";1680static const char *loader_attic_name = "'file:' loader";16811682static OSSL_STORE_LOADER *loader_attic = NULL;16831684static int loader_attic_init(ENGINE *e)1685{1686return 1;1687}168816891690static int loader_attic_finish(ENGINE *e)1691{1692return 1;1693}169416951696static int loader_attic_destroy(ENGINE *e)1697{1698OSSL_STORE_LOADER *loader = OSSL_STORE_unregister_loader("file");16991700if (loader == NULL)1701return 0;17021703ERR_unload_ATTIC_strings();1704OSSL_STORE_LOADER_free(loader);1705return 1;1706}17071708static int bind_loader_attic(ENGINE *e)1709{17101711/* Ensure the ATTIC error handling is set up on best effort basis */1712ERR_load_ATTIC_strings();17131714if (/* Create the OSSL_STORE_LOADER */1715(loader_attic = OSSL_STORE_LOADER_new(e, "file")) == NULL1716|| !OSSL_STORE_LOADER_set_open_ex(loader_attic, file_open_ex)1717|| !OSSL_STORE_LOADER_set_open(loader_attic, file_open)1718|| !OSSL_STORE_LOADER_set_attach(loader_attic, file_attach)1719|| !OSSL_STORE_LOADER_set_ctrl(loader_attic, file_ctrl)1720|| !OSSL_STORE_LOADER_set_expect(loader_attic, file_expect)1721|| !OSSL_STORE_LOADER_set_find(loader_attic, file_find)1722|| !OSSL_STORE_LOADER_set_load(loader_attic, file_load)1723|| !OSSL_STORE_LOADER_set_eof(loader_attic, file_eof)1724|| !OSSL_STORE_LOADER_set_error(loader_attic, file_error)1725|| !OSSL_STORE_LOADER_set_close(loader_attic, file_close)1726/* Init the engine itself */1727|| !ENGINE_set_id(e, loader_attic_id)1728|| !ENGINE_set_name(e, loader_attic_name)1729|| !ENGINE_set_destroy_function(e, loader_attic_destroy)1730|| !ENGINE_set_init_function(e, loader_attic_init)1731|| !ENGINE_set_finish_function(e, loader_attic_finish)1732/* Finally, register the method with libcrypto */1733|| !OSSL_STORE_register_loader(loader_attic)) {1734OSSL_STORE_LOADER_free(loader_attic);1735loader_attic = NULL;1736ATTICerr(0, ATTIC_R_INIT_FAILED);1737return 0;1738}17391740return 1;1741}17421743#ifdef OPENSSL_NO_DYNAMIC_ENGINE1744# error "Only allowed as dynamically shared object"1745#endif17461747static int bind_helper(ENGINE *e, const char *id)1748{1749if (id && (strcmp(id, loader_attic_id) != 0))1750return 0;1751if (!bind_loader_attic(e))1752return 0;1753return 1;1754}17551756IMPLEMENT_DYNAMIC_CHECK_FN()1757IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)175817591760