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