Document most X509_NAME functions.

Unfortunately, these functions are not const-correct, even the
accessors. Document what they should have been, especially since
mutating an X509_NAME_ENTRY directly won't even update the 'modified'
bit correctly.

Do a pass at adding consts to our code internally, but since the
functions return non-const pointers, this isn't checked anywhere. And
since serializing an X509_NAME is not always thread-safe, there's a
limit to how much we can correctly mark things as const.

Bug: 426
Change-Id: Ifa3d8bafb5396fbe7b91416f234de4585284c705
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53326
Reviewed-by: Bob Beck <bbe@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
chromium-5359
David Benjamin 3 years ago committed by Boringssl LUCI CQ
parent 3be30a55b0
commit b6f47e88b0
  1. 8
      crypto/x509/name_print.c
  2. 6
      crypto/x509/x509_vfy.c
  3. 63
      crypto/x509/x509name.c
  4. 19
      crypto/x509v3/v3_ncons.c
  5. 55
      crypto/x509v3/v3_utl.c
  6. 338
      include/openssl/x509.h

@ -86,9 +86,6 @@ static int do_name_ex(BIO *out, const X509_NAME *n, int indent,
unsigned long flags) {
int i, prev = -1, orflags, cnt;
int fn_opt, fn_nid;
ASN1_OBJECT *fn;
ASN1_STRING *val;
X509_NAME_ENTRY *ent;
char objtmp[80];
const char *objbuf;
int outlen, len;
@ -149,6 +146,7 @@ static int do_name_ex(BIO *out, const X509_NAME *n, int indent,
cnt = X509_NAME_entry_count(n);
for (i = 0; i < cnt; i++) {
const X509_NAME_ENTRY *ent;
if (flags & XN_FLAG_DN_REV) {
ent = X509_NAME_get_entry(n, cnt - i - 1);
} else {
@ -172,8 +170,8 @@ static int do_name_ex(BIO *out, const X509_NAME *n, int indent,
}
}
prev = X509_NAME_ENTRY_set(ent);
fn = X509_NAME_ENTRY_get_object(ent);
val = X509_NAME_ENTRY_get_data(ent);
const ASN1_OBJECT *fn = X509_NAME_ENTRY_get_object(ent);
const ASN1_STRING *val = X509_NAME_ENTRY_get_data(ent);
fn_nid = OBJ_obj2nid(fn);
if (fn_opt != XN_FLAG_FN_NONE) {
int objlen, fld_len;

@ -689,7 +689,7 @@ end:
}
static int reject_dns_name_in_common_name(X509 *x509) {
X509_NAME *name = X509_get_subject_name(x509);
const X509_NAME *name = X509_get_subject_name(x509);
int i = -1;
for (;;) {
i = X509_NAME_get_index_by_NID(name, NID_commonName, i);
@ -697,8 +697,8 @@ static int reject_dns_name_in_common_name(X509 *x509) {
return X509_V_OK;
}
X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, i);
ASN1_STRING *common_name = X509_NAME_ENTRY_get_data(entry);
const X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, i);
const ASN1_STRING *common_name = X509_NAME_ENTRY_get_data(entry);
unsigned char *idval;
int idlen = ASN1_STRING_to_UTF8(&idval, common_name);
if (idlen < 0) {

@ -80,14 +80,12 @@ int X509_NAME_get_text_by_NID(const X509_NAME *name, int nid, char *buf,
int X509_NAME_get_text_by_OBJ(const X509_NAME *name, const ASN1_OBJECT *obj,
char *buf, int len) {
int i;
ASN1_STRING *data;
i = X509_NAME_get_index_by_OBJ(name, obj, -1);
int i = X509_NAME_get_index_by_OBJ(name, obj, -1);
if (i < 0) {
return -1;
}
data = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i));
const ASN1_STRING *data =
X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i));
i = (data->length > (len - 1)) ? (len - 1) : data->length;
if (buf == NULL) {
return data->length;
@ -148,51 +146,46 @@ X509_NAME_ENTRY *X509_NAME_get_entry(const X509_NAME *name, int loc) {
}
X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *name, int loc) {
X509_NAME_ENTRY *ret;
int i, n, set_prev, set_next;
STACK_OF(X509_NAME_ENTRY) *sk;
if (name == NULL || loc < 0 ||
sk_X509_NAME_ENTRY_num(name->entries) <= (size_t)loc) {
return NULL;
}
sk = name->entries;
ret = sk_X509_NAME_ENTRY_delete(sk, loc);
n = sk_X509_NAME_ENTRY_num(sk);
STACK_OF(X509_NAME_ENTRY) *sk = name->entries;
X509_NAME_ENTRY *ret = sk_X509_NAME_ENTRY_delete(sk, loc);
int n = sk_X509_NAME_ENTRY_num(sk);
name->modified = 1;
if (loc == n) {
return ret;
}
// else we need to fixup the set field
int set_prev;
if (loc != 0) {
set_prev = (sk_X509_NAME_ENTRY_value(sk, loc - 1))->set;
set_prev = sk_X509_NAME_ENTRY_value(sk, loc - 1)->set;
} else {
set_prev = ret->set - 1;
}
set_next = sk_X509_NAME_ENTRY_value(sk, loc)->set;
int set_next = sk_X509_NAME_ENTRY_value(sk, loc)->set;
// set_prev is the previous set set is the current set set_next is the
// following prev 1 1 1 1 1 1 1 1 set 1 1 2 2 next 1 1 2 2 2 2 3 2 so
// basically only if prev and next differ by 2, then re-number down by 1
// If we removed a singleton RDN, update the RDN indices so they are
// consecutive again.
if (set_prev + 1 < set_next) {
for (i = loc; i < n; i++) {
for (int i = loc; i < n; i++) {
sk_X509_NAME_ENTRY_value(sk, i)->set--;
}
}
return ret;
}
int X509_NAME_add_entry_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj, int type,
const unsigned char *bytes, int len, int loc,
int set) {
X509_NAME_ENTRY *ne;
int ret;
ne = X509_NAME_ENTRY_create_by_OBJ(NULL, obj, type, bytes, len);
int X509_NAME_add_entry_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj,
int type, const unsigned char *bytes, int len,
int loc, int set) {
X509_NAME_ENTRY *ne =
X509_NAME_ENTRY_create_by_OBJ(NULL, obj, type, bytes, len);
if (!ne) {
return 0;
}
ret = X509_NAME_add_entry(name, ne, loc, set);
int ret = X509_NAME_add_entry(name, ne, loc, set);
X509_NAME_ENTRY_free(ne);
return ret;
}
@ -200,13 +193,12 @@ int X509_NAME_add_entry_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj, int type,
int X509_NAME_add_entry_by_NID(X509_NAME *name, int nid, int type,
const unsigned char *bytes, int len, int loc,
int set) {
X509_NAME_ENTRY *ne;
int ret;
ne = X509_NAME_ENTRY_create_by_NID(NULL, nid, type, bytes, len);
X509_NAME_ENTRY *ne =
X509_NAME_ENTRY_create_by_NID(NULL, nid, type, bytes, len);
if (!ne) {
return 0;
}
ret = X509_NAME_add_entry(name, ne, loc, set);
int ret = X509_NAME_add_entry(name, ne, loc, set);
X509_NAME_ENTRY_free(ne);
return ret;
}
@ -214,20 +206,19 @@ int X509_NAME_add_entry_by_NID(X509_NAME *name, int nid, int type,
int X509_NAME_add_entry_by_txt(X509_NAME *name, const char *field, int type,
const unsigned char *bytes, int len, int loc,
int set) {
X509_NAME_ENTRY *ne;
int ret;
ne = X509_NAME_ENTRY_create_by_txt(NULL, field, type, bytes, len);
X509_NAME_ENTRY *ne =
X509_NAME_ENTRY_create_by_txt(NULL, field, type, bytes, len);
if (!ne) {
return 0;
}
ret = X509_NAME_add_entry(name, ne, loc, set);
int ret = X509_NAME_add_entry(name, ne, loc, set);
X509_NAME_ENTRY_free(ne);
return ret;
}
// if set is -1, append to previous set, 0 'a new one', and 1, prepend to the
// guy we are about to stomp on.
int X509_NAME_add_entry(X509_NAME *name, X509_NAME_ENTRY *ne, int loc,
int X509_NAME_add_entry(X509_NAME *name, const X509_NAME_ENTRY *entry, int loc,
int set) {
X509_NAME_ENTRY *new_name = NULL;
int n, i, inc;
@ -267,7 +258,7 @@ int X509_NAME_add_entry(X509_NAME *name, X509_NAME_ENTRY *ne, int loc,
}
}
if ((new_name = X509_NAME_ENTRY_dup(ne)) == NULL) {
if ((new_name = X509_NAME_ENTRY_dup(entry)) == NULL) {
goto err;
}
new_name->set = set;

@ -76,14 +76,14 @@ static int i2r_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, void *a,
static int do_i2r_name_constraints(const X509V3_EXT_METHOD *method,
STACK_OF(GENERAL_SUBTREE) *trees, BIO *bp,
int ind, const char *name);
static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip);
static int print_nc_ipadd(BIO *bp, const ASN1_OCTET_STRING *ip);
static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc);
static int nc_match_single(GENERAL_NAME *sub, GENERAL_NAME *gen);
static int nc_dn(X509_NAME *sub, X509_NAME *nm);
static int nc_dns(ASN1_IA5STRING *sub, ASN1_IA5STRING *dns);
static int nc_email(ASN1_IA5STRING *sub, ASN1_IA5STRING *eml);
static int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base);
static int nc_dns(const ASN1_IA5STRING *sub, const ASN1_IA5STRING *dns);
static int nc_email(const ASN1_IA5STRING *sub, const ASN1_IA5STRING *eml);
static int nc_uri(const ASN1_IA5STRING *uri, const ASN1_IA5STRING *base);
const X509V3_EXT_METHOD v3_name_constraints = {
NID_name_constraints,
@ -196,7 +196,7 @@ static int do_i2r_name_constraints(const X509V3_EXT_METHOD *method,
return 1;
}
static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip) {
static int print_nc_ipadd(BIO *bp, const ASN1_OCTET_STRING *ip) {
int i, len;
unsigned char *p;
p = ip->data;
@ -273,12 +273,11 @@ int NAME_CONSTRAINTS_check(X509 *x, NAME_CONSTRAINTS *nc) {
// Process any email address attributes in subject name
for (i = -1;;) {
X509_NAME_ENTRY *ne;
i = X509_NAME_get_index_by_NID(nm, NID_pkcs9_emailAddress, i);
if (i == -1) {
break;
}
ne = X509_NAME_get_entry(nm, i);
const X509_NAME_ENTRY *ne = X509_NAME_get_entry(nm, i);
gntmp.d.rfc822Name = X509_NAME_ENTRY_get_data(ne);
if (gntmp.d.rfc822Name->type != V_ASN1_IA5STRING) {
return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
@ -429,7 +428,7 @@ static int has_suffix_case(const CBS *a, const CBS *b) {
return equal_case(&copy, b);
}
static int nc_dns(ASN1_IA5STRING *dns, ASN1_IA5STRING *base) {
static int nc_dns(const ASN1_IA5STRING *dns, const ASN1_IA5STRING *base) {
CBS dns_cbs, base_cbs;
CBS_init(&dns_cbs, dns->data, dns->length);
CBS_init(&base_cbs, base->data, base->length);
@ -465,7 +464,7 @@ static int nc_dns(ASN1_IA5STRING *dns, ASN1_IA5STRING *base) {
return X509_V_OK;
}
static int nc_email(ASN1_IA5STRING *eml, ASN1_IA5STRING *base) {
static int nc_email(const ASN1_IA5STRING *eml, const ASN1_IA5STRING *base) {
CBS eml_cbs, base_cbs;
CBS_init(&eml_cbs, eml->data, eml->length);
CBS_init(&base_cbs, base->data, base->length);
@ -513,7 +512,7 @@ static int nc_email(ASN1_IA5STRING *eml, ASN1_IA5STRING *base) {
return X509_V_OK;
}
static int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base) {
static int nc_uri(const ASN1_IA5STRING *uri, const ASN1_IA5STRING *base) {
CBS uri_cbs, base_cbs;
CBS_init(&uri_cbs, uri->data, uri->length);
CBS_init(&base_cbs, base->data, base->length);

@ -77,10 +77,11 @@
static char *strip_spaces(char *name);
static int sk_strcmp(const char **a, const char **b);
static STACK_OF(OPENSSL_STRING) *get_email(X509_NAME *name,
GENERAL_NAMES *gens);
static STACK_OF(OPENSSL_STRING) *get_email(const X509_NAME *name,
const GENERAL_NAMES *gens);
static void str_free(OPENSSL_STRING str);
static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, ASN1_IA5STRING *email);
static int append_ia5(STACK_OF(OPENSSL_STRING) **sk,
const ASN1_IA5STRING *email);
static int ipv4_from_asc(unsigned char v4[4], const char *in);
static int ipv6_from_asc(unsigned char v6[16], const char *in);
@ -617,27 +618,22 @@ STACK_OF(OPENSSL_STRING) *X509_REQ_get1_email(X509_REQ *x) {
return ret;
}
static STACK_OF(OPENSSL_STRING) *get_email(X509_NAME *name,
GENERAL_NAMES *gens) {
static STACK_OF(OPENSSL_STRING) *get_email(const X509_NAME *name,
const GENERAL_NAMES *gens) {
STACK_OF(OPENSSL_STRING) *ret = NULL;
X509_NAME_ENTRY *ne;
ASN1_IA5STRING *email;
GENERAL_NAME *gen;
int i;
size_t j;
// Now add any email address(es) to STACK
i = -1;
int i = -1;
// First supplied X509_NAME
while ((i = X509_NAME_get_index_by_NID(name, NID_pkcs9_emailAddress, i)) >=
0) {
ne = X509_NAME_get_entry(name, i);
email = X509_NAME_ENTRY_get_data(ne);
const X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, i);
const ASN1_IA5STRING *email = X509_NAME_ENTRY_get_data(ne);
if (!append_ia5(&ret, email)) {
return NULL;
}
}
for (j = 0; j < sk_GENERAL_NAME_num(gens); j++) {
gen = sk_GENERAL_NAME_value(gens, j);
for (size_t j = 0; j < sk_GENERAL_NAME_num(gens); j++) {
const GENERAL_NAME *gen = sk_GENERAL_NAME_value(gens, j);
if (gen->type != GEN_EMAIL) {
continue;
}
@ -650,7 +646,8 @@ static STACK_OF(OPENSSL_STRING) *get_email(X509_NAME *name,
static void str_free(OPENSSL_STRING str) { OPENSSL_free(str); }
static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, ASN1_IA5STRING *email) {
static int append_ia5(STACK_OF(OPENSSL_STRING) **sk,
const ASN1_IA5STRING *email) {
// First some sanity checks
if (email->type != V_ASN1_IA5STRING) {
return 1;
@ -952,7 +949,7 @@ int x509v3_looks_like_dns_name(const unsigned char *in, size_t len) {
// cmp_type > 0 only compare if string matches the type, otherwise convert it
// to UTF8.
static int do_check_string(ASN1_STRING *a, int cmp_type, equal_fn equal,
static int do_check_string(const ASN1_STRING *a, int cmp_type, equal_fn equal,
unsigned int flags, int check_type, const char *b,
size_t blen, char **peername) {
int rv = 0;
@ -997,15 +994,10 @@ static int do_check_string(ASN1_STRING *a, int cmp_type, equal_fn equal,
static int do_x509_check(X509 *x, const char *chk, size_t chklen,
unsigned int flags, int check_type, char **peername) {
GENERAL_NAMES *gens = NULL;
X509_NAME *name = NULL;
size_t i;
int j;
int cnid = NID_undef;
int alt_type;
int rv = 0;
equal_fn equal;
if (check_type == GEN_EMAIL) {
cnid = NID_pkcs9_emailAddress;
alt_type = V_ASN1_IA5STRING;
@ -1023,15 +1015,14 @@ static int do_x509_check(X509 *x, const char *chk, size_t chklen,
equal = equal_case;
}
gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
GENERAL_NAMES *gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
if (gens) {
for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
GENERAL_NAME *gen;
ASN1_STRING *cstr;
gen = sk_GENERAL_NAME_value(gens, i);
for (size_t i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
const GENERAL_NAME *gen = sk_GENERAL_NAME_value(gens, i);
if (gen->type != check_type) {
continue;
}
const ASN1_STRING *cstr;
if (check_type == GEN_EMAIL) {
cstr = gen->d.rfc822Name;
} else if (check_type == GEN_DNS) {
@ -1054,13 +1045,11 @@ static int do_x509_check(X509 *x, const char *chk, size_t chklen,
return 0;
}
j = -1;
name = X509_get_subject_name(x);
int j = -1;
const X509_NAME *name = X509_get_subject_name(x);
while ((j = X509_NAME_get_index_by_NID(name, cnid, j)) >= 0) {
X509_NAME_ENTRY *ne;
ASN1_STRING *str;
ne = X509_NAME_get_entry(name, j);
str = X509_NAME_ENTRY_get_data(ne);
const X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, j);
const ASN1_STRING *str = X509_NAME_ENTRY_get_data(ne);
// Positive on success, negative on error!
if ((rv = do_check_string(str, -1, equal, flags, check_type, chk, chklen,
peername)) != 0) {

@ -711,6 +711,246 @@ OPENSSL_EXPORT int X509_REQ_set1_signature_value(X509_REQ *req,
size_t sig_len);
// Names.
//
// An |X509_NAME| represents an X.509 Name structure (RFC 5280). X.509 names are
// a complex, hierarchical structure over a collection of attributes. Each name
// is sequence of relative distinguished names (RDNs), decreasing in
// specificity. For example, the first RDN may specify the country, while the
// next RDN may specify a locality. Each RDN is, itself, a set of attributes.
// Having more than one attribute in an RDN is uncommon, but possible. Within an
// RDN, attributes have the same level in specificity. Attribute types are
// OBJECT IDENTIFIERs. This determines the ASN.1 type of the value, which is
// commonly a string but may be other types.
//
// The |X509_NAME| representation flattens this two-level structure into a
// single list of attributes. Each attribute is stored in an |X509_NAME_ENTRY|,
// with also maintains the index of the RDN it is part of, accessible via
// |X509_NAME_ENTRY_set|. This can be used to recover the two-level structure.
//
// X.509 names are largely vestigial. Historically, DNS names were parsed out of
// the subject's common name attribute, but this is deprecated and has since
// moved to the subject alternative name extension. In modern usage, X.509 names
// are primarily opaque identifiers to link a certificate with its issuer.
DEFINE_STACK_OF(X509_NAME_ENTRY)
DEFINE_STACK_OF(X509_NAME)
// X509_NAME is an |ASN1_ITEM| whose ASN.1 type is X.509 Name (RFC 5280) and C
// type is |X509_NAME*|.
DECLARE_ASN1_ITEM(X509_NAME)
// X509_NAME_new returns a new, empty |X509_NAME_new|, or NULL on
// error.
OPENSSL_EXPORT X509_NAME *X509_NAME_new(void);
// X509_NAME_free releases memory associated with |name|.
OPENSSL_EXPORT void X509_NAME_free(X509_NAME *name);
// d2i_X509_NAME parses up to |len| bytes from |*inp| as a DER-encoded X.509
// Name (RFC 5280), as described in |d2i_SAMPLE_with_reuse|.
OPENSSL_EXPORT X509_NAME *d2i_X509_NAME(X509_NAME **out, const uint8_t **inp,
long len);
// i2d_X509_NAME marshals |in| as a DER-encoded X.509 Name (RFC 5280), as
// described in |i2d_SAMPLE|.
//
// TODO(https://crbug.com/boringssl/407): This function should be const and
// thread-safe but is currently neither in some cases, notably if |in| was
// mutated.
OPENSSL_EXPORT int i2d_X509_NAME(X509_NAME *in, uint8_t **outp);
// X509_NAME_dup returns a newly-allocated copy of |name|, or NULL on error.
//
// TODO(https://crbug.com/boringssl/407): This function should be const and
// thread-safe but is currently neither in some cases, notably if |name| was
// mutated.
OPENSSL_EXPORT X509_NAME *X509_NAME_dup(X509_NAME *name);
// X509_NAME_get0_der sets |*out_der| and |*out_der_len|
//
// Avoid this function and prefer |i2d_X509_NAME|. It is one of the reasons
// these functions are not consistently thread-safe or const-correct. Depending
// on the resolution of https://crbug.com/boringssl/407, this function may be
// removed or cause poor performance.
OPENSSL_EXPORT int X509_NAME_get0_der(X509_NAME *name, const uint8_t **out_der,
size_t *out_der_len);
// X509_NAME_set makes a copy of |name|. On success, it frees |*xn|, sets |*xn|
// to the copy, and returns one. Otherwise, it returns zero.
//
// TODO(https://crbug.com/boringssl/407): This function should be const and
// thread-safe but is currently neither in some cases, notably if |name| was
// mutated.
OPENSSL_EXPORT int X509_NAME_set(X509_NAME **xn, X509_NAME *name);
// X509_NAME_entry_count returns the number of entries in |name|.
OPENSSL_EXPORT int X509_NAME_entry_count(const X509_NAME *name);
// X509_NAME_get_index_by_NID returns the zero-based index of the first
// attribute in |name| with type |nid|, or -1 if there is none. |nid| should be
// one of the |NID_*| constants. If |lastpos| is non-negative, it begins
// searching at |lastpos+1|. To search all attributes, pass in -1, not zero.
//
// Indices from this function refer to |X509_NAME|'s flattened representation.
OPENSSL_EXPORT int X509_NAME_get_index_by_NID(const X509_NAME *name, int nid,
int lastpos);
// X509_NAME_get_index_by_OBJ behaves like |X509_NAME_get_index_by_NID| but
// looks for attributes with type |obj|.
OPENSSL_EXPORT int X509_NAME_get_index_by_OBJ(const X509_NAME *name,
const ASN1_OBJECT *obj,
int lastpos);
// X509_NAME_get_entry returns the attribute in |name| at index |loc|, or NULL
// if |loc| is out of range. |loc| is interpreted using |X509_NAME|'s flattened
// representation. This function returns a non-const pointer for OpenSSL
// compatibility, but callers should not mutate the result. Doing so will break
// internal invariants in the library.
OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_get_entry(const X509_NAME *name,
int loc);
// X509_NAME_delete_entry removes and returns the attribute in |name| at index
// |loc|, or NULL if |loc| is out of range. |loc| is interpreted using
// |X509_NAME|'s flattened representation. If the attribute is found, the caller
// is responsible for releasing the result with |X509_NAME_ENTRY_free|.
//
// This function will internally update RDN indices (see |X509_NAME_ENTRY_set|)
// so they continue to be consecutive.
OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *name,
int loc);
// X509_NAME_add_entry adds a copy of |entry| to |name| and returns one on
// success or zero on error. If |loc| is -1, the entry is appended to |name|.
// Otherwise, it is inserted at index |loc|. If |set| is -1, the entry is added
// to the previous entry's RDN. If it is 0, the entry becomes a singleton RDN.
// If 1, it is added to next entry's RDN.
//
// This function will internally update RDN indices (see |X509_NAME_ENTRY_set|)
// so they continue to be consecutive.
OPENSSL_EXPORT int X509_NAME_add_entry(X509_NAME *name,
const X509_NAME_ENTRY *entry, int loc,
int set);
// X509_NAME_add_entry_by_OBJ adds a new entry to |name| and returns one on
// success or zero on error. The entry's attribute type is |obj|. The entry's
// attribute value is determined by |type|, |bytes|, and |len|, as in
// |X509_NAME_ENTRY_set_data|. The entry's position is determined by |loc| and
// |set| as in |X509_NAME_entry|.
OPENSSL_EXPORT int X509_NAME_add_entry_by_OBJ(X509_NAME *name,
const ASN1_OBJECT *obj, int type,
const uint8_t *bytes, int len,
int loc, int set);
// X509_NAME_add_entry_by_NID behaves like |X509_NAME_add_entry_by_OBJ| but sets
// the entry's attribute type to |nid|, which should be one of the |NID_*|
// constants.
OPENSSL_EXPORT int X509_NAME_add_entry_by_NID(X509_NAME *name, int nid,
int type, const uint8_t *bytes,
int len, int loc, int set);
// X509_NAME_add_entry_by_txt behaves like |X509_NAME_add_entry_by_OBJ| but sets
// the entry's attribute type to |field|, which is passed to |OBJ_txt2obj|.
OPENSSL_EXPORT int X509_NAME_add_entry_by_txt(X509_NAME *name,
const char *field, int type,
const uint8_t *bytes, int len,
int loc, int set);
// X509_NAME_ENTRY is an |ASN1_ITEM| whose ASN.1 type is AttributeTypeAndValue
// (RFC 5280) and C type is |X509_NAME_ENTRY*|.
DECLARE_ASN1_ITEM(X509_NAME_ENTRY)
// X509_NAME_ENTRY_new returns a new, empty |X509_NAME_ENTRY_new|, or NULL on
// error.
OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_new(void);
// X509_NAME_ENTRY_free releases memory associated with |entry|.
OPENSSL_EXPORT void X509_NAME_ENTRY_free(X509_NAME_ENTRY *entry);
// d2i_X509_NAME_ENTRY parses up to |len| bytes from |*inp| as a DER-encoded
// AttributeTypeAndValue (RFC 5280), as described in |d2i_SAMPLE_with_reuse|.
OPENSSL_EXPORT X509_NAME_ENTRY *d2i_X509_NAME_ENTRY(X509_NAME_ENTRY **out,
const uint8_t **inp,
long len);
// i2d_X509_NAME_ENTRY marshals |in| as a DER-encoded AttributeTypeAndValue (RFC
// 5280), as described in |i2d_SAMPLE|.
OPENSSL_EXPORT int i2d_X509_NAME_ENTRY(const X509_NAME_ENTRY *in,
uint8_t **outp);
// X509_NAME_ENTRY_dup returns a newly-allocated copy of |entry|, or NULL on
// error.
OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_dup(
const X509_NAME_ENTRY *entry);
// X509_NAME_ENTRY_get_object returns |entry|'s attribute type. This function
// returns a non-const pointer for OpenSSL compatibility, but callers should not
// mutate the result. Doing so will break internal invariants in the library.
OPENSSL_EXPORT ASN1_OBJECT *X509_NAME_ENTRY_get_object(
const X509_NAME_ENTRY *entry);
// X509_NAME_ENTRY_set_object sets |entry|'s attribute type to |obj|. It returns
// one on success and zero on error.
OPENSSL_EXPORT int X509_NAME_ENTRY_set_object(X509_NAME_ENTRY *entry,
const ASN1_OBJECT *obj);
// X509_NAME_ENTRY_get_data returns |entry|'s attribute value, represented as an
// |ASN1_STRING|. This value may have any ASN.1 type, so callers must check the
// type before interpreting the contents. This function returns a non-const
// pointer for OpenSSL compatibility, but callers should not mutate the result.
// Doing so will break internal invariants in the library.
//
// TODO(https://crbug.com/boringssl/412): Although the spec says any ASN.1 type
// is allowed, we currently only allow an ad-hoc set of types. Additionally, it
// is unclear if some types can even be represented by this function.
OPENSSL_EXPORT ASN1_STRING *X509_NAME_ENTRY_get_data(
const X509_NAME_ENTRY *entry);
// X509_NAME_ENTRY_set_data sets |entry|'s value to |len| bytes from |bytes|. It
// returns one on success and zero on error. If |len| is -1, |bytes| must be a
// NUL-terminated C string and the length is determined by |strlen|. |bytes| is
// converted to an ASN.1 type as follows:
//
// If |type| is a |MBSTRING_*| constant, the value is an ASN.1 string. The
// string is determined by decoding |bytes| in the encoding specified by |type|,
// and then re-encoding it in a form appropriate for |entry|'s attribute type.
// See |ASN1_STRING_set_by_NID| for details.
//
// Otherwise, the value is an |ASN1_STRING| with type |type| and value |bytes|.
// See |ASN1_STRING| for how to format ASN.1 types as an |ASN1_STRING|. If
// |type| is |V_ASN1_UNDEF| the previous |ASN1_STRING| type is reused.
OPENSSL_EXPORT int X509_NAME_ENTRY_set_data(X509_NAME_ENTRY *entry, int type,
const uint8_t *bytes, int len);
// X509_NAME_ENTRY_set returns the zero-based index of the RDN which contains
// |entry|. Consecutive entries with the same index are part of the same RDN.
OPENSSL_EXPORT int X509_NAME_ENTRY_set(const X509_NAME_ENTRY *entry);
// X509_NAME_ENTRY_create_by_OBJ creates a new |X509_NAME_ENTRY| with attribute
// type |obj|. The attribute value is determined from |type|, |bytes|, and |len|
// as in |X509_NAME_ENTRY_set_data|. It returns the |X509_NAME_ENTRY| on success
// and NULL on error.
//
// If |out| is non-NULL and |*out| is NULL, it additionally sets |*out| to the
// result on success. If both |out| and |*out| are non-NULL, it updates the
// object at |*out| instead of allocating a new one.
OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_OBJ(
X509_NAME_ENTRY **out, const ASN1_OBJECT *obj, int type,
const uint8_t *bytes, int len);
// X509_NAME_ENTRY_create_by_NID behaves like |X509_NAME_ENTRY_create_by_OBJ|
// except the attribute type is |nid|, which should be one of the |NID_*|
// constants.
OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_NID(
X509_NAME_ENTRY **out, int nid, int type, const uint8_t *bytes, int len);
// X509_NAME_ENTRY_create_by_txt behaves like |X509_NAME_ENTRY_create_by_OBJ|
// except the attribute type is |field|, which is passed to |OBJ_txt2obj|.
OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_txt(
X509_NAME_ENTRY **out, const char *field, int type, const uint8_t *bytes,
int len);
// Algorithm identifiers.
//
// An |X509_ALGOR| represents an AlgorithmIdentifier structure, used in X.509
@ -874,6 +1114,31 @@ OPENSSL_EXPORT ASN1_TIME *X509_CRL_get_nextUpdate(X509_CRL *crl);
// Prefer |X509_get0_serialNumber|.
OPENSSL_EXPORT ASN1_INTEGER *X509_get_serialNumber(X509 *x509);
// X509_NAME_get_text_by_OBJ finds the first attribute with type |obj| in
// |name|. If found, it ignores the value's ASN.1 type, writes the raw
// |ASN1_STRING| representation to |buf|, followed by a NUL byte, and
// returns the number of bytes in output, excluding the NUL byte.
//
// This function writes at most |len| bytes, including the NUL byte. If |len| is
// not large enough, it silently truncates the output to fit. If |buf| is NULL,
// it instead writes enough and returns the number of bytes in the output,
// excluding the NUL byte.
//
// WARNING: Do not use this function. It does not return enough information for
// the caller to correctly interpret its output. The attribute value may be of
// any type, including one of several ASN.1 string encodings, but this function
// only outputs the raw |ASN1_STRING| representation. See
// https://crbug.com/boringssl/436.
OPENSSL_EXPORT int X509_NAME_get_text_by_OBJ(const X509_NAME *name,
const ASN1_OBJECT *obj, char *buf,
int len);
// X509_NAME_get_text_by_NID behaves like |X509_NAME_get_text_by_OBJ| except it
// finds an attribute of type |nid|, which should be one of the |NID_*|
// constants.
OPENSSL_EXPORT int X509_NAME_get_text_by_NID(const X509_NAME *name, int nid,
char *buf, int len);
// Private structures.
@ -900,10 +1165,6 @@ struct X509_algor_st {
#define X509v3_KU_DECIPHER_ONLY 0x8000
#define X509v3_KU_UNDEF 0xffff
DEFINE_STACK_OF(X509_NAME_ENTRY)
DEFINE_STACK_OF(X509_NAME)
typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS;
DEFINE_STACK_OF(X509_EXTENSION)
@ -1269,13 +1530,6 @@ OPENSSL_EXPORT X509_REVOKED *X509_REVOKED_dup(X509_REVOKED *rev);
OPENSSL_EXPORT X509_REQ *X509_REQ_dup(X509_REQ *req);
OPENSSL_EXPORT X509_ALGOR *X509_ALGOR_dup(const X509_ALGOR *xn);
OPENSSL_EXPORT X509_NAME *X509_NAME_dup(X509_NAME *xn);
OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_dup(const X509_NAME_ENTRY *ne);
OPENSSL_EXPORT int X509_NAME_ENTRY_set(const X509_NAME_ENTRY *ne);
OPENSSL_EXPORT int X509_NAME_get0_der(X509_NAME *nm, const unsigned char **pder,
size_t *pderlen);
// X509_cmp_time compares |s| against |*t|. On success, it returns a negative
// number if |s| <= |*t| and a positive number if |s| > |*t|. On error, it
// returns zero. If |t| is NULL, it uses the current time instead of |*t|.
@ -1335,16 +1589,6 @@ OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int attrtype,
DECLARE_ASN1_FUNCTIONS_const(X509_EXTENSION)
DECLARE_ASN1_ENCODE_FUNCTIONS_const(X509_EXTENSIONS, X509_EXTENSIONS)
DECLARE_ASN1_FUNCTIONS_const(X509_NAME_ENTRY)
// TODO(https://crbug.com/boringssl/407): This is not const because serializing
// an |X509_NAME| is sometimes not thread-safe.
DECLARE_ASN1_FUNCTIONS(X509_NAME)
// X509_NAME_set makes a copy of |name|. On success, it frees |*xn|, sets |*xn|
// to the copy, and returns one. Otherwise, it returns zero.
OPENSSL_EXPORT int X509_NAME_set(X509_NAME **xn, X509_NAME *name);
OPENSSL_EXPORT int X509_add1_trust_object(X509 *x, ASN1_OBJECT *obj);
OPENSSL_EXPORT int X509_add1_reject_object(X509 *x, ASN1_OBJECT *obj);
OPENSSL_EXPORT void X509_trust_clear(X509 *x);
@ -1559,56 +1803,6 @@ OPENSSL_EXPORT int X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflag,
unsigned long cflag);
OPENSSL_EXPORT int X509_REQ_print(BIO *bp, X509_REQ *req);
OPENSSL_EXPORT int X509_NAME_entry_count(const X509_NAME *name);
OPENSSL_EXPORT int X509_NAME_get_text_by_NID(const X509_NAME *name, int nid,
char *buf, int len);
OPENSSL_EXPORT int X509_NAME_get_text_by_OBJ(const X509_NAME *name,
const ASN1_OBJECT *obj, char *buf,
int len);
// NOTE: you should be passsing -1, not 0 as lastpos. The functions that use
// lastpos, search after that position on.
OPENSSL_EXPORT int X509_NAME_get_index_by_NID(const X509_NAME *name, int nid,
int lastpos);
OPENSSL_EXPORT int X509_NAME_get_index_by_OBJ(const X509_NAME *name,
const ASN1_OBJECT *obj,
int lastpos);
OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_get_entry(const X509_NAME *name,
int loc);
OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *name,
int loc);
OPENSSL_EXPORT int X509_NAME_add_entry(X509_NAME *name, X509_NAME_ENTRY *ne,
int loc, int set);
OPENSSL_EXPORT int X509_NAME_add_entry_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj,
int type,
const unsigned char *bytes,
int len, int loc, int set);
OPENSSL_EXPORT int X509_NAME_add_entry_by_NID(X509_NAME *name, int nid,
int type,
const unsigned char *bytes,
int len, int loc, int set);
OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_txt(
X509_NAME_ENTRY **ne, const char *field, int type,
const unsigned char *bytes, int len);
OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_NID(
X509_NAME_ENTRY **ne, int nid, int type, const unsigned char *bytes,
int len);
OPENSSL_EXPORT int X509_NAME_add_entry_by_txt(X509_NAME *name,
const char *field, int type,
const unsigned char *bytes,
int len, int loc, int set);
OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_OBJ(
X509_NAME_ENTRY **ne, const ASN1_OBJECT *obj, int type,
const unsigned char *bytes, int len);
OPENSSL_EXPORT int X509_NAME_ENTRY_set_object(X509_NAME_ENTRY *ne,
const ASN1_OBJECT *obj);
OPENSSL_EXPORT int X509_NAME_ENTRY_set_data(X509_NAME_ENTRY *ne, int type,
const unsigned char *bytes,
int len);
OPENSSL_EXPORT ASN1_OBJECT *X509_NAME_ENTRY_get_object(
const X509_NAME_ENTRY *ne);
OPENSSL_EXPORT ASN1_STRING *X509_NAME_ENTRY_get_data(const X509_NAME_ENTRY *ne);
// X509v3_get_ext_count returns the number of extensions in |x|.
OPENSSL_EXPORT int X509v3_get_ext_count(const STACK_OF(X509_EXTENSION) *x);
@ -1969,8 +2163,6 @@ OPENSSL_EXPORT int X509_ATTRIBUTE_set1_object(X509_ATTRIBUTE *attr,
// |attr|'s type. If |len| is -1, |strlen(data)| is used instead. See
// |ASN1_STRING_set_by_NID| for details.
//
// TODO(davidben): Document |ASN1_STRING_set_by_NID| so the reference is useful.
//
// Otherwise, if |len| is not -1, the value is an ASN.1 string. |attrtype| is an
// |ASN1_STRING| type value and the |len| bytes from |data| are copied as the
// type-specific representation of |ASN1_STRING|. See |ASN1_STRING| for details.

Loading…
Cancel
Save