use bytescontainer::BytesContainer;
use meta::Meta;
use signature::Signature;
use chrono;
use ed25519;
use fingerprint::Fingerprint;
use validator::ValidationError;
use validator::Validatable;
use validator::Validator;
use revoker::RevokeError;
use revoker::Revokable;
use revoker::Revoker;
pub const SIGNATURE_LEN: usize = ed25519::SIGNATURE_LEN;
pub const PRIVATE_KEY_LEN: usize = ed25519::PRIVATE_KEY_LEN;
pub const PUBLIC_KEY_LEN: usize = ed25519::PUBLIC_KEY_LEN;
pub const CERTIFICATE_BYTE_LEN: usize =
25 + 64 + PUBLIC_KEY_LEN;
#[derive(Clone,RustcDecodable,RustcEncodable,Debug,PartialEq)]
pub struct Certificate {
meta: Meta,
public_key: BytesContainer,
private_key: Option<BytesContainer>,
expires: String,
signature: Option<Signature>,
}
impl Certificate {
pub fn generate_random(meta: Meta, expires: chrono::DateTime<chrono::UTC>) -> Certificate {
let (pubslice, prvslice) = ed25519::generate_keypair();
let mut public_key = Vec::new();
let mut private_key = Vec::new();
public_key.extend_from_slice(&pubslice[..]);
private_key.extend_from_slice(&prvslice[..]);
Certificate {
private_key: Some(BytesContainer::new(private_key)),
public_key: BytesContainer::new(public_key),
expires: expires.to_rfc3339(),
meta: meta,
signature: None,
}
}
pub fn meta_mut(&mut self) -> &mut Meta {
&mut self.meta
}
pub fn meta(&self) -> &Meta {
&self.meta
}
pub fn public_key(&self) -> &Vec<u8> {
self.public_key.get()
}
pub fn private_key(&self) -> Option<&Vec<u8>> {
if self.has_private_key() {
let vec = self.private_key.as_ref().unwrap().get();
Some(vec)
} else {
None
}
}
pub fn has_private_key(&self) -> bool {
self.private_key.is_some()
}
pub fn remove_private_key(&mut self) {
self.private_key = None
}
pub fn expiration_date(&self) -> &str {
&self.expires
}
pub fn signature(&self) -> Option<&Signature> {
self.signature.as_ref()
}
pub fn set_private_key(&mut self, private_key: Vec<u8>) {
self.private_key = Some(BytesContainer::new(private_key));
}
pub fn can_sign(&self) -> Result<(), &'static str> {
use rustc_serialize::json;
let meta = self.meta();
match meta.get("use-for") {
Some(use_for) => {
let use_for: Vec<String> = match json::decode(use_for) {
Ok(x) => x,
Err(_) => {
return Err("Failed to parse content of meta value \"use-for\"");
}
};
if use_for.contains(&"edcert.sign".to_string()) {
Ok(())
} else {
Err("This certificate is not allowed to sign certificates")
}
}
None => Err("The meta value \"use-for\" could not be found"),
}
}
pub fn safehash(&self) -> [u8; CERTIFICATE_BYTE_LEN] {
let mut bytes = [0; CERTIFICATE_BYTE_LEN];
self.meta.fill_bytes(&mut bytes[0..64]);
::copy_bytes(&mut bytes[64..], self.expires.as_bytes(), 0, 0, 25);
::copy_bytes(&mut bytes[89..],
&self.public_key.get()[..],
0,
0,
PUBLIC_KEY_LEN);
bytes
}
pub fn parent(&self) -> Option<&Certificate> {
if self.is_signed() {
let sig = &self.signature.as_ref().unwrap();
sig.parent()
} else {
None
}
}
pub fn is_signed(&self) -> bool {
self.signature.is_some()
}
pub fn sign(&self, data: &[u8]) -> Option<Vec<u8>> {
if self.has_private_key() {
let signature = ed25519::sign(data, self.private_key().unwrap());
Some(signature)
} else {
None
}
}
pub fn sign_with_master(&mut self, master_private_key: &[u8]) {
let bytes = self.safehash();
let hash = ed25519::sign(&bytes[..], master_private_key);
self.signature = Some(Signature::new(hash));
}
pub fn sign_certificate(&self, other: &mut Certificate) -> Result<(), &'static str> {
if self.has_private_key() {
let child_bytes = other.safehash();
let signature_bytes = self.sign(&child_bytes).unwrap().to_vec();
let parent = Box::new(self.clone());
let signature = Signature::with_parent(parent, signature_bytes);
other.signature = Some(signature);
Ok(())
} else {
Err("This certificate has no private key")
}
}
pub fn is_expired(&self) -> bool {
let expires = match chrono::DateTime::parse_from_rfc3339(&self.expires) {
Err(_) => return true,
Ok(expires) => expires.with_timezone(&chrono::UTC),
};
expires <= chrono::UTC::now()
}
pub fn verify(&self, data: &[u8], signature: &[u8]) -> bool {
ed25519::verify(data, signature, self.public_key())
}
}
impl Validatable for Certificate {
fn self_validate<V: Validator>(&self, cv: &V) -> Result<(), ValidationError> {
if self.is_signed() {
let bytes: &[u8] = &self.safehash()[..];
let signature = self.signature.as_ref().unwrap();
if signature.is_signed_by_master() {
let hash = signature.hash();
if cv.is_signature_valid(bytes, hash) {
if self.is_expired() {
Err(ValidationError::Expired)
} else {
Ok(())
}
} else {
Err(ValidationError::SignatureInvalid)
}
} else {
let parent: &Certificate = signature.parent().unwrap();
let sign_real = parent.verify(bytes, signature.hash());
let parent_real = cv.is_valid(parent);
let parent_can_sign = parent.can_sign().is_ok();
if sign_real {
if parent_real.is_ok() {
if parent_can_sign {
if self.is_expired() {
Err(ValidationError::Expired)
} else {
Ok(())
}
} else {
Err(ValidationError::Other)
}
} else {
Err(ValidationError::ParentInvalid)
}
} else {
Err(ValidationError::ParentInvalid)
}
}
} else {
Err(ValidationError::SignatureInvalid)
}
}
}
impl Fingerprint for Certificate {
fn fingerprint(&self) -> Vec<u8> {
self.public_key().clone()
}
}
impl Revokable for Certificate {
fn self_check_revoked<R: Revoker>(&self, revoker: &R) -> Result<(), RevokeError> {
revoker.is_revoked(self)
}
}
#[test]
fn test_generate_certificate() {
use chrono::Timelike;
use chrono::UTC;
use chrono::duration::Duration;
let meta = Meta::new_empty();
let expires = UTC::now()
.checked_add(Duration::days(90))
.expect("Failed to add a day to expiration date.")
.with_nanosecond(0)
.unwrap();
let a = Certificate::generate_random(meta, expires);
let meta = Meta::new_empty();
let b = Certificate::generate_random(meta, expires);
assert!(a.public_key() != b.public_key());
}