Skip to content

Commit 13022bb

Browse files
davidbennebeid
authored andcommitted
Simplify and document X509_VERIFY_PARAM inheritance
X509_VERIFY_PARAM inheritance is unbelievably thorny, and I'm not sure it was ever thought through very well. We can make it slightly less complicated by removing the internal inh_flags value. We don't support X509_VERIFY_PARAM_set_inh_flags (and really should keep it that way!), so there are actually only two possible values, zero and X509_VP_FLAG_DEFAULT, used to implement X509_VERIFY_PARAM_inherit, and X509_VERIFY_PARAM_set1, respectively. This still leaves some weird behaviors that are expected through the public API, which I've documented in the headers. They'll probably need another pass when they're grouped into sections and whatnot. Bug: 441, 426 Change-Id: Ib0a855afd35e597c65c249627addfef76ed7099d Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/64253 Commit-Queue: David Benjamin <[email protected]> Reviewed-by: Bob Beck <[email protected]> (cherry picked from commit 51ae958ff7c99103932e07905c40cbc71a22b389)
1 parent ad211a9 commit 13022bb

File tree

5 files changed

+203
-118
lines changed

5 files changed

+203
-118
lines changed

crypto/x509/internal.h

-1
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,6 @@ struct X509_crl_st {
248248

249249
struct X509_VERIFY_PARAM_st {
250250
int64_t check_time; // POSIX time to use
251-
unsigned long inh_flags; // Inheritance flags
252251
unsigned long flags; // Various verify flags
253252
int purpose; // purpose to check untrusted certificates
254253
int trust; // trust setting to check

crypto/x509/x509_lu.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,7 @@ int X509_STORE_set_trust(X509_STORE *ctx, int trust) {
630630
return X509_VERIFY_PARAM_set_trust(ctx->param, trust);
631631
}
632632

633-
int X509_STORE_set1_param(X509_STORE *ctx, X509_VERIFY_PARAM *param) {
633+
int X509_STORE_set1_param(X509_STORE *ctx, const X509_VERIFY_PARAM *param) {
634634
return X509_VERIFY_PARAM_set1(ctx->param, param);
635635
}
636636

crypto/x509/x509_test.cc

+91
Original file line numberDiff line numberDiff line change
@@ -7128,3 +7128,94 @@ TEST(X509Test, ExternalData) {
71287128
EXPECT_EQ(retrieved_data->custom_data, 123);
71297129
}
71307130

7131+
TEST(X509Test, ParamInheritance) {
7132+
// |X509_VERIFY_PARAM_inherit| with both unset.
7133+
{
7134+
bssl::UniquePtr<X509_VERIFY_PARAM> dest(X509_VERIFY_PARAM_new());
7135+
ASSERT_TRUE(dest);
7136+
bssl::UniquePtr<X509_VERIFY_PARAM> src(X509_VERIFY_PARAM_new());
7137+
ASSERT_TRUE(src);
7138+
ASSERT_TRUE(X509_VERIFY_PARAM_inherit(dest.get(), src.get()));
7139+
EXPECT_EQ(X509_VERIFY_PARAM_get_depth(dest.get()), -1);
7140+
}
7141+
7142+
// |X509_VERIFY_PARAM_inherit| with source set.
7143+
{
7144+
bssl::UniquePtr<X509_VERIFY_PARAM> dest(X509_VERIFY_PARAM_new());
7145+
ASSERT_TRUE(dest);
7146+
bssl::UniquePtr<X509_VERIFY_PARAM> src(X509_VERIFY_PARAM_new());
7147+
ASSERT_TRUE(src);
7148+
X509_VERIFY_PARAM_set_depth(src.get(), 5);
7149+
ASSERT_TRUE(X509_VERIFY_PARAM_inherit(dest.get(), src.get()));
7150+
EXPECT_EQ(X509_VERIFY_PARAM_get_depth(dest.get()), 5);
7151+
}
7152+
7153+
// |X509_VERIFY_PARAM_inherit| with destination set.
7154+
{
7155+
bssl::UniquePtr<X509_VERIFY_PARAM> dest(X509_VERIFY_PARAM_new());
7156+
ASSERT_TRUE(dest);
7157+
bssl::UniquePtr<X509_VERIFY_PARAM> src(X509_VERIFY_PARAM_new());
7158+
ASSERT_TRUE(src);
7159+
X509_VERIFY_PARAM_set_depth(dest.get(), 5);
7160+
ASSERT_TRUE(X509_VERIFY_PARAM_inherit(dest.get(), src.get()));
7161+
EXPECT_EQ(X509_VERIFY_PARAM_get_depth(dest.get()), 5);
7162+
}
7163+
7164+
// |X509_VERIFY_PARAM_inherit| with both set.
7165+
{
7166+
bssl::UniquePtr<X509_VERIFY_PARAM> dest(X509_VERIFY_PARAM_new());
7167+
ASSERT_TRUE(dest);
7168+
bssl::UniquePtr<X509_VERIFY_PARAM> src(X509_VERIFY_PARAM_new());
7169+
ASSERT_TRUE(src);
7170+
X509_VERIFY_PARAM_set_depth(dest.get(), 5);
7171+
X509_VERIFY_PARAM_set_depth(src.get(), 10);
7172+
ASSERT_TRUE(X509_VERIFY_PARAM_inherit(dest.get(), src.get()));
7173+
// The existing value is used.
7174+
EXPECT_EQ(X509_VERIFY_PARAM_get_depth(dest.get()), 5);
7175+
}
7176+
7177+
// |X509_VERIFY_PARAM_set1| with both unset.
7178+
{
7179+
bssl::UniquePtr<X509_VERIFY_PARAM> dest(X509_VERIFY_PARAM_new());
7180+
ASSERT_TRUE(dest);
7181+
bssl::UniquePtr<X509_VERIFY_PARAM> src(X509_VERIFY_PARAM_new());
7182+
ASSERT_TRUE(src);
7183+
ASSERT_TRUE(X509_VERIFY_PARAM_set1(dest.get(), src.get()));
7184+
EXPECT_EQ(X509_VERIFY_PARAM_get_depth(dest.get()), -1);
7185+
}
7186+
7187+
// |X509_VERIFY_PARAM_set1| with source set.
7188+
{
7189+
bssl::UniquePtr<X509_VERIFY_PARAM> dest(X509_VERIFY_PARAM_new());
7190+
ASSERT_TRUE(dest);
7191+
bssl::UniquePtr<X509_VERIFY_PARAM> src(X509_VERIFY_PARAM_new());
7192+
ASSERT_TRUE(src);
7193+
X509_VERIFY_PARAM_set_depth(src.get(), 5);
7194+
ASSERT_TRUE(X509_VERIFY_PARAM_set1(dest.get(), src.get()));
7195+
EXPECT_EQ(X509_VERIFY_PARAM_get_depth(dest.get()), 5);
7196+
}
7197+
7198+
// |X509_VERIFY_PARAM_set1| with destination set.
7199+
{
7200+
bssl::UniquePtr<X509_VERIFY_PARAM> dest(X509_VERIFY_PARAM_new());
7201+
ASSERT_TRUE(dest);
7202+
bssl::UniquePtr<X509_VERIFY_PARAM> src(X509_VERIFY_PARAM_new());
7203+
ASSERT_TRUE(src);
7204+
X509_VERIFY_PARAM_set_depth(dest.get(), 5);
7205+
ASSERT_TRUE(X509_VERIFY_PARAM_set1(dest.get(), src.get()));
7206+
EXPECT_EQ(X509_VERIFY_PARAM_get_depth(dest.get()), 5);
7207+
}
7208+
7209+
// |X509_VERIFY_PARAM_set1| with both set.
7210+
{
7211+
bssl::UniquePtr<X509_VERIFY_PARAM> dest(X509_VERIFY_PARAM_new());
7212+
ASSERT_TRUE(dest);
7213+
bssl::UniquePtr<X509_VERIFY_PARAM> src(X509_VERIFY_PARAM_new());
7214+
ASSERT_TRUE(src);
7215+
X509_VERIFY_PARAM_set_depth(dest.get(), 5);
7216+
X509_VERIFY_PARAM_set_depth(src.get(), 10);
7217+
ASSERT_TRUE(X509_VERIFY_PARAM_set1(dest.get(), src.get()));
7218+
// The new value is used.
7219+
EXPECT_EQ(X509_VERIFY_PARAM_get_depth(dest.get()), 10);
7220+
}
7221+
}

crypto/x509/x509_vpm.c

+49-97
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,6 @@ X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void) {
129129
return NULL;
130130
}
131131
param->depth = -1;
132-
// TODO(crbug.com/boringssl/441): This line was commented out. Figure out what
133-
// this was for:
134-
// param->inh_flags = X509_VP_FLAG_DEFAULT;
135132
return param;
136133
}
137134

@@ -146,143 +143,98 @@ void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param) {
146143
OPENSSL_free(param);
147144
}
148145

