summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Kehrer <paul.l.kehrer@gmail.com>2023-05-07 11:01:33 -0500
committerGitHub <noreply@github.com>2023-05-07 16:01:33 +0000
commit0f2b72bb12b698e5787241a54ea9132837a1ec9c (patch)
tree06a1d9579b85b244d6f7f631608329e4ca9e078a
parent8ab4d1a58e6128f8c32981ee3f667e89d09c758b (diff)
downloadcryptography-0f2b72bb12b698e5787241a54ea9132837a1ec9c.tar.gz
invalid visible string support (#8884)
* invalid visible string support this allows utf8 in visiblestring, which is not valid DER. we raise a warning when this happens, but allow it since belgian eIDs, among others, have encoding errors. Belgium fixed this by 2021 (and possibly earlier), but their eID certificates have 10 year validity. * review comments * clippy
-rw-r--r--docs/development/test-vectors.rst2
-rw-r--r--src/cryptography/utils.py1
-rw-r--r--src/rust/cryptography-x509/src/common.rs37
-rw-r--r--src/rust/cryptography-x509/src/extensions.rs3
-rw-r--r--src/rust/src/x509/certificate.rs11
-rw-r--r--tests/x509/test_x509.py19
-rw-r--r--vectors/cryptography_vectors/x509/belgian-eid-invalid-visiblestring.pem37
7 files changed, 108 insertions, 2 deletions
diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst
index 1916c57c4..c84bdeff4 100644
--- a/docs/development/test-vectors.rst
+++ b/docs/development/test-vectors.rst
@@ -287,6 +287,8 @@ X.509
a subject DN with a bit string type.
* ``cryptography-scts-tbs-precert.der`` - The "to-be-signed" pre-certificate
bytes from ``cryptography-scts.pem``, with the SCT list extension removed.
+* ``belgian-eid-invalid-visiblestring.pem`` - A certificate with UTF-8
+ bytes in a ``VisibleString`` type.
Custom X.509 Vectors
~~~~~~~~~~~~~~~~~~~~
diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py
index 651e8509a..719168168 100644
--- a/src/cryptography/utils.py
+++ b/src/cryptography/utils.py
@@ -23,6 +23,7 @@ class CryptographyDeprecationWarning(UserWarning):
DeprecatedIn36 = CryptographyDeprecationWarning
DeprecatedIn37 = CryptographyDeprecationWarning
DeprecatedIn40 = CryptographyDeprecationWarning
+DeprecatedIn41 = CryptographyDeprecationWarning
def _check_bytes(name: str, value: bytes) -> None:
diff --git a/src/rust/cryptography-x509/src/common.rs b/src/rust/cryptography-x509/src/common.rs
index 65e583f11..9668ae237 100644
--- a/src/rust/cryptography-x509/src/common.rs
+++ b/src/rust/cryptography-x509/src/common.rs
@@ -206,13 +206,48 @@ pub struct DHParams<'a> {
pub q: Option<asn1::BigUint<'a>>,
}
+/// A VisibleString ASN.1 element whose contents is not validated as meeting the
+/// requirements (visible characters of IA5), and instead is only known to be
+/// valid UTF-8.
+pub struct UnvalidatedVisibleString<'a>(pub &'a str);
+
+impl<'a> UnvalidatedVisibleString<'a> {
+ pub fn as_str(&self) -> &'a str {
+ self.0
+ }
+}
+
+impl<'a> asn1::SimpleAsn1Readable<'a> for UnvalidatedVisibleString<'a> {
+ const TAG: asn1::Tag = asn1::VisibleString::TAG;
+ fn parse_data(data: &'a [u8]) -> asn1::ParseResult<Self> {
+ Ok(UnvalidatedVisibleString(
+ std::str::from_utf8(data)
+ .map_err(|_| asn1::ParseError::new(asn1::ParseErrorKind::InvalidValue))?,
+ ))
+ }
+}
+
+impl<'a> asn1::SimpleAsn1Writable for UnvalidatedVisibleString<'a> {
+ const TAG: asn1::Tag = asn1::VisibleString::TAG;
+ fn write_data(&self, _: &mut asn1::WriteBuf) -> asn1::WriteResult {
+ unimplemented!();
+ }
+}
+
#[cfg(test)]
mod tests {
- use super::{Asn1ReadableOrWritable, RawTlv};
+ use super::{Asn1ReadableOrWritable, RawTlv, UnvalidatedVisibleString};
use asn1::Asn1Readable;
#[test]
#[should_panic]
+ fn test_unvalidated_visible_string_write() {
+ let v = UnvalidatedVisibleString("foo");
+ asn1::write_single(&v).unwrap();
+ }
+
+ #[test]
+ #[should_panic]
fn test_asn1_readable_or_writable_unwrap_read() {
Asn1ReadableOrWritable::<u32, u32>::new_write(17).unwrap_read();
}
diff --git a/src/rust/cryptography-x509/src/extensions.rs b/src/rust/cryptography-x509/src/extensions.rs
index 11c6e54a4..0728633d4 100644
--- a/src/rust/cryptography-x509/src/extensions.rs
+++ b/src/rust/cryptography-x509/src/extensions.rs
@@ -87,7 +87,8 @@ pub struct NoticeReference<'a> {
pub enum DisplayText<'a> {
IA5String(asn1::IA5String<'a>),
Utf8String(asn1::Utf8String<'a>),
- VisibleString(asn1::VisibleString<'a>),
+ // Not validated due to certificates with UTF-8 in VisibleString. See PR #8884
+ VisibleString(common::UnvalidatedVisibleString<'a>),
BmpString(asn1::BMPString<'a>),
}
diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs
index 58dcf2d5d..98f1a073f 100644
--- a/src/rust/src/x509/certificate.rs
+++ b/src/rust/src/x509/certificate.rs
@@ -412,6 +412,17 @@ fn parse_display_text(
DisplayText::IA5String(o) => Ok(pyo3::types::PyString::new(py, o.as_str()).to_object(py)),
DisplayText::Utf8String(o) => Ok(pyo3::types::PyString::new(py, o.as_str()).to_object(py)),
DisplayText::VisibleString(o) => {
+ if asn1::VisibleString::new(o.as_str()).is_none() {
+ let cryptography_warning = py
+ .import(pyo3::intern!(py, "cryptography.utils"))?
+ .getattr(pyo3::intern!(py, "DeprecatedIn41"))?;
+ pyo3::PyErr::warn(
+ py,
+ cryptography_warning,
+ "Invalid ASN.1 (UTF-8 characters in a VisibleString) in the explicit text and/or notice reference of the certificate policies extension. In a future version of cryptography, an exception will be raised.",
+ 1,
+ )?;
+ }
Ok(pyo3::types::PyString::new(py, o.as_str()).to_object(py))
}
DisplayText::BmpString(o) => {
diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py
index 4a3fb26c6..1de45192b 100644
--- a/tests/x509/test_x509.py
+++ b/tests/x509/test_x509.py
@@ -1250,6 +1250,25 @@ class TestRSACertificate:
assert exc.value.parsed_version == 7
+ def test_invalid_visiblestring_in_explicit_text(self, backend):
+ cert = _load_cert(
+ os.path.join(
+ "x509",
+ "belgian-eid-invalid-visiblestring.pem",
+ ),
+ x509.load_pem_x509_certificate,
+ )
+ with pytest.warns(utils.DeprecatedIn41):
+ cp = cert.extensions.get_extension_for_class(
+ x509.CertificatePolicies
+ ).value
+ assert isinstance(cp, x509.CertificatePolicies)
+ assert cp[0].policy_qualifiers[1].explicit_text == (
+ "Gebruik onderworpen aan aansprakelijkheidsbeperkingen, zie CPS "
+ "- Usage soumis à des limitations de responsabilité, voir CPS - "
+ "Verwendung unterliegt Haftungsbeschränkungen, gemäss CPS"
+ )
+
def test_eq(self, backend):
cert = _load_cert(
os.path.join("x509", "custom", "post2000utctime.pem"),
diff --git a/vectors/cryptography_vectors/x509/belgian-eid-invalid-visiblestring.pem b/vectors/cryptography_vectors/x509/belgian-eid-invalid-visiblestring.pem
new file mode 100644
index 000000000..17650782f
--- /dev/null
+++ b/vectors/cryptography_vectors/x509/belgian-eid-invalid-visiblestring.pem
@@ -0,0 +1,37 @@
+-----BEGIN CERTIFICATE-----
+MIIGYzCCBEugAwIBAgIQEAAAAAAAdQQMgK5bRTyOHTANBgkqhkiG9w0BAQsFADAz
+MQswCQYDVQQGEwJCRTETMBEGA1UEAxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAx
+NjIzMB4XDTE2MDgyOTA5NDcwMFoXDTI2MDgyNDIzNTk1OVowbzELMAkGA1UEBhMC
+QkUxIjAgBgNVBAMTGUVsc2UgRGUgUHJvZnQgKFNpZ25hdHVyZSkxETAPBgNVBAQT
+CERlIFByb2Z0MRMwEQYDVQQqEwpFbHNlIEZyYW5zMRQwEgYDVQQFEws2OTA3MDMz
+ODg1MDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANSMFzc0v5Fr5GM3
+1cvaF7obKH1mNUR5cAcNPdLbC8U8SzOIvArBIKToYJRQIxgy7S/XOPs7p/cnidQe
+5yVNoIZlxWyB1nbbCR2c4rZJjzUz8bAXPKILjY7C+Q+Zxp6+8C6igDfd+n+eYuhU
+u1kxPvGiZ+m+DuKTfjzhQAqG0kZteqwwlipJkt7FDsLxsgcxPBpMDm02sVL5pTme
+rkY7mQpXZ5fpT2n2nzuNerxlfExeSdROAD/EZAxTAkuOgURWXmFBHPm0A9cipDYO
+foyPcMO5/7JUPv7LWhRoMr+XrTBOVmkFxccJ8EXRtNxNVujwbjeUJp7Z+20ST1h/
+rDyNOKMCAwEAAaOCAjUwggIxMB8GA1UdIwQYMBaAFIIiihHTwEk9pIiqBydUoV6f
+KmxqMHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVp
+ZC5iZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8v
+b2NzcC5laWQuYmVsZ2l1bS5iZS8yMIIBGAYDVR0gBIIBDzCCAQswggEHBgdgOAwB
+AQIBMIH7MCwGCCsGAQUFBwIBFiBodHRwOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1
+bS5iZTCBygYIKwYBBQUHAgIwgb0agbpHZWJydWlrIG9uZGVyd29ycGVuIGFhbiBh
+YW5zcHJha2VsaWpraGVpZHNiZXBlcmtpbmdlbiwgemllIENQUyAtIFVzYWdlIHNv
+dW1pcyDDoCBkZXMgbGltaXRhdGlvbnMgZGUgcmVzcG9uc2FiaWxpdMOpLCB2b2ly
+IENQUyAtIFZlcndlbmR1bmcgdW50ZXJsaWVndCBIYWZ0dW5nc2Jlc2NocsOkbmt1
+bmdlbiwgZ2Vtw6RzcyBDUFMwOQYDVR0fBDIwMDAuoCygKoYoaHR0cDovL2NybC5l
+aWQuYmVsZ2l1bS5iZS9laWRjMjAxNjIzLmNybDAOBgNVHQ8BAf8EBAMCBkAwEQYJ
+YIZIAYb4QgEBBAQDAgUgMCIGCCsGAQUFBwEDBBYwFDAIBgYEAI5GAQEwCAYGBACO
+RgEEMA0GCSqGSIb3DQEBCwUAA4ICAQABNGZci7JGuvzXfk5MJCX/2Py3M9//R9iN
+E/b8brMP6aCHJuDnEW7RcGAyleQQJYrTQnizWqoHRnkQ4BjQCZCpTEhERvCJz9KC
+J0L9+9M3TNDGLMY14Tu/h8Uga6vThXoxI4VK2Y3gEP5qWV0tMdbu+dLSLZ+O2qkj
+vtk8apYLn/2MGQ/srbu6HOLATvAKMtkF2za6zY0VL1Se9gHaHQdI9nnXKA3YD/7n
+C4UrqozruMqGRNCpWhD/fRgdHotRaD4ZDuC7hUZH2b+ldFII4tsZiXcVhX6RN7KF
+h5Ji/F2K9vqA0TbMWUEfiULSQfNc86LOd4riJ5VeVYtUl5kcrfVWMGBPQaq7c3OG
+G2L2x4rkB8mvRTeQZCU5ENuEZX34jZuKnv7pabdntzowE5VQWjLgFGQ7UyTFbImZ
+cR+H5djrrzO3Uvnu6a9v0ILGCLqES06pgH/apwtpHQPhvCWA8KBqf2aTgpZ8GsFI
+qTraP819yyr+GOOp/NO8EvcOsyjgWwzDvtpoLty3/wMXC5DBNoUb3W/uMju5MJ3E
+2dthCxnP7ES2PbdGTDK8Jtbgp5sJtfV6GCjgHDsIL5XGy6CagDghEG84TrYvKxTG
+PlmUThXhFRVjwv2tbpgFC7z/RwARqcNYxZKFKAHXCx6hWgSQbuEN5j6JFQh3ZUL+
+R2V64/XeBQ==
+-----END CERTIFICATE-----