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 ¶ms_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