2019-03-11 13:42:53 +01:00
|
|
|
// Copyright 2019 Parity Technologies (UK) Ltd.
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
// copy of this software and associated documentation files (the "Software"),
|
|
|
|
// to deal in the Software without restriction, including without limitation
|
|
|
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
// and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
// Software is furnished to do so, subject to the following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
// all copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
// DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
//! RSA keys.
|
|
|
|
|
|
|
|
use super::error::*;
|
2021-08-11 13:12:12 +02:00
|
|
|
use asn1_der::typed::{DerDecodable, DerEncodable, DerTypeView, Sequence};
|
|
|
|
use asn1_der::{Asn1DerError, Asn1DerErrorVariant, DerObject, Sink, VecBacking};
|
2019-03-11 13:42:53 +01:00
|
|
|
use ring::rand::SystemRandom;
|
|
|
|
use ring::signature::KeyPair;
|
2021-08-11 13:12:12 +02:00
|
|
|
use ring::signature::{self, RsaKeyPair, RSA_PKCS1_2048_8192_SHA256, RSA_PKCS1_SHA256};
|
2021-03-09 10:56:19 +01:00
|
|
|
use std::{fmt, sync::Arc};
|
2019-03-11 13:42:53 +01:00
|
|
|
use zeroize::Zeroize;
|
|
|
|
|
|
|
|
/// An RSA keypair.
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Keypair(Arc<RsaKeyPair>);
|
|
|
|
|
2022-02-16 17:16:54 +02:00
|
|
|
impl std::fmt::Debug for Keypair {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
|
|
f.debug_struct("Keypair")
|
|
|
|
.field("public", self.0.public_key())
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-11 13:42:53 +01:00
|
|
|
impl Keypair {
|
|
|
|
/// Decode an RSA keypair from a DER-encoded private key in PKCS#8 PrivateKeyInfo
|
|
|
|
/// format (i.e. unencrypted) as defined in [RFC5208].
|
|
|
|
///
|
|
|
|
/// [RFC5208]: https://tools.ietf.org/html/rfc5208#section-5
|
|
|
|
pub fn from_pkcs8(der: &mut [u8]) -> Result<Keypair, DecodingError> {
|
2021-09-14 16:00:05 +03:00
|
|
|
let kp = RsaKeyPair::from_pkcs8(der)
|
2019-05-14 19:33:30 +02:00
|
|
|
.map_err(|e| DecodingError::new("RSA PKCS#8 PrivateKeyInfo").source(e))?;
|
2019-03-11 13:42:53 +01:00
|
|
|
der.zeroize();
|
|
|
|
Ok(Keypair(Arc::new(kp)))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the public key from the keypair.
|
|
|
|
pub fn public(&self) -> PublicKey {
|
|
|
|
PublicKey(self.0.public_key().as_ref().to_vec())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sign a message with this keypair.
|
|
|
|
pub fn sign(&self, data: &[u8]) -> Result<Vec<u8>, SigningError> {
|
|
|
|
let mut signature = vec![0; self.0.public_modulus_len()];
|
|
|
|
let rng = SystemRandom::new();
|
2021-09-14 16:00:05 +03:00
|
|
|
match self.0.sign(&RSA_PKCS1_SHA256, &rng, data, &mut signature) {
|
2019-03-11 13:42:53 +01:00
|
|
|
Ok(()) => Ok(signature),
|
2021-08-11 13:12:12 +02:00
|
|
|
Err(e) => Err(SigningError::new("RSA").source(e)),
|
2019-03-11 13:42:53 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// An RSA public key.
|
2020-02-05 19:50:13 +01:00
|
|
|
#[derive(Clone, PartialEq, Eq)]
|
2019-03-11 13:42:53 +01:00
|
|
|
pub struct PublicKey(Vec<u8>);
|
|
|
|
|
|
|
|
impl PublicKey {
|
|
|
|
/// Verify an RSA signature on a message using the public key.
|
|
|
|
pub fn verify(&self, msg: &[u8], sig: &[u8]) -> bool {
|
2019-10-11 04:19:35 -04:00
|
|
|
let key = signature::UnparsedPublicKey::new(&RSA_PKCS1_2048_8192_SHA256, &self.0);
|
|
|
|
key.verify(msg, sig).is_ok()
|
2019-03-11 13:42:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Encode the RSA public key in DER as a PKCS#1 RSAPublicKey structure,
|
|
|
|
/// as defined in [RFC3447].
|
|
|
|
///
|
|
|
|
/// [RFC3447]: https://tools.ietf.org/html/rfc3447#appendix-A.1.1
|
|
|
|
pub fn encode_pkcs1(&self) -> Vec<u8> {
|
|
|
|
// This is the encoding currently used in-memory, so it is trivial.
|
|
|
|
self.0.clone()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Encode the RSA public key in DER as a X.509 SubjectPublicKeyInfo structure,
|
|
|
|
/// as defined in [RFC5280].
|
|
|
|
///
|
2020-02-10 15:17:08 +01:00
|
|
|
/// [RFC5280]: https://tools.ietf.org/html/rfc5280#section-4.1
|
2019-03-11 13:42:53 +01:00
|
|
|
pub fn encode_x509(&self) -> Vec<u8> {
|
|
|
|
let spki = Asn1SubjectPublicKeyInfo {
|
|
|
|
algorithmIdentifier: Asn1RsaEncryption {
|
2021-03-22 13:53:47 +01:00
|
|
|
algorithm: Asn1OidRsaEncryption,
|
2021-08-11 13:12:12 +02:00
|
|
|
parameters: (),
|
2019-03-11 13:42:53 +01:00
|
|
|
},
|
2021-08-11 13:12:12 +02:00
|
|
|
subjectPublicKey: Asn1SubjectPublicKey(self.clone()),
|
2019-03-11 13:42:53 +01:00
|
|
|
};
|
2021-03-22 13:53:47 +01:00
|
|
|
let mut buf = Vec::new();
|
2021-09-14 16:00:05 +03:00
|
|
|
spki.encode(&mut buf)
|
2021-08-11 13:12:12 +02:00
|
|
|
.map(|_| buf)
|
2021-09-14 16:00:05 +03:00
|
|
|
.expect("RSA X.509 public key encoding failed.")
|
2019-03-11 13:42:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Decode an RSA public key from a DER-encoded X.509 SubjectPublicKeyInfo
|
|
|
|
/// structure. See also `encode_x509`.
|
|
|
|
pub fn decode_x509(pk: &[u8]) -> Result<PublicKey, DecodingError> {
|
2021-03-22 13:53:47 +01:00
|
|
|
Asn1SubjectPublicKeyInfo::decode(pk)
|
2019-05-14 19:33:30 +02:00
|
|
|
.map_err(|e| DecodingError::new("RSA X.509").source(e))
|
2019-03-11 13:42:53 +01:00
|
|
|
.map(|spki| spki.subjectPublicKey.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-05 19:50:13 +01:00
|
|
|
impl fmt::Debug for PublicKey {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2021-03-09 10:56:19 +01:00
|
|
|
f.write_str("PublicKey(PKCS1): ")?;
|
|
|
|
for byte in &self.0 {
|
|
|
|
write!(f, "{:x}", byte)?;
|
2020-02-05 19:50:13 +01:00
|
|
|
}
|
2021-03-09 10:56:19 +01:00
|
|
|
Ok(())
|
2020-02-05 19:50:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-11 13:42:53 +01:00
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
// DER encoding / decoding of public keys
|
|
|
|
//
|
|
|
|
// Primer: http://luca.ntop.org/Teaching/Appunti/asn1.html
|
|
|
|
// Playground: https://lapo.it/asn1js/
|
|
|
|
|
2021-03-22 13:53:47 +01:00
|
|
|
/// A raw ASN1 OID.
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
struct Asn1RawOid<'a> {
|
2021-08-11 13:12:12 +02:00
|
|
|
object: DerObject<'a>,
|
2021-03-22 13:53:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Asn1RawOid<'a> {
|
|
|
|
/// The underlying OID as byte literal.
|
|
|
|
pub fn oid(&self) -> &[u8] {
|
|
|
|
self.object.value()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Writes an OID raw `value` as DER-object to `sink`.
|
|
|
|
pub fn write<S: Sink>(value: &[u8], sink: &mut S) -> Result<(), Asn1DerError> {
|
|
|
|
DerObject::write(Self::TAG, value.len(), &mut value.iter(), sink)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> DerTypeView<'a> for Asn1RawOid<'a> {
|
|
|
|
const TAG: u8 = 6;
|
|
|
|
|
|
|
|
fn object(&self) -> DerObject<'a> {
|
|
|
|
self.object
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> DerEncodable for Asn1RawOid<'a> {
|
|
|
|
fn encode<S: Sink>(&self, sink: &mut S) -> Result<(), Asn1DerError> {
|
|
|
|
self.object.encode(sink)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> DerDecodable<'a> for Asn1RawOid<'a> {
|
|
|
|
fn load(object: DerObject<'a>) -> Result<Self, Asn1DerError> {
|
|
|
|
if object.tag() != Self::TAG {
|
|
|
|
return Err(Asn1DerError::new(Asn1DerErrorVariant::InvalidData(
|
|
|
|
"DER object tag is not the object identifier tag.",
|
|
|
|
)));
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(Self { object })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The ASN.1 OID for "rsaEncryption".
|
|
|
|
#[derive(Clone)]
|
|
|
|
struct Asn1OidRsaEncryption;
|
|
|
|
|
|
|
|
impl Asn1OidRsaEncryption {
|
2019-03-11 13:42:53 +01:00
|
|
|
/// The DER encoding of the object identifier (OID) 'rsaEncryption' for
|
|
|
|
/// RSA public keys defined for X.509 in [RFC-3279] and used in
|
|
|
|
/// SubjectPublicKeyInfo structures defined in [RFC-5280].
|
|
|
|
///
|
|
|
|
/// [RFC-3279]: https://tools.ietf.org/html/rfc3279#section-2.3.1
|
|
|
|
/// [RFC-5280]: https://tools.ietf.org/html/rfc5280#section-4.1
|
2021-08-11 13:12:12 +02:00
|
|
|
const OID: [u8; 9] = [0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01];
|
2019-03-11 13:42:53 +01:00
|
|
|
}
|
|
|
|
|
2021-03-22 13:53:47 +01:00
|
|
|
impl DerEncodable for Asn1OidRsaEncryption {
|
|
|
|
fn encode<S: Sink>(&self, sink: &mut S) -> Result<(), Asn1DerError> {
|
|
|
|
Asn1RawOid::write(&Self::OID, sink)
|
2019-03-11 13:42:53 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-22 13:53:47 +01:00
|
|
|
impl DerDecodable<'_> for Asn1OidRsaEncryption {
|
|
|
|
fn load(object: DerObject<'_>) -> Result<Self, Asn1DerError> {
|
|
|
|
match Asn1RawOid::load(object)?.oid() {
|
|
|
|
oid if oid == Self::OID => Ok(Self),
|
|
|
|
_ => Err(Asn1DerError::new(Asn1DerErrorVariant::InvalidData(
|
|
|
|
"DER object is not the 'rsaEncryption' identifier.",
|
2021-08-11 13:12:12 +02:00
|
|
|
))),
|
2019-03-11 13:42:53 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The ASN.1 AlgorithmIdentifier for "rsaEncryption".
|
|
|
|
struct Asn1RsaEncryption {
|
|
|
|
algorithm: Asn1OidRsaEncryption,
|
2021-08-11 13:12:12 +02:00
|
|
|
parameters: (),
|
2019-03-11 13:42:53 +01:00
|
|
|
}
|
|
|
|
|
2021-03-22 13:53:47 +01:00
|
|
|
impl DerEncodable for Asn1RsaEncryption {
|
|
|
|
fn encode<S: Sink>(&self, sink: &mut S) -> Result<(), Asn1DerError> {
|
|
|
|
let mut algorithm_buf = Vec::new();
|
|
|
|
let algorithm = self.algorithm.der_object(VecBacking(&mut algorithm_buf))?;
|
|
|
|
|
|
|
|
let mut parameters_buf = Vec::new();
|
2021-08-11 13:12:12 +02:00
|
|
|
let parameters = self
|
|
|
|
.parameters
|
|
|
|
.der_object(VecBacking(&mut parameters_buf))?;
|
2021-03-22 13:53:47 +01:00
|
|
|
|
|
|
|
Sequence::write(&[algorithm, parameters], sink)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DerDecodable<'_> for Asn1RsaEncryption {
|
|
|
|
fn load(object: DerObject<'_>) -> Result<Self, Asn1DerError> {
|
|
|
|
let seq: Sequence = Sequence::load(object)?;
|
|
|
|
|
2021-08-11 13:12:12 +02:00
|
|
|
Ok(Self {
|
2021-03-22 13:53:47 +01:00
|
|
|
algorithm: seq.get_as(0)?,
|
|
|
|
parameters: seq.get_as(1)?,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-11 13:42:53 +01:00
|
|
|
/// The ASN.1 SubjectPublicKey inside a SubjectPublicKeyInfo,
|
|
|
|
/// i.e. encoded as a DER BIT STRING.
|
|
|
|
struct Asn1SubjectPublicKey(PublicKey);
|
|
|
|
|
2021-03-22 13:53:47 +01:00
|
|
|
impl DerEncodable for Asn1SubjectPublicKey {
|
|
|
|
fn encode<S: Sink>(&self, sink: &mut S) -> Result<(), Asn1DerError> {
|
|
|
|
let pk_der = &(self.0).0;
|
2019-03-11 13:42:53 +01:00
|
|
|
let mut bit_string = Vec::with_capacity(pk_der.len() + 1);
|
|
|
|
// The number of bits in pk_der is trivially always a multiple of 8,
|
|
|
|
// so there are always 0 "unused bits" signaled by the first byte.
|
|
|
|
bit_string.push(0u8);
|
|
|
|
bit_string.extend(pk_der);
|
2021-03-22 13:53:47 +01:00
|
|
|
DerObject::write(3, bit_string.len(), &mut bit_string.iter(), sink)?;
|
|
|
|
Ok(())
|
2019-03-11 13:42:53 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-22 13:53:47 +01:00
|
|
|
impl DerDecodable<'_> for Asn1SubjectPublicKey {
|
|
|
|
fn load(object: DerObject<'_>) -> Result<Self, Asn1DerError> {
|
|
|
|
if object.tag() != 3 {
|
2021-08-11 13:12:12 +02:00
|
|
|
return Err(Asn1DerError::new(Asn1DerErrorVariant::InvalidData(
|
|
|
|
"DER object tag is not the bit string tag.",
|
|
|
|
)));
|
2019-03-11 13:42:53 +01:00
|
|
|
}
|
2021-03-22 13:53:47 +01:00
|
|
|
|
|
|
|
let pk_der: Vec<u8> = object.value().into_iter().skip(1).cloned().collect();
|
2019-03-11 13:42:53 +01:00
|
|
|
// We don't parse pk_der further as an ASN.1 RsaPublicKey, since
|
|
|
|
// we only need the DER encoding for `verify`.
|
2021-03-22 13:53:47 +01:00
|
|
|
Ok(Self(PublicKey(pk_der)))
|
2019-03-11 13:42:53 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ASN.1 SubjectPublicKeyInfo
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
struct Asn1SubjectPublicKeyInfo {
|
|
|
|
algorithmIdentifier: Asn1RsaEncryption,
|
2021-08-11 13:12:12 +02:00
|
|
|
subjectPublicKey: Asn1SubjectPublicKey,
|
2019-03-11 13:42:53 +01:00
|
|
|
}
|
|
|
|
|
2021-03-22 13:53:47 +01:00
|
|
|
impl DerEncodable for Asn1SubjectPublicKeyInfo {
|
|
|
|
fn encode<S: Sink>(&self, sink: &mut S) -> Result<(), Asn1DerError> {
|
|
|
|
let mut identifier_buf = Vec::new();
|
2021-08-11 13:12:12 +02:00
|
|
|
let identifier = self
|
|
|
|
.algorithmIdentifier
|
|
|
|
.der_object(VecBacking(&mut identifier_buf))?;
|
2021-03-22 13:53:47 +01:00
|
|
|
|
|
|
|
let mut key_buf = Vec::new();
|
|
|
|
let key = self.subjectPublicKey.der_object(VecBacking(&mut key_buf))?;
|
|
|
|
|
|
|
|
Sequence::write(&[identifier, key], sink)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DerDecodable<'_> for Asn1SubjectPublicKeyInfo {
|
|
|
|
fn load(object: DerObject<'_>) -> Result<Self, Asn1DerError> {
|
|
|
|
let seq: Sequence = Sequence::load(object)?;
|
|
|
|
|
|
|
|
Ok(Self {
|
|
|
|
algorithmIdentifier: seq.get_as(0)?,
|
|
|
|
subjectPublicKey: seq.get_as(1)?,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-11 13:42:53 +01:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
use quickcheck::*;
|
2021-10-22 18:09:02 +08:00
|
|
|
use rand07::seq::SliceRandom;
|
2019-03-11 13:42:53 +01:00
|
|
|
use std::fmt;
|
|
|
|
|
|
|
|
const KEY1: &'static [u8] = include_bytes!("test/rsa-2048.pk8");
|
|
|
|
const KEY2: &'static [u8] = include_bytes!("test/rsa-3072.pk8");
|
|
|
|
const KEY3: &'static [u8] = include_bytes!("test/rsa-4096.pk8");
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
struct SomeKeypair(Keypair);
|
|
|
|
|
|
|
|
impl fmt::Debug for SomeKeypair {
|
2020-07-27 20:27:33 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2019-03-11 13:42:53 +01:00
|
|
|
write!(f, "SomeKeypair")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Arbitrary for SomeKeypair {
|
|
|
|
fn arbitrary<G: Gen>(g: &mut G) -> SomeKeypair {
|
|
|
|
let mut key = [KEY1, KEY2, KEY3].choose(g).unwrap().to_vec();
|
|
|
|
SomeKeypair(Keypair::from_pkcs8(&mut key).unwrap())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn rsa_from_pkcs8() {
|
|
|
|
assert!(Keypair::from_pkcs8(&mut KEY1.to_vec()).is_ok());
|
|
|
|
assert!(Keypair::from_pkcs8(&mut KEY2.to_vec()).is_ok());
|
|
|
|
assert!(Keypair::from_pkcs8(&mut KEY3.to_vec()).is_ok());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn rsa_x509_encode_decode() {
|
|
|
|
fn prop(SomeKeypair(kp): SomeKeypair) -> Result<bool, String> {
|
|
|
|
let pk = kp.public();
|
|
|
|
PublicKey::decode_x509(&pk.encode_x509())
|
|
|
|
.map_err(|e| e.to_string())
|
|
|
|
.map(|pk2| pk2 == pk)
|
|
|
|
}
|
|
|
|
QuickCheck::new().tests(10).quickcheck(prop as fn(_) -> _);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn rsa_sign_verify() {
|
|
|
|
fn prop(SomeKeypair(kp): SomeKeypair, msg: Vec<u8>) -> Result<bool, SigningError> {
|
|
|
|
kp.sign(&msg).map(|s| kp.public().verify(&msg, &s))
|
|
|
|
}
|
2021-08-11 13:12:12 +02:00
|
|
|
QuickCheck::new()
|
|
|
|
.tests(10)
|
|
|
|
.quickcheck(prop as fn(_, _) -> _);
|
2019-03-11 13:42:53 +01:00
|
|
|
}
|
|
|
|
}
|