sequoia-sqv-0.14.0/Cargo.toml.orig010064400017500001750000000017651361731103000151650ustar0000000000000000[package] name = "sequoia-sqv" description = "A simple OpenPGP signature verification program" version = "0.14.0" authors = [ "Justus Winter ", "Kai Michaelis ", "Neal H. Walfield ", ] documentation = "https://docs.sequoia-pgp.org/0.14.0/sqv" homepage = "https://sequoia-pgp.org/" repository = "https://gitlab.com/sequoia-pgp/sequoia" readme = "README.md" keywords = ["cryptography", "openpgp", "pgp", "signature", "verification"] categories = ["cryptography", "command-line-utilities"] license = "GPL-2.0-or-later" edition = "2018" [badges] gitlab = { repository = "sequoia-pgp/sequoia" } maintenance = { status = "actively-developed" } [dependencies] sequoia-openpgp = { path = "../openpgp", version = "0.14", default-features = false } chrono = "0.4" clap = "2.32.0" failure = "0.1.2" [build-dependencies] clap = "2.27.1" [dev-dependencies] assert_cli = "0.6" colored = "=1.9.1" [[bin]] name = "sqv" path = "src/sqv-usage.rs" sequoia-sqv-0.14.0/Cargo.toml0000644000000031050000000000000114270ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "sequoia-sqv" version = "0.14.0" authors = ["Justus Winter ", "Kai Michaelis ", "Neal H. Walfield "] description = "A simple OpenPGP signature verification program" homepage = "https://sequoia-pgp.org/" documentation = "https://docs.sequoia-pgp.org/0.14.0/sqv" readme = "README.md" keywords = ["cryptography", "openpgp", "pgp", "signature", "verification"] categories = ["cryptography", "command-line-utilities"] license = "GPL-2.0-or-later" repository = "https://gitlab.com/sequoia-pgp/sequoia" [[bin]] name = "sqv" path = "src/sqv-usage.rs" [dependencies.chrono] version = "0.4" [dependencies.clap] version = "2.32.0" [dependencies.failure] version = "0.1.2" [dependencies.sequoia-openpgp] version = "0.14" default-features = false [dev-dependencies.assert_cli] version = "0.6" [dev-dependencies.colored] version = "=1.9.1" [build-dependencies.clap] version = "2.27.1" [badges.gitlab] repository = "sequoia-pgp/sequoia" [badges.maintenance] status = "actively-developed" sequoia-sqv-0.14.0/Makefile010064400017500001750000000014071361731103000137270ustar0000000000000000# Configuration. CARGO_TARGET_DIR ?= $(shell pwd)/../target # We currently only support absolute paths. CARGO_TARGET_DIR := $(abspath $(CARGO_TARGET_DIR)) SQV ?= $(CARGO_TARGET_DIR)/debug/sqv # Tools. CARGO ?= cargo ifeq ($(shell uname -s), Darwin) INSTALL ?= ginstall else INSTALL ?= install endif all: src/sqv-usage.rs # Installation. .PHONY: build-release build-release: CARGO_TARGET_DIR=$(CARGO_TARGET_DIR) \ $(CARGO) build $(CARGO_FLAGS) --release --package sequoia-sqv .PHONY: install install: build-release $(INSTALL) -d $(DESTDIR)$(PREFIX)/bin $(INSTALL) -t $(DESTDIR)$(PREFIX)/bin $(CARGO_TARGET_DIR)/release/sqv # Maintenance. .PHONY: update-usage update-usage: src/sqv-usage.rs src/sqv-usage.rs: make-usage.sh $(SQV) sh make-usage.sh $(SQV) >$@ sequoia-sqv-0.14.0/README.md010064400017500001750000000004331361731103000135440ustar0000000000000000A simple signature verification program. `sqv` verifies detached OpenPGP signatures. It is a replacement for `gpgv`. Unlike `gpgv`, it can take additional constraints on the signature into account. See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=872271 for the motivation. sequoia-sqv-0.14.0/build.rs010064400017500001750000000007611361731103000137360ustar0000000000000000extern crate clap; use std::env; use std::fs; use clap::Shell; mod sqv_cli { include!("src/sqv_cli.rs"); } fn main() { let outdir = match env::var_os("CARGO_TARGET_DIR") { None => return, Some(outdir) => outdir, }; fs::create_dir_all(&outdir).unwrap(); let mut sqv = sqv_cli::build(); for shell in &[Shell::Bash, Shell::Fish, Shell::Zsh, Shell::PowerShell, Shell::Elvish] { sqv.gen_completions("sqv", *shell, &outdir); } } sequoia-sqv-0.14.0/make-usage.sh010064400017500001750000000015131361731103000146400ustar0000000000000000#!/bin/sh tool=$1 quote() { sed 's@^@//! @' | sed 's/ $//' } begin_code() { printf '```text\n' } end_code() { printf '```\n' } dump_help() { # subcommand, indentation if [ -z "$1" ] then printf "\n# Usage\n\n" set "" "#" else printf "\n$2 Subcommand$1\n\n" fi help="`$tool $1 --help`" begin_code printf "$help\n" | tail -n +2 end_code if echo $help | fgrep -q SUBCOMMANDS then printf "$help\n" | sed -n '/^SUBCOMMANDS:/,$p' | tail -n+2 | while read subcommand desc do if [ "$subcommand" = help ]; then continue fi dump_help "$1 $subcommand" "#$2" done fi } ( printf "A command-line frontend for Sequoia.\n" dump_help ) | quote printf '\ninclude!("'"$(basename $tool)"'.rs");\n' sequoia-sqv-0.14.0/src/sqv-usage.rs010064400017500001750000000026101361731103000153340ustar0000000000000000//! A command-line frontend for Sequoia. //! //! # Usage //! //! ```text //! sqv is a command-line OpenPGP signature verification tool. //! //! USAGE: //! sqv [FLAGS] [OPTIONS] --keyring ... //! //! FLAGS: //! -h, --help Prints help information //! -V, --version Prints version information //! -v, --verbose Be verbose. //! //! OPTIONS: //! --keyring ... A keyring. Can be given multiple times. //! --not-after Consider signatures created after TIMESTAMP as invalid. If a date is given, //! 23:59:59 is used for the time. //! [default: now] //! --not-before Consider signatures created before TIMESTAMP as invalid. If a date is given, //! 00:00:00 is used for the time. //! [default: no constraint] //! -n, --signatures The number of valid signatures to return success. Default: 1 //! //! ARGS: //! File containing the detached signature. //! File to verify. //! //! TIMESTAMPs must be given in ISO 8601 format (e.g. '2017-03-04T13:25:35Z', '2017-03-04T13:25', '20170304T1325+0830', //! '2017-03-04', '2017031', ...). If no timezone is specified, UTC is assumed. //! ``` include!("sqv.rs"); sequoia-sqv-0.14.0/src/sqv.rs010064400017500001750000000321271361731103000142400ustar0000000000000000/// A simple signature verification program. /// /// See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=872271 for /// the motivation. use std::process::exit; use std::io; use chrono::{DateTime, offset::Utc}; extern crate clap; extern crate failure; use failure::ResultExt; extern crate sequoia_openpgp as openpgp; use crate::openpgp::{ Cert, KeyHandle, Result, parse::Parse, }; use crate::openpgp::parse::stream::{ DetachedVerifier, MessageLayer, MessageStructure, VerificationHelper, VerificationResult, }; use crate::openpgp::cert::CertParser; use crate::openpgp::policy::StandardPolicy as P; mod sqv_cli; struct VHelper<'a> { not_before: Option, not_after: std::time::SystemTime, good: usize, total: usize, threshold: usize, keyrings: clap::OsValues<'a>, } impl<'a> std::fmt::Debug for VHelper<'a> { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.debug_struct("VHelper") .field("not_before", &self.not_before) .field("not_after", &self.not_after) .field("good", &self.good) .field("total", &self.total) .field("threshold", &self.threshold) .field("keyrings", &self.keyrings) .finish() } } impl<'a> VHelper<'a> { fn new(threshold: usize, not_before: Option, not_after: std::time::SystemTime, keyrings: clap::OsValues<'a>) -> Self { VHelper { not_before: not_before, not_after: not_after, good: 0, total: 0, threshold: threshold, keyrings: keyrings, } } } impl<'a> VerificationHelper for VHelper<'a> { fn get_public_keys(&mut self, ids: &[crate::KeyHandle]) -> Result> { let mut certs = Vec::with_capacity(ids.len()); // Load relevant keys from the keyring. for filename in self.keyrings.clone() { certs.extend( CertParser::from_file(filename)? .unvalidated_cert_filter(|cert, _| { // We don't skip keys that are valid (not revoked, // alive, etc.) so that cert.keys().key_handles(ids.iter()).next().is_some() }) .map(|certr| { match certr { Ok(cert) => cert, Err(err) => { eprintln!("Error reading keyring {:?}: {}", filename, err); exit(2); } } })) } // Dedup. To avoid cloning the certificates, we don't use // Vec::dedup. certs.sort_by(|a, b| a.fingerprint().cmp(&b.fingerprint())); let count = certs.len(); let (certs, errs) = certs.into_iter().fold( (Vec::with_capacity(count), Vec::new()), |(mut certs, mut errs), a| { if certs.len() == 0 { certs.push(a); } else if certs[certs.len() - 1].fingerprint() == a.fingerprint() { // Merge `a` into the last element. match certs.pop().expect("non-empty vec").merge(a) { Ok(cert) => certs.push(cert), Err(err) => errs.push(err), } } else { certs.push(a); } (certs, errs) }); if errs.len() > 0 { eprintln!("Error merging duplicate keys:"); for err in errs.iter() { eprintln!(" {}", err); } Err(errs.into_iter().next().expect("non-empty vec")) } else { Ok(certs) } } fn check(&mut self, structure: MessageStructure) -> Result<()> { use self::VerificationResult::*; let mut signers = Vec::with_capacity(2); let mut verification_err = None; for layer in structure.into_iter() { match layer { MessageLayer::SignatureGroup { results } => for result in results { self.total += 1; match result { GoodChecksum { sig, ka, .. } => { match (sig.signature_creation_time(), self.not_before, self.not_after) { (None, _, _) => eprintln!("Malformed signature: \ no signature creation time"), (Some(t), Some(not_before), not_after) => { if t < not_before { eprintln!( "Signature by {} was created before \ the --not-before date.", ka.key().fingerprint().to_hex()); } else if t > not_after { eprintln!( "Signature by {} was created after \ the --not-after date.", ka.key().fingerprint().to_hex()); } else { signers.push(ka.cert().fingerprint()); } } (Some(t), None, not_after) => { if t > not_after { eprintln!( "Signature by {} was created after \ the --not-after date.", ka.key().fingerprint().to_hex()); } else { signers.push(ka.cert().fingerprint()); } } }; } NotAlive { .. } => { eprintln!("Signature is not alive."); } MissingKey { sig, .. } => { if let Some(issuer) = sig.get_issuers().first() { eprintln!("Missing {}, which is needed to \ verify signature.", issuer.to_hex()); } else { eprintln!("Signature has no Issuer or \ Issuer Fingerprint subpacket. \ Don't know what key to use to \ verify signature."); } } Error { error, .. } => { eprintln!("Verifying signature: {}.", error); if verification_err.is_none() { verification_err = Some(error) } } } } MessageLayer::Compression { .. } => (), _ => unreachable!(), } } // Dedup the keys so that it is not possible to exceed the // threshold by duplicating signatures or by using the same // key. signers.sort(); signers.dedup(); self.good = signers.len(); for signer in signers { println!("{}", signer.to_hex()); } Ok(()) } } fn real_main() -> Result<()> { let p = &P::new(); let matches = sqv_cli::build().get_matches(); let verbose = matches.is_present("verbose"); let good_threshold = if let Some(good_threshold) = matches.value_of("signatures") { match good_threshold.parse::() { Ok(good_threshold) => good_threshold, Err(err) => { eprintln!("Value passed to --signatures must be numeric: \ {} (got: {:?}).", err, good_threshold); exit(2); }, } } else { 1 }; if good_threshold < 1 { eprintln!("Value passed to --signatures must be >= 1 (got: {:?}).", good_threshold); exit(2); } let file = matches.value_of_os("file").expect("'file' is required"); let sig_file = matches.value_of_os("sig-file") .expect("'sig-file' is required"); let not_before: Option = if let Some(t) = matches.value_of("not-before") { Some(parse_iso8601(t, chrono::NaiveTime::from_hms(0, 0, 0)) .context(format!("Bad value passed to --not-before: {:?}", t))? .into()) } else { None }; let not_after: std::time::SystemTime = if let Some(t) = matches.value_of("not-after") { Some(parse_iso8601(t, chrono::NaiveTime::from_hms(23, 59, 59)) .context(format!("Bad value passed to --not-after: {:?}", t))? .into()) } else { None }.unwrap_or_else(|| std::time::SystemTime::now()); let keyrings = matches.values_of_os("keyring") .expect("No keyring specified."); let h = VHelper::new(good_threshold, not_before, not_after, keyrings); let mut v = DetachedVerifier::from_file( p, sig_file, file, h, None)?; io::copy(&mut v, &mut io::sink())?; let h = v.into_helper(); if verbose { eprintln!("{} of {} signatures are valid (threshold is: {}).", h.good, h.total, good_threshold); } exit(if h.good >= good_threshold { 0 } else { 1 }); } fn main() { if let Err(e) = real_main() { let mut cause = e.as_fail(); eprint!("{}", cause); while let Some(c) = cause.cause() { eprint!(":\n {}", c); cause = c; } eprintln!(); exit(2); } } /// Parses the given string depicting a ISO 8601 timestamp. fn parse_iso8601(s: &str, pad_date_with: chrono::NaiveTime) -> failure::Fallible> { // If you modify this function this function, synchronize the // changes with the copy in sqv.rs! for f in &[ "%Y-%m-%dT%H:%M:%S%#z", "%Y-%m-%dT%H:%M:%S", "%Y-%m-%dT%H:%M%#z", "%Y-%m-%dT%H:%M", "%Y-%m-%dT%H%#z", "%Y-%m-%dT%H", "%Y%m%dT%H%M%S%#z", "%Y%m%dT%H%M%S", "%Y%m%dT%H%M%#z", "%Y%m%dT%H%M", "%Y%m%dT%H%#z", "%Y%m%dT%H", ] { if f.ends_with("%#z") { if let Ok(d) = DateTime::parse_from_str(s, *f) { return Ok(d.into()); } } else { if let Ok(d) = chrono::NaiveDateTime::parse_from_str(s, *f) { return Ok(DateTime::from_utc(d, Utc)); } } } for f in &[ "%Y-%m-%d", "%Y-%m", "%Y-%j", "%Y%m%d", "%Y%m", "%Y%j", "%Y", ] { if let Ok(d) = chrono::NaiveDate::parse_from_str(s, *f) { return Ok(DateTime::from_utc(d.and_time(pad_date_with), Utc)); } } Err(failure::format_err!("Malformed ISO8601 timestamp: {}", s)) } #[test] fn test_parse_iso8601() { let z = chrono::NaiveTime::from_hms(0, 0, 0); parse_iso8601("2017-03-04T13:25:35Z", z).unwrap(); parse_iso8601("2017-03-04T13:25:35+08:30", z).unwrap(); parse_iso8601("2017-03-04T13:25:35", z).unwrap(); parse_iso8601("2017-03-04T13:25Z", z).unwrap(); parse_iso8601("2017-03-04T13:25", z).unwrap(); // parse_iso8601("2017-03-04T13Z", z).unwrap(); // XXX: chrono doesn't like // parse_iso8601("2017-03-04T13", z).unwrap(); // ditto parse_iso8601("2017-03-04", z).unwrap(); // parse_iso8601("2017-03", z).unwrap(); // ditto parse_iso8601("2017-031", z).unwrap(); parse_iso8601("20170304T132535Z", z).unwrap(); parse_iso8601("20170304T132535+0830", z).unwrap(); parse_iso8601("20170304T132535", z).unwrap(); parse_iso8601("20170304T1325Z", z).unwrap(); parse_iso8601("20170304T1325", z).unwrap(); // parse_iso8601("20170304T13Z", z).unwrap(); // ditto // parse_iso8601("20170304T13", z).unwrap(); // ditto parse_iso8601("20170304", z).unwrap(); // parse_iso8601("201703", z).unwrap(); // ditto parse_iso8601("2017031", z).unwrap(); // parse_iso8601("2017", z).unwrap(); // ditto } sequoia-sqv-0.14.0/src/sqv_cli.rs010064400017500001750000000044331361731103000150660ustar0000000000000000/// Command-line parser for sqv. /// /// If you change this file, please rebuild `sqv`, run `make -C tool /// update-usage`, and commit the resulting changes to /// `tool/src/sqv-usage.rs`. use clap::{App, Arg, AppSettings}; // The argument parser. pub fn build() -> App<'static, 'static> { App::new("sqv") .version(env!("CARGO_PKG_VERSION")) .about("sqv is a command-line OpenPGP signature verification tool.") .setting(AppSettings::ArgRequiredElseHelp) .arg(Arg::with_name("keyring").value_name("FILE") .help("A keyring. Can be given multiple times.") .long("keyring") .required(true) .takes_value(true) .number_of_values(1) .multiple(true)) .arg(Arg::with_name("signatures").value_name("N") .help("The number of valid signatures to return success. Default: 1") .long("signatures") .short("n") .takes_value(true)) .arg(Arg::with_name("not-before").value_name("TIMESTAMP") .help("Consider signatures created before TIMESTAMP as invalid. \ If a date is given, 00:00:00 is used for the time. \ \n[default: no constraint]") .long("not-before") .takes_value(true)) .arg(Arg::with_name("not-after").value_name("TIMESTAMP") .help("Consider signatures created after TIMESTAMP as invalid. \ If a date is given, 23:59:59 is used for the time. \ \n[default: now]") .long("not-after") .takes_value(true)) .arg(Arg::with_name("sig-file").value_name("SIG-FILE") .help("File containing the detached signature.") .required(true)) .arg(Arg::with_name("file").value_name("FILE") .help("File to verify.") .required(true)) .arg(Arg::with_name("verbose") .help("Be verbose.") .long("verbose") .short("v")) .after_help( "TIMESTAMPs must be given in ISO 8601 format \ (e.g. '2017-03-04T13:25:35Z', '2017-03-04T13:25', \ '20170304T1325+0830', '2017-03-04', '2017031', ...). \ If no timezone is specified, UTC is assumed.") } sequoia-sqv-0.14.0/tests/bad-subkey.rs010064400017500001750000000007261361731103000160300ustar0000000000000000extern crate assert_cli; #[cfg(test)] mod integration { use std::path; use assert_cli::Assert; #[test] fn bad_subkey() { Assert::cargo_binary("sqv") .current_dir(path::Path::new("tests").join("data")) .with_args(&["--keyring", "bad-subkey-keyring.pgp", "bad-subkey.txt.sig", "bad-subkey.txt"]) .stdout().is("8F17777118A33DDA9BA48E62AACB3243630052D9") .unwrap(); } } sequoia-sqv-0.14.0/tests/data/bad-subkey-keyring.pgp010064400017500001750000000432201361731103000205450ustar0000000000000000 YoJP}K5E8n[џ QZ6&JN=D1'q&_ .!hJ )+ |ӭIJ11S#ʡu>5'KKW-YQomo&'_1LwBmrW@rzm5C)f-*XB@SIZn7[9rikj$W9"ʹֆ$R.74y-]p'na~z*klZE݈+l.T''~N(Zvbp/G]ވIM,` dg, } aJp qH|nsnQS8Vl뫫q_.@5+Justus Winter M ;!͏e>e}3TJYo f     }3TJ,kc)(`\C \?jldH]la,jTEl}6;k~qCv8nG=^ƅ !,Z<5ɫ*S4Lo c }FDTTAwh+pqK}ߟa * ֙Z€|:WʿW*;SL]Gnn5{v!6poKO}d](~pnb {N2d=F@zP+0TD6\  M蟜Fu[Fbwu;zi/J9oH[M?QZI XLK %Īy(,<񜙴#Justus Winter M ;!͏e>e}3TJYo f     }3TJT0|\hagLêu; y9w:AjAkjb7$X访9%\@ .4D)]Ũ[87S5ണ[S@brDsy{)7c [VmŨq0F,f?qm#0aIHs5<יtbGwxuJS0C=SH9 M6ѵˤmSgkHYp&fy Yoc *. U{ Na uwٌ; L9;b .GTh3M{`] NPqiU~aq 8\|d0\ye+HFs] Hni圑J}%2-S;1R~aqok"QdVOeaDz $"g<"3 BAojLZIKc*},>+Zc\JϷ g=Zfn &!͏e>e}3TJYo g@ }3TJt  !%jNU-$h~38_yYo ~38_yfV!Ok;_ѫxf/BqB_ͱ% L[xH~O OIHq=xgu(oP[82y"B3b3 >M66{S۔qbgA9tQ;c4 ߞ0+qnd7.| N59d=9^Lh目(O}«Uꩠ#4(J|ah_`@15IVo^`R^0ug+h|iggV-2v ;k U,-Ak ZLZ Yo)ajK?ù9v#hAF6ܦ3c['c6qd5 #XV/=D2Czw͊5+(|S:Dav\"'e}3TJYo  g }3TJOt=g壞MY7=VY|F~r `I+dC}y_qBVir<|[cGW^ZGrID)6`-?ĭqzCi鰺0Acpv׹@d;Ƶ܏܃^فހ׌Y(.FPAw>>:xO(S3Bf5ho`Z ٪#"K ~T8c]”+ 37%+&1@3b>9%9-nsKop \{W#= Gg> zucz e]>^7KwrWx3Xā&Oލp4݇ e]!9Ac\i+Ehu`iMQI?BU_M%keRN"Hge.]XV'4zK+ #8 1esOnh=;q^"ǣ[7\ Yosɕ᪜`C1Gf ~ljCIYJ=xt1\>=7&aW($rv~gO>|;gw_&B =!m[^S2owg&lQ skʖ==khc;}5~#P}(u%lS^zYjOD[<>$\ovVX焲Ÿ!lpo'-h=snBna-￀ dOm8 &!͏e>e}3TJYo  g }3TJ\<=s R=1Cu؆<e_&9\?}sm/ hwSA;=J" W =}C%Zh[$347ٟtto滰_8:6*!*f@R75bQ;Li'k =k'\BtmD;]A@(Xʈ9cq%w նPD6U[1(mZCϮW-Rpũ_` NgY)b2+ .QilHJ~DMN 6Xܮ'<8H`GϏԛMwJR֖ P3? (ZT U#5Q$_|p|CxTsls_yAHxeYZvS2j[ױØ;?|4%߯š p-xc a!Л&d #$݀['yX2}H& ۨ9=[@S I~GP=LqW?2$c?rrw(eQ+9]:ߤ0 \.NBMenO]U U# g) 2CcR]  U# r#fx%(yΆ>H ܖ]Wk>-N$`$48b觶FRL[Pэ 4ڀ9R W6 փ玮d)~6mR#2C#?5dȏˤ>WX|ьk))`ZB1w$1Q#3Qz6M} dQ<\^U&v8c&jPb{10|iX #I'TJ+ɖx1 2٤'ELOOH ߅5cF€dQ|G/5E01uƐl="HS\n|zU f0 Q:# lP$PŦ"JE&Mb:ʏp ,_'N'Pkڛ3<"54m;XQlz3 f묟CQɻ[7qX%ΝFغfJ1Zԣ|Ef4bI29֠^)Ӵ oY\/9+M~%贐\%]] h5NDu=sǪ ⅤzY<A#_s}qG" C&˥>g>' ]P i   4y cauQfU8ڐ^뎼 rLU} X%Hm"E^$8x0bq#-=Fʼn X#  )]  U# r#fx%(yΆ>H ܖ]Wk>-N$`$48b觶FRL[Pэ 4ڀ9R W6 փ玮d)~6mR#2C#?5dȏˤ>WX|ьk))`ZB1w$1Q#3Qz6M} dQ<\^U&v8c&jPb{10|iX #I'TJ+ɖx1 2٤ 2CcR0?友rɳ~PFbJ=vj/nI {<\+}9ٚ/H0qJԚpd FE᳐k/ЦS10[[ܾ؉z/ǀvԧwK((V.lwdtNr%oC/mv`~3 HV+Vz1mĀcW iPϕ=E8ZzNdlkh(TOѻner/&3[ScLT] }4 (3FC'8}9}B06>)9 2"^2DWby8C:MSГdjlߏ3챆)>> SvtرuVТB #:!o8|/'CD-`(f-3 U#  g 2CcRم]qbON@6>HܐŌE  X# # 2CcRS-`KsAN.) $Xt@F18iVȘY%䠠y"^ApJԛW(8)g<ܜg#$1]'_e5ef;}GI~?fLE K6*I~XiIb\t؀@ffkjGL>47_;B5dwEц0N@-ɇQ1/t~i`]١lهkO758.,{2wdӱU"TowI| -H:G"=qbk,)td.b5 ^k @Sr}*ISЦ$N%T 0QZ<eL)s3Kg^fF@ɦAҨOS7bP;-Z}y6͢_)Dg]Ϲ U#֭ݣ#x [s`T@IhZ>-Wp>- OkеH)AZ6G:?D P/?%+&e_Hon1~-W=Xf.y:6d`pm1l+* &N_(ob2 v }.\To(M U::k;L/'D(/,H5nvm8:8wBF(Hi.5nT-tዐl9[! I_18ukMtrr$!4Г+}ow  X#  2CcRrQy-c@ygճ1CWsk,L [4ykX/GpK]hϤ?uS|W3HNS~|+!Qp~)gC^Ji"jJNopvLrQ9 '~*ud"$S瓵4DE+zd=&F~=Osb<8'}w &:˦u#0@"=XT %Rx\7ll%{wLR  K(&W=*Es@yALLDV*mŁz/%;,Ui6uuu݋u_7gE&rqh$,9?)6J )%2xH1Q8DcJEJ$0n[|G²L#㦫tYI)kMX![v=;wtNkQ( >    !wq=ڛb2CcRY6{ L 2CcRك+M4ޒ=.#Шw3|շA 4"o)WlYn! n]`tq؀?KjTSKc:X8L':@(a'@j Q\ 1^оeS<t9Y!Qi o蕩 p?ueom^{-vM&HDL~OU#R;U1RLo\G^zO`DR#2ܰ5q1~l߈J^jgL%XC]?}]$ *%|ic8x1"R2'bעo{i(1< T dvWBʰűٺzv/'hrd@w1z<+͙aыfb{f?A'[}*P.6. ~(|M褮 =&_{]gAS#wq; p]B3Ux!g6}(!ScOҽ~&URgEXґ!,-=֑jiA.f= B+Rڔ*- ?DG$Neal H. Walfield ( >    !wq=ڛb2CcRY6{ L 2CcRك+M4ޒ=.#Шw3|շA 4"o)WlYn! n]`tq؀?KjTSKc:X8L':@(a'@j Q\ 1^оeS<t9Y!Qi o蕩 p?ueom^{-vM&HDL~O!Neal H. Walfield % ;    !wq=ڛb2CcRY6{ L 2CcRٷ-pȿd4\<ɰe #~5g,jO,a-uzC<[٧Q;>G5aG)x1*]T{S&k4-zJ=r.UVt*aof-/XGOiGֆP}XkmTW̕1rKqHww^uyIJ t]wO\_*;K:{eۖ$z ;Ǜۀ }AzI$sc尽&ʅ xK_ˆFruQV^Oy'O0;챐z҆%2/R@cĻK 8T+3 $eyE`+Z49M.7^e>q< <%J8&ߕkS}SwMA[]ӌ#Neal H. Walfield  0 !wq=ڛb2CcRY5 2CcR<qmE*\bsp!qLzRb(i/4!j"b8E,7X@/kme qXy2kd/A[eI˪ݕ -:g gs>@:z#pʀmO^ӀރhrYH, F4@uL5R_l(B#PĊuVr2.Z |Ed)K3Z\15W{ cHnzZ_UyŲß_U8v矜nByA #3BB:b#շ73+ ==&J{r_&Neal H. Walfield % ;    !wq=ڛb2CcRY6{ L 2CcR$4 P뀁W M;8LtW-*ҹ,Vҿs0+Q3ԗLsbя߲ nީ[w-~pJZ\) #(y7t=wKKk Z}9AB#tRBD!8{=w'U58z![īXop~<@?9/6KRJO$?֪c)I4mQ{Ta%,gVL_fZK< mXcNYjegVKߊMu7<vOՅle|;;L&M jзDOFRwh5xnL5}:N'Neal H. Walfield % ;    !wq=ڛb2CcRY6| L 2CcRH} (&*(.txc:ྪ!ѴL]<. Aaj|ijwEyꓥ/|,mcw*a~v=xw:g ]judHnuX1tlǩM06z(l)tDgϱd< A΁B'wqWy}\ŅgY5E;*=RIFp=.)Lyz4%&fO1nxFu;{s0:܌[zǪHO.*%8.*+JtqAu]et#뼊9 4, +5[rt˙O9|L.j5!BC<:feb1ܬ~/ٝǏzia-ͻB'| p+9=,m,LRd'Neal H. Walfield % ;!wq=ڛb2CcRZ<  L     2CcRyP-vΦ&ʾHEiFdn6mZE#H"S0R¤O`?>`ՄM-nGS#=! Gi xP(,6zU 8W,poj4t R_1k R+GebW}Y^;sfWn\5NvL>Fs0D U#5Q$_|p|CxTsls_yAHxeYZvS2j[ױØ;?|4%߯š p-xc a!Л&d #$݀['yX2}H& ۨ9=[@S I~GP=LqW?2$c?rrw(eQ+9]:ߤ0 \.NBMenO]U U# g) 2CcR]  U# r#fx%(yΆ>H ܖ]Wk>-N$`$48b觶FRL[Pэ 4ڀ9R W6 փ玮d)~6mR#2C#?5dȏˤ>WX|ьk))`ZB1w$1Q#3Qz6M} dQ<\^U&v8c&jPb{10|iX #I'TJ+ɖx1 2٤'ELOOH ߅5cF€dQ|G/5E01uƐl="HS\n|zU f0 Q:# lP$PŦ"JE&Mb:ʏp ,_'N'Pkڛ3<"54m;XQlz3 f묟CQɻ[7qX%ΝFغfJ1Zԣ|Ef4bI29֠^)Ӵ oY\/9+M~%贐\%]] h5NDu=sǪ ⅤzY<A#_s}qG" C&˥>g>' ]P i   4y cauQfU8ڐ^뎼 rLU} X%Hm"E^$8x0bq#-=Fʼn X#  )]  U# r#fx%(yΆ>H ܖ]Wk>-N$`$48b觶FRL[Pэ 4ڀ9R W6 փ玮d)~6mR#2C#?5dȏˤ>WX|ьk))`ZB1w$1Q#3Qz6M} dQ<\^U&v8c&jPb{10|iX #I'TJ+ɖx1 2٤ 2CcR0?友rɳ~PFbJ=vj/nI {<\+}9ٚ/H0qJԚpd FE᳐k/ЦS10[[ܾ؉z/ǀvԧwK((V.lwdtNr%oC/mv`~3 HV+Vz1mĀcW iPϕ=E8ZzNdlkh(TOѻner/&3[ScLT] }4 (3FC'8}9}B06>)9 2"^2DWby8C:MSГdjlߏ3챆)>> SvtرuVТB #:!o8|/'CD-`(f-3 U#  g 2CcRم]qbON@6>HܐŌE  X# # 2CcRS-`KsAN.) $Xt@F18iVȘY%䠠y"^ApJԛW(8)g<ܜg#$1]'_e5ef;}GI~?fLE K6*I~XiIb\t؀@ffkjGL>47_;B5dwEц0N@-ɇQ1/t~i`]١lهkO758.,{2wdӱU"TowI| -H:G"=qbk,)td.b5 ^k @Sr}*ISЦ$N%T 0QZ<eL)s3Kg^fF@ɦAҨOS7bP;-Z}y6͢_)Dg]Ϲ U#֭ݣ#x [s`T@IhZ>-Wp>- OkеH)AZ6G:?D P/?%+&e_Hon1~-W=Xf.y:6d`pm1l+* &N_(ob2 v }.\To(M U::k;L/'D(/,H5nvm8:8wBF(Hi.5nT-tዐl9[! I_18ukMtrr$!4Г+}ow  X#  2CcRrQy-c@ygճ1CWsk,L [4ykX/GpK]hϤ?uS|W3HNS~|+!Qp~)gC^Ji"jJNopvLrQ9 '~*ud"$S瓵4DE+zd=&F~=Osb<8'}w &:˦u#0@"=XT %Rx\7ll%{wLR  K(&W=*Es@yALLDV*mŁz/%;,Ui6uuu݋u_7gE&rqh$,9?)6J )%2xH1Q8DcJEJ$0n[|G²L#㦫tYI)kMX![v=;wtNkQsequoia-sqv-0.14.0/tests/data/bad-subkey-keyring.txt010064400017500001750000000006631361731103000206020ustar0000000000000000This key keyring contains two keys in the following order: "Justus", "Neal". Justus's key includes all of Neal's subkeys. When Justus's key is canonicalized, Neal's subkeys should be dropped. If an application looks for Neal's signing subkey and either doesn't validate the keys or only filters on the unvalidated keys, then it will not find the right key. This was fixed in sqv in commit 1d63e71a839bf68f50cb7f4c1942f0d0b1eccfca. sequoia-sqv-0.14.0/tests/data/bad-subkey.txt010064400017500001750000000000041361731103000171210ustar0000000000000000foo sequoia-sqv-0.14.0/tests/data/bad-subkey.txt.sig010064400017500001750000000004661361731103000177160ustar00000000000000003 !?AWdar#fx%([4 r#fx%(?BLX Nfrq'9_wu:P?] TIL83̷xn=f/=:[}e)>!L̠{ EӳPV<;+-MC#^zĐ͗,&yZ}H\hxΖLO-d;,.PEᗬjt/L~BV:p^J=xīF FK/$[6U(ſ=//7-I@d QK*j{N@2%XZT[]'Fx9<8s"!-! e/>d5nH.CneJIyɎގj \A Z^\L"QfA@XTqw5Tj(6¹Uam u+`sK=ŖKIݑdmXVi\hCI/~rdu.v{ 5K_+ɶyAU\׌ E:t*޷pQiɮV0eg蜴!@ce#Y~J3ķ 6$[ڶwe2@q,uegc~T֔0w~Qgxݫ>0faJU, |HuE wnقAxG#Cۃ\Z`Bma(1C 3 \A!L/fw m w m m .XmB!kcimq[ V҆>~)/T0u"-#Xfԋsŝ*'4œ%(0-PP`^t7S=ymMyF/I4J&-҇:7 *In<`D}b&@ ߸s51/wgw4 ;f"xb݅͹&Y. H\މhi }6U9HSƷu6N|lg8Gn'0n'\ q$KiTroS8( Q72JW OO*)]D; HTśi v N[JqO hS:Aˍ3sequoia-sqv-0.14.0/tests/data/no-signing-caps.sig010064400017500001750000000006661361731103000200500ustar0000000000000000 '\A!1z"fbM-,)`X -,)`X(z hT7}8RQ)GPejn"J_jp w3ʢ:7%\{l!0|'2sO $w _G \g 6ݣ+H7ry(Zz,{,9`;lVILcFpN, xZq0HhL1〿T`8}%S? #.^\YS`[B6&v NnQrrb!Խ ;zւh^/Gzn[* j|h?}.)TN|O[z"9f[%T#r(DE\naeW$5!G};sequoia-sqv-0.14.0/tests/data/revoked-key-cert-not-revoked.pgp010064400017500001750000000015161361731103000224660ustar000000000000000038m5p +G@LQh Yx7RqDViC&yNk~0<0!aG.Љt@;1 t@;1 &a$̵ї>Ԛ\\# *LמGS+gPJ |O +~08m5p!aG.Љt@;1 t@;1 |}us{cQDzux2SuYXCӜ?p`[[;E*x38n +G@?; )uxYyJӗy +/>y'hK=Nٻ;ō8A <Z|DI|j'k dC ?o:2rTR5-6`ZP2BVT߁tG6A8Z /*9 !aG.Љt@;1 t@;1wv'9 !1smƔ+/>y +/>y=N赿Fmo/|""0r5mCHj!@E*`q1o*B F . Qw?EK>s:'a@2YnoE sequoia-sqv-0.14.0/tests/data/revoked-key-cert-revoked-compromised.pgp010064400017500001750000000017511361731103000242100ustar000000000000000038m5p +G@LQh Yx7RqDViC&yNk~0<0!aG.Љt@;1 t@;1 &a$̵ї>Ԛ\\# *LמGS+gPJ |O +~08m5p!aG.Љt@;1 t@;1 |}us{cQDzux2SuYXCӜ?p`[[;E*x™ K:Op!aG.Љt@;1 t@;1#Key material has been compromisedtGSy1 bvT牆[KQqx$Z/U3YMH1]IO38n +G@?; )uxYyJӗy +/>y'hK=Nٻ;ō8A <Z|DI|j'k dC ?o:2rTR5-6`ZP2BVT߁tG6A8Z /*9 !aG.Љt@;1 t@;1wv'9 !1smƔ+/>y +/>y=N赿Fmo/|""0r5mCHj!@E*`q1o*B F . Qw?EK>s:'a@2YnoE sequoia-sqv-0.14.0/tests/data/revoked-key-cert-revoked-compromised.sk.pgp010064400017500001750000000017511361731103000246240ustar000000000000000038m5p +G@LQh Yx7RqDViC&yNk~0<0!aG.Љt@;1 t@;1 &a$̵ї>Ԛ\\# *LמGS+gPJ |O +~08m5p!aG.Љt@;1 t@;1 |}us{cQDzux2SuYXCӜ?p`[[;E*x38n +G@?; )uxYyJӗ<™(K:Op!aG.Љt@;1 t@;1#Key material has been compromisedn[o6[8P}CЦ W=vnm0љ9Q:G^=<,C=s /*<0!aG.Љt@;1 t@;1wv'<0!1smƔ+/>y +/>y'hK=Nٻ;ō8A <Z|DI|j'k dC ?o:2rTR5-6`ZP2BVT߁tG6A8Z /*9 !aG.Љt@;1 t@;1wv'9 !1smƔ+/>y +/>y=N赿Fmo/|""0r5mCHj!@E*`q1o*B F . Qw?EK>s:'a@2YnoE sequoia-sqv-0.14.0/tests/data/revoked-key-cert-revoked-key_retired.pgp010064400017500001750000000017511361731103000241750ustar000000000000000038m5p +G@LQh Yx7RqDViC&yNk~0<0!aG.Љt@;1 t@;1 &a$̵ї>Ԛ\\# *LמGS+gPJ |O +~08m5p!aG.Љt@;1 t@;1 |}us{cQDzux2SuYXCӜ?p`[[;E*x™ K:Op!aG.Љt@;1 t@;1#Key is retired and no longer usedr4UЇZ7mx{v[x,<.Jć‘1Bz{lzP)A38n +G@?; )uxYyJӗy +/>y'hK=Nٻ;ō8A <Z|DI|j'k dC ?o:2rTR5-6`ZP2BVT߁tG6A8Z /*9 !aG.Љt@;1 t@;1wv'9 !1smƔ+/>y +/>y=N赿Fmo/|""0r5mCHj!@E*`q1o*B F . Qw?EK>s:'a@2YnoE sequoia-sqv-0.14.0/tests/data/revoked-key-cert-revoked-key_retired.sk.pgp010064400017500001750000000017511361731103000246110ustar000000000000000038m5p +G@LQh Yx7RqDViC&yNk~0<0!aG.Љt@;1 t@;1 &a$̵ї>Ԛ\\# *LמGS+gPJ |O +~08m5p!aG.Љt@;1 t@;1 |}us{cQDzux2SuYXCӜ?p`[[;E*x38n +G@?; )uxYyJӗ<™(K:Op!aG.Љt@;1 t@;1#Key is retired and no longer used$Ke/+nwF 9#YKdcvw5DNrzVUXc[tp/*<0!aG.Љt@;1 t@;1wv'<0!1smƔ+/>y +/>y'hK=Nٻ;ō8A <Z|DI|j'k dC ?o:2rTR5-6`ZP2BVT߁tG6A8Z /*9 !aG.Љt@;1 t@;1wv'9 !1smƔ+/>y +/>y=N赿Fmo/|""0r5mCHj!@E*`q1o*B F . Qw?EK>s:'a@2YnoE sequoia-sqv-0.14.0/tests/data/revoked-key-cert-revoked-no_subpacket.pgp010064400017500001750000000017051361731103000243430ustar000000000000000038m5p +G@LQh Yx7RqDViC&yNk~0<0!aG.Љt@;1 t@;1 &a$̵ї>Ԛ\\# *LמGS+gPJ |O +~08m5p!aG.Љt@;1 t@;1 |}us{cQDzux2SuYXCӜ?p`[[;E*xu ':Op!aG.Љt@;1 t@;1B:@QXkBBtx$NAúYI:[pUfw{:;)38n +G@?; )uxYyJӗy +/>y'hK=Nٻ;ō8A <Z|DI|j'k dC ?o:2rTR5-6`ZP2BVT߁tG6A8Z /*9 !aG.Љt@;1 t@;1wv'9 !1smƔ+/>y +/>y=N赿Fmo/|""0r5mCHj!@E*`q1o*B F . Qw?EK>s:'a@2YnoE sequoia-sqv-0.14.0/tests/data/revoked-key-cert-revoked-no_subpacket.sk.pgp010064400017500001750000000017051361731103000247570ustar000000000000000038m5p +G@LQh Yx7RqDViC&yNk~0<0!aG.Љt@;1 t@;1 &a$̵ї>Ԛ\\# *LמGS+gPJ |O +~08m5p!aG.Љt@;1 t@;1 |}us{cQDzux2SuYXCӜ?p`[[;E*x38n +G@?; )uxYyJӗ-z^P/0Zx?kęU>^euox /*<0!aG.Љt@;1 t@;1wv'<0!1smƔ+/>y +/>y'hK=Nٻ;ō8A <Z|DI|j'k dC ?o:2rTR5-6`ZP2BVT߁tG6A8Z /*9 !aG.Љt@;1 t@;1wv'9 !1smƔ+/>y +/>y=N赿Fmo/|""0r5mCHj!@E*`q1o*B F . Qw?EK>s:'a@2YnoE sequoia-sqv-0.14.0/tests/data/revoked-key-cert-revoked-private.pgp010064400017500001750000000017621361731103000233430ustar000000000000000038m5p +G@LQh Yx7RqDViC&yNk~0<0!aG.Љt@;1 t@;1 &a$̵ї>Ԛ\\# *LמGS+gPJ |O +~08m5p!aG.Љt@;1 t@;1 |}us{cQDzux2SuYXCӜ?p`[[;E*x¢ T:Op!aG.Љt@;1 t@;1,dPrivate/Experimental revocation reason 100 Y ֿ@W)*_6^#萢ǁnͦǭ򘺢.BA$F 38n +G@?; )uxYyJӗy +/>y'hK=Nٻ;ō8A <Z|DI|j'k dC ?o:2rTR5-6`ZP2BVT߁tG6A8Z /*9 !aG.Љt@;1 t@;1wv'9 !1smƔ+/>y +/>y=N赿Fmo/|""0r5mCHj!@E*`q1o*B F . Qw?EK>s:'a@2YnoE sequoia-sqv-0.14.0/tests/data/revoked-key-cert-revoked-private.sk.pgp010064400017500001750000000017621361731103000237570ustar000000000000000038m5p +G@LQh Yx7RqDViC&yNk~0<0!aG.Љt@;1 t@;1 &a$̵ї>Ԛ\\# *LמGS+gPJ |O +~08m5p!aG.Љt@;1 t@;1 |}us{cQDzux2SuYXCӜ?p`[[;E*x38n +G@?; )uxYyJӗ<¢(T:Op!aG.Љt@;1 t@;1,dPrivate/Experimental revocation reason 100xڔY|?0s7 ~'go.!tq9hb?A M/Ê /*<0!aG.Љt@;1 t@;1wv'<0!1smƔ+/>y +/>y'hK=Nٻ;ō8A <Z|DI|j'k dC ?o:2rTR5-6`ZP2BVT߁tG6A8Z /*9 !aG.Љt@;1 t@;1wv'9 !1smƔ+/>y +/>y=N赿Fmo/|""0r5mCHj!@E*`q1o*B F . Qw?EK>s:'a@2YnoE sequoia-sqv-0.14.0/tests/data/revoked-key-cert-revoked-superseded.pgp010064400017500001750000000017311361731103000240300ustar000000000000000038m5p +G@LQh Yx7RqDViC&yNk~0<0!aG.Љt@;1 t@;1 &a$̵ї>Ԛ\\# *LמGS+gPJ |O +~08m5p!aG.Љt@;1 t@;1 |}us{cQDzux2SuYXCӜ?p`[[;E*x‰ ;:Op!aG.Љt@;1 t@;1Key is superseded Pjk*`*DZǩ\y9Dt<w,?צTT+:wL1(Kg 38n +G@?; )uxYyJӗy +/>y'hK=Nٻ;ō8A <Z|DI|j'k dC ?o:2rTR5-6`ZP2BVT߁tG6A8Z /*9 !aG.Љt@;1 t@;1wv'9 !1smƔ+/>y +/>y=N赿Fmo/|""0r5mCHj!@E*`q1o*B F . Qw?EK>s:'a@2YnoE sequoia-sqv-0.14.0/tests/data/revoked-key-cert-revoked-superseded.sk.pgp010064400017500001750000000017311361731103000244440ustar000000000000000038m5p +G@LQh Yx7RqDViC&yNk~0<0!aG.Љt@;1 t@;1 &a$̵ї>Ԛ\\# *LמGS+gPJ |O +~08m5p!aG.Љt@;1 t@;1 |}us{cQDzux2SuYXCӜ?p`[[;E*x38n +G@?; )uxYyJӗ<‰(;:Op!aG.Љt@;1 t@;1Key is supersededB|7󦷜t/pQx"m0>hgQh641ALhFէ~fd /*<0!aG.Љt@;1 t@;1wv'<0!1smƔ+/>y +/>y'hK=Nٻ;ō8A <Z|DI|j'k dC ?o:2rTR5-6`ZP2BVT߁tG6A8Z /*9 !aG.Љt@;1 t@;1wv'9 !1smƔ+/>y +/>y=N赿Fmo/|""0r5mCHj!@E*`q1o*B F . Qw?EK>s:'a@2YnoE sequoia-sqv-0.14.0/tests/data/revoked-key-cert-revoked-uid_retired.pgp010064400017500001750000000017561361731103000241730ustar000000000000000038m5p +G@LQh Yx7RqDViC&yNk~0<0!aG.Љt@;1 t@;1 &a$̵ї>Ԛ\\# *LמGS+gPJ |O +~08m5p!aG.Љt@;1 t@;1 |}us{cQDzux2SuYXCӜ?p`[[;E*xž P:Op!aG.Љt@;1 t@;1( User ID information is no longer valid;hU;S&&jcri%E;vj+IE>Q,:0UՋ85>\q) 38n +G@?; )uxYyJӗy +/>y'hK=Nٻ;ō8A <Z|DI|j'k dC ?o:2rTR5-6`ZP2BVT߁tG6A8Z /*9 !aG.Љt@;1 t@;1wv'9 !1smƔ+/>y +/>y=N赿Fmo/|""0r5mCHj!@E*`q1o*B F . Qw?EK>s:'a@2YnoE sequoia-sqv-0.14.0/tests/data/revoked-key-cert-revoked-uid_retired.sk.pgp010064400017500001750000000017561361731103000246070ustar000000000000000038m5p +G@LQh Yx7RqDViC&yNk~0<0!aG.Љt@;1 t@;1 &a$̵ї>Ԛ\\# *LמGS+gPJ |O +~08m5p!aG.Љt@;1 t@;1 |}us{cQDzux2SuYXCӜ?p`[[;E*x38n +G@?; )uxYyJӗ<ž(P:Op!aG.Љt@;1 t@;1( User ID information is no longer validq pI{ki6gQ j!wXR&zoj% /*<0!aG.Љt@;1 t@;1wv'<0!1smƔ+/>y +/>y'hK=Nٻ;ō8A <Z|DI|j'k dC ?o:2rTR5-6`ZP2BVT߁tG6A8Z /*9 !aG.Љt@;1 t@;1wv'9 !1smƔ+/>y +/>y=N赿Fmo/|""0r5mCHj!@E*`q1o*B F . Qw?EK>s:'a@2YnoE sequoia-sqv-0.14.0/tests/data/revoked-key-cert-revoked-unknown.pgp010064400017500001750000000017451361731103000233710ustar000000000000000038m5p +G@LQh Yx7RqDViC&yNk~0<0!aG.Љt@;1 t@;1 &a$̵ї>Ԛ\\# *LמGS+gPJ |O +~08m5p!aG.Љt@;1 t@;1 |}us{cQDzux2SuYXCӜ?p`[[;E*x• G:Op!aG.Љt@;1 t@;1Unknown revocation reason 200gY,cWUFmQk)i9S]ȲQ*UiM$38n +G@?; )uxYyJӗy +/>y'hK=Nٻ;ō8A <Z|DI|j'k dC ?o:2rTR5-6`ZP2BVT߁tG6A8Z /*9 !aG.Љt@;1 t@;1wv'9 !1smƔ+/>y +/>y=N赿Fmo/|""0r5mCHj!@E*`q1o*B F . Qw?EK>s:'a@2YnoE sequoia-sqv-0.14.0/tests/data/revoked-key-cert-revoked-unknown.sk.pgp010064400017500001750000000017451361731103000240050ustar000000000000000038m5p +G@LQh Yx7RqDViC&yNk~0<0!aG.Љt@;1 t@;1 &a$̵ї>Ԛ\\# *LמGS+gPJ |O +~08m5p!aG.Љt@;1 t@;1 |}us{cQDzux2SuYXCӜ?p`[[;E*x38n +G@?; )uxYyJӗ<•(G:Op!aG.Љt@;1 t@;1Unknown revocation reason 2000a}꓅pj{_HʂbE˓`FJqLqtjhz H @_l/*<0!aG.Љt@;1 t@;1wv'<0!1smƔ+/>y +/>y'hK=Nٻ;ō8A <Z|DI|j'k dC ?o:2rTR5-6`ZP2BVT߁tG6A8Z /*9 !aG.Љt@;1 t@;1wv'9 !1smƔ+/>y +/>y=N赿Fmo/|""0r5mCHj!@E*`q1o*B F . Qw?EK>s:'a@2YnoE sequoia-sqv-0.14.0/tests/data/revoked-key-cert-revoked-unspecified.pgp010064400017500001750000000017331361731103000241650ustar000000000000000038m5p +G@LQh Yx7RqDViC&yNk~0<0!aG.Љt@;1 t@;1 &a$̵ї>Ԛ\\# *LמGS+gPJ |O +~08m5p!aG.Љt@;1 t@;1 |}us{cQDzux2SuYXCӜ?p`[[;E*x‹ =:Op!aG.Љt@;1 t@;1No reason specifiedYEtp^]i6 yqJ6Oe +Eմdt^k+L}V{An1ɾ9S 38n +G@?; )uxYyJӗy +/>y'hK=Nٻ;ō8A <Z|DI|j'k dC ?o:2rTR5-6`ZP2BVT߁tG6A8Z /*9 !aG.Љt@;1 t@;1wv'9 !1smƔ+/>y +/>y=N赿Fmo/|""0r5mCHj!@E*`q1o*B F . Qw?EK>s:'a@2YnoE sequoia-sqv-0.14.0/tests/data/revoked-key-cert-revoked-unspecified.sk.pgp010064400017500001750000000017331361731103000246010ustar000000000000000038m5p +G@LQh Yx7RqDViC&yNk~0<0!aG.Љt@;1 t@;1 &a$̵ї>Ԛ\\# *LמGS+gPJ |O +~08m5p!aG.Љt@;1 t@;1 |}us{cQDzux2SuYXCӜ?p`[[;E*x38n +G@?; )uxYyJӗ<‹(=:Op!aG.Љt@;1 t@;1No reason specifiedX؟=3[ʘhp N;\Xv 187 -!,'dvjFO/*<0!aG.Љt@;1 t@;1wv'<0!1smƔ+/>y +/>y'hK=Nٻ;ō8A <Z|DI|j'k dC ?o:2rTR5-6`ZP2BVT߁tG6A8Z /*9 !aG.Љt@;1 t@;1wv'9 !1smƔ+/>y +/>y=N赿Fmo/|""0r5mCHj!@E*`q1o*B F . Qw?EK>s:'a@2YnoE sequoia-sqv-0.14.0/tests/data/revoked-key-sig-t0.pgp010064400017500001750000000001671361731103000204020ustar0000000000000000u'6!aG.Љt@;1 t@;1 W~Bh,$P3W9&lfs)L5L7_:k sequoia-sqv-0.14.0/tests/data/revoked-key-sig-t0.sk.pgp010064400017500001750000000001671361731103000210160ustar0000000000000000u'6!1smƔ+/>y +/>yꕷry4隷r9ă-ZدܠvqU. %wA⤃ sequoia-sqv-0.14.0/tests/data/revoked-key-sig-t1-t2.pgp010064400017500001750000000001671361731103000207260ustar0000000000000000u'9 ip!aG.Љt@;1 t@;1n_T dvVGg"@jzu59[韤~ꬾ`#6* sequoia-sqv-0.14.0/tests/data/revoked-key-sig-t1-t2.sk.pgp010064400017500001750000000001671361731103000213420ustar0000000000000000u'9 ip!1smƔ+/>y +/>y\m]Yj ,:C=c>vZ:ꦓ1EDZ$tEﶴ sequoia-sqv-0.14.0/tests/data/revoked-key-sig-t2-t3.pgp010064400017500001750000000001671361731103000207300ustar0000000000000000u';dp!aG.Љt@;1 t@;1 Zu1.>EMğ1gpGN`. DlB;u sequoia-sqv-0.14.0/tests/data/revoked-key-sig-t2-t3.sk.pgp010064400017500001750000000001671361731103000213440ustar0000000000000000u';dp!1smƔ+/>y +/>y|45Th?w$x7xzWUN\Xf #B{*4y +/>y+-H$5x'|rD9x}"ׁd!sq{TGӂ:Jdsequoia-sqv-0.14.0/tests/duplicate-signatures.rs010064400017500001750000000020011361731103000201220ustar0000000000000000extern crate assert_cli; use assert_cli::Assert; fn p(filename: &str) -> String { format!("../openpgp/tests/data/{}", filename) } /// Asserts that duplicate signatures are properly ignored. #[test] fn ignore_duplicates() { // Duplicate is ignored, but remaining one is ok. Assert::cargo_binary("sqv") .with_args( &["--keyring", &p("keys/emmelie-dorothea-dina-samantha-awina-ed25519.pgp"), &p("messages/a-cypherpunks-manifesto.txt.ed25519.sig.duplicated"), &p("messages/a-cypherpunks-manifesto.txt")]) .unwrap(); // Duplicate is ignored, and fails to meet the threshold. Assert::cargo_binary("sqv") .with_args( &["--keyring", &p("keys/emmelie-dorothea-dina-samantha-awina-ed25519.pgp"), "--signatures=2", &p("messages/a-cypherpunks-manifesto.txt.ed25519.sig.duplicated"), &p("messages/a-cypherpunks-manifesto.txt")]) .fails() .unwrap(); } sequoia-sqv-0.14.0/tests/multiple-signatures.rs010064400017500001750000000013241361731103000200120ustar0000000000000000extern crate assert_cli; use assert_cli::Assert; fn p(filename: &str) -> String { format!("../openpgp/tests/data/{}", filename) } /// Asserts that multiple signatures from the same Cert are properly /// ignored. #[test] fn ignore_multiple_signatures() { // Multiple signatures from the same Cert are ignored, and fails to // meet the threshold. Assert::cargo_binary("sqv") .with_args( &["--keyring", &p("keys/emmelie-dorothea-dina-samantha-awina-ed25519.pgp"), "--signatures=2", &p("messages/a-cypherpunks-manifesto.txt.ed25519.sig.duplicated"), &p("messages/a-cypherpunks-manifesto.txt")]) .fails() .unwrap(); } sequoia-sqv-0.14.0/tests/not-before-after.rs010064400017500001750000000037621361731103000171440ustar0000000000000000extern crate assert_cli; #[cfg(test)] mod integration { use assert_cli::Assert; fn p(filename: &str) -> String { format!("../openpgp/tests/data/{}", filename) } #[test] fn unconstrained() { Assert::cargo_binary("sqv") .with_args( &["--keyring", &p("keys/emmelie-dorothea-dina-samantha-awina-ed25519.pgp"), &p("messages/a-cypherpunks-manifesto.txt.ed25519.sig"), &p("messages/a-cypherpunks-manifesto.txt")]) .stdout().is("8E8C33FA4626337976D97978069C0C348DD82C19") .unwrap(); } #[test] fn in_interval() { Assert::cargo_binary("sqv") .with_args( &["--keyring", &p("keys/emmelie-dorothea-dina-samantha-awina-ed25519.pgp"), "--not-before", "2018-08-14", "--not-after", "2018-08-15", &p("messages/a-cypherpunks-manifesto.txt.ed25519.sig"), &p("messages/a-cypherpunks-manifesto.txt")]) .stdout().is("8E8C33FA4626337976D97978069C0C348DD82C19") .unwrap(); } #[test] fn before() { Assert::cargo_binary("sqv") .with_args( &["--keyring", &p("keys/emmelie-dorothea-dina-samantha-awina-ed25519.pgp"), "--not-before", "2018-08-15", &p("messages/a-cypherpunks-manifesto.txt.ed25519.sig"), &p("messages/a-cypherpunks-manifesto.txt")]) .fails() .unwrap(); } #[test] fn after() { Assert::cargo_binary("sqv") .with_args( &["--keyring", &p("keys/emmelie-dorothea-dina-samantha-awina-ed25519.pgp"), "--not-after", "2018-08-13", &p("messages/a-cypherpunks-manifesto.txt.ed25519.sig"), &p("messages/a-cypherpunks-manifesto.txt")]) .fails() .unwrap(); } } sequoia-sqv-0.14.0/tests/revoked-key.rs010064400017500001750000000475451361731103000162410ustar0000000000000000//! Tests revocations and binding signatures over time. //! //! These tests create a certificate with a signing capable primary //! key (subkey), and revoke it later on, then re-legitimize it using //! a new signature. We then ask sqv to verify a signature at //! different points in time. Hard revocations of the key invalidate //! the signature at any point in time, whereas in the case of soft //! revocations, the keys can be re-legitimized. //! //! All tests are run in three flavors: //! //! 0. The primary key makes the signatures and is revoked. //! 1. The subkey makes the signatures, primary key is revoked. //! 2. The subkey makes the signatures and is revoked. //! //! As extra subtlety, we bind the subkey *after* the t1-t2 signature. //! //! Timeline: v //! | //! t0 -| - Signature revoked-key-sig-t0.pgp //! | //! t1 -| - Primary key creation //! | //! | - Subkey creation //! | //! | - Signature revoked-key-sig-t1-t2.pgp //! | //! | - Subkey is bound //! | //! t2 -| - Revocation of (sub)key //! | //! | - Signature revoked-key-sig-t2-t3.pgp //! | //! t3 -| - New direct/binding signature //! | //! | - Signature revoked-key-sig-t3-now.pgp //! | //! now -| //! v extern crate assert_cli; #[cfg(test)] mod integration { use assert_cli::Assert; use std::path; fn sqv(keyring: &str, sig: &str) -> Assert { Assert::cargo_binary("sqv") .current_dir(path::Path::new("tests").join("data")) .with_args( &["--keyring", &format!("revoked-key-cert-{}.pgp", keyring), &format!("revoked-key-sig-{}.pgp", sig), "msg.txt"]) } /// Tests flavor 0, primary key signs and is revoked. fn f0(keyring: &str, sig: &str) -> Assert { sqv(keyring, sig) } /// Tests flavor 1, subkey signs and primary key is revoked. fn f1(keyring: &str, sig: &str) -> Assert { sqv(keyring, &format!("{}.sk", sig)) } /// Tests flavor 2, subkey signs and is revoked. fn f2(keyring: &str, sig: &str) -> Assert { sqv(&format!("{}.sk", keyring), &format!("{}.sk", sig)) } /// Base case, cert is not revoked. #[test] fn not_revoked() { let c = "not-revoked"; f0(c, "t0").fails().unwrap(); f0(c, "t1-t2").unwrap(); f0(c, "t2-t3").unwrap(); f0(c, "t3-now").unwrap(); f1(c, "t0").fails().unwrap(); f1(c, "t1-t2").fails().unwrap(); f1(c, "t2-t3").unwrap(); f1(c, "t3-now").unwrap(); // f2 is not used here, because we don't have any revocations. } /// The hard revocation reasons. All signatures are invalid. #[test] fn revoked_no_subpacket() { let c = "revoked-no_subpacket"; f0(c, "t0").fails().unwrap(); f0(c, "t1-t2").fails().and().stderr().contains("revoked").unwrap(); f0(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f0(c, "t3-now").fails().and().stderr().contains("revoked").unwrap(); f1(c, "t0").fails().unwrap(); f1(c, "t1-t2").fails().unwrap(); f1(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f1(c, "t3-now").fails().and().stderr().contains("revoked").unwrap(); f2(c, "t0").fails().unwrap(); f2(c, "t1-t2").fails().unwrap(); f2(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f2(c, "t3-now").fails().and().stderr().contains("revoked").unwrap(); } #[test] fn revoked_unspecified() { let c = "revoked-unspecified"; f0(c, "t0").fails().unwrap(); f0(c, "t1-t2").fails().and().stderr().contains("revoked").unwrap(); f0(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f0(c, "t3-now").fails().and().stderr().contains("revoked").unwrap(); f1(c, "t0").fails().unwrap(); f1(c, "t1-t2").fails().unwrap(); f1(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f1(c, "t3-now").fails().and().stderr().contains("revoked").unwrap(); f2(c, "t0").fails().unwrap(); f2(c, "t1-t2").fails().unwrap(); f2(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f2(c, "t3-now").fails().and().stderr().contains("revoked").unwrap(); } #[test] fn revoked_compromised() { let c = "revoked-compromised"; f0(c, "t0").fails().unwrap(); f0(c, "t1-t2").fails().and().stderr().contains("revoked").unwrap(); f0(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f0(c, "t3-now").fails().and().stderr().contains("revoked").unwrap(); f1(c, "t0").fails().unwrap(); f1(c, "t1-t2").fails().unwrap(); f1(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f1(c, "t3-now").fails().and().stderr().contains("revoked").unwrap(); f2(c, "t0").fails().unwrap(); f2(c, "t1-t2").fails().unwrap(); f2(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f2(c, "t3-now").fails().and().stderr().contains("revoked").unwrap(); } #[test] fn revoked_private() { let c = "revoked-private"; f0(c, "t0").fails().unwrap(); f0(c, "t1-t2").fails().and().stderr().contains("revoked").unwrap(); f0(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f0(c, "t3-now").fails().and().stderr().contains("revoked").unwrap(); f1(c, "t0").fails().unwrap(); f1(c, "t1-t2").fails().unwrap(); f1(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f1(c, "t3-now").fails().and().stderr().contains("revoked").unwrap(); f2(c, "t0").fails().unwrap(); f2(c, "t1-t2").fails().unwrap(); f2(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f2(c, "t3-now").fails().and().stderr().contains("revoked").unwrap(); } #[test] fn revoked_unknown() { let c = "revoked-unknown"; f0(c, "t0").fails().unwrap(); f0(c, "t1-t2").fails().and().stderr().contains("revoked").unwrap(); f0(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f0(c, "t3-now").fails().and().stderr().contains("revoked").unwrap(); f1(c, "t0").fails().unwrap(); f1(c, "t1-t2").fails().unwrap(); f1(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f1(c, "t3-now").fails().and().stderr().contains("revoked").unwrap(); f2(c, "t0").fails().unwrap(); f2(c, "t1-t2").fails().unwrap(); f2(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f2(c, "t3-now").fails().and().stderr().contains("revoked").unwrap(); } /// The soft revocation reasons. Only the signature dated prior /// to the key creation and the one directly after the revocation /// are invalid. #[test] fn revoked_superseded() { let c = "revoked-superseded"; f0(c, "t0").fails().unwrap(); f0(c, "t1-t2").unwrap(); f0(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f0(c, "t3-now").unwrap(); f1(c, "t0").fails().unwrap(); f1(c, "t1-t2").fails().unwrap(); f1(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f1(c, "t3-now").unwrap(); f2(c, "t0").fails().unwrap(); f2(c, "t1-t2").fails().unwrap(); f2(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f2(c, "t3-now").unwrap(); } #[test] fn revoked_key_retired() { let c = "revoked-key_retired"; f0(c, "t0").fails().unwrap(); f0(c, "t1-t2").unwrap(); f0(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f0(c, "t3-now").unwrap(); f1(c, "t0").fails().unwrap(); f1(c, "t1-t2").fails().unwrap(); f1(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f1(c, "t3-now").unwrap(); f2(c, "t0").fails().unwrap(); f2(c, "t1-t2").fails().unwrap(); f2(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f2(c, "t3-now").unwrap(); } /// XXX: This is an odd one. #[test] fn revoked_uid_retired() { let c = "revoked-uid_retired"; f0(c, "t0").fails().unwrap(); f0(c, "t1-t2").unwrap(); f0(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f0(c, "t3-now").unwrap(); f1(c, "t0").fails().unwrap(); f1(c, "t1-t2").fails().unwrap(); f1(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f1(c, "t3-now").unwrap(); f2(c, "t0").fails().unwrap(); f2(c, "t1-t2").fails().unwrap(); f2(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap(); f2(c, "t3-now").unwrap(); } } // Code to create the data for the test cases above //#[test] #[allow(dead_code)] fn create_key() { use std::fs::File; use sequoia_openpgp::{ Cert, Packet, PacketPile, packet::{ signature, Key, key::{ Key4, PrimaryRole, SubordinateRole, }, }, serialize::Serialize, types::{ Curve, Features, KeyFlags, SignatureType, HashAlgorithm, ReasonForRevocation, } }; use chrono::offset::TimeZone; let msg = b"Hello, World"; let t0 = chrono::offset::Utc.timestamp(915145200, 0); // 1999-01-01 let t1 = chrono::offset::Utc.timestamp(946681200, 0); // 2000-01-01 let t2 = chrono::offset::Utc.timestamp(978303600, 0); // 2001-01-01 let t3 = chrono::offset::Utc.timestamp(1009839600, 0); // 2002-01-01 let f1: f32 = 0.4; // Chosen by fair dice roll. let f2: f32 = 0.7; // Likewise. let t12 = t1 + chrono::Duration::days((300.0 * f1) as i64); let t_sk_binding = t12 + chrono::Duration::days(1); let t23 = t2 + chrono::Duration::days((300.0 * f2) as i64); // Create primary key. let mut key: Key<_, PrimaryRole> = Key4::generate_ecc(true, Curve::Ed25519).unwrap().into(); key.set_creation_time(t1).unwrap(); let mut signer = key.clone().into_keypair().unwrap(); // Create subkey. let mut subkey: Key<_, SubordinateRole> = Key4::generate_ecc(true, Curve::Ed25519).unwrap().into(); subkey.set_creation_time(t1 + chrono::Duration::days(1)).unwrap(); let mut sk_signer = subkey.clone().into_keypair().unwrap(); // 1st direct key signature valid from t1 on let mut b = signature::Builder::new(SignatureType::DirectKey) .set_features(&Features::sequoia()).unwrap() .set_key_flags(&KeyFlags::default() .set_signing(true).set_certification(true)).unwrap() .set_signature_creation_time(t1).unwrap() .set_issuer_fingerprint(key.fingerprint()).unwrap() .set_issuer(key.fingerprint().into()).unwrap() .set_preferred_hash_algorithms(vec![HashAlgorithm::SHA512]) .unwrap(); let direct1 = b.sign_direct_key(&mut signer).unwrap(); // 1st subkey binding signature valid from t_sk_binding on b = signature::Builder::new(SignatureType::SubkeyBinding) .set_key_flags(&KeyFlags::default().set_signing(true)).unwrap() .set_signature_creation_time(t_sk_binding).unwrap() .set_issuer_fingerprint(key.fingerprint()).unwrap() .set_issuer(key.fingerprint().into()).unwrap() .set_embedded_signature( signature::Builder::new(SignatureType::PrimaryKeyBinding) .set_signature_creation_time(t_sk_binding).unwrap() .set_issuer_fingerprint(subkey.fingerprint()).unwrap() .set_issuer(subkey.keyid()).unwrap() .sign_subkey_binding(&mut sk_signer, &key, &subkey).unwrap()) .unwrap(); let sk_bind1 = b.sign_subkey_binding(&mut signer, &key, &subkey).unwrap(); // 2nd direct key signature valid from t3 on b = signature::Builder::new(SignatureType::DirectKey) .set_features(&Features::sequoia()).unwrap() .set_key_flags(&KeyFlags::default() .set_signing(true).set_certification(true)).unwrap() .set_signature_creation_time(t3).unwrap() .set_issuer_fingerprint(key.fingerprint()).unwrap() .set_issuer(key.fingerprint().into()).unwrap() .set_preferred_hash_algorithms(vec![HashAlgorithm::SHA512]) .unwrap(); let direct2 = b.sign_direct_key(&mut signer).unwrap(); // 2nd subkey binding signature valid from t3 on let mut b = signature::Builder::new(SignatureType::SubkeyBinding) .set_key_flags(&KeyFlags::default().set_signing(true)).unwrap() .set_signature_creation_time(t3).unwrap() .set_issuer_fingerprint(key.fingerprint()).unwrap() .set_issuer(key.fingerprint().into()).unwrap() .set_embedded_signature( signature::Builder::new(SignatureType::PrimaryKeyBinding) .set_signature_creation_time(t3).unwrap() .set_issuer_fingerprint(subkey.fingerprint()).unwrap() .set_issuer(subkey.keyid()).unwrap() .sign_subkey_binding(&mut sk_signer, &key, &subkey).unwrap()) .unwrap(); let sk_bind2 = b.sign_subkey_binding(&mut signer, &key, &subkey).unwrap(); let cert = Cert::from_packet_pile(PacketPile::from(vec![ key.clone().into(), direct1.clone().into(), direct2.clone().into(), subkey.clone().into(), sk_bind1.clone().into(), sk_bind2.clone().into(), ])).unwrap(); let mut fd = File::create("revoked-key-cert-not-revoked.pgp").unwrap(); cert.serialize(&mut fd).unwrap(); for (slug, reason) in &[ ("no_subpacket", None), ("unspecified", Some(ReasonForRevocation::Unspecified)), ("superseded", Some(ReasonForRevocation::KeySuperseded)), ("compromised", Some(ReasonForRevocation::KeyCompromised)), ("key_retired", Some(ReasonForRevocation::KeyRetired)), ("uid_retired", Some(ReasonForRevocation::UIDRetired)), ("private", Some(ReasonForRevocation::Private(100))), ("unknown", Some(ReasonForRevocation::Unknown(200))), ] { // Revocation sig valid from t2 on let mut b = signature::Builder::new(SignatureType::KeyRevocation) .set_signature_creation_time(t2).unwrap() .set_issuer_fingerprint(key.fingerprint()).unwrap() .set_issuer(key.fingerprint().into()).unwrap(); if let Some(r) = reason { b = b.set_reason_for_revocation(r.clone(), r.to_string().as_bytes()) .unwrap(); } let rev = b.sign_direct_key(&mut signer).unwrap(); let cert = Cert::from_packet_pile(PacketPile::from(vec![ key.clone().into(), direct1.clone().into(), rev.clone().into(), direct2.clone().into(), subkey.clone().into(), sk_bind1.clone().into(), sk_bind2.clone().into(), ])).unwrap(); let mut fd = File::create(format!("revoked-key-cert-revoked-{}.pgp", slug)) .unwrap(); cert.serialize(&mut fd).unwrap(); // Again, this time we revoke the subkey. let mut b = signature::Builder::new(SignatureType::SubkeyRevocation) .set_signature_creation_time(t2).unwrap() .set_issuer_fingerprint(key.fingerprint()).unwrap() .set_issuer(key.fingerprint().into()).unwrap(); if let Some(r) = reason { b = b.set_reason_for_revocation(r.clone(), r.to_string().as_bytes()) .unwrap(); } let rev = b.sign_subkey_binding(&mut signer, &key, &subkey).unwrap(); let cert = Cert::from_packet_pile(PacketPile::from(vec![ key.clone().into(), direct1.clone().into(), direct2.clone().into(), subkey.clone().into(), sk_bind1.clone().into(), rev.clone().into(), sk_bind2.clone().into(), ])).unwrap(); let mut fd = File::create(format!("revoked-key-cert-revoked-{}.sk.pgp", slug)) .unwrap(); cert.serialize(&mut fd).unwrap(); } // 0th message sig before t1 let sig0 = signature::Builder::new(SignatureType::Binary) .set_signature_creation_time(t0).unwrap() .set_issuer_fingerprint(key.fingerprint()).unwrap() .set_issuer(key.fingerprint().into()).unwrap() .sign_message(&mut signer, msg).unwrap(); let mut fd = File::create("revoked-key-sig-t0.pgp").unwrap(); Packet::from(sig0).serialize(&mut fd).unwrap(); // 0th message sig before t1, subkey let sig0 = signature::Builder::new(SignatureType::Binary) .set_signature_creation_time(t0).unwrap() .set_issuer_fingerprint(subkey.fingerprint()).unwrap() .set_issuer(subkey.fingerprint().into()).unwrap() .sign_message(&mut sk_signer, msg).unwrap(); let mut fd = File::create("revoked-key-sig-t0.sk.pgp").unwrap(); Packet::from(sig0).serialize(&mut fd).unwrap(); // 1st message sig between t1 and t2 b = signature::Builder::new(SignatureType::Binary) .set_signature_creation_time(t12).unwrap() .set_issuer_fingerprint(key.fingerprint()).unwrap() .set_issuer(key.fingerprint().into()).unwrap(); let sig1 = b.sign_message(&mut signer, msg).unwrap(); let mut fd = File::create("revoked-key-sig-t1-t2.pgp").unwrap(); Packet::from(sig1).serialize(&mut fd).unwrap(); // 1st message sig between t1 and t2, subkey b = signature::Builder::new(SignatureType::Binary) .set_signature_creation_time(t12).unwrap() .set_issuer_fingerprint(subkey.fingerprint()).unwrap() .set_issuer(subkey.fingerprint().into()).unwrap(); let sig1 = b.sign_message(&mut sk_signer, msg).unwrap(); let mut fd = File::create("revoked-key-sig-t1-t2.sk.pgp").unwrap(); Packet::from(sig1).serialize(&mut fd).unwrap(); // 2nd message sig between t2 and t3 b = signature::Builder::new(SignatureType::Binary) .set_signature_creation_time(t23).unwrap() .set_issuer_fingerprint(key.fingerprint()).unwrap() .set_issuer(key.fingerprint().into()).unwrap(); let sig2 = b.sign_message(&mut signer, msg).unwrap(); let mut fd = File::create("revoked-key-sig-t2-t3.pgp").unwrap(); Packet::from(sig2).serialize(&mut fd).unwrap(); // 2nd message sig between t2 and t3, subkey b = signature::Builder::new(SignatureType::Binary) .set_signature_creation_time(t23).unwrap() .set_issuer_fingerprint(subkey.fingerprint()).unwrap() .set_issuer(subkey.fingerprint().into()).unwrap(); let sig2 = b.sign_message(&mut sk_signer, msg).unwrap(); let mut fd = File::create("revoked-key-sig-t2-t3.sk.pgp").unwrap(); Packet::from(sig2).serialize(&mut fd).unwrap(); // 3rd message sig between t3 and now b = signature::Builder::new(SignatureType::Binary) .set_signature_creation_time(std::time::SystemTime::now()).unwrap() .set_issuer_fingerprint(key.fingerprint()).unwrap() .set_issuer(key.fingerprint().into()).unwrap(); let sig3 = b.sign_message(&mut signer, msg).unwrap(); let mut fd = File::create("revoked-key-sig-t3-now.pgp").unwrap(); Packet::from(sig3).serialize(&mut fd).unwrap(); // 3rd message sig between t3 and now, subkey b = signature::Builder::new(SignatureType::Binary) .set_signature_creation_time(std::time::SystemTime::now()).unwrap() .set_issuer_fingerprint(subkey.fingerprint()).unwrap() .set_issuer(subkey.fingerprint().into()).unwrap(); let sig3 = b.sign_message(&mut sk_signer, msg).unwrap(); let mut fd = File::create("revoked-key-sig-t3-now.sk.pgp").unwrap(); Packet::from(sig3).serialize(&mut fd).unwrap(); } sequoia-sqv-0.14.0/tests/wrong-key-flags.rs010064400017500001750000000037721361731103000170220ustar0000000000000000extern crate assert_cli; #[cfg(test)] mod integration { use assert_cli::Assert; use std::path; #[test] fn not_for_signing_subkey() { Assert::cargo_binary("sqv") .current_dir(path::Path::new("tests").join("data")) .with_args( &["--keyring", &"no-signing-caps.key", &"no-signing-caps.sig", &"msg.txt"]) .fails() .unwrap(); } } // Code to create the data for the test cases above // extern crate sequoia_openpgp; // // #[test] // fn create_key() { // use std::fs::File; // use sequoia_openpgp::{ // cert::CertBuilder, // packet::{ // signature, // key::SecretKey, // }, // crypto::KeyPair, // serialize::Serialize, // types::{ // SignatureType, // HashAlgorithm, // } // }; // // let (cert, _) = CertBuilder::default() // .add_userid("Testy Mc Test") // .add_transport_encryption_subkey() // .generate().unwrap(); // let subkey = cert.subkeys().next().unwrap(); // let key = subkey.subkey(); // let sig = { // let mpis = match key.secret() { // Some(SecretKey::Unencrypted{ ref mpis }) => mpis, // _ => unreachable!(), // }; // let mut b = signature::Builder::new(SignatureType::Binary); // b.set_signature_creation_time(time::now()).unwrap(); // b.set_issuer_fingerprint(key.fingerprint()).unwrap(); // b.set_issuer(key.fingerprint().into()).unwrap(); // b.sign_message( // &mut KeyPair::new(key.clone(), mpis.clone()).unwrap(), // HashAlgorithm::SHA512, b"Hello, World").unwrap() // }; // // { // let mut fd = File::create("key").unwrap(); // cert.serialize(&mut fd).unwrap(); // } // // { // let mut fd = File::create("sig").unwrap(); // sig.serialize(&mut fd).unwrap(); // } // } sequoia-sqv-0.14.0/.cargo_vcs_info.json0000644000000001120000000000000134240ustar00{ "git": { "sha1": "d98c6ca4a75fa707728d3544ad58093db4ebbaba" } }