blob: a0d9d6d788618a8b5ec0adc088715b4035879881 [file] [log] [blame]
use chrono::DateTime;
use chrono::offset::Utc;
use data_encoding::HEXLOWER;
use ring;
use ring::digest::{self, SHA256};
use ring::signature::{ED25519, RSA_PSS_2048_8192_SHA256, RSA_PSS_2048_8192_SHA512};
use serde::de::{Deserialize, DeserializeOwned, Deserializer, Error as DeserializeError};
use serde::ser::{Serialize, Serializer, SerializeTupleStruct, Error as SerializeError};
use std::collections::{HashMap, HashSet};
use std::fmt::{self, Debug};
use std::marker::PhantomData;
use std::str::FromStr;
use untrusted::Input;
use Result;
use error::Error;
use metadata::interchange::{RawData, DataInterchange};
use metadata::shims;
pub fn calculate_key_id(public_key: &PublicKeyValue) -> KeyId {
let mut context = digest::Context::new(&SHA256);
context.update(&public_key.0);
KeyId(context.finish().as_ref().to_vec())
}
#[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Role {
#[serde(rename = "root")]
Root,
#[serde(rename = "snapshot")]
Snapshot,
#[serde(rename = "targets")]
Targets,
#[serde(rename = "timestamp")]
Timestamp,
}
#[derive(Debug)]
pub enum MetadataVersion {
None,
Number(u32),
Hash(String),
}
impl MetadataVersion {
pub fn prefix(&self) -> String {
match self {
&MetadataVersion::None => String::new(),
&MetadataVersion::Number(ref x) => format!("{}.", x),
&MetadataVersion::Hash(ref s) => format!("{}.", s),
}
}
}
pub trait Metadata: Debug + PartialEq + Serialize + DeserializeOwned {}
#[derive(Debug, Serialize, Deserialize)]
pub struct SignedMetadata<D, R, M>
where
D: DataInterchange,
R: RawData<D>,
M: Metadata,
{
signatures: Vec<Signature>,
signed: R,
_interchage: PhantomData<D>,
_metadata: PhantomData<M>,
}
impl<D, R, M> SignedMetadata<D, R, M>
where
D: DataInterchange,
R: RawData<D>,
M: Metadata,
{
pub fn signatures(&self) -> &[Signature] {
&self.signatures
}
pub fn signatures_mut(&mut self) -> &mut Vec<Signature> {
&mut self.signatures
}
pub fn signed(&self) -> &R {
&self.signed
}
}
#[derive(Debug, PartialEq)]
pub struct RootMetadata {
version: u32,
expires: DateTime<Utc>,
consistent_snapshot: bool,
keys: HashMap<KeyId, PublicKey>,
root: RoleDefinition,
snapshot: RoleDefinition,
targets: RoleDefinition,
timestamp: RoleDefinition,
}
impl RootMetadata {
pub fn new(
version: u32,
expires: DateTime<Utc>,
consistent_snapshot: bool,
keys: HashMap<KeyId, PublicKey>,
root: RoleDefinition,
snapshot: RoleDefinition,
targets: RoleDefinition,
timestamp: RoleDefinition,
) -> Self {
RootMetadata {
version: version,
expires: expires,
consistent_snapshot: consistent_snapshot,
keys: keys,
root: root,
snapshot: snapshot,
targets: targets,
timestamp: timestamp,
}
}
pub fn version(&self) -> u32 {
self.version
}
pub fn expires(&self) -> &DateTime<Utc> {
&self.expires
}
pub fn consistent_snapshot(&self) -> bool {
self.consistent_snapshot
}
pub fn keys(&self) -> &HashMap<KeyId, PublicKey> {
&self.keys
}
pub fn root(&self) -> &RoleDefinition {
&self.root
}
pub fn snapshot(&self) -> &RoleDefinition {
&self.snapshot
}
pub fn targets(&self) -> &RoleDefinition {
&self.targets
}
pub fn timestamp(&self) -> &RoleDefinition {
&self.timestamp
}
}
impl Metadata for RootMetadata {}
impl Serialize for RootMetadata {
fn serialize<S>(&self, ser: S) -> ::std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
shims::RootMetadata::from(self)
.map_err(|e| SerializeError::custom(format!("{:?}", e)))?
.serialize(ser)
}
}
impl<'de> Deserialize<'de> for RootMetadata {
fn deserialize<D: Deserializer<'de>>(de: D) -> ::std::result::Result<Self, D::Error> {
let intermediate: shims::RootMetadata = Deserialize::deserialize(de)?;
intermediate.try_into().map_err(|e| {
DeserializeError::custom(format!("{:?}", e))
})
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Signature {
key_id: KeyId,
scheme: SignatureScheme,
signature: SignatureValue,
}
impl Signature {
pub fn key_id(&self) -> &KeyId {
&self.key_id
}
pub fn scheme(&self) -> &SignatureScheme {
&self.scheme
}
pub fn signature(&self) -> &SignatureValue {
&self.signature
}
}
/// A `KeyId` is calculated as `sha256(public_key_bytes)`. The TUF spec says that it should be
/// `sha256(cjson(encoded(public_key_bytes)))`, but this is meaningless once the spec moves away
/// from using only JSON as the data interchange format.
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct KeyId(Vec<u8>);
impl KeyId {
pub fn new(bytes: Vec<u8>) -> Self {
KeyId(bytes)
}
pub fn from_string(string: &str) -> Result<Self> {
Ok(KeyId(HEXLOWER.decode(string.as_bytes())?))
}
}
impl Debug for KeyId {
fn fmt(&self, f: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
write!(f, "KeyId {{ \"{}\" }}", HEXLOWER.encode(&self.0))
}
}
impl Serialize for KeyId {
fn serialize<S>(&self, ser: S) -> ::std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut s = ser.serialize_tuple_struct("KeyId", 1)?;
s.serialize_field(&HEXLOWER.encode(&self.0))?;
s.end()
}
}
impl<'de> Deserialize<'de> for KeyId {
fn deserialize<D: Deserializer<'de>>(de: D) -> ::std::result::Result<Self, D::Error> {
let mut string: String = Deserialize::deserialize(de)?;
KeyId::from_string(&string).map_err(|e| DeserializeError::custom("shit!".to_string()))
}
}
#[derive(Debug, PartialEq)]
pub enum SignatureScheme {
Ed25519,
RsaSsaPssSha256,
RsaSsaPssSha512,
}
impl SignatureScheme {}
impl ToString for SignatureScheme {
fn to_string(&self) -> String {
match self {
&SignatureScheme::Ed25519 => "ed25519",
&SignatureScheme::RsaSsaPssSha256 => "rsassa-pss-sha256",
&SignatureScheme::RsaSsaPssSha512 => "rsassa-pss-sha512",
}.to_string()
}
}
impl FromStr for SignatureScheme {
type Err = Error;
fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
match s {
"ed25519" => Ok(SignatureScheme::Ed25519),
"rsassa-pss-sha256" => Ok(SignatureScheme::RsaSsaPssSha256),
"rsassa-pss-sha512" => Ok(SignatureScheme::RsaSsaPssSha512),
typ => Err(Error::UnsupportedSignatureScheme(typ.into())),
}
}
}
impl Serialize for SignatureScheme {
fn serialize<S>(&self, ser: S) -> ::std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
ser.serialize_str(&self.to_string())
}
}
impl<'de> Deserialize<'de> for SignatureScheme {
fn deserialize<D: Deserializer<'de>>(de: D) -> ::std::result::Result<Self, D::Error> {
let mut string: String = Deserialize::deserialize(de)?;
Ok(string.parse().unwrap())
}
}
#[derive(PartialEq)]
pub struct SignatureValue(Vec<u8>);
impl SignatureValue {
pub fn new(bytes: Vec<u8>) -> Self {
SignatureValue(bytes)
}
pub fn from_string(string: &str) -> Result<Self> {
Ok(SignatureValue(HEXLOWER.decode(string.as_bytes())?))
}
}
impl Debug for SignatureValue {
fn fmt(&self, f: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
write!(f, "SignatureValue {{ \"{}\" }}", HEXLOWER.encode(&self.0))
}
}
impl Serialize for SignatureValue {
fn serialize<S>(&self, ser: S) -> ::std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut s = ser.serialize_tuple_struct("SignatureValue", 1)?;
s.serialize_field(&HEXLOWER.encode(&self.0))?;
s.end()
}
}
impl<'de> Deserialize<'de> for SignatureValue {
fn deserialize<D: Deserializer<'de>>(de: D) -> ::std::result::Result<Self, D::Error> {
let mut string: String = Deserialize::deserialize(de)?;
SignatureValue::from_string(&string).map_err(|e| {
DeserializeError::custom("Signature value was not valid hex lower".to_string())
})
}
}
/// Types of public keys.
#[derive(Clone, PartialEq, Debug)]
pub enum KeyType {
/// [Ed25519](https://en.wikipedia.org/wiki/EdDSA#Ed25519)
Ed25519,
/// [RSA](https://en.wikipedia.org/wiki/RSA_%28cryptosystem%29)
Rsa,
}
impl FromStr for KeyType {
type Err = Error;
fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
match s {
"ed25519" => Ok(KeyType::Ed25519),
"rsa" => Ok(KeyType::Rsa),
typ => Err(Error::UnsupportedKeyType(typ.into())),
}
}
}
impl ToString for KeyType {
fn to_string(&self) -> String {
match self {
&KeyType::Ed25519 => "ed25519",
&KeyType::Rsa => "rsa",
}.to_string()
}
}
impl Serialize for KeyType {
fn serialize<S>(&self, ser: S) -> ::std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
ser.serialize_str(&self.to_string())
}
}
impl<'de> Deserialize<'de> for KeyType {
fn deserialize<D: Deserializer<'de>>(de: D) -> ::std::result::Result<Self, D::Error> {
let mut string: String = Deserialize::deserialize(de)?;
Ok(string.parse().unwrap())
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct PublicKey {
typ: KeyType,
format: KeyFormat,
key_id: KeyId,
value: PublicKeyValue,
}
impl PublicKey {
pub fn new(typ: KeyType, format: KeyFormat, value: PublicKeyValue) -> Self {
PublicKey {
typ: typ,
format: format,
key_id: calculate_key_id(&value),
value: value,
}
}
pub fn typ(&self) -> &KeyType {
&self.typ
}
pub fn format(&self) -> &KeyFormat {
&self.format
}
pub fn key_id(&self) -> &KeyId {
&self.key_id
}
pub fn value(&self) -> &PublicKeyValue {
&self.value
}
pub fn verify(&self, scheme: &SignatureScheme, msg: &[u8], sig: &SignatureValue) -> Result<()> {
let alg: &ring::signature::VerificationAlgorithm = match scheme {
&SignatureScheme::Ed25519 => &ED25519,
&SignatureScheme::RsaSsaPssSha256 => &RSA_PSS_2048_8192_SHA256,
&SignatureScheme::RsaSsaPssSha512 => &RSA_PSS_2048_8192_SHA512,
};
ring::signature::verify(
alg,
Input::from(&self.value.0),
Input::from(msg),
Input::from(&sig.0),
).map_err(|_: ring::error::Unspecified| Error::BadSignature)
}
}
impl Serialize for PublicKey {
fn serialize<S>(&self, ser: S) -> ::std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
shims::PublicKey::from(self)
.map_err(|e| SerializeError::custom(format!("{:?}", e)))?
.serialize(ser)
}
}
impl<'de> Deserialize<'de> for PublicKey {
fn deserialize<D: Deserializer<'de>>(de: D) -> ::std::result::Result<Self, D::Error> {
let intermediate: shims::PublicKey = Deserialize::deserialize(de)?;
intermediate.try_into().map_err(|e| {
DeserializeError::custom(format!("{:?}", e))
})
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct PublicKeyValue(Vec<u8>);
impl PublicKeyValue {
pub fn new(bytes: Vec<u8>) -> Self {
PublicKeyValue(bytes)
}
pub fn value(&self) -> &[u8] {
&self.0
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum KeyFormat {
HexLower,
Pkcs1,
Spki,
}
#[derive(Clone, Debug, PartialEq)]
pub struct RoleDefinition {
threshold: u32,
key_ids: HashSet<KeyId>,
}
impl RoleDefinition {
pub fn new(threshold: u32, key_ids: HashSet<KeyId>) -> Result<Self> {
if threshold < 1 {
return Err(Error::Encode(format!("Illegal threshold: {}", threshold)));
}
Ok(RoleDefinition {
threshold: threshold,
key_ids: key_ids,
})
}
pub fn threshold(&self) -> u32 {
self.threshold
}
pub fn key_ids(&self) -> &HashSet<KeyId> {
&self.key_ids
}
}
impl Serialize for RoleDefinition {
fn serialize<S>(&self, ser: S) -> ::std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
shims::RoleDefinition::from(self)
.map_err(|e| SerializeError::custom(format!("{:?}", e)))?
.serialize(ser)
}
}
impl<'de> Deserialize<'de> for RoleDefinition {
fn deserialize<D: Deserializer<'de>>(de: D) -> ::std::result::Result<Self, D::Error> {
let intermediate: shims::RoleDefinition = Deserialize::deserialize(de)?;
intermediate.try_into().map_err(|e| {
DeserializeError::custom(format!("{:?}", e))
})
}
}
#[cfg(test)]
mod test {
use super::*;
use json;
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;
#[test]
fn parse_spki_json() {
let mut jsn = json!({"type": "rsa", "value": {}});
let mut file = File::open(
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("tests")
.join("rsa")
.join("spki-1.pub"),
).unwrap();
let mut buf = String::new();
file.read_to_string(&mut buf).unwrap();
let _ = jsn.as_object_mut()
.unwrap()
.get_mut("value")
.unwrap()
.as_object_mut()
.unwrap()
.insert("public".into(), json::Value::String(buf.trim().into()));
let key: PublicKey = json::from_value(jsn.clone()).unwrap();
assert_eq!(key.typ(), &KeyType::Rsa);
assert_eq!(key.format(), &KeyFormat::Spki);
let deserialized: json::Value = json::to_value(key).unwrap();
assert_eq!(deserialized, jsn);
}
#[test]
fn parse_pkcs1_json() {
let mut jsn = json!({"type": "rsa", "value": {}});
let mut file = File::open(
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("tests")
.join("rsa")
.join("pkcs1-1.pub"),
).unwrap();
let mut buf = String::new();
file.read_to_string(&mut buf).unwrap();
let _ = jsn.as_object_mut()
.unwrap()
.get_mut("value")
.unwrap()
.as_object_mut()
.unwrap()
.insert("public".into(), json::Value::String(buf.trim().into()));
let key: PublicKey = json::from_value(jsn.clone()).unwrap();
assert_eq!(key.typ(), &KeyType::Rsa);
assert_eq!(key.format(), &KeyFormat::Pkcs1);
let deserialized: json::Value = json::to_value(key).unwrap();
assert_eq!(deserialized, jsn);
}
#[test]
fn parse_hex_json() {
let mut jsn = json!({"type": "ed25519", "value": {}});
let buf = "2bedead4feed".to_string();
let _ = jsn.as_object_mut()
.unwrap()
.get_mut("value")
.unwrap()
.as_object_mut()
.unwrap()
.insert("public".into(), json::Value::String(buf.clone()));
let key: PublicKey = json::from_value(jsn.clone()).unwrap();
assert_eq!(key.typ(), &KeyType::Ed25519);
assert_eq!(key.format(), &KeyFormat::HexLower);
let deserialized: json::Value = json::to_value(key).unwrap();
assert_eq!(deserialized, jsn);
}
}