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 pem_contents = content.contents;
57                let asn1_content = match simple_asn1::from_der(pem_contents.as_slice()) {
58                    Ok(asn1) => asn1,
59                    Err(_) => return Err(ErrorKind::InvalidKeyFormat.into()),
60                };
61
62                match content.tag.as_ref() {
63                    // This handles a PKCS#1 RSA Private key
64                    "RSA PRIVATE KEY" => Ok(PemEncodedKey {
65                        content: pem_contents,
66                        asn1: asn1_content,
67                        pem_type: PemType::RsaPrivate,
68                        standard: Standard::Pkcs1,
69                    }),
70                    "RSA PUBLIC KEY" => Ok(PemEncodedKey {
71                        content: pem_contents,
72                        asn1: asn1_content,
73                        pem_type: PemType::RsaPublic,
74                        standard: Standard::Pkcs1,
75                    }),
76
77                    // No "EC PRIVATE KEY"
78                    // https://security.stackexchange.com/questions/84327/converting-ecc-private-key-to-pkcs1-format
79                    // "there is no such thing as a "PKCS#1 format" for elliptic curve (EC) keys"
80
81                    // This handles PKCS#8 certificates and public & private keys
82                    tag @ "PRIVATE KEY" | tag @ "PUBLIC KEY" | tag @ "CERTIFICATE" => {
83                        match classify_pem(&asn1_content) {
84                            Some(c) => {
85                                let is_private = tag == "PRIVATE KEY";
86                                let pem_type = match c {
87                                    Classification::Ec => {
88                                        if is_private {
89                                            PemType::EcPrivate
90                                        } else {
91                                            PemType::EcPublic
92                                        }
93                                    }
94                                    Classification::Ed => {
95                                        if is_private {
96                                            PemType::EdPrivate
97                                        } else {
98                                            PemType::EdPublic
99                                        }
100                                    }
101                                    Classification::Rsa => {
102                                        if is_private {
103                                            PemType::RsaPrivate
104                                        } else {
105                                            PemType::RsaPublic
106                                        }
107                                    }
108                                };
109                                Ok(PemEncodedKey {
110                                    content: pem_contents,
111                                    asn1: asn1_content,
112                                    pem_type,
113                                    standard: Standard::Pkcs8,
114                                })
115                            }
116                            None => Err(ErrorKind::InvalidKeyFormat.into()),
117                        }
118                    }
119
120                    // Unknown/unsupported type
121                    _ => Err(ErrorKind::InvalidKeyFormat.into()),
122                }
123            }
124            Err(_) => Err(ErrorKind::InvalidKeyFormat.into()),
125        }
126    }
127
128    /// Can only be PKCS8
129    pub fn as_ec_private_key(&self) -> Result<&[u8]> {
130        match self.standard {
131            Standard::Pkcs1 => Err(ErrorKind::InvalidKeyFormat.into()),
132            Standard::Pkcs8 => match self.pem_type {
133                PemType::EcPrivate => Ok(self.content.as_slice()),
134                _ => Err(ErrorKind::InvalidKeyFormat.into()),
135            },
136        }
137    }
138
139    /// Can only be PKCS8
140    pub fn as_ec_public_key(&self) -> Result<&[u8]> {
141        match self.standard {
142            Standard::Pkcs1 => Err(ErrorKind::InvalidKeyFormat.into()),
143            Standard::Pkcs8 => match self.pem_type {
144                PemType::EcPublic => extract_first_bitstring(&self.asn1),
145                _ => Err(ErrorKind::InvalidKeyFormat.into()),
146            },
147        }
148    }
149
150    /// Can only be PKCS8
151    pub fn as_ed_private_key(&self) -> Result<&[u8]> {
152        match self.standard {
153            Standard::Pkcs1 => Err(ErrorKind::InvalidKeyFormat.into()),
154            Standard::Pkcs8 => match self.pem_type {
155                PemType::EdPrivate => Ok(self.content.as_slice()),
156                _ => Err(ErrorKind::InvalidKeyFormat.into()),
157            },
158        }
159    }
160
161    /// Can only be PKCS8
162    pub fn as_ed_public_key(&self) -> Result<&[u8]> {
163        match self.standard {
164            Standard::Pkcs1 => Err(ErrorKind::InvalidKeyFormat.into()),
165            Standard::Pkcs8 => match self.pem_type {
166                PemType::EdPublic => extract_first_bitstring(&self.asn1),
167                _ => Err(ErrorKind::InvalidKeyFormat.into()),
168            },
169        }
170    }
171
172    /// Can be PKCS1 or PKCS8
173    pub fn as_rsa_key(&self) -> Result<&[u8]> {
174        match self.standard {
175            Standard::Pkcs1 => Ok(self.content.as_slice()),
176            Standard::Pkcs8 => match self.pem_type {
177                PemType::RsaPrivate => extract_first_bitstring(&self.asn1),
178                PemType::RsaPublic => extract_first_bitstring(&self.asn1),
179                _ => Err(ErrorKind::InvalidKeyFormat.into()),
180            },
181        }
182    }
183}
184
185// This really just finds and returns the first bitstring or octet string
186// Which is the x coordinate for EC public keys
187// And the DER contents of an RSA key
188// Though PKCS#11 keys shouldn't have anything else.
189// It will get confusing with certificates.
190fn extract_first_bitstring(asn1: &[simple_asn1::ASN1Block]) -> Result<&[u8]> {
191    for asn1_entry in asn1.iter() {
192        match asn1_entry {
193            simple_asn1::ASN1Block::Sequence(_, entries) => {
194                if let Ok(result) = extract_first_bitstring(entries) {
195                    return Ok(result);
196                }
197            }
198            simple_asn1::ASN1Block::BitString(_, _, value) => {
199                return Ok(value.as_ref());
200            }
201            simple_asn1::ASN1Block::OctetString(_, value) => {
202                return Ok(value.as_ref());
203            }
204            _ => (),
205        }
206    }
207
208    Err(ErrorKind::InvalidEcdsaKey.into())
209}
210
211/// Find whether this is EC, RSA, or Ed
212fn classify_pem(asn1: &[simple_asn1::ASN1Block]) -> Option<Classification> {
213    // These should be constant but the macro requires
214    // #![feature(const_vec_new)]
215    let ec_public_key_oid = simple_asn1::oid!(1, 2, 840, 10_045, 2, 1);
216    let rsa_public_key_oid = simple_asn1::oid!(1, 2, 840, 113_549, 1, 1, 1);
217    let ed25519_oid = simple_asn1::oid!(1, 3, 101, 112);
218
219    for asn1_entry in asn1.iter() {
220        match asn1_entry {
221            simple_asn1::ASN1Block::Sequence(_, entries) => {
222                if let Some(classification) = classify_pem(entries) {
223                    return Some(classification);
224                }
225            }
226            simple_asn1::ASN1Block::ObjectIdentifier(_, oid) => {
227                if oid == ec_public_key_oid {
228                    return Some(Classification::Ec);
229                }
230                if oid == rsa_public_key_oid {
231                    return Some(Classification::Rsa);
232                }
233                if oid == ed25519_oid {
234                    return Some(Classification::Ed);
235                }
236            }
237            _ => {}
238        }
239    }
240    None
241}