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