blob: ce9b01d20c0f3294cbe5e1916331bf350c3efc64 [file] [log] [blame] [edit]
// 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 <ctype.h>
#include <limits.h>
#include <string.h>
#include <utility>
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/buf.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/obj.h>
#include <openssl/stack.h>
#include <openssl/x509.h>
#include "../asn1/internal.h"
#include "../bytestring/internal.h"
#include "../internal.h"
#include "../mem_internal.h"
#include "internal.h"
// X509_NAME_MAX is the length of the maximum encoded |X509_NAME| we accept.
#define X509_NAME_MAX (1024 * 1024)
static int asn1_marshal_string_canon(CBB *cbb, const ASN1_STRING *in);
X509_NAME_ENTRY *X509_NAME_ENTRY_new(void) {
bssl::UniquePtr<X509_NAME_ENTRY> ret = bssl::MakeUnique<X509_NAME_ENTRY>();
if (ret == nullptr) {
return nullptr;
}
ret->object = const_cast<ASN1_OBJECT *>(OBJ_get_undef());
asn1_string_init(&ret->value, -1);
ret->set = 0;
return ret.release();
}
void X509_NAME_ENTRY_free(X509_NAME_ENTRY *entry) {
if (entry != nullptr) {
ASN1_OBJECT_free(entry->object);
asn1_string_cleanup(&entry->value);
OPENSSL_free(entry);
}
}
static int x509_parse_name_entry(CBS *cbs, X509_NAME_ENTRY *out) {
CBS seq;
if (!CBS_get_asn1(cbs, &seq, CBS_ASN1_SEQUENCE)) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
return 0;
}
ASN1_OBJECT_free(out->object);
out->object = asn1_parse_object(&seq, /*tag=*/0);
if (out->object == nullptr || //
!asn1_parse_any_as_string(&seq, &out->value) || //
CBS_len(&seq) != 0) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
return 0;
}
return 1;
}
static int x509_marshal_name_entry(CBB *cbb, const X509_NAME_ENTRY *entry,
int canonicalize) {
CBB seq;
if (!CBB_add_asn1(cbb, &seq, CBS_ASN1_SEQUENCE) ||
!asn1_marshal_object(&seq, entry->object, /*tag=*/0)) {
return 0;
}
int ok = canonicalize ? asn1_marshal_string_canon(&seq, &entry->value)
: asn1_marshal_any_string(&seq, &entry->value);
if (!ok) {
return 0;
}
return CBB_flush(cbb);
}
static int i2d_x509_name_entry(const X509_NAME_ENTRY *entry, uint8_t **out) {
return bssl::I2DFromCBB(/*initial_capacity=*/16, out, [&](CBB *cbb) -> bool {
return x509_marshal_name_entry(cbb, entry, /*canonicalize=*/0);
});
}
IMPLEMENT_EXTERN_ASN1_SIMPLE(X509_NAME_ENTRY, X509_NAME_ENTRY_new,
X509_NAME_ENTRY_free, CBS_ASN1_SEQUENCE,
x509_parse_name_entry, i2d_x509_name_entry)
X509_NAME_ENTRY *X509_NAME_ENTRY_dup(const X509_NAME_ENTRY *entry) {
bssl::ScopedCBB cbb;
if (!CBB_init(cbb.get(), 16) ||
!x509_marshal_name_entry(cbb.get(), entry, /*canonicalize=*/0)) {
return nullptr;
}
CBS cbs;
CBS_init(&cbs, CBB_data(cbb.get()), CBB_len(cbb.get()));
bssl::UniquePtr<X509_NAME_ENTRY> copy(X509_NAME_ENTRY_new());
if (copy == nullptr || !x509_parse_name_entry(&cbs, copy.get())) {
return nullptr;
}
return copy.release();
}
static void x509_name_cache_free(X509_NAME_CACHE *cache) {
if (cache != nullptr) {
OPENSSL_free(cache->canon);
OPENSSL_free(cache->der);
OPENSSL_free(cache);
}
}
void x509_name_init(X509_NAME *name) {
OPENSSL_memset(name, 0, sizeof(X509_NAME));
}
void x509_name_cleanup(X509_NAME *name) {
sk_X509_NAME_ENTRY_pop_free(name->entries, X509_NAME_ENTRY_free);
x509_name_cache_free(name->cache.exchange(nullptr));
}
X509_NAME *X509_NAME_new(void) {
return static_cast<X509_NAME *>(OPENSSL_zalloc(sizeof(X509_NAME)));
}
void X509_NAME_free(X509_NAME *name) {
if (name != nullptr) {
x509_name_cleanup(name);
OPENSSL_free(name);
}
}
int x509_parse_name(CBS *cbs, X509_NAME *out) {
// Reset the old state.
x509_name_cleanup(out);
x509_name_init(out);
out->entries = sk_X509_NAME_ENTRY_new_null();
if (out->entries == nullptr) {
return 0;
}
CBS seq, rdn;
if (!CBS_get_asn1(cbs, &seq, CBS_ASN1_SEQUENCE) ||
// Bound the size of an X509_NAME we are willing to parse.
CBS_len(&seq) > X509_NAME_MAX) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
return 0;
}
static_assert(X509_NAME_MAX <= INT_MAX, "set may overflow");
for (int set = 0; CBS_len(&seq) > 0; set++) {
if (!CBS_get_asn1(&seq, &rdn, CBS_ASN1_SET) || //
CBS_len(&rdn) == 0) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
return 0;
}
while (CBS_len(&rdn) != 0) {
bssl::UniquePtr<X509_NAME_ENTRY> entry(X509_NAME_ENTRY_new());
if (entry == nullptr || !x509_parse_name_entry(&rdn, entry.get())) {
return 0;
}
entry->set = set;
if (!bssl::PushToStack(out->entries, std::move(entry))) {
return 0;
}
}
}
// While we are single-threaded, also fill in the cached state.
return x509_name_get_cache(out) != nullptr;
}
static int x509_marshal_name_entries(CBB *out, const X509_NAME *name,
int canonicalize) {
if (sk_X509_NAME_ENTRY_num(name->entries) == 0) {
return 1;
}
// Bootstrap the first RDN.
int set = sk_X509_NAME_ENTRY_value(name->entries, 0)->set;
CBB rdn;
if (!CBB_add_asn1(out, &rdn, CBS_ASN1_SET)) {
return 0;
}
for (const X509_NAME_ENTRY *entry : name->entries) {
if (entry->set != set) {
// Flush the previous RDN and start a new one.
if (!CBB_flush_asn1_set_of(&rdn) ||
!CBB_add_asn1(out, &rdn, CBS_ASN1_SET)) {
return 0;
}
set = entry->set;
}
if (!x509_marshal_name_entry(&rdn, entry, canonicalize)) {
return 0;
}
}
return CBB_flush_asn1_set_of(&rdn) && CBB_flush(out);
}
const X509_NAME_CACHE *x509_name_get_cache(const X509_NAME *name) {
const X509_NAME_CACHE *cache = name->cache.load();
if (cache != nullptr) {
return cache;
}
X509_NAME_CACHE *new_cache =
static_cast<X509_NAME_CACHE *>(OPENSSL_zalloc(sizeof(X509_NAME_CACHE)));
// Cache the DER encoding, including the outer TLV.
bssl::ScopedCBB cbb;
CBB seq;
if (!CBB_init(cbb.get(), 16) ||
!CBB_add_asn1(cbb.get(), &seq, CBS_ASN1_SEQUENCE) ||
!x509_marshal_name_entries(&seq, name, /*canonicalize=*/0) ||
!CBB_finish(cbb.get(), &new_cache->der, &new_cache->der_len)) {
x509_name_cache_free(new_cache);
return 0;
}
// Cache the canonicalized form, without the outer TLV.
if (!CBB_init(cbb.get(), 16) ||
!x509_marshal_name_entries(cbb.get(), name, /*canonicalize=*/1) ||
!CBB_finish(cbb.get(), &new_cache->canon, &new_cache->canon_len)) {
x509_name_cache_free(new_cache);
return 0;
}
X509_NAME_CACHE *expected = nullptr;
if (name->cache.compare_exchange_strong(expected, new_cache)) {
// We won the race. |name| now owns |new_cache|.
return new_cache;
}
// Some other thread installed a (presumably identical) cache. Release the one
// we made and return the winning one.
assert(expected != nullptr);
x509_name_cache_free(new_cache);
return expected;
}
void x509_name_invalidate_cache(X509_NAME *name) {
x509_name_cache_free(name->cache.exchange(nullptr));
}
int x509_marshal_name(CBB *out, const X509_NAME *in) {
const X509_NAME_CACHE *cache = x509_name_get_cache(in);
if (cache == nullptr) {
return 0;
}
return CBB_add_bytes(out, cache->der, cache->der_len);
}
int x509_name_copy(X509_NAME *dst, const X509_NAME *src) {
const X509_NAME_CACHE *cache = x509_name_get_cache(src);
if (cache == nullptr) {
return 0;
}
// Callers sometimes try to set a name back to itself. We check this after
// |x509_name_get_cache| because, if |src| was so broken that it could not be
// serialized, we used to return an error. (It's not clear if this codepath is
// even possible.)
if (dst == src) {
return 1;
}
CBS cbs;
CBS_init(&cbs, cache->der, cache->der_len);
if (!x509_parse_name(&cbs, dst)) {
return 0;
}
assert(CBS_len(&cbs) == 0);
return 1;
}
X509_NAME *X509_NAME_dup(const X509_NAME *name) {
bssl::UniquePtr<X509_NAME> copy(X509_NAME_new());
if (copy == nullptr || !x509_name_copy(copy.get(), name)) {
return nullptr;
}
return copy.release();
}
X509_NAME *d2i_X509_NAME(X509_NAME **out, const uint8_t **inp, long len) {
return bssl::D2IFromCBS(
out, inp, len, [](CBS *cbs) -> bssl::UniquePtr<X509_NAME> {
bssl::UniquePtr<X509_NAME> name(X509_NAME_new());
if (name == nullptr || !x509_parse_name(cbs, name.get())) {
return nullptr;
}
return name;
});
}
int i2d_X509_NAME(const X509_NAME *in, uint8_t **outp) {
if (in == nullptr) {
OPENSSL_PUT_ERROR(X509, ERR_R_PASSED_NULL_PARAMETER);
return -1;
}
const X509_NAME_CACHE *cache = x509_name_get_cache(in);
if (cache == nullptr) {
return -1;
}
if (cache->der_len > INT_MAX) {
OPENSSL_PUT_ERROR(X509, ERR_R_OVERFLOW);
return -1;
}
int len = static_cast<int>(cache->der_len);
if (outp == nullptr) {
return len;
}
if (*outp == nullptr) {
*outp = static_cast<uint8_t*>(OPENSSL_memdup(cache->der, cache->der_len));
return *outp != nullptr ? len : -1;
}
OPENSSL_memcpy(*outp, cache->der, cache->der_len);
*outp += cache->der_len;
return len;
}
IMPLEMENT_EXTERN_ASN1_SIMPLE(X509_NAME, X509_NAME_new, X509_NAME_free,
CBS_ASN1_SEQUENCE, x509_parse_name, i2d_X509_NAME)
static int asn1_marshal_string_canon(CBB *cbb, const ASN1_STRING *in) {
int (*decode_func)(CBS *, uint32_t *);
int error;
switch (in->type) {
case V_ASN1_UTF8STRING:
decode_func = CBS_get_utf8;
error = ASN1_R_INVALID_UTF8STRING;
break;
case V_ASN1_BMPSTRING:
decode_func = CBS_get_ucs2_be;
error = ASN1_R_INVALID_BMPSTRING;
break;
case V_ASN1_UNIVERSALSTRING:
decode_func = CBS_get_utf32_be;
error = ASN1_R_INVALID_UNIVERSALSTRING;
break;
case V_ASN1_PRINTABLESTRING:
case V_ASN1_T61STRING:
case V_ASN1_IA5STRING:
case V_ASN1_VISIBLESTRING:
decode_func = CBS_get_latin1;
error = ERR_R_INTERNAL_ERROR; // Latin-1 inputs are never invalid.
break;
default:
// Other string types are not canonicalized.
return asn1_marshal_any_string(cbb, in);
}
CBB child;
if (!CBB_add_asn1(cbb, &child, CBS_ASN1_UTF8STRING)) {
return 0;
}
bool empty = true;
bool in_whitespace = false;
CBS cbs;
CBS_init(&cbs, in->data, in->length);
while (CBS_len(&cbs) != 0) {
uint32_t c;
if (!decode_func(&cbs, &c)) {
OPENSSL_PUT_ERROR(ASN1, error);
return 0;
}
if (OPENSSL_isspace(c)) {
if (empty) {
continue; // Trim leading whitespace.
}
in_whitespace = true;
} else {
if (in_whitespace) {
// Collapse the previous run of whitespace into one space.
if (!CBB_add_u8(&child, ' ')) {
return 0;
}
}
in_whitespace = false;
// Lowecase ASCII codepoints.
if (c <= 0x7f) {
c = OPENSSL_tolower(c);
}
if (!CBB_add_utf8(&child, c)) {
return 0;
}
empty = false;
}
}
return CBB_flush(cbb);
}
int X509_NAME_set(X509_NAME **xn, const X509_NAME *name) {
bssl::UniquePtr<X509_NAME> copy(X509_NAME_dup(name));
if (copy == nullptr) {
return 0;
}
X509_NAME_free(*xn);
*xn = copy.release();
return 1;
}
int X509_NAME_ENTRY_set(const X509_NAME_ENTRY *ne) { return ne->set; }
int X509_NAME_get0_der(const X509_NAME *nm, const unsigned char **out_der,
size_t *out_der_len) {
const X509_NAME_CACHE *cache = x509_name_get_cache(nm);
if (cache == nullptr) {
return 0;
}
if (out_der != nullptr) {
*out_der = cache->der;
}
if (out_der_len != nullptr) {
*out_der_len = cache->der_len;
}
return 1;
}