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