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
//! Public key algorithm identification and decoded key data.
//!
//! [`decode_public_key_info`] inspects a `SubjectPublicKeyInfo`'s algorithm
//! OID and parameters, then returns an algorithm-specific [`PublicKeyInfo`]
//! that callers can pattern-match for display or further processing without
//! re-implementing algorithm dispatch in each consumer.
use synta::{types::oid::ObjectIdentifier, Element};
use crate::{ec_curve_key_bits, ec_curve_nist_name, ec_curve_short_name, oids};
/// Decoded public key data, keyed by algorithm family.
pub enum PublicKeyInfo {
/// RSA public key parsed from `SEQUENCE { INTEGER (n), INTEGER (e) }`.
Rsa {
/// Raw modulus bytes from the INTEGER TLV (may begin with 0x00 sign byte).
modulus: Vec<u8>,
/// Public exponent (typically 65537).
exponent: u64,
/// Key size in bits: `(modulus − leading 0x00) × 8`.
bit_count: usize,
},
/// Elliptic-curve public key (id-ecPublicKey).
Ec {
/// Raw key bytes from the BIT STRING (uncompressed or compressed point).
key_bytes: Vec<u8>,
/// Key size in bits derived from the named curve, or BIT STRING length.
bit_count: usize,
/// Short OID name for the curve, e.g. `"prime256v1"` (None if unknown).
curve_short_name: Option<&'static str>,
/// NIST curve name, e.g. `"P-256"` (None if not a NIST named curve).
curve_nist_name: Option<&'static str>,
/// Dotted OID string for the curve, used as fallback when curve_short_name is None.
curve_oid_str: String,
},
/// Any other algorithm — raw BIT STRING bytes and algorithm name.
Unknown {
/// Human-readable algorithm name, or dotted OID if unrecognised.
alg_name: String,
/// Raw key bytes from the BIT STRING.
key_bytes: Vec<u8>,
/// Key size in bits (BIT STRING bit length).
bit_count: usize,
},
}
/// Decode a `SubjectPublicKeyInfo` into algorithm-specific [`PublicKeyInfo`].
///
/// - `alg_oid`: the `AlgorithmIdentifier.algorithm` OID.
/// - `alg_params`: the `AlgorithmIdentifier.parameters` (e.g. EC curve OID).
/// - `key_bytes`: the BIT STRING content (unused-bits byte already stripped).
/// - `key_bit_len`: the BIT STRING's reported bit length.
pub fn decode_public_key_info(
alg_oid: &ObjectIdentifier,
alg_params: Option<&Element<'_>>,
key_bytes: &[u8],
key_bit_len: usize,
) -> PublicKeyInfo {
match alg_oid.components() {
oids::RSA_ENCRYPTION => {
if let Ok(rsa) =
synta::Decoder::new(key_bytes, synta::Encoding::Der).decode::<crate::RsaPublicKey>()
{
let modulus = rsa.modulus.as_bytes().to_vec();
let bit_count = modulus.strip_prefix(&[0u8]).unwrap_or(&modulus).len() * 8;
let exp_bytes = rsa.public_exponent.as_bytes();
let exponent = exp_bytes
.iter()
.fold(0u64, |acc, &b| (acc << 8) | (b as u64));
return PublicKeyInfo::Rsa {
modulus,
exponent,
bit_count,
};
}
// Malformed key — fall through to Unknown.
PublicKeyInfo::Unknown {
alg_name: "rsaEncryption".to_string(),
key_bytes: key_bytes.to_vec(),
bit_count: key_bit_len,
}
}
oids::EC_PUBLIC_KEY => {
if let Some(Element::ObjectIdentifier(curve_oid)) = alg_params {
let c = curve_oid.components();
let bit_count = ec_curve_key_bits(c).unwrap_or(key_bit_len);
let curve_short_name = ec_curve_short_name(c);
let curve_nist_name = ec_curve_nist_name(c);
let curve_oid_str = c
.iter()
.map(|n| n.to_string())
.collect::<Vec<_>>()
.join(".");
return PublicKeyInfo::Ec {
key_bytes: key_bytes.to_vec(),
bit_count,
curve_short_name,
curve_nist_name,
curve_oid_str,
};
}
// EC without a named-curve parameter — treat as unknown.
PublicKeyInfo::Unknown {
alg_name: "id-ecPublicKey".to_string(),
key_bytes: key_bytes.to_vec(),
bit_count: key_bit_len,
}
}
_ => {
let alg_name = crate::identify_public_key_algorithm(alg_oid)
.unwrap_or(crate::names::OTHER)
.to_string();
PublicKeyInfo::Unknown {
alg_name,
key_bytes: key_bytes.to_vec(),
bit_count: key_bit_len,
}
}
}
}