1use std::{
4 backtrace::Backtrace,
5 borrow::{Borrow, Cow},
6 collections::HashSet,
7 fmt::{Debug, Display},
8 str::FromStr,
9 string::FromUtf8Error,
10};
11
12use base64ct::{Base64, Encoding as _};
13use chrono::{DateTime, Utc};
14use digest::DynDigest;
15use ed25519_dalek::VerifyingKey;
16use email_address::{EmailAddress, Options};
17use log::{error, warn};
18use pgp::{
19 composed::{
20 ArmorOptions,
21 Deserializable as _,
22 SignedPublicKey,
23 SignedSecretKey,
24 StandaloneSignature,
25 },
26 crypto::{hash::HashAlgorithm, public_key::PublicKeyAlgorithm},
27 packet::{
28 KeyFlags,
29 Notation,
30 PacketTrait,
31 PubKeyInner,
32 PublicKey,
33 Signature,
34 SignatureConfig,
35 SignatureType,
36 Subpacket,
37 SubpacketData,
38 UserId,
39 },
40 ser::Serialize,
41 types::{
42 CompressionAlgorithm,
43 EcdsaPublicParams,
44 KeyDetails as _,
45 KeyId,
46 KeyVersion,
47 Mpi,
48 Password,
49 PlainSecretParams,
50 PublicKeyTrait as _,
51 PublicParams,
52 RsaPublicParams,
53 SecretKeyTrait,
54 SecretParams,
55 SignatureBytes,
56 SignedUser,
57 },
58};
59use picky_asn1_x509::{
60 AlgorithmIdentifier,
61 DigestInfo,
62 ShaVariant,
63 signature::EcdsaSignatureValue,
64};
65use rsa::BigUint;
66use rsa::traits::PublicKeyParts as _;
67use sha2::digest::Digest as _;
68
69use crate::{KeyMechanism, KeyType, NetHsm, PrivateKeyImport, key_type_matches_length};
70
71#[derive(Debug, thiserror::Error)]
73pub enum Error {
74 #[error("Decoding Base64 string failed: {0}")]
76 Base64Decode(#[from] base64ct::Error),
77
78 #[error("Certificate for the key \"{0}\" has not been initialized")]
80 CertificateMissing(crate::KeyId),
81
82 #[error("Elliptic curve error: {0}")]
84 EllipticCurve(#[from] p256::elliptic_curve::Error),
85
86 #[error("The OpenPGP User ID {user_id} is used more than once!")]
88 DuplicateUserId {
89 user_id: OpenPgpUserId,
91 },
92
93 #[error("Invalid OpenPGP version: {0}")]
95 InvalidOpenPgpVersion(String),
96
97 #[error("Key data invalid: {0}")]
99 KeyData(String),
100
101 #[error("NetHSM error: {0}")]
103 NetHsm(String),
104
105 #[error("rPGP error: {0}")]
107 Pgp(#[from] pgp::errors::Error),
108
109 #[error("Transferable Secret Key is passphrase protected")]
111 PrivateKeyPassphraseProtected,
112
113 #[error("Unsupported multiple component keys")]
115 UnsupportedMultipleComponentKeys,
116
117 #[error("Unsupported key format: {public_params:?}")]
119 UnsupportedKeyFormat {
120 public_params: Box<PublicParams>,
122 },
123
124 #[error("The OpenPGP User ID is too large: {user_id}")]
126 UserIdTooLarge {
127 user_id: String,
129 },
130
131 #[error("Creating a valid UTF-8 string from bytes failed while {context}:\n{source}")]
133 FromUtf8 {
134 context: &'static str,
139 source: FromUtf8Error,
141 },
142}
143
144#[derive(
146 Clone,
147 Copy,
148 Debug,
149 Default,
150 serde::Deserialize,
151 strum::Display,
152 strum::EnumIter,
153 Hash,
154 strum::IntoStaticStr,
155 Eq,
156 PartialEq,
157 serde::Serialize,
158)]
159#[serde(into = "String", try_from = "String")]
160pub enum OpenPgpVersion {
161 #[default]
165 #[strum(to_string = "4")]
166 V4,
167
168 #[strum(to_string = "6")]
172 V6,
173}
174
175impl AsRef<str> for OpenPgpVersion {
176 fn as_ref(&self) -> &str {
177 match self {
178 Self::V4 => "4",
179 Self::V6 => "6",
180 }
181 }
182}
183
184impl FromStr for OpenPgpVersion {
185 type Err = Error;
186
187 fn from_str(s: &str) -> Result<Self, Self::Err> {
215 match s {
216 "4" | "v4" | "V4" | "OpenPGPv4" => Ok(Self::V4),
217 "5" | "v5" | "V5" | "OpenPGPv5" => Err(Error::InvalidOpenPgpVersion(format!(
218 "{s} (\"we don't do these things around here\")"
219 ))),
220 "6" | "v6" | "V6" | "OpenPGPv6" => Ok(Self::V6),
221 _ => Err(Error::InvalidOpenPgpVersion(s.to_string())),
222 }
223 }
224}
225
226impl From<OpenPgpVersion> for String {
227 fn from(value: OpenPgpVersion) -> Self {
228 value.to_string()
229 }
230}
231
232impl TryFrom<KeyVersion> for OpenPgpVersion {
233 type Error = Error;
234
235 fn try_from(value: KeyVersion) -> Result<Self, Self::Error> {
241 Ok(match value {
242 KeyVersion::V4 => Self::V4,
243 KeyVersion::V6 => Self::V6,
244 _ => {
245 return Err(Error::InvalidOpenPgpVersion(
246 Into::<u8>::into(value).to_string(),
247 ));
248 }
249 })
250 }
251}
252
253impl TryFrom<String> for OpenPgpVersion {
254 type Error = Error;
255
256 fn try_from(value: String) -> Result<Self, Self::Error> {
257 Self::from_str(&value)
258 }
259}
260
261#[derive(Clone, Debug, Eq, Hash, PartialEq)]
263enum OpenPgpUserIdType {
264 Email(EmailAddress),
270
271 Plain(String),
275}
276
277#[derive(Clone, Debug, serde::Deserialize, Eq, Hash, PartialEq, serde::Serialize)]
290#[serde(into = "String", try_from = "String")]
291pub struct OpenPgpUserId(OpenPgpUserIdType);
292
293impl OpenPgpUserId {
294 pub fn new(user_id: String) -> Result<Self, Error> {
323 if user_id.len() > 4096 {
324 return Err(Error::UserIdTooLarge { user_id });
325 }
326 if let Ok(email) = EmailAddress::parse_with_options(
327 &user_id,
328 Options::default()
329 .with_required_tld()
330 .without_domain_literal(),
331 ) {
332 Ok(Self(OpenPgpUserIdType::Email(email)))
333 } else {
334 Ok(Self(OpenPgpUserIdType::Plain(user_id)))
335 }
336 }
337
338 pub fn is_email(&self) -> bool {
353 matches!(self.0, OpenPgpUserIdType::Email(..))
354 }
355}
356
357impl AsRef<str> for OpenPgpUserId {
358 fn as_ref(&self) -> &str {
359 match self.0.borrow() {
360 OpenPgpUserIdType::Email(user_id) => user_id.as_str(),
361 OpenPgpUserIdType::Plain(user_id) => user_id.as_str(),
362 }
363 }
364}
365
366impl Display for OpenPgpUserId {
367 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
368 write!(f, "{}", self.as_ref())
369 }
370}
371
372impl FromStr for OpenPgpUserId {
373 type Err = Error;
374
375 fn from_str(s: &str) -> Result<Self, Self::Err> {
376 Self::new(s.to_string())
377 }
378}
379
380impl From<OpenPgpUserId> for String {
381 fn from(value: OpenPgpUserId) -> Self {
382 value.to_string()
383 }
384}
385
386impl TryFrom<&SignedUser> for OpenPgpUserId {
387 type Error = Error;
388
389 fn try_from(value: &SignedUser) -> Result<Self, Self::Error> {
396 Self::new(
397 String::from_utf8(value.id.id().to_vec()).map_err(|source| Error::FromUtf8 {
398 context: "converting an OpenPGP UserID",
399 source,
400 })?,
401 )
402 }
403}
404
405impl TryFrom<String> for OpenPgpUserId {
406 type Error = Error;
407
408 fn try_from(value: String) -> Result<Self, Self::Error> {
409 Self::new(value)
410 }
411}
412
413#[derive(Clone, Debug, serde::Deserialize, Eq, Hash, PartialEq, serde::Serialize)]
417#[serde(into = "Vec<String>", try_from = "Vec<String>")]
418pub struct OpenPgpUserIdList(Vec<OpenPgpUserId>);
419
420impl OpenPgpUserIdList {
421 pub fn new(user_ids: Vec<OpenPgpUserId>) -> Result<Self, Error> {
450 let mut set = HashSet::new();
451 for user_id in user_ids.iter() {
452 if !set.insert(user_id) {
453 return Err(Error::DuplicateUserId {
454 user_id: user_id.to_owned(),
455 });
456 }
457 }
458 Ok(Self(user_ids))
459 }
460
461 pub fn iter(&self) -> impl Iterator<Item = &OpenPgpUserId> {
463 self.0.iter()
464 }
465
466 pub fn first(&self) -> Option<&OpenPgpUserId> {
468 self.0.first()
469 }
470}
471
472impl AsRef<[OpenPgpUserId]> for OpenPgpUserIdList {
473 fn as_ref(&self) -> &[OpenPgpUserId] {
474 &self.0
475 }
476}
477
478impl From<OpenPgpUserIdList> for Vec<String> {
479 fn from(value: OpenPgpUserIdList) -> Self {
480 value
481 .iter()
482 .map(|user_id| user_id.to_string())
483 .collect::<Vec<String>>()
484 }
485}
486
487impl TryFrom<Vec<String>> for OpenPgpUserIdList {
488 type Error = Error;
489
490 fn try_from(value: Vec<String>) -> Result<Self, Self::Error> {
491 let user_ids = {
492 let mut user_ids: Vec<OpenPgpUserId> = vec![];
493 for user_id in value {
494 user_ids.push(OpenPgpUserId::new(user_id)?)
495 }
496 user_ids
497 };
498 OpenPgpUserIdList::new(user_ids)
499 }
500}
501
502struct HsmKey<'a, 'b> {
507 public_key: PublicKey,
508 nethsm: &'a NetHsm,
509 key_id: &'b crate::KeyId,
510}
511
512impl Debug for HsmKey<'_, '_> {
513 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
514 f.debug_struct("HsmKey")
515 .field("public_key", &self.public_key)
516 .field("key_id", &self.key_id)
517 .finish()
518 }
519}
520
521#[inline]
527fn to_rpgp_error(e: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> pgp::errors::Error {
528 pgp::errors::Error::IO {
529 source: std::io::Error::other(e),
530 backtrace: Some(Backtrace::capture()),
531 }
532}
533
534fn parse_signature(sig_type: crate::SignatureType, sig: &[u8]) -> pgp::errors::Result<Vec<Mpi>> {
536 use crate::SignatureType;
537 Ok(match sig_type {
538 SignatureType::EcdsaP256 | SignatureType::EcdsaP384 | SignatureType::EcdsaP521 => {
539 let sig: EcdsaSignatureValue = picky_asn1_der::from_bytes(sig).map_err(|e| {
540 error!("DER decoding error when parsing ECDSA signature: {e:?}");
541 to_rpgp_error(e)
542 })?;
543 vec![
544 Mpi::from_slice(sig.r.as_unsigned_bytes_be()),
545 Mpi::from_slice(sig.s.as_unsigned_bytes_be()),
546 ]
547 }
548 SignatureType::EdDsa => {
549 if sig.len() != 64 {
550 return Err(pgp::errors::Error::InvalidKeyLength);
551 }
552
553 vec![Mpi::from_slice(&sig[..32]), Mpi::from_slice(&sig[32..])]
554 }
555 SignatureType::Pkcs1 => {
556 vec![Mpi::from_slice(sig)]
558 }
559 _ => {
560 warn!("Unsupported signature type: {sig_type}");
561 return Err(pgp::errors::Error::InvalidInput {
562 backtrace: Some(Backtrace::capture()),
563 });
564 }
565 })
566}
567
568impl<'a, 'b> HsmKey<'a, 'b> {
569 fn new(nethsm: &'a NetHsm, public_key: PublicKey, key_id: &'b crate::KeyId) -> Self {
571 Self {
572 nethsm,
573 public_key,
574 key_id,
575 }
576 }
577
578 fn sign_mode(&self) -> pgp::errors::Result<crate::SignatureType> {
580 Ok(match self.public_key.public_params() {
581 PublicParams::ECDSA(ecdsa) => match ecdsa {
582 EcdsaPublicParams::P256 { .. } => crate::SignatureType::EcdsaP256,
583 EcdsaPublicParams::P384 { .. } => crate::SignatureType::EcdsaP384,
584 EcdsaPublicParams::P521 { .. } => crate::SignatureType::EcdsaP521,
585 _ => {
586 warn!("Unsupported ECDSA parameter type: {ecdsa:?}");
587 return Err(pgp::errors::Error::InvalidInput {
588 backtrace: Some(Backtrace::capture()),
589 });
590 }
591 },
592 PublicParams::EdDSALegacy { .. } => crate::SignatureType::EdDsa,
593 PublicParams::RSA { .. } => crate::SignatureType::Pkcs1,
594 params => {
595 warn!("Unsupported signing parameters: {params:?}");
596 return Err(pgp::errors::Error::InvalidInput {
597 backtrace: Some(Backtrace::capture()),
598 });
599 }
600 })
601 }
602}
603
604impl pgp::types::KeyDetails for HsmKey<'_, '_> {
605 fn version(&self) -> KeyVersion {
606 self.public_key.version()
607 }
608
609 fn fingerprint(&self) -> pgp::types::Fingerprint {
610 self.public_key.fingerprint()
611 }
612
613 fn key_id(&self) -> KeyId {
614 self.public_key.key_id()
615 }
616
617 fn algorithm(&self) -> PublicKeyAlgorithm {
618 self.public_key.algorithm()
619 }
620}
621
622fn prepare_digest_data(
632 signature_type: crate::SignatureType,
633 hash: HashAlgorithm,
634 digest: &[u8],
635) -> pgp::errors::Result<Cow<'_, [u8]>> {
636 Ok(match signature_type {
637 crate::SignatureType::Pkcs1 => picky_asn1_der::to_vec(&DigestInfo {
642 oid: hash_to_oid(hash)?,
643 digest: digest.to_vec().into(),
644 })
645 .map_err(|e| {
646 error!("Encoding signature to PKCS#1 format failed: {e:?}");
647 to_rpgp_error(e)
648 })?
649 .into(),
650
651 crate::SignatureType::EcdsaP224 => digest[..usize::min(28, digest.len())].into(),
654 crate::SignatureType::EcdsaP256 => digest[..usize::min(32, digest.len())].into(),
655 crate::SignatureType::EcdsaP384 => digest[..usize::min(48, digest.len())].into(),
656
657 _ => digest.into(),
660 })
661}
662
663impl SecretKeyTrait for HsmKey<'_, '_> {
664 fn create_signature(
681 &self,
682 _key_pw: &Password,
683 hash: HashAlgorithm,
684 data: &[u8],
685 ) -> pgp::errors::Result<SignatureBytes> {
686 let signature_type = self.sign_mode()?;
687 let request_data = prepare_digest_data(signature_type, hash, data)?;
688
689 let sig = self
690 .nethsm
691 .sign_digest(self.key_id, signature_type, &request_data)
692 .map_err(|e| {
693 error!("NetHsm::sign_digest failed: {e:?}");
694 to_rpgp_error(e)
695 })?;
696
697 Ok(SignatureBytes::Mpis(parse_signature(signature_type, &sig)?))
698 }
699
700 fn hash_alg(&self) -> HashAlgorithm {
706 HashAlgorithm::Sha512
707 }
708}
709
710pub fn add_certificate(
712 nethsm: &NetHsm,
713 flags: KeyUsageFlags,
714 key_id: &crate::KeyId,
715 user_id: OpenPgpUserId,
716 created_at: DateTime<Utc>,
717 version: OpenPgpVersion,
718) -> Result<Vec<u8>, Error> {
719 if version != OpenPgpVersion::V4 {
720 unimplemented!(
721 "Support for creating OpenPGP {version} certificates is not yet implemented!"
722 );
723 }
724
725 let public_key = nethsm.get_key(key_id).map_err(to_rpgp_error)?;
726 let signer = HsmKey::new(nethsm, hsm_pk_to_pgp_pk(public_key, created_at)?, key_id);
727
728 let composed_pk = pgp::composed::PublicKey::new(
729 signer.public_key.clone(),
730 pgp::composed::KeyDetails::new(
731 Some(UserId::from_str(Default::default(), user_id.as_ref())?),
732 vec![],
733 vec![],
734 flags.into(),
735 Default::default(),
736 Default::default(),
737 Default::default(),
738 vec![CompressionAlgorithm::Uncompressed].into(),
739 vec![].into(),
740 ),
741 vec![],
742 );
743
744 let signed_pk = composed_pk.sign(
745 rand::thread_rng(),
746 &signer,
747 &signer.public_key,
748 &Password::empty(),
749 )?;
750
751 let mut buffer = vec![];
752 signed_pk.to_writer(&mut buffer)?;
753 Ok(buffer)
754}
755
756fn hash_to_oid(hash: HashAlgorithm) -> pgp::errors::Result<AlgorithmIdentifier> {
758 Ok(AlgorithmIdentifier::new_sha(match hash {
759 HashAlgorithm::Sha1 => ShaVariant::SHA1,
760 HashAlgorithm::Sha256 => ShaVariant::SHA2_256,
761 HashAlgorithm::Sha384 => ShaVariant::SHA2_384,
762 HashAlgorithm::Sha512 => ShaVariant::SHA2_512,
763 HashAlgorithm::Sha224 => ShaVariant::SHA2_224,
764 HashAlgorithm::Sha3_256 => ShaVariant::SHA3_256,
765 HashAlgorithm::Sha3_512 => ShaVariant::SHA3_512,
766 _ => {
767 warn!("Unsupported hash algorithm: {hash}");
768 return Err(pgp::errors::Error::InvalidInput {
769 backtrace: Some(Backtrace::capture()),
770 });
771 }
772 }))
773}
774
775pub fn tsk_to_private_key_import(
785 key_data: &[u8],
786) -> Result<(PrivateKeyImport, KeyMechanism), Error> {
787 let key = SignedSecretKey::from_bytes(key_data)?;
788 if !key.secret_subkeys.is_empty() {
789 return Err(Error::UnsupportedMultipleComponentKeys);
790 }
791 let SecretParams::Plain(secret) = key.primary_key.secret_params() else {
792 return Err(Error::PrivateKeyPassphraseProtected);
793 };
794 Ok(match (secret, key.public_key().public_params()) {
795 (PlainSecretParams::RSA(secret), PublicParams::RSA(public)) => {
796 key_type_matches_length(
798 KeyType::Rsa,
799 Some(public.key.n().to_bytes_be().len() as u32 * 8),
800 )
801 .map_err(to_rpgp_error)?;
802
803 let (_d, p, q, _u) = secret.to_bytes();
804
805 (
806 PrivateKeyImport::from_rsa(p, q, public.key.e().to_bytes_be().to_vec()),
807 KeyMechanism::RsaSignaturePkcs1,
808 )
809 }
810 (PlainSecretParams::ECDSA(secret_key), _) => {
811 let ec = if let PublicParams::ECDSA(pp) = key.primary_key.public_key().public_params() {
812 match pp {
813 EcdsaPublicParams::P256 { .. } => crate::KeyType::EcP256,
814 EcdsaPublicParams::P384 { .. } => crate::KeyType::EcP384,
815 EcdsaPublicParams::P521 { .. } => crate::KeyType::EcP521,
816 pp => {
817 warn!("Unsupported ECDSA parameters: {pp:?}");
818 return Err(Error::UnsupportedKeyFormat {
819 public_params: Box::new(key.public_key().public_params().clone()),
820 })?;
821 }
822 }
823 } else {
824 return Err(Error::UnsupportedKeyFormat {
825 public_params: Box::new(key.public_key().public_params().clone()),
826 });
827 };
828
829 let bytes = match secret_key {
830 pgp::crypto::ecdsa::SecretKey::P256(secret_key) => secret_key.to_bytes().to_vec(),
831 pgp::crypto::ecdsa::SecretKey::P384(secret_key) => secret_key.to_bytes().to_vec(),
832 pgp::crypto::ecdsa::SecretKey::P521(secret_key) => secret_key.to_bytes().to_vec(),
833
834 pgp::crypto::ecdsa::SecretKey::Secp256k1(secret_key) => {
835 secret_key.to_bytes().to_vec()
836 }
837 secret_key => {
838 warn!("Unsupported secret key parameters: {secret_key:?}");
839 return Err(Error::UnsupportedKeyFormat {
840 public_params: Box::new(key.public_key().public_params().clone()),
841 })?;
842 }
843 };
844
845 (
846 PrivateKeyImport::from_raw_bytes(ec, bytes).map_err(to_rpgp_error)?,
847 KeyMechanism::EcdsaSignature,
848 )
849 }
850 (PlainSecretParams::Ed25519Legacy(bytes), _) => (
851 PrivateKeyImport::from_raw_bytes(crate::KeyType::Curve25519, bytes.as_bytes())
852 .map_err(to_rpgp_error)?,
853 KeyMechanism::EdDsaSignature,
854 ),
855 (_, public_params) => {
856 return Err(Error::UnsupportedKeyFormat {
857 public_params: Box::new(public_params.clone()),
858 });
859 }
860 })
861}
862
863pub fn sign(nethsm: &NetHsm, key_id: &crate::KeyId, message: &[u8]) -> Result<Vec<u8>, Error> {
904 let Some(public_key) = nethsm.get_key_certificate(key_id).map_err(to_rpgp_error)? else {
905 return Err(Error::CertificateMissing(key_id.clone()));
906 };
907
908 let signer = HsmKey::new(
909 nethsm,
910 SignedPublicKey::from_bytes(&*public_key)?.primary_key,
911 key_id,
912 );
913
914 let mut sig_config =
915 SignatureConfig::v4(SignatureType::Binary, signer.algorithm(), signer.hash_alg());
916 sig_config.hashed_subpackets = vec![
917 Subpacket::regular(SubpacketData::SignatureCreationTime(
918 std::time::SystemTime::now().into(),
919 ))?,
920 Subpacket::regular(SubpacketData::Issuer(signer.key_id()))?,
921 Subpacket::regular(SubpacketData::IssuerFingerprint(signer.fingerprint()))?,
922 ];
923
924 let mut hasher = sig_config.hash_alg.new_hasher().map_err(to_rpgp_error)?;
925 sig_config.hash_data_to_sign(&mut hasher, message)?;
926
927 let len = sig_config.hash_signature_data(&mut hasher)?;
928
929 hasher.update(&sig_config.trailer(len)?);
930
931 let hash = &hasher.finalize()[..];
932
933 let signed_hash_value = [hash[0], hash[1]];
934 let raw_sig = signer.create_signature(&Password::empty(), sig_config.hash_alg, hash)?;
935
936 let signature = Signature::from_config(sig_config, signed_hash_value, raw_sig)?;
937
938 let mut out = vec![];
939 signature.to_writer_with_header(&mut out)?;
940
941 Ok(out)
942}
943
944#[derive(Clone, Default)]
954struct Hasher(sha2::Sha512);
955
956impl DynDigest for Hasher {
957 fn update(&mut self, data: &[u8]) {
961 self.0.update(data);
962 }
963
964 fn finalize_into(self, buf: &mut [u8]) -> Result<(), digest::InvalidBufferSize> {
970 sha2::digest::DynDigest::finalize_into(self.0, buf)
971 .map_err(|_| digest::InvalidBufferSize)?;
972 Ok(())
973 }
974
975 fn finalize_into_reset(&mut self, out: &mut [u8]) -> Result<(), digest::InvalidBufferSize> {
981 sha2::digest::DynDigest::finalize_into_reset(&mut self.0, out)
982 .map_err(|_| digest::InvalidBufferSize)?;
983 Ok(())
984 }
985
986 fn reset(&mut self) {
988 sha2::digest::DynDigest::reset(&mut self.0)
989 }
990
991 fn output_size(&self) -> usize {
993 sha2::digest::DynDigest::output_size(&self.0)
994 }
995
996 fn box_clone(&self) -> Box<dyn DynDigest> {
998 Box::new(self.clone())
999 }
1000}
1001
1002pub fn sign_hasher_state(
1037 nethsm: &NetHsm,
1038 key_id: &crate::KeyId,
1039 state: sha2::Sha512,
1040) -> Result<String, Error> {
1041 let Some(public_key) = nethsm.get_key_certificate(key_id).map_err(to_rpgp_error)? else {
1042 return Err(Error::CertificateMissing(key_id.clone()));
1043 };
1044
1045 let signer = HsmKey::new(
1046 nethsm,
1047 SignedPublicKey::from_bytes(public_key.as_slice())?.primary_key,
1048 key_id,
1049 );
1050
1051 let hasher = state.clone();
1052
1053 let file_hash = Box::new(hasher).finalize().to_vec();
1054
1055 let sig_config = {
1056 let mut sig_config =
1057 SignatureConfig::v4(SignatureType::Binary, signer.algorithm(), signer.hash_alg());
1058 sig_config.hashed_subpackets = vec![
1059 Subpacket::regular(SubpacketData::SignatureCreationTime(
1060 std::time::SystemTime::now().into(),
1061 ))?,
1062 Subpacket::regular(SubpacketData::Issuer(signer.key_id()))?,
1063 Subpacket::regular(SubpacketData::IssuerFingerprint(signer.fingerprint()))?,
1064 Subpacket::regular(SubpacketData::Notation(Notation {
1065 readable: false,
1066 name: "data-digest@archlinux.org".into(),
1067 value: file_hash.into(),
1068 }))?,
1069 ];
1070 sig_config
1071 };
1072
1073 let mut hasher = Box::new(Hasher(state.clone())) as Box<dyn DynDigest + Send>;
1074
1075 let len = sig_config.hash_signature_data(&mut hasher)?;
1076
1077 hasher.update(&sig_config.trailer(len)?);
1078
1079 let hash = &hasher.finalize()[..];
1080
1081 let signed_hash_value = [hash[0], hash[1]];
1082
1083 let raw_sig = signer.create_signature(&Password::empty(), sig_config.hash_alg, hash)?;
1084
1085 let signature = pgp::packet::Signature::from_config(sig_config, signed_hash_value, raw_sig)?;
1086
1087 let signature = StandaloneSignature { signature };
1088 Ok(signature.to_armored_string(ArmorOptions::default())?)
1089}
1090
1091fn ecdsa_to_public_key(
1102 created_at: DateTime<Utc>,
1103 key: EcdsaPublicParams,
1104) -> Result<PublicKey, Error> {
1105 Ok(PublicKey::from_inner(PubKeyInner::new(
1106 KeyVersion::V4,
1107 PublicKeyAlgorithm::ECDSA,
1108 created_at,
1109 None,
1110 PublicParams::ECDSA(key),
1111 )?)?)
1112}
1113
1114fn data_to_bytes(data: Option<&str>) -> Result<Vec<u8>, Error> {
1123 Ok(Base64::decode_vec(data.ok_or(Error::KeyData(
1124 "missing EC public key data".into(),
1125 ))?)?)
1126}
1127
1128fn hsm_pk_to_pgp_pk(
1134 pk: nethsm_sdk_rs::models::PublicKey,
1135 created_at: DateTime<Utc>,
1136) -> Result<PublicKey, Error> {
1137 let public = &pk
1138 .public
1139 .ok_or(Error::KeyData("missing public key data".into()))?;
1140
1141 let key_type: KeyType = pk.r#type.into();
1142 Ok(match key_type {
1143 KeyType::Rsa => PublicKey::from_inner(PubKeyInner::new(
1144 KeyVersion::V4,
1145 PublicKeyAlgorithm::RSA,
1146 created_at,
1147 None,
1148 PublicParams::RSA(RsaPublicParams {
1149 key: rsa::RsaPublicKey::new(
1150 BigUint::from_bytes_be(&Base64::decode_vec(
1151 public
1152 .modulus
1153 .as_ref()
1154 .ok_or(Error::KeyData("missing RSA modulus".into()))?,
1155 )?),
1156 BigUint::from_bytes_be(&Base64::decode_vec(
1157 public
1158 .public_exponent
1159 .as_ref()
1160 .ok_or(Error::KeyData("missing RSA exponent".into()))?,
1161 )?),
1162 )
1163 .map_err(to_rpgp_error)?,
1164 }),
1165 )?)?,
1166
1167 KeyType::Curve25519 => {
1168 let pubkey: &[u8] = &data_to_bytes(public.data.as_deref())?;
1169
1170 PublicKey::from_inner(PubKeyInner::new(
1171 KeyVersion::V4,
1172 PublicKeyAlgorithm::EdDSALegacy,
1173 created_at,
1174 None,
1175 PublicParams::EdDSALegacy(pgp::types::EddsaLegacyPublicParams::Ed25519 {
1176 key: VerifyingKey::from_bytes(pubkey.try_into().map_err(to_rpgp_error)?)
1177 .map_err(to_rpgp_error)?,
1178 }),
1179 )?)?
1180 }
1181
1182 KeyType::EcP256 => ecdsa_to_public_key(
1183 created_at,
1184 EcdsaPublicParams::P256 {
1185 key: p256::PublicKey::from_sec1_bytes(&data_to_bytes(public.data.as_deref())?)?,
1186 },
1187 )?,
1188 KeyType::EcP384 => ecdsa_to_public_key(
1189 created_at,
1190 EcdsaPublicParams::P384 {
1191 key: p384::PublicKey::from_sec1_bytes(&data_to_bytes(public.data.as_deref())?)?,
1192 },
1193 )?,
1194 KeyType::EcP521 => ecdsa_to_public_key(
1195 created_at,
1196 EcdsaPublicParams::P521 {
1197 key: p521::PublicKey::from_sec1_bytes(&data_to_bytes(public.data.as_deref())?)?,
1198 },
1199 )?,
1200
1201 _ => {
1202 warn!("Unsupported key type: {key_type}");
1203 return Err(pgp::errors::Error::InvalidInput {
1204 backtrace: Some(Backtrace::capture()),
1205 })?;
1206 }
1207 })
1208}
1209
1210pub fn extract_certificate(key_data: &[u8]) -> Result<Vec<u8>, Error> {
1219 let key = SignedSecretKey::from_bytes(key_data)?;
1220 let public: SignedPublicKey = key.into();
1221 let mut buffer = vec![];
1222 public.to_writer(&mut buffer)?;
1223 Ok(buffer)
1224}
1225
1226#[derive(Debug, Default)]
1228pub struct KeyUsageFlags(KeyFlags);
1229
1230impl KeyUsageFlags {
1231 pub fn set_sign(&mut self) {
1233 self.0.set_sign(true);
1234 }
1235
1236 pub fn clear_sign(&mut self) {
1238 self.0.set_sign(false);
1239 }
1240}
1241
1242impl AsRef<KeyFlags> for KeyUsageFlags {
1243 fn as_ref(&self) -> &KeyFlags {
1244 &self.0
1245 }
1246}
1247
1248impl From<KeyUsageFlags> for KeyFlags {
1249 fn from(value: KeyUsageFlags) -> Self {
1250 value.0
1251 }
1252}
1253
1254#[cfg(test)]
1255mod tests {
1256 use nethsm_sdk_rs::models::{KeyMechanism, KeyPublicData, KeyRestrictions, KeyType};
1257 use pgp::types::{EcdsaPublicParams, PublicParams};
1258 use rstest::rstest;
1259 use testresult::TestResult;
1260
1261 use super::*;
1262
1263 #[test]
1264 fn convert_ed25519_to_pgp() -> TestResult {
1265 let hsm_key = nethsm_sdk_rs::models::PublicKey {
1266 mechanisms: vec![KeyMechanism::EdDsaSignature],
1267 r#type: KeyType::Curve25519,
1268 restrictions: Box::new(KeyRestrictions {
1269 tags: Some(vec!["signing1".into()]),
1270 }),
1271 public: Some(Box::new(KeyPublicData {
1272 modulus: None,
1273 public_exponent: None,
1274 data: Some("/ODoaDzX9xDjpx2LfR0DCIgdxqOndY9tukEFLVCObQo=".into()),
1275 })),
1276 operations: 1,
1277 };
1278
1279 let pgp_key = hsm_pk_to_pgp_pk(hsm_key, DateTime::UNIX_EPOCH)?;
1280 let PublicParams::EdDSALegacy(pgp::types::EddsaLegacyPublicParams::Ed25519 { key }) =
1281 pgp_key.public_params()
1282 else {
1283 panic!("Wrong type of public params");
1284 };
1285 assert_eq!(
1286 key.to_bytes(),
1287 [
1288 252, 224, 232, 104, 60, 215, 247, 16, 227, 167, 29, 139, 125, 29, 3, 8, 136, 29,
1289 198, 163, 167, 117, 143, 109, 186, 65, 5, 45, 80, 142, 109, 10
1290 ]
1291 );
1292
1293 Ok(())
1294 }
1295
1296 #[test]
1297 fn convert_p256_to_pgp() -> TestResult {
1298 let hsm_key = nethsm_sdk_rs::models::PublicKey {
1299 mechanisms: vec![KeyMechanism::EcdsaSignature],
1300 r#type: KeyType::EcP256,
1301 restrictions: Box::new(KeyRestrictions {
1302 tags: Some(vec!["signing2".into()]),
1303 }),
1304 public: Some(Box::new(KeyPublicData {
1305 modulus: None,
1306 public_exponent: None,
1307 data: Some(
1308 "BN5q7GCR8w1RtXdMBR1IcIaCqbbn92vM5LItTcRbdXo5RfDwhnKK6D8tjWakqXbWY9eKelkCtALtD/hoU44WuYU="
1309 .into(),
1310 ),
1311 })),
1312 operations: 1,
1313 };
1314 let pgp_key = hsm_pk_to_pgp_pk(hsm_key, DateTime::UNIX_EPOCH)?;
1315 let PublicParams::ECDSA(EcdsaPublicParams::P256 { key, .. }) = pgp_key.public_params()
1316 else {
1317 panic!("Wrong type of public params");
1318 };
1319 assert_eq!(
1320 key.to_sec1_bytes().to_vec(),
1321 [
1322 4, 222, 106, 236, 96, 145, 243, 13, 81, 181, 119, 76, 5, 29, 72, 112, 134, 130,
1323 169, 182, 231, 247, 107, 204, 228, 178, 45, 77, 196, 91, 117, 122, 57, 69, 240,
1324 240, 134, 114, 138, 232, 63, 45, 141, 102, 164, 169, 118, 214, 99, 215, 138, 122,
1325 89, 2, 180, 2, 237, 15, 248, 104, 83, 142, 22, 185, 133
1326 ]
1327 );
1328
1329 Ok(())
1330 }
1331
1332 #[test]
1333 fn convert_p384_to_pgp() -> TestResult {
1334 let hsm_key = nethsm_sdk_rs::models::PublicKey {
1335 mechanisms: vec![KeyMechanism::EcdsaSignature],
1336 r#type: KeyType::EcP384,
1337 restrictions: Box::new(KeyRestrictions {
1338 tags: Some(vec!["signing2".into()]),
1339 }),
1340 public: Some(Box::new(KeyPublicData {
1341 modulus: None,
1342 public_exponent: None,
1343 data: Some(
1344 "BH+Ik2+7v4NUpnZDTGs0jq9I+kDFTJqiMNOHP5k81agoKW8ICEJ13aL06dLNzkZAdB5iulgRCEuX/Htitii3BhxuHTUPWuN0uVKGhgYRddpTteaaauv0cOPni9la3O+/lA=="
1345 .into(),
1346 ),
1347 })),
1348 operations: 3,
1349 };
1350 let pgp_key = hsm_pk_to_pgp_pk(hsm_key, DateTime::UNIX_EPOCH)?;
1351 let PublicParams::ECDSA(EcdsaPublicParams::P384 { key, .. }) = pgp_key.public_params()
1352 else {
1353 panic!("Wrong type of public params");
1354 };
1355 assert_eq!(
1356 key.to_sec1_bytes().to_vec(),
1357 [
1358 4, 127, 136, 147, 111, 187, 191, 131, 84, 166, 118, 67, 76, 107, 52, 142, 175, 72,
1359 250, 64, 197, 76, 154, 162, 48, 211, 135, 63, 153, 60, 213, 168, 40, 41, 111, 8, 8,
1360 66, 117, 221, 162, 244, 233, 210, 205, 206, 70, 64, 116, 30, 98, 186, 88, 17, 8,
1361 75, 151, 252, 123, 98, 182, 40, 183, 6, 28, 110, 29, 53, 15, 90, 227, 116, 185, 82,
1362 134, 134, 6, 17, 117, 218, 83, 181, 230, 154, 106, 235, 244, 112, 227, 231, 139,
1363 217, 90, 220, 239, 191, 148
1364 ]
1365 );
1366
1367 Ok(())
1368 }
1369
1370 #[test]
1371 fn convert_p521_to_pgp() -> TestResult {
1372 let hsm_key = nethsm_sdk_rs::models::PublicKey {
1373 mechanisms: vec![KeyMechanism::EcdsaSignature],
1374 r#type: KeyType::EcP521,
1375 restrictions: Box::new(KeyRestrictions {
1376 tags: Some(vec!["signing2".into()]),
1377 }),
1378 public: Some(Box::new(KeyPublicData {
1379 modulus: None,
1380 public_exponent: None,
1381 data: Some(
1382 "BAEhJ8HuyTN/DBjAoXD3H7jTdl+TwOwJ3taKwq2q+HsBislgZjeg1JZlOus1Mh4viKv0iuwaviid0D9cqsO2UHLN/QHTWGbzQw6fLiNZvCaGuNDf1c5+aiFMxvAgbDB8qp4eBAsl6f6ro5kKQXbpT7NauRVHYxUv32TgxG5mcRpnf+ovUQ=="
1383 .into(),
1384 ),
1385 })),
1386 operations: 2,
1387 };
1388 let pgp_key = hsm_pk_to_pgp_pk(hsm_key, DateTime::UNIX_EPOCH)?;
1389 let PublicParams::ECDSA(EcdsaPublicParams::P521 { key, .. }) = pgp_key.public_params()
1390 else {
1391 panic!("Wrong type of public params");
1392 };
1393 assert_eq!(
1394 key.to_sec1_bytes().to_vec(),
1395 [
1396 4, 1, 33, 39, 193, 238, 201, 51, 127, 12, 24, 192, 161, 112, 247, 31, 184, 211,
1397 118, 95, 147, 192, 236, 9, 222, 214, 138, 194, 173, 170, 248, 123, 1, 138, 201, 96,
1398 102, 55, 160, 212, 150, 101, 58, 235, 53, 50, 30, 47, 136, 171, 244, 138, 236, 26,
1399 190, 40, 157, 208, 63, 92, 170, 195, 182, 80, 114, 205, 253, 1, 211, 88, 102, 243,
1400 67, 14, 159, 46, 35, 89, 188, 38, 134, 184, 208, 223, 213, 206, 126, 106, 33, 76,
1401 198, 240, 32, 108, 48, 124, 170, 158, 30, 4, 11, 37, 233, 254, 171, 163, 153, 10,
1402 65, 118, 233, 79, 179, 90, 185, 21, 71, 99, 21, 47, 223, 100, 224, 196, 110, 102,
1403 113, 26, 103, 127, 234, 47, 81
1404 ]
1405 );
1406
1407 Ok(())
1408 }
1409
1410 #[test]
1411 fn convert_rsa_to_pgp() -> TestResult {
1412 let hsm_key = nethsm_sdk_rs::models::PublicKey {
1413 mechanisms: vec![KeyMechanism::RsaSignaturePkcs1],
1414 r#type: KeyType::Rsa,
1415 restrictions: Box::new(KeyRestrictions {
1416 tags: Some(vec!["signing8".into()]) }),
1417 public: Some(Box::new(KeyPublicData {
1418 modulus: Some("4386l1aC1e4N93rxM+Npj+dy0CGY0W3PNbOTBGRj7tTEflkEl2qx2xW7kyme8sLQQ/yxhyJ4mqo/ggR9ODfvYytzxsS/n/MNZwdATGC4QDBjPv74s/51nC/gZHq9VzvYq3bmF0e0WNiXRT3p53Zofmv1CBDPBEDrrJq3Mq+O3+TH8/ur3OOMgvNx2CDgwwQ1WGSW3XITN9ekZpoj/h8cwxFkz5ljmygCLRtXdNWrzVJGW3G5L/Jz9sdSfE2tyb8+312IVFJ57zcvRygqAkkS11uYIPxuoabT6IJ8SpScfqltGsU3jiALKyFRV58I91KUlXegjUVR31ExFc0eADuhuw==".into()),
1419 public_exponent: Some("AQAB".into()),
1420 data: None })),
1421 operations: 2 };
1422 let pgp_key = hsm_pk_to_pgp_pk(hsm_key, DateTime::UNIX_EPOCH)?;
1423 let PublicParams::RSA(public) = pgp_key.public_params() else {
1424 panic!("Wrong type of public params");
1425 };
1426 assert_eq!(public.key.e().to_bytes_be(), [1, 0, 1]);
1427 assert_eq!(
1428 public.key.n().to_bytes_be(),
1429 [
1430 227, 127, 58, 151, 86, 130, 213, 238, 13, 247, 122, 241, 51, 227, 105, 143, 231,
1431 114, 208, 33, 152, 209, 109, 207, 53, 179, 147, 4, 100, 99, 238, 212, 196, 126, 89,
1432 4, 151, 106, 177, 219, 21, 187, 147, 41, 158, 242, 194, 208, 67, 252, 177, 135, 34,
1433 120, 154, 170, 63, 130, 4, 125, 56, 55, 239, 99, 43, 115, 198, 196, 191, 159, 243,
1434 13, 103, 7, 64, 76, 96, 184, 64, 48, 99, 62, 254, 248, 179, 254, 117, 156, 47, 224,
1435 100, 122, 189, 87, 59, 216, 171, 118, 230, 23, 71, 180, 88, 216, 151, 69, 61, 233,
1436 231, 118, 104, 126, 107, 245, 8, 16, 207, 4, 64, 235, 172, 154, 183, 50, 175, 142,
1437 223, 228, 199, 243, 251, 171, 220, 227, 140, 130, 243, 113, 216, 32, 224, 195, 4,
1438 53, 88, 100, 150, 221, 114, 19, 55, 215, 164, 102, 154, 35, 254, 31, 28, 195, 17,
1439 100, 207, 153, 99, 155, 40, 2, 45, 27, 87, 116, 213, 171, 205, 82, 70, 91, 113,
1440 185, 47, 242, 115, 246, 199, 82, 124, 77, 173, 201, 191, 62, 223, 93, 136, 84, 82,
1441 121, 239, 55, 47, 71, 40, 42, 2, 73, 18, 215, 91, 152, 32, 252, 110, 161, 166, 211,
1442 232, 130, 124, 74, 148, 156, 126, 169, 109, 26, 197, 55, 142, 32, 11, 43, 33, 81,
1443 87, 159, 8, 247, 82, 148, 149, 119, 160, 141, 69, 81, 223, 81, 49, 21, 205, 30, 0,
1444 59, 161, 187
1445 ]
1446 );
1447
1448 Ok(())
1449 }
1450
1451 #[test]
1452 fn parse_rsa_signature_produces_valid_data() -> TestResult {
1453 let sig = parse_signature(crate::SignatureType::Pkcs1, &[0, 1, 2])?;
1454 assert_eq!(sig.len(), 1);
1455 assert_eq!(&sig[0].as_ref(), &[1, 2]);
1456
1457 Ok(())
1458 }
1459
1460 #[test]
1461 fn parse_ed25519_signature_produces_valid_data() -> TestResult {
1462 let sig = parse_signature(
1463 crate::SignatureType::EdDsa,
1464 &[
1465 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1466 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1467 1, 1, 1, 1, 1, 1, 1, 1,
1468 ],
1469 )?;
1470 assert_eq!(sig.len(), 2);
1471 assert_eq!(sig[0].as_ref(), vec![2; 32]);
1472 assert_eq!(sig[1].as_ref(), vec![1; 32]);
1473
1474 Ok(())
1475 }
1476
1477 #[test]
1478 fn parse_p256_signature_produces_valid_data() -> TestResult {
1479 let sig = parse_signature(
1480 crate::SignatureType::EcdsaP256,
1481 &[
1482 48, 70, 2, 33, 0, 193, 176, 219, 0, 133, 254, 212, 239, 236, 122, 85, 239, 73, 161,
1483 179, 53, 100, 172, 103, 45, 123, 21, 169, 28, 59, 150, 72, 92, 242, 9, 53, 143, 2,
1484 33, 0, 165, 1, 144, 97, 102, 109, 66, 50, 185, 234, 211, 150, 253, 228, 210, 126,
1485 26, 0, 189, 184, 230, 163, 36, 203, 232, 161, 12, 75, 121, 171, 45, 107,
1486 ],
1487 )?;
1488 assert_eq!(sig.len(), 2);
1489 assert_eq!(
1490 sig[0].as_ref(),
1491 [
1492 193, 176, 219, 0, 133, 254, 212, 239, 236, 122, 85, 239, 73, 161, 179, 53, 100,
1493 172, 103, 45, 123, 21, 169, 28, 59, 150, 72, 92, 242, 9, 53, 143
1494 ]
1495 );
1496 assert_eq!(
1497 sig[1].as_ref(),
1498 [
1499 165, 1, 144, 97, 102, 109, 66, 50, 185, 234, 211, 150, 253, 228, 210, 126, 26, 0,
1500 189, 184, 230, 163, 36, 203, 232, 161, 12, 75, 121, 171, 45, 107
1501 ]
1502 );
1503
1504 Ok(())
1505 }
1506
1507 #[test]
1508 fn parse_p384_signature_produces_valid_data() -> TestResult {
1509 let sig = parse_signature(
1510 crate::SignatureType::EcdsaP384,
1511 &[
1512 48, 101, 2, 49, 0, 134, 13, 108, 74, 135, 234, 174, 105, 208, 46, 109, 18, 77, 21,
1513 177, 59, 73, 150, 228, 26, 244, 134, 187, 217, 172, 34, 2, 1, 229, 123, 105, 202,
1514 132, 233, 72, 41, 243, 138, 127, 107, 135, 95, 139, 19, 121, 179, 170, 27, 2, 48,
1515 44, 80, 117, 90, 18, 137, 36, 190, 8, 60, 201, 235, 242, 168, 164, 245, 119, 136,
1516 207, 178, 237, 64, 117, 69, 218, 189, 209, 110, 2, 9, 191, 194, 70, 50, 227, 47, 6,
1517 34, 8, 135, 43, 188, 236, 192, 184, 227, 59, 40,
1518 ],
1519 )?;
1520 assert_eq!(sig.len(), 2);
1521 assert_eq!(
1522 sig[0].as_ref(),
1523 [
1524 134, 13, 108, 74, 135, 234, 174, 105, 208, 46, 109, 18, 77, 21, 177, 59, 73, 150,
1525 228, 26, 244, 134, 187, 217, 172, 34, 2, 1, 229, 123, 105, 202, 132, 233, 72, 41,
1526 243, 138, 127, 107, 135, 95, 139, 19, 121, 179, 170, 27
1527 ]
1528 );
1529 assert_eq!(
1530 sig[1].as_ref(),
1531 [
1532 44, 80, 117, 90, 18, 137, 36, 190, 8, 60, 201, 235, 242, 168, 164, 245, 119, 136,
1533 207, 178, 237, 64, 117, 69, 218, 189, 209, 110, 2, 9, 191, 194, 70, 50, 227, 47, 6,
1534 34, 8, 135, 43, 188, 236, 192, 184, 227, 59, 40
1535 ]
1536 );
1537
1538 Ok(())
1539 }
1540
1541 #[test]
1542 fn parse_p521_signature_produces_valid_data() -> TestResult {
1543 let sig = parse_signature(
1544 crate::SignatureType::EcdsaP521,
1545 &[
1546 48, 129, 136, 2, 66, 0, 203, 246, 21, 57, 217, 6, 101, 73, 103, 113, 98, 39, 223,
1547 246, 199, 136, 238, 213, 134, 163, 153, 151, 116, 237, 207, 181, 107, 183, 204,
1548 110, 97, 160, 95, 160, 193, 3, 219, 46, 105, 191, 0, 139, 124, 234, 90, 125, 114,
1549 115, 205, 109, 15, 193, 166, 100, 224, 108, 87, 143, 240, 65, 41, 93, 164, 166, 2,
1550 2, 66, 1, 203, 115, 121, 219, 49, 18, 3, 101, 130, 153, 95, 80, 27, 148, 249, 221,
1551 198, 251, 149, 118, 119, 32, 44, 160, 24, 125, 72, 161, 168, 71, 48, 138, 223, 200,
1552 37, 124, 234, 17, 237, 246, 13, 123, 102, 151, 83, 95, 186, 161, 112, 41, 158, 138,
1553 144, 55, 23, 110, 100, 185, 237, 13, 174, 83, 4, 153, 34,
1554 ],
1555 )?;
1556 assert_eq!(sig.len(), 2);
1557 assert_eq!(
1558 sig[0].as_ref(),
1559 [
1560 203, 246, 21, 57, 217, 6, 101, 73, 103, 113, 98, 39, 223, 246, 199, 136, 238, 213,
1561 134, 163, 153, 151, 116, 237, 207, 181, 107, 183, 204, 110, 97, 160, 95, 160, 193,
1562 3, 219, 46, 105, 191, 0, 139, 124, 234, 90, 125, 114, 115, 205, 109, 15, 193, 166,
1563 100, 224, 108, 87, 143, 240, 65, 41, 93, 164, 166, 2
1564 ]
1565 );
1566 assert_eq!(
1567 sig[1].as_ref(),
1568 [
1569 1, 203, 115, 121, 219, 49, 18, 3, 101, 130, 153, 95, 80, 27, 148, 249, 221, 198,
1570 251, 149, 118, 119, 32, 44, 160, 24, 125, 72, 161, 168, 71, 48, 138, 223, 200, 37,
1571 124, 234, 17, 237, 246, 13, 123, 102, 151, 83, 95, 186, 161, 112, 41, 158, 138,
1572 144, 55, 23, 110, 100, 185, 237, 13, 174, 83, 4, 153, 34
1573 ]
1574 );
1575
1576 Ok(())
1577 }
1578
1579 #[test]
1580 fn private_key_import_ed25199_is_correctly_zero_padded() -> TestResult {
1581 let mut key_data = vec![];
1582 SignedSecretKey::from_armor_single(std::fs::File::open(
1583 "tests/fixtures/ed25519-key-with-31-byte-private-key-scalar.asc",
1584 )?)?
1585 .0
1586 .to_writer(&mut key_data)?;
1587
1588 let import: nethsm_sdk_rs::models::KeyPrivateData =
1589 tsk_to_private_key_import(&key_data)?.0.into();
1590
1591 let data = Base64::decode_vec(&import.data.unwrap())?;
1592
1593 assert_eq!(data.len(), 32);
1596 assert_eq!(data[0], 0x00);
1597
1598 Ok(())
1599 }
1600
1601 #[test]
1602 fn private_key_import_rsa_key_with_nonstandard_moduli_is_read_correctly() -> TestResult {
1603 let mut key_data = vec![];
1604 SignedSecretKey::from_armor_single(std::fs::File::open(
1605 "tests/fixtures/rsa-key-with-modulus-e-257.asc",
1606 )?)?
1607 .0
1608 .to_writer(&mut key_data)?;
1609
1610 let import: nethsm_sdk_rs::models::KeyPrivateData =
1611 tsk_to_private_key_import(&key_data)?.0.into();
1612
1613 let data = Base64::decode_vec(&import.public_exponent.unwrap())?;
1614
1615 assert_eq!(data, vec![0x01, 0x01]); Ok(())
1619 }
1620
1621 #[test]
1622 fn rsa_digest_info_is_wrapped() -> TestResult {
1623 let data = prepare_digest_data(crate::SignatureType::Pkcs1, HashAlgorithm::Sha1, &[0; 20])?;
1624
1625 assert_eq!(
1626 data,
1627 vec![
1628 48, 33, 48, 9, 6, 5, 43, 14, 3, 2, 26, 5, 0, 4, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1629 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1630 ]
1631 );
1632
1633 Ok(())
1634 }
1635
1636 #[rstest]
1637 #[case(crate::SignatureType::EcdsaP224, 28)]
1638 #[case(crate::SignatureType::EcdsaP256, 32)]
1639 #[case(crate::SignatureType::EcdsaP384, 48)]
1640 #[case(crate::SignatureType::EcdsaP521, 64)]
1641 fn ecdsa_wrapped_up_to_max_len(
1642 #[case] sig_type: crate::SignatureType,
1643 #[case] max_len: usize,
1644 #[values(HashAlgorithm::Sha1, HashAlgorithm::Sha256, HashAlgorithm::Sha512)]
1645 hash_algo: HashAlgorithm,
1646 ) -> TestResult {
1647 let digest = hash_algo.new_hasher()?.finalize();
1649 let data = prepare_digest_data(sig_type, hash_algo, &digest)?;
1650
1651 assert_eq!(
1655 data.len(),
1656 usize::min(max_len, digest.len()),
1657 "the data to be signed's length ({}) cannot exceed maximum length imposed by the curve ({})",
1658 data.len(),
1659 max_len
1660 );
1661
1662 Ok(())
1663 }
1664
1665 #[rstest]
1666 fn eddsa_is_not_wrapped(
1667 #[values(HashAlgorithm::Sha1, HashAlgorithm::Sha256, HashAlgorithm::Sha512)]
1668 hash_algo: HashAlgorithm,
1669 ) -> TestResult {
1670 let digest = &hash_algo.new_hasher()?.finalize()[..];
1672
1673 let data = prepare_digest_data(crate::SignatureType::EdDsa, hash_algo, digest)?;
1674
1675 assert_eq!(data, digest);
1676
1677 Ok(())
1678 }
1679}