| /* Copyright (c) 2023, Google Inc. |
| * |
| * Permission to use, copy, modify, and/or distribute this software for any |
| * purpose with or without fee is hereby granted, provided that the above |
| * copyright notice and this permission notice appear in all copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
| * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
| * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ |
| |
| #include <optional> |
| #include <string_view> |
| |
| #include <openssl/pki/certificate.h> |
| #include <openssl/pool.h> |
| |
| #include "cert_errors.h" |
| #include "encode_values.h" |
| #include "parsed_certificate.h" |
| #include "pem.h" |
| #include "parse_values.h" |
| |
| namespace bssl { |
| |
| namespace { |
| |
| std::shared_ptr<const bssl::ParsedCertificate> ParseCertificateFromDer( |
| bssl::Span<const uint8_t>cert, std::string *out_diagnostic) { |
| bssl::ParseCertificateOptions default_options{}; |
| // We follow Chromium in setting |allow_invalid_serial_numbers| in order to |
| // not choke on 21-byte serial numbers, which are common. davidben explains |
| // why: |
| // |
| // The reason for the discrepancy is that unsigned numbers with the high bit |
| // otherwise set get an extra 0 byte in front to keep them positive. So if you |
| // do: |
| // var num [20]byte |
| // fillWithRandom(num[:]) |
| // serialNumber := new(big.Int).SetBytes(num[:]) |
| // encodeASN1Integer(serialNumber) |
| // |
| // Then half of your serial numbers will be encoded with 21 bytes. (And |
| // 1/512th will have 19 bytes instead of 20.) |
| default_options.allow_invalid_serial_numbers = true; |
| |
| bssl::UniquePtr<CRYPTO_BUFFER> buffer( |
| CRYPTO_BUFFER_new(cert.data(), cert.size(), nullptr)); |
| bssl::CertErrors errors; |
| std::shared_ptr<const bssl::ParsedCertificate> parsed_cert( |
| bssl::ParsedCertificate::Create(std::move(buffer), default_options, &errors)); |
| if (!parsed_cert) { |
| *out_diagnostic = errors.ToDebugString(); |
| return nullptr; |
| } |
| return parsed_cert; |
| } |
| |
| } // namespace |
| |
| struct CertificateInternals { |
| std::shared_ptr<const bssl::ParsedCertificate> cert; |
| }; |
| |
| Certificate::Certificate(std::unique_ptr<CertificateInternals> internals) |
| : internals_(std::move(internals)) {} |
| Certificate::~Certificate() = default; |
| Certificate::Certificate(Certificate&& other) = default; |
| |
| std::unique_ptr<Certificate> Certificate::FromDER(bssl::Span<const uint8_t> der, |
| std::string *out_diagnostic) { |
| std::shared_ptr<const bssl::ParsedCertificate> result = |
| ParseCertificateFromDer(der, out_diagnostic); |
| if (result == nullptr) { |
| return nullptr; |
| } |
| |
| auto internals = std::make_unique<CertificateInternals>(); |
| internals->cert = std::move(result); |
| std::unique_ptr<Certificate> ret(new Certificate(std::move(internals))); |
| return ret; |
| } |
| |
| std::unique_ptr<Certificate> Certificate::FromPEM(std::string_view pem, |
| std::string *out_diagnostic) { |
| bssl::PEMTokenizer tokenizer(pem, {"CERTIFICATE"}); |
| if (!tokenizer.GetNext()) { |
| return nullptr; |
| } |
| return FromDER(StringAsBytes(tokenizer.data()), out_diagnostic); |
| } |
| |
| bool Certificate::IsSelfIssued() const { |
| return internals_->cert->normalized_subject() == |
| internals_->cert->normalized_issuer(); |
| } |
| |
| Certificate::Validity Certificate::GetValidity() const { |
| Certificate::Validity validity; |
| |
| // As this is a previously parsed certificate, we know the not_before |
| // and not after are valid, so these conversions can not fail. |
| (void) GeneralizedTimeToPosixTime( |
| internals_->cert->tbs().validity_not_before, &validity.not_before); |
| (void) GeneralizedTimeToPosixTime( |
| internals_->cert->tbs().validity_not_after, &validity.not_after); |
| return validity; |
| } |
| |
| bssl::Span<const uint8_t> Certificate::GetSerialNumber() const { |
| return internals_->cert->tbs().serial_number; |
| } |
| |
| } // namespace boringssl |