libp2p_core/identity/
rsa.rs

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