Skip to content

Commit 25d75f0

Browse files
authored
Certificate: useful APIs (#9300)
* certificate: new APIs Signed-off-by: William Woodruff <[email protected]> * certificate: docs Signed-off-by: William Woodruff <[email protected]> * certificate: remove some APIs Signed-off-by: William Woodruff <[email protected]> * remove import Signed-off-by: William Woodruff <[email protected]> * rust: fixup error types Signed-off-by: William Woodruff <[email protected]> * extensions: Debug Signed-off-by: William Woodruff <[email protected]> * certificate: remove CertificateError Signed-off-by: William Woodruff <[email protected]> * rename error Signed-off-by: William Woodruff <[email protected]> * rust: nicer error unpacking Signed-off-by: William Woodruff <[email protected]> * certificate: use extensions() Signed-off-by: William Woodruff <[email protected]> * rust: use subject() and issuer() APIs Signed-off-by: William Woodruff <[email protected]> * certificate: rm `is_self_issued` Signed-off-by: William Woodruff <[email protected]> * clippage Signed-off-by: William Woodruff <[email protected]> * fmt Signed-off-by: William Woodruff <[email protected]> * extensions: remove Debug Signed-off-by: William Woodruff <[email protected]> --------- Signed-off-by: William Woodruff <[email protected]>
1 parent 50ae962 commit 25d75f0

File tree

7 files changed

+56
-29
lines changed

7 files changed

+56
-29
lines changed

src/rust/cryptography-x509/src/certificate.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44

55
use crate::common;
66
use crate::extensions;
7+
use crate::extensions::DuplicateExtensionsError;
78
use crate::extensions::Extensions;
89
use crate::name;
10+
use crate::name::NameReadable;
911

1012
#[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, PartialEq, Eq, Clone)]
1113
pub struct Certificate<'a> {
@@ -14,6 +16,24 @@ pub struct Certificate<'a> {
1416
pub signature: asn1::BitString<'a>,
1517
}
1618

19+
impl Certificate<'_> {
20+
/// Returns the certificate's issuer.
21+
pub fn issuer(&self) -> &NameReadable<'_> {
22+
self.tbs_cert.issuer.unwrap_read()
23+
}
24+
25+
/// Returns the certificate's subject.
26+
pub fn subject(&self) -> &NameReadable<'_> {
27+
self.tbs_cert.subject.unwrap_read()
28+
}
29+
30+
/// Returns an iterable container over the certificate's extension, or
31+
/// an error if the extension set contains a duplicate extension.
32+
pub fn extensions(&self) -> Result<Extensions<'_>, DuplicateExtensionsError> {
33+
self.tbs_cert.extensions()
34+
}
35+
}
36+
1737
#[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, PartialEq, Eq, Clone)]
1838
pub struct TbsCertificate<'a> {
1939
#[explicit(0)]
@@ -36,7 +56,7 @@ pub struct TbsCertificate<'a> {
3656
}
3757

3858
impl TbsCertificate<'_> {
39-
pub fn extensions(&self) -> Result<Extensions<'_>, asn1::ObjectIdentifier> {
59+
pub fn extensions(&self) -> Result<Extensions<'_>, DuplicateExtensionsError> {
4060
Extensions::from_raw_extensions(self.raw_extensions.as_ref())
4161
}
4262
}

src/rust/cryptography-x509/src/extensions.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use crate::common;
88
use crate::crl;
99
use crate::name;
1010

