Skip to main content

rpm_sequoia/
lib.rs

1//! An implementation of RPM's OpenPGP interface.
2//!
3//! This library provides an implementation of [RPM's OpenPGP
4//! interface](https://github.com/rpm-software-management/rpm/blob/master/include/rpm/rpmpgp.h).
5//!
6//! **You should not link to this library directly**.
7//!
8//! If you are looking for an OpenPGP interface, consider using
9//! [Sequoia], which this library is based on.  If you want to use
10//! RPM's OpenPGP interface, which you should only do if you are
11//! interacting with RPM, then you should link against [RPM], which
12//! reexports this interface.
13//!
14//! [Sequoia]: https://gitlab.com/sequoia-pgp/sequoia
15//! [RPM]: http://rpm.org
16//!
17//! If you are investigating a bug in this library, set the
18//! `RPM_TRACE` environment variable to 1 to get a verbose trace of
19//! the library's execution:
20//!
21//! ```sh
22//! $ LD_LIBRARY_PATH=/tmp/rpm-sequoia/release RPM_TRACE=1 ./rpmkeys \
23//!   --import ../tests/data/keys/CVE-2021-3521-badbind.asc
24//! _rpmInitCrypto: entered
25//! _rpmInitCrypto: -> success
26//! _pgpParsePkts: entered
27//! ...
28//! ```
29//!
30//! # Policy
31//!
32//! When Sequoia evaluates the validity of an object (e.g., a
33//! cryptographic signature) it consults a policy.  The policy is user
34//! defined.  This library uses [Sequoia's standard policy].
35//!
36//! [Sequoia's standard policy]: https://docs.sequoia-pgp.org/sequoia_openpgp/policy/struct.StandardPolicy.html
37//!
38//! Sequoia's standard policy allows self-signatures (i.e., the
39//! signatures that bind a User ID or subkey to a certificate) made
40//! with SHA-1 until February 2023.  It completely disallows data
41//! signatures made with SHA-1.  The reason for this is that SHA-1
42//! collision resistance is broken, but its second pre-image
43//! resistance is still okay.
44//!
45//! As an added protection, Sequoia uses [SHA-1 collision detection],
46//! which is a variant of SHA-1, which mitigates known attacks against
47//! SHA-1.  SHA-1 CD has a very low [false positive rate] (2^-90) so
48//! it can be treated as a drop-in, fully compatible replacement for
49//! SHA-1.
50//!
51//! [SHA-1 collision detection]: https://github.com/cr-marcstevens/sha1collisiondetection
52//! [false positive rate]: https://github.com/cr-marcstevens/sha1collisiondetection#about
53//!
54//! # Configuration File
55//!
56//! This library reads the [crypto policy configuration] in
57//! `/etc/crypto-policies/back-ends/sequoia.config`.  If that file
58//! doesn't exist, it tries
59//! `/usr/share/crypto-policies/back-ends/rpm-sequoia.config`.  This
60//! can be overridden using the `SEQUOIA_CRYPTO_POLICY` environment
61//! variable.  If set to the empty string, then no crypto policy will
62//! be read and instead [Sequoia's default policy] will be used.
63//!
64//! Refer to the [Fedora Crypto Policy] project for information about
65//! the crypto policy.
66//!
67//! [crypto policy configuration]: https://docs.rs/sequoia-policy-config/latest/sequoia_policy_config/
68//! [Sequoia's default policy]: https://docs.sequoia-pgp.org/sequoia_openpgp/policy/struct.StandardPolicy.html
69//! [Fedora Crypto Policy]: https://gitlab.com/redhat-crypto/fedora-crypto-policies/
70use std::env;
71use std::ffi::{
72    CString,
73};
74use std::fmt::Debug;
75use std::io::Read;
76use std::io::Write;
77use std::path::PathBuf;
78use std::sync::RwLock;
79use std::time::{
80    Duration,
81    SystemTime,
82    UNIX_EPOCH,
83};
84
85#[allow(unused_imports)]
86use anyhow::Context;
87
88use libc::{
89    c_char,
90    c_int,
91    c_uint,
92    c_void,
93    size_t,
94};
95
96use chrono::{
97    DateTime,
98    Utc,
99};
100
101use sequoia_openpgp as openpgp;
102use openpgp::armor;
103use openpgp::Cert;
104use openpgp::cert::prelude::*;
105use openpgp::Fingerprint;
106use openpgp::KeyID;
107use openpgp::packet::key::{
108    PublicParts,
109};
110use openpgp::packet::{
111    Packet,
112    Signature,
113    Tag,
114};
115use openpgp::parse::{
116    PacketParser,
117    PacketParserResult,
118    PacketParserBuilder,
119    Dearmor,
120};
121use openpgp::parse::Parse;
122use openpgp::policy::{
123    NullPolicy,
124    StandardPolicy,
125    Policy,
126};
127use openpgp::serialize::SerializeInto;
128use openpgp::types::RevocationStatus;
129
130use openpgp::parse::buffered_reader;
131
132#[macro_use] mod log;
133#[macro_use] mod ffi;
134#[macro_use] pub mod rpm;
135use rpm::{
136    Error,
137    ErrorCode,
138    PgpArmor,
139    PgpArmorError,
140    Result,
141};
142pub mod digest;
143
144lazy_static::lazy_static! {
145    static ref P: RwLock<StandardPolicy<'static>> = RwLock::new(StandardPolicy::new());
146}
147const NP: &NullPolicy = unsafe {
148    &NullPolicy::new()
149};
150
151// Set according to the RPM_TRACE environment variable (enabled if
152// non-zero), or if we are built in debug mode.
153lazy_static::lazy_static! {
154    static ref TRACE: bool = {
155        if let Ok(v) = env::var("RPM_TRACE") {
156            let v: isize = v.parse().unwrap_or(1);
157            v != 0
158        } else {
159            false
160        }
161    };
162}
163
164/// Prints the error and causes, if any.
165pub fn print_error_chain(err: &anyhow::Error) {
166    eprintln!("           {}", err);
167    err.chain().skip(1).for_each(|cause| eprintln!("  because: {}", cause));
168}
169
170// Sometimes the same error cascades, e.g.:
171//
172// ```
173// $ sq-wot --time 20230110T0406   --keyring sha1.pgp path B5FA089BA76FE3E17DC11660960E53286738F94C 231BC4AB9D8CAB86D1622CE02C0CE554998EECDB FABA8485B2D4D5BF1582AA963A8115E774FA9852 "<carol@example.org>"
174// [ ] FABA8485B2D4D5BF1582AA963A8115E774FA9852 <carol@example.org>: not authenticated (0%)
175//   ◯ B5FA089BA76FE3E17DC11660960E53286738F94C ("<alice@example.org>")
176//   │   No adequate certification found.
177//   │   No binding signature at time 2023-01-10T04:06:00Z
178//   │     No binding signature at time 2023-01-10T04:06:00Z
179//   │     No binding signature at time 2023-01-10T04:06:00Z
180// ...
181// ```
182//
183// Although technically correct, it's just noise.  Compress them.
184fn error_chain(err: &anyhow::Error) -> Vec<String> {
185    let mut errs = std::iter::once(err.to_string())
186        .chain(err.chain().map(|source| source.to_string()))
187        .collect::<Vec<String>>();
188    errs.dedup();
189    errs
190}
191
192// Generate macros for working with lints.
193//
194// Note: $dollar is a hack, which we use because nested macros with
195// repetitions don't currently work.  See:
196// https://github.com/rust-lang/rust/pull/95860
197macro_rules! linter {
198    ($dollar:tt, $lints:ident) => {
199        // A helper macro to add a lint.
200        //
201        // If `$err` is `None`, `$msg` is turned into an `anyhow::Error` and
202        // appended to `lints`.
203        //
204        // If `$err` is `Some`, `$msg` is added as context to `$err` and is
205        // then appended to `lints`.
206        macro_rules! add_lint {
207            ($err:expr, $msg:expr $dollar(, $args:expr)*) => {{
208                let err: Option<anyhow::Error> = $err;
209                let msg = format!("{}", format_args!($msg $dollar(, $args)*));
210                let err = if let Some(err) = err {
211                    err.context(msg)
212                } else {
213                    anyhow::anyhow!(msg)
214                };
215                $lints.push(err);
216            }};
217        }
218
219        // A helper to return an error.
220        //
221        // This adds a lint using `lint!` and then returns
222        // `Error::Fail($msg)`.
223        macro_rules! return_err {
224            ($err:expr, $msg:expr $dollar(, $args:expr)*) => {{
225                add_lint!($err, $msg $dollar(, $args)*);
226                return Err(Error::Fail(
227                    format!("{}", format_args!($msg $dollar(, $args)*))));
228            }};
229        }
230    }
231}
232
233// By default we prefer this environment variable and this file, but
234// if that is not present, we fallback to the default configuration.
235const RPM_SEQUOIA_CONFIG_ENV: &'static str
236    = "RPM_SEQUOIA_CRYPTO_POLICY";
237const RPM_SEQUOIA_CONFIG: &[&str] = &[
238    "/etc/crypto-policies/back-ends/rpm-sequoia.config",
239    "/usr/share/crypto-policies/back-ends/rpm-sequoia.config",
240];
241
242ffi!(
243/// int rpmInitCrypto(void)
244fn _rpmInitCrypto() -> Binary {
245    // XXX: Remove this once v4 signatures are ubiquitous.
246    //
247    // Unfortunately, much of the rpm ecosystem is still (2022)
248    // generating v3 signatures.  As they aren't completely broken,
249    // accept them by default, but still let them be overridden by the
250    // system policy.
251    //
252    // See https://bugzilla.redhat.com/show_bug.cgi?id=2141686
253    let mut p = openpgp::policy::StandardPolicy::new();
254    p.accept_packet_tag_version(openpgp::packet::Tag::Signature, 3);
255
256    let mut p = sequoia_policy_config::ConfiguredStandardPolicy
257        ::from_policy(p);
258
259    // We can only specify a single file to
260    // `ConfiguredStandardPolicy::parse_config_file`.  We work around
261    // it (for now) by taking the first file that exists.
262    let rpm_sequoia_config = RPM_SEQUOIA_CONFIG
263	.iter()
264	.find(|path| {
265	    PathBuf::from(path).exists()
266	})
267	.unwrap_or(&RPM_SEQUOIA_CONFIG[0]);
268
269    match p.parse_config(RPM_SEQUOIA_CONFIG_ENV,
270                         rpm_sequoia_config)
271    {
272        Ok(false) => {
273            // Fallback to the default configuration.
274            if let Err(err) = p.parse_default_config() {
275                print_error_chain(&err);
276                return Err(err.into());
277            }
278        }
279        Ok(true) => (),
280        Err(err) => {
281            print_error_chain(&err);
282            return Err(err.into());
283        }
284    }
285
286    *crate::P.write().unwrap() = p.build();
287
288    Ok(())
289});
290
291ffi!(
292/// int rpmFreeCrypto(void)
293fn _rpmFreeCrypto() -> Binary {
294    Ok(())
295});
296
297// These are still implemented in C due to internationalization, and
298// to avoid translating the string tables, which is a fair amount of
299// error prone work, and doesn't improve safety.
300//
301// stub!(pgpValString);
302// stub!(pgpIdentItem);
303
304// This is implemented in C: it is just a wrapper around pgpParsePkts,
305// which uses some internal rpm functions.
306//
307// stub!(pgpReadPkts);
308
309/// An OpenPGP object.
310///
311/// This data structure can hold either a signature, a certificate, or
312/// a subkey.
313enum PgpDigParamsObj {
314    Cert(Cert),
315    Subkey(Cert, Fingerprint),
316    Signature(Signature),
317}
318
319pub struct PgpDigParams {
320    obj: PgpDigParamsObj,
321    signid: [u8; 8],
322    userid: Option<CString>,
323}
324
325impl PgpDigParams {
326    fn cert(&self) -> Option<&Cert> {
327        match &self.obj {
328            PgpDigParamsObj::Cert(cert) => Some(cert),
329            PgpDigParamsObj::Subkey(cert, _) => Some(cert),
330            PgpDigParamsObj::Signature(_) => None,
331        }
332    }
333
334    fn key(&self) -> Option<ErasedKeyAmalgamation<PublicParts>> {
335        match &self.obj {
336            PgpDigParamsObj::Cert(cert) => {
337                Some(cert.primary_key().into())
338            }
339            PgpDigParamsObj::Subkey(cert, fpr) => {
340                Some(cert.keys().subkeys()
341                     .key_handle(fpr)
342                     .next()
343                     .expect("subkey missing")
344                     .into())
345            }
346            PgpDigParamsObj::Signature(_) => None,
347        }
348    }
349
350    fn signature(&self) -> Option<&Signature> {
351        match &self.obj {
352            PgpDigParamsObj::Cert(_) => None,
353            PgpDigParamsObj::Subkey(_, _) => None,
354            PgpDigParamsObj::Signature(sig) => Some(sig),
355        }
356    }
357}
358
359ffi!(
360/// Returns the signature's type.
361///
362/// If `dig` is NULL or does not contain a signature, then this
363/// function returns -1.
364fn _pgpSignatureType(dig: *const PgpDigParams) -> c_int[-1] {
365    let dig = check_ptr!(dig);
366
367    dig.signature()
368        .ok_or_else(|| Error::Fail("Not a signature".into()))
369        .map(|sig| {
370            u8::from(sig.typ()).into()
371        })
372});
373
374ffi!(
375/// Frees the parameters.
376fn _pgpDigParamsFree(dig: Option<&mut PgpDigParams>) {
377    free!(dig);
378});
379
380ffi!(
381/// "Compares" the two parameters and returns 1 if they differ and 0 if
382/// they match.
383///
384/// Two signatures are considered the same if they have the same
385/// parameters (version, signature type, public key and hash
386/// algorithms, and the first issuer packet).  Note: this function
387/// explicitly does not check that the MPIs are the same, nor that the
388/// signature creation time is the same!  This is intended.  The only
389/// use of this function in the rpm code base is to check whether a key
390/// has already made a signature (cf. sign/rpmgensig.c:haveSignature).
391///
392/// Two certificates are considered the same if they have the same
393/// fingerprint.  (rpm does not currently use this functionality.)
394///
395/// Two subkeys are considered the same if they have the same
396/// fingerprint.  (rpm does not currently use this functionality.)
397fn _pgpDigParamsCmp(p1: *const PgpDigParams,
398                    p2: *const PgpDigParams)
399     -> c_int[1]
400{
401    let p1 = check_ptr!(p1);
402    let p2 = check_ptr!(p2);
403
404    let r = match (&p1.obj, &p2.obj) {
405        (PgpDigParamsObj::Cert(c1), PgpDigParamsObj::Cert(c2)) => {
406            c1.fingerprint() == c2.fingerprint()
407        }
408        (PgpDigParamsObj::Subkey(_, f1), PgpDigParamsObj::Subkey(_, f2)) => {
409            f1 == f2
410        }
411        (PgpDigParamsObj::Signature(s1), PgpDigParamsObj::Signature(s2)) => {
412            t!("s1: {:?}", s1);
413            t!("s2: {:?}", s2);
414            s1.hash_algo() == s2.hash_algo()
415                && s1.pk_algo() == s2.pk_algo()
416                && s1.version() == s2.version()
417                && s1.typ() == s2.typ()
418                && p1.signid == p2.signid
419        }
420        _ => {
421            false
422        }
423    };
424
425    Ok(if r { 0 } else { 1 })
426});
427
428const PGPVAL_PUBKEYALGO: c_uint = 6;
429const PGPVAL_HASHALGO: c_uint = 9;
430
431ffi!(
432/// Returns the object's public key or algorithm algorithm.
433///
434/// `algotype` is either `PGPVAL_PUBKEYALGO` or `PGPVAL_HASHALGO`.
435/// Other algo types are not support and cause this function to return
436/// 0.
437fn _pgpDigParamsAlgo(dig: *const PgpDigParams,
438                     algotype: c_uint) -> c_uint[0]
439{
440    let dig = check_ptr!(dig);
441
442    match (algotype, &dig.obj) {
443        // pubkey algo.
444        (PGPVAL_PUBKEYALGO, PgpDigParamsObj::Cert(cert)) => {
445            Ok(u8::from(cert.primary_key().key().pk_algo()).into())
446        }
447        (PGPVAL_PUBKEYALGO, PgpDigParamsObj::Subkey(_, _)) => {
448            Ok(u8::from(dig.key().expect("valid").key().pk_algo()).into())
449        }
450        (PGPVAL_PUBKEYALGO, PgpDigParamsObj::Signature(sig)) => {
451            Ok(u8::from(sig.pk_algo()).into())
452        }
453
454        // hash algo.
455        (PGPVAL_HASHALGO, PgpDigParamsObj::Cert(cert)) => {
456            match cert.with_policy(&*P.read().unwrap(), None) {
457                Ok(vc) => {
458                    let algo = vc.primary_key().binding_signature().hash_algo();
459                    Ok(u8::from(algo).into())
460                }
461                Err(err) => {
462                    Err(Error::Fail(
463                        format!("Using {}: {}", cert.fingerprint(), err)))
464                }
465            }
466        }
467        (PGPVAL_HASHALGO, PgpDigParamsObj::Subkey(_, fpr)) => {
468            let ka = dig.key().expect("valid");
469            match ka.with_policy(&*P.read().unwrap(), None) {
470                Ok(ka) => {
471                    let algo = ka.binding_signature().hash_algo();
472                    Ok(u8::from(algo).into())
473                }
474                Err(err) => {
475                    Err(Error::Fail(
476                        format!("Using {}: {}", fpr, err)))
477                }
478            }
479        }
480        (PGPVAL_HASHALGO, PgpDigParamsObj::Signature(sig)) => {
481            Ok(u8::from(sig.hash_algo()).into())
482        }
483
484        // Unknown algo.
485        (t, PgpDigParamsObj::Cert(_))
486        | (t, PgpDigParamsObj::Subkey(_, _))
487        | (t, PgpDigParamsObj::Signature(_)) => {
488            Err(Error::Fail(format!("Invalid algorithm type: {}", t)))
489        }
490    }
491});
492
493ffi!(
494/// Returns the issuer or the Key ID.
495///
496/// If `dig` is a signature, then this returns the Key ID stored in the
497/// first Issuer or Issuer Fingerprint subpacket as a hex string.
498/// (This is not authenticated!)
499///
500/// If `dig` is a certificate or a subkey, then this returns the key's
501/// Key ID.
502///
503/// The caller must *not* free the returned buffer.
504fn _pgpDigParamsSignID(dig: *const PgpDigParams) -> *const u8 {
505    let dig = check_ptr!(dig);
506    t!("SignID: {}",
507       dig.signid.iter().map(|v| format!("{:02X}", v)).collect::<String>());
508    Ok(dig.signid.as_ptr())
509});
510
511ffi!(
512/// Returns the primary User ID, if any.
513///
514/// If `dig` is a signature, then this returns `NULL`.
515///
516/// If `dig` is a certificate or a subkey, then this returns the
517/// certificate's primary User ID, if any.
518///
519/// This interface does not provide a way for the caller to recognize
520/// any embedded `NUL` characters.
521///
522/// The caller must *not* free the returned buffer.
523fn _pgpDigParamsUserID(dig: *const PgpDigParams) -> *const c_char {
524    let dig = check_ptr!(dig);
525    if let Some(ref userid) = dig.userid {
526        Ok(userid.as_ptr())
527    } else {
528        Ok(std::ptr::null())
529    }
530});
531
532ffi!(
533/// Returns the object's version.
534///
535/// If `dig` is a signature, then this returns the version of the
536/// signature packet.
537///
538/// If `dig` is a certificate, then this returns the version of the
539/// primary key packet.
540///
541/// If `dig` is a subkey, then this returns the version of the subkey's
542/// key packet.
543fn _pgpDigParamsVersion(dig: *const PgpDigParams) -> c_int[0] {
544    let dig = check_ptr!(dig);
545    let version = match &dig.obj {
546        PgpDigParamsObj::Cert(cert) => {
547            cert.primary_key().key().version()
548        }
549        PgpDigParamsObj::Subkey(_, _) => {
550            dig.key().unwrap().key().version()
551        }
552        PgpDigParamsObj::Signature(sig) => {
553            sig.version()
554        }
555    };
556    Ok(version as c_int)
557});
558
559ffi!(
560/// Returns the object's time.
561///
562/// If `dig` is a signature, then this returns the signature's creation
563/// time.
564///
565/// If `dig` is a certificate, then this returns the primary key's key
566/// creation time.
567///
568/// If `dig` is a subkey, then this returns the subkey's key creation
569/// time.
570fn _pgpDigParamsCreationTime(dig: *const PgpDigParams) -> u32[0] {
571    let dig = check_ptr!(dig);
572    let t = match &dig.obj {
573        PgpDigParamsObj::Cert(cert) => {
574            cert.primary_key().key().creation_time()
575        }
576        PgpDigParamsObj::Subkey(cert, fpr) => {
577            cert.keys().subkeys()
578                .key_handle(fpr)
579                .next()
580                .expect("subkey missing")
581                .key()
582                .creation_time()
583        }
584        PgpDigParamsObj::Signature(sig) => {
585            sig.signature_creation_time().unwrap_or(UNIX_EPOCH)
586        }
587    };
588    Ok(t.duration_since(UNIX_EPOCH)
589       .map_err(|_| Error::Fail("time".into()))?
590       .as_secs() as u32)
591});
592
593ffi!(
594/// Returns a signature's salt.
595///
596/// Version 6 signatures are salted.  The salt needs to be fed into
597/// the digest buffer before the actual message, which is processed
598/// already by RPM.
599///
600/// The caller must *not* free the returned buffer.
601///
602/// Returns an error if the signature does not include a salt.
603/// Version 6 signatures always have a salt; version 3 and version 4
604/// signatures never have a salt and thus will always return an error.
605fn _pgpDigParamsSalt(dig: *const PgpDigParams,
606                     datap: *mut *const u8,
607                     lenp: *mut size_t)
608    -> ErrorCode
609{
610    let dig = check_ptr!(dig);
611    let datap = check_mut!(datap);
612    let lenp = check_mut!(lenp);
613
614    let sig = dig.signature().ok_or_else(|| {
615        Error::Fail("dig parameter does not designate a signature".into())
616    })?;
617
618    if let Some(salt) = sig.salt() {
619        t!("Salt: {}",
620           salt.iter().map(|v| format!("{:02X}", v)).collect::<String>());
621        *lenp = salt.len() as size_t;
622        *datap = salt.as_ptr();
623        Ok(())
624    } else {
625        Err(Error::Fail("The provided signature does not have any salt".into()))
626    }
627});
628
629
630ffi!(
631/// Verifies the signature.
632///
633/// If `key` is `NULL`, then this computes the hash and checks it
634/// against the hash prefix.
635///
636/// If `key` is not `NULL`, then this checks that the signature is
637/// correct.
638///
639/// This function does not modify `ctx`.  Instead, it first duplicates
640/// `ctx` and then hashes the the meta-data into that context.
641///
642/// This function fails if the signature is not valid, or a supplied
643/// key is not valid.
644///
645/// A signature is valid if:
646///
647///   - The signature is alive now (not created in the future, and not
648///     yet expired)
649///
650///   - It is accepted by the [policy].
651///
652/// A key is valid if as of the *signature's* creation time if:
653///
654///   - The certificate is valid according to the [policy].
655///
656///   - The certificate is alive
657///
658///   - The certificate is not revoke
659///
660///   - The key is alive
661///
662///   - The key is not revoke
663///
664///   - The key has the signing capability set.
665///
666/// [policy]: index.html#policy
667fn _pgpVerifySignature(key: *const PgpDigParams,
668                       sig: *const PgpDigParams,
669                       ctx: *const digest::DigestContext) -> ErrorCode {
670    match _pgpVerifySignature2(key, sig, ctx, std::ptr::null_mut()) {
671        0 => Ok(()),
672        ec => Err(Error::from(ec)),
673    }
674});
675
676ffi!(
677/// Like _pgpVerifySignature, but returns error messages and lints in
678/// `lint_str`.
679fn _pgpVerifySignature2(key: *const PgpDigParams,
680                        sig: *const PgpDigParams,
681                        ctx: *const digest::DigestContext,
682                        lint_str: *mut *mut c_char) -> ErrorCode {
683    let key: Option<&PgpDigParams> = check_optional_ptr!(key);
684    let sig: &PgpDigParams = check_ptr!(sig);
685    // This function MUST NOT free or even change ctx.
686    let mut ctx = check_ptr!(ctx).clone();
687    let mut lint_str: Option<&mut _> = check_optional_mut!(lint_str);
688
689    if let Some(lint_str) = lint_str.as_mut() {
690        **lint_str = std::ptr::null_mut();
691    }
692
693    let mut lints = Vec::new();
694    let r = pgp_verify_signature(key, sig, ctx, &mut lints);
695
696    // Return any lint / error messages.
697    if lints.len() > 0 {
698        let mut s: String = if let Some(key) = key {
699            format!(
700                "Verifying a signature using certificate {} ({}):",
701                key.cert()
702                    .map(|cert| cert.fingerprint().to_string())
703                    .unwrap_or_else(|| "<invalid certificate>".to_string()),
704                key.cert()
705                    .and_then(|cert| {
706                        cert.userids().next()
707                            .map(|userid| {
708                                String::from_utf8_lossy(userid.userid().value()).into_owned()
709                            })
710                    })
711                    .unwrap_or_else(|| {
712                        "<unknown>".into()
713                    }))
714        } else {
715            format!(
716                "Verifying a signature, but no certificate was \
717                 provided:")
718        };
719
720        // Indent the lints.
721        let sep = "\n  ";
722
723        let lints_count = lints.len();
724        for (err_i, err) in lints.into_iter().enumerate() {
725            for (cause_i, cause) in error_chain(&err).into_iter().enumerate() {
726                if cause_i == 0 {
727                    s.push_str(sep);
728                    if lints_count > 1 {
729                        s.push_str(&format!("{}. ", err_i + 1));
730                    }
731                } else {
732                    s.push_str(sep);
733                    s.push_str("    because: ");
734                }
735                s.push_str(&cause);
736            }
737        }
738
739        t!("Lints: {}", s);
740
741        if let Some(lint_str) = lint_str.as_mut() {
742            // Add a trailing NUL.
743            s.push('\0');
744
745            **lint_str = s.as_mut_ptr() as *mut c_char;
746            // Pass ownership to the caller.
747            std::mem::forget(s);
748        }
749    }
750
751    r
752});
753
754// Verifies the signature.
755//
756// Lints are appended to `lints`.  Note: multiple lints may be added.
757fn pgp_verify_signature(key: Option<&PgpDigParams>,
758                        sig: &PgpDigParams,
759                        mut ctx: digest::DigestContext,
760                        lints: &mut Vec<anyhow::Error>)
761    -> Result<()>
762{
763    tracer!(*crate::TRACE, "pgp_verify_signature");
764
765    linter!($, lints);
766
767    // Whether the verification relies on legacy cryptography.
768    let mut legacy = false;
769
770    let sig = sig.signature().ok_or_else(|| {
771        Error::Fail("sig parameter does not designate a signature".into())
772    })?;
773
774    let sig_id = || {
775        let digest_prefix = sig.digest_prefix();
776        format!("{:02x}{:02x} created at {}",
777                digest_prefix[0],
778                digest_prefix[1],
779                if let Some(t) = sig.signature_creation_time() {
780                    DateTime::<Utc>::from(t)
781                        .format("%c").to_string()
782                } else {
783                    "<unknown>".to_string()
784                })
785    };
786
787    let sig_time = if let Some(t) = sig.signature_creation_time() {
788        t
789    } else {
790        return_err!(
791            None,
792            "Signature {} invalid: signature missing a creation time",
793            sig_id());
794    };
795
796    // Allow some clock skew.
797    if let Err(err) = sig.signature_alive(None,  Duration::new(5 * 60, 0)) {
798        return_err!(
799            Some(err),
800            "Signature {} invalid: signature is not alive",
801            sig_id());
802    }
803
804    {
805        let policy = P.read().unwrap();
806        if let Err(err) = policy.signature(sig, Default::default()) {
807            if NP.signature(sig, Default::default()).is_ok() {
808                legacy = true;
809                add_lint!(
810                    Some(err),
811                    "Signature {} invalid: signature relies on legacy cryptography",
812                    sig_id());
813            } else {
814                return_err!(
815                    Some(err),
816                    "Signature {} invalid: policy violation", sig_id());
817            }
818        }
819        // XXX: As of sequoia-openpgp v1.11.0, this check is not done
820        // by `policy.signature` (see issue #953).  We do it manually,
821        // but once rpm-sequoia depends on a newer version of
822        // sequoia-openpgp that does this, remove this code.
823        if let Err(err) = policy.packet(&Packet::from(sig.clone())) {
824            if NP.packet(&Packet::from(sig.clone())).is_ok() {
825                legacy = true;
826                add_lint!(
827                    Some(err),
828                    "Signature {} invalid: signature relies on legacy cryptography",
829                    sig_id());
830            } else {
831                return_err!(
832                    Some(err),
833                    "Signature {} invalid: policy violation", sig_id());
834            }
835        }
836    }
837
838    // XXX: rpm only cares about the first issuer
839    // subpacket.
840    let issuer = match sig.get_issuers().into_iter().next() {
841        Some(issuer) => issuer,
842        None => return_err!(
843            None,
844            "Signature {} invalid: signature has no issuer subpacket",
845            sig_id()),
846    };
847
848    if let Some(key) = key {
849        // Actually verify the signature.
850        let cert = key.cert().ok_or_else(|| {
851            Error::Fail("key parameter is not a cert".into())
852        })?;
853        let subkey = key.key().expect("is a certificate").key().fingerprint();
854
855        t!("Checking signature {} using {} with {} / {}",
856           sig_id(), sig.hash_algo(),
857           cert.fingerprint(), subkey);
858
859        // We evaluate the certificate as of the signature creation
860        // time.
861        let p = &*P.read().unwrap();
862        let vc = cert.with_policy(p, sig_time)
863            .or_else(|err| {
864                // Try again, but use the current time as a reference
865                // time.  It is quite common for old self-signatures
866                // to be stripped.
867                match cert.with_policy(p, None) {
868                    Ok(vc) => {
869                        // We'd really like to emit the following
870                        // lint, but for most users it is not
871                        // actionable.  When the ecosystem changes so
872                        // that certificates include older self
873                        // signatures, enable it again.
874
875                        // add_lint!(
876                        //     None,
877                        //     "Certificate has no valid binding signature \
878                        //      as of the signature's creation time, but \
879                        //      is valid now.  The certificate has probably \
880                        //      been stripped or minimized.");
881                        Ok(vc)
882                    }
883                    Err(err2) => {
884                        add_lint!(
885                            Some(err),
886                            "Certificate {} invalid: policy violation",
887                            cert.keyid());
888                        Err(err2)
889                    }
890                }
891            })
892            .or_else(|err| {
893                legacy = true;
894                add_lint!(
895                    Some(err),
896                    "Certificate {} invalid: policy violation",
897                    cert.keyid());
898                cert.with_policy(NP, sig_time)
899            })?;
900
901        if let Err(err) = vc.alive() {
902            legacy = true;
903            add_lint!(
904                Some(err),
905                "Certificate {} invalid: certificate is not alive",
906                vc.keyid());
907        }
908        if let RevocationStatus::Revoked(_) = vc.revocation_status() {
909            legacy = true;
910            add_lint!(
911                None,
912                "Certificate {} invalid: certificate is revoked",
913                vc.keyid());
914        }
915
916        // Find the key.
917        match vc.keys().key_handle(issuer.clone()).next() {
918            Some(ka) => {
919                if ka.key().fingerprint() != subkey {
920                    return_err!(None,
921                                "Key {} invalid: wrong subkey ({})",
922                                ka.key().keyid(), subkey);
923                }
924                if ! ka.for_signing() {
925                    return_err!(None,
926                                "Key {} invalid: not signing capable",
927                                ka.key().keyid());
928                }
929                if let Err(err) = ka.alive() {
930                    legacy = true;
931                    add_lint!(Some(err),
932                              "Key {} invalid: key is not alive",
933                              ka.key().keyid());
934                }
935                if let RevocationStatus::Revoked(_) = ka.revocation_status() {
936                    legacy = true;
937                    add_lint!(None,
938                              "Key {} is invalid: key is revoked",
939                              ka.key().keyid());
940                }
941
942                // Finally we can verify the signature.
943                sig.clone().verify_hash(ka.key(), ctx.ctx.clone())?;
944                if legacy {
945                    return Err(Error::NotTrusted(
946                        "Verification relies on legacy crypto".into())
947                               .into());
948                } else {
949                    return Ok(());
950                }
951            }
952            None => {
953                return_err!(None,
954                            "Certificate {} does not contain key {} \
955                             or it is not valid",
956                            vc.keyid(), issuer);
957            }
958        }
959    } else {
960        // We don't have a key, but we still check that the prefix is
961        // correct.
962
963        // These traits should be imported only where needed to avoid
964        // bugs.
965        use openpgp::serialize::Marshal;
966        use openpgp::serialize::MarshalInto;
967
968        // See https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.4
969        let mut sig_data = Vec::with_capacity(128);
970
971        // Hash the signature into the context.
972        match sig.version() {
973            4 | 6 => {
974                sig_data.push(sig.version());
975                sig_data.push(sig.typ().into());
976                sig_data.push(sig.pk_algo().into());
977                sig_data.push(sig.hash_algo().into());
978
979                let l = sig.hashed_area().serialized_len();
980                if sig.version() == 6 {
981                    // The v6 signatures encode the hashed length as 4 bytes
982                    sig_data.push((l >> 24) as u8);
983                    sig_data.push((l >> 16) as u8);
984                }
985                sig_data.push((l >> 8) as u8);
986                sig_data.push((l >> 0) as u8);
987
988                sig.hashed_area().serialize(&mut sig_data).expect("vec");
989
990                let sig_len = sig_data.len();
991
992                // Trailer.
993                sig_data.push(sig.version());
994                sig_data.push(0xFF);
995                sig_data.push((sig_len >> 24) as u8);
996                sig_data.push((sig_len >> 16) as u8);
997                sig_data.push((sig_len >>  8) as u8);
998                sig_data.push((sig_len >>  0) as u8);
999            }
1000            3 => {
1001                sig_data.push(sig.typ().into());
1002                let ct = sig.signature_creation_time().unwrap_or(UNIX_EPOCH);
1003                let ct = ct.duration_since(UNIX_EPOCH)
1004                    .map_err(|_| Error::Fail("time".into()))?
1005                    .as_secs() as u32;
1006                sig_data.push((ct >> 24) as u8);
1007                sig_data.push((ct >> 16) as u8);
1008                sig_data.push((ct >>  8) as u8);
1009                sig_data.push((ct >>  0) as u8);
1010            }
1011            v => {
1012                return Err(Error::Fail(
1013                    format!("Unsupported signature version: {}", v)));
1014            }
1015        }
1016
1017        ctx.update(&sig_data);
1018
1019        let digest_size = ctx.digest_size();
1020        let mut digest: Vec<u8> = Vec::with_capacity(digest_size);
1021        for _ in 0..digest_size {
1022            digest.push(0);
1023        }
1024        ctx.digest(&mut digest[..])?;
1025
1026        let p = sig.digest_prefix();
1027        if p[0] != digest[0] || p[1] != digest[1] {
1028            return Err(Error::Fail("digest prefix mismatch".into()));
1029        } else {
1030            t!("digest prefix matches");
1031        }
1032
1033        if ! sig.pk_algo().is_supported() {
1034            return Err(Error::NotTrusted(
1035                format!("Signature relies on unknown or unsupported \
1036                         cryptographic algorithm {}",
1037                        sig.pk_algo())));
1038        } else if legacy {
1039            return Err(Error::NotTrusted(
1040                "Signature relies on legacy crypto".into())
1041                       .into());
1042        } else {
1043            return Err(Error::NoKey(
1044                format!("Not provided (issuer: {})", issuer).into()));
1045        }
1046    }
1047}
1048
1049ffi!(
1050/// Returns the Key ID of the public key or the secret key stored in
1051/// `pkt`.
1052///
1053/// Returns -1 if `pkt` is not a public key or secret key.
1054///
1055/// Note: this function does not handle public subkeys or secret
1056/// subkeys!
1057///
1058/// `keyid` must be allocated by the caller and points to at least 8
1059/// bytes of memory.
1060///
1061/// Returns 0 on success and -1 on failure.
1062fn _pgpPubkeyKeyID(pkt: *const u8, pktlen: size_t, keyid: *mut u8)
1063     -> Binary
1064{
1065    let pkt = check_slice!(pkt, pktlen);
1066
1067    let ppr = PacketParser::from_bytes(pkt)?;
1068    let k = if let PacketParserResult::Some(ref pp) = ppr {
1069        match &pp.packet {
1070            Packet::PublicKey(key) => Some(key.keyid()),
1071            Packet::SecretKey(key) => Some(key.keyid()),
1072            _ => None,
1073        }
1074    } else {
1075        None
1076    };
1077
1078    t!("Key ID: {}",
1079       k.as_ref()
1080           .map(|k| k.to_string())
1081           .unwrap_or_else(|| String::from("none")));
1082
1083    if let Some(k) = k {
1084        let buffer = check_mut_slice!(keyid, 8);
1085        buffer.copy_from_slice(k.as_bytes());
1086
1087        Ok(())
1088    } else {
1089        Err(Error::Fail("Not a key".into()))
1090    }
1091});
1092
1093ffi!(
1094/// Calculate OpenPGP public key fingerprint.
1095///
1096/// Returns -1 if `pkt` is not a public key or secret key.
1097///
1098/// Note: this function does not handle public subkeys or secret
1099/// subkeys!
1100///
1101/// `*fprout` is allocated using `malloc` and must be allocated by the
1102/// caller.
1103///
1104/// Returns 0 on success and -1 on failure.
1105fn _pgpPubkeyFingerprint(pkt: *const u8, pktlen: size_t,
1106                         fprout: *mut *mut u8, fprlen: *mut size_t)
1107     -> Binary
1108{
1109    let pkt = check_slice!(pkt, pktlen);
1110
1111    let ppr = PacketParserBuilder::from_bytes(pkt)?
1112        .dearmor(Dearmor::Disabled) // Disable dearmoring.
1113        .build()?;
1114    let fpr = if let PacketParserResult::Some(ref pp) = ppr {
1115        match &pp.packet {
1116            Packet::PublicKey(key) => Some(key.fingerprint()),
1117            Packet::SecretKey(key) => Some(key.fingerprint()),
1118            _ => None,
1119        }
1120    } else {
1121        None
1122    };
1123
1124    t!("Fingerprint: {}",
1125       fpr.as_ref()
1126           .map(|fpr| fpr.to_string())
1127           .unwrap_or_else(|| String::from("none")));
1128
1129    if let Some(fpr) = fpr {
1130        let fpr = fpr.as_bytes();
1131        unsafe {
1132            let buffer = libc::malloc(fpr.len());
1133            if buffer.is_null() {
1134                return Err(Error::Fail("out of memory".into()));
1135            }
1136            libc::memcpy(buffer, fpr.as_ptr() as *const c_void, fpr.len());
1137            *fprout = buffer as *mut u8;
1138            *fprlen = fpr.len();
1139        }
1140
1141        Ok(())
1142    } else {
1143        Err(Error::Fail("Not a key".into()))
1144    }
1145});
1146
1147ffi!(
1148/// Wraps the data in ASCII armor.
1149///
1150/// `atype` is the armor type.
1151///
1152/// The caller must free the returned buffer.
1153///
1154/// Returns `NULL` on failure.
1155fn _pgpArmorWrap(atype: c_int, s: *const c_char, ns: size_t)
1156     -> *mut c_char
1157{
1158    let atype = armor::Kind::try_from(PgpArmor::from(atype))?;
1159    let s = check_slice!(s, ns);
1160
1161    let mut writer = armor::Writer::new(Vec::new(), atype)
1162        .map_err(|err| Error::Fail(format!("creating armor writer: {}", err)))?;
1163    writer.write(s)
1164        .map_err(|err| Error::Fail(format!("writing armor body: {}", err)))?;
1165
1166    let mut buffer = writer.finalize()
1167        .map_err(|err| Error::Fail(format!("finalizing armor: {}", err)))?;
1168    // Add a trailing NUL.
1169    buffer.push(0);
1170
1171    let ptr = buffer.as_mut_ptr() as *mut c_char;
1172    std::mem::forget(buffer);
1173
1174    Ok(ptr)
1175});
1176
1177ffi!(
1178/// Returns the length of the certificate in bytes.
1179///
1180/// `pkts` points to a buffer.  Fails if `pkts` does not point to
1181/// exactly one valid OpenPGP certificate.
1182///
1183/// Returns 0 on failure.
1184fn _pgpPubKeyCertLen(pkts: *const u8, pktslen: size_t,
1185                     certlen: *mut size_t) -> Binary
1186{
1187    use openpgp::packet::Header;
1188    use openpgp::packet::header::PacketLengthType;
1189    use openpgp::packet::header::BodyLength;
1190    use openpgp::packet::header::CTB;
1191    use buffered_reader::BufferedReader;
1192
1193    let pkts = check_slice!(pkts, pktslen);
1194    let certlen = check_mut!(certlen);
1195
1196    // XXX: These functions are more or less copied from
1197    // sequoia/openpgp/src/parse.rs.  When sequoia-openpgp makes them
1198    // public, we drop this copy.
1199    fn body_length_parse_new_format<T, C>(bio: &mut T)
1200        -> openpgp::Result<BodyLength>
1201        where T: BufferedReader<C>, C: Debug + Send + Sync
1202    {
1203        let octet1 : u8 = bio.data_consume_hard(1)?[0];
1204        match octet1 {
1205            0..=191 => // One octet.
1206                Ok(BodyLength::Full(octet1 as u32)),
1207            192..=223 => { // Two octets length.
1208                let octet2 = bio.data_consume_hard(1)?[0];
1209                Ok(BodyLength::Full(((octet1 as u32 - 192) << 8)
1210                                    + octet2 as u32 + 192))
1211            },
1212            224..=254 => // Partial body length.
1213                Ok(BodyLength::Partial(1 << (octet1 & 0x1F))),
1214            255 => // Five octets.
1215                Ok(BodyLength::Full(bio.read_be_u32()?)),
1216        }
1217    }
1218
1219    /// Decodes an old format body length as described in [Section
1220    /// 4.2.1 of RFC 4880].
1221    ///
1222    ///   [Section 4.2.1 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-4.2.1
1223    fn body_length_parse_old_format<T, C>(bio: &mut T,
1224                                          length_type: PacketLengthType)
1225         -> openpgp::Result<BodyLength>
1226        where T: BufferedReader<C>, C: Debug + Send + Sync
1227    {
1228        match length_type {
1229            PacketLengthType::OneOctet =>
1230                Ok(BodyLength::Full(bio.data_consume_hard(1)?[0] as u32)),
1231            PacketLengthType::TwoOctets =>
1232                Ok(BodyLength::Full(bio.read_be_u16()? as u32)),
1233            PacketLengthType::FourOctets =>
1234                Ok(BodyLength::Full(bio.read_be_u32()? as u32)),
1235            PacketLengthType::Indeterminate =>
1236                Ok(BodyLength::Indeterminate),
1237        }
1238    }
1239
1240    fn parse_header<T, C>(bio: &mut T)
1241        -> openpgp::Result<Header>
1242        where T: BufferedReader<C>, C: Debug + Send + Sync
1243    {
1244        let ctb = CTB::try_from(bio.data_consume_hard(1)?[0])?;
1245        let length = match ctb {
1246            CTB::New(_) => body_length_parse_new_format(bio)?,
1247            CTB::Old(ref ctb) =>
1248                body_length_parse_old_format(bio, ctb.length_type())?,
1249        };
1250        return Ok(Header::new(ctb, length));
1251    }
1252
1253    let mut br = buffered_reader::Memory::new(pkts);
1254
1255    let mut found_cert = false;
1256    let len: Option<usize> = loop {
1257        // The start of this packet as a byte offset into buffer.
1258        let start_of_packet = br.total_out();
1259
1260        if start_of_packet == pkts.len() {
1261            // We're done.
1262            break Some(start_of_packet);
1263        }
1264
1265        let header = match parse_header(&mut br) {
1266            Ok(header) => header,
1267            Err(err) => {
1268                t!("Error reading certificate at offset {}: {}",
1269                   start_of_packet, err);
1270                break None;
1271            }
1272        };
1273
1274        use Tag::*;
1275        let t = header.ctb().tag();
1276        t!("Found a {:?} at offset {}, length: {:?}",
1277           t, start_of_packet, header.length());
1278        match t {
1279            // Start of a new certificate.
1280            PublicKey | SecretKey => {
1281                if found_cert {
1282                    break Some(start_of_packet);
1283                } else {
1284                    found_cert = true;
1285                }
1286            }
1287
1288            // The body of a certificate.
1289            PublicSubkey
1290            | SecretSubkey
1291            | UserID
1292            | UserAttribute
1293            | Signature
1294            | Marker
1295            | Trust
1296            | Unknown(_)
1297            | Private(_) => {
1298                if start_of_packet == 0 {
1299                    t!("Encountered a ({:?}) at offset {}, \
1300                        which is not a valid start of a certificate",
1301                       t, start_of_packet);
1302                    break None;
1303                }
1304            }
1305
1306            Reserved
1307            | PKESK
1308            | SKESK
1309            | OnePassSig
1310            | CompressedData
1311            | SED
1312            | Literal
1313            | SEIP
1314            | MDC
1315            | AED =>
1316            {
1317                t!("Encountered a ({:?}) at offset {}, \
1318                    which does not belong in a certificate",
1319                   t, start_of_packet);
1320                break None;
1321            }
1322
1323            t => if t.is_critical() {
1324                t!("Encountered a ({:?}) at offset {}, \
1325                    which does not belong in a certificate",
1326                   t, start_of_packet);
1327                break None;
1328            } else {
1329                // Ignore unknown non-critical packet.
1330            },
1331        }
1332
1333        // Advance to the next packet.
1334        match header.length() {
1335            BodyLength::Full(l) => {
1336                let l = *l as usize;
1337                if let Err(err) = br.data_consume_hard(l) {
1338                    t!("Error while reading packet: {}", err);
1339                    break None;
1340                }
1341            }
1342            BodyLength::Partial(_) => {
1343                t!("Packet {} has partial body length, \
1344                    which is unsupported by keyring splitter",
1345                   t);
1346                break None;
1347            }
1348            BodyLength::Indeterminate => {
1349                t!("Packet {} has intedeterminite length, \
1350                    which is unsupported by keyring splitter",
1351                   t);
1352                break None;
1353            }
1354        }
1355    };
1356
1357    if let Some(len) = len {
1358        *certlen = len;
1359        Ok(())
1360    } else {
1361        Err(Error::Fail("No certificate found".into()))
1362    }
1363});
1364
1365ffi!(
1366/// Parses OpenPGP data.
1367///
1368/// If `pkts` contains a signature and `pkttype` is 0 or
1369/// `Tag::Signature`, this returns a `PgpDigParams` containing a
1370/// signature.
1371///
1372/// If `pkts` contains a certificate and `pkttype` is 0,
1373/// `Tag::PublicKey`, or `Tag::SecretKey`, this returns a
1374/// `PgpDigParams` containing a certificate.  The certificate is
1375/// checked for validity in the sense that it only contains packets
1376/// that belong to a certificate; this function does **not** check the
1377/// binding signatures, etc.  That check is done when the key is used
1378/// in [_pgpVerifySignature].
1379///
1380/// Returns 0 on success, -1 on failure.
1381fn _pgpPrtParams(pkts: *const u8, pktlen: size_t,
1382                 pkttype: c_uint, paramsp: *mut *mut PgpDigParams)
1383    -> Binary
1384{
1385    match _pgpPrtParams2(pkts, pktlen, pkttype, paramsp, std::ptr::null_mut()) {
1386        0 => Ok(()),
1387        ec => Err(Error::from(ec)),
1388    }
1389});
1390
1391ffi!(
1392/// Like _pgpPrtParams, but returns error messages and lints in
1393/// `lint_str`.
1394fn _pgpPrtParams2(pkts: *const u8, pktlen: size_t,
1395                  pkttype: c_uint, paramsp: *mut *mut PgpDigParams,
1396                  lint_str: *mut *mut c_char)
1397    -> Binary
1398{
1399    let mut lint_str: Option<&mut _> = check_optional_mut!(lint_str);
1400
1401    if let Some(lint_str) = lint_str.as_mut() {
1402        **lint_str = std::ptr::null_mut();
1403    }
1404
1405    let mut lints = Vec::new();
1406    let r = pgp_prt_params(pkts, pktlen, pkttype, paramsp, &mut lints);
1407
1408    // Return any lint / error messages.
1409    if lints.len() > 0 {
1410        let mut s: String = format!("Parsing an OpenPGP packet:");
1411
1412        // Indent the lints.
1413        let sep = "\n  ";
1414
1415        let lints_count = lints.len();
1416        for (err_i, err) in lints.into_iter().enumerate() {
1417            for (cause_i, cause) in error_chain(&err).into_iter().enumerate() {
1418                if cause_i == 0 {
1419                    s.push_str(sep);
1420                    if lints_count > 1 {
1421                        s.push_str(&format!("{}. ", err_i + 1));
1422                    }
1423                } else {
1424                    s.push_str(sep);
1425                    s.push_str("    because: ");
1426                }
1427                s.push_str(&cause);
1428            }
1429        }
1430
1431        t!("Lints: {}", s);
1432
1433        if let Some(lint_str) = lint_str.as_mut() {
1434            // Add a trailing NUL.
1435            s.push('\0');
1436
1437            **lint_str = s.as_mut_ptr() as *mut c_char;
1438            // Pass ownership to the caller.
1439            std::mem::forget(s);
1440        }
1441    }
1442
1443    r
1444});
1445
1446fn pgp_prt_params(pkts: *const u8, pktlen: size_t,
1447                  pkttype: c_uint, paramsp: *mut *mut PgpDigParams,
1448                  lints: &mut Vec<anyhow::Error>)
1449    -> Result<()>
1450{
1451    tracer!(*crate::TRACE, "pgp_prt_params");
1452
1453    linter!($, lints);
1454
1455    let pkttype: Option<Tag> = if pkttype == 0 {
1456        None
1457    } else {
1458        Some(Tag::from(pkttype as u8))
1459    };
1460
1461    let pkts = check_slice!(pkts, pktlen);
1462    let paramsp = check_mut!(paramsp);
1463    *paramsp = std::ptr::null_mut();
1464
1465    let ppr = PacketParser::from_bytes(pkts)?;
1466
1467    let (obj, issuer, userid) = if let PacketParserResult::Some(pp) = ppr {
1468        // Process the packet.
1469        match pp.packet {
1470            Packet::Signature(_)
1471                if pkttype.is_none() || pkttype == Some(Tag::Signature) =>
1472            {
1473                let (packet, next_ppr) = pp.next()?;
1474
1475                if let PacketParserResult::Some(p) = next_ppr {
1476                    return_err!(None,
1477                                "Expected a bare OpenPGP signature, \
1478                                 but it's followed by a {}",
1479                                p.packet.tag());
1480                }
1481
1482                let sig = if let Packet::Signature(sig) = packet {
1483                    sig
1484                } else {
1485                    panic!("it's a sig");
1486                };
1487
1488                (PgpDigParamsObj::Signature(sig.clone()),
1489                 // XXX: Although there is normally only one issuer
1490                 // subpacket, there may be multiple such subpackets.
1491                 // Unfortunately, the API only allows us to return
1492                 // one.
1493                 sig.get_issuers().into_iter().next()
1494                     .map(|i| KeyID::from(&i)),
1495                 None)
1496            }
1497            Packet::PublicKey(_) | Packet::SecretKey(_)
1498                if pkttype.is_none()
1499                    || pkttype == Some(Tag::PublicKey)
1500                    || pkttype == Some(Tag::SecretKey) =>
1501            {
1502                let cert = match CertParser::from(PacketParserResult::Some(pp)).next()
1503                {
1504                    Some(Ok(cert)) => cert,
1505                    Some(Err(err)) => return_err!(
1506                        Some(err),
1507                        "Failed to read an OpenPGP certificate"),
1508                    None => return_err!(
1509                        None,
1510                        "Failed to read an OpenPGP certificate"),
1511                };
1512
1513                let keyid = cert.keyid().clone();
1514
1515                let userid = if let Ok(vc)
1516                    = cert.with_policy(&*P.read().unwrap(), None)
1517                {
1518                    vc.primary_userid()
1519                        .ok()
1520                        .and_then(|u| {
1521                            CString::new(u.userid().value()).ok()
1522                        })
1523                } else {
1524                    None
1525                };
1526
1527                (PgpDigParamsObj::Cert(cert),
1528                 Some(keyid),
1529                 userid)
1530            }
1531            Packet::Unknown(mut u) => {
1532                let mut err = u.set_error(anyhow::anyhow!("Error"));
1533                if let Some(openpgp::Error::MalformedMPI(_))
1534                    = err.downcast_ref::<openpgp::Error>()
1535                {
1536                    err = err.context("\
1537                        Signature appears to be created by a \
1538                        non-conformant OpenPGP implementation, see \
1539                        <https://github.com/rpm-software-management/rpm/issues/2351>.");
1540                }
1541
1542                return_err!(Some(err), "Failed to parse {}", u.tag());
1543            }
1544            ref p => {
1545                return_err!(
1546                    None,
1547                    "Unexpected OpenPGP packet in this context {}",
1548                    p.tag());
1549            }
1550        }
1551    } else {
1552        return_err!(
1553            None,
1554            "Expected an OpenPGP packet, encountered the end of the file");
1555    };
1556
1557    let mut buffer: [u8; 8] = [0; 8];
1558    if let Some(issuer) = issuer {
1559        for (i, c) in issuer.as_bytes().into_iter().enumerate() {
1560            buffer[i] = *c as u8;
1561        }
1562    }
1563
1564    *paramsp = move_to_c!(PgpDigParams {
1565        obj,
1566        signid: buffer,
1567        userid: userid,
1568    });
1569
1570    Ok(())
1571}
1572
1573ffi!(
1574/// Returns a `PgpDigParams` data structure for each subkey.
1575///
1576/// This does not return a `PgpDigParams` for the primary (just use
1577/// this one).  The subkeys are **not** checked for validity.  That
1578/// check is done when the key is used in [_pgpVerifySignature].
1579fn _pgpPrtParamsSubkeys(pkts: *const u8, pktlen: size_t,
1580                        _mainkey: *const PgpDigParams,
1581                        subkeys: *mut *mut PgpDigParams,
1582                        subkeys_count: *mut c_int) -> Binary {
1583    let pkts = check_slice!(pkts, pktlen);
1584    let subkeys = check_mut!(subkeys);
1585    *subkeys = std::ptr::null_mut();
1586    let subkeys_count = check_mut!(subkeys_count);
1587
1588    let ppr = PacketParser::from_bytes(pkts)?;
1589
1590    let cert = match ppr {
1591        PacketParserResult::Some(ref pp) => {
1592            match pp.packet {
1593                Packet::PublicKey(_) | Packet::SecretKey(_) => {
1594                    let cert = CertParser::from(ppr)
1595                        .next()
1596                        .ok_or(Error::Fail("Not an OpenPGP certificate".into()))??;
1597                    cert
1598                }
1599                ref p => {
1600                    return Err(Error::Fail(format!("{}", p.tag())));
1601                }
1602            }
1603        }
1604        _ => return Err(Error::Fail("Not an OpenPGP message".into())),
1605    };
1606
1607    let userid = if let Ok(vc) = cert.with_policy(&*P.read().unwrap(), None) {
1608        vc.primary_userid()
1609            .ok()
1610            .and_then(|u| {
1611                CString::new(u.userid().value()).ok()
1612            })
1613    } else {
1614        None
1615    };
1616
1617    // We return all subkeys here.  Subkeys are checked for validity
1618    // on demand.
1619    let mut keys: Vec<*mut PgpDigParams> = cert
1620        .keys().subkeys()
1621        .map(|ka| {
1622            t!("Subkey: {}", ka.key().keyid());
1623
1624            let zeros = [0; 8];
1625            let mut dig = PgpDigParams {
1626                obj: PgpDigParamsObj::Subkey(cert.clone(), ka.key().fingerprint()),
1627                signid: zeros,
1628                userid: userid.clone(),
1629            };
1630            dig.signid.copy_from_slice(ka.key().keyid().as_bytes());
1631            move_to_c!(dig)
1632        })
1633        .collect();
1634
1635    t!("Got {} subkeys", keys.len());
1636    *subkeys_count = keys.len() as c_int;
1637    if keys.len() == 0 {
1638        *subkeys = std::ptr::null_mut();
1639    } else {
1640        *subkeys = keys.as_mut_ptr() as *mut PgpDigParams;
1641        // Pass ownership to the caller.
1642        std::mem::forget(keys);
1643    }
1644
1645    Ok(())
1646});
1647
1648ffi!(
1649/// Strips the ASCII armor and returns the decoded data in `pkt`.
1650///
1651/// Despite its name, this function does not actually parse any OpenPGP
1652/// packets; it just strips the ASCII armor encoding.
1653///
1654/// Returns the type of armor on success (>0) or an error code
1655/// indicating the type of failure (<0).
1656fn _pgpParsePkts(armor: *const c_char,
1657                 pkt: *mut *mut c_char, pktlen: *mut size_t)
1658     -> PgpArmor
1659{
1660    let armor = check_cstr!(armor);
1661    let pkt = check_mut!(pkt);
1662    *pkt = std::ptr::null_mut();
1663    let pktlen = check_mut!(pktlen);
1664
1665    let mut reader = armor::Reader::from_reader(
1666        std::io::BufReader::new(
1667            armor.to_str().map_err(|_| PgpArmorError::BodyDecode)?.as_bytes()),
1668        armor::ReaderMode::Tolerant(None));
1669
1670    let mut buf = Vec::new();
1671    reader.read_to_end(&mut buf).map_err(|_| PgpArmorError::BodyDecode)?;
1672
1673    let kind = reader.kind();
1674
1675    *pktlen = buf.len() as size_t;
1676    *pkt = buf.as_mut_ptr() as *mut c_char;
1677    // Pass ownership to the caller.
1678    std::mem::forget(buf);
1679
1680    Ok(kind.into())
1681});
1682
1683ffi!(
1684/// Lints the first certificate in pkts.
1685///
1686/// This function lints the certificate according to the current
1687/// [policy].  It warns about things like unusable subkeys, because they
1688/// do not have a valid binding signature.  It will also generate a
1689/// warning if there are no valid, signing-capable keys.
1690///
1691/// There are four cases:
1692///
1693/// - The packets do not describe a certificate: returns an error and
1694///   sets `*explanation` to `NULL`.
1695///
1696/// - The packets describe a certificate and the certificate is
1697///   completely unusable: returns an error and sets `*explanation` to
1698///   a human readable explanation.
1699///
1700/// - The packets describe a certificate and some components are not
1701///   usable: returns success, and sets `*explanation` to a human
1702///   readable explanation.
1703///
1704/// - The packets describe a certificate and there are no lints:
1705///   returns success, and sets `*explanation` to `NULL`.
1706///
1707/// [policy]: index.html#policy
1708fn _pgpPubKeyLint(pkts: *const c_char,
1709                  pktslen: size_t,
1710                  explanation: *mut *mut c_char) -> ErrorCode
1711{
1712    let pkts = check_slice!(pkts, pktslen);
1713    let explanation = check_mut!(explanation);
1714
1715    // Make sure we always set explanation to something.
1716    *explanation = std::ptr::null_mut();
1717
1718    let cert = CertParser::from_bytes(pkts)?.next()
1719        .ok_or(Error::Fail("Not an OpenPGP certificate".into()))??;
1720
1721    let mut lints: Vec<String> = Vec::new();
1722    let mut lint = |l: &str| {
1723        lints.push(l.into());
1724    };
1725
1726    #[allow(clippy::never_loop)]
1727    let usable = 'done : loop {
1728        match cert.with_policy(&*P.read().unwrap(), None) {
1729            Err(err) => {
1730                lint(&format!("Policy rejects {}: {}", cert.keyid(), err));
1731                break 'done false;
1732            }
1733            Ok(vc) => {
1734                if let RevocationStatus::Revoked(revs)
1735                    = vc.revocation_status()
1736                {
1737                    for rev in revs {
1738                        if let Some((reason, msg))
1739                            = rev.reason_for_revocation()
1740                        {
1741                            let mut l = format!(
1742                                "The certificate was revoked: {}", reason);
1743                            if ! msg.is_empty() {
1744                                l.push_str(&format!(
1745                                    ", {}",
1746                                    String::from_utf8_lossy(msg)));
1747                            }
1748                            lint(&l);
1749                        } else {
1750                            lint("The certificate was revoked: \
1751                                  unspecified reason");
1752                        }
1753                    }
1754                }
1755
1756                if let Err(err) = vc.alive() {
1757                    if let Some(e) = vc.primary_key().key_expiration_time() {
1758                        if e <= SystemTime::now() {
1759                            lint(&format!("The certificate is expired: {}",
1760                                          err));
1761                        } else {
1762                            lint(&format!("The certificate is not live: {}",
1763                                          err));
1764                        }
1765                    }
1766                }
1767            }
1768        };
1769
1770        let mut have_signing = false;
1771        for ka in cert.keys() {
1772            let keyid = ka.key().keyid();
1773
1774            match ka.with_policy(&*P.read().unwrap(), None) {
1775                Err(err) => {
1776                    lint(&format!("Policy rejects subkey {}: {}",
1777                                  keyid, err));
1778                    continue;
1779                }
1780                Ok(ka) => {
1781                    if ! ka.for_signing() {
1782                        // Silently ignore non-signing capable
1783                        // subkeys.  We don't care about them.
1784                        continue;
1785                    }
1786
1787                    if let RevocationStatus::Revoked(revs)
1788                        = ka.revocation_status()
1789                    {
1790                        for rev in revs {
1791                            if let Some((reason, msg))
1792                                = rev.reason_for_revocation()
1793                            {
1794                                let mut l = format!(
1795                                    "Subkey {} was revoked: {}",
1796                                    keyid, reason);
1797                                if ! msg.is_empty() {
1798                                    l.push_str(&format!(
1799                                        ", {}",
1800                                        String::from_utf8_lossy(msg)));
1801                                }
1802                                lint(&l);
1803                            } else {
1804                                lint(&format!(
1805                                    "Subkey {} was revoked: \
1806                                     unspecified reason",
1807                                    keyid));
1808                            }
1809                        }
1810                        continue;
1811                    }
1812
1813                    if let Err(err) = ka.alive() {
1814                        if let Some(e) = ka.key_expiration_time() {
1815                            if e <= SystemTime::now() {
1816                                lint(&format!("Subkey {} is expired: {}",
1817                                              keyid, err));
1818                            } else {
1819                                lint(&format!("Subkey {} is not live: {}",
1820                                              keyid, err));
1821                            }
1822                        }
1823                        continue;
1824                    }
1825
1826                    if ! ka.key().pk_algo().is_supported() {
1827                        lint(&format!("Subkey {} is not supported \
1828                                       (no support for {})",
1829                                      keyid,
1830                                      ka.key().pk_algo()));
1831                        continue;
1832                    }
1833
1834                    have_signing = true;
1835                }
1836            }
1837        }
1838
1839        if ! have_signing {
1840            lint("Certificate does not have any usable signing keys");
1841        }
1842
1843        break true;
1844    };
1845
1846    if ! lints.is_empty() {
1847        // Indent the lints.
1848        let sep = "\n  ";
1849
1850        let mut s: String = format!("Certificate {}:{}", cert.keyid(), sep);
1851        s.push_str(&lints.join(sep));
1852        s.push('\0');
1853
1854        *explanation = s.as_mut_ptr() as *mut c_char;
1855        // Pass ownership to the caller.
1856        std::mem::forget(s);
1857    }
1858
1859    if usable {
1860        Ok(())
1861    } else {
1862        Err(Error::Fail(format!("Certificate {} is unusable", cert.keyid())))
1863    }
1864});
1865
1866/// An optional OpenPGP certificate *and* an optional signature.
1867///
1868/// This data structure is deprecated and is scheduled for removal in
1869/// rpm 4.19.
1870pub struct PgpDig {
1871    cert: Option<Box<PgpDigParams>>,
1872    sig: Option<Box<PgpDigParams>>,
1873}
1874
1875/// Dump the packets to stderr.
1876///
1877/// This is used by _pgpPrtPkts, which is deprecated and is scheduled
1878/// for removal in rpm 4.19.  It is intended to be bug compatible with
1879/// rpm's internal implementation.
1880fn dump_packets(pkts: &[u8]) -> Result<()> {
1881    use openpgp::types::CompressionAlgorithm;
1882    use openpgp::types::KeyServerPreferences;
1883    use openpgp::types::PublicKeyAlgorithm;
1884    use openpgp::types::SignatureType;
1885    use openpgp::types::SymmetricAlgorithm;
1886    use openpgp::packet::signature::subpacket::Subpacket;
1887    use openpgp::packet::signature::subpacket::SubpacketTag;
1888    use openpgp::packet::signature::subpacket::SubpacketValue;
1889
1890    let mut ppr = PacketParser::from_bytes(pkts)?;
1891
1892    fn pk_algo(a: PublicKeyAlgorithm) -> &'static str {
1893        use PublicKeyAlgorithm::*;
1894        #[allow(deprecated)]
1895        match a {
1896            RSAEncryptSign => "RSA",
1897            RSAEncrypt => "RSA(Encrypt-Only)",
1898            RSASign => "RSA(Sign-Only)",
1899            ElGamalEncrypt => "Elgamal(Encrypt-Only)",
1900            DSA => "DSA",
1901            ECDH => "Elliptic Curve",
1902            ECDSA => "ECDSA",
1903            ElGamalEncryptSign => "Elgamal",
1904            EdDSA => "EdDSA",
1905            _ => "Unknown public key algorithm",
1906        }
1907    }
1908
1909    fn sigtype(t: SignatureType) -> &'static str {
1910        use SignatureType::*;
1911        match t {
1912            Binary => "Binary document signature",
1913            Text => "Text document signature",
1914            Standalone => "Standalone signature",
1915            GenericCertification => "Generic certification of a User ID and Public Key",
1916            PersonaCertification => "Persona certification of a User ID and Public Key",
1917            CasualCertification => "Casual certification of a User ID and Public Key",
1918            PositiveCertification => "Positive certification of a User ID and Public Key",
1919            SubkeyBinding => "Subkey Binding Signature",
1920            PrimaryKeyBinding => "Primary Key Binding Signature",
1921            DirectKey => "Signature directly on a key",
1922            KeyRevocation => "Key revocation signature",
1923            SubkeyRevocation => "Subkey revocation signature",
1924            CertificationRevocation => "Certification revocation signature",
1925            Timestamp => "Timestamp signature",
1926            _ => "Unknown signature type",
1927        }
1928    }
1929
1930    fn symalgo(a: SymmetricAlgorithm) -> &'static str {
1931        use SymmetricAlgorithm::*;
1932        #[allow(deprecated)]
1933        match a {
1934            Unencrypted => "Plaintext",
1935            IDEA => "IDEA",
1936            TripleDES => "3DES",
1937            CAST5 => "CAST5",
1938            Blowfish => "BLOWFISH",
1939            AES128 => "AES(128-bit key)",
1940            AES192 => "AES(192-bit key)",
1941            AES256 => "AES(256-bit key)",
1942            Twofish => "TWOFISH(256-bit key)",
1943            _ => "Unknown symmetric key algorithm",
1944        }
1945    }
1946
1947    fn compalgo(a: CompressionAlgorithm) -> &'static str {
1948        use CompressionAlgorithm::*;
1949        match a {
1950            Uncompressed => "Uncompressed",
1951            Zip => "ZIP",
1952            Zlib => "ZLIB",
1953            BZip2 => "BZIP2",
1954            _ => "Unknown compression algorithm",
1955        }
1956    }
1957
1958    fn ksprefs(prefs: KeyServerPreferences) -> &'static str {
1959        // This is wrong, but this is what the internal implementation
1960        // does.
1961        if prefs.no_modify() {
1962            "No-modify(128)"
1963        } else if KeyServerPreferences::empty().normalized_eq(&prefs) {
1964            ""
1965        } else {
1966            "Unknown key server preference"
1967        }
1968    }
1969
1970    fn subpacket(sp: &Subpacket) -> String {
1971        let mut output: Vec<String> = Vec::new();
1972
1973        let tag = sp.tag();
1974        let s = {
1975            use SubpacketTag::*;
1976            match tag {
1977                SignatureCreationTime => "signature creation time",
1978                SignatureExpirationTime => "signature expiration time",
1979                ExportableCertification => "exportable certification",
1980                TrustSignature => "trust signature",
1981                RegularExpression => "regular expression",
1982                Revocable => "revocable",
1983                KeyExpirationTime => "key expiration time",
1984                PlaceholderForBackwardCompatibility => "additional recipient request",
1985                PreferredSymmetricAlgorithms => "preferred symmetric algorithms",
1986                RevocationKey => "revocation key",
1987                Issuer => "issuer key ID",
1988                NotationData => "notation data",
1989                PreferredHashAlgorithms => "preferred hash algorithms",
1990                PreferredCompressionAlgorithms => "preferred compression algorithms",
1991                KeyServerPreferences => "key server preferences",
1992                PreferredKeyServer => "preferred key server",
1993                PrimaryUserID => "primary user id",
1994                PolicyURI => "policy URL",
1995                KeyFlags => "key flags",
1996                SignersUserID => "signer's user id",
1997                ReasonForRevocation => "reason for revocation",
1998                Features => "features",
1999                EmbeddedSignature => "embedded signature",
2000                _ => "Unknown signature subkey type",
2001            }
2002        };
2003        output.push(s.into());
2004
2005        output.push(format!("({})", Into::<u8>::into(tag)));
2006
2007        if sp.critical() {
2008            output.push(" *CRITICAL*".into());
2009        }
2010
2011        {
2012            use SubpacketValue::*;
2013            match sp.value() {
2014                PreferredSymmetricAlgorithms(algos) => {
2015                    output.push(" ".into());
2016                    output.push(
2017                        algos.iter()
2018                            .map(|a| {
2019                                format!("{}({})",
2020                                        symalgo(*a),
2021                                        Into::<u8>::into(*a))
2022                            })
2023                            .collect::<Vec<String>>()
2024                            .join(" "))
2025                }
2026                PreferredHashAlgorithms(algos) => {
2027                    output.push(" ".into());
2028                    output.push(
2029                        algos.iter()
2030                            .map(|a| {
2031                                format!("{}({})",
2032                                        a,
2033                                        Into::<u8>::into(*a))
2034                            })
2035                            .collect::<Vec<String>>()
2036                            .join(" "))
2037                }
2038                PreferredCompressionAlgorithms(algos) => {
2039                    output.push(" ".into());
2040                    output.push(
2041                        algos.iter()
2042                            .map(|a| {
2043                                format!("{}({})",
2044                                        compalgo(*a),
2045                                        Into::<u8>::into(*a))
2046                            })
2047                            .collect::<Vec<String>>()
2048                            .join(" "))
2049                }
2050                KeyServerPreferences(prefs) => {
2051                    output.push(format!(" {}", ksprefs(prefs.clone())))
2052                }
2053                SignatureExpirationTime(d)
2054                    | KeyExpirationTime(d) =>
2055                {
2056                    // expiration time is an offset from the creation
2057                    // time, but rpm's internal OpenPGP implementation
2058                    // treats it as an absolute time.  As we're going
2059                    // for bug-for-bug compatibility here, we do the
2060                    // same.
2061                    let t = DateTime::from_timestamp(
2062                        d.as_secs() as i64, 0)
2063                        // This is just compatibility, debugging
2064                        // output.  Fallback to the unix epoch.
2065                        .unwrap_or_default();
2066                    output.push(format!("  {}(0x{:08x})",
2067                                        t.format("%c"),
2068                                        d.as_secs()));
2069                }
2070
2071                SignatureCreationTime(_)
2072                    | Issuer(_)
2073                    | KeyFlags(_) => (),
2074
2075                _ => {
2076                    use sequoia_openpgp::serialize::MarshalInto;
2077
2078                    output.push(" ".into());
2079                    output.extend(
2080                        sp.value()
2081                            .to_vec()
2082                            .unwrap_or(Vec::new())
2083                            .into_iter()
2084                            .map(|b| format!("{:02x}", b)))
2085                }
2086            }
2087        }
2088
2089        output.join("")
2090    }
2091
2092    while let PacketParserResult::Some(pp) = ppr {
2093        let (packet, next_ppr) = pp.recurse()?;
2094        ppr = next_ppr;
2095
2096        // We only dump what rpm's internal OpenPGP implementation
2097        // dumps.  Other packets we silently ignore.
2098        #[allow(deprecated)]
2099        match packet {
2100            Packet::Signature(sig) => {
2101                // V4 Signature(2) DSA(17) SHA512(10) Generic certification of a User ID and Public Key(16)
2102                //     signature creation time(2)
2103                //     issuer key ID(16)
2104                //  signhash16 1418
2105                eprintln!("V{} Signature(2) {}({}) {}({}) {}({})",
2106                          sig.version(),
2107                          pk_algo(sig.pk_algo()),
2108                          Into::<u8>::into(sig.pk_algo()),
2109                          sig.hash_algo(),
2110                          Into::<u8>::into(sig.hash_algo()),
2111                          sigtype(sig.typ()),
2112                          Into::<u8>::into(sig.typ()));
2113                sig.hashed_area().iter().for_each(|sb| {
2114                    eprintln!("    {}", subpacket(sb));
2115                });
2116                sig.unhashed_area().iter().for_each(|sb| {
2117                    eprintln!("    {}", subpacket(sb));
2118                });
2119
2120                eprintln!(" signhash16 {:02x}{:02x}",
2121                          sig.digest_prefix()[0],
2122                          sig.digest_prefix()[1]);
2123            },
2124            Packet::PublicKey(key) => {
2125                // V4 Public Key(6) RSA(1)  Tue Apr  7 08:52:57 2015(0x55239ae9)
2126
2127                let secs = key.creation_time()
2128                    .duration_since(SystemTime::UNIX_EPOCH)
2129                    .map(|d| d.as_secs())
2130                    .unwrap_or(0);
2131                let t: DateTime::<Utc> = key.creation_time().into();
2132
2133                eprintln!("V{} Public Key(6) {}({})  {}(0x{:08x})",
2134                          key.version(),
2135                          pk_algo(key.pk_algo()),
2136                          Into::<u8>::into(key.pk_algo()),
2137                          t.format("%c"), secs);
2138            }
2139            Packet::PublicSubkey(key) => {
2140                // Public Subkey(14) 045523a696010...
2141                use sequoia_openpgp::serialize::MarshalInto;
2142
2143                let secs = key.creation_time()
2144                    .duration_since(SystemTime::UNIX_EPOCH)
2145                    .map(|d| d.as_secs())
2146                    .unwrap_or(0);
2147
2148                eprintln!("Public Subkey(14) {:02}{:08x}{:02x}{}",
2149                          key.version(), secs,
2150                          Into::<u8>::into(key.pk_algo()),
2151                          key.mpis().to_vec()
2152                          .unwrap_or_else(|_| Vec::new())
2153                          .into_iter()
2154                          .map(|b| format!("{:02x}", b))
2155                          .collect::<String>());
2156            }
2157            Packet::UserID(userid) => {
2158                // User ID(13) "Neal H. Walfield <neal@walfield.org>"
2159                eprintln!("User ID(13) {:?}",
2160                          String::from_utf8_lossy(userid.value()));
2161            }
2162
2163            Packet::Unknown(_pkt) => (),
2164            Packet::OnePassSig(_ops) => (),
2165            Packet::SecretKey(_key) => (),
2166            Packet::SecretSubkey(_key) => (),
2167            Packet::Marker(_marker) => (),
2168            Packet::Trust(_trust) => (),
2169            Packet::UserAttribute(_ua) => (),
2170            Packet::Literal(_lit) => (),
2171            Packet::CompressedData(_cd) => (),
2172            Packet::PKESK(_pkesk) => (),
2173            Packet::SKESK(_skesk) => (),
2174            Packet::SEIP(_seip) => (),
2175            Packet::MDC(_mdc) => (),
2176            _ => (),
2177        }
2178    }
2179
2180    Ok(())
2181}
2182
2183ffi!(
2184/// Parses and optionally prints to stdout a OpenPGP packet(s).
2185///
2186/// This function is deprecated and is scheduled for removal in rpm
2187/// 4.19.
2188///
2189/// @param pkts		OpenPGP packet(s)
2190/// @param pktlen	OpenPGP packet(s) length (no. of bytes)
2191/// @param(out) dig	parsed output of signature/pubkey packet parameters
2192/// @param printing	should packets be printed?
2193///
2194/// Returns 0 on success, -1 on failure.
2195fn _pgpPrtPkts(pkts: *const u8, pktslen: size_t,
2196               dig: *mut PgpDig, printing: c_int)
2197    -> Binary
2198{
2199    let dig = check_mut!(dig);
2200
2201    let mut params: *mut PgpDigParams = std::ptr::null_mut();
2202
2203    if printing != 0 {
2204        // We ignore any error here as this printing should not change
2205        // the functions semantics.
2206        let _ = dump_packets(check_slice!(pkts, pktslen));
2207    }
2208
2209    let result = _pgpPrtParams(pkts, pktslen, 0, &mut params);
2210    if result == -1 {
2211        return Err(Error::Fail("Parse error".into()));
2212    }
2213
2214    let params = claim_from_c!(params);
2215    match params.obj {
2216        PgpDigParamsObj::Cert(_) => dig.cert = Some(params),
2217        PgpDigParamsObj::Subkey(_, _) => dig.cert = Some(params),
2218        PgpDigParamsObj::Signature(_) => dig.sig = Some(params),
2219    }
2220
2221    Ok(())
2222});
2223
2224ffi!(
2225/// Create a container for parsed OpenPGP packet(s).
2226///
2227/// This function is deprecated and is scheduled for removal in rpm
2228/// 4.19.
2229///
2230/// @return		container
2231fn _pgpNewDig() -> *mut PgpDig {
2232    Ok(move_to_c!(PgpDig {
2233        cert: None,
2234        sig: None,
2235    }))
2236});
2237
2238ffi!(
2239/// Release (malloc'd) data from container.
2240///
2241/// This function is deprecated and is scheduled for removal in rpm
2242/// 4.19.
2243///
2244/// @param dig		container
2245fn _pgpCleanDig(dig: *mut PgpDig) {
2246    let dig = check_mut!(dig);
2247    dig.cert = None;
2248    dig.sig = None;
2249});
2250
2251ffi!(
2252/// Destroy a container for parsed OpenPGP packet(s).
2253///
2254/// This function is deprecated and is scheduled for removal in rpm
2255/// 4.19.
2256///
2257/// @param dig		container
2258/// @return		NULL always
2259fn _pgpFreeDig(dig: Option<&mut PgpDig>) -> *mut PgpDig {
2260    free!(dig);
2261    Ok(std::ptr::null_mut())
2262});
2263
2264ffi!(
2265/// Retrieve parameters for parsed OpenPGP packet(s).
2266///
2267/// This function is deprecated and is scheduled for removal in rpm
2268/// 4.19.
2269///
2270/// @param dig		container
2271/// @param pkttype	type of params to retrieve (signature / pubkey)
2272/// @return		pointer to OpenPGP parameters, NULL on error/not found
2273fn _pgpDigGetParams(dig: *const PgpDig, pkttype: c_uint)
2274    -> *const PgpDigParams
2275{
2276    let dig = check_ptr!(dig);
2277
2278    let ptr = match Tag::from(pkttype as u8) {
2279        Tag::PublicKey => {
2280            if let Some(ref cert) = dig.cert {
2281                cert.as_ref()
2282            } else {
2283                std::ptr::null()
2284            }
2285        }
2286        Tag::Signature => {
2287            if let Some(ref sig) = dig.sig {
2288                sig.as_ref()
2289            } else {
2290                std::ptr::null()
2291            }
2292        }
2293        _ => {
2294            std::ptr::null()
2295        }
2296    };
2297
2298    Ok(ptr)
2299});
2300
2301ffi!(
2302/// Verify a PGP signature.
2303///
2304/// This function is deprecated and is scheduled for removal in rpm
2305/// 4.19.
2306///
2307/// @param dig		container
2308/// @param hashctx	digest context
2309/// @return 		RPMRC_OK on success
2310fn _pgpVerifySig(dig: *const PgpDig,
2311                 ctx: *const digest::DigestContext) -> ErrorCode {
2312    Err(
2313        _pgpVerifySignature(
2314            _pgpDigGetParams(dig, u8::from(Tag::PublicKey) as u32),
2315	    _pgpDigGetParams(dig, u8::from(Tag::Signature) as u32),
2316            ctx).into())
2317});
2318
2319ffi!(
2320/// Merge the PGP packets of two certificates
2321///
2322/// The certificates must describe the same public key. The call should merge
2323/// important pgp packets (self-signatures, new subkeys, ...) and remove duplicates.
2324///
2325/// - `pkts1` - OpenPGP pointer to a buffer with the first certificate
2326/// - `pkts1len` - length of the buffer with the first certificate
2327/// - `pkts2` - OpenPGP pointer to a buffer with the second certificate
2328/// - `pkts2len` - length of the buffer with the second certificate
2329/// - `pktsm` - merged certificate (malloced)
2330/// - `pktsmlen` - length of merged certificate
2331/// - `flags` - merge flags (currently not used, must be zero)
2332///
2333/// Returns `RPMRC_OK` on success.
2334fn _pgpPubkeyMerge(
2335    pkts1: *const u8, pkts1len: size_t,
2336    pkts2: *const u8, pkts2len: size_t,
2337    pktsm: *mut *mut u8, pktsmlen: *mut size_t,
2338    flags: c_int)
2339  -> ErrorCode
2340{
2341    let pkts1 = check_slice!(pkts1, pkts1len);
2342    let pkts2 = check_slice!(pkts2, pkts2len);
2343
2344    let cert1 = Cert::from_bytes(pkts1)?;
2345    let cert2 = Cert::from_bytes(pkts2)?;
2346
2347    if cert1.fingerprint() != cert2.fingerprint() {
2348	return Err(Error::Fail("Can't merge different certificates".into()));
2349    }
2350
2351    let (merged, updated)
2352	= cert1.clone().insert_packets(cert2.into_packets())?;
2353
2354    let merged_bytes_;
2355    let (result, result_len) = if ! updated {
2356	// The certificate is unchanged.  Nevertheless,
2357	// Cert::from_bytes may have changed the bit representation,
2358	// e.g., by canonicalizing it.  To avoid making rpm think that
2359	// the certificate has changed when it hasn't (it does a
2360	// memcmp), we return pkts1.
2361	(pkts1.as_ptr(), pkts1len)
2362    } else {
2363	merged_bytes_ = merged.to_vec()?;
2364	(merged_bytes_.as_ptr(), merged_bytes_.len())
2365    };
2366
2367    unsafe {
2368	let buffer = libc::malloc(result_len);
2369        if buffer.is_null() {
2370            return Err(Error::Fail("out of memory".into()));
2371        }
2372	libc::memcpy(buffer, result as *const c_void, result_len);
2373
2374	*pktsmlen = result_len as size_t;
2375	*pktsm = buffer as *mut u8;
2376    }
2377
2378    Ok(())
2379});
2380
2381
2382#[cfg(test)]
2383mod tests {
2384    use super::*;
2385
2386    use openpgp::cert::CertBuilder;
2387    use openpgp::serialize::SerializeInto;
2388    use openpgp::types::KeyFlags;
2389
2390    // Check that we can successfully merge two certificates.
2391    #[test]
2392    fn merge_certs() {
2393	let p = openpgp::policy::StandardPolicy::new();
2394
2395	let (cert, _rev) = CertBuilder::new()
2396	    .add_userid("Alice")
2397	    .generate()
2398	    .unwrap();
2399
2400	let vc = cert.with_policy(&p, None).unwrap();
2401
2402	// We should only have a primary, which is certification capable.
2403	assert_eq!(vc.keys().for_signing().count(), 0);
2404	assert_eq!(vc.keys().for_transport_encryption().count(), 0);
2405	assert_eq!(vc.keys().for_storage_encryption().count(), 0);
2406
2407	// Add a signing subkey.
2408	let cert2 = KeyBuilder::new(
2409	    KeyFlags::empty().set_signing())
2410	    .subkey(vc.clone()).unwrap()
2411	    .attach_cert().unwrap();
2412
2413	// Add an encryption subkey.
2414	let cert3 = KeyBuilder::new(
2415	    KeyFlags::empty().set_transport_encryption())
2416	    .subkey(vc.clone()).unwrap()
2417	    .attach_cert().unwrap();
2418
2419	let cert2_bytes = cert2.to_vec().unwrap();
2420	let cert3_bytes = cert3.to_vec().unwrap();
2421
2422	let mut result: *mut u8 = std::ptr::null_mut();
2423	let mut result_len: size_t = 0;
2424
2425	eprintln!("About to run pgpPubkeyMerge");
2426	let ec = _pgpPubkeyMerge(
2427	    cert2_bytes.as_ptr(), cert2_bytes.len(),
2428	    cert3_bytes.as_ptr(), cert3_bytes.len(),
2429	    &mut result, &mut result_len,
2430	    0);
2431
2432	assert_eq!(ec, 0);
2433
2434	assert!(! result.is_null());
2435        let result = unsafe {
2436	    std::slice::from_raw_parts(result as *const u8, result_len)
2437	};
2438
2439	let result = Cert::from_bytes(result).expect("valid cert");
2440
2441	assert_eq!(cert.fingerprint(), result.fingerprint());
2442	assert!(result != cert);
2443	assert!(result != cert2);
2444	assert!(result != cert3);
2445
2446	let expected = cert2.clone().merge_public(cert3.clone()).unwrap();
2447	assert_eq!(result, expected);
2448
2449	let result_vc = result.with_policy(&p, None).unwrap();
2450
2451	assert_eq!(result_vc.keys().for_signing().count(), 1);
2452	assert_eq!(result_vc.keys().for_transport_encryption().count(), 1);
2453	assert_eq!(result_vc.keys().for_storage_encryption().count(), 0);
2454    }
2455
2456    // Check that when we attempt to merge two different certificates,
2457    // we return an error.
2458    #[test]
2459    fn merge_certs_mismatch() {
2460	let (cert, _rev) = CertBuilder::new()
2461	    .add_userid("Alice")
2462	    .generate()
2463	    .unwrap();
2464	let (cert2, _rev) = CertBuilder::new()
2465	    .add_userid("Bob")
2466	    .generate()
2467	    .unwrap();
2468
2469	let cert_bytes = cert.to_vec().unwrap();
2470	let cert2_bytes = cert2.to_vec().unwrap();
2471
2472	let mut result: *mut u8 = std::ptr::null_mut();
2473	let mut result_len: size_t = 0;
2474
2475	eprintln!("About to run pgpPubkeyMerge");
2476	let ec = _pgpPubkeyMerge(
2477	    cert_bytes.as_ptr(), cert_bytes.len(),
2478	    cert2_bytes.as_ptr(), cert2_bytes.len(),
2479	    &mut result, &mut result_len,
2480	    0);
2481
2482	assert_ne!(ec, 0);
2483    }
2484}