• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE-MIT)
2 //! [![Apache License 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](./LICENSE-APACHE)
3 //! [![docs.rs](https://docs.rs/oid-registry/badge.svg)](https://docs.rs/oid-registry)
4 //! [![crates.io](https://img.shields.io/crates/v/oid-registry.svg)](https://crates.io/crates/oid-registry)
5 //! [![Github CI](https://github.com/rusticata/oid-registry/workflows/Continuous%20integration/badge.svg)](https://github.com/rusticata/oid-registry/actions)
6 //! [![Minimum rustc version](https://img.shields.io/badge/rustc-1.45.0+-lightgray.svg)](#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 oid_registry::{OidEntry, OidRegistry};
48 //! use der_parser::oid;
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 //! ## Contributing OIDs
62 //!
63 //! All OID values, constants, and features are derived from files in the `assets` directory in the
64 //! build script (see `build.rs`).
65 //! See `load_file` for documentation of the file format.
66 
67 #![deny(missing_docs, unstable_features, unused_import_braces, unused_qualifications, unreachable_pub)]
68 #![forbid(unsafe_code)]
69 #![warn(
70       /* missing_docs,
71       rust_2018_idioms,*/
72       missing_debug_implementations,
73   )]
74 // pragmas for doc
75 // #![deny(intra_doc_link_resolution_failure)]
76 #![cfg_attr(docsrs, feature(doc_cfg))]
77 
78 use der_parser::oid;
79 pub use der_parser::oid::Oid;
80 use std::borrow::Cow;
81 use std::collections::HashMap;
82 use std::convert::From;
83 
84 mod load;
85 
86 pub use load::*;
87 
88 /// An entry stored in the OID registry
89 #[derive(Debug)]
90 pub struct OidEntry {
91     // Short name
92     sn: Cow<'static, str>,
93     description: Cow<'static, str>,
94 }
95 
96 impl OidEntry {
97     /// Create a new entry
new<S, T>(sn: S, description: T) -> OidEntry where S: Into<Cow<'static, str>>, T: Into<Cow<'static, str>>,98     pub fn new<S, T>(sn: S, description: T) -> OidEntry
99     where
100         S: Into<Cow<'static, str>>,
101         T: Into<Cow<'static, str>>,
102     {
103         let sn = sn.into();
104         let description = description.into();
105         OidEntry { sn, description }
106     }
107 
108     /// Get the short name for this entry
109     #[inline]
sn(&self) -> &str110     pub fn sn(&self) -> &str {
111         &self.sn
112     }
113 
114     /// Get the description for this entry
115     #[inline]
description(&self) -> &str116     pub fn description(&self) -> &str {
117         &self.description
118     }
119 }
120 
121 impl From<(&'static str, &'static str)> for OidEntry {
from(t: (&'static str, &'static str)) -> Self122     fn from(t: (&'static str, &'static str)) -> Self {
123         Self::new(t.0, t.1)
124     }
125 }
126 
127 /// Registry of known OIDs
128 ///
129 /// Use `OidRegistry::default()` to create an empty registry. If the corresponding features have
130 /// been selected, the `with_xxx()` methods can be used to add sets of known objets to the
131 /// database.
132 ///
133 /// # Example
134 ///
135 /// ```rust
136 /// use der_parser::{oid, oid::Oid};
137 /// use oid_registry::{OidEntry, OidRegistry};
138 ///
139 /// let mut registry = OidRegistry::default()
140 /// # ;
141 /// # #[cfg(feature = "crypto")] {
142 /// #     registry = registry
143 ///     .with_crypto() // only if the 'crypto' feature is enabled
144 /// # }
145 /// ;
146 ///
147 /// // entries can be added by creating an OidEntry object:
148 /// let entry = OidEntry::new("shortName", "description");
149 /// registry.insert(oid!(1.2.3.4), entry);
150 ///
151 /// // when using static strings, a tuple can also be used directly for the entry:
152 /// registry.insert(oid!(1.2.3.5), ("shortName", "A description"));
153 ///
154 /// // To query an entry, use the `get` method:
155 /// const OID_1234: Oid<'static> = oid!(1.2.3.4);
156 /// let e = registry.get(&OID_1234);
157 /// assert!(e.is_some());
158 /// if let Some(e) = e {
159 ///     assert_eq!(e.sn(), "shortName");
160 /// }
161 /// ```
162 #[derive(Debug, Default)]
163 pub struct OidRegistry<'a> {
164     map: HashMap<Oid<'a>, OidEntry>,
165 }
166 
167 impl<'a> OidRegistry<'a> {
168     /// Insert a new entry
insert<E>(&mut self, oid: Oid<'a>, entry: E) -> Option<OidEntry> where E: Into<OidEntry>,169     pub fn insert<E>(&mut self, oid: Oid<'a>, entry: E) -> Option<OidEntry>
170     where
171         E: Into<OidEntry>,
172     {
173         self.map.insert(oid, entry.into())
174     }
175 
176     /// Returns a reference to the registry entry, if found for this OID.
get(&self, oid: &Oid<'a>) -> Option<&OidEntry>177     pub fn get(&self, oid: &Oid<'a>) -> Option<&OidEntry> {
178         self.map.get(oid)
179     }
180 
181     /// Return an Iterator over references to the OID numbers (registry keys)
keys(&self) -> impl Iterator<Item = &Oid<'a>>182     pub fn keys(&self) -> impl Iterator<Item = &Oid<'a>> {
183         self.map.keys()
184     }
185 
186     /// Return an Iterator over references to the `OidEntry` values
values(&self) -> impl Iterator<Item = &OidEntry>187     pub fn values(&self) -> impl Iterator<Item = &OidEntry> {
188         self.map.values()
189     }
190 
191     /// Return an Iterator over references to the `(Oid, OidEntry)` key/value pairs
iter(&self) -> impl Iterator<Item = (&Oid<'a>, &OidEntry)>192     pub fn iter(&self) -> impl Iterator<Item = (&Oid<'a>, &OidEntry)> {
193         self.map.iter()
194     }
195 
196     /// Return the `(Oid, OidEntry)` key/value pairs, matching a short name
197     ///
198     /// The registry should not contain entries with same short name to avoid ambiguity, but it is
199     /// not mandatory.
200     ///
201     /// This function returns an iterator over the key/value pairs. In most cases, it will have 0
202     /// (not found) or 1 item, but can contain more if there are multiple definitions.
203     ///
204     /// ```rust
205     /// # use oid_registry::OidRegistry;
206     /// #
207     /// # let registry = OidRegistry::default();
208     /// // iterate all entries matching "shortName"
209     /// for (oid, entry) in registry.iter_by_sn("shortName") {
210     ///     // do something
211     /// }
212     ///
213     /// // if you are *sure* that there is at most one entry:
214     /// let opt_sn = registry.iter_by_sn("shortName").next();
215     /// if let Some((oid, entry)) = opt_sn {
216     ///     // do something
217     /// }
218     /// ```
iter_by_sn<S: Into<String>>(&self, sn: S) -> impl Iterator<Item = (&Oid<'a>, &OidEntry)>219     pub fn iter_by_sn<S: Into<String>>(&self, sn: S) -> impl Iterator<Item = (&Oid<'a>, &OidEntry)> {
220         let s = sn.into();
221         self.map.iter().filter(move |(_, entry)| entry.sn == s)
222     }
223 
224     /// Populate registry with common crypto OIDs (encryption, hash algorithms)
225     #[cfg(feature = "crypto")]
226     #[cfg_attr(docsrs, doc(cfg(feature = "crypto")))]
with_crypto(self) -> Self227     pub fn with_crypto(self) -> Self {
228         self.with_pkcs1().with_x962().with_kdf().with_nist_algs()
229     }
230 
231     /// Populate registry with all known crypto OIDs (encryption, hash algorithms, PKCS constants,
232     /// etc.)
233     #[cfg(feature = "crypto")]
234     #[cfg_attr(docsrs, doc(cfg(feature = "crypto")))]
with_all_crypto(self) -> Self235     pub fn with_all_crypto(self) -> Self {
236         self.with_crypto().with_pkcs7().with_pkcs9().with_pkcs12()
237     }
238 }
239 
240 /// Format a OID to a `String`, using the provided registry to get the short name if present.
format_oid(oid: &Oid, registry: &OidRegistry) -> String241 pub fn format_oid(oid: &Oid, registry: &OidRegistry) -> String {
242     if let Some(entry) = registry.map.get(oid) {
243         format!("{} ({})", entry.sn, oid)
244     } else {
245         format!("{}", oid)
246     }
247 }
248 
249 include!(concat!(env!("OUT_DIR"), "/oid_db.rs"));
250 
251 #[rustfmt::skip::macros(oid)]
252 #[cfg(test)]
253 mod tests {
254     use super::*;
255 
256     // This test is mostly a compile test, to ensure the API has not changed
257     #[test]
test_lifetimes()258     fn test_lifetimes() {
259         fn add_entry(input: &str, oid: Oid<'static>, registry: &mut OidRegistry) {
260             // test insertion of owned string
261             let s = String::from(input);
262             let entry = OidEntry::new("test", s);
263             registry.insert(oid, entry);
264         }
265 
266         let mut registry = OidRegistry::default();
267         add_entry("a", oid!(1.2.3.4), &mut registry);
268         add_entry("b", oid!(1.2.3.5), &mut registry);
269 
270         // test insertion of owned data
271         let e = OidEntry::new("c", "test_c");
272         registry.insert(oid!(1.2.4.1), e);
273 
274         registry.insert(oid!(1.2.5.1), ("a", "b"));
275 
276         let iter = registry.iter_by_sn("test");
277         assert_eq!(iter.count(), 2);
278 
279         // dbg!(&registry);
280     }
281 }
282