use std::borrow::Cow;
use std::io;
use std::ops::{Deref, DerefMut};
use std::path::Path;
use time;
use {
Result,
TPK,
Error,
Packet,
conversions::Time,
};
use crypto::{KeyPair, Password};
use packet::{
signature::Signature,
Tag,
UserID,
Key,
UserAttribute,
KeyFlags,
};
use serialize::{
Serialize,
SerializeKey,
};
use parse::{Parse, PacketParserResult};
#[derive(Debug, PartialEq)]
pub struct TSK {
key: TPK,
}
impl Deref for TSK {
type Target = TPK;
fn deref(&self) -> &Self::Target {
&self.key
}
}
impl DerefMut for TSK {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.key
}
}
impl<'a> Parse<'a, TSK> for TSK {
fn from_reader<R: 'a + io::Read>(reader: R) -> Result<Self> {
TPK::from_reader(reader).map(|tpk| Self::from_tpk(tpk))
}
fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
TPK::from_file(path).map(|tpk| Self::from_tpk(tpk))
}
fn from_bytes(data: &'a [u8]) -> Result<Self> {
TPK::from_bytes(data).map(|tpk| Self::from_tpk(tpk))
}
}
impl TSK {
pub fn from_packet_parser<'a>(ppr: PacketParserResult<'a>) -> Result<Self> {
TPK::from_packet_parser(ppr).map(|tpk| Self::from_tpk(tpk))
}
pub(crate) fn from_tpk(tpk: TPK) -> TSK {
TSK{ key: tpk }
}
pub fn new<'a, O>(primary_uid: O) -> Result<(TSK, Signature)>
where O: Into<Option<Cow<'a, str>>>
{
use tpk::TPKBuilder;
let key = TPKBuilder::autocrypt(None, primary_uid);
let (tpk, revocation) = key.generate()?;
Ok((TSK::from_tpk(tpk), revocation))
}
pub fn tpk<'a>(&'a self) -> &'a TPK {
&self.key
}
pub fn into_tpk(self) -> TPK {
self.key
}
pub fn certify_userid(&self, key: &Key, userid: &UserID) -> Result<Signature> {
use packet::{signature, key::SecretKey};
use constants::{HashAlgorithm, SignatureType};
let certification_key = self.key.keys_all()
.certification_capable()
.unencrypted_secret(true)
.nth(0)
.map(|x| x.2);
match certification_key {
Some(my_key) => {
match my_key.secret() {
Some(&SecretKey::Unencrypted{ ref mpis }) => {
signature::Builder::new(SignatureType::GenericCertificate)
.sign_userid_binding(
&mut KeyPair::new((*my_key).clone(),
mpis.clone())?,
key, userid, HashAlgorithm::SHA512)
}
_ => Err(Error::InvalidOperation(
"secret key missing or encrypted".into()).into()),
}
}
None => Err(Error::InvalidOperation(
"this key cannot certify keys".into()).into()),
}
}
pub fn certify_key(&self, key: &TPK) -> Result<Signature> {
match key.primary_key_signature_full() {
None | Some((None, _)) =>
Err(Error::InvalidOperation(
"this key has nothing to certify".into()).into()),
Some((Some(uid), _)) =>
self.certify_userid(key.primary(), uid.userid()),
}
}
pub fn sign_userid(&self, userid: &UserID) -> Result<Signature> {
use packet::{signature, key::SecretKey};
use constants::{HashAlgorithm, SignatureType};
let builder =
if let Some(sig) = self.primary_key_signature() {
signature::Builder::from(sig.clone())
.set_sigtype(SignatureType::PositiveCertificate)
} else {
signature::Builder::new(SignatureType::PositiveCertificate)
}
.set_signature_creation_time(time::now())?;
let certification_key = self.key.keys_valid()
.certification_capable()
.unencrypted_secret(true)
.nth(0)
.map(|x| x.2);
match certification_key {
Some(my_key) => {
match my_key.secret() {
Some(&SecretKey::Unencrypted{ ref mpis }) => {
builder
.set_issuer_fingerprint(my_key.fingerprint())?
.set_issuer(my_key.fingerprint().to_keyid())?
.sign_userid_binding(
&mut KeyPair::new((*my_key).clone(),
mpis.clone())?,
my_key, userid, HashAlgorithm::SHA512)
}
_ => Err(Error::InvalidOperation(
"secret key missing or encrypted".into()).into()),
}
}
None => Err(Error::InvalidOperation(
"this key cannot certify keys".into()).into()),
}
}
pub fn sign_user_attribute(&self, userattr: &UserAttribute) -> Result<Signature> {
use packet::{signature, key::SecretKey};
use constants::{HashAlgorithm, SignatureType};
let certification_key = self.key.keys_valid()
.certification_capable()
.unencrypted_secret(true)
.nth(0)
.map(|x| x.2);
match certification_key {
Some(my_key) => {
match my_key.secret() {
Some(&SecretKey::Unencrypted{ ref mpis }) => {
let mut pair =
KeyPair::new((*my_key).clone(), mpis.clone())?;
signature::Builder::new(SignatureType::GenericCertificate)
.set_signature_creation_time(time::now())?
.set_issuer_fingerprint(my_key.fingerprint())?
.set_issuer(my_key.fingerprint().to_keyid())?
.sign_user_attribute_binding(
&mut pair,
userattr,
HashAlgorithm::SHA512)
}
_ => Err(Error::InvalidOperation(
"secret key missing or encrypted".into()).into()),
}
}
None => Err(Error::InvalidOperation(
"this key cannot certify user attributes".into()).into()),
}
}
pub fn sign_subkey(&self, subkey: &Key, flags: &KeyFlags,
passwd: Option<&Password>)
-> Result<Signature>
{
use packet::{signature, Features, key::SecretKey};
use constants::{HashAlgorithm, SignatureType, SymmetricAlgorithm};
let prim = self.key.primary();
let mut sig = signature::Builder::new(SignatureType::SubkeyBinding)
.set_features(&Features::sequoia())?
.set_key_flags(flags)?
.set_signature_creation_time(time::now().canonicalize())?
.set_key_expiration_time(Some(time::Duration::weeks(3 * 52)))?
.set_issuer_fingerprint(prim.fingerprint())?
.set_issuer(prim.fingerprint().to_keyid())?;
if flags.can_encrypt_for_transport()
|| flags.can_encrypt_at_rest() {
sig = sig.set_preferred_symmetric_algorithms(
vec![SymmetricAlgorithm::AES256])?;
}
if flags.can_certify() || flags.can_sign() {
sig = sig.set_preferred_hash_algorithms(vec![HashAlgorithm::SHA512])?;
let sk = match passwd {
Some(pwd) => subkey.secret().and_then(|sk| {
sk
.decrypt(subkey.pk_algo(), pwd)
.ok()
.map(|mpi| SecretKey::Unencrypted{ mpis: mpi })
.or(subkey.secret().cloned())
}),
None => subkey.secret().cloned(),
};
let backsig = match sk {
Some(SecretKey::Unencrypted{ ref mpis }) => {
signature::Builder::new(SignatureType::PrimaryKeyBinding)
.set_signature_creation_time(time::now().canonicalize())?
.set_issuer_fingerprint(subkey.fingerprint())?
.set_issuer(subkey.fingerprint().to_keyid())?
.sign_subkey_binding(
&mut KeyPair::new(subkey.clone(), mpis.clone())?,
prim, &subkey, HashAlgorithm::SHA512)?
}
Some(SecretKey::Encrypted{ .. }) => {
return Err(Error::InvalidOperation(
"Secret key is encrypted".into()).into());
}
None => {
return Err(Error::InvalidOperation(
"No secret key".into()).into());
}
};
sig = sig.set_embedded_signature(backsig)?;
}
let sig = match prim.secret() {
Some(SecretKey::Unencrypted{ ref mpis }) => {
sig.sign_subkey_binding(&mut KeyPair::new(prim.clone(),
mpis.clone())?,
prim, &subkey,
HashAlgorithm::SHA512)?
}
Some(SecretKey::Encrypted{ .. }) => {
return Err(Error::InvalidOperation(
"Secret key is encrypted".into()).into());
}
None => {
return Err(Error::InvalidOperation(
"No secret key".into()).into());
}
};
Ok(sig)
}
pub fn with_userid_certification(self, certifier: &TSK, userid: &UserID)
-> Result<Self>
{
let sig = certifier.certify_userid(self.key.primary(), userid)?;
Ok(TSK{
key: self.key.merge_packets(vec![
Packet::Signature(sig)
])?
})
}
pub fn with_userid(self, userid: UserID) -> Result<Self> {
let sig = self.sign_userid(&userid)?;
Ok(TSK{
key: self.key.merge_packets(vec![
Packet::UserID(userid),
Packet::Signature(sig)
])?
})
}
pub fn with_user_attribute(self, userattr: UserAttribute) -> Result<Self> {
let sig = self.sign_user_attribute(&userattr)?;
Ok(TSK{
key: self.key.merge_packets(vec![
Packet::UserAttribute(userattr),
Packet::Signature(sig)
])?
})
}
pub fn with_subkey(self, subkey: Key, flags: &KeyFlags, passwd: Option<&Password>) -> Result<Self> {
let sig = self.sign_subkey(&subkey, flags, passwd)?;
let pkt = if subkey.secret().is_some() {
Packet::SecretSubkey(subkey)
} else {
Packet::PublicSubkey(subkey)
};
Ok(TSK{
key: self.key.merge_packets(vec![
pkt,
Packet::Signature(sig)
])?
})
}
}
impl Serialize for TSK {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
self.key.primary.serialize(o, Tag::SecretKey)?;
for s in self.key.primary_selfsigs.iter() {
s.serialize(o)?;
}
for s in self.key.primary_self_revocations.iter() {
s.serialize(o)?;
}
for s in self.key.primary_certifications.iter() {
s.serialize(o)?;
}
for s in self.key.primary_other_revocations.iter() {
s.serialize(o)?;
}
for u in self.key.userids() {
u.userid().serialize(o)?;
for s in u.self_revocations() {
s.serialize(o)?;
}
for s in u.selfsigs() {
s.serialize(o)?;
}
for s in u.other_revocations() {
s.serialize(o)?;
}
for s in u.certifications() {
s.serialize(o)?;
}
}
for u in self.key.user_attributes() {
u.user_attribute().serialize(o)?;
for s in u.self_revocations() {
s.serialize(o)?;
}
for s in u.selfsigs() {
s.serialize(o)?;
}
for s in u.other_revocations() {
s.serialize(o)?;
}
for s in u.certifications() {
s.serialize(o)?;
}
}
for k in self.key.subkeys() {
k.subkey().serialize(o, Tag::SecretSubkey)?;
for s in k.self_revocations() {
s.serialize(o)?;
}
for s in k.selfsigs() {
s.serialize(o)?;
}
for s in k.other_revocations() {
s.serialize(o)?;
}
for s in k.certifications() {
s.serialize(o)?;
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use tpk::TPKBuilder;
#[test]
fn certification_direct_key() {
let (tpk1, _) = TPKBuilder::default()
.add_certification_subkey()
.generate().unwrap();
let tsk = tpk1.into_tsk();
let (tpk2, _) = TPKBuilder::default()
.generate().unwrap();
assert!(tsk.certify_key(&tpk2).is_err());
}
#[test]
fn certification_user_id() {
let (tpk1, _) = TPKBuilder::default()
.add_certification_subkey()
.generate().unwrap();
let tsk = tpk1.into_tsk();
let (tpk2, _) = TPKBuilder::default()
.add_userid("test1@example.com")
.add_userid("test2@example.com")
.generate().unwrap();
let sig = tsk.certify_key(&tpk2).unwrap();
let key = tsk.tpk().keys_all()
.certification_capable().nth(0).unwrap().2;
assert_eq!(
sig.verify_userid_binding(
key,
tpk2.primary(),
tpk2.userids().next().unwrap().userid()).unwrap(),
true);
}
#[test]
fn add_userid() {
use std::str;
let ui1 = b"test1@example.com";
let ui2 = b"test2@example.com";
let (tpk, _) = TPKBuilder::default()
.add_userid(str::from_utf8(ui1).unwrap())
.generate().unwrap();
let tsk = TSK::from_tpk(tpk)
.with_userid(UserID::from(str::from_utf8(ui2).unwrap()))
.unwrap();
let userids = tsk
.userids()
.map(|binding| binding.userid().userid())
.collect::<Vec<_>>();
assert_eq!(userids.len(), 2);
assert!((userids[0] == ui1 && userids[1] == ui2) ^
(userids[0] == ui2 && userids[1] == ui1));
}
#[test]
fn add_user_attr() {
let (tpk, _) = TPKBuilder::default()
.add_userid("test1@example.com")
.generate().unwrap();
let tsk = TSK::from_tpk(tpk)
.with_user_attribute(UserAttribute::from(Vec::from(&b"Hello, World"[..])))
.unwrap();
let userattrs = tsk
.user_attributes()
.map(|binding| binding.user_attribute().user_attribute())
.collect::<Vec<_>>();
assert_eq!(userattrs.len(), 1);
}
#[test]
fn add_subkey() {
let (tpk, _) = TPKBuilder::default()
.add_userid("test1@example.com")
.generate().unwrap();
let key = Key::generate_rsa(1024).unwrap();
let flags = KeyFlags::default().set_sign(true);
let tsk = TSK::from_tpk(tpk)
.with_subkey(key, &flags, None)
.unwrap();
let subkeys = tsk
.subkeys()
.map(|binding| binding.subkey())
.collect::<Vec<_>>();
assert_eq!(subkeys.len(), 1);
}
#[test]
fn user_ids() {
let (tpk, _) = TPKBuilder::default()
.add_userid("test1@example.com")
.add_userid("test2@example.com")
.generate().unwrap();
let userids = tpk
.userids()
.map(|binding| binding.userid().userid())
.collect::<Vec<_>>();
assert_eq!(userids.len(), 2);
assert!((userids[0] == b"test1@example.com"
&& userids[1] == b"test2@example.com")
|| (userids[0] == b"test2@example.com"
&& userids[1] == b"test1@example.com"),
"User ids: {:?}", userids);
let (tpk, _) = TPKBuilder::autocrypt(None, Some("Foo".into()))
.generate()
.unwrap();
let userids = tpk
.userids()
.map(|binding| binding.userid().userid())
.collect::<Vec<_>>();
assert_eq!(userids.len(), 1);
assert_eq!(userids[0], b"Foo");
let (tsk, _) = TSK::new(Some("test@example.com".into())).unwrap();
let tpk = tsk.into_tpk();
let userids = tpk
.userids()
.map(|binding| binding.userid().userid())
.collect::<Vec<_>>();
assert_eq!(userids.len(), 1);
assert_eq!(userids[0], b"test@example.com",
"User ids: {:?}", userids);
}
}