149-
//-
150-
// This function determines how parameters are "inherited" from one structure
151-
// to another. There are several different ways this can happen.
152-
//
153-
// 1. If a child structure needs to have its values initialized from a parent
154-
// they are simply copied across. For example SSL_CTX copied to SSL.
155-
// 2. If the structure should take on values only if they are currently unset.
156-
// For example the values in an SSL structure will take appropriate value
157-
// for SSL servers or clients but only if the application has not set new
158-
// ones.
159-
//
160-
// The "inh_flags" field determines how this function behaves.
161-
//
162-
// Normally any values which are set in the default are not copied from the
163-
// destination and verify flags are ORed together.
164-
//
165-
// If X509_VP_FLAG_DEFAULT is set then anything set in the source is copied
166-
// to the destination. Effectively the values in "to" become default values
167-
// which will be used only if nothing new is set in "from".
168-
//
169-
// If X509_VP_FLAG_OVERWRITE is set then all value are copied across whether
170-
// they are set or not. Flags is still Ored though.
171-
//
172-
// If X509_VP_FLAG_RESET_FLAGS is set then the flags value is copied instead
173-
// of ORed.
174-
//
175-
// If X509_VP_FLAG_LOCKED is set then no values are copied.
176-
//
177-
// If X509_VP_FLAG_ONCE is set then the current inh_flags setting is zeroed
178-
// after the next call.
179-
180-
// Macro to test if a field should be copied from src to dest
181-
182-
#define test_x509_verify_param_copy(field, def) \
183-
(to_overwrite || \
184-
((src->field != (def)) && (to_default || (dest->field == (def)))))
185-
186-
// Macro to test and copy a field if necessary
187-
188-
#define x509_verify_param_copy(field, def) \
189-
if (test_x509_verify_param_copy(field, def)) \
190-
dest->field = src->field
191-
192-
int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest,
193-
const X509_VERIFY_PARAM *src) {
194-
unsigned long inh_flags;
195-
int to_default, to_overwrite;
196-
if (!src) {
197-
return 1;
198-
}
199-
inh_flags = dest->inh_flags | src->inh_flags;
200-
201-
if (inh_flags & X509_VP_FLAG_ONCE) {
202-
dest->inh_flags = 0;
146+
static int should_copy(int dest_is_set, int src_is_set, int prefer_src) {
147+
if (prefer_src) {
148+
// We prefer the source, so as long as there is a value to copy, copy it.
149+
return src_is_set;
203150
}
204151

205-
if (inh_flags & X509_VP_FLAG_LOCKED) {
206-
return 1;
207-
}
152+
// We prefer the destination, so only copy if the destination is unset.
153+
return src_is_set && !dest_is_set;
154+
}
208155

209-
if (inh_flags & X509_VP_FLAG_DEFAULT) {
210-
to_default = 1;
211-
} else {
212-
to_default = 0;
156+
static void copy_int_param(int *dest, const int *src, int default_val,
157+
int prefer_src) {
158+
if (should_copy(*dest != default_val, *src != default_val, prefer_src)) {
159+
*dest = *src;
213160
}
161+
}
214162

215-
if (inh_flags & X509_VP_FLAG_OVERWRITE) {
216-
to_overwrite = 1;
217-
} else {
218-
to_overwrite = 0;
163+
// x509_verify_param_copy copies fields from |src| to |dest|. If both |src| and
164+
// |dest| have some field set, |prefer_src| determines whether |src| or |dest|'s
165+
// version is used.
166+
static int x509_verify_param_copy(X509_VERIFY_PARAM *dest,
167+
const X509_VERIFY_PARAM *src,
168+
int prefer_src) {
169+
if (src == NULL) {
170+
return 1;
219171
}
220172

221-
x509_verify_param_copy(purpose, 0);
222-
x509_verify_param_copy(trust, 0);
223-
x509_verify_param_copy(depth, -1);
224-
225-
// If overwrite or check time not set, copy across
173+
copy_int_param(&dest->purpose, &src->purpose, /*default_val=*/0, prefer_src);
174+
copy_int_param(&dest->trust, &src->trust, /*default_val=*/0, prefer_src);
175+
copy_int_param(&dest->depth, &src->depth, /*default_val=*/-1, prefer_src);
226176

227-
if (to_overwrite || !(dest->flags & X509_V_FLAG_USE_CHECK_TIME)) {
177+
// |check_time|, unlike all other parameters, does not honor |prefer_src|.
178+
// This means |X509_VERIFY_PARAM_set1| will not overwrite it. This behavior
179+
// comes from OpenSSL but may have been a bug.
180+
if (!(dest->flags & X509_V_FLAG_USE_CHECK_TIME)) {
228181
dest->check_time = src->check_time;
229-
dest->flags &= ~X509_V_FLAG_USE_CHECK_TIME;
230-
// Don't need to copy flag: that is done below
231-
}
232-
233-
if (inh_flags & X509_VP_FLAG_RESET_FLAGS) {
234-
dest->flags = 0;
182+
// The source |X509_V_FLAG_USE_CHECK_TIME| flag, if set, is copied below.
235183
}
236184

237185
dest->flags |= src->flags;
238186

239-
if (test_x509_verify_param_copy(policies, NULL)) {
187+
if (should_copy(dest->policies != NULL, src->policies != NULL, prefer_src)) {
240188
if (!X509_VERIFY_PARAM_set1_policies(dest, src->policies)) {
241189
return 0;
242190
}
243191
}
244192

245-
// Copy the host flags if and only if we're copying the host list
246-
if (test_x509_verify_param_copy(hosts, NULL)) {
247-
if (dest->hosts) {
248-
sk_OPENSSL_STRING_pop_free(dest->hosts, str_free);
249-
dest->hosts = NULL;
250-
}
193+
if (should_copy(dest->hosts != NULL, src->hosts != NULL, prefer_src)) {
194+
sk_OPENSSL_STRING_pop_free(dest->hosts, str_free);
195+
dest->hosts = NULL;
251196
if (src->hosts) {
252197
dest->hosts =
253198
sk_OPENSSL_STRING_deep_copy(src->hosts, OPENSSL_strdup, str_free);
254199
if (dest->hosts == NULL) {
255200
return 0;
256201
}
202+
// Copy the host flags if and only if we're copying the host list. Note
203+
// this means mechanisms like |X509_STORE_CTX_set_default| cannot be used
204+
// to set host flags. E.g. we cannot change the defaults using
205+
// |kDefaultParam| below.
257206
dest->hostflags = src->hostflags;
258207
}
259208
}
260209

261-
if (test_x509_verify_param_copy(email, NULL)) {
210+
if (should_copy(dest->email != NULL, src->email != NULL, prefer_src)) {
262211
if (!X509_VERIFY_PARAM_set1_email(dest, src->email, src->emaillen)) {
263212
return 0;
264213
}
265214
}
266215

267-
if (test_x509_verify_param_copy(ip, NULL)) {
216+
if (should_copy(dest->ip != NULL, src->ip != NULL, prefer_src)) {
268217
if (!X509_VERIFY_PARAM_set1_ip(dest, src->ip, src->iplen)) {
269218
return 0;
270219
}
271220
}
272221

273222
dest->poison = src->poison;
274-
275223
return 1;
276224
}
277225

226+
int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest,
227+
const X509_VERIFY_PARAM *src) {
228+
// Prefer the destination. That is, this function only changes unset
229+
// parameters in |dest|.
230+
return x509_verify_param_copy(dest, src, /*prefer_src=*/0);
231+
}
232+
278233
int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to,
279234
const X509_VERIFY_PARAM *from) {
280-
unsigned long save_flags = to->inh_flags;
281-
int ret;
282-
to->inh_flags |= X509_VP_FLAG_DEFAULT;
283-
ret = X509_VERIFY_PARAM_inherit(to, from);
284-
to->inh_flags = save_flags;
285-
return ret;
235+
// Prefer the source. That is, values in |to| are only preserved if they were
236+
// unset in |from|.
237+
return x509_verify_param_copy(to, from, /*prefer_src=*/1);
286238
}
287239

288240
static int int_x509_param_set1_email(char **pdest, size_t *pdestlen,
@@ -365,7 +317,7 @@ int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *param,
365317
return 1;
366318
}
367319

368-
unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *param) {
320+
unsigned long X509_VERIFY_PARAM_get_flags(const X509_VERIFY_PARAM *param) {
369321
return param->flags;
370322
}
371323

0 commit comments

Comments
 (0)