logo
   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
use std::time::{Duration, SystemTime};

use crate::packet::{
    Key,
    key,
};

use crate::Result;
use crate::Packet;
use crate::packet::signature::{
    SignatureBuilder,
    SIG_BACKDATE_BY,
    subpacket::SubpacketTag,
};
use crate::cert::prelude::*;
use crate::Error;
use crate::crypto::{Password, Signer};
use crate::types::{
    HashAlgorithm,
    KeyFlags,
    SignatureType,
};

/// A Key builder.
///
/// A `KeyBuilder` is used to create a key, which can then be attached
/// to an existing certificate as a subkey using
/// [`KeyBuilder::subkey`].
///
/// # Examples
///
/// Generate a signing key and attach it to a certificate:
///
/// ```
/// use sequoia_openpgp as openpgp;
/// use openpgp::cert::prelude::*;
/// use openpgp::policy::StandardPolicy;
/// use openpgp::types::KeyFlags;
///
/// # fn main() -> openpgp::Result<()> {
/// let p = &StandardPolicy::new();
///
/// # let (cert, _) =
/// #     CertBuilder::general_purpose(None, Some("alice@example.org"))
/// #         .generate()?;
/// #
/// let vc = cert.with_policy(p, None)?;
/// # let vc1 = vc.clone();
/// let cert_new = KeyBuilder::new(KeyFlags::empty().set_signing())
///     .subkey(vc)?
///     .attach_cert()?;
/// # let vc2 = cert_new.with_policy(p, None)?;
/// # assert_eq!(vc1.keys().count() + 1, vc2.keys().count());
/// # Ok(())
/// # }
/// ```
pub struct KeyBuilder {
    flags: KeyFlags,
    cipher_suite: CipherSuite,
    password: Option<Password>,
    creation_time: Option<SystemTime>,
}
assert_send_and_sync!(KeyBuilder);

impl KeyBuilder {
    /// Returns a new `KeyBuilder`.
    ///
    /// Use [`KeyBuilder::subkey`] to generate a subkey and get a
    /// [`SubkeyBuilder`], which can be used to add the subkey to a
    /// certificate.
    pub fn new(flags: KeyFlags) -> Self {
        KeyBuilder {
            flags,
            cipher_suite: Default::default(),
            creation_time: None,
            password: None,
        }
    }

    /// Returns the selected cipher suite.
    pub fn cipher_suite(&self) -> CipherSuite {
        self.cipher_suite
    }

    /// Sets the cipher suite.
    pub fn set_cipher_suite(mut self, cipher_suite: CipherSuite) -> Self {
        self.cipher_suite = cipher_suite;
        self
    }

    /// Returns the creation time.
    ///
    /// Returns `None` if the creation time hasn't been specified.  In
    /// that case, the creation time will be set to the current time
    /// when the key material is generated by [`KeyBuilder::subkey`].
    pub fn creation_time(&self) -> Option<SystemTime> {
        self.creation_time
    }

    /// Sets the creation time.
    ///
    /// If `None`, then the creation time will be set to the current
    /// time when the key material is generated by
    /// [`KeyBuilder::subkey`].
    pub fn set_creation_time<T>(mut self, creation_time: T) -> Self
    where T: Into<Option<SystemTime>>
    {
        self.creation_time = creation_time.into();
        self
    }

    /// Returns the password, if any.
    pub fn password(&self) -> Option<&Password> {
        self.password.as_ref()
    }

    /// Sets the password.
    pub fn set_password<T>(mut self, password: T) -> Self
    where T: Into<Option<Password>>
    {
        self.password = password.into();
        self
    }

    /// Generates a key, and returns a `SubkeyBuilder`.
    ///
    /// The [`SubkeyBuilder`] will add the key to the specified
    /// certificate.
    ///
    /// If the key creation time has not been explicitly set using
    /// [`KeyBuilder::set_creation_time`], then the key's creation
    /// time is set to the current time minus a few seconds.
    ///
    /// Setting the creation time to a short time in the past solves
    /// two problems.  First, when a new binding signature is created,
    /// it must have a newer time than the previous binding signature.
    /// This policy ensures that if a second binding signature is
    /// immediately created after the key is created it does not need
    /// to be postdated and thus can be used immediately.  Second, if
    /// the key is immediately transferred to another computer and its
    /// clock is not quite synchronized, the key may appear to have
    /// been created in the future and will thus be ignored.  Although
    /// NTP is widely used, emperically it seems that some virtual
    /// machines have laggy clocks.
    pub fn subkey(self, vc: ValidCert) -> Result<SubkeyBuilder<'_>> {
        let mut key: Key<key::SecretParts, key::SubordinateRole>
            = self.cipher_suite.generate_key(&self.flags)?;
        let ct = self.creation_time.unwrap_or_else(|| {
            crate::now() - Duration::new(SIG_BACKDATE_BY, 0)
        });
        key.set_creation_time(ct)?;

