Skip to content

Commit 43dad12

Browse files
committed
Better errors for ASN.1 string types
1 parent ca58360 commit 43dad12

File tree

3 files changed

+66
-32
lines changed

3 files changed

+66
-32
lines changed

rcgen/src/error.rs

+33-15
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,8 @@ pub enum Error {
1313
#[cfg(feature = "x509-parser")]
1414
/// Invalid subject alternative name type
1515
InvalidNameType,
16-
/// Invalid PrintableString type
17-
InvalidPrintableString,
18-
/// Invalide UniversalString type
19-
InvalidUniversalString,
20-
/// Invalid Ia5String type
21-
InvalidIa5String,
22-
/// Invalid TeletexString type
23-
InvalidTeletexString,
24-
/// Invalid BmpString type
25-
InvalidBmpString,
16+
/// Invalid ASN.1 string
17+
InvalidAsn1String(InvalidAsn1String),
2618
/// An IP address was provided as a byte array, but the byte array was an invalid length.
2719
InvalidIpAddressOctetLength(usize),
2820
/// There is no support for generating
@@ -65,11 +57,7 @@ impl fmt::Display for Error {
6557
CouldNotParseKeyPair => write!(f, "Could not parse key pair")?,
6658
#[cfg(feature = "x509-parser")]
6759
InvalidNameType => write!(f, "Invalid subject alternative name type")?,
68-
InvalidPrintableString => write!(f, "Invalid PrintableString")?,
69-
InvalidIa5String => write!(f, "Invalid IA5String")?,
70-
InvalidBmpString => write!(f, "Invalid BMPString")?,
71-
InvalidUniversalString => write!(f, "Invalid UniversalString")?,
72-
InvalidTeletexString => write!(f, "Invalid TeletexString")?,
60+
InvalidAsn1String(e) => write!(f, "{}", e)?,
7361
InvalidIpAddressOctetLength(actual) => {
7462
write!(f, "Invalid IP address octet length of {actual} bytes")?
7563
},
@@ -105,6 +93,36 @@ impl fmt::Display for Error {
10593

10694
impl std::error::Error for Error {}
10795

96+
/// Invalid ASN.1 string type
97+
#[derive(Debug, PartialEq, Eq)]
98+
#[non_exhaustive]
99+
pub enum InvalidAsn1String {
100+
/// Invalid PrintableString type
101+
PrintableString(String),
102+
/// Invalide UniversalString type
103+
UniversalString(String),
104+
/// Invalid Ia5String type
105+
Ia5String(String),
106+
/// Invalid TeletexString type
107+
TeletexString(String),
108+
/// Invalid BmpString type
109+
BmpString(String),
110+
}
111+
112+
impl fmt::Display for InvalidAsn1String {
113+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114+
use InvalidAsn1String::*;
115+
match self {
116+
PrintableString(s) => write!(f, "Invalid PrintableString: '{}'", s)?,
117+
Ia5String(s) => write!(f, "Invalid IA5String: '{}'", s)?,
118+
BmpString(s) => write!(f, "Invalid BMPString: '{}'", s)?,
119+
UniversalString(s) => write!(f, "Invalid UniversalString: '{}'", s)?,
120+
TeletexString(s) => write!(f, "Invalid TeletexString: '{}'", s)?,
121+
};
122+
Ok(())
123+
}
124+
}
125+
108126
/// A trait describing an error that can be converted into an `rcgen::Error`.
109127
///
110128
/// We use this trait to avoid leaking external error types into the public API

rcgen/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ pub use crate::crl::{
5656
CrlIssuingDistributionPoint, CrlScope, RevocationReason, RevokedCertParams,
5757
};
5858
pub use crate::csr::{CertificateSigningRequestParams, PublicKey};
59-
pub use crate::error::Error;
59+
pub use crate::error::{Error, InvalidAsn1String};
6060
use crate::key_pair::PublicKeyData;
6161
pub use crate::key_pair::{KeyPair, RemoteKeyPair};
6262
use crate::oid::*;

rcgen/src/string_types.rs

+32-16
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::Error;
1+
use crate::{Error, InvalidAsn1String};
22
use std::str::FromStr;
33

44
/// ASN.1 `PrintableString` type.
@@ -93,7 +93,11 @@ impl TryFrom<String> for PrintableString {
9393
| b':'
9494
| b'='
9595
| b'?' => (),
96-
_ => return Err(Error::InvalidPrintableString),
96+
_ => {
97+
return Err(Error::InvalidAsn1String(
98+
InvalidAsn1String::PrintableString(value),
99+
))
100+
},
97101
}
98102
}
99103
Ok(Self(value))
@@ -168,7 +172,9 @@ impl TryFrom<String> for Ia5String {
168172
/// See [`Ia5String`] documentation for more information.
169173
fn try_from(input: String) -> Result<Self, Error> {
170174
if !input.is_ascii() {
171-
return Err(Error::InvalidIa5String);
175+
return Err(Error::InvalidAsn1String(InvalidAsn1String::Ia5String(
176+
input,
177+
)));
172178
}
173179
Ok(Self(input))
174180
}
@@ -251,7 +257,9 @@ impl TryFrom<String> for TeletexString {
251257
fn try_from(input: String) -> Result<Self, Error> {
252258
// Check all bytes are visible
253259
if !input.as_bytes().iter().all(|b| (0x20..=0x7f).contains(b)) {
254-
return Err(Error::InvalidTeletexString);
260+
return Err(Error::InvalidAsn1String(InvalidAsn1String::TeletexString(
261+
input,
262+
)));
255263
}
256264
Ok(Self(input))
257265
}
@@ -318,7 +326,9 @@ impl BmpString {
318326
/// Decode a UTF-16BE–encoded vector `vec` into a `BmpString`, returning [Err](`std::result::Result::Err`) if `vec` contains any invalid data.
319327
pub fn from_utf16be(vec: Vec<u8>) -> Result<Self, Error> {
320328
if vec.len() % 2 != 0 {
321-
return Err(Error::InvalidBmpString);
329+
return Err(Error::InvalidAsn1String(InvalidAsn1String::BmpString(
330+
"Invalid UTF-16 encoding".to_string(),
331+
)));
322332
}
323333

324334
// FIXME: Update this when `array_chunks` is stabilized.
@@ -331,7 +341,11 @@ impl BmpString {
331341
// Character is in the Basic Multilingual Plane
332342
Ok(c) if (c as u64) < u64::from(u16::MAX) => (),
333343
// Characters outside Basic Multilingual Plane or unpaired surrogates
334-
_ => return Err(Error::InvalidBmpString),
344+
_ => {
345+
return Err(Error::InvalidAsn1String(InvalidAsn1String::BmpString(
346+
"Invalid UTF-16 encoding".to_string(),
347+
)));
348+
},
335349
}
336350
}
337351
Ok(Self(vec.to_vec()))
@@ -348,10 +362,9 @@ impl TryFrom<&str> for BmpString {
348362
///
349363
/// The result is allocated on the heap.
350364
fn try_from(value: &str) -> Result<Self, Self::Error> {
351-
let capacity = value
352-
.len()
353-
.checked_mul(2)
354-
.ok_or_else(|| Error::InvalidBmpString)?;
365+
let capacity = value.len().checked_mul(2).ok_or_else(|| {
366+
Error::InvalidAsn1String(InvalidAsn1String::BmpString(value.to_string()))
367+
})?;
355368

356369
let mut bytes = Vec::with_capacity(capacity);
357370

@@ -432,7 +445,9 @@ impl UniversalString {
432445
/// Decode a UTF-32BE–encoded vector `vec` into a `UniversalString`, returning [Err](`std::result::Result::Err`) if `vec` contains any invalid data.
433446
pub fn from_utf32be(vec: Vec<u8>) -> Result<UniversalString, Error> {
434447
if vec.len() % 4 != 0 {
435-
return Err(Error::InvalidUniversalString);
448+
return Err(Error::InvalidAsn1String(
449+
InvalidAsn1String::UniversalString("Invalid UTF-32 encoding".to_string()),
450+
));
436451
}
437452

438453
// FIXME: Update this when `array_chunks` is stabilized.
@@ -441,7 +456,9 @@ impl UniversalString {
441456
.map(|chunk| u32::from_be_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]))
442457
{
443458
if core::char::from_u32(maybe_char).is_none() {
444-
return Err(Error::InvalidUniversalString);
459+
return Err(Error::InvalidAsn1String(
460+
InvalidAsn1String::UniversalString("Invalid UTF-32 encoding".to_string()),
461+
));
445462
}
446463
}
447464

@@ -459,10 +476,9 @@ impl TryFrom<&str> for UniversalString {
459476
///
460477
/// The result is allocated on the heap.
461478
fn try_from(value: &str) -> Result<Self, Self::Error> {
462-
let capacity = value
463-
.len()
464-
.checked_mul(4)
465-
.ok_or_else(|| Error::InvalidUniversalString)?;
479+
let capacity = value.len().checked_mul(4).ok_or_else(|| {
480+
Error::InvalidAsn1String(InvalidAsn1String::UniversalString(value.to_string()))
481+
})?;
466482

467483
let mut bytes = Vec::with_capacity(capacity);
468484

0 commit comments

Comments
 (0)