oid_registry/lib.rs
1//! [](./LICENSE-MIT)
2//! [](./LICENSE-APACHE)
3//! [](https://docs.rs/oid-registry)
4//! [](https://crates.io/crates/oid-registry)
5//! [](https://github.com/rusticata/oid-registry/actions)
6//! [](#rust-version-requirements)
7//! # OID Registry
8//!
9//! This crate is a helper crate, containing a database of OID objects. These objects are intended
10//! for use when manipulating ASN.1 grammars and BER/DER encodings, for example.
11//!
12//! This crate provides only a simple registry (similar to a `HashMap`) by default. This object can
13//! be used to get names and descriptions from OID.
14//!
15//! This crate provides default lists of known OIDs, that can be selected using the build features.
16//! By default, the registry has no feature enabled, to avoid embedding a huge database in crates.
17//!
18//! It also declares constants for most of these OIDs.
19//!
20//! ```rust
21//! use oid_registry::OidRegistry;
22//!
23//! let mut registry = OidRegistry::default()
24//! # ;
25//! # #[cfg(feature = "crypto")] {
26//! # registry = registry
27//! .with_crypto() // only if the 'crypto' feature is enabled
28//! # }
29//! ;
30//!
31//! let e = registry.get(&oid_registry::OID_PKCS1_SHA256WITHRSA);
32//! if let Some(entry) = e {
33//! // get sn: sha256WithRSAEncryption
34//! println!("sn: {}", entry.sn());
35//! // get description: SHA256 with RSA encryption
36//! println!("description: {}", entry.description());
37//! }
38//!
39//! ```
40//!
41//! ## Extending the registry
42//!
43//! These provided lists are often incomplete, or may lack some specific OIDs.
44//! This is why the registry allows adding new entries after construction:
45//!
46//! ```rust
47//! use asn1_rs::oid;
48//! use oid_registry::{OidEntry, OidRegistry};
49//!
50//! let mut registry = OidRegistry::default();
51//!
52//! // entries can be added by creating an OidEntry object:
53//! let entry = OidEntry::new("shortName", "description");
54//! registry.insert(oid!(1.2.3.4), entry);
55//!
56//! // when using static strings, a tuple can also be used directly for the entry:
57//! registry.insert(oid!(1.2.3.5), ("shortName", "A description"));
58//!
59//! ```
60//!
61//! ## Versions and compatibility with `asn1-rs`
62//!
63//! Versions of `oid-registry` must be chosen specifically, to depend on a precise version of `asn1-rs`.
64//! The following table summarizes the matching versions:
65//!
66//! - `oid-registry` 0.7.x depends on `asn1-rs` 0.6.0
67//! - `oid-registry` 0.6.x depends on `asn1-rs` 0.5.0
68//! - `oid-registry` 0.5.x depends on `asn1-rs` 0.4.0
69//!
70//! ## Contributing OIDs
71//!
72//! All OID values, constants, and features are derived from files in the `assets` directory in the
73//! build script (see `build.rs`).
74//! See `load_file` for documentation of the file format.
75
76#![deny(missing_docs, unstable_features, unused_import_braces, unused_qualifications, unreachable_pub)]
77#![forbid(unsafe_code)]
78#![warn(
79 /* missing_docs,
80 rust_2018_idioms,*/
81 missing_debug_implementations,
82 )]
83// pragmas for doc
84// #![deny(intra_doc_link_resolution_failure)]
85#![cfg_attr(docsrs, feature(doc_cfg))]
86
87pub use asn1_rs;
88pub use asn1_rs::Oid;
89
90use asn1_rs::oid;
91use std::borrow::Cow;
92use std::collections::HashMap;
93
94mod deprecated;
95mod load;
96
97pub use deprecated::*;
98pub use load::*;
99
100/// An entry stored in the OID registry
101#[derive(Debug)]
102pub struct OidEntry {
103 // Short name
104 sn: Cow<'static, str>,
105 description: Cow<'static, str>,
106}
107
108impl OidEntry {
109 /// Create a new entry
110 pub fn new<S, T>(sn: S, description: T) -> OidEntry
111 where
112 S: Into<Cow<'static, str>>,
113 T: Into<Cow<'static, str>>,
114 {
115 let sn = sn.into();
116 let description = description.into();
117 OidEntry { sn, description }
118 }
119
120 /// Get the short name for this entry
121 #[inline]
122 pub fn sn(&self) -> &str {
123 &self.sn
124 }
125
126 /// Get the description for this entry
127 #[inline]
128 pub fn description(&self) -> &str {
129 &self.description
130 }
131}
132
133impl From<(&'static str, &'static str)> for OidEntry {
134 fn from(t: (&'static str, &'static str)) -> Self {
135 Self::new(t.0, t.1)
136 }
137}
138
139/// Registry of known OIDs
140///
141/// Use `OidRegistry::default()` to create an empty registry. If the corresponding features have
142/// been selected, the `with_xxx()` methods can be used to add sets of known objets to the
143/// database.
144///
145/// # Example
146///
147/// ```rust
148/// use asn1_rs::{oid, Oid};
149/// use oid_registry::{OidEntry, OidRegistry};
150///
151/// let mut registry = OidRegistry::default()
152/// # ;
153/// # #[cfg(feature = "crypto")] {
154/// # registry = registry
155/// .with_crypto() // only if the 'crypto' feature is enabled
156/// # }
157/// ;
158///
159/// // entries can be added by creating an OidEntry object:
160/// let entry = OidEntry::new("shortName", "description");
161/// registry.insert(oid!(1.2.3.4), entry);
162///
163/// // when using static strings, a tuple can also be used directly for the entry:
164/// registry.insert(oid!(1.2.3.5), ("shortName", "A description"));
165///
166/// // To query an entry, use the `get` method:
167/// const OID_1234: Oid<'static> = oid!(1.2.3.4);
168/// let e = registry.get(&OID_1234);
169/// assert!(e.is_some());
170/// if let Some(e) = e {
171/// assert_eq!(e.sn(), "shortName");
172/// }
173/// ```
174#[derive(Debug, Default)]
175pub struct OidRegistry<'a> {
176 map: HashMap<Oid<'a>, OidEntry>,
177}
178
179impl<'a> OidRegistry<'a> {
180 /// Insert a new entry
181 pub fn insert<E>(&mut self, oid: Oid<'a>, entry: E) -> Option<OidEntry>
182 where
183 E: Into<OidEntry>,
184 {
185 self.map.insert(oid, entry.into())
186 }
187
188 /// Returns a reference to the registry entry, if found for this OID.
189 pub fn get(&self, oid: &Oid<'a>) -> Option<&OidEntry> {
190 self.map.get(oid)
191 }
192
193 /// Return an Iterator over references to the OID numbers (registry keys)
194 pub fn keys(&self) -> impl Iterator<Item = &Oid<'a>> {
195 self.map.keys()
196 }
197
198 /// Return an Iterator over references to the `OidEntry` values
199 pub fn values(&self) -> impl Iterator<Item = &OidEntry> {
200 self.map.values()
201 }
202
203 /// Return an Iterator over references to the `(Oid, OidEntry)` key/value pairs
204 pub fn iter(&self) -> impl Iterator<Item = (&Oid<'a>, &OidEntry)> {
205 self.map.iter()
206 }
207
208 /// Return the `(Oid, OidEntry)` key/value pairs, matching a short name
209 ///
210 /// The registry should not contain entries with same short name to avoid ambiguity, but it is
211 /// not mandatory.
212 ///
213 /// This function returns an iterator over the key/value pairs. In most cases, it will have 0
214 /// (not found) or 1 item, but can contain more if there are multiple definitions.
215 ///
216 /// ```rust
217 /// # use oid_registry::OidRegistry;
218 /// #
219 /// # let registry = OidRegistry::default();
220 /// // iterate all entries matching "shortName"
221 /// for (oid, entry) in registry.iter_by_sn("shortName") {
222 /// // do something
223 /// }
224 ///
225 /// // if you are *sure* that there is at most one entry:
226 /// let opt_sn = registry.iter_by_sn("shortName").next();
227 /// if let Some((oid, entry)) = opt_sn {
228 /// // do something
229 /// }
230 /// ```
231 pub fn iter_by_sn<S: Into<String>>(&self, sn: S) -> impl Iterator<Item = (&Oid<'a>, &OidEntry)> {
232 let s = sn.into();
233 self.map.iter().filter(move |(_, entry)| entry.sn == s)
234 }
235
236 /// Populate registry with common crypto OIDs (encryption, hash algorithms)
237 #[cfg(feature = "crypto")]
238 #[cfg_attr(docsrs, doc(cfg(feature = "crypto")))]
239 pub fn with_crypto(self) -> Self {
240 self.with_pkcs1().with_x962().with_kdf().with_nist_algs()
241 }
242
243 /// Populate registry with all known crypto OIDs (encryption, hash algorithms, PKCS constants,
244 /// etc.)
245 #[cfg(feature = "crypto")]
246 #[cfg_attr(docsrs, doc(cfg(feature = "crypto")))]
247 pub fn with_all_crypto(self) -> Self {
248 self.with_crypto().with_pkcs7().with_pkcs9().with_pkcs12()
249 }
250}
251
252/// Format a OID to a `String`, using the provided registry to get the short name if present.
253pub fn format_oid(oid: &Oid, registry: &OidRegistry) -> String {
254 if let Some(entry) = registry.map.get(oid) {
255 format!("{} ({})", entry.sn, oid)
256 } else {
257 format!("{}", oid)
258 }
259}
260
261include!(concat!(env!("OUT_DIR"), "/oid_db.rs"));
262
263#[rustfmt::skip::macros(oid)]
264#[cfg(test)]
265mod tests {
266 use super::*;
267
268 // This test is mostly a compile test, to ensure the API has not changed
269 #[test]
270 fn test_lifetimes() {
271 fn add_entry(input: &str, oid: Oid<'static>, registry: &mut OidRegistry) {
272 // test insertion of owned string
273 let s = String::from(input);
274 let entry = OidEntry::new("test", s);
275 registry.insert(oid, entry);
276 }
277
278 let mut registry = OidRegistry::default();
279 add_entry("a", oid!(1.2.3.4), &mut registry);
280 add_entry("b", oid!(1.2.3.5), &mut registry);
281
282 // test insertion of owned data
283 let e = OidEntry::new("c", "test_c");
284 registry.insert(oid!(1.2.4.1), e);
285
286 registry.insert(oid!(1.2.5.1), ("a", "b"));
287
288 let iter = registry.iter_by_sn("test");
289 assert_eq!(iter.count(), 2);
290
291 // dbg!(®istry);
292 }
293}