use std::convert::TryFrom;
use std::ops::Deref;
use std::time;
use crate::{
HashAlgorithm,
Result,
SignatureType,
};
use crate::types::{
ReasonForRevocation,
};
use crate::crypto::Signer;
use crate::packet::{
Key,
key,
signature,
Signature,
UserAttribute,
UserID,
};
use crate::packet::signature::subpacket::NotationDataFlags;
use crate::cert::prelude::*;
pub struct CertRevocationBuilder {
builder: signature::SignatureBuilder,
}
assert_send_and_sync!(CertRevocationBuilder);
#[allow(clippy::new_without_default)]
impl CertRevocationBuilder {
pub fn new() -> Self {
Self {
builder:
signature::SignatureBuilder::new(SignatureType::KeyRevocation)
}
}
pub fn set_reason_for_revocation(self, code: ReasonForRevocation,
reason: &[u8])
-> Result<Self>
{
Ok(Self {
builder: self.builder.set_reason_for_revocation(code, reason)?
})
}
pub fn set_signature_creation_time(self, creation_time: time::SystemTime)
-> Result<Self>
{
Ok(Self {
builder: self.builder.set_signature_creation_time(creation_time)?
})
}
pub fn add_notation<N, V, F>(self, name: N, value: V, flags: F,
critical: bool)
-> Result<Self>
where
N: AsRef<str>,
V: AsRef<[u8]>,
F: Into<Option<NotationDataFlags>>,
{
Ok(Self {
builder: self.builder.add_notation(name, value, flags, critical)?
})
}
pub fn set_notation<N, V, F>(self, name: N, value: V, flags: F,
critical: bool)
-> Result<Self>
where
N: AsRef<str>,
V: AsRef<[u8]>,
F: Into<Option<NotationDataFlags>>,
{
Ok(Self {
builder: self.builder.set_notation(name, value, flags, critical)?
})
}
pub fn build<H>(self, signer: &mut dyn Signer, cert: &Cert, hash_algo: H)
-> Result<Signature>
where H: Into<Option<HashAlgorithm>>
{
self.builder
.set_hash_algo(hash_algo.into().unwrap_or(HashAlgorithm::SHA512))
.sign_direct_key(signer, cert.primary_key().key())
}
}
impl Deref for CertRevocationBuilder {
type Target = signature::SignatureBuilder;
fn deref(&self) -> &Self::Target {
&self.builder
}
}
impl TryFrom<signature::SignatureBuilder> for CertRevocationBuilder {
type Error = anyhow::Error;
fn try_from(builder: signature::SignatureBuilder) -> Result<Self> {
if builder.typ() != SignatureType::KeyRevocation {
return Err(
crate::Error::InvalidArgument(
format!("Expected signature type to be KeyRevocation but got {}",
builder.typ())).into());
}
Ok(Self {
builder
})
}
}
pub struct SubkeyRevocationBuilder {
builder: signature::SignatureBuilder,
}
assert_send_and_sync!(SubkeyRevocationBuilder);
#[allow(clippy::new_without_default)]
impl SubkeyRevocationBuilder {
pub fn new() -> Self {
Self {
builder:
signature::SignatureBuilder::new(SignatureType::SubkeyRevocation)
}
}
pub fn set_reason_for_revocation(self, code: ReasonForRevocation,
reason: &[u8])
-> Result<Self>
{
Ok(Self {
builder: self.builder.set_reason_for_revocation(code, reason)?
})
}
pub fn set_signature_creation_time(self, creation_time: time::SystemTime)
-> Result<Self>
{
Ok(Self {
builder: self.builder.set_signature_creation_time(creation_time)?
})
}
pub fn add_notation<N, V, F>(self, name: N, value: V, flags: F,
critical: bool)
-> Result<Self>
where
N: AsRef<str>,
V: AsRef<[u8]>,
F: Into<Option<NotationDataFlags>>,
{
Ok(Self {
builder: self.builder.add_notation(name, value, flags, critical)?
})
}
pub fn set_notation<N, V, F>(self, name: N, value: V, flags: F,
critical: bool)
-> Result<Self>
where
N: AsRef<str>,
V: AsRef<[u8]>,
F: Into<Option<NotationDataFlags>>,
{
Ok(Self {
builder: self.builder.set_notation(name, value, flags, critical)?
})
}
pub fn build<H, P>(mut self, signer: &mut dyn Signer,
cert: &Cert, key: &Key<P, key::SubordinateRole>,
hash_algo: H)
-> Result<Signature>
where H: Into<Option<HashAlgorithm>>,
P: key::KeyParts,
{
self.builder = self.builder
.set_hash_algo(hash_algo.into().unwrap_or(HashAlgorithm::SHA512));
key.bind(signer, cert, self.builder)
}
}
impl Deref for SubkeyRevocationBuilder {
type Target = signature::SignatureBuilder;
fn deref(&self) -> &Self::Target {
&self.builder
}
}
impl TryFrom<signature::SignatureBuilder> for SubkeyRevocationBuilder {
type Error = anyhow::Error;
fn try_from(builder: signature::SignatureBuilder) -> Result<Self> {
if builder.typ() != SignatureType::SubkeyRevocation {
return Err(
crate::Error::InvalidArgument(
format!("Expected signature type to be SubkeyRevocation but got {}",
builder.typ())).into());
}
Ok(Self {
builder
})
}
}
pub struct UserIDRevocationBuilder {
builder: signature::SignatureBuilder,
}
assert_send_and_sync!(UserIDRevocationBuilder);
#[allow(clippy::new_without_default)]
impl UserIDRevocationBuilder {
pub fn new() -> Self {
Self {
builder:
signature::SignatureBuilder::new(SignatureType::CertificationRevocation)
}
}
pub fn set_reason_for_revocation(self, code: ReasonForRevocation,
reason: &[u8])
-> Result<Self>
{
Ok(Self {
builder: self.builder.set_reason_for_revocation(code, reason)?
})
}
pub fn set_signature_creation_time(self, creation_time: time::SystemTime)
-> Result<Self>
{
Ok(Self {
builder: self.builder.set_signature_creation_time(creation_time)?
})
}
pub fn add_notation<N, V, F>(self, name: N, value: V, flags: F,
critical: bool)
-> Result<Self>
where
N: AsRef<str>,
V: AsRef<[u8]>,
F: Into<Option<NotationDataFlags>>,
{
Ok(Self {
builder: self.builder.add_notation(name, value, flags, critical)?
})
}
pub fn set_notation<N, V, F>(self, name: N, value: V, flags: F,
critical: bool)
-> Result<Self>
where
N: AsRef<str>,
V: AsRef<[u8]>,
F: Into<Option<NotationDataFlags>>,
{
Ok(Self {
builder: self.builder.set_notation(name, value, flags, critical)?
})
}
pub fn build<H>(mut self, signer: &mut dyn Signer,
cert: &Cert, userid: &UserID,
hash_algo: H)
-> Result<Signature>
where H: Into<Option<HashAlgorithm>>
{
self.builder = self.builder
.set_hash_algo(hash_algo.into().unwrap_or(HashAlgorithm::SHA512));
userid.bind(signer, cert, self.builder)
}
}
impl Deref for UserIDRevocationBuilder {
type Target = signature::SignatureBuilder;
fn deref(&self) -> &Self::Target {
&self.builder
}
}
impl TryFrom<signature::SignatureBuilder> for UserIDRevocationBuilder {
type Error = anyhow::Error;
fn try_from(builder: signature::SignatureBuilder) -> Result<Self> {
if builder.typ() != SignatureType::CertificationRevocation {
return Err(
crate::Error::InvalidArgument(
format!("Expected signature type to be CertificationRevocation but got {}",
builder.typ())).into());
}
Ok(Self {
builder
})
}
}
pub struct UserAttributeRevocationBuilder {
builder: signature::SignatureBuilder,
}
assert_send_and_sync!(UserAttributeRevocationBuilder);
#[allow(clippy::new_without_default)]
impl UserAttributeRevocationBuilder {
pub fn new() -> Self {
Self {
builder:
signature::SignatureBuilder::new(SignatureType::CertificationRevocation)
}
}
pub fn set_reason_for_revocation(self, code: ReasonForRevocation,
reason: &[u8])
-> Result<Self>
{
Ok(Self {
builder: self.builder.set_reason_for_revocation(code, reason)?
})
}
pub fn set_signature_creation_time(self, creation_time: time::SystemTime)
-> Result<Self>
{
Ok(Self {
builder: self.builder.set_signature_creation_time(creation_time)?
})
}
pub fn add_notation<N, V, F>(self, name: N, value: V, flags: F,
critical: bool)
-> Result<Self>
where
N: AsRef<str>,
V: AsRef<[u8]>,
F: Into<Option<NotationDataFlags>>,
{
Ok(Self {
builder: self.builder.add_notation(name, value, flags, critical)?
})
}
pub fn set_notation<N, V, F>(self, name: N, value: V, flags: F,
critical: bool)
-> Result<Self>
where
N: AsRef<str>,
V: AsRef<[u8]>,
F: Into<Option<NotationDataFlags>>,
{
Ok(Self {
builder: self.builder.set_notation(name, value, flags, critical)?
})
}
pub fn build<H>(mut self, signer: &mut dyn Signer,
cert: &Cert, ua: &UserAttribute,
hash_algo: H)
-> Result<Signature>
where H: Into<Option<HashAlgorithm>>
{
self.builder = self.builder
.set_hash_algo(hash_algo.into().unwrap_or(HashAlgorithm::SHA512));
ua.bind(signer, cert, self.builder)
}
}
impl Deref for UserAttributeRevocationBuilder {
type Target = signature::SignatureBuilder;
fn deref(&self) -> &Self::Target {
&self.builder
}
}
impl TryFrom<signature::SignatureBuilder> for UserAttributeRevocationBuilder {
type Error = anyhow::Error;
fn try_from(builder: signature::SignatureBuilder) -> Result<Self> {
if builder.typ() != SignatureType::CertificationRevocation {
return Err(
crate::Error::InvalidArgument(
format!("Expected signature type to be CertificationRevocation but got {}",
builder.typ())).into());
}
Ok(Self {
builder
})
}
}
#[cfg(test)]
mod tests {
#[test]
fn try_into_cert_revocation_builder_success() -> crate::Result<()> {
use std::convert::TryInto;
use crate as openpgp;
use openpgp::cert::prelude::*;
use openpgp::packet::signature::SignatureBuilder;
use openpgp::cert::CertRevocationBuilder;
use openpgp::types::SignatureType;
let (cert, _) = CertBuilder::new()
.generate()?;
let mut signer = cert.primary_key().key().clone()
.parts_into_secret()?.into_keypair()?;
let builder = SignatureBuilder::new(SignatureType::KeyRevocation);
let revocation_builder: CertRevocationBuilder = builder.try_into()?;
let sig = revocation_builder.build(&mut signer, &cert, None)?;
assert_eq!(sig.typ(), SignatureType::KeyRevocation);
Ok(())
}
#[test]
fn try_into_cert_revocation_builder_failure() -> crate::Result<()> {
use std::convert::TryInto;
use crate as openpgp;
use openpgp::packet::signature::SignatureBuilder;
use openpgp::cert::CertRevocationBuilder;
use openpgp::types::SignatureType;
let builder = SignatureBuilder::new(SignatureType::Binary);
let result: openpgp::Result<CertRevocationBuilder> = builder.try_into();
assert!(result.is_err());
Ok(())
}
#[test]
fn try_into_subkey_revocation_builder_success() -> crate::Result<()> {
use std::convert::TryInto;
use crate as openpgp;
use openpgp::cert::prelude::*;
use openpgp::packet::signature::SignatureBuilder;
use openpgp::cert::SubkeyRevocationBuilder;
use openpgp::types::SignatureType;
let (cert, _) = CertBuilder::new()
.add_transport_encryption_subkey()
.generate()?;
let mut signer = cert.primary_key().key().clone()
.parts_into_secret()?.into_keypair()?;
let subkey = cert.keys().subkeys().nth(0).unwrap();
let builder = SignatureBuilder::new(SignatureType::SubkeyRevocation);
let revocation_builder: SubkeyRevocationBuilder = builder.try_into()?;
let sig = revocation_builder.build(&mut signer, &cert, subkey.key(), None)?;
assert_eq!(sig.typ(), SignatureType::SubkeyRevocation);
Ok(())
}
#[test]
fn try_into_subkey_revocation_builder_failure() -> crate::Result<()> {
use std::convert::TryInto;
use crate as openpgp;
use openpgp::packet::signature::SignatureBuilder;
use openpgp::cert::SubkeyRevocationBuilder;
use openpgp::types::SignatureType;
let builder = SignatureBuilder::new(SignatureType::Binary);
let result: openpgp::Result<SubkeyRevocationBuilder> = builder.try_into();
assert!(result.is_err());
Ok(())
}
#[test]
fn try_into_userid_revocation_builder_success() -> crate::Result<()> {
use std::convert::TryInto;
use crate as openpgp;
use openpgp::cert::prelude::*;
use openpgp::packet::signature::SignatureBuilder;
use openpgp::cert::UserIDRevocationBuilder;
use openpgp::types::SignatureType;
let (cert, _) = CertBuilder::new()
.add_userid("test@example.com")
.generate()?;
let mut signer = cert.primary_key().key().clone()
.parts_into_secret()?.into_keypair()?;
let user_id = cert.userids().next().unwrap();
let builder = SignatureBuilder::new(SignatureType::CertificationRevocation);
let revocation_builder: UserIDRevocationBuilder = builder.try_into()?;
let sig = revocation_builder.build(&mut signer, &cert, &user_id, None)?;
assert_eq!(sig.typ(), SignatureType::CertificationRevocation);
Ok(())
}
#[test]
fn try_into_userid_revocation_builder_failure() -> crate::Result<()> {
use std::convert::TryInto;
use crate as openpgp;
use openpgp::packet::signature::SignatureBuilder;
use openpgp::cert::UserIDRevocationBuilder;
use openpgp::types::SignatureType;
let builder = SignatureBuilder::new(SignatureType::Binary);
let result: openpgp::Result<UserIDRevocationBuilder> = builder.try_into();
assert!(result.is_err());
Ok(())
}
#[test]
fn try_into_userattribute_revocation_builder_success() -> crate::Result<()> {
use std::convert::TryInto;
use crate as openpgp;
use openpgp::cert::prelude::*;
use openpgp::packet::prelude::*;
use openpgp::packet::signature::SignatureBuilder;
use openpgp::packet::user_attribute::Subpacket;
use openpgp::cert::UserAttributeRevocationBuilder;
use openpgp::types::SignatureType;
let sp = Subpacket::Unknown(7, vec![7; 7].into_boxed_slice());
let user_attribute = UserAttribute::new(&[sp])?;
let (cert, _) = CertBuilder::new()
.add_user_attribute(user_attribute)
.generate()?;
let mut signer = cert.primary_key().key().clone()
.parts_into_secret()?.into_keypair()?;
let user_attribute = cert.user_attributes().next().unwrap();
let builder = SignatureBuilder::new(SignatureType::CertificationRevocation);
let revocation_builder: UserAttributeRevocationBuilder = builder.try_into()?;
let sig = revocation_builder.build(&mut signer, &cert, &user_attribute, None)?;
assert_eq!(sig.typ(), SignatureType::CertificationRevocation);
Ok(())
}
#[test]
fn try_into_userattribute_revocation_builder_failure() -> crate::Result<()> {
use std::convert::TryInto;
use crate as openpgp;
use openpgp::packet::signature::SignatureBuilder;
use openpgp::cert::UserAttributeRevocationBuilder;
use openpgp::types::SignatureType;
let builder = SignatureBuilder::new(SignatureType::Binary);
let result: openpgp::Result<UserAttributeRevocationBuilder> = builder.try_into();
assert!(result.is_err());
Ok(())
}
}