Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Async signing of repository objects. #163

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 110 additions & 1 deletion src/repository/cert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ use crate::uri;
use super::crypto::{
KeyIdentifier, PublicKey, SignatureAlgorithm, Signer, SigningError
};
use super::crypto::signer::{AlgorithmError, Sign, SignWithKey};
use super::crypto::signature::Signature;
use super::oid;
use super::resources::{
AsBlock, AsBlocks, AsBlocksBuilder, AsResources, AsResourcesBuilder,
Expand Down Expand Up @@ -996,6 +998,11 @@ impl TbsCert {
tbs: self
})
}

pub fn sign(self) -> EncodedTbsCert {
let encoded = Captured::from_values(Mode::Der, self.encode_ref());
EncodedTbsCert { tbs: self, encoded }
}
}


Expand Down Expand Up @@ -1990,6 +1997,38 @@ impl Sia {
}


//------------ EncodedTbsCert ------------------------------------------------

#[derive(Clone, Debug)]
pub struct EncodedTbsCert {
tbs: TbsCert,
encoded: Captured,
}

impl SignWithKey for EncodedTbsCert {
type Sign = Self;

fn set_key(self, _key: &PublicKey) -> Result<Self, AlgorithmError> {
Ok(self)
}
}

impl Sign for EncodedTbsCert {
type Final = Cert;

fn signed_data(&self) -> &[u8] {
self.encoded.as_ref()
}

fn sign(self, signature: Signature) -> Self::Final {
Cert {
signed_data: SignedData::new(self.encoded, signature),
tbs: self.tbs
}
}
}


//------------ CertBuilder ---------------------------------------------------

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -2430,6 +2469,42 @@ impl CertBuilder {
}
}

impl SignWithKey for CertBuilder {
type Sign = CertBuilderWithKey;

fn set_key(
self, public_key: &PublicKey
) -> Result<Self::Sign, AlgorithmError> {
let alg = match public_key.signature_algorithm() {
Some(alg) => alg,
None => return Err(AlgorithmError)
};
Ok(CertBuilderWithKey {
tbs_cert: self.encode_tbs_cert(alg, public_key)
})
}
}


//------------ CertBuilderWithKey --------------------------------------------

#[derive(Clone, Debug)]
pub struct CertBuilderWithKey {
tbs_cert: Captured,
}

impl Sign for CertBuilderWithKey {
type Final = SignedData;

fn signed_data(&self) -> &[u8] {
self.tbs_cert.as_ref()
}

fn sign(self, signature: Signature) -> Self::Final {
SignedData::new(self.tbs_cert, signature)
}
}


//------------ ResourceCert --------------------------------------------------

