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>
diff --git a/crypto/x509/name_print.c b/crypto/x509/name_print.c
index f871df9..29207cc 100644
--- a/crypto/x509/name_print.c
+++ b/crypto/x509/name_print.c
@@ -86,9 +86,6 @@
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 @@
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 @@
}
}
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;
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c
index 8569d2a..5a97353 100644
--- a/crypto/x509/x509_vfy.c
+++ b/crypto/x509/x509_vfy.c
@@ -689,7 +689,7 @@
}
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 @@
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) {
diff --git a/crypto/x509/x509name.c b/crypto/x509/x509name.c
index 6771b68..fcfbc0c 100644
--- a/crypto/x509/x509name.c
+++ b/crypto/x509/x509name.c
@@ -80,14 +80,12 @@
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_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_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_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 @@
}
}
- if ((new_name = X509_NAME_ENTRY_dup(ne)) == NULL) {
+ if ((new_name = X509_NAME_ENTRY_dup(entry)) == NULL) {
goto err;
}
new_name->set = set;
diff --git a/crypto/x509v3/v3_ncons.c b/crypto/x509v3/v3_ncons.c
index 967423a..5505a62 100644
--- a/crypto/x509v3/v3_ncons.c
+++ b/crypto/x509v3/v3_ncons.c
@@ -76,14 +76,14 @@
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 @@
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 @@
// 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 @@
return equal_case(©, 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 @@
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 @@
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);
diff --git a/crypto/x509v3/v3_utl.c b/crypto/x509v3/v3_utl.c
index 3eccf06..15ebe54 100644
--- a/crypto/x509v3/v3_utl.c
+++ b/crypto/x509v3/v3_utl.c
@@ -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 @@
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 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 @@
// 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_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 @@
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 @@
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) {
diff --git a/include/openssl/x509.h b/include/openssl/x509.h
index 1e8105b..34eb840 100644
--- a/include/openssl/x509.h
+++ b/include/openssl/x509.h
@@ -711,6 +711,246 @@
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 @@
// 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 @@
#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_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 @@
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 @@
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 @@
// |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.