libp2prs_core/identity/
rsa.rs

1// Copyright 2019 Parity Technologies (UK) Ltd.
2// Copyright 2020 Netwarps Ltd.
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20// DEALINGS IN THE SOFTWARE.
21
22//! RSA keys.
23
24use super::error::*;
25use asn1_der::{Asn1Der, Asn1DerError, DerObject, DerTag, DerValue, FromDerObject, IntoDerObject};
26use lazy_static::lazy_static;
27use ring::rand::SystemRandom;
28use ring::signature::KeyPair;
29use ring::signature::{self, RsaKeyPair, RSA_PKCS1_2048_8192_SHA256, RSA_PKCS1_SHA256};
30use std::{
31    fmt::{self, Write},
32    sync::Arc,
33};
34use zeroize::Zeroize;
35
36/// An RSA keypair.
37#[derive(Clone)]
38pub struct Keypair(Arc<RsaKeyPair>);
39
40impl Keypair {
41    /// Decode an RSA keypair from a DER-encoded private key in PKCS#8 PrivateKeyInfo
42    /// format (i.e. unencrypted) as defined in [RFC5208].
43    ///
44    /// [RFC5208]: https://tools.ietf.org/html/rfc5208#section-5
45    pub fn from_pkcs8(der: &mut [u8]) -> Result<Keypair, DecodingError> {
46        let kp = RsaKeyPair::from_pkcs8(&der).map_err(|e| DecodingError::new("RSA PKCS#8 PrivateKeyInfo").source(e))?;
47        der.zeroize();
48        Ok(Keypair(Arc::new(kp)))
49    }
50
51    /// Get the public key from the keypair.
52    pub fn public(&self) -> PublicKey {
53        PublicKey(self.0.public_key().as_ref().to_vec())
54    }
55
56    /// Sign a message with this keypair.
57    pub fn sign(&self, data: &[u8]) -> Result<Vec<u8>, SigningError> {
58        let mut signature = vec![0; self.0.public_modulus_len()];
59        let rng = SystemRandom::new();
60        match self.0.sign(&RSA_PKCS1_SHA256, &rng, &data, &mut signature) {
61            Ok(()) => Ok(signature),
62            Err(e) => Err(SigningError::new("RSA").source(e)),
63        }
64    }
65}
66
67/// An RSA public key.
68#[derive(Clone, PartialEq, Eq)]
69pub struct PublicKey(Vec<u8>);
70
71impl PublicKey {
72    /// Verify an RSA signature on a message using the public key.
73    pub fn verify(&self, msg: &[u8], sig: &[u8]) -> bool {
74        let key = signature::UnparsedPublicKey::new(&RSA_PKCS1_2048_8192_SHA256, &self.0);
75        key.verify(msg, sig).is_ok()
76    }
77
78    /// Encode the RSA public key in DER as a PKCS#1 RSAPublicKey structure,
79    /// as defined in [RFC3447].
80    ///
81    /// [RFC3447]: https://tools.ietf.org/html/rfc3447#appendix-A.1.1
82    pub fn encode_pkcs1(&self) -> Vec<u8> {
83        // This is the encoding currently used in-memory, so it is trivial.
84        self.0.clone()
85    }
86
87    /// Encode the RSA public key in DER as a X.509 SubjectPublicKeyInfo structure,
88    /// as defined in [RFC5280].
89    ///
90    /// [RFC5280]: https://tools.ietf.org/html/rfc5280#section-4.1
91    pub fn encode_x509(&self) -> Vec<u8> {
92        let spki = Asn1SubjectPublicKeyInfo {
93            algorithmIdentifier: Asn1RsaEncryption {
94                algorithm: Asn1OidRsaEncryption(),
95                parameters: (),
96            },
97            subjectPublicKey: Asn1SubjectPublicKey(self.clone()),
98        };
99        let mut buf = vec![0u8; spki.serialized_len()];
100        spki.serialize(buf.iter_mut())
101            .map(|_| buf)
102            .expect("RSA X.509 public key encoding failed.")
103    }
104
105    /// Decode an RSA public key from a DER-encoded X.509 SubjectPublicKeyInfo
106    /// structure. See also `encode_x509`.
107    pub fn decode_x509(pk: &[u8]) -> Result<PublicKey, DecodingError> {
108        Asn1SubjectPublicKeyInfo::deserialize(pk.iter())
109            .map_err(|e| DecodingError::new("RSA X.509").source(e))
110            .map(|spki| spki.subjectPublicKey.0)
111    }
112}
113
114impl fmt::Debug for PublicKey {
115    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116        let bytes = &self.0;
117        let mut hex = String::with_capacity(bytes.len() * 2);
118
119        for byte in bytes {
120            write!(hex, "{:02x}", byte).expect("Can't fail on writing to string");
121        }
122
123        f.debug_struct("PublicKey").field("pkcs1", &hex).finish()
124    }
125}
126
127//////////////////////////////////////////////////////////////////////////////
128// DER encoding / decoding of public keys
129//
130// Primer: http://luca.ntop.org/Teaching/Appunti/asn1.html
131// Playground: https://lapo.it/asn1js/
132
133lazy_static! {
134    /// The DER encoding of the object identifier (OID) 'rsaEncryption' for
135    /// RSA public keys defined for X.509 in [RFC-3279] and used in
136    /// SubjectPublicKeyInfo structures defined in [RFC-5280].
137    ///
138    /// [RFC-3279]: https://tools.ietf.org/html/rfc3279#section-2.3.1
139    /// [RFC-5280]: https://tools.ietf.org/html/rfc5280#section-4.1
140    static ref OID_RSA_ENCRYPTION_DER: DerObject =
141        DerObject {
142            tag: DerTag::x06,
143            value: DerValue {
144                data: vec![ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 ]
145            }
146        };
147}
148
149/// The ASN.1 OID for "rsaEncryption".
150#[derive(Clone)]
151struct Asn1OidRsaEncryption();
152
153impl IntoDerObject for Asn1OidRsaEncryption {
154    fn into_der_object(self) -> DerObject {
155        OID_RSA_ENCRYPTION_DER.clone()
156    }
157    fn serialized_len(&self) -> usize {
158        OID_RSA_ENCRYPTION_DER.serialized_len()
159    }
160}
161
162impl FromDerObject for Asn1OidRsaEncryption {
163    fn from_der_object(o: DerObject) -> Result<Self, Asn1DerError> {
164        if o.tag != DerTag::x06 {
165            return Err(Asn1DerError::InvalidTag);
166        }
167        if o.value != OID_RSA_ENCRYPTION_DER.value {
168            return Err(Asn1DerError::InvalidEncoding);
169        }
170        Ok(Asn1OidRsaEncryption())
171    }
172}
173
174/// The ASN.1 AlgorithmIdentifier for "rsaEncryption".
175#[derive(Asn1Der)]
176struct Asn1RsaEncryption {
177    algorithm: Asn1OidRsaEncryption,
178    parameters: (),
179}
180
181/// The ASN.1 SubjectPublicKey inside a SubjectPublicKeyInfo,
182/// i.e. encoded as a DER BIT STRING.
183struct Asn1SubjectPublicKey(PublicKey);
184
185impl IntoDerObject for Asn1SubjectPublicKey {
186    fn into_der_object(self) -> DerObject {
187        let pk_der = (self.0).0;
188        let mut bit_string = Vec::with_capacity(pk_der.len() + 1);
189        // The number of bits in pk_der is trivially always a multiple of 8,
190        // so there are always 0 "unused bits" signaled by the first byte.
191        bit_string.push(0u8);
192        bit_string.extend(pk_der);
193        DerObject::new(DerTag::x03, bit_string.into())
194    }
195    fn serialized_len(&self) -> usize {
196        DerObject::compute_serialized_len((self.0).0.len() + 1)
197    }
198}
199
200impl FromDerObject for Asn1SubjectPublicKey {
201    fn from_der_object(o: DerObject) -> Result<Self, Asn1DerError> {
202        if o.tag != DerTag::x03 {
203            return Err(Asn1DerError::InvalidTag);
204        }
205        let pk_der: Vec<u8> = o.value.data.into_iter().skip(1).collect();
206        // We don't parse pk_der further as an ASN.1 RsaPublicKey, since
207        // we only need the DER encoding for `verify`.
208        Ok(Asn1SubjectPublicKey(PublicKey(pk_der)))
209    }
210}
211
212/// ASN.1 SubjectPublicKeyInfo
213#[derive(Asn1Der)]
214#[allow(non_snake_case)]
215struct Asn1SubjectPublicKeyInfo {
216    algorithmIdentifier: Asn1RsaEncryption,
217    subjectPublicKey: Asn1SubjectPublicKey,
218}
219
220#[cfg(test)]
221mod tests {
222    use super::*;
223    use quickcheck::*;
224    use rand::seq::SliceRandom;
225    use std::fmt;
226
227    const KEY1: &[u8] = include_bytes!("test/rsa-2048.pk8");
228    const KEY2: &[u8] = include_bytes!("test/rsa-3072.pk8");
229    const KEY3: &[u8] = include_bytes!("test/rsa-4096.pk8");
230
231    #[derive(Clone)]
232    struct SomeKeypair(Keypair);
233
234    impl fmt::Debug for SomeKeypair {
235        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
236            write!(f, "SomeKeypair")
237        }
238    }
239
240    impl Arbitrary for SomeKeypair {
241        fn arbitrary<G: Gen>(g: &mut G) -> SomeKeypair {
242            let mut key = [KEY1, KEY2, KEY3].choose(g).unwrap().to_vec();
243            SomeKeypair(Keypair::from_pkcs8(&mut key).unwrap())
244        }
245    }
246
247    #[test]
248    fn rsa_from_pkcs8() {
249        assert!(Keypair::from_pkcs8(&mut KEY1.to_vec()).is_ok());
250        assert!(Keypair::from_pkcs8(&mut KEY2.to_vec()).is_ok());
251        assert!(Keypair::from_pkcs8(&mut KEY3.to_vec()).is_ok());
252    }
253
254    #[test]
255    fn rsa_x509_encode_decode() {
256        fn prop(SomeKeypair(kp): SomeKeypair) -> Result<bool, String> {
257            let pk = kp.public();
258            PublicKey::decode_x509(&pk.encode_x509())
259                .map_err(|e| e.to_string())
260                .map(|pk2| pk2 == pk)
261        }
262        QuickCheck::new().tests(10).quickcheck(prop as fn(_) -> _);
263    }
264
265    #[test]
266    fn rsa_sign_verify() {
267        fn prop(SomeKeypair(kp): SomeKeypair, msg: Vec<u8>) -> Result<bool, SigningError> {
268            kp.sign(&msg).map(|s| kp.public().verify(&msg, &s))
269        }
270        QuickCheck::new().tests(10).quickcheck(prop as fn(_, _) -> _);
271    }
272}