From c67a48d55f35a95ceb8b5c13437af82603829d5b Mon Sep 17 00:00:00 2001 From: Jeff Vander Stoep Date: Thu, 8 Dec 2022 12:41:05 +0100 Subject: Upgrade const-oid to 0.9.1 This project was upgraded with external_updater. Usage: tools/external_updater/updater.sh update rust/crates/const-oid For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md Test: TreeHugger Change-Id: I8c67c6d4557e0ef828403f5a271e5f987c04e97e --- .cargo_vcs_info.json | 2 +- Android.bp | 4 +--- CHANGELOG.md | 8 ++++++++ Cargo.toml | 31 +++++++++++++++++++++++++------ Cargo.toml.orig | 2 +- LICENSE-MIT | 25 +++++++++++++++++++++++++ METADATA | 13 ++++++++----- README.md | 2 +- src/arcs.rs | 19 ++++++++++++++++--- src/checked.rs | 11 +++++++++++ src/db.rs | 2 +- src/encoder.rs | 9 ++++++++- src/error.rs | 18 ++++++++++++++++++ src/lib.rs | 51 +++++++++++++++++++++++++++++++++++++-------------- src/parser.rs | 2 ++ 15 files changed, 163 insertions(+), 36 deletions(-) create mode 100644 LICENSE-MIT create mode 100644 src/checked.rs diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 65a697a..80de78a 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "87223cd4203097729be3fad21d23ef183405991b" + "sha1": "252671f5828a6df3c1a31222519cd278c8704e4b" }, "path_in_vcs": "const-oid" } \ No newline at end of file diff --git a/Android.bp b/Android.bp index c6af18a..334199c 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_const-oid_license"], } @@ -37,7 +35,7 @@ rust_library_host { name: "libconst_oid", crate_name: "const_oid", cargo_env_compat: true, - cargo_pkg_version: "0.9.0", + cargo_pkg_version: "0.9.1", srcs: ["src/lib.rs"], edition: "2021", features: ["db"], diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dcb4fb..f6ea7d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ 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.9.1 (2022-11-12) +### Added +- clippy lints for checked arithmetic and panics ([#561]) +- `DynAssociatedOid` trait ([#758]) + +[#561]: https://github.com/RustCrypto/formats/pull/561 +[#758]: https://github.com/RustCrypto/formats/pull/758 + ## 0.9.0 (2022-03-11) ### Added - Fallible `const fn` parser + `::new_unwrap` ([#458], [#459]) diff --git a/Cargo.toml b/Cargo.toml index d45e11e..0080b6f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,19 +13,38 @@ edition = "2021" rust-version = "1.57" name = "const-oid" -version = "0.9.0" +version = "0.9.1" authors = ["RustCrypto Developers"] -description = "Const-friendly implementation of the ISO/IEC Object Identifier (OID) standard\nas defined in ITU X.660, with support for BER/DER encoding/decoding as well as\nheapless no_std (i.e. embedded) support\n" +description = """ +Const-friendly implementation of the ISO/IEC Object Identifier (OID) standard +as defined in ITU X.660, with support for BER/DER encoding/decoding as well as +heapless no_std (i.e. embedded) support +""" documentation = "https://docs.rs/const-oid" readme = "README.md" -keywords = ["iso", "iec", "itu", "oid"] -categories = ["cryptography", "data-structures", "encoding", "no-std", "parser-implementations"] +keywords = [ + "iso", + "iec", + "itu", + "oid", +] +categories = [ + "cryptography", + "data-structures", + "encoding", + "no-std", + "parser-implementations", +] license = "Apache-2.0 OR MIT" repository = "https://github.com/RustCrypto/formats/tree/master/const-oid" -resolver = "2" + [package.metadata.docs.rs] all-features = true -rustdoc-args = ["--cfg", "docsrs"] +rustdoc-args = [ + "--cfg", + "docsrs", +] + [dev-dependencies.hex-literal] version = "0.3" diff --git a/Cargo.toml.orig b/Cargo.toml.orig index 5978809..ffc05e6 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "const-oid" -version = "0.9.0" +version = "0.9.1" authors = ["RustCrypto Developers"] license = "Apache-2.0 OR MIT" description = """ 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 6afb80d..c994f5c 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/const-oid +# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md + name: "const-oid" description: "Const-friendly implementation of the ISO/IEC Object Identifier (OID) standard as defined in ITU X.660, with support for BER/DER encoding/decoding as well as heapless no_std (i.e. embedded) support" third_party { @@ -7,14 +11,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/const-oid/const-oid-0.9.0.crate" + value: "https://static.crates.io/crates/const-oid/const-oid-0.9.1.crate" } - version: "0.9.0" - # Dual-licensed, using the least restrictive per go/thirdpartylicenses#same. + version: "0.9.1" license_type: NOTICE last_upgrade_date { year: 2022 - month: 8 - day: 19 + month: 12 + day: 8 } } diff --git a/README.md b/README.md index bd6dbad..fae3cfc 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ dual licensed as above, without any additional terms or conditions. [//]: # (badges) -[crate-image]: https://img.shields.io/crates/v/const-oid.svg +[crate-image]: https://buildstats.info/crate/const-oid [crate-link]: https://crates.io/crates/const-oid [docs-image]: https://docs.rs/const-oid/badge.svg [docs-link]: https://docs.rs/const-oid/ diff --git a/src/arcs.rs b/src/arcs.rs index b3f9f24..7bf7a9a 100644 --- a/src/arcs.rs +++ b/src/arcs.rs @@ -66,9 +66,15 @@ impl<'a> Arcs<'a> { let mut arc_bytes = 0; loop { - match self.oid.as_bytes().get(offset + arc_bytes).cloned() { + let len = checked_add!(offset, arc_bytes); + + match self.oid.as_bytes().get(len).cloned() { + // The arithmetic below includes advance checks + // against `ARC_MAX_BYTES` and `ARC_MAX_LAST_OCTET` + // which ensure the operations will not overflow. + #[allow(clippy::integer_arithmetic)] Some(byte) => { - arc_bytes += 1; + arc_bytes = checked_add!(arc_bytes, 1); if (arc_bytes > ARC_MAX_BYTES) && (byte & ARC_MAX_LAST_OCTET != 0) { return Err(Error::ArcTooBig); @@ -77,7 +83,7 @@ impl<'a> Arcs<'a> { result = result << 7 | (byte & 0b1111111) as Arc; if byte & 0b10000000 == 0 { - self.cursor = Some(offset + arc_bytes); + self.cursor = Some(checked_add!(offset, arc_bytes)); return Ok(Some(result)); } } @@ -123,16 +129,21 @@ impl RootArcs { return Err(Error::ArcInvalid { arc: second_arc }); } + // The checks above ensure this operation will not overflow + #[allow(clippy::integer_arithmetic)] let byte = (first_arc * (ARC_MAX_SECOND + 1)) as u8 + second_arc as u8; + Ok(Self(byte)) } /// Get the value of the first arc + #[allow(clippy::integer_arithmetic)] pub(crate) const fn first_arc(self) -> Arc { self.0 as Arc / (ARC_MAX_SECOND + 1) } /// Get the value of the second arc + #[allow(clippy::integer_arithmetic)] pub(crate) const fn second_arc(self) -> Arc { self.0 as Arc % (ARC_MAX_SECOND + 1) } @@ -141,6 +152,8 @@ impl RootArcs { impl TryFrom for RootArcs { type Error = Error; + // Ensured not to overflow by constructor invariants + #[allow(clippy::integer_arithmetic)] fn try_from(octet: u8) -> Result { let first = octet as Arc / (ARC_MAX_SECOND + 1); let second = octet as Arc % (ARC_MAX_SECOND + 1); diff --git a/src/checked.rs b/src/checked.rs new file mode 100644 index 0000000..7ff16a2 --- /dev/null +++ b/src/checked.rs @@ -0,0 +1,11 @@ +//! Checked arithmetic helpers. + +/// `const fn`-friendly checked addition helper. +macro_rules! checked_add { + ($a:expr, $b:expr) => { + match $a.checked_add($b) { + Some(n) => n, + None => return Err(Error::Length), + } + }; +} diff --git a/src/db.rs b/src/db.rs index 9491d2f..971990d 100644 --- a/src/db.rs +++ b/src/db.rs @@ -9,7 +9,7 @@ //! [RFC 5280]: https://datatracker.ietf.org/doc/html/rfc5280 //! [Object Identifier Descriptors]: https://www.iana.org/assignments/ldap-parameters/ldap-parameters.xhtml#ldap-parameters-3 -#![allow(missing_docs)] +#![allow(clippy::integer_arithmetic, missing_docs)] mod gen; diff --git a/src/encoder.rs b/src/encoder.rs index 877b6ed..4df3aab 100644 --- a/src/encoder.rs +++ b/src/encoder.rs @@ -61,6 +61,8 @@ impl Encoder { self.state = State::FirstArc(arc); Ok(self) } + // Ensured not to overflow by `ARC_MAX_SECOND` check + #[allow(clippy::integer_arithmetic)] State::FirstArc(first_arc) => { if arc > ARC_MAX_SECOND { return Err(Error::ArcInvalid { arc }); @@ -71,10 +73,13 @@ impl Encoder { self.cursor = 1; Ok(self) } + // TODO(tarcieri): finer-grained overflow safety / checked arithmetic + #[allow(clippy::integer_arithmetic)] State::Body => { // Total number of bytes in encoded arc - 1 let nbytes = base128_len(arc); + // Shouldn't overflow on any 16-bit+ architectures if self.cursor + nbytes + 1 >= ObjectIdentifier::MAX_SIZE { return Err(Error::Length); } @@ -109,8 +114,10 @@ impl Encoder { const fn encode_base128_byte(mut self, mut n: u32, i: usize, continued: bool) -> Result { let mask = if continued { 0b10000000 } else { 0 }; + // Underflow checked by branch + #[allow(clippy::integer_arithmetic)] if n > 0x80 { - self.bytes[self.cursor + i] = (n & 0b1111111) as u8 | mask; + self.bytes[checked_add!(self.cursor, i)] = (n & 0b1111111) as u8 | mask; n >>= 7; if i > 0 { diff --git a/src/error.rs b/src/error.rs index 72658f2..528ce78 100644 --- a/src/error.rs +++ b/src/error.rs @@ -44,6 +44,24 @@ pub enum Error { TrailingDot, } +impl Error { + /// Escalate this error into a panic. + /// + /// This is a workaround until `Result::unwrap` is allowed in `const fn`. + #[allow(clippy::panic)] + pub(crate) const fn panic(self) -> ! { + match self { + Error::ArcInvalid { .. } | Error::ArcTooBig => panic!("OID contains invalid arc"), + Error::Base128 => panic!("OID contains arc with invalid base 128 encoding"), + Error::DigitExpected { .. } => panic!("OID expected to start with digit"), + Error::Empty => panic!("OID value is empty"), + Error::Length => panic!("OID length invalid"), + Error::NotEnoughArcs => panic!("OID requires minimum of 3 arcs"), + Error::TrailingDot => panic!("OID ends with invalid trailing '.'"), + } + } +} + impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { diff --git a/src/lib.rs b/src/lib.rs index 01337e5..d847065 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,12 +2,20 @@ #![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_root_url = "https://docs.rs/const-oid/0.9.0" + 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( + clippy::integer_arithmetic, + clippy::panic, + clippy::panic_in_result_fn, + clippy::unwrap_used, + missing_docs, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications )] -#![forbid(unsafe_code, clippy::unwrap_used)] -#![warn(missing_docs, rust_2018_idioms)] /// Local Android change: Use std to allow building as a dylib. #[cfg(android_dylib)] @@ -16,6 +24,9 @@ extern crate std; #[cfg(feature = "std")] extern crate std; +#[macro_use] +mod checked; + mod arcs; mod encoder; mod error; @@ -39,6 +50,22 @@ pub trait AssociatedOid { const OID: ObjectIdentifier; } +/// A trait which associates a dynamic, `&self`-dependent OID with a type, +/// which may change depending on the type's value. +/// +/// This trait is object safe and auto-impl'd for any types which impl +/// [`AssociatedOid`]. +pub trait DynAssociatedOid { + /// Get the OID associated with this value. + fn oid(&self) -> ObjectIdentifier; +} + +impl DynAssociatedOid for T { + fn oid(&self) -> ObjectIdentifier { + T::OID + } +} + /// Object identifier (OID). /// /// OIDs are hierarchical structures consisting of "arcs", i.e. integer @@ -89,13 +116,7 @@ impl ObjectIdentifier { pub const fn new_unwrap(s: &str) -> Self { match Self::new(s) { Ok(oid) => oid, - Err(Error::ArcInvalid { .. } | Error::ArcTooBig) => panic!("OID contains invalid arc"), - Err(Error::Base128) => panic!("OID contains arc with invalid base 128 encoding"), - Err(Error::DigitExpected { .. }) => panic!("OID expected to start with digit"), - Err(Error::Empty) => panic!("OID value is empty"), - Err(Error::Length) => panic!("OID length invalid"), - Err(Error::NotEnoughArcs) => panic!("OID requires minimum of 3 arcs"), - Err(Error::TrailingDot) => panic!("OID ends with invalid trailing '.'"), + Err(err) => err.panic(), } } @@ -225,8 +246,10 @@ impl fmt::Display for ObjectIdentifier { for (i, arc) in self.arcs().enumerate() { write!(f, "{}", arc)?; - if i < len - 1 { - write!(f, ".")?; + if let Some(j) = i.checked_add(1) { + if j < len { + write!(f, ".")?; + } } } diff --git a/src/parser.rs b/src/parser.rs index 3554ec6..6f875fa 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -49,6 +49,8 @@ impl Parser { } Err(err) => Err(err), }, + // TODO(tarcieri): checked arithmetic + #[allow(clippy::integer_arithmetic)] [byte @ b'0'..=b'9', remaining @ ..] => { let digit = byte.saturating_sub(b'0'); self.current_arc = self.current_arc * 10 + digit as Arc; -- cgit v1.2.3