Skip to content

Commit 8af022c

Browse files
committed
end_entity: infallible name iteration
The purpose of the `dns_names` helper on an `EndEntityCert` is to provide users the opportunity to get information on the dNSName SAN values in a certificate for **non-validation** purposes. Checking that a certificate is valid for a particular name should always be done with `verify_is_valid_for_at_least_one_dns_name`. With that use-case in mind, we can make the `dns_names` helper easier for consumers to use by filtering out invalid general names, returning an `Iterator<Item = GeneraDnsNameRef<'a>>` unconditionally, instead of a `Result`. This allows the method to be alloc-free and better matches the updated name validation semantics where we ignore `MalformedDnsIdentifier` errors to continue to try to find a valid name to validate against.
1 parent ce5c3cf commit 8af022c

File tree

3 files changed

+19
-35
lines changed

3 files changed

+19
-35
lines changed

src/end_entity.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,13 +150,14 @@ impl<'a> EndEntityCert<'a> {
150150
)
151151
}
152152

153-
/// Returns a list of the DNS names provided in the subject alternative names extension
153+
/// Returns a list of the valid DNS names provided in the subject alternative names (SAN)
154+
/// extension. Invalid names are skipped.
154155
///
155156
/// This function must not be used to implement custom DNS name verification.
156157
/// Verification functions are already provided as `verify_is_valid_for_dns_name`
157158
/// and `verify_is_valid_for_at_least_one_dns_name`.
158159
#[cfg(feature = "alloc")]
159-
pub fn dns_names(&'a self) -> Result<impl Iterator<Item = GeneralDnsNameRef<'a>>, Error> {
160+
pub fn dns_names(&'a self) -> impl Iterator<Item = GeneralDnsNameRef<'a>> {
160161
subject_name::list_cert_dns_names(self)
161162
}
162163
}
@@ -214,9 +215,7 @@ mod tests {
214215
let cert =
215216
EndEntityCert::try_from(der).expect("should parse end entity certificate correctly");
216217

217-
let mut names = cert
218-
.dns_names()
219-
.expect("should get all DNS names correctly for end entity cert");
218+
let mut names = cert.dns_names();
220219
assert_eq!(names.next().map(<&str>::from), Some(name));
221220
assert_eq!(names.next().map(<&str>::from), None);
222221
}

src/subject_name/verify.rs

Lines changed: 14 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@
1212
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1313
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1414

15-
#[cfg(feature = "alloc")]
16-
use alloc::vec::Vec;
17-
1815
#[cfg(feature = "alloc")]
1916
use super::dns_name::GeneralDnsNameRef;
2017
use super::dns_name::{self, DnsNameRef};
@@ -320,35 +317,23 @@ impl<'a> Iterator for NameIterator<'a> {
320317
#[cfg(feature = "alloc")]
321318
pub(crate) fn list_cert_dns_names<'names>(
322319
cert: &'names crate::EndEntityCert<'names>,
323-
) -> Result<impl Iterator<Item = GeneralDnsNameRef<'names>>, Error> {
320+
) -> impl Iterator<Item = GeneralDnsNameRef<'names>> {
324321
let cert = &cert.inner();
325-
let mut names = Vec::new();
326-
327-
let result =
328-
NameIterator::new(Some(cert.subject), cert.subject_alt_name).find_map(&mut |result| {
329-
let name = match result {
330-
Ok(name) => name,
331-
Err(err) => return Some(err),
332-
};
333-
334-
let presented_id = match name {
335-
GeneralName::DnsName(presented) => presented,
336-
_ => return None,
337-
};
338-
339-
// if the name could be converted to a DNS name, add it; otherwise,
340-
// keep going.
341-
if let Ok(name) = GeneralDnsNameRef::try_from_ascii(presented_id.as_slice_less_safe()) {
342-
names.push(name)
343-
}
322+
NameIterator::new(Some(cert.subject), cert.subject_alt_name).filter_map(|result| {
323+
let name = match result {
324+
Ok(name) => name,
325+
// Ignore invalid names, this is an informational function, not something used
326+
// during validation.
327+
Err(_) => return None,
328+
};
344329

345-
None
346-
});
330+
let presented_id = match name {
331+
GeneralName::DnsName(presented) => presented,
332+
_ => return None,
333+
};
347334

348-
match result {
349-
Some(err) => Err(err),
350-
_ => Ok(names.into_iter()),
351-
}
335+
GeneralDnsNameRef::try_from_ascii(presented_id.as_slice_less_safe()).ok()
336+
})
352337
}
353338

354339
// It is *not* valid to derive `Eq`, `PartialEq, etc. for this type. In

tests/integration.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,5 +346,5 @@ fn expect_cert_dns_names<'name>(
346346
.into_iter()
347347
.map(|name| GeneralDnsNameRef::try_from_ascii_str(name).unwrap());
348348

349-
assert!(cert.dns_names().unwrap().eq(expected_names));
349+
assert!(cert.dns_names().eq(expected_names));
350350
}

0 commit comments

Comments
 (0)