Skip to content

Commit 1767ad0

Browse files
authored
X509 custom verification groundwork (#11559)
* Add CustomPolicyBuilder foundation. * Add EKU getters to ClientVerifier and ServerVerifier. * Document the implemented part of custom verification. * Remove `subject` field from VerifiedClient, rename `sans` back to `subjects`. * Remove EKU-related setters, getters and documentation from this PR. * Use double backticks in reStructuredText. * Remove CustomPolicyBuilder in favor of extending PolicyBuilder. * Code style improvements. * Resolve coverage issues.
1 parent cb0a83f commit 1767ad0

File tree

5 files changed

+37
-18
lines changed

5 files changed

+37
-18
lines changed

docs/spelling_wordlist.txt

+1
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ unencrypted
140140
unicode
141141
unpadded
142142
unpadding
143+
validator
143144
Ventura
144145
verifier
145146
Verifier

docs/x509/verification.rst

+5-2
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,15 @@ the root of trust:
111111

112112
.. versionadded:: 43.0.0
113113

114+
.. versionchanged:: 44.0.0
115+
Made ``subjects`` optional with the addition of custom extension policies.
116+
114117
.. attribute:: subjects
115118

116-
:type: list of :class:`~cryptography.x509.GeneralName`
119+
:type: list of :class:`~cryptography.x509.GeneralName` or None
117120

118121
The subjects presented in the verified client's Subject Alternative Name
119-
extension.
122+
extension or ``None`` if the extension is not present.
120123

121124
.. attribute:: chain
122125

src/cryptography/hazmat/bindings/_rust/x509.pyi

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class PolicyBuilder:
6969

7070
class VerifiedClient:
7171
@property
72-
def subjects(self) -> list[x509.GeneralName]: ...
72+
def subjects(self) -> list[x509.GeneralName] | None: ...
7373
@property
7474
def chain(self) -> list[x509.Certificate]: ...
7575

src/rust/src/x509/verify.rs

+29-15
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,16 @@ pub(crate) struct PolicyBuilder {
7575
max_chain_depth: Option<u8>,
7676
}
7777

78+
impl PolicyBuilder {
79+
fn py_clone(&self, py: pyo3::Python<'_>) -> PolicyBuilder {
80+
PolicyBuilder {
81+
time: self.time.clone(),
82+
store: self.store.as_ref().map(|s| s.clone_ref(py)),
83+
max_chain_depth: self.max_chain_depth,
84+
}
85+
}
86+
}
87+
7888
#[pyo3::pymethods]
7989
impl PolicyBuilder {
8090
#[new]
@@ -95,18 +105,20 @@ impl PolicyBuilder {
95105

96106
Ok(PolicyBuilder {
97107
time: Some(py_to_datetime(py, new_time)?),
98-
store: self.store.as_ref().map(|s| s.clone_ref(py)),
99-
max_chain_depth: self.max_chain_depth,
108+
..self.py_clone(py)
100109
})
101110
}
102111

103-
fn store(&self, new_store: pyo3::Py<PyStore>) -> CryptographyResult<PolicyBuilder> {
112+
fn store(
113+
&self,
114+
py: pyo3::Python<'_>,
115+
new_store: pyo3::Py<PyStore>,
116+
) -> CryptographyResult<PolicyBuilder> {
104117
policy_builder_set_once_check!(self, store, "trust store");
105118

106119
Ok(PolicyBuilder {
107-
time: self.time.clone(),
108120
store: Some(new_store),
109-
max_chain_depth: self.max_chain_depth,
121+
..self.py_clone(py)
110122
})
111123
}
112124

@@ -118,9 +130,8 @@ impl PolicyBuilder {
118130
policy_builder_set_once_check!(self, max_chain_depth, "maximum chain depth");
119131

120132
Ok(PolicyBuilder {
121-
time: self.time.clone(),
122-
store: self.store.as_ref().map(|s| s.clone_ref(py)),
123133
max_chain_depth: Some(new_max_chain_depth),
134+
..self.py_clone(py)
124135
})
125136
}
126137

@@ -141,7 +152,8 @@ impl PolicyBuilder {
141152
None => datetime_now(py)?,
142153
};
143154

144-
let policy = PyCryptoPolicy(Policy::client(PyCryptoOps {}, time, self.max_chain_depth));
155+
// TODO: Pass extension policies here once implemented in cryptography-x509-verification.
156+
let policy = Policy::client(PyCryptoOps {}, time, self.max_chain_depth);
145157

146158
Ok(PyClientVerifier { policy, store })
147159
}
@@ -170,12 +182,14 @@ impl PolicyBuilder {
170182

171183
let policy = OwnedPolicy::try_new(subject_owner, |subject_owner| {
172184
let subject = build_subject(py, subject_owner)?;
173-
Ok::<PyCryptoPolicy<'_>, pyo3::PyErr>(PyCryptoPolicy(Policy::server(
185+
186+
// TODO: Pass extension policies here once implemented in cryptography-x509-verification.
187+
Ok::<PyCryptoPolicy<'_>, pyo3::PyErr>(Policy::server(
174188
PyCryptoOps {},
175189
subject,
176190
time,
177191
self.max_chain_depth,
178-
)))
192+
))
179193
})?;
180194

181195
Ok(PyServerVerifier {
@@ -186,7 +200,7 @@ impl PolicyBuilder {
186200
}
187201
}
188202

189-
struct PyCryptoPolicy<'a>(Policy<'a, PyCryptoOps>);
203+
type PyCryptoPolicy<'a> = Policy<'a, PyCryptoOps>;
190204

191205
/// This enum exists solely to provide heterogeneously typed ownership for `OwnedPolicy`.
192206
enum SubjectOwner {
@@ -215,7 +229,7 @@ self_cell::self_cell!(
215229
)]
216230
pub(crate) struct PyVerifiedClient {
217231
#[pyo3(get)]
218-
subjects: pyo3::Py<pyo3::PyAny>,
232+
subjects: Option<pyo3::Py<pyo3::PyAny>>,
219233
#[pyo3(get)]
220234
chain: pyo3::Py<pyo3::types::PyList>,
221235
}
@@ -233,7 +247,7 @@ pub(crate) struct PyClientVerifier {
233247

234248
impl PyClientVerifier {
235249
fn as_policy(&self) -> &Policy<'_, PyCryptoOps> {
236-
&self.policy.0
250+
&self.policy
237251
}
238252
}
239253

@@ -305,7 +319,7 @@ impl PyClientVerifier {
305319
let py_gns = parse_general_names(py, &leaf_gns)?;
306320

307321
Ok(PyVerifiedClient {
308-
subjects: py_gns,
322+
subjects: Some(py_gns),
309323
chain: py_chain.unbind(),
310324
})
311325
}
@@ -326,7 +340,7 @@ pub(crate) struct PyServerVerifier {
326340

327341
impl PyServerVerifier {
328342
fn as_policy(&self) -> &Policy<'_, PyCryptoOps> {
329-
&self.policy.borrow_dependent().0
343+
self.policy.borrow_dependent()
330344
}
331345
}
332346

tests/x509/verification/test_verification.py

+1
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ def test_verify(self):
139139
verified_client = verifier.verify(leaf, [])
140140
assert verified_client.chain == [leaf]
141141

142+
assert verified_client.subjects is not None
142143
assert x509.DNSName("www.cryptography.io") in verified_client.subjects
143144
assert x509.DNSName("cryptography.io") in verified_client.subjects
144145
assert len(verified_client.subjects) == 2

0 commit comments

Comments
 (0)