11+
pub struct DuplicateExtensionsError(pub asn1::ObjectIdentifier);
12+
1113
pub type RawExtensions<'a> = common::Asn1ReadableOrWritable<
1214
'a,
1315
asn1::SequenceOf<'a, Extension<'a>>,
@@ -27,14 +29,14 @@ impl<'a> Extensions<'a> {
2729
/// OID, if there are any duplicates.
2830
pub fn from_raw_extensions(
2931
raw: Option<&RawExtensions<'a>>,
30-
) -> Result<Self, asn1::ObjectIdentifier> {
32+
) -> Result<Self, DuplicateExtensionsError> {
3133
match raw {
3234
Some(raw_exts) => {
3335
let mut seen_oids = HashSet::new();
3436

3537
for ext in raw_exts.unwrap_read().clone() {
3638
if !seen_oids.insert(ext.extn_id.clone()) {
37-
return Err(ext.extn_id);
39+
return Err(DuplicateExtensionsError(ext.extn_id));
3840
}
3941
}
4042

@@ -311,7 +313,7 @@ mod tests {
311313
let der = asn1::write_single(&extensions).unwrap();
312314
let raw = asn1::parse_single(&der).unwrap();
313315

314-
let extensions: Extensions = Extensions::from_raw_extensions(Some(&raw)).unwrap();
316+
let extensions: Extensions = Extensions::from_raw_extensions(Some(&raw)).ok().unwrap();
315317

316318
assert!(&extensions.get_extension(&BASIC_CONSTRAINTS_OID).is_some());
317319
assert!(&extensions
@@ -335,7 +337,7 @@ mod tests {
335337
let der = asn1::write_single(&extensions).unwrap();
336338
let parsed = asn1::parse_single(&der).unwrap();
337339

338-
let extensions: Extensions = Extensions::from_raw_extensions(Some(&parsed)).unwrap();
340+
let extensions: Extensions = Extensions::from_raw_extensions(Some(&parsed)).ok().unwrap();
339341

340342
let extension_list: Vec<_> = extensions.iter().collect();
341343
assert_eq!(extension_list.len(), 1);

src/rust/src/x509/certificate.rs

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ use cryptography_x509::certificate::Certificate as RawCertificate;
1313
use cryptography_x509::common::{AlgorithmParameters, Asn1ReadableOrWritable};
1414
use cryptography_x509::extensions::{
1515
AuthorityKeyIdentifier, BasicConstraints, DisplayText, DistributionPoint,
16-
DistributionPointName, IssuerAlternativeName, KeyUsage, MSCertificateTemplate, NameConstraints,
17-
PolicyConstraints, PolicyInformation, PolicyQualifierInfo, Qualifier, RawExtensions,
18-
SequenceOfAccessDescriptions, SequenceOfSubtrees, UserNotice,
16+
DistributionPointName, DuplicateExtensionsError, IssuerAlternativeName, KeyUsage,
17+
MSCertificateTemplate, NameConstraints, PolicyConstraints, PolicyInformation,
18+
PolicyQualifierInfo, Qualifier, RawExtensions, SequenceOfAccessDescriptions,
19+
SequenceOfSubtrees, UserNotice,
1920
};
2021
use cryptography_x509::extensions::{Extension, SubjectAlternativeName};
2122
use cryptography_x509::{common, oid};
@@ -129,18 +130,14 @@ impl Certificate {
129130

130131
#[getter]
131132
fn issuer<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> {
132-
Ok(
133-
x509::parse_name(py, &self.raw.borrow_dependent().tbs_cert.issuer)
134-
.map_err(|e| e.add_location(asn1::ParseLocation::Field("issuer")))?,
135-
)
133+
Ok(x509::parse_name(py, self.raw.borrow_dependent().issuer())
134+
.map_err(|e| e.add_location(asn1::ParseLocation::Field("issuer")))?)
136135
}
137136

138137
#[getter]
139138
fn subject<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> {
140-
Ok(
141-
x509::parse_name(py, &self.raw.borrow_dependent().tbs_cert.subject)
142-
.map_err(|e| e.add_location(asn1::ParseLocation::Field("subject")))?,
143-
)
139+
Ok(x509::parse_name(py, self.raw.borrow_dependent().subject())
140+
.map_err(|e| e.add_location(asn1::ParseLocation::Field("subject")))?)
144141
}
145142

146143
#[getter]
@@ -160,7 +157,7 @@ impl Certificate {
160157
let val = self.raw.borrow_dependent();
161158
let mut tbs_precert = val.tbs_cert.clone();
162159
// Remove the SCT list extension
163-
match val.tbs_cert.extensions() {
160+
match val.extensions() {
164161
Ok(extensions) => {
165162
let ext_count = extensions
166163
.as_raw()
@@ -185,10 +182,10 @@ impl Certificate {
185182
let result = asn1::write_single(&tbs_precert)?;
186183
Ok(pyo3::types::PyBytes::new(py, &result))
187184
}
188-
Err(oid) => {
185+
Err(DuplicateExtensionsError(oid)) => {
189186
let oid_obj = oid_to_py_oid(py, &oid)?;
190187
Err(exceptions::DuplicateExtension::new_err((
191-
format!("Duplicate {} extension found", oid),
188+
format!("Duplicate {} extension found", &oid),
192189
oid_obj.into_py(py),
193190
))
194191
.into())

src/rust/src/x509/common.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ use crate::asn1::{oid_to_py_oid, py_oid_to_oid};
66
use crate::error::{CryptographyError, CryptographyResult};
77
use crate::{exceptions, x509};
88
use cryptography_x509::common::{Asn1ReadableOrWritable, AttributeTypeValue, RawTlv};
9-
use cryptography_x509::extensions::{AccessDescription, Extension, Extensions, RawExtensions};
10-
use cryptography_x509::name::{GeneralName, Name, OtherName, UnvalidatedIA5String};
9+
use cryptography_x509::extensions::{
10+
AccessDescription, DuplicateExtensionsError, Extension, Extensions, RawExtensions,
11+
};
12+
use cryptography_x509::name::{GeneralName, Name, NameReadable, OtherName, UnvalidatedIA5String};
1113
use pyo3::types::IntoPyDict;
1214
use pyo3::{IntoPy, ToPyObject};
1315

@@ -173,11 +175,11 @@ pub(crate) fn encode_access_descriptions<'a>(
173175

174176
pub(crate) fn parse_name<'p>(
175177
py: pyo3::Python<'p>,
176-
name: &Name<'_>,
178+
name: &NameReadable<'_>,
177179
) -> Result<&'p pyo3::PyAny, CryptographyError> {
178180
let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?;
179181
let py_rdns = pyo3::types::PyList::empty(py);
180-
for rdn in name.unwrap_read().clone() {
182+
for rdn in name.clone() {
181183
let py_rdn = parse_rdn(py, &rdn)?;
182184
py_rdns.append(py_rdn)?;
183185
}
@@ -272,7 +274,7 @@ pub(crate) fn parse_general_name(
272274
.call_method1(pyo3::intern!(py, "_init_without_validation"), (data.0,))?
273275
.to_object(py),
274276
GeneralName::DirectoryName(data) => {
275-
let py_name = parse_name(py, &data)?;
277+
let py_name = parse_name(py, data.unwrap_read())?;
276278
x509_module
277279
.call_method1(pyo3::intern!(py, "DirectoryName"), (py_name,))?
278280
.to_object(py)
@@ -395,10 +397,10 @@ pub(crate) fn parse_and_cache_extensions<
395397

396398
let extensions = match Extensions::from_raw_extensions(raw_extensions.as_ref()) {
397399
Ok(extensions) => extensions,
398-
Err(oid) => {
400+
Err(DuplicateExtensionsError(oid)) => {
399401
let oid_obj = oid_to_py_oid(py, &oid)?;
400402
return Err(exceptions::DuplicateExtension::new_err((
401-
format!("Duplicate {} extension found", oid),
403+
format!("Duplicate {} extension found", &oid),
402404
oid_obj.into_py(py),
403405
)));
404406
}

src/rust/src/x509/crl.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,11 @@ impl CertificateRevocationList {
240240
fn issuer<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> {
241241
Ok(x509::parse_name(
242242
py,
243-
&self.owned.borrow_dependent().tbs_cert_list.issuer,
243+
self.owned
244+
.borrow_dependent()
245+
.tbs_cert_list
246+
.issuer
247+
.unwrap_read(),
244248
)?)
245249
}
246250

src/rust/src/x509/csr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl CertificateSigningRequest {
7474
fn subject<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> {
7575
Ok(x509::parse_name(
7676
py,
77-
&self.raw.borrow_dependent().csr_info.subject,
77+
self.raw.borrow_dependent().csr_info.subject.unwrap_read(),
7878
)?)
7979
}
8080

src/rust/src/x509/ocsp_resp.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,9 @@ impl OCSPResponse {
147147
fn responder_name<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> {
148148
let resp = self.requires_successful_response()?;
149149
match resp.tbs_response_data.responder_id {
150-
ocsp_resp::ResponderId::ByName(ref name) => Ok(x509::parse_name(py, name)?),
150+
ocsp_resp::ResponderId::ByName(ref name) => {
151+
Ok(x509::parse_name(py, name.unwrap_read())?)
152+
}
151153
ocsp_resp::ResponderId::ByKey(_) => Ok(py.None().into_ref(py)),
152154
}
153155
}

0 commit comments

Comments
 (0)