xref: /freebsd-src/crypto/openssl/engines/e_loader_attic.c (revision b077aed33b7b6aefca7b17ddb250cf521f938613)
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     &params_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