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 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!(®istry);
280 }
281 }
282