Expand Down Expand Up @@ -2703,7 +2778,6 @@ mod signer_test {
use crate::repository::tal::TalInfo;
use super::*;


#[test]
fn build_ta_cert() {
let signer = OpenSslSigner::new();
Expand All @@ -2728,4 +2802,39 @@ mod signer_test {
}
}

#[cfg(all(test, feature="softkeys"))]
mod reverse_signer_test {
use std::str::FromStr;
use crate::repository::cert::Cert;
use crate::repository::crypto::PublicKeyFormat;
use crate::repository::crypto::softsigner::OpenSslSigner;
use crate::repository::resources::{AsId, Prefix};
use crate::repository::tal::TalInfo;
use super::*;

#[test]
fn build_ta_cert() {
let signer = OpenSslSigner::new();
let key = signer.create_key(PublicKeyFormat::Rsa).unwrap();
let pubkey = signer.get_key_info(&key).unwrap();
let uri = uri::Rsync::from_str("rsync://example.com/m/p").unwrap();
let mut cert = TbsCert::new(
12u64.into(), pubkey.to_subject_name(),
Validity::from_secs(86400), None, pubkey, KeyUsage::Ca,
Overclaim::Trim
);
cert.set_basic_ca(Some(true));
cert.set_ca_repository(Some(uri.clone()));
cert.set_rpki_manifest(Some(uri.clone()));
cert.build_v4_resource_blocks(|b| b.push(Prefix::new(0, 0)));
cert.build_v6_resource_blocks(|b| b.push(Prefix::new(0, 0)));
cert.build_as_resource_blocks(|b| b.push((AsId::MIN, AsId::MAX)));
let cert = signer.sign_with_key(
key, cert.sign()
).unwrap().to_captured();
let cert = Cert::decode(cert.as_slice()).unwrap();
let talinfo = TalInfo::from_name("foo".into()).into_arc();
cert.validate_ta(talinfo, true).unwrap();
}
}

21 changes: 20 additions & 1 deletion src/repository/crypto/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use untrusted::Input;
use super::super::oid;
use super::super::util::hex;
use super::super::x509::{Name, RepresentationError};
use super::signature::Signature;
use super::signature::{Signature, SignatureAlgorithm};


//------------ PublicKeyFormat -----------------------------------------------
Expand Down Expand Up @@ -51,6 +51,17 @@ impl PublicKeyFormat {
matches!(self, PublicKeyFormat::Rsa)
}

/// Returns the RPKI signature algorithm for this key if available.
///
/// Only keys for which [`allow_rpki_cert`][Self::allow_rpki_cert] returns
/// `true` will return a value.
pub fn signature_algorithm(self) -> Option<SignatureAlgorithm> {
match self {
PublicKeyFormat::Rsa => Some(SignatureAlgorithm::default()),
_ => None
}
}

/// Returns whether the format is acceptable for router certificates.
pub fn allow_router_cert(self) -> bool {
matches!(self, PublicKeyFormat::EcdsaP256)
Expand Down Expand Up @@ -165,6 +176,14 @@ impl PublicKey {
self.algorithm.allow_rpki_cert()
}

/// Returns the RPKI signature algorithm for this key if available.
///
/// Only keys for which [`allow_rpki_cert`][Self::allow_rpki_cert] returns
/// `true` will return a value.
pub fn signature_algorithm(&self) -> Option<SignatureAlgorithm> {
self.algorithm.signature_algorithm()
}

/// Returns whether the key is acceptable for BGPSec router certificates.
pub fn allow_router_cert(&self) -> bool {
self.algorithm.allow_router_cert()
Expand Down
52 changes: 52 additions & 0 deletions src/repository/crypto/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,58 @@ use super::keys::{PublicKey, PublicKeyFormat};
use super::signature::{Signature, SignatureAlgorithm};


//------------ Experimental Reversed Signer Traits ---------------------------
//
// These will make it possible to have async signers. Instead of implementing
// a signer, we define the logic for signing something. Each signer can then
// implement a method to sign with a key or one off.


/// A type that can be signed but needs to know about the signing key.
///
/// A type implementing this trait will have to be signed in two steps. First,
/// the key is presented to the object via [`SignWithKey::set_key`]. This
/// step returns a transitional value that knows about the signing key and
/// can now be signed via the [`Sign`] trait.
pub trait SignWithKey {
/// The transitional type for actual signing.
type Sign: Sign + Sized;

fn set_key(
self, public_key: &PublicKey
) -> Result<Self::Sign, AlgorithmError>;
}

/// A type that can be signed.
///
/// The type provides access to the data to be signed via
/// [`signed_data`][Self::signed_data]. Once the signer has finished its job,
/// it can provide the signature to the value through [`sign`][Self::sign],
/// which will apply the signature and return the final, signed value.
pub trait Sign {
/// The type of a final, signed value.
type Final: Sized;

/// Returns a reference to the data to be signed.
fn signed_data(&self) -> &[u8];

/// Applies the signature and returns the final, signed value.
fn sign(self, signature: Signature) -> Self::Final;
}

/// A key of the given algorithm cannot be used to sign this object.
#[derive(Clone, Copy, Debug)]
pub struct AlgorithmError;

impl fmt::Display for AlgorithmError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("invalid algorithm")
}
}

impl std::error::Error for AlgorithmError { }


//------------ Signer --------------------------------------------------------

/// A type that allow creating signatures.
Expand Down
53 changes: 48 additions & 5 deletions src/repository/crypto/softsigner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ use ring::rand;
use ring::rand::SecureRandom;
use super::keys::{PublicKey, PublicKeyFormat};
use super::signature::{Signature, SignatureAlgorithm};
use super::signer::{KeyError, Signer, SigningError};
use super::signer::{
AlgorithmError, KeyError, Sign, SignWithKey, Signer, SigningError
};



Expand Down Expand Up @@ -44,6 +46,26 @@ impl OpenSslSigner {
Ok(self.insert_key(KeyPair::from_pem(pem)?))
}

pub fn sign_with_key<What: SignWithKey>(
&self, key: KeyId, what: What
) -> Result<<What::Sign as Sign>::Final, SignError> {
let key = self.get_key(key).map_err(|_| SignError::KeyNotFound)?;
let info = key.get_key_info()?;
let what = what.set_key(&info)?;
let signature = key.sign(what.signed_data())?;
Ok(what.sign(signature))
}

pub fn sign_with_one_off_key<What: SignWithKey>(
&self, algorithm: SignatureAlgorithm, what: What
) -> Result<<What::Sign as Sign>::Final, SignError> {
let key = KeyPair::new(algorithm.public_key_format())?;
let info = key.get_key_info()?;
let what = what.set_key(&info)?;
let signature = key.sign(what.signed_data())?;
Ok(what.sign(signature))
}

fn insert_key(&self, key: KeyPair) -> KeyId {
let mut keys = self.keys.write().unwrap();
let res = keys.len();
Expand Down Expand Up @@ -100,10 +122,10 @@ impl Signer for OpenSslSigner {
fn sign<D: AsRef<[u8]> + ?Sized>(
&self,
key: &Self::KeyId,
algorithm: SignatureAlgorithm,
_algorithm: SignatureAlgorithm,
data: &D
) -> Result<Signature, SigningError<Self::Error>> {
self.get_key(*key)?.sign(algorithm, data.as_ref()).map_err(Into::into)
self.get_key(*key)?.sign(data.as_ref()).map_err(Into::into)
}

fn sign_one_off<D: AsRef<[u8]> + ?Sized>(
Expand All @@ -113,7 +135,7 @@ impl Signer for OpenSslSigner {
) -> Result<(Signature, PublicKey), Self::Error> {
let key = KeyPair::new(algorithm.public_key_format())?;
let info = key.get_key_info()?;
let sig = key.sign(algorithm, data.as_ref())?;
let sig = key.sign(data.as_ref())?;
Ok((sig, info))
}

Expand Down Expand Up @@ -193,7 +215,6 @@ impl KeyPair {

fn sign(
&self,
_algorithm: SignatureAlgorithm,
data: &[u8]
) -> Result<Signature, io::Error> {
let mut signer = ::openssl::sign::Signer::new(
Expand All @@ -208,6 +229,28 @@ impl KeyPair {
}


//------------ SignError -----------------------------------------------------

#[derive(Debug)]
pub enum SignError {
KeyNotFound,
AlgorithmError,
Io(io::Error)
}

impl From<AlgorithmError> for SignError {
fn from(_: AlgorithmError) -> Self {
SignError::AlgorithmError
}
}

impl From<io::Error> for SignError {
fn from(err: io::Error) -> Self {
SignError::Io(err)
}
}


//------------ Tests ---------------------------------------------------------

#[cfg(test)]
Expand Down
Loading