        let signer = key.clone().into_keypair().unwrap();

        if let Some(ref password) = self.password {
            key.secret_mut().encrypt_in_place(password)?;
        }

        let mut builder = SubkeyBuilder::new(
            vc, key.parts_into_unspecified(), self.flags)?;
        builder = builder.set_signature_creation_time(ct)?;
        Ok(builder.set_subkey_signer(signer))
    }
}

/// A Subkey builder.
///
/// This builder simplifies attaching a subkey to a certificate, or
/// updating an existing subkey's binding signature.  It is a more
/// high-level variant of [`SignatureBuilder`], which should be used
/// if more control is needed than this builder provides.
///
/// # Security Considerations: Key Expiration
///
/// **It is essential that keys have reasonable expiration times.** If
/// a binding signature is accidentally published without an
/// expiration time, it is effectively impossible to retract this by
/// publishing a new binding signature that has an expiration.  This
/// is because an attacker may be able to withhold the newer binding
/// signature thereby causing a victim to use a key that is actually
/// expired.
///
/// The heuristic described below takes this security consideration
/// into account.  However, because the heuristic never extends a
/// key's expiration on its own, there are still cases where it is
/// necessary to set the expiration manually.
///
/// # Binding Signature
///
/// To attach a subkey to a certificate, the primary key needs to
/// issue a [subkey binding signature].  This binding signature
/// provides information about the key including its validity period
/// (i.e., when it expires), and may contain auxiliary information
/// like notations.  A subkey binding signature usually contains the
/// following information:
///
///   [subkey binding signature]: https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.1
///
///   - [Signature creation time](https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.3.4)
///
///   - [Key flags](https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.3.21)
///
///   - [Issuer](https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.3.5) and Issuer Fingerprint.
///
///   - [Primary key binding signature](https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.3.26) (if the key is signing capable)
///
/// The following information is also meaningful in the context of
/// a subkey binding signature:
///
///   - [Key expiration time](https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.3.6)
///     (relative to the key's creation time, not the signature's
///     creation time!)
///
///   - [Signature exiration time](https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.3.10)
///
///   - [Exportable certification](https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.3.11)
///
///   - [Notations](https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.3.16)
///
/// Because a `SubkeyBuilder` is just a wrapper around a
/// [`SignatureBuilder`], refer [`SignatureBuilder`]'s documentation
/// about to understand how some of these subpackets are automatically
/// set.
///
/// It is possible to change the signature's creation time and key
/// expiration time using the
/// [`SubkeyBuilder::set_signature_creation_time`] and
/// [`SubkeyBuilder::set_key_expiration_time`] methods.  Other
/// subpackets can be modified using
/// [`SubkeyBuilder::with_signature_template`].
///
/// ## Heuristic
///
/// This builder uses a heuristic to select a binding signature to use
/// as a template and to select a key expiration.  It is possible to
/// use your own binding signature by calling
/// [`SubkeyBuilder::set_signature_template`], and override the key
/// expiration time using [`SubkeyBuilder::set_key_expiration_time`].
/// In general, you should use an existing binding signature as a
/// template to preserve any customizations that the user may have
/// made.
///
/// Because forgetting to set an expiration time can be security
/// relevant, this heuristic acts conservatively.  If possible, the
/// user interface should show the expiration time, and allow the user
/// to adjust it manually.
///
/// The heuristic is:
///
/// - If the subkey is already present on the certificate, the default
///   binding signature is based on the subkey's active binding
///   signature, and the key expiration time is reused.
///
///   If the key would expire before the binding signature becomes
///   valid then [`SubkeyBuilder::attach`] will fail.
///
///   Note: if the subkey is present, but it does not have a valid
///   binding signature, then the subkey is treated as a new subkey.
///
/// - If the subkey is new, then the active binding signature of the
///   newest live, non-revoked, valid subkey is used as the binding
///   signature template.  Newest means the the key with the latest
///   Key Creation Time and not necessarily the newest binding
///   signature.  (If multiple keys have the same key creation time,
///   the key to use is chosen in an undefined, but deterministic
///   manner.)
///
///   If the certificate does not have a subkey, then a default
///   binding signature is created.  In this case, the default
///   expiration is set to the same expiration as the primary key, if
///   any.
///
///   As above, if the key would expire before the binding signature
///   becomes valid then [`SubkeyBuilder::attach`] will fail.
///
/// # Examples
///
/// Add a new, signing-capable subkey to a certificate:
///
/// ```
/// use sequoia_openpgp as openpgp;
/// use openpgp::cert::prelude::*;
/// use openpgp::policy::StandardPolicy;
/// use openpgp::types::KeyFlags;
///
/// # fn main() -> openpgp::Result<()> {
/// let p = &StandardPolicy::new();
///
/// # let (cert, _) =
/// #     CertBuilder::general_purpose(None, Some("alice@example.org"))
/// #         .generate()?;
/// #
/// let vc = cert.with_policy(p, None)?;
/// # let vc1 = vc.clone();
/// let cert_new = KeyBuilder::new(KeyFlags::empty().set_signing())
///     .subkey(vc)?
///     .attach_cert()?;
/// # let vc2 = cert_new.with_policy(p, None)?;
/// # assert_eq!(vc1.keys().count() + 1, vc2.keys().count());
/// # Ok(())
/// # }
/// ```
///
/// Import a raw encryption key:
///
/// ```
/// use std::time::SystemTime;
///
/// use sequoia_openpgp as openpgp;
/// use openpgp::cert::prelude::*;
/// use openpgp::packet::Key;
/// use openpgp::packet::key::Key4;
/// use openpgp::policy::StandardPolicy;
/// use openpgp::types::KeyFlags;
///
/// # fn main() -> openpgp::Result<()> {
/// let p = &StandardPolicy::new();
///
/// # let q = b"\x57\x15\x45\x1B\x68\xA5\x13\xA2\x20\x0F\x71\x9D\xE3\x05\x3B\xED\xA2\x21\xDE\x61\x5A\xF5\x67\x45\xBB\x97\x99\x43\x53\x59\x7C\x3F";
/// let k: Key<_, _>
///     = Key4::import_public_ed25519(q, SystemTime::now())?.into();
///
/// # let (cert, _) = CertBuilder::new().generate()?;
/// #
/// let vc = cert.with_policy(p, None)?;
/// # let vc1 = vc.clone();
/// let mut cert2 = SubkeyBuilder::new(
///     vc, k.parts_into_unspecified(),
///     KeyFlags::empty().set_transport_encryption())?
///     .attach_cert()?;
/// #
/// # let vc2 = cert2.with_policy(p, None)?;
/// # assert_eq!(vc1.keys().count() + 1, vc2.keys().count());
/// # Ok(())
/// # }
/// ```
///
/// Change all valid, non-revoked subkeys to expire in a year from now:
///
/// ```
/// use std::time::{SystemTime, Duration};
///
/// use sequoia_openpgp as openpgp;
/// use openpgp::cert::prelude::*;
/// use openpgp::Packet;
/// use openpgp::policy::StandardPolicy;
/// use openpgp::types::KeyFlags;
///
/// # fn main() -> openpgp::Result<()> {
/// let p = &StandardPolicy::new();
///
/// let now = SystemTime::now();
/// let e = now + Duration::new(365 * 24 * 60 * 60, 0);
///
/// # let v = Duration::new(24 * 60 * 60, 0);
/// # let (cert, _) =
/// #     CertBuilder::new()
/// #         .set_creation_time(now - Duration::new(60, 0))
/// #         .add_subkey(KeyFlags::empty().set_storage_encryption(),
/// #                     v, None)
/// #         .add_subkey(KeyFlags::empty().set_signing(),
/// #                     v, None)
/// #         .generate()?;
/// # assert_eq!(cert.keys().subkeys().count(), 2);
/// let vc = cert.with_policy(p, None)?;
/// # assert_eq!(vc.keys().subkeys().count(), 2);
/// # for ka in vc.keys().subkeys() {
/// #     assert_eq!(ka.key_validity_period(), Some(v));
/// # }
///
/// // If you only want to extend non-expired keys, then add .alive().
/// let packets = vc.keys().subkeys().revoked(false)
///     .map(|ka| {
///         SubkeyBuilder::from(ka)
///             .set_signature_creation_time(now)?
///             .set_key_expiration_time(e)?
///             .attach()
///     })
///     .collect::<Result<Vec<Vec<Packet>>, _>>()?;
/// let cert = cert.insert_packets(packets.into_iter().flatten())?;
///
/// let vc = cert.with_policy(p, now)?;
/// # assert_eq!(vc.keys().subkeys().count(), 2);
/// for ka in vc.keys().subkeys().revoked(false) {
///     // Check that the key's expiration time is really e.  Note: We
///     // need to take into account that SystemTime has a subsecond
///     // resolution, but OpenPGP's timestamps only have a 1 second
///     // resolution.
///     assert!(e.duration_since(ka.key_expiration_time().unwrap()).unwrap()
///             < Duration::new(1, 0));
/// }
/// # Ok(())
/// # }
/// ```
pub struct SubkeyBuilder<'a> {
    vc: ValidCert<'a>,
    primary_signer: Option<Box<dyn Signer + Send + Sync + 'a>>,

    subkey: Key<key::UnspecifiedParts, key::SubordinateRole>,
    subkey_signer: Option<Box<dyn Signer + Send + Sync + 'a>>,

    template: SignatureBuilder,
}
assert_send_and_sync!(SubkeyBuilder<'_>);

impl<'a> SubkeyBuilder<'a> {
    /// Returns a SubkeyBuilder that will add the key to the specified
    /// certificate.
    ///
    /// If the subkey is already present on the certificate, then the
    /// `SubkeyBuilder` effectively adds a new binding signature to
    /// the certificate.
    pub fn new<P>(vc: ValidCert<'a>,
                  subkey: Key<P, key::SubordinateRole>,
                  subkey_flags: KeyFlags)
        -> Result<Self>
    where P: key::KeyParts,
    {
        // If the key is already present on the certificate, then we
        // use the current self signature on that subkey as the
        // template.
        let (template, key_expiration): (SignatureBuilder, Option<SystemTime>)
            = vc.keys().subkeys()
            .filter_map(|ka| {
                if ka.key().parts_as_unspecified().public_eq(&subkey) {
                    let sig = ka.binding_signature().clone();
                    let e = sig.key_validity_period().map(|v| {
                        ka.key().creation_time() + v
                    });
                    Some((sig.into(), e))
                } else {
                    None
                }
            })
            .next()
            .or_else(|| {
                // The key is completely new.  Use the active self
                // signature on the newest, non-revoked, non-expired
                // subkey.
                vc.keys().subkeys().revoked(false).alive()
                    // Fallback to sorting by fingerprint to ensure
                    // this is deterministic.
                    .max_by_key(|ka| (ka.key().creation_time(), ka.fingerprint()))
                    .map(|ka| {
                        let sig = ka.binding_signature().clone();
                        let e = sig.key_validity_period().map(|v| {
                            ka.key().creation_time() + v
                        });
                        (sig.into(), e)
                    })
            })
            .unwrap_or_else(|| {
                // The certificate doesn't have any valid subkeys, so
                // we don't have existing signatures that we can use
                // as a template.  In this case, we use a default
                // binding signature, and the primary key's expiration
                // time.
                (SignatureBuilder::new(SignatureType::SubkeyBinding),
                 vc.primary_key().key_validity_period().map(|v| {
                     vc.primary_key().creation_time() + v
                 }))
            });

        let template = template.set_key_flags(subkey_flags)?;

        let mut builder = SubkeyBuilder {
            vc,
            primary_signer: None,
            subkey: subkey.parts_into_unspecified(),
            subkey_signer: None,
            template: SignatureBuilder::new(SignatureType::SubkeyBinding),
        };
        builder = builder.set_signature_template(template);
        builder = builder.set_key_expiration_time(key_expiration)?;

        Ok(builder)
    }

    /// Like SubkeyBuilder::new, but the binding signature is supplied.
    ///
    /// # Security Considerations
    ///
    /// The key validity period (i.e., the [Key Expiration Time
    /// subpacket]) is left as is.  **The Key Expiration Time
    /// subpacket contains a relative time.** Thus, if you are using a
    /// signature from another key with a different key creation time
    /// as a template, the effective key expiration time will be
    /// different!  In this case, you should set the key expiration
    /// time explicitly by calling
    /// [`SubkeyBuilder::set_key_expiration_time`] or
    /// [`SubkeyBuilder::set_key_validity_period`].
    ///
    ///   [Key Expiration Time subpacket]: https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.3.6
    ///
    /// # Examples
    ///
    /// Adjusting the key expiration time:
    ///
    /// ```
    /// use std::time::{SystemTime, Duration};
    ///
    /// use sequoia_openpgp as openpgp;
    /// use openpgp::cert::prelude::*;
    /// use openpgp::packet::Key;
    /// use openpgp::packet::key::Key4;
    /// use openpgp::policy::StandardPolicy;
    /// use openpgp::types::KeyFlags;
    ///
    /// # fn main() -> openpgp::Result<()> {
    /// let p = &StandardPolicy::new();
    ///
    /// let now = SystemTime::now();
    /// let year = Duration::new(365 * 24 * 60 * 60, 0);
    /// let last_year = now - year;
    /// // cert was created last year and expires after two years.
    /// let (cert, _) =
    ///     CertBuilder::new()
    ///         .set_creation_time(now - year)
    ///         .add_subkey(KeyFlags::empty().set_transport_encryption(),
    ///                     2 * year, None)
    ///         .generate()?;
    ///
    /// // Import a raw key and add it to the certificate.  We
    /// // explicitly reuse the existing subkey's signature, and adjust
    /// // the key expiration time.
    ///
    /// # let q = b"\x57\x15\x45\x1B\x68\xA5\x13\xA2\x20\x0F\x71\x9D\xE3\x05\x3B\xED\xA2\x21\xDE\x61\x5A\xF5\x67\x45\xBB\x97\x99\x43\x53\x59\x7C\x3F";
    /// let k: Key<_, _> = Key4::import_public_ed25519(q, now)?.into();
    ///
    /// let vc = cert.with_policy(p, now)?;
    /// let template
    ///     = vc.keys().subkeys().next().unwrap().binding_signature().clone();
    /// # let vc1 = vc.clone();
    /// let cert2 = SubkeyBuilder::new_with(vc, k, template)
    ///     .set_key_validity_period(year)?
    ///     .attach_cert()?;
    /// let vc2 = cert2.with_policy(p, now)?;
    /// # assert_eq!(vc1.keys().count() + 1, vc2.keys().count());
    ///
    /// // Observe that both keys expire one year from now.  If we
    /// // hadn't adjust the validity period of the new key, it would
    /// // have expired in two years from now, because the key validity
    /// // period is relative to the key's creation time!
    /// vc2.keys().subkeys().for_each(|sig| {
    ///     // SystemTime has a subsection resolution.
    ///     assert!((now + year)
    ///                 .duration_since(sig.key_expiration_time().unwrap())
    ///                 .unwrap()
    ///             < Duration::new(1, 0));
    /// });
    /// # Ok(())
    /// # }
    /// ```
    pub fn new_with<P, T>(vc: ValidCert<'a>,
                          subkey: Key<P, key::SubordinateRole>,
                          template: T)
        -> Self
    where P: key::KeyParts,
          T: Into<SignatureBuilder>,
    {
        let template = template.into();

        let mut builder = SubkeyBuilder {
            vc,
            primary_signer: None,
            subkey: subkey.parts_into_unspecified(),
            subkey_signer: None,
            template: SignatureBuilder::new(SignatureType::SubkeyBinding),
        };
        builder = builder.set_signature_template(template);
        builder
    }

    /// Sets the signature template that will be used for the binding
    /// signature.
    ///
    /// This effectively discards any previous calls to
    /// [`SubkeyBuilder::set_signature_creation_time`],
    /// [`SubkeyBuilder::set_key_expiration_time`], etc.
    ///
    /// This function modifies the template as follows:
    ///
    ///   - The hash algorithm is set to a safe default.
    ///
    /// These changes can be overridden by using
    /// [`SubkeyBuilder::with_signature_template`].
    ///
    /// # Security Considerations
    ///
    /// The key validity period (i.e., the [Key Expiration Time
    /// subpacket]) is left as is.  **This packet contains a relative
    /// time.** Thus, if you are using a Signature from another key
    /// with a different key creation time as a template, the
    /// effective key expiration time will be different!  In this
    /// case, you should set the key expiration time explicitly by
    /// calling [`SubkeyBuilder::set_key_expiration_time`] or
    /// [`SubkeyBuilder::set_key_validity_period`].
    ///
    ///   [Key Expiration Time subpacket]: https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.3.6
    pub fn set_signature_template<T>(mut self, template: T) -> Self
    where T: Into<SignatureBuilder>,
    {
        self.template = template.into();

        // GnuPG wants at least a 512-bit hash for P521 keys.
        self.template = self.template.set_hash_algo(HashAlgorithm::SHA512);

        self
    }

    /// Allows a function to directly modify the signature template.
    ///
    /// This function does not fail; it returns the result of the
    /// callback function.
    ///
    /// # Examples
    ///
    /// Add a notation to an existing key:
    ///
    /// ```
    /// use sequoia_openpgp as openpgp;
    /// use openpgp::cert::prelude::*;
    /// use openpgp::packet::signature::subpacket::NotationDataFlags;
    /// use openpgp::policy::StandardPolicy;
    /// use openpgp::types::KeyFlags;
    ///
    /// # fn main() -> openpgp::Result<()> {
    /// let p = &StandardPolicy::new();
    ///
    /// # let (cert, _) = CertBuilder::new().add_signing_subkey().generate()?;
    /// let vc = cert.with_policy(p, None)?;
    /// let cert2 = SubkeyBuilder::from(vc.keys().subkeys().next().unwrap())
    ///     .with_signature_template(|sig| {
    ///         sig.add_notation("policy@example.org", b"1",
    ///                          NotationDataFlags::empty().set_human_readable(),
    ///                          false /* critical */)
    ///     })?
    ///     .attach_cert()?;
    /// # let vc2 = cert2.with_policy(p, None)?;
    /// # assert_eq!(vc2.keys().count(), 2);
    /// # let ka = vc2.keys().subkeys().next().unwrap();
    /// # assert_eq!(ka.self_signatures().count(), 2);
    /// # assert_eq!(
    /// #     ka.binding_signature().notation("policy@example.org")
    /// #         .collect::<Vec<_>>(),
    /// #     vec![ b"1" ]);
    /// # Ok(())
    /// # }
    /// ```
    pub fn with_signature_template<F>(mut self, f: F) -> Result<Self>
    where F: FnOnce(SignatureBuilder) -> Result<SignatureBuilder>
    {
        self.template = f(self.template.clone())?;

        Ok(self)
    }

    /// Sets the binding signature's creation time.
    ///
    /// This directly modifies the current signature template.
    ///
    /// This just calls
    /// [`SignatureBuilder::set_signature_creation_time`] on the
    /// signature template.
    pub fn set_signature_creation_time<T>(mut self, creation_time: T)
        -> Result<Self>
    where T: Into<SystemTime>
    {
        self.template = self.template.set_signature_creation_time(
            creation_time.into())?;
        Ok(self)
    }

    /// Preserves the signature creation time set in the template.
    ///
    /// This directly modifies the current signature template.
    ///
    /// This just calls
    /// [`SignatureBuilder::preserve_signature_creation_time`] on the
    /// signature template.
    pub fn preserve_signature_creation_time(mut self) -> Result<Self>
    {
        self.template
            = self.template.preserve_signature_creation_time()?;
        Ok(self)
    }

    /// Sets the key's expiration time.
    ///
    /// This directly modifies the current signature template.
    ///
    /// This returns an error if the expiration time is before the
    /// key's creation time.
    pub fn set_key_expiration_time<T>(mut self, key_expiration_time: T)
        -> Result<Self>
    where T: Into<Option<SystemTime>>
    {
        let key_expiration_time = key_expiration_time.into();
        let validity_period = key_expiration_time
            .map(|e| {
                e.duration_since(self.subkey.creation_time())
                    .map_err(|_| {
                        Error::InvalidArgument(
                            "expiration time precedes creation time".into())
                    })
            })
            .transpose()?;

        self = self.with_signature_template(|sig| {
            sig.set_key_validity_period(validity_period)
        })?;

        Ok(self)
    }

    /// Sets the key's validity period.
    ///
    /// The validity period is the amount of time after the key's
    /// creation time that the key is considered fresh (i.e., not
    /// expired).
    ///
    /// This directly modifies the current signature template.
    pub fn set_key_validity_period<T>(mut self, validity: T)
        -> Result<Self>
    where T: Into<Option<Duration>>
    {
        self = self.with_signature_template(|sig| {
            sig.set_key_validity_period(validity.into())
        })?;

        Ok(self)
    }

    /// Returns a reference to the subkey.
    pub fn key(&self) -> &Key<key::UnspecifiedParts, key::SubordinateRole> {
        &self.subkey
    }

    /// Adds a signer for the primary key.
    ///
    /// In order to attach a subkey to a certificate one or more
    /// signatures need to be issued.  First, the primary key needs to
    /// issue a [subkey binding signature].  If the subkey is signing
    /// capable, then it also needs to issue a [primary key binding
    /// signature].  By default, [`SubkeyBuilder::attach`] will
    /// automatically derive the signers from the key material.  This
    /// only works, however, if the key material is present, and it is
    /// unencrypted.  This method allows you to explicitly provide a
    /// signer for the primary key.
    ///
    ///   [subkey binding signature]: https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.1
    ///   [primary binding signature]: https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.1
    pub fn set_primary_key_signer<S>(mut self, signer: S) -> Self
    where S: Signer + Send + Sync + 'a,
    {
        self.primary_signer = Some(Box::new(signer));
        self
    }

    /// Adds a signer for the subkey.
    ///
    /// In order to attach a subkey to a certificate one or more
    /// signatures need to be issued.  First, the primary key needs to
    /// issue a [subkey binding signature].  If the subkey is signing
    /// capable, then it also needs to issue a [primary key binding
    /// signature].  By default, [`SubkeyBuilder::attach`] will
    /// automatically derive the signers from the key material.  This
    /// only works, however, if the key material is present, and it is
    /// unencrypted.  This method allows you to explicitly provide a
    /// signer for the subkey.
    ///
    ///   [subkey binding signature]: https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.1
    ///   [primary binding signature]: https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.1
    pub fn set_subkey_signer<S>(mut self, signer: S) -> Self
    where S: Signer + Send + Sync + 'a,
    {
        self.subkey_signer = Some(Box::new(signer));
        self
    }

    /// Attaches the subkey to the certificate.
    ///
    /// This method generates the appropriate signatures to attach the
    /// subkey to the certificate.
    ///
    /// This function returns an error if the expiration time would
    /// cause the key to expire before the binding signature's
    /// expiration time.
    ///
    /// This method returns a number of packets, which need to be
    /// merged into the cert.  This can be done using
    /// [`Cert::insert_packets`].
    pub fn attach(self) -> Result<Vec<Packet>> {
        let SubkeyBuilder {
            vc,
            primary_signer,
            subkey,
            subkey_signer,
            template,
        } = self;

        if template.typ() != SignatureType::SubkeyBinding {
            return Err(Error::InvalidArgument(
                format!("Expected a SubkeyBinding signature, got a {}",
                        template.typ())).into());
        }

        let mut builder = template;

        let creation_time = builder.effective_signature_creation_time()?;

        // creation_time is only None if
        // preserve_signature_creation_time is done and that's a
        // Highly Advanced Interface that doesn't need sanity checks.
        if let Some(sig_ct) = creation_time {
            if let Some(v) = builder.key_validity_period() {
                let e = subkey.creation_time() + v;
                if let Err(err) = e.duration_since(sig_ct) {
                    return Err(Error::InvalidArgument(
                        format!(
                            "key expiration precedes signature creation time \
                             (by {:?})",
                            err.duration())).into());
                }
            }
        }

        if let Some(flags) = builder.key_flags() {
            if flags.for_certification() || flags.for_signing() {
                // We need to create a primary key binding signature.
                let mut subkey_signer = if let Some(signer) = subkey_signer {
                    signer
                } else {
                    Box::new(
                        subkey.clone().parts_into_secret()?.into_keypair()?)
                };

                let mut backsig =
                    SignatureBuilder::new(
                        SignatureType::PrimaryKeyBinding)
                    // GnuPG wants at least a 512-bit hash for P521 keys.
                    .set_hash_algo(HashAlgorithm::SHA512)
                    .set_reference_time(creation_time);
                if let Some(t) = creation_time {
                    backsig = backsig.set_reference_time(t);
                } else {
                    backsig = backsig.preserve_signature_creation_time()?;
                }
                let backsig = backsig.sign_primary_key_binding(
                    &mut *subkey_signer, &vc.primary_key(), &subkey)?;
                builder = builder.set_embedded_signature(backsig)?;
            } else {
                // We don't need the embedded signature, remove it.
                builder.hashed_area_mut()
                    .remove_all(SubpacketTag::EmbeddedSignature);
                builder.unhashed_area_mut()
                    .remove_all(SubpacketTag::EmbeddedSignature);
            }
        }

        let mut primary_signer = if let Some(signer) = primary_signer {
            signer
        } else {
            Box::new(
                vc.primary_key().key().clone()
                    .parts_into_secret()?.into_keypair()?)
        };

        let signature = subkey.bind(
            &mut *primary_signer, vc.cert(), builder)?;

        let subkey = if subkey.has_secret() {
            Packet::SecretSubkey(subkey.parts_into_secret().unwrap())
        } else {
            Packet::PublicSubkey(subkey.parts_into_public())
        };

        Ok(vec![subkey, signature.into()])
    }

    /// Attaches the subkey directly to the certificate.
    ///
    /// This function is like [`SubkeyBuilder::attach`], but it also
    /// merges the resulting packets into the certificate.
    ///
    /// Note: if you are adding multiple subkeys to a certificate or
    /// updating multiple subkeys, it is usually more efficient to use
    /// [`SubkeyBuilder::attach`], and then merge all of the packets
    /// at once.
    ///
    /// # Examples
    ///
    /// ```
    /// use sequoia_openpgp as openpgp;
    /// use openpgp::cert::prelude::*;
    /// use openpgp::policy::StandardPolicy;
    /// use openpgp::types::KeyFlags;
    ///
    /// # fn main() -> openpgp::Result<()> {
    /// let p = &StandardPolicy::new();
    ///
    /// # let (cert, _) =
    /// #     CertBuilder::general_purpose(None, Some("alice@example.org"))
    /// #         .generate()?;
    /// #
    /// let vc = cert.with_policy(p, None)?;
    /// # let vc1 = vc.clone();
    /// let cert2 = KeyBuilder::new(KeyFlags::empty().set_signing())
    ///     .subkey(vc)?
    ///     .attach_cert()?;
    /// # let vc2 = cert2.with_policy(p, None)?;
    /// # assert_eq!(vc1.keys().count() + 1, vc2.keys().count());
    /// # Ok(())
    /// # }
    /// ```
    pub fn attach_cert(self) -> Result<Cert> {
        let cert = self.vc.cert().clone();
        let packets = self.attach()?;
        Ok(cert.insert_packets(packets)?)
    }
}

impl<'a, P> From<ValidPrimaryKeyAmalgamation<'a, P>> for SubkeyBuilder<'a>
where
    P: key::KeyParts + Clone,
{
    fn from(ka: ValidPrimaryKeyAmalgamation<'a, P>) -> Self {
        ValidErasedKeyAmalgamation::from(ka).into()
    }
}

impl<'a, P> From<ValidSubordinateKeyAmalgamation<'a, P>> for SubkeyBuilder<'a>
where
    P: key::KeyParts + Clone,
{
    fn from(ka: ValidSubordinateKeyAmalgamation<'a, P>) -> Self {
        ValidErasedKeyAmalgamation::from(ka).into()
    }
}

impl<'a, P> From<ValidErasedKeyAmalgamation<'a, P>> for SubkeyBuilder<'a>
where
    P: key::KeyParts + Clone,
{
    fn from(ka: ValidErasedKeyAmalgamation<'a, P>) -> SubkeyBuilder<'a> {
        let key = ka.key().clone().role_into_subordinate();
        SubkeyBuilder::new_with(
            ka.cert().clone(), key, ka.binding_signature().clone())
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::time::{Duration, UNIX_EPOCH};

    use crate::policy::StandardPolicy;

    #[test]
    fn expiry() -> Result<()> {
        let p = &StandardPolicy::new();

        // t0: Create certificate, keys expire at t2.
        // t1: Add a new key, heuristic should have it expire at t2.
        // t2: All keys expire.

        // We do it all in the past to make sure the current time is
        // never used.

        // Avoid milliseconds.
        let t1 = crate::now() - Duration::new(7 * 24 * 60 * 60, 0);
        let t1 = t1.duration_since(UNIX_EPOCH)?.as_secs();
        let t1 = UNIX_EPOCH + Duration::new(t1, 0);

        let t0 = t1 - Duration::new(60 * 60, 0);
        let t2 = t1 + Duration::new(60 * 60, 0);
        let validity = t2.duration_since(t0).unwrap();

        let (pre, _) =
            CertBuilder::general_purpose(None, Some("alice@example.org"))
            .set_creation_time(t0)
            .set_validity_period(validity)
            .generate()?;

        let vc_pre = pre.with_policy(p, t1)?;
        let post = KeyBuilder::new(KeyFlags::empty().set_signing())
            .set_creation_time(t1)
            .subkey(vc_pre)?
            .set_signature_creation_time(t1)?
            .attach_cert()?;

        let vc_post = post.with_policy(p, t1).unwrap();

        // We should have one more key.
        assert_eq!(pre.keys().count() + 1, post.keys().count());

        // Make sure the signature and backsig are valid.
        assert_eq!(post.keys().count(), vc_post.keys().count());

        // And the new key should have inherited the other keys'
        // expiration.
        eprintln!("t0: {:?}", t0);
        eprintln!("t1: {:?}", t1);
        eprintln!("t2: {:?}", t2);
        assert!(vc_post.keys().all(|ka| {
            eprintln!("{}: {:?} -> {:?}",
                      ka.fingerprint(),
                      ka.creation_time(),
                      ka.key_expiration_time());
            ka.key_expiration_time() == Some(t2)
        }));

        Ok(())
    }
}