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 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 42 X509_LOOKUP_METHOD *X509_LOOKUP_file(void) 43 { 44 return &x509_file_lookup; 45 } 46 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 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 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 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 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 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 #if defined(OPENSSL_SYS_WINDOWS) 242 in = BIO_new_file(file, "rb"); 243 #else 244 in = BIO_new_file(file, "r"); 245 #endif 246 if (in == NULL) { 247 ERR_raise(ERR_LIB_X509, ERR_R_BIO_LIB); 248 return 0; 249 } 250 inf = PEM_X509_INFO_read_bio_ex(in, NULL, NULL, "", libctx, propq); 251 BIO_free(in); 252 if (inf == NULL) { 253 ERR_raise(ERR_LIB_X509, ERR_R_PEM_LIB); 254 return 0; 255 } 256 for (i = 0; i < sk_X509_INFO_num(inf); i++) { 257 itmp = sk_X509_INFO_value(inf, i); 258 if (itmp->x509) { 259 if (!X509_STORE_add_cert(ctx->store_ctx, itmp->x509)) { 260 count = 0; 261 goto err; 262 } 263 count++; 264 } 265 if (itmp->crl) { 266 if (!X509_STORE_add_crl(ctx->store_ctx, itmp->crl)) { 267 count = 0; 268 goto err; 269 } 270 count++; 271 } 272 } 273 if (count == 0) 274 ERR_raise(ERR_LIB_X509, X509_R_NO_CERTIFICATE_OR_CRL_FOUND); 275 err: 276 sk_X509_INFO_pop_free(inf, X509_INFO_free); 277 return count; 278 } 279 280 int X509_load_cert_crl_file(X509_LOOKUP *ctx, const char *file, int type) 281 { 282 return X509_load_cert_crl_file_ex(ctx, file, type, NULL, NULL); 283 } 284 285