x509_parser/
public_key.rs

1use crate::error::*;
2use asn1_rs::FromDer;
3use der_parser::{
4    der::{parse_der_integer, parse_der_sequence_defined_g},
5    error::BerResult,
6};
7
8/// Public Key value
9#[derive(Debug, PartialEq, Eq)]
10pub enum PublicKey<'a> {
11    RSA(RSAPublicKey<'a>),
12    EC(ECPoint<'a>),
13    /// DSAPublicKey ::= INTEGER -- public key, Y (RFC 3279)
14    DSA(&'a [u8]),
15    /// GostR3410-94-PublicKey ::= OCTET STRING -- public key, Y (RFC 4491)
16    GostR3410(&'a [u8]),
17    /// GostR3410-2012-256-PublicKey ::= OCTET STRING (64),
18    /// GostR3410-2012-512-PublicKey ::= OCTET STRING (128). (RFC 4491-bis)
19    GostR3410_2012(&'a [u8]),
20
21    Unknown(&'a [u8]),
22}
23
24impl PublicKey<'_> {
25    /// Return the key size (in bits) or 0
26    pub fn key_size(&self) -> usize {
27        match self {
28            Self::EC(ec) => ec.key_size(),
29            Self::RSA(rsa) => rsa.key_size(),
30            Self::DSA(y) | Self::GostR3410(y) => y.len() * 8,
31            _ => 0,
32        }
33    }
34}
35
36/// RSA public Key, defined in rfc3279
37#[derive(Debug, PartialEq, Eq)]
38pub struct RSAPublicKey<'a> {
39    /// Raw bytes of the modulus
40    ///
41    /// This possibly includes a leading 0 if the MSB is 1
42    pub modulus: &'a [u8],
43    /// Raw bytes of the exponent
44    ///
45    /// This possibly includes a leading 0 if the MSB is 1
46    pub exponent: &'a [u8],
47}
48
49impl RSAPublicKey<'_> {
50    /// Attempt to convert exponent to u64
51    ///
52    /// Returns an error if integer is too large, empty, or negative
53    pub fn try_exponent(&self) -> Result<u64, X509Error> {
54        let mut buf = [0u8; 8];
55        if self.exponent.is_empty() || self.exponent[0] & 0x80 != 0 || self.exponent.len() > 8 {
56            return Err(X509Error::InvalidNumber);
57        }
58        buf[8_usize.saturating_sub(self.exponent.len())..].copy_from_slice(self.exponent);
59        let int = <u64>::from_be_bytes(buf);
60        Ok(int)
61    }
62
63    /// Return the key size (in bits) or 0
64    pub fn key_size(&self) -> usize {
65        if !self.modulus.is_empty() && self.modulus[0] & 0x80 == 0 {
66            // XXX len must substract leading zeroes
67            let modulus = &self.modulus[1..];
68            8 * modulus.len()
69        } else {
70            0
71        }
72    }
73}
74
75// helper function to parse with error type BerError
76fn parse_rsa_key(bytes: &[u8]) -> BerResult<RSAPublicKey> {
77    parse_der_sequence_defined_g(move |i, _| {
78        let (i, obj_modulus) = parse_der_integer(i)?;
79        let (i, obj_exponent) = parse_der_integer(i)?;
80        let modulus = obj_modulus.as_slice()?;
81        let exponent = obj_exponent.as_slice()?;
82        let key = RSAPublicKey { modulus, exponent };
83        Ok((i, key))
84    })(bytes)
85}
86
87impl<'a> FromDer<'a, X509Error> for RSAPublicKey<'a> {
88    fn from_der(bytes: &'a [u8]) -> X509Result<'a, Self> {
89        parse_rsa_key(bytes).map_err(|_| nom::Err::Error(X509Error::InvalidSPKI))
90    }
91}
92
93/// Elliptic Curve point, as defined in [RFC5480](https://datatracker.ietf.org/doc/html/rfc5480)
94#[derive(Debug, PartialEq, Eq)]
95pub struct ECPoint<'a> {
96    data: &'a [u8],
97}
98
99impl<'a> ECPoint<'a> {
100    /// EC Point content (See Standards for Efficient Cryptography Group (SECG), "SEC1: Elliptic Curve Cryptography")
101    pub fn data(&'a self) -> &'a [u8] {
102        self.data
103    }
104
105    /// Return the key size (in bits) or 0
106    pub fn key_size(&self) -> usize {
107        match self.data {
108            [] => {
109                // empty
110                0
111            }
112            [4, rem @ ..] => {
113                // uncompressed
114                rem.len() * 8 / 2
115            }
116            [2..=3, rem @ ..] => {
117                // compressed
118                rem.len() * 8
119            }
120            _ => {
121                // invalid
122                0
123            }
124        }
125    }
126}
127
128impl<'a> From<&'a [u8]> for ECPoint<'a> {
129    fn from(data: &'a [u8]) -> Self {
130        ECPoint { data }
131    }
132}