1 /*
2 * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 #include <stdio.h>
11 #include <time.h>
12 #include <errno.h>
13
14 #include "internal/cryptlib.h"
15 #include <openssl/buffer.h>
16 #include <openssl/x509.h>
17 #include <openssl/pem.h>
18 #include "x509_local.h"
19
20 static int by_file_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc,
21 long argl, char **ret);
22 static int by_file_ctrl_ex(X509_LOOKUP *ctx, int cmd, const char *argc,
23 long argl, char **ret, OSSL_LIB_CTX *libctx,
24 const char *propq);
25
26 static X509_LOOKUP_METHOD x509_file_lookup = {
27 "Load file into cache",
28 NULL, /* new_item */
29 NULL, /* free */
30 NULL, /* init */
31 NULL, /* shutdown */
32 by_file_ctrl, /* ctrl */
33 NULL, /* get_by_subject */
34 NULL, /* get_by_issuer_serial */
35 NULL, /* get_by_fingerprint */
36 NULL, /* get_by_alias */
37 NULL, /* get_by_subject_ex */
38 by_file_ctrl_ex, /* ctrl_ex */
39 };
40
X509_LOOKUP_file(void)41 X509_LOOKUP_METHOD *X509_LOOKUP_file(void)
42 {
43 return &x509_file_lookup;
44 }
45
by_file_ctrl_ex(X509_LOOKUP * ctx,int cmd,const char * argp,long argl,char ** ret,OSSL_LIB_CTX * libctx,const char * propq)46 static int by_file_ctrl_ex(X509_LOOKUP *ctx, int cmd, const char *argp,
47 long argl, char **ret, OSSL_LIB_CTX *libctx,
48 const char *propq)
49 {
50 int ok = 0;
51 const char *file;
52
53 switch (cmd) {
54 case X509_L_FILE_LOAD:
55 if (argl == X509_FILETYPE_DEFAULT) {
56 file = ossl_safe_getenv(X509_get_default_cert_file_env());
57 if (file)
58 ok = (X509_load_cert_crl_file_ex(ctx, file, X509_FILETYPE_PEM,
59 libctx, propq)
60 != 0);
61 else
62 ok = (X509_load_cert_crl_file_ex(
63 ctx, X509_get_default_cert_file(),
64 X509_FILETYPE_PEM, libctx, propq)
65 != 0);
66
67 if (!ok)
68 ERR_raise(ERR_LIB_X509, X509_R_LOADING_DEFAULTS);
69 } else {
70 if (argl == X509_FILETYPE_PEM)
71 ok = (X509_load_cert_crl_file_ex(ctx, argp, X509_FILETYPE_PEM,
72 libctx, propq)
73 != 0);
74 else
75 ok = (X509_load_cert_file_ex(ctx, argp, (int)argl, libctx,
76 propq)
77 != 0);
78 }
79 break;
80 }
81 return ok;
82 }
83
by_file_ctrl(X509_LOOKUP * ctx,int cmd,const char * argp,long argl,char ** ret)84 static int by_file_ctrl(X509_LOOKUP *ctx, int cmd,
85 const char *argp, long argl, char **ret)
86 {
87 return by_file_ctrl_ex(ctx, cmd, argp, argl, ret, NULL, NULL);
88 }
89
X509_load_cert_file_ex(X509_LOOKUP * ctx,const char * file,int type,OSSL_LIB_CTX * libctx,const char * propq)90 int X509_load_cert_file_ex(X509_LOOKUP *ctx, const char *file, int type,
91 OSSL_LIB_CTX *libctx, const char *propq)
92 {
93 BIO *in = NULL;
94 int count = 0;
95 X509 *x = NULL;
96
97 if (file == NULL) {
98 ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
99 goto err;
100 }
101
102 in = BIO_new(BIO_s_file());
103
104 if ((in == NULL) || (BIO_read_filename(in, file) <= 0)) {
105 ERR_raise(ERR_LIB_X509, ERR_R_BIO_LIB);
106 goto err;
107 }
108
109 x = X509_new_ex(libctx, propq);
110 if (x == NULL) {
111 ERR_raise(ERR_LIB_X509, ERR_R_ASN1_LIB);
112 goto err;
113 }
114
115 if (type == X509_FILETYPE_PEM) {
116 for (;;) {
117 ERR_set_mark();
118 if (PEM_read_bio_X509_AUX(in, &x, NULL, "") == NULL) {
119 if ((ERR_GET_REASON(ERR_peek_last_error()) == PEM_R_NO_START_LINE) && (count > 0)) {
120 ERR_pop_to_mark();
121 break;
122 } else {
123 ERR_clear_last_mark();
124 if (count == 0) {
125 ERR_raise(ERR_LIB_X509, X509_R_NO_CERTIFICATE_FOUND);
126 } else {
127 ERR_raise(ERR_LIB_X509, ERR_R_PEM_LIB);
128 count = 0;
129 }
130 goto err;
131 }
132 }
133 ERR_clear_last_mark();
134 if (!X509_STORE_add_cert(ctx->store_ctx, x)) {
135 count = 0;
136 goto err;
137 }
138 /*
139 * X509_STORE_add_cert() added a reference rather than a copy,
140 * so we need a fresh X509 object.
141 */
142 X509_free(x);
143 x = X509_new_ex(libctx, propq);
144 if (x == NULL) {
145 ERR_raise(ERR_LIB_X509, ERR_R_ASN1_LIB);
146 count = 0;
147 goto err;
148 }
149 count++;
150 }
151 } else if (type == X509_FILETYPE_ASN1) {
152 if (d2i_X509_bio(in, &x) == NULL) {
153 ERR_raise(ERR_LIB_X509, X509_R_NO_CERTIFICATE_FOUND);
154 goto err;
155 }
156 count = X509_STORE_add_cert(ctx->store_ctx, x);
157 } else {
158 ERR_raise(ERR_LIB_X509, X509_R_BAD_X509_FILETYPE);
159 goto err;
160 }
161 err:
162 X509_free(x);
163 BIO_free(in);
164 return count;
165 }
166
X509_load_cert_file(X509_LOOKUP * ctx,const char * file,int type)167 int X509_load_cert_file(X509_LOOKUP *ctx, const char *file, int type)
168 {
169 return X509_load_cert_file_ex(ctx, file, type, NULL, NULL);
170 }
171
X509_load_crl_file(X509_LOOKUP * ctx,const char * file,int type)172 int X509_load_crl_file(X509_LOOKUP *ctx, const char *file, int type)
173 {
174 BIO *in = NULL;
175 int count = 0;
176 X509_CRL *x = NULL;
177
178 if (file == NULL) {
179 ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
180 goto err;
181 }
182
183 in = BIO_new(BIO_s_file());
184
185 if ((in == NULL) || (BIO_read_filename(in, file) <= 0)) {
186 ERR_raise(ERR_LIB_X509, ERR_R_BIO_LIB);
187 goto err;
188 }
189
190 if (type == X509_FILETYPE_PEM) {
191 for (;;) {
192 x = PEM_read_bio_X509_CRL(in, NULL, NULL, "");
193 if (x == NULL) {
194 if ((ERR_GET_REASON(ERR_peek_last_error()) == PEM_R_NO_START_LINE) && (count > 0)) {
195 ERR_clear_error();
196 break;
197 } else {
198 if (count == 0) {
199 ERR_raise(ERR_LIB_X509, X509_R_NO_CRL_FOUND);
200 } else {
201 ERR_raise(ERR_LIB_X509, ERR_R_PEM_LIB);
202 count = 0;
203 }
204 goto err;
205 }
206 }
207 if (!X509_STORE_add_crl(ctx->store_ctx, x)) {
208 count = 0;
209 goto err;
210 }
211 count++;
212 X509_CRL_free(x);
213 x = NULL;
214 }
215 } else if (type == X509_FILETYPE_ASN1) {
216 x = d2i_X509_CRL_bio(in, NULL);
217 if (x == NULL) {
218 ERR_raise(ERR_LIB_X509, X509_R_NO_CRL_FOUND);
219 goto err;
220 }
221 count = X509_STORE_add_crl(ctx->store_ctx, x);
222 } else {
223 ERR_raise(ERR_LIB_X509, X509_R_BAD_X509_FILETYPE);
224 goto err;
225 }
226 err:
227 X509_CRL_free(x);
228 BIO_free(in);
229 return count;
230 }
231
X509_load_cert_crl_file_ex(X509_LOOKUP * ctx,const char * file,int type,OSSL_LIB_CTX * libctx,const char * propq)232 int X509_load_cert_crl_file_ex(X509_LOOKUP *ctx, const char *file, int type,
233 OSSL_LIB_CTX *libctx, const char *propq)
234 {
235 STACK_OF(X509_INFO) *inf = NULL;
236 X509_INFO *itmp = NULL;
237 BIO *in = NULL;
238 int i, count = 0;
239
240 if (type != X509_FILETYPE_PEM)
241 return X509_load_cert_file_ex(ctx, file, type, libctx, propq);
242 #if defined(OPENSSL_SYS_WINDOWS)
243 in = BIO_new_file(file, "rb");
244 #else
245 in = BIO_new_file(file, "r");
246 #endif
247 if (in == NULL) {
248 ERR_raise(ERR_LIB_X509, ERR_R_BIO_LIB);
249 return 0;
250 }
251 inf = PEM_X509_INFO_read_bio_ex(in, NULL, NULL, "", libctx, propq);
252 BIO_free(in);
253 if (inf == NULL) {
254 ERR_raise(ERR_LIB_X509, ERR_R_PEM_LIB);
255 return 0;
256 }
257 for (i = 0; i < sk_X509_INFO_num(inf); i++) {
258 itmp = sk_X509_INFO_value(inf, i);
259 if (itmp->x509) {
260 if (!X509_STORE_add_cert(ctx->store_ctx, itmp->x509)) {
261 count = 0;
262 goto err;
263 }
264 count++;
265 }
266 if (itmp->crl) {
267 if (!X509_STORE_add_crl(ctx->store_ctx, itmp->crl)) {
268 count = 0;
269 goto err;
270 }
271 count++;
272 }
273 }
274 if (count == 0)
275 ERR_raise(ERR_LIB_X509, X509_R_NO_CERTIFICATE_OR_CRL_FOUND);
276 err:
277 sk_X509_INFO_pop_free(inf, X509_INFO_free);
278 return count;
279 }
280
X509_load_cert_crl_file(X509_LOOKUP * ctx,const char * file,int type)281 int X509_load_cert_crl_file(X509_LOOKUP *ctx, const char *file, int type)
282 {
283 return X509_load_cert_crl_file_ex(ctx, file, type, NULL, NULL);
284 }
285