Don't create partial X509 and X509_CRL objects to search the X509_STORE
This gets in the way of embedding X509_NAME into X509, as well as giving
X509 and X509_CRL proper C++ destructors.
Change-Id: I8415976a3fc5aa2774a24fb2f7a6c43c3687ceb5
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/81893
Commit-Queue: David Benjamin <davidben@google.com>
Auto-Submit: David Benjamin <davidben@google.com>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/x509/x509_lu.cc b/crypto/x509/x509_lu.cc
index d3c0630..4599ef9 100644
--- a/crypto/x509/x509_lu.cc
+++ b/crypto/x509/x509_lu.cc
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include <assert.h>
+#include <limits.h>
#include <string.h>
#include <openssl/err.h>
@@ -87,16 +89,32 @@
return ctx->method->get_by_subject(ctx, type, name, ret) > 0;
}
-static int x509_object_cmp(const X509_OBJECT *a, const X509_OBJECT *b) {
- int ret = a->type - b->type;
+// x509_object_cmp_name compares |a| against the specified type and name. This
+// avoids needing to construct a reference certificate or CRL.
+static int x509_object_cmp_name(const X509_OBJECT *a, int type,
+ const X509_NAME *name) {
+ int ret = a->type - type;
if (ret) {
return ret;
}
- switch (a->type) {
+ switch (type) {
case X509_LU_X509:
- return X509_subject_name_cmp(a->data.x509, b->data.x509);
+ return X509_NAME_cmp(X509_get_subject_name(a->data.x509), name);
case X509_LU_CRL:
- return X509_CRL_cmp(a->data.crl, b->data.crl);
+ return X509_NAME_cmp(X509_CRL_get_issuer(a->data.crl), name);
+ default:
+ // abort();
+ return 0;
+ }
+}
+
+static int x509_object_cmp(const X509_OBJECT *a, const X509_OBJECT *b) {
+ switch (b->type) {
+ case X509_LU_X509:
+ return x509_object_cmp_name(a, b->type,
+ X509_get_subject_name(b->data.x509));
+ case X509_LU_CRL:
+ return x509_object_cmp_name(a, b->type, X509_CRL_get_issuer(b->data.crl));
default:
// abort();
return 0;
@@ -285,46 +303,46 @@
}
static int x509_object_idx_cnt(STACK_OF(X509_OBJECT) *h, int type,
- const X509_NAME *name, int *pnmatch) {
- X509_OBJECT stmp;
- X509 x509_s;
- X509_CRL crl_s;
- X509_CRL_INFO crl_info_s;
-
- stmp.type = type;
- switch (type) {
- case X509_LU_X509:
- stmp.data.x509 = &x509_s;
- x509_s.subject = const_cast<X509_NAME*>(name);
- break;
- case X509_LU_CRL:
- stmp.data.crl = &crl_s;
- crl_s.crl = &crl_info_s;
- crl_info_s.issuer = const_cast<X509_NAME*>(name);
- break;
- default:
- // abort();
- return -1;
- }
-
- size_t idx;
+ const X509_NAME *name, int *out_num_match) {
sk_X509_OBJECT_sort(h);
- if (!sk_X509_OBJECT_find(h, &idx, &stmp)) {
+
+ // Find the first matching object. |sk_X509_OBJECT_find| would require
+ // constructing an |X509| or |X509_CRL| object, so implement our own binary
+ // search.
+ size_t start = 0, end = sk_X509_OBJECT_num(h);
+ while (end - start > 1) {
+ // Bias |mid| towards |start|. The range has more than one element, so |mid|
+ // is not the last element.
+ size_t mid = start + (end - start - 1) / 2;
+ assert(start <= mid && mid + 1 < end);
+ int r = x509_object_cmp_name(sk_X509_OBJECT_value(h, mid), type, name);
+ if (r < 0) {
+ start = mid + 1; // |mid| is too low.
+ } else if (r > 0) {
+ end = mid; // |mid| is too high.
+ } else {
+ // |mid| matches, but we need to keep searching to find the first match.
+ end = mid + 1;
+ }
+ }
+ if (start == end ||
+ x509_object_cmp_name(sk_X509_OBJECT_value(h, start), type, name) != 0) {
return -1;
}
- if (pnmatch != NULL) {
- *pnmatch = 1;
- for (size_t tidx = idx + 1; tidx < sk_X509_OBJECT_num(h); tidx++) {
+ if (out_num_match != nullptr) {
+ *out_num_match = 1;
+ for (size_t tidx = start + 1; tidx < sk_X509_OBJECT_num(h); tidx++) {
const X509_OBJECT *tobj = sk_X509_OBJECT_value(h, tidx);
- if (x509_object_cmp(tobj, &stmp)) {
+ if (x509_object_cmp_name(tobj, type, name) != 0) {
break;
}
- (*pnmatch)++;
+ (*out_num_match)++;
}
}
- return (int)idx;
+ assert(start <= INT_MAX); // |STACK_OF(T)| never stores more than |INT_MAX|.
+ return static_cast<int>(start);
}
static int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, int type,