Packages
hackney
2.0.0
4.7.2
4.7.1
4.7.0
4.6.1
4.6.0
4.5.2
4.5.1
4.5.0
4.4.5
4.4.3
4.4.2
4.4.1
4.4.0
4.3.0
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.3
4.0.2
4.0.1
4.0.0
3.2.1
3.2.0
3.1.2
3.1.1
3.1.0
3.0.3
3.0.2
3.0.1
3.0.0
retired
2.0.1
2.0.0
2.0.0-beta.1
1.25.0
1.24.1
1.24.0
1.23.0
1.22.0
1.21.0
1.20.1
1.20.0
1.19.1
1.19.0
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.0
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.0
1.13.0
1.12.1
1.12.0
1.11.0
1.10.1
1.10.0
1.9.0
1.8.6
1.8.5
1.8.4
1.8.3
1.8.2
1.8.0
1.7.1
1.7.0
1.6.6
retired
1.6.5
1.6.4
retired
1.6.3
1.6.2
1.6.1
1.6.0
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.10
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.6
1.0.5
1.0.2
1.0.1
0.15.2
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
Simple HTTP client with HTTP/1.1, HTTP/2, and HTTP/3 support
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
c_src/boringssl/ssl/ssl_file.cc
// Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <openssl/ssl.h>
#include <string.h>
#include <openssl/asn1.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/pem.h>
#include <openssl/stack.h>
#include <openssl/x509.h>
#include "internal.h"
static int xname_cmp(const X509_NAME *const *a, const X509_NAME *const *b) {
return X509_NAME_cmp(*a, *b);
}
static int add_bio_cert_subjects_to_stack(STACK_OF(X509_NAME) *out, BIO *bio,
bool allow_empty) {
// This function historically sorted |out| after every addition and skipped
// duplicates. This implementation preserves that behavior, but only sorts at
// the end, to avoid a quadratic running time. Existing duplicates in |out|
// are preserved, but do not introduce new duplicates.
bssl::UniquePtr<STACK_OF(X509_NAME)> to_append(sk_X509_NAME_new(xname_cmp));
if (to_append == nullptr) {
return 0;
}
// Temporarily switch the comparison function for |out|.
struct RestoreCmpFunc {
~RestoreCmpFunc() { sk_X509_NAME_set_cmp_func(stack, old_cmp); }
STACK_OF(X509_NAME) *stack;
int (*old_cmp)(const X509_NAME *const *, const X509_NAME *const *);
};
RestoreCmpFunc restore = {out, sk_X509_NAME_set_cmp_func(out, xname_cmp)};
sk_X509_NAME_sort(out);
bool first = true;
for (;;) {
bssl::UniquePtr<X509> x509(
PEM_read_bio_X509(bio, nullptr, nullptr, nullptr));
if (x509 == nullptr) {
if (first && !allow_empty) {
return 0;
}
// TODO(davidben): This ignores PEM syntax errors. It should only succeed
// on |PEM_R_NO_START_LINE|.
ERR_clear_error();
break;
}
first = false;
X509_NAME *subject = X509_get_subject_name(x509.get());
// Skip if already present in |out|. Duplicates in |to_append| will be
// handled separately.
if (sk_X509_NAME_find(out, /*out_index=*/nullptr, subject)) {
continue;
}
bssl::UniquePtr<X509_NAME> copy(X509_NAME_dup(subject));
if (copy == nullptr ||
!bssl::PushToStack(to_append.get(), std::move(copy))) {
return 0;
}
}
// Append |to_append| to |stack|, skipping any duplicates.
sk_X509_NAME_sort(to_append.get());
size_t num = sk_X509_NAME_num(to_append.get());
for (size_t i = 0; i < num; i++) {
bssl::UniquePtr<X509_NAME> name(sk_X509_NAME_value(to_append.get(), i));
sk_X509_NAME_set(to_append.get(), i, nullptr);
if (i + 1 < num &&
X509_NAME_cmp(name.get(), sk_X509_NAME_value(to_append.get(), i + 1)) ==
0) {
continue;
}
if (!bssl::PushToStack(out, std::move(name))) {
return 0;
}
}
// Sort |out| one last time, to preserve the historical behavior of
// maintaining the sorted list.
sk_X509_NAME_sort(out);
return 1;
}
int SSL_add_bio_cert_subjects_to_stack(STACK_OF(X509_NAME) *out, BIO *bio) {
return add_bio_cert_subjects_to_stack(out, bio, /*allow_empty=*/true);
}
STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file) {
bssl::UniquePtr<BIO> in(BIO_new_file(file, "rb"));
if (in == nullptr) {
return nullptr;
}
bssl::UniquePtr<STACK_OF(X509_NAME)> ret(sk_X509_NAME_new_null());
if (ret == nullptr || //
!add_bio_cert_subjects_to_stack(ret.get(), in.get(),
/*allow_empty=*/false)) {
return nullptr;
}
return ret.release();
}
int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *out,
const char *file) {
bssl::UniquePtr<BIO> in(BIO_new_file(file, "rb"));
if (in == nullptr) {
return 0;
}
return SSL_add_bio_cert_subjects_to_stack(out, in.get());
}
int SSL_use_certificate_file(SSL *ssl, const char *file, int type) {
bssl::UniquePtr<BIO> in(BIO_new_file(file, "rb"));
if (in == nullptr) {
OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
return 0;
}
int reason_code;
bssl::UniquePtr<X509> x;
if (type == SSL_FILETYPE_ASN1) {
reason_code = ERR_R_ASN1_LIB;
x.reset(d2i_X509_bio(in.get(), nullptr));
} else if (type == SSL_FILETYPE_PEM) {
reason_code = ERR_R_PEM_LIB;
x.reset(PEM_read_bio_X509(in.get(), nullptr,
ssl->ctx->default_passwd_callback,
ssl->ctx->default_passwd_callback_userdata));
} else {
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
return 0;
}
if (x == nullptr) {
OPENSSL_PUT_ERROR(SSL, reason_code);
return 0;
}
return SSL_use_certificate(ssl, x.get());
}
int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type) {
bssl::UniquePtr<BIO> in(BIO_new_file(file, "rb"));
if (in == nullptr) {
OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
return 0;
}
int reason_code;
bssl::UniquePtr<RSA> rsa;
if (type == SSL_FILETYPE_ASN1) {
reason_code = ERR_R_ASN1_LIB;
rsa.reset(d2i_RSAPrivateKey_bio(in.get(), nullptr));
} else if (type == SSL_FILETYPE_PEM) {
reason_code = ERR_R_PEM_LIB;
rsa.reset(PEM_read_bio_RSAPrivateKey(
in.get(), nullptr, ssl->ctx->default_passwd_callback,
ssl->ctx->default_passwd_callback_userdata));
} else {
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
return 0;
}
if (rsa == nullptr) {
OPENSSL_PUT_ERROR(SSL, reason_code);
return 0;
}
return SSL_use_RSAPrivateKey(ssl, rsa.get());
}
int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type) {
bssl::UniquePtr<BIO> in(BIO_new_file(file, "rb"));
if (in == nullptr) {
OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
return 0;
}
int reason_code;
bssl::UniquePtr<EVP_PKEY> pkey;
if (type == SSL_FILETYPE_PEM) {
reason_code = ERR_R_PEM_LIB;
pkey.reset(PEM_read_bio_PrivateKey(
in.get(), nullptr, ssl->ctx->default_passwd_callback,
ssl->ctx->default_passwd_callback_userdata));
} else if (type == SSL_FILETYPE_ASN1) {
reason_code = ERR_R_ASN1_LIB;
pkey.reset(d2i_PrivateKey_bio(in.get(), nullptr));
} else {
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
return 0;
}
if (pkey == nullptr) {
OPENSSL_PUT_ERROR(SSL, reason_code);
return 0;
}
return SSL_use_PrivateKey(ssl, pkey.get());
}
int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type) {
bssl::UniquePtr<BIO> in(BIO_new_file(file, "rb"));
if (in == nullptr) {
OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
return 0;
}
int reason_code;
bssl::UniquePtr<X509> x;
if (type == SSL_FILETYPE_ASN1) {
reason_code = ERR_R_ASN1_LIB;
x.reset(d2i_X509_bio(in.get(), nullptr));
} else if (type == SSL_FILETYPE_PEM) {
reason_code = ERR_R_PEM_LIB;
x.reset(PEM_read_bio_X509(in.get(), nullptr, ctx->default_passwd_callback,
ctx->default_passwd_callback_userdata));
} else {
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
return 0;
}
if (x == nullptr) {
OPENSSL_PUT_ERROR(SSL, reason_code);
return 0;
}
return SSL_CTX_use_certificate(ctx, x.get());
}
int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type) {
bssl::UniquePtr<BIO> in(BIO_new_file(file, "rb"));
if (in == nullptr) {
OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
return 0;
}
int reason_code;
bssl::UniquePtr<RSA> rsa;
if (type == SSL_FILETYPE_ASN1) {
reason_code = ERR_R_ASN1_LIB;
rsa.reset(d2i_RSAPrivateKey_bio(in.get(), nullptr));
} else if (type == SSL_FILETYPE_PEM) {
reason_code = ERR_R_PEM_LIB;
rsa.reset(PEM_read_bio_RSAPrivateKey(
in.get(), nullptr, ctx->default_passwd_callback,
ctx->default_passwd_callback_userdata));
} else {
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
return 0;
}
if (rsa == nullptr) {
OPENSSL_PUT_ERROR(SSL, reason_code);
return 0;
}
return SSL_CTX_use_RSAPrivateKey(ctx, rsa.get());
}
int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) {
bssl::UniquePtr<BIO> in(BIO_new_file(file, "rb"));
if (in == nullptr) {
OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
return 0;
}
int reason_code;
bssl::UniquePtr<EVP_PKEY> pkey;
if (type == SSL_FILETYPE_PEM) {
reason_code = ERR_R_PEM_LIB;
pkey.reset(PEM_read_bio_PrivateKey(in.get(), nullptr,
ctx->default_passwd_callback,
ctx->default_passwd_callback_userdata));
} else if (type == SSL_FILETYPE_ASN1) {
reason_code = ERR_R_ASN1_LIB;
pkey.reset(d2i_PrivateKey_bio(in.get(), nullptr));
} else {
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SSL_FILETYPE);
return 0;
}
if (pkey == nullptr) {
OPENSSL_PUT_ERROR(SSL, reason_code);
return 0;
}
return SSL_CTX_use_PrivateKey(ctx, pkey.get());
}
// Read a file that contains our certificate in "PEM" format, possibly followed
// by a sequence of CA certificates that should be sent to the peer in the
// Certificate message.
int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) {
bssl::UniquePtr<BIO> in(BIO_new_file(file, "rb"));
if (in == nullptr) {
OPENSSL_PUT_ERROR(SSL, ERR_R_BUF_LIB);
return 0;
}
bssl::UniquePtr<X509> x(
PEM_read_bio_X509_AUX(in.get(), nullptr, ctx->default_passwd_callback,
ctx->default_passwd_callback_userdata));
if (x == nullptr) {
OPENSSL_PUT_ERROR(SSL, ERR_R_PEM_LIB);
return 0;
}
if (!SSL_CTX_use_certificate(ctx, x.get())) {
return 0;
}
// If we could set up our certificate, now proceed to the CA certificates.
SSL_CTX_clear_chain_certs(ctx);
for (;;) {
bssl::UniquePtr<X509> ca(
PEM_read_bio_X509(in.get(), nullptr, ctx->default_passwd_callback,
ctx->default_passwd_callback_userdata));
if (ca == nullptr) {
break;
}
if (!SSL_CTX_add1_chain_cert(ctx, ca.get())) {
return 0;
}
}
// When the while loop ends, it's usually just EOF.
if (ERR_equals(ERR_peek_last_error(), ERR_LIB_PEM, PEM_R_NO_START_LINE)) {
ERR_clear_error();
return 1;
}
return 0; // Some real error.
}
void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb) {
ctx->default_passwd_callback = cb;
}
pem_password_cb *SSL_CTX_get_default_passwd_cb(const SSL_CTX *ctx) {
return ctx->default_passwd_callback;
}
void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *data) {
ctx->default_passwd_callback_userdata = data;
}
void *SSL_CTX_get_default_passwd_cb_userdata(const SSL_CTX *ctx) {
return ctx->default_passwd_callback_userdata;
}