jsonwebtoken/pem/
decoder.rs

1use crate::errors::{ErrorKind, Result};
2
3/// Supported PEM files for EC and RSA Public and Private Keys
4#[derive(Debug, PartialEq)]
5enum PemType {
6    EcPublic,
7    EcPrivate,
8    RsaPublic,
9    RsaPrivate,
10    EdPublic,
11    EdPrivate,
12}
13
14#[derive(Debug, PartialEq)]
15enum Standard {
16    // Only for RSA
17    Pkcs1,
18    // RSA/EC
19    Pkcs8,
20}
21
22#[derive(Debug, PartialEq)]
23enum Classification {
24    Ec,
25    Ed,
26    Rsa,
27}
28
29/// The return type of a successful PEM encoded key with `decode_pem`
30///
31/// This struct gives a way to parse a string to a key for use in jsonwebtoken.
32/// A struct is necessary as it provides the lifetime of the key
33///
34/// PEM public private keys are encoded PKCS#1 or PKCS#8
35/// You will find that with PKCS#8 RSA keys that the PKCS#1 content
36/// is embedded inside. This is what is provided to ring via `Key::Der`
37/// For EC keys, they are always PKCS#8 on the outside but like RSA keys
38/// EC keys contain a section within that ultimately has the configuration
39/// that ring uses.
40/// Documentation about these formats is at
41/// PKCS#1: https://tools.ietf.org/html/rfc8017
42/// PKCS#8: https://tools.ietf.org/html/rfc5958
43#[derive(Debug)]
44pub(crate) struct PemEncodedKey {
45    content: Vec<u8>,
46    asn1: Vec<simple_asn1::ASN1Block>,
47    pem_type: PemType,
48    standard: Standard,
49}
50
51impl PemEncodedKey {
52    /// Read the PEM file for later key use
53    pub fn new(input: &[u8]) -> Result<PemEncodedKey> {
54        match pem::parse(input) {
55            Ok(content) => {
56                let asn1_content = match simple_asn1::from_der(content.contents()) {
57                    Ok(asn1) => asn1,
58                    Err(_) => return Err(ErrorKind::InvalidKeyFormat.into()),
59                };
60
61                match content.tag() {
62                    // This handles a PKCS#1 RSA Private key
63                    "RSA PRIVATE KEY" => Ok(PemEncodedKey {
64                        content: content.into_contents(),
65                        asn1: asn1_content,
66                        pem_type: PemType::RsaPrivate,
67                        standard: Standard::Pkcs1,
68                    }),
69                    "RSA PUBLIC KEY" => Ok(PemEncodedKey {
70                        content: content.into_contents(),
71                        asn1: asn1_content,
72                        pem_type: PemType::RsaPublic,
73                        standard: Standard::Pkcs1,
74                    }),
75
76                    // No "EC PRIVATE KEY"
77                    // https://security.stackexchange.com/questions/84327/converting-ecc-private-key-to-pkcs1-format
78                    // "there is no such thing as a "PKCS#1 format" for elliptic curve (EC) keys"
79
80                    // This handles PKCS#8 certificates and public & private keys
81                    tag @ "PRIVATE KEY" | tag @ "PUBLIC KEY" | tag @ "CERTIFICATE" => {
82                        match classify_pem(&asn1_content) {
83                            Some(c) => {
84                                let is_private = tag == "PRIVATE KEY";
85                                let pem_type = match c {
86                                    Classification::Ec => {
87                                        if is_private {
88                                            PemType::EcPrivate
89                                        } else {
90                                            PemType::EcPublic
91                                        }
92                                    }
93                                    Classification::Ed => {
94                                        if is_private {
95                                            PemType::EdPrivate
96                                        } else {
97                                            PemType::EdPublic
98                                        }
99                                    }
100                                    Classification::Rsa => {
101                                        if is_private {
102                                            PemType::RsaPrivate
103                                        } else {
104                                            PemType::RsaPublic
105                                        }
106                                    }
107                                };
108                                Ok(PemEncodedKey {
109                                    content: content.into_contents(),
110                                    asn1: asn1_content,
111                                    pem_type,
112                                    standard: Standard::Pkcs8,
113                                })
114                            }
115                            None => Err(ErrorKind::InvalidKeyFormat.into()),
116                        }
117                    }
118
119                    // Unknown/unsupported type
120                    _ => Err(ErrorKind::InvalidKeyFormat.into()),
121                }
122            }
123            Err(_) => Err(ErrorKind::InvalidKeyFormat.into()),
124        }
125    }
126
127    /// Can only be PKCS8
128    pub fn as_ec_private_key(&self) -> Result<&[u8]> {
129        match self.standard {
130            Standard::Pkcs1 => Err(ErrorKind::InvalidKeyFormat.into()),
131            Standard::Pkcs8 => match self.pem_type {
132                PemType::EcPrivate => Ok(self.content.as_slice()),
133                _ => Err(ErrorKind::InvalidKeyFormat.into()),
134            },
135        }
136    }
137
138    /// Can only be PKCS8
139    pub fn as_ec_public_key(&self) -> Result<&[u8]> {
140        match self.standard {
141            Standard::Pkcs1 => Err(ErrorKind::InvalidKeyFormat.into()),
142            Standard::Pkcs8 => match self.pem_type {
143                PemType::EcPublic => extract_first_bitstring(&self.asn1),
144                _ => Err(ErrorKind::InvalidKeyFormat.into()),
145            },
146        }
147    }
148
149    /// Can only be PKCS8
150    pub fn as_ed_private_key(&self) -> Result<&[u8]> {
151        match self.standard {
152            Standard::Pkcs1 => Err(ErrorKind::InvalidKeyFormat.into()),
153            Standard::Pkcs8 => match self.pem_type {
154                PemType::EdPrivate => Ok(self.content.as_slice()),
155                _ => Err(ErrorKind::InvalidKeyFormat.into()),
156            },
157        }
158    }
159
160    /// Can only be PKCS8
161    pub fn as_ed_public_key(&self) -> Result<&[u8]> {
162        match self.standard {
163            Standard::Pkcs1 => Err(ErrorKind::InvalidKeyFormat.into()),
164            Standard::Pkcs8 => match self.pem_type {
165                PemType::EdPublic => extract_first_bitstring(&self.asn1),
166                _ => Err(ErrorKind::InvalidKeyFormat.into()),
167            },
168        }
169    }
170
171    /// Can be PKCS1 or PKCS8
172    pub fn as_rsa_key(&self) -> Result<&[u8]> {
173        match self.standard {
174            Standard::Pkcs1 => Ok(self.content.as_slice()),
175            Standard::Pkcs8 => match self.pem_type {
176                PemType::RsaPrivate => extract_first_bitstring(&self.asn1),
177                PemType::RsaPublic => extract_first_bitstring(&self.asn1),
178                _ => Err(ErrorKind::InvalidKeyFormat.into()),
179            },
180        }
181    }
182}
183
184// This really just finds and returns the first bitstring or octet string
185// Which is the x coordinate for EC public keys
186// And the DER contents of an RSA key
187// Though PKCS#11 keys shouldn't have anything else.
188// It will get confusing with certificates.
189fn extract_first_bitstring(asn1: &[simple_asn1::ASN1Block]) -> Result<&[u8]> {
190    for asn1_entry in asn1.iter() {
191        match asn1_entry {
192            simple_asn1::ASN1Block::Sequence(_, entries) => {
193                if let Ok(result) = extract_first_bitstring(entries) {
194                    return Ok(result);
195                }
196            }
197            simple_asn1::ASN1Block::BitString(_, _, value) => {
198                return Ok(value.as_ref());
199            }
200            simple_asn1::ASN1Block::OctetString(_, value) => {
201                return Ok(value.as_ref());
202            }
203            _ => (),
204        }
205    }
206
207    Err(ErrorKind::InvalidEcdsaKey.into())
208}
209
210/// Find whether this is EC, RSA, or Ed
211fn classify_pem(asn1: &[simple_asn1::ASN1Block]) -> Option<Classification> {
212    // These should be constant but the macro requires
213    // #![feature(const_vec_new)]
214    let ec_public_key_oid = simple_asn1::oid!(1, 2, 840, 10_045, 2, 1);
215    let rsa_public_key_oid = simple_asn1::oid!(1, 2, 840, 113_549, 1, 1, 1);
216    let ed25519_oid = simple_asn1::oid!(1, 3, 101, 112);
217
218    for asn1_entry in asn1.iter() {
219        match asn1_entry {
220            simple_asn1::ASN1Block::Sequence(_, entries) => {
221                if let Some(classification) = classify_pem(entries) {
222                    return Some(classification);
223                }
224            }
225            simple_asn1::ASN1Block::ObjectIdentifier(_, oid) => {
226                if oid == ec_public_key_oid {
227                    return Some(Classification::Ec);
228                }
229                if oid == rsa_public_key_oid {
230                    return Some(Classification::Rsa);
231                }
232                if oid == ed25519_oid {
233                    return Some(Classification::Ed);
234                }
235            }
236            _ => {}
237        }
238    }
239    None
240}