aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2022-12-09 21:51:06 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2022-12-09 21:51:06 +0000
commitc72e9f07a9dc9940b306c511fd91be6f707e6be6 (patch)
treec0affd3a2a6ff5a102d41969ff042dd497b7b3bb
parentfc7a3870f7ac371af7ff47be9b6299201edea5d9 (diff)
parent5307b41af8dcf634fdfdf7954b90458026cb1208 (diff)
downloadder-c72e9f07a9dc9940b306c511fd91be6f707e6be6.tar.gz
Merge "Upgrade der to 0.6.1"main-16k-with-phones
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--Android.bp4
-rw-r--r--CHANGELOG.md12
-rw-r--r--Cargo.toml3
-rw-r--r--Cargo.toml.orig2
-rw-r--r--LICENSE-MIT25
-rw-r--r--METADATA13
-rw-r--r--src/asn1.rs4
-rw-r--r--src/asn1/any.rs10
-rw-r--r--src/asn1/bit_string.rs11
-rw-r--r--src/asn1/ia5_string.rs30
-rw-r--r--src/asn1/integer/bigint.rs8
-rw-r--r--src/asn1/octet_string.rs3
-rw-r--r--src/asn1/printable_string.rs34
-rw-r--r--src/asn1/teletex_string.rs144
-rw-r--r--src/asn1/utf8_string.rs30
-rw-r--r--src/asn1/videotex_string.rs143
-rw-r--r--src/lib.rs14
-rw-r--r--src/str_slice.rs2
-rw-r--r--src/tag.rs14
20 files changed, 413 insertions, 95 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index fd618ae..db1ff23 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
{
"git": {
- "sha1": "00f6c926a7aaed60441e17b93cd3e3fe5b93650e"
+ "sha1": "14164f9dccd1ba4ceed9938f792b4e99874ef8e0"
},
"path_in_vcs": "der"
} \ No newline at end of file
diff --git a/Android.bp b/Android.bp
index 0a0da6e..eec2405 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,8 +1,6 @@
// This file is generated by cargo2android.py --config cargo2android.json.
// Do not modify this file as changes will be overridden on upgrade.
-
-
package {
default_applicable_licenses: ["external_rust_crates_der_license"],
}
@@ -37,7 +35,7 @@ rust_library_host {
name: "libder",
crate_name: "der",
cargo_env_compat: true,
- cargo_pkg_version: "0.6.0",
+ cargo_pkg_version: "0.6.1",
srcs: ["src/lib.rs"],
edition: "2021",
features: [
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 451056d..0472850 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## 0.6.1 (2022-12-05)
+### Added
+- Rudimentary implementation of `TeletexString` and `VideotexString` ([#691])
+- Impl `ValueOrd` for `FlagSet<T>` and `UIntRef` ([#723])
+
+### Changed
+- Eliminate some boilerplate code by using `Deref` ([#697])
+
+[#691]: https://github.com/RustCrypto/formats/pull/691
+[#697]: https://github.com/RustCrypto/formats/pull/697
+[#723]: https://github.com/RustCrypto/formats/pull/723
+
## 0.6.0 (2022-05-08)
### Added
- Impl `ValueOrd` for `SetOf` and `SetOfVec` ([#362])
diff --git a/Cargo.toml b/Cargo.toml
index f7822e0..1296c9f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@
edition = "2021"
rust-version = "1.57"
name = "der"
-version = "0.6.0"
+version = "0.6.1"
authors = ["RustCrypto Developers"]
description = """
Pure Rust embedded-friendly implementation of the Distinguished Encoding Rules
@@ -36,7 +36,6 @@ categories = [
]
license = "Apache-2.0 OR MIT"
repository = "https://github.com/RustCrypto/formats/tree/master/der"
-resolver = "2"
[package.metadata.docs.rs]
all-features = true
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 7c34417..f8c7dfe 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
[package]
name = "der"
-version = "0.6.0"
+version = "0.6.1"
description = """
Pure Rust embedded-friendly implementation of the Distinguished Encoding Rules
(DER) for Abstract Syntax Notation One (ASN.1) as described in ITU X.690 with
diff --git a/LICENSE-MIT b/LICENSE-MIT
new file mode 100644
index 0000000..1b78809
--- /dev/null
+++ b/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2020-2022 The RustCrypto Project Developers
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/METADATA b/METADATA
index 427d79a..3217d88 100644
--- a/METADATA
+++ b/METADATA
@@ -1,3 +1,7 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update rust/crates/der
+# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+
name: "der"
description: "Pure Rust embedded-friendly implementation of the Distinguished Encoding Rules (DER) for Abstract Syntax Notation One (ASN.1) as described in ITU X.690."
third_party {
@@ -7,14 +11,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/der/der-0.6.0.crate"
+ value: "https://static.crates.io/crates/der/der-0.6.1.crate"
}
- version: "0.6.0"
- # Dual-licensed, using the least restrictive per go/thirdpartylicenses#same.
+ version: "0.6.1"
license_type: NOTICE
last_upgrade_date {
year: 2022
- month: 8
- day: 31
+ month: 12
+ day: 9
}
}
diff --git a/src/asn1.rs b/src/asn1.rs
index 0f7290c..34d692b 100644
--- a/src/asn1.rs
+++ b/src/asn1.rs
@@ -20,8 +20,10 @@ mod real;
mod sequence;
mod sequence_of;
mod set_of;
+mod teletex_string;
mod utc_time;
mod utf8_string;
+mod videotex_string;
pub use self::{
any::AnyRef,
@@ -37,8 +39,10 @@ pub use self::{
sequence::{Sequence, SequenceRef},
sequence_of::{SequenceOf, SequenceOfIter},
set_of::{SetOf, SetOfIter},
+ teletex_string::TeletexStringRef,
utc_time::UtcTime,
utf8_string::Utf8StringRef,
+ videotex_string::VideotexStringRef,
};
#[cfg(feature = "alloc")]
diff --git a/src/asn1/any.rs b/src/asn1/any.rs
index 717d666..cb65f23 100644
--- a/src/asn1/any.rs
+++ b/src/asn1/any.rs
@@ -128,6 +128,16 @@ impl<'a> AnyRef<'a> {
self.try_into()
}
+ /// Attempt to decode an ASN.1 `TeletexString`.
+ pub fn teletex_string(self) -> Result<TeletexStringRef<'a>> {
+ self.try_into()
+ }
+
+ /// Attempt to decode an ASN.1 `VideotexString`.
+ pub fn videotex_string(self) -> Result<VideotexStringRef<'a>> {
+ self.try_into()
+ }
+
/// Attempt to decode this value an ASN.1 `SEQUENCE`, creating a new
/// nested reader and calling the provided argument with it.
pub fn sequence<F, T>(self, f: F) -> Result<T>
diff --git a/src/asn1/bit_string.rs b/src/asn1/bit_string.rs
index 7eea5a5..eed14e4 100644
--- a/src/asn1/bit_string.rs
+++ b/src/asn1/bit_string.rs
@@ -376,6 +376,17 @@ impl<T: flagset::Flags> FixedTag for flagset::FlagSet<T> {
}
#[cfg(feature = "flagset")]
+impl<T> ValueOrd for flagset::FlagSet<T>
+where
+ T: flagset::Flags,
+ T::Type: Ord,
+{
+ fn value_cmp(&self, other: &Self) -> Result<Ordering> {
+ Ok(self.bits().cmp(&other.bits()))
+ }
+}
+
+#[cfg(feature = "flagset")]
#[allow(clippy::integer_arithmetic)]
impl<'a, T> DecodeValue<'a> for flagset::FlagSet<T>
where
diff --git a/src/asn1/ia5_string.rs b/src/asn1/ia5_string.rs
index c1dbfaa..3971270 100644
--- a/src/asn1/ia5_string.rs
+++ b/src/asn1/ia5_string.rs
@@ -4,7 +4,7 @@ use crate::{
asn1::AnyRef, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, FixedTag, Header,
Length, Reader, Result, StrSlice, Tag, Writer,
};
-use core::{fmt, str};
+use core::{fmt, ops::Deref, str};
/// ASN.1 `IA5String` type.
///
@@ -41,25 +41,13 @@ impl<'a> Ia5StringRef<'a> {
.map(|inner| Self { inner })
.map_err(|_| Self::TAG.value_error())
}
+}
- /// Borrow the string as a `str`.
- pub fn as_str(&self) -> &'a str {
- self.inner.as_str()
- }
+impl<'a> Deref for Ia5StringRef<'a> {
+ type Target = StrSlice<'a>;
- /// Borrow the string as bytes.
- pub fn as_bytes(&self) -> &'a [u8] {
- self.inner.as_bytes()
- }
-
- /// Get the length of the inner byte slice.
- pub fn len(&self) -> Length {
- self.inner.len()
- }
-
- /// Is the inner string empty?
- pub fn is_empty(&self) -> bool {
- self.inner.is_empty()
+ fn deref(&self) -> &Self::Target {
+ &self.inner
}
}
@@ -117,12 +105,6 @@ impl<'a> From<Ia5StringRef<'a>> for AnyRef<'a> {
}
}
-impl<'a> From<Ia5StringRef<'a>> for &'a [u8] {
- fn from(printable_string: Ia5StringRef<'a>) -> &'a [u8] {
- printable_string.as_bytes()
- }
-}
-
impl<'a> fmt::Display for Ia5StringRef<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
diff --git a/src/asn1/integer/bigint.rs b/src/asn1/integer/bigint.rs
index 7a73c48..f896406 100644
--- a/src/asn1/integer/bigint.rs
+++ b/src/asn1/integer/bigint.rs
@@ -2,8 +2,8 @@
use super::uint;
use crate::{
- asn1::AnyRef, ByteSlice, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length,
- Reader, Result, Tag, Writer,
+ asn1::AnyRef, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, ErrorKind,
+ FixedTag, Header, Length, Reader, Result, Tag, Writer,
};
/// "Big" unsigned ASN.1 `INTEGER` type.
@@ -13,7 +13,7 @@ use crate::{
///
/// Intended for use cases like very large integers that are used in
/// cryptographic applications (e.g. keys, signatures).
-#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct UIntRef<'a> {
/// Inner value
inner: ByteSlice<'a>,
@@ -92,6 +92,8 @@ impl<'a> FixedTag for UIntRef<'a> {
const TAG: Tag = Tag::Integer;
}
+impl<'a> OrdIsValueOrd for UIntRef<'a> {}
+
#[cfg(test)]
mod tests {
use super::UIntRef;
diff --git a/src/asn1/octet_string.rs b/src/asn1/octet_string.rs
index 9f78c96..6f5b91a 100644
--- a/src/asn1/octet_string.rs
+++ b/src/asn1/octet_string.rs
@@ -177,3 +177,6 @@ impl<'a> From<&'a OctetString> for OctetStringRef<'a> {
OctetStringRef::new(&octet_string.inner).expect("invalid OCTET STRING")
}
}
+
+#[cfg(feature = "alloc")]
+impl OrdIsValueOrd for OctetString {}
diff --git a/src/asn1/printable_string.rs b/src/asn1/printable_string.rs
index c5560a0..d48f90f 100644
--- a/src/asn1/printable_string.rs
+++ b/src/asn1/printable_string.rs
@@ -4,11 +4,11 @@ use crate::{
asn1::AnyRef, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, FixedTag, Header,
Length, Reader, Result, StrSlice, Tag, Writer,
};
-use core::{fmt, str};
+use core::{fmt, ops::Deref, str};
/// ASN.1 `PrintableString` type.
///
-/// Supports a subset the ASCII character set (desribed below).
+/// Supports a subset the ASCII character set (described below).
///
/// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead.
/// For the full ASCII character set, use
@@ -49,7 +49,7 @@ impl<'a> PrintableStringRef<'a> {
{
let input = input.as_ref();
- // Validate all characters are within PrintedString's allowed set
+ // Validate all characters are within PrintableString's allowed set
for &c in input.iter() {
match c {
b'A'..=b'Z'
@@ -75,25 +75,13 @@ impl<'a> PrintableStringRef<'a> {
.map(|inner| Self { inner })
.map_err(|_| Self::TAG.value_error())
}
+}
- /// Borrow the string as a `str`.
- pub fn as_str(&self) -> &'a str {
- self.inner.as_str()
- }
+impl<'a> Deref for PrintableStringRef<'a> {
+ type Target = StrSlice<'a>;
- /// Borrow the string as bytes.
- pub fn as_bytes(&self) -> &'a [u8] {
- self.inner.as_bytes()
- }
-
- /// Get the length of the inner byte slice.
- pub fn len(&self) -> Length {
- self.inner.len()
- }
-
- /// Is the inner string empty?
- pub fn is_empty(&self) -> bool {
- self.inner.is_empty()
+ fn deref(&self) -> &Self::Target {
+ &self.inner
}
}
@@ -151,12 +139,6 @@ impl<'a> From<PrintableStringRef<'a>> for AnyRef<'a> {
}
}
-impl<'a> From<PrintableStringRef<'a>> for &'a [u8] {
- fn from(printable_string: PrintableStringRef<'a>) -> &'a [u8] {
- printable_string.as_bytes()
- }
-}
-
impl<'a> fmt::Display for PrintableStringRef<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
diff --git a/src/asn1/teletex_string.rs b/src/asn1/teletex_string.rs
new file mode 100644
index 0000000..7d6621d
--- /dev/null
+++ b/src/asn1/teletex_string.rs
@@ -0,0 +1,144 @@
+//! ASN.1 `TeletexString` support.
+
+use crate::{
+ asn1::AnyRef, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, FixedTag, Header,
+ Length, Reader, Result, StrSlice, Tag, Writer,
+};
+use core::{fmt, ops::Deref, str};
+
+/// ASN.1 `TeletexString` type.
+///
+/// Supports a subset the ASCII character set (described below).
+///
+/// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead.
+/// For the full ASCII character set, use
+/// [`Ia5StringRef`][`crate::asn1::Ia5StringRef`].
+///
+/// This is a zero-copy reference type which borrows from the input data.
+///
+/// # Supported characters
+///
+/// The standard defines a complex character set allowed in this type. However, quoting the ASN.1
+/// mailing list, "a sizable volume of software in the world treats TeletexString (T61String) as a
+/// simple 8-bit string with mostly Windows Latin 1 (superset of iso-8859-1) encoding".
+///
+#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
+pub struct TeletexStringRef<'a> {
+ /// Inner value
+ inner: StrSlice<'a>,
+}
+
+impl<'a> TeletexStringRef<'a> {
+ /// Create a new ASN.1 `TeletexString`.
+ pub fn new<T>(input: &'a T) -> Result<Self>
+ where
+ T: AsRef<[u8]> + ?Sized,
+ {
+ let input = input.as_ref();
+
+ // FIXME: support higher part of the charset
+ if input.iter().any(|&c| c > 0x7F) {
+ return Err(Self::TAG.value_error());
+ }
+
+ StrSlice::from_bytes(input)
+ .map(|inner| Self { inner })
+ .map_err(|_| Self::TAG.value_error())
+ }
+}
+
+impl<'a> Deref for TeletexStringRef<'a> {
+ type Target = StrSlice<'a>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.inner
+ }
+}
+
+impl AsRef<str> for TeletexStringRef<'_> {
+ fn as_ref(&self) -> &str {
+ self.as_str()
+ }
+}
+
+impl AsRef<[u8]> for TeletexStringRef<'_> {
+ fn as_ref(&self) -> &[u8] {
+ self.as_bytes()
+ }
+}
+
+impl<'a> DecodeValue<'a> for TeletexStringRef<'a> {
+ fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
+ Self::new(ByteSlice::decode_value(reader, header)?.as_slice())
+ }
+}
+
+impl<'a> EncodeValue for TeletexStringRef<'a> {
+ fn value_len(&self) -> Result<Length> {
+ self.inner.value_len()
+ }
+
+ fn encode_value(&self, writer: &mut dyn Writer) -> Result<()> {
+ self.inner.encode_value(writer)
+ }
+}
+
+impl FixedTag for TeletexStringRef<'_> {
+ const TAG: Tag = Tag::TeletexString;
+}
+
+impl OrdIsValueOrd for TeletexStringRef<'_> {}
+
+impl<'a> From<&TeletexStringRef<'a>> for TeletexStringRef<'a> {
+ fn from(value: &TeletexStringRef<'a>) -> TeletexStringRef<'a> {
+ *value
+ }
+}
+
+impl<'a> TryFrom<AnyRef<'a>> for TeletexStringRef<'a> {
+ type Error = Error;
+
+ fn try_from(any: AnyRef<'a>) -> Result<TeletexStringRef<'a>> {
+ any.decode_into()
+ }
+}
+
+impl<'a> From<TeletexStringRef<'a>> for AnyRef<'a> {
+ fn from(teletex_string: TeletexStringRef<'a>) -> AnyRef<'a> {
+ AnyRef::from_tag_and_value(Tag::TeletexString, teletex_string.inner.into())
+ }
+}
+
+impl<'a> fmt::Display for TeletexStringRef<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(self.as_str())
+ }
+}
+
+impl<'a> fmt::Debug for TeletexStringRef<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "TeletexString({:?})", self.as_str())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::TeletexStringRef;
+ use crate::Decode;
+ use crate::SliceWriter;
+
+ #[test]
+ fn parse_bytes() {
+ let example_bytes = &[
+ 0x14, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x65, 0x72, 0x20, 0x31,
+ ];
+
+ let teletex_string = TeletexStringRef::from_der(example_bytes).unwrap();
+ assert_eq!(teletex_string.as_str(), "Test User 1");
+ let mut out = [0_u8; 30];
+ let mut writer = SliceWriter::new(&mut out);
+ writer.encode(&teletex_string).unwrap();
+ let encoded = writer.finish().unwrap();
+ assert_eq!(encoded, example_bytes);
+ }
+}
diff --git a/src/asn1/utf8_string.rs b/src/asn1/utf8_string.rs
index 9f7a1bc..1a06411 100644
--- a/src/asn1/utf8_string.rs
+++ b/src/asn1/utf8_string.rs
@@ -4,7 +4,7 @@ use crate::{
asn1::AnyRef, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, FixedTag, Header,
Length, Reader, Result, StrSlice, Tag, Writer,
};
-use core::{fmt, str};
+use core::{fmt, ops::Deref, str};
#[cfg(feature = "alloc")]
use alloc::{borrow::ToOwned, string::String};
@@ -37,25 +37,13 @@ impl<'a> Utf8StringRef<'a> {
{
StrSlice::from_bytes(input.as_ref()).map(|inner| Self { inner })
}
+}
- /// Borrow the string as a `str`.
- pub fn as_str(&self) -> &'a str {
- self.inner.as_str()
- }
+impl<'a> Deref for Utf8StringRef<'a> {
+ type Target = StrSlice<'a>;
- /// Borrow the string as bytes.
- pub fn as_bytes(&self) -> &'a [u8] {
- self.inner.as_bytes()
- }
-
- /// Get the length of the inner byte slice.
- pub fn len(&self) -> Length {
- self.inner.len()
- }
-
- /// Is the inner string empty?
- pub fn is_empty(&self) -> bool {
- self.inner.is_empty()
+ fn deref(&self) -> &Self::Target {
+ &self.inner
}
}
@@ -113,12 +101,6 @@ impl<'a> From<Utf8StringRef<'a>> for AnyRef<'a> {
}
}
-impl<'a> From<Utf8StringRef<'a>> for &'a [u8] {
- fn from(utf8_string: Utf8StringRef<'a>) -> &'a [u8] {
- utf8_string.as_bytes()
- }
-}
-
impl<'a> fmt::Display for Utf8StringRef<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
diff --git a/src/asn1/videotex_string.rs b/src/asn1/videotex_string.rs
new file mode 100644
index 0000000..b758a22
--- /dev/null
+++ b/src/asn1/videotex_string.rs
@@ -0,0 +1,143 @@
+//! ASN.1 `VideotexString` support.
+
+use crate::{
+ asn1::AnyRef, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, FixedTag, Header,
+ Length, Reader, Result, StrSlice, Tag, Writer,
+};
+use core::{fmt, ops::Deref, str};
+
+/// ASN.1 `VideotexString` type.
+///
+/// Supports a subset the ASCII character set (described below).
+///
+/// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead.
+/// For the full ASCII character set, use
+/// [`Ia5StringRef`][`crate::asn1::Ia5StringRef`].
+///
+/// This is a zero-copy reference type which borrows from the input data.
+///
+/// # Supported characters
+///
+/// For the practical purposes VideotexString is treated as IA5string, disallowing non-ASCII chars.
+///
+#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
+pub struct VideotexStringRef<'a> {
+ /// Inner value
+ inner: StrSlice<'a>,
+}
+
+impl<'a> VideotexStringRef<'a> {
+ /// Create a new ASN.1 `VideotexString`.
+ pub fn new<T>(input: &'a T) -> Result<Self>
+ where
+ T: AsRef<[u8]> + ?Sized,
+ {
+ let input = input.as_ref();
+
+ // Validate all characters are within VideotexString's allowed set
+ // FIXME: treat as if it were IA5String
+ if input.iter().any(|&c| c > 0x7F) {
+ return Err(Self::TAG.value_error());
+ }
+
+ StrSlice::from_bytes(input)
+ .map(|inner| Self { inner })
+ .map_err(|_| Self::TAG.value_error())
+ }
+}
+
+impl<'a> Deref for VideotexStringRef<'a> {
+ type Target = StrSlice<'a>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.inner
+ }
+}
+
+impl AsRef<str> for VideotexStringRef<'_> {
+ fn as_ref(&self) -> &str {
+ self.as_str()
+ }
+}
+
+impl AsRef<[u8]> for VideotexStringRef<'_> {
+ fn as_ref(&self) -> &[u8] {
+ self.as_bytes()
+ }
+}
+
+impl<'a> DecodeValue<'a> for VideotexStringRef<'a> {
+ fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
+ Self::new(ByteSlice::decode_value(reader, header)?.as_slice())
+ }
+}
+
+impl<'a> EncodeValue for VideotexStringRef<'a> {
+ fn value_len(&self) -> Result<Length> {
+ self.inner.value_len()
+ }
+
+ fn encode_value(&self, writer: &mut dyn Writer) -> Result<()> {
+ self.inner.encode_value(writer)
+ }
+}
+
+impl FixedTag for VideotexStringRef<'_> {
+ const TAG: Tag = Tag::VideotexString;
+}
+
+impl OrdIsValueOrd for VideotexStringRef<'_> {}
+
+impl<'a> From<&VideotexStringRef<'a>> for VideotexStringRef<'a> {
+ fn from(value: &VideotexStringRef<'a>) -> VideotexStringRef<'a> {
+ *value
+ }
+}
+
+impl<'a> TryFrom<AnyRef<'a>> for VideotexStringRef<'a> {
+ type Error = Error;
+
+ fn try_from(any: AnyRef<'a>) -> Result<VideotexStringRef<'a>> {
+ any.decode_into()
+ }
+}
+
+impl<'a> From<VideotexStringRef<'a>> for AnyRef<'a> {
+ fn from(printable_string: VideotexStringRef<'a>) -> AnyRef<'a> {
+ AnyRef::from_tag_and_value(Tag::VideotexString, printable_string.inner.into())
+ }
+}
+
+impl<'a> From<VideotexStringRef<'a>> for &'a [u8] {
+ fn from(printable_string: VideotexStringRef<'a>) -> &'a [u8] {
+ printable_string.as_bytes()
+ }
+}
+
+impl<'a> fmt::Display for VideotexStringRef<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(self.as_str())
+ }
+}
+
+impl<'a> fmt::Debug for VideotexStringRef<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "VideotexString({:?})", self.as_str())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::VideotexStringRef;
+ use crate::Decode;
+
+ #[test]
+ fn parse_bytes() {
+ let example_bytes = &[
+ 0x15, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x65, 0x72, 0x20, 0x31,
+ ];
+
+ let printable_string = VideotexStringRef::from_der(example_bytes).unwrap();
+ assert_eq!(printable_string.as_str(), "Test User 1");
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index f16857b..c8e7945 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,8 +2,8 @@
#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc = include_str!("../README.md")]
#![doc(
- html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
- html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
+ html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
+ html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
)]
#![forbid(unsafe_code)]
#![warn(
@@ -52,6 +52,8 @@
//! - [`ObjectIdentifier`]: ASN.1 `OBJECT IDENTIFIER`.
//! - [`OctetString`], [`OctetStringRef`]: ASN.1 `OCTET STRING`.
//! - [`PrintableStringRef`]: ASN.1 `PrintableString` (ASCII subset).
+//! - [`TeletexStringRef`]: ASN.1 `TeletexString`.
+//! - [`VideotexStringRef`]: ASN.1 `VideotexString`.
//! - [`SequenceOf`]: ASN.1 `SEQUENCE OF`.
//! - [`SetOf`], [`SetOfVec`]: ASN.1 `SET OF`.
//! - [`UIntRef`]: ASN.1 unsigned `INTEGER` with raw access to encoded bytes.
@@ -308,19 +310,21 @@
//! [A Layman's Guide to a Subset of ASN.1, BER, and DER]: https://luca.ntop.org/Teaching/Appunti/asn1.html
//! [A Warm Welcome to ASN.1 and DER]: https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/
//!
-//! [`Any`]: asn1::AnyRef
+//! [`Any`]: asn1::Any
//! [`AnyRef`]: asn1::AnyRef
//! [`ContextSpecific`]: asn1::ContextSpecific
//! [`ContextSpecificRef`]: asn1::ContextSpecificRef
-//! [`BitString`]: asn1::BitStringRef
+//! [`BitString`]: asn1::BitString
//! [`BitStringRef`]: asn1::BitStringRef
//! [`GeneralizedTime`]: asn1::GeneralizedTime
//! [`Ia5StringRef`]: asn1::Ia5StringRef
//! [`Null`]: asn1::Null
//! [`ObjectIdentifier`]: asn1::ObjectIdentifier
-//! [`OctetString`]: asn1::OctetStringRef
+//! [`OctetString`]: asn1::OctetString
//! [`OctetStringRef`]: asn1::OctetStringRef
//! [`PrintableStringRef`]: asn1::PrintableStringRef
+//! [`TeletexStringRef`]: asn1::TeletexStringRef
+//! [`VideotexStringRef`]: asn1::VideotexStringRef
//! [`SequenceOf`]: asn1::SequenceOf
//! [`SetOf`]: asn1::SetOf
//! [`SetOfVec`]: asn1::SetOfVec
diff --git a/src/str_slice.rs b/src/str_slice.rs
index 0016e95..8c94528 100644
--- a/src/str_slice.rs
+++ b/src/str_slice.rs
@@ -6,7 +6,7 @@ use core::str;
/// String slice newtype which respects the [`Length::max`] limit.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
-pub(crate) struct StrSlice<'a> {
+pub struct StrSlice<'a> {
/// Inner value
pub(crate) inner: &'a str,
diff --git a/src/tag.rs b/src/tag.rs
index 4906abb..0e7bf20 100644
--- a/src/tag.rs
+++ b/src/tag.rs
@@ -88,6 +88,12 @@ pub enum Tag {
/// `PrintableString` tag: `19`.
PrintableString,
+ /// `TeletexString` tag: `20`.
+ TeletexString,
+
+ /// `VideotexString` tag: `21`.
+ VideotexString,
+
/// `IA5String` tag: `22`.
Ia5String,
@@ -199,6 +205,8 @@ impl Tag {
Tag::Set => 0x11 | CONSTRUCTED_FLAG,
Tag::NumericString => 0x12,
Tag::PrintableString => 0x13,
+ Tag::TeletexString => 0x14,
+ Tag::VideotexString => 0x15,
Tag::Ia5String => 0x16,
Tag::UtcTime => 0x17,
Tag::GeneralizedTime => 0x18,
@@ -266,6 +274,8 @@ impl TryFrom<u8> for Tag {
0x0C => Ok(Tag::Utf8String),
0x12 => Ok(Tag::NumericString),
0x13 => Ok(Tag::PrintableString),
+ 0x14 => Ok(Tag::TeletexString),
+ 0x15 => Ok(Tag::VideotexString),
0x16 => Ok(Tag::Ia5String),
0x17 => Ok(Tag::UtcTime),
0x18 => Ok(Tag::GeneralizedTime),
@@ -341,6 +351,8 @@ impl fmt::Display for Tag {
Tag::Set => f.write_str("SET"),
Tag::NumericString => f.write_str("NumericString"),
Tag::PrintableString => f.write_str("PrintableString"),
+ Tag::TeletexString => f.write_str("TeletexString"),
+ Tag::VideotexString => f.write_str("VideotexString"),
Tag::Ia5String => f.write_str("IA5String"),
Tag::UtcTime => f.write_str("UTCTime"),
Tag::GeneralizedTime => f.write_str("GeneralizedTime"),
@@ -403,6 +415,8 @@ mod tests {
assert_eq!(Tag::Set.class(), Class::Universal);
assert_eq!(Tag::NumericString.class(), Class::Universal);
assert_eq!(Tag::PrintableString.class(), Class::Universal);
+ assert_eq!(Tag::TeletexString.class(), Class::Universal);
+ assert_eq!(Tag::VideotexString.class(), Class::Universal);
assert_eq!(Tag::Ia5String.class(), Class::Universal);
assert_eq!(Tag::UtcTime.class(), Class::Universal);
assert_eq!(Tag::GeneralizedTime.class(), Class::Universal);