blob: 0b55a9d9505876a6035e8c689363dc98bc2e1af8 [file] [log] [blame]
David Benjamin33d10492025-02-03 17:00:03 -05001// Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
David Benjamin443a1f62015-09-04 15:05:05 -040014
15#include <openssl/ssl.h>
16
17#include <errno.h>
18#include <string.h>
19
David Benjamin72279902015-10-17 22:15:37 -040020#include <openssl/asn1.h>
David Benjamin443a1f62015-09-04 15:05:05 -040021#include <openssl/bio.h>
22#include <openssl/err.h>
23#include <openssl/mem.h>
24#include <openssl/pem.h>
25#include <openssl/stack.h>
26#include <openssl/x509.h>
27
David Benjamin443a1f62015-09-04 15:05:05 -040028#include "internal.h"
29
30
David Benjaminaf0739f2023-01-09 10:03:02 -080031static int xname_cmp(const X509_NAME *const *a, const X509_NAME *const *b) {
David Benjamin443a1f62015-09-04 15:05:05 -040032 return X509_NAME_cmp(*a, *b);
33}
34
David Benjamin4da5a942022-08-02 14:39:44 -070035static int add_bio_cert_subjects_to_stack(STACK_OF(X509_NAME) *out, BIO *bio,
36 bool allow_empty) {
David Benjamin955ef792022-06-13 13:16:43 -040037 // This function historically sorted |out| after every addition and skipped
38 // duplicates. This implementation preserves that behavior, but only sorts at
39 // the end, to avoid a quadratic running time. Existing duplicates in |out|
40 // are preserved, but do not introduce new duplicates.
41 bssl::UniquePtr<STACK_OF(X509_NAME)> to_append(sk_X509_NAME_new(xname_cmp));
42 if (to_append == nullptr) {
43 return 0;
David Benjamin443a1f62015-09-04 15:05:05 -040044 }
45
David Benjamin955ef792022-06-13 13:16:43 -040046 // Temporarily switch the comparison function for |out|.
47 struct RestoreCmpFunc {
48 ~RestoreCmpFunc() { sk_X509_NAME_set_cmp_func(stack, old_cmp); }
49 STACK_OF(X509_NAME) *stack;
David Benjaminaf0739f2023-01-09 10:03:02 -080050 int (*old_cmp)(const X509_NAME *const *, const X509_NAME *const *);
David Benjamin955ef792022-06-13 13:16:43 -040051 };
52 RestoreCmpFunc restore = {out, sk_X509_NAME_set_cmp_func(out, xname_cmp)};
David Benjamin443a1f62015-09-04 15:05:05 -040053
David Benjamin955ef792022-06-13 13:16:43 -040054 sk_X509_NAME_sort(out);
David Benjamin4da5a942022-08-02 14:39:44 -070055 bool first = true;
David Benjamin443a1f62015-09-04 15:05:05 -040056 for (;;) {
David Benjamin955ef792022-06-13 13:16:43 -040057 bssl::UniquePtr<X509> x509(
58 PEM_read_bio_X509(bio, nullptr, nullptr, nullptr));
59 if (x509 == nullptr) {
David Benjamin4da5a942022-08-02 14:39:44 -070060 if (first && !allow_empty) {
61 return 0;
62 }
David Benjamin955ef792022-06-13 13:16:43 -040063 // TODO(davidben): This ignores PEM syntax errors. It should only succeed
64 // on |PEM_R_NO_START_LINE|.
65 ERR_clear_error();
David Benjamin443a1f62015-09-04 15:05:05 -040066 break;
67 }
David Benjamin4da5a942022-08-02 14:39:44 -070068 first = false;
David Benjamin1eeb0b02016-09-27 01:20:31 -040069
David Benjamin955ef792022-06-13 13:16:43 -040070 X509_NAME *subject = X509_get_subject_name(x509.get());
71 // Skip if already present in |out|. Duplicates in |to_append| will be
72 // handled separately.
73 if (sk_X509_NAME_find(out, /*out_index=*/NULL, subject)) {
David Benjamin1eeb0b02016-09-27 01:20:31 -040074 continue;
75 }
76
David Benjamin955ef792022-06-13 13:16:43 -040077 bssl::UniquePtr<X509_NAME> copy(X509_NAME_dup(subject));
78 if (copy == nullptr ||
79 !bssl::PushToStack(to_append.get(), std::move(copy))) {
80 return 0;
David Benjamin443a1f62015-09-04 15:05:05 -040081 }
82 }
83
David Benjamin955ef792022-06-13 13:16:43 -040084 // Append |to_append| to |stack|, skipping any duplicates.
85 sk_X509_NAME_sort(to_append.get());
86 size_t num = sk_X509_NAME_num(to_append.get());
87 for (size_t i = 0; i < num; i++) {
88 bssl::UniquePtr<X509_NAME> name(sk_X509_NAME_value(to_append.get(), i));
89 sk_X509_NAME_set(to_append.get(), i, nullptr);
90 if (i + 1 < num &&
91 X509_NAME_cmp(name.get(), sk_X509_NAME_value(to_append.get(), i + 1)) ==
92 0) {
93 continue;
94 }
95 if (!bssl::PushToStack(out, std::move(name))) {
96 return 0;
97 }
98 }
David Benjamin443a1f62015-09-04 15:05:05 -040099
David Benjamin955ef792022-06-13 13:16:43 -0400100 // Sort |out| one last time, to preserve the historical behavior of
101 // maintaining the sorted list.
102 sk_X509_NAME_sort(out);
103 return 1;
David Benjamin443a1f62015-09-04 15:05:05 -0400104}
105
David Benjamin5ba5db12023-07-14 16:30:43 -0400106int SSL_add_bio_cert_subjects_to_stack(STACK_OF(X509_NAME) *out, BIO *bio) {
107 return add_bio_cert_subjects_to_stack(out, bio, /*allow_empty=*/true);
108}
109
David Benjamin4da5a942022-08-02 14:39:44 -0700110STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file) {
David Benjamincadebfd2024-02-04 23:27:14 -0500111 bssl::UniquePtr<BIO> in(BIO_new_file(file, "rb"));
David Benjamin4da5a942022-08-02 14:39:44 -0700112 if (in == nullptr) {
113 return nullptr;
114 }
115 bssl::UniquePtr<STACK_OF(X509_NAME)> ret(sk_X509_NAME_new_null());
116 if (ret == nullptr || //
117 !add_bio_cert_subjects_to_stack(ret.get(), in.get(),
118 /*allow_empty=*/false)) {
119 return nullptr;
120 }
121 return ret.release();
122}
123
124int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *out,
125 const char *file) {
David Benjamincadebfd2024-02-04 23:27:14 -0500126 bssl::UniquePtr<BIO> in(BIO_new_file(file, "rb"));
David Benjamin4da5a942022-08-02 14:39:44 -0700127 if (in == nullptr) {
128 return 0;
129 }
130 return SSL_add_bio_cert_subjects_to_stack(out, in.get());
131}
132
David Benjamin443a1f62015-09-04 15:05:05 -0400133int SSL_use_certificate_file(SSL *ssl, const char *file, int type) {
134 int reason_code;
135 BIO *in;
136 int ret = 0;
137 X509 *x = NULL;
138
139 in = BIO_new(BIO_s_file());
140 if (in == NULL) {
141 OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
142 goto end;
143 }
144
145 if (BIO_read_filename(in, file) <= 0) {
146 OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
147 goto end;
148 }
149
150 if (type == SSL_FILETYPE_ASN1) {
151 reason_code = ERR_R_ASN1_LIB;
152 x = d2i_X509_bio(in, NULL);
153 } else if (type == SSL_FILETYPE_PEM) {
154 reason_code = ERR_R_PEM_LIB;
155 x = PEM_read_bio_X509(in, NULL, ssl->ctx->default_passwd_callback,
156 ssl->ctx->default_passwd_callback_userdata);
157 } else {
158 OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
159 goto end;
160 }
161
162 if (x == NULL) {
163 OPENSSL_PUT_ERROR(SSL, reason_code);
164 goto end;
165 }
166
167 ret = SSL_use_certificate(ssl, x);
168
169end:
170 X509_free(x);
171 BIO_free(in);
172
173 return ret;
174}
175
176int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type) {
177 int reason_code, ret = 0;
178 BIO *in;
179 RSA *rsa = NULL;
180
181 in = BIO_new(BIO_s_file());
182 if (in == NULL) {
183 OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
184 goto end;
185 }
186
187 if (BIO_read_filename(in, file) <= 0) {
188 OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
189 goto end;
190 }
191
192 if (type == SSL_FILETYPE_ASN1) {
193 reason_code = ERR_R_ASN1_LIB;
194 rsa = d2i_RSAPrivateKey_bio(in, NULL);
195 } else if (type == SSL_FILETYPE_PEM) {
196 reason_code = ERR_R_PEM_LIB;
197 rsa =
198 PEM_read_bio_RSAPrivateKey(in, NULL, ssl->ctx->default_passwd_callback,
199 ssl->ctx->default_passwd_callback_userdata);
200 } else {
201 OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
202 goto end;
203 }
204
205 if (rsa == NULL) {
206 OPENSSL_PUT_ERROR(SSL, reason_code);
207 goto end;
208 }
209 ret = SSL_use_RSAPrivateKey(ssl, rsa);
210 RSA_free(rsa);
211
212end:
213 BIO_free(in);
214 return ret;
215}
216
217int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type) {
218 int reason_code, ret = 0;
219 BIO *in;
220 EVP_PKEY *pkey = NULL;
221
222 in = BIO_new(BIO_s_file());
223 if (in == NULL) {
224 OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
225 goto end;
226 }
227
228 if (BIO_read_filename(in, file) <= 0) {
229 OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
230 goto end;
231 }
232
233 if (type == SSL_FILETYPE_PEM) {
234 reason_code = ERR_R_PEM_LIB;
235 pkey = PEM_read_bio_PrivateKey(in, NULL, ssl->ctx->default_passwd_callback,
236 ssl->ctx->default_passwd_callback_userdata);
237 } else if (type == SSL_FILETYPE_ASN1) {
238 reason_code = ERR_R_ASN1_LIB;
239 pkey = d2i_PrivateKey_bio(in, NULL);
240 } else {
241 OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
242 goto end;
243 }
244
245 if (pkey == NULL) {
246 OPENSSL_PUT_ERROR(SSL, reason_code);
247 goto end;
248 }
249 ret = SSL_use_PrivateKey(ssl, pkey);
250 EVP_PKEY_free(pkey);
251
252end:
253 BIO_free(in);
254 return ret;
255}
256
257int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type) {
258 int reason_code;
259 BIO *in;
260 int ret = 0;
261 X509 *x = NULL;
262
263 in = BIO_new(BIO_s_file());
264 if (in == NULL) {
265 OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
266 goto end;
267 }
268
269 if (BIO_read_filename(in, file) <= 0) {
270 OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
271 goto end;
272 }
273
274 if (type == SSL_FILETYPE_ASN1) {
275 reason_code = ERR_R_ASN1_LIB;
276 x = d2i_X509_bio(in, NULL);
277 } else if (type == SSL_FILETYPE_PEM) {
278 reason_code = ERR_R_PEM_LIB;
279 x = PEM_read_bio_X509(in, NULL, ctx->default_passwd_callback,
280 ctx->default_passwd_callback_userdata);
281 } else {
282 OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
283 goto end;
284 }
285
286 if (x == NULL) {
287 OPENSSL_PUT_ERROR(SSL, reason_code);
288 goto end;
289 }
290
291 ret = SSL_CTX_use_certificate(ctx, x);
292
293end:
294 X509_free(x);
295 BIO_free(in);
296 return ret;
297}
298
299int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type) {
300 int reason_code, ret = 0;
301 BIO *in;
302 RSA *rsa = NULL;
303
304 in = BIO_new(BIO_s_file());
305 if (in == NULL) {
306 OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
307 goto end;
308 }
309
310 if (BIO_read_filename(in, file) <= 0) {
311 OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
312 goto end;
313 }
314
315 if (type == SSL_FILETYPE_ASN1) {
316 reason_code = ERR_R_ASN1_LIB;
317 rsa = d2i_RSAPrivateKey_bio(in, NULL);
318 } else if (type == SSL_FILETYPE_PEM) {
319 reason_code = ERR_R_PEM_LIB;
320 rsa = PEM_read_bio_RSAPrivateKey(in, NULL, ctx->default_passwd_callback,
321 ctx->default_passwd_callback_userdata);
322 } else {
323 OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
324 goto end;
325 }
326
327 if (rsa == NULL) {
328 OPENSSL_PUT_ERROR(SSL, reason_code);
329 goto end;
330 }
331 ret = SSL_CTX_use_RSAPrivateKey(ctx, rsa);
332 RSA_free(rsa);
333
334end:
335 BIO_free(in);
336 return ret;
337}
338
339int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) {
340 int reason_code, ret = 0;
341 BIO *in;
342 EVP_PKEY *pkey = NULL;
343
344 in = BIO_new(BIO_s_file());
345 if (in == NULL) {
346 OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
347 goto end;
348 }
349
350 if (BIO_read_filename(in, file) <= 0) {
351 OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
352 goto end;
353 }
354
355 if (type == SSL_FILETYPE_PEM) {
356 reason_code = ERR_R_PEM_LIB;
357 pkey = PEM_read_bio_PrivateKey(in, NULL, ctx->default_passwd_callback,
358 ctx->default_passwd_callback_userdata);
359 } else if (type == SSL_FILETYPE_ASN1) {
360 reason_code = ERR_R_ASN1_LIB;
361 pkey = d2i_PrivateKey_bio(in, NULL);
362 } else {
363 OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
364 goto end;
365 }
366
367 if (pkey == NULL) {
368 OPENSSL_PUT_ERROR(SSL, reason_code);
369 goto end;
370 }
371 ret = SSL_CTX_use_PrivateKey(ctx, pkey);
372 EVP_PKEY_free(pkey);
373
374end:
375 BIO_free(in);
376 return ret;
377}
378
David Benjaminc11ea9422017-08-29 16:33:21 -0400379// Read a file that contains our certificate in "PEM" format, possibly followed
380// by a sequence of CA certificates that should be sent to the peer in the
381// Certificate message.
David Benjamin443a1f62015-09-04 15:05:05 -0400382int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) {
383 BIO *in;
384 int ret = 0;
385 X509 *x = NULL;
386
David Benjaminc11ea9422017-08-29 16:33:21 -0400387 ERR_clear_error(); // clear error stack for SSL_CTX_use_certificate()
David Benjamin443a1f62015-09-04 15:05:05 -0400388
389 in = BIO_new(BIO_s_file());
390 if (in == NULL) {
391 OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
392 goto end;
393 }
394
395 if (BIO_read_filename(in, file) <= 0) {
396 OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
397 goto end;
398 }
399
400 x = PEM_read_bio_X509_AUX(in, NULL, ctx->default_passwd_callback,
401 ctx->default_passwd_callback_userdata);
402 if (x == NULL) {
403 OPENSSL_PUT_ERROR(SSL, ERR_R_PEM_LIB);
404 goto end;
405 }
406
407 ret = SSL_CTX_use_certificate(ctx, x);
408
409 if (ERR_peek_error() != 0) {
David Benjaminc11ea9422017-08-29 16:33:21 -0400410 ret = 0; // Key/certificate mismatch doesn't imply ret==0 ...
David Benjamin443a1f62015-09-04 15:05:05 -0400411 }
412
413 if (ret) {
David Benjaminc11ea9422017-08-29 16:33:21 -0400414 // If we could set up our certificate, now proceed to the CA
415 // certificates.
David Benjamin443a1f62015-09-04 15:05:05 -0400416 X509 *ca;
417 int r;
418 uint32_t err;
419
420 SSL_CTX_clear_chain_certs(ctx);
421
422 while ((ca = PEM_read_bio_X509(in, NULL, ctx->default_passwd_callback,
423 ctx->default_passwd_callback_userdata)) !=
424 NULL) {
425 r = SSL_CTX_add0_chain_cert(ctx, ca);
426 if (!r) {
427 X509_free(ca);
428 ret = 0;
429 goto end;
430 }
David Benjaminc11ea9422017-08-29 16:33:21 -0400431 // Note that we must not free r if it was successfully added to the chain
432 // (while we must free the main certificate, since its reference count is
433 // increased by SSL_CTX_use_certificate).
David Benjamin443a1f62015-09-04 15:05:05 -0400434 }
435
David Benjaminc11ea9422017-08-29 16:33:21 -0400436 // When the while loop ends, it's usually just EOF.
David Benjamin443a1f62015-09-04 15:05:05 -0400437 err = ERR_peek_last_error();
438 if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
439 ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
440 ERR_clear_error();
441 } else {
David Benjaminc11ea9422017-08-29 16:33:21 -0400442 ret = 0; // some real error
David Benjamin443a1f62015-09-04 15:05:05 -0400443 }
444 }
445
446end:
447 X509_free(x);
448 BIO_free(in);
449 return ret;
450}
451
David Benjamin42fea372015-09-19 01:22:44 -0400452void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb) {
453 ctx->default_passwd_callback = cb;
454}
455
David Benjamin81f030b2016-08-12 14:48:19 -0400456pem_password_cb *SSL_CTX_get_default_passwd_cb(const SSL_CTX *ctx) {
457 return ctx->default_passwd_callback;
458}
459
David Benjamin42fea372015-09-19 01:22:44 -0400460void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *data) {
461 ctx->default_passwd_callback_userdata = data;
462}
David Benjamin81f030b2016-08-12 14:48:19 -0400463
464void *SSL_CTX_get_default_passwd_cb_userdata(const SSL_CTX *ctx) {
465 return ctx->default_passwd_callback_userdata;
466}