Coverage Report

Created: 2025-11-28 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/jsonwebtoken-9.3.1/src/pem/decoder.rs
Line
Count
Source
1
use crate::errors::{ErrorKind, Result};
2
3
/// Supported PEM files for EC and RSA Public and Private Keys
4
#[derive(Debug, PartialEq)]
5
enum PemType {
6
    EcPublic,
7
    EcPrivate,
8
    RsaPublic,
9
    RsaPrivate,
10
    EdPublic,
11
    EdPrivate,
12
}
13
14
#[derive(Debug, PartialEq)]
15
enum Standard {
16
    // Only for RSA
17
    Pkcs1,
18
    // RSA/EC
19
    Pkcs8,
20
}
21
22
#[derive(Debug, PartialEq)]
23
enum 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)]
44
pub(crate) struct PemEncodedKey {
45
    content: Vec<u8>,
46
    asn1: Vec<simple_asn1::ASN1Block>,
47
    pem_type: PemType,
48
    standard: Standard,
49
}
50
51
impl PemEncodedKey {
52
    /// Read the PEM file for later key use
53
0
    pub fn new(input: &[u8]) -> Result<PemEncodedKey> {
54
0
        match pem::parse(input) {
55
0
            Ok(content) => {
56
0
                let asn1_content = match simple_asn1::from_der(content.contents()) {
57
0
                    Ok(asn1) => asn1,
58
0
                    Err(_) => return Err(ErrorKind::InvalidKeyFormat.into()),
59
                };
60
61
0
                match content.tag() {
62
                    // This handles a PKCS#1 RSA Private key
63
0
                    "RSA PRIVATE KEY" => Ok(PemEncodedKey {
64
0
                        content: content.into_contents(),
65
0
                        asn1: asn1_content,
66
0
                        pem_type: PemType::RsaPrivate,
67
0
                        standard: Standard::Pkcs1,
68
0
                    }),
69
0
                    "RSA PUBLIC KEY" => Ok(PemEncodedKey {
70
0
                        content: content.into_contents(),
71
0
                        asn1: asn1_content,
72
0
                        pem_type: PemType::RsaPublic,
73
0
                        standard: Standard::Pkcs1,
74
0
                    }),
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
0
                    tag @ "PRIVATE KEY" | tag @ "PUBLIC KEY" | tag @ "CERTIFICATE" => {
82
0
                        match classify_pem(&asn1_content) {
83
0
                            Some(c) => {
84
0
                                let is_private = tag == "PRIVATE KEY";
85
0
                                let pem_type = match c {
86
                                    Classification::Ec => {
87
0
                                        if is_private {
88
0
                                            PemType::EcPrivate
89
                                        } else {
90
0
                                            PemType::EcPublic
91
                                        }
92
                                    }
93
                                    Classification::Ed => {
94
0
                                        if is_private {
95
0
                                            PemType::EdPrivate
96
                                        } else {
97
0
                                            PemType::EdPublic
98
                                        }
99
                                    }
100
                                    Classification::Rsa => {
101
0
                                        if is_private {
102
0
                                            PemType::RsaPrivate
103
                                        } else {
104
0
                                            PemType::RsaPublic
105
                                        }
106
                                    }
107
                                };
108
0
                                Ok(PemEncodedKey {
109
0
                                    content: content.into_contents(),
110
0
                                    asn1: asn1_content,
111
0
                                    pem_type,
112
0
                                    standard: Standard::Pkcs8,
113
0
                                })
114
                            }
115
0
                            None => Err(ErrorKind::InvalidKeyFormat.into()),
116
                        }
117
                    }
118
119
                    // Unknown/unsupported type
120
0
                    _ => Err(ErrorKind::InvalidKeyFormat.into()),
121
                }
122
            }
123
0
            Err(_) => Err(ErrorKind::InvalidKeyFormat.into()),
124
        }
125
0
    }
126
127
    /// Can only be PKCS8
128
0
    pub fn as_ec_private_key(&self) -> Result<&[u8]> {
129
0
        match self.standard {
130
0
            Standard::Pkcs1 => Err(ErrorKind::InvalidKeyFormat.into()),
131
0
            Standard::Pkcs8 => match self.pem_type {
132
0
                PemType::EcPrivate => Ok(self.content.as_slice()),
133
0
                _ => Err(ErrorKind::InvalidKeyFormat.into()),
134
            },
135
        }
136
0
    }
137
138
    /// Can only be PKCS8
139
0
    pub fn as_ec_public_key(&self) -> Result<&[u8]> {
140
0
        match self.standard {
141
0
            Standard::Pkcs1 => Err(ErrorKind::InvalidKeyFormat.into()),
142
0
            Standard::Pkcs8 => match self.pem_type {
143
0
                PemType::EcPublic => extract_first_bitstring(&self.asn1),
144
0
                _ => Err(ErrorKind::InvalidKeyFormat.into()),
145
            },
146
        }
147
0
    }
148
149
    /// Can only be PKCS8
150
0
    pub fn as_ed_private_key(&self) -> Result<&[u8]> {
151
0
        match self.standard {
152
0
            Standard::Pkcs1 => Err(ErrorKind::InvalidKeyFormat.into()),
153
0
            Standard::Pkcs8 => match self.pem_type {
154
0
                PemType::EdPrivate => Ok(self.content.as_slice()),
155
0
                _ => Err(ErrorKind::InvalidKeyFormat.into()),
156
            },
157
        }
158
0
    }
159
160
    /// Can only be PKCS8
161
0
    pub fn as_ed_public_key(&self) -> Result<&[u8]> {
162
0
        match self.standard {
163
0
            Standard::Pkcs1 => Err(ErrorKind::InvalidKeyFormat.into()),
164
0
            Standard::Pkcs8 => match self.pem_type {
165
0
                PemType::EdPublic => extract_first_bitstring(&self.asn1),
166
0
                _ => Err(ErrorKind::InvalidKeyFormat.into()),
167
            },
168
        }
169
0
    }
170
171
    /// Can be PKCS1 or PKCS8
172
0
    pub fn as_rsa_key(&self) -> Result<&[u8]> {
173
0
        match self.standard {
174
0
            Standard::Pkcs1 => Ok(self.content.as_slice()),
175
0
            Standard::Pkcs8 => match self.pem_type {
176
0
                PemType::RsaPrivate => extract_first_bitstring(&self.asn1),
177
0
                PemType::RsaPublic => extract_first_bitstring(&self.asn1),
178
0
                _ => Err(ErrorKind::InvalidKeyFormat.into()),
179
            },
180
        }
181
0
    }
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.
189
0
fn extract_first_bitstring(asn1: &[simple_asn1::ASN1Block]) -> Result<&[u8]> {
190
0
    for asn1_entry in asn1.iter() {
191
0
        match asn1_entry {
192
0
            simple_asn1::ASN1Block::Sequence(_, entries) => {
193
0
                if let Ok(result) = extract_first_bitstring(entries) {
194
0
                    return Ok(result);
195
0
                }
196
            }
197
0
            simple_asn1::ASN1Block::BitString(_, _, value) => {
198
0
                return Ok(value.as_ref());
199
            }
200
0
            simple_asn1::ASN1Block::OctetString(_, value) => {
201
0
                return Ok(value.as_ref());
202
            }
203
0
            _ => (),
204
        }
205
    }
206
207
0
    Err(ErrorKind::InvalidEcdsaKey.into())
208
0
}
209
210
/// Find whether this is EC, RSA, or Ed
211
0
fn classify_pem(asn1: &[simple_asn1::ASN1Block]) -> Option<Classification> {
212
    // These should be constant but the macro requires
213
    // #![feature(const_vec_new)]
214
0
    let ec_public_key_oid = simple_asn1::oid!(1, 2, 840, 10_045, 2, 1);
215
0
    let rsa_public_key_oid = simple_asn1::oid!(1, 2, 840, 113_549, 1, 1, 1);
216
0
    let ed25519_oid = simple_asn1::oid!(1, 3, 101, 112);
217
218
0
    for asn1_entry in asn1.iter() {
219
0
        match asn1_entry {
220
0
            simple_asn1::ASN1Block::Sequence(_, entries) => {
221
0
                if let Some(classification) = classify_pem(entries) {
222
0
                    return Some(classification);
223
0
                }
224
            }
225
0
            simple_asn1::ASN1Block::ObjectIdentifier(_, oid) => {
226
0
                if oid == ec_public_key_oid {
227
0
                    return Some(Classification::Ec);
228
0
                }
229
0
                if oid == rsa_public_key_oid {
230
0
                    return Some(Classification::Rsa);
231
0
                }
232
0
                if oid == ed25519_oid {
233
0
                    return Some(Classification::Ed);
234
0
                }
235
            }
236
0
            _ => {}
237
        }
238
    }
239
0
    None
240
0
}