Packages
hackney
2.0.1
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/crypto/pem/pem_info.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/pem.h>
#include <limits.h>
#include <string.h>
#include <string_view>
#include <openssl/dsa.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/mem.h>
#include <openssl/obj.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include "internal.h"
static X509_PKEY *X509_PKEY_new(void) {
return reinterpret_cast<X509_PKEY *>(OPENSSL_zalloc(sizeof(X509_PKEY)));
}
static void X509_PKEY_free(X509_PKEY *x) {
if (x == nullptr) {
return;
}
EVP_PKEY_free(x->dec_pkey);
OPENSSL_free(x);
}
static X509_INFO *X509_INFO_new(void) {
return reinterpret_cast<X509_INFO *>(OPENSSL_zalloc(sizeof(X509_INFO)));
}
void X509_INFO_free(X509_INFO *x) {
if (x == nullptr) {
return;
}
X509_free(x->x509);
X509_CRL_free(x->crl);
X509_PKEY_free(x->x_pkey);
OPENSSL_free(x->enc_data);
OPENSSL_free(x);
}
STACK_OF(X509_INFO) *PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk,
pem_password_cb *cb, void *u) {
BIO *b = BIO_new_fp(fp, BIO_NOCLOSE);
if (b == nullptr) {
OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB);
return nullptr;
}
STACK_OF(X509_INFO) *ret = PEM_X509_INFO_read_bio(b, sk, cb, u);
BIO_free(b);
return ret;
}
enum parse_result_t {
parse_ok,
parse_error,
parse_new_entry,
};
static enum parse_result_t parse_x509(X509_INFO *info, const uint8_t *data,
size_t len, int key_type) {
if (info->x509 != nullptr) {
return parse_new_entry;
}
info->x509 = d2i_X509(nullptr, &data, len);
return info->x509 != nullptr ? parse_ok : parse_error;
}
static enum parse_result_t parse_x509_aux(X509_INFO *info, const uint8_t *data,
size_t len, int key_type) {
if (info->x509 != nullptr) {
return parse_new_entry;
}
info->x509 = d2i_X509_AUX(nullptr, &data, len);
return info->x509 != nullptr ? parse_ok : parse_error;
}
static enum parse_result_t parse_crl(X509_INFO *info, const uint8_t *data,
size_t len, int key_type) {
if (info->crl != nullptr) {
return parse_new_entry;
}
info->crl = d2i_X509_CRL(nullptr, &data, len);
return info->crl != nullptr ? parse_ok : parse_error;
}
static enum parse_result_t parse_key(X509_INFO *info, const uint8_t *data,
size_t len, int key_type) {
if (info->x_pkey != nullptr) {
return parse_new_entry;
}
info->x_pkey = X509_PKEY_new();
if (info->x_pkey == nullptr) {
return parse_error;
}
info->x_pkey->dec_pkey = d2i_PrivateKey(key_type, nullptr, &data, len);
return info->x_pkey->dec_pkey != nullptr ? parse_ok : parse_error;
}
STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk,
pem_password_cb *cb, void *u) {
X509_INFO *info = nullptr;
bssl::UniquePtr<char> name;
bssl::UniquePtr<char> header;
bssl::Array<uint8_t> data;
int ok = 0;
STACK_OF(X509_INFO) *ret = nullptr;
if (sk == nullptr) {
ret = sk_X509_INFO_new_null();
if (ret == nullptr) {
return nullptr;
}
} else {
ret = sk;
}
size_t orig_num = sk_X509_INFO_num(ret);
info = X509_INFO_new();
if (info == nullptr) {
goto err;
}
for (;;) {
if (!PEM_read_bio_inner(bp, &name, &header, &data)) {
if (ERR_equals(ERR_peek_last_error(), ERR_LIB_PEM, PEM_R_NO_START_LINE)) {
ERR_clear_error();
break;
}
goto err;
}
enum parse_result_t (*parse_function)(X509_INFO *, const uint8_t *, size_t,
int) = nullptr;
int key_type = EVP_PKEY_NONE;
std::string_view name_view = name.get();
if (name_view == PEM_STRING_X509 || name_view == PEM_STRING_X509_OLD) {
parse_function = parse_x509;
} else if (name_view == PEM_STRING_X509_TRUSTED) {
parse_function = parse_x509_aux;
} else if (name_view == PEM_STRING_X509_CRL) {
parse_function = parse_crl;
} else if (name_view == PEM_STRING_RSA) {
parse_function = parse_key;
key_type = EVP_PKEY_RSA;
} else if (name_view == PEM_STRING_DSA) {
parse_function = parse_key;
key_type = EVP_PKEY_DSA;
} else if (name_view == PEM_STRING_ECPRIVATEKEY) {
parse_function = parse_key;
key_type = EVP_PKEY_EC;
}
// If a private key has a header, assume it is encrypted. This function does
// not decrypt private keys.
if (key_type != EVP_PKEY_NONE && strlen(header.get()) > 10) {
if (data.size() > INT_MAX) {
// We need the data to fit in |info| which forces the size to
// fit in one int type.
goto err;
}
if (info->x_pkey != nullptr) {
if (!sk_X509_INFO_push(ret, info)) {
goto err;
}
info = X509_INFO_new();
if (info == nullptr) {
goto err;
}
}
// Use an empty key as a placeholder.
info->x_pkey = X509_PKEY_new();
if (info->x_pkey == nullptr ||
!PEM_get_EVP_CIPHER_INFO(header.get(), &info->enc_cipher)) {
goto err;
}
size_t size;
data.Release(reinterpret_cast<uint8_t **>(&info->enc_data), &size);
// Safety: we checked that |size| <= |INT_MAX|.
info->enc_len = static_cast<int>(size);
} else if (parse_function != nullptr) {
EVP_CIPHER_INFO cipher;
size_t len = data.size();
if (!PEM_get_EVP_CIPHER_INFO(header.get(), &cipher) ||
!PEM_do_header(&cipher, data.data(), &len, cb, u)) {
goto err;
}
enum parse_result_t result =
parse_function(info, data.data(), len, key_type);
if (result == parse_new_entry) {
if (!sk_X509_INFO_push(ret, info)) {
goto err;
}
info = X509_INFO_new();
if (info == nullptr) {
goto err;
}
result = parse_function(info, data.data(), len, key_type);
}
if (result != parse_ok) {
OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB);
goto err;
}
}
}
// Push the last entry on the stack if not empty.
if (info->x509 != nullptr || info->crl != nullptr ||
info->x_pkey != nullptr || info->enc_data != nullptr) {
if (!sk_X509_INFO_push(ret, info)) {
goto err;
}
info = nullptr;
}
ok = 1;
err:
X509_INFO_free(info);
if (!ok) {
while (sk_X509_INFO_num(ret) > orig_num) {
X509_INFO_free(sk_X509_INFO_pop(ret));
}
if (ret != sk) {
sk_X509_INFO_free(ret);
}
ret = nullptr;
}
return ret;
}