Skip to main content

nethsm/
signer.rs

1//! OpenPGP related signing facilities for NetHSM.
2
3use std::borrow::Cow;
4
5use base64ct::{Base64, Encoding as _};
6use log::{error, warn};
7use nethsm_sdk_rs::models::KeyType;
8use picky_asn1_x509::{
9    AlgorithmIdentifier,
10    DigestInfo,
11    ShaVariant,
12    signature::EcdsaSignatureValue,
13};
14use signstar_crypto::{
15    Error,
16    key::Error as SignstarCryptoKeyError,
17    signer::{
18        error::Error as SignstarCryptoSignerError,
19        traits::{RawPublicKey, RawSigningKey},
20    },
21};
22
23use crate::{KeyId, NetHsm, SignatureType};
24
25/// Access to signature creation with a specific key in a [`NetHsm`].
26///
27/// Tracks a [`SignatureType`], which defines the type of signature that is created when using a key
28/// identified by [`KeyId`] on a [`NetHsm`].
29///
30/// For owned access see [`OwnedNetHsmKey`].
31#[derive(Debug)]
32pub struct NetHsmKey<'a, 'b> {
33    signature_type: SignatureType,
34    nethsm: &'a NetHsm,
35    key_id: &'b KeyId,
36}
37
38/// Returns a [`SignatureType`] for a [`KeyType`].
39///
40/// Reflects the specific capabilities of a NetHSM backend and only returns a [`SignatureType`] for
41/// a supported `key_type`.
42///
43/// # Errors
44///
45/// Returns an error if the key type is unsupported (e.g. [`KeyType::Generic`],
46/// [`KeyType::BrainpoolP256`], [`KeyType::BrainpoolP384`], [`KeyType::BrainpoolP512`],
47/// [`KeyType::EcP256K1`]).
48pub(crate) fn nethsm_signature_type(key_type: KeyType) -> Result<SignatureType, crate::Error> {
49    Ok(match key_type {
50        KeyType::Rsa => SignatureType::Pkcs1,
51        KeyType::Curve25519 => SignatureType::EdDsa,
52        KeyType::BrainpoolP256
53        | KeyType::BrainpoolP384
54        | KeyType::BrainpoolP512
55        | KeyType::EcP256K1 => {
56            return Err(
57                crate::nethsm_sdk::Error::NetHsmSdkRsKeyTypeUnsupportedInSignstar { key_type }
58                    .into(),
59            );
60        }
61        KeyType::EcP256 => SignatureType::EcdsaP256,
62        KeyType::EcP384 => SignatureType::EcdsaP384,
63        KeyType::EcP521 => SignatureType::EcdsaP521,
64        KeyType::Generic => {
65            return Err(crate::Error::Default(
66                "Generic keys cannot be used to sign OpenPGP data".into(),
67            ));
68        }
69        key_type => {
70            return Err(
71                crate::nethsm_sdk::Error::NetHsmSdkRsKeyTypeUnsupportedInSignstar { key_type }
72                    .into(),
73            );
74        }
75    })
76}
77
78impl<'a, 'b> NetHsmKey<'a, 'b> {
79    /// Creates a new remote signing key which will use `key_id` key for signing.
80    ///
81    /// # Errors
82    ///
83    /// Returns an error if no key can be retrieved from `nethsm` using `key_id`.
84    pub fn new(nethsm: &'a NetHsm, key_id: &'b KeyId) -> Result<Self, crate::Error> {
85        let pk = nethsm.get_key(key_id)?;
86        let signature_type = nethsm_signature_type(pk.r#type)?;
87
88        Ok(Self {
89            nethsm,
90            signature_type,
91            key_id,
92        })
93    }
94}
95
96/// Converts base64-encoded EC public key data into a vector of bytes.
97///
98/// # Errors
99///
100/// Returns an error if
101///
102/// - `data` is [`None`],
103/// - or `data` provides invalid base64 encoding.
104fn ec_public_key_data_to_bytes(data: Option<&str>) -> Result<Vec<u8>, Error> {
105    Base64::decode_vec(data.ok_or(SignstarCryptoSignerError::InvalidPublicKeyData {
106        context: "EC public key data is missing".into(),
107    })?)
108    .map_err(|e| {
109        SignstarCryptoSignerError::Hsm {
110            context: "deserializing EC data",
111            source: Box::new(e),
112        }
113        .into()
114    })
115}
116
117impl RawSigningKey for NetHsmKey<'_, '_> {
118    fn key_id(&self) -> String {
119        self.key_id.to_string()
120    }
121
122    fn sign(&self, digest: &[u8]) -> Result<Vec<Vec<u8>>, Error> {
123        let hash = AlgorithmIdentifier::new_sha(ShaVariant::SHA2_512);
124        let request_data = prepare_digest_data_for_openpgp(self.signature_type, hash, digest)?;
125
126        let sig = self
127            .nethsm
128            .sign_digest(self.key_id, self.signature_type, &request_data)
129            .map_err(|e| {
130                error!("NetHsm::sign_digest failed: {e:?}");
131                SignstarCryptoSignerError::Hsm {
132                    context: "executing NetHsm::sign_digest",
133                    source: e.into(),
134                }
135            })?;
136
137        raw_signature_to_mpis(self.signature_type, &sig)
138    }
139
140    fn certificate(&self) -> Result<Option<Vec<u8>>, Error> {
141        self.nethsm.get_key_certificate(self.key_id).map_err(|e| {
142            SignstarCryptoSignerError::Hsm {
143                context: "executing NetHsm::get_key_certificate",
144                source: e.into(),
145            }
146            .into()
147        })
148    }
149
150    fn public(&self) -> Result<RawPublicKey, Error> {
151        let pk = self
152            .nethsm
153            .get_key(self.key_id)
154            .map_err(|e| SignstarCryptoSignerError::Hsm {
155                context: "executing NetHsm::get_key",
156                source: e.into(),
157            })?;
158
159        let public = &pk
160            .public
161            .ok_or(SignstarCryptoSignerError::InvalidPublicKeyData {
162                context: "public key data is missing".into(),
163            })?;
164
165        let key_type: KeyType = pk.r#type;
166        Ok(match key_type {
167            KeyType::Rsa => RawPublicKey::Rsa {
168                modulus: Base64::decode_vec(public.modulus.as_ref().ok_or(
169                    SignstarCryptoSignerError::InvalidPublicKeyData {
170                        context: "RSA modulus is missing".into(),
171                    },
172                )?)
173                .map_err(|e| SignstarCryptoSignerError::Hsm {
174                    context: "deserializing modulus",
175                    source: Box::new(e),
176                })?,
177                exponent: Base64::decode_vec(public.public_exponent.as_ref().ok_or(
178                    SignstarCryptoSignerError::InvalidPublicKeyData {
179                        context: "RSA exponent is missing".into(),
180                    },
181                )?)
182                .map_err(|e| SignstarCryptoSignerError::Hsm {
183                    context: "deserializing exponent",
184                    source: Box::new(e),
185                })?,
186            },
187            KeyType::Curve25519 => {
188                RawPublicKey::Ed25519(ec_public_key_data_to_bytes(public.data.as_deref())?)
189            }
190            KeyType::EcP256 => {
191                RawPublicKey::P256(ec_public_key_data_to_bytes(public.data.as_deref())?)
192            }
193            KeyType::EcP384 => {
194                RawPublicKey::P384(ec_public_key_data_to_bytes(public.data.as_deref())?)
195            }
196            KeyType::EcP521 => {
197                RawPublicKey::P521(ec_public_key_data_to_bytes(public.data.as_deref())?)
198            }
199            KeyType::EcP256K1
200            | KeyType::BrainpoolP256
201            | KeyType::BrainpoolP384
202            | KeyType::BrainpoolP512
203            | KeyType::Generic
204            | _ => {
205                warn!("Unsupported key type: {key_type}");
206                return Err(SignstarCryptoSignerError::InvalidPublicKeyData {
207                    context: format!("Unsupported key type: {key_type}"),
208                }
209                .into());
210            }
211        })
212    }
213}
214
215/// Owned access to signature creation with a specific key in a [`NetHsm`].
216///
217/// Tracks a [`SignatureType`], which defines the type of signature that is created when using a key
218/// identified by [`KeyId`] on a [`NetHsm`].
219///
220/// For reference access see [`NetHsmKey`].
221#[derive(Debug)]
222pub struct OwnedNetHsmKey {
223    signature_type: SignatureType,
224    nethsm: NetHsm,
225    key_id: KeyId,
226}
227
228impl OwnedNetHsmKey {
229    /// Creates a new [`OwnedNetHsmKey`].
230    ///
231    /// This remote signing key relies on a backend key accessible via `key_id` for signing.
232    ///
233    /// # Errors
234    ///
235    /// Returns an error if
236    ///
237    /// - retrieving raw signing key from NetHSM fails
238    /// - signing mode of the key is unsupported
239    pub fn new(nethsm: NetHsm, key_id: KeyId) -> Result<Self, crate::Error> {
240        let pk = nethsm.get_key(&key_id)?;
241        let signature_type = nethsm_signature_type(pk.r#type)?;
242
243        Ok(Self {
244            nethsm,
245            signature_type,
246            key_id,
247        })
248    }
249
250    /// Returns a reference view of `self` (a [`NetHsmKey`]).
251    pub(crate) fn as_nethsm_key<'a>(&'a self) -> NetHsmKey<'a, 'a> {
252        NetHsmKey {
253            signature_type: self.signature_type,
254            nethsm: &self.nethsm,
255            key_id: &self.key_id,
256        }
257    }
258}
259
260impl RawSigningKey for OwnedNetHsmKey {
261    fn key_id(&self) -> String {
262        self.as_nethsm_key().key_id()
263    }
264
265    fn sign(&self, digest: &[u8]) -> Result<Vec<Vec<u8>>, Error> {
266        self.as_nethsm_key().sign(digest)
267    }
268
269    fn certificate(&self) -> Result<Option<Vec<u8>>, Error> {
270        self.as_nethsm_key().certificate()
271    }
272
273    fn public(&self) -> Result<RawPublicKey, Error> {
274        self.as_nethsm_key().public()
275    }
276}
277
278/// Transforms the raw digest data for cryptographic signing with OpenPGP.
279///
280/// Raw cryptographic signing primitives have special provisions that
281/// need to be taken care of when using certain combinations of
282/// signing schemes and hashing algorithms.
283///
284/// This function transforms the digest into bytes that are ready to
285/// be passed to raw cryptographic functions. The exact specifics of
286/// the transformations are documented inside the function.
287///
288/// # Errors
289///
290/// Returns an error if
291///
292/// - the `signature_type` is [`SignatureType::Pkcs1`] and the encoding of the digest data fails,
293/// - or the `signature_type` is the unsupported [`SignatureType::PssSha1`],
294///   [`SignatureType::PssSha224`], [`SignatureType::PssSha256`], [`SignatureType::PssSha384`], or
295///   [`SignatureType::PssSha512`].
296fn prepare_digest_data_for_openpgp(
297    signature_type: SignatureType,
298    oid: AlgorithmIdentifier,
299    digest: &[u8],
300) -> Result<Cow<'_, [u8]>, Error> {
301    Ok(match signature_type {
302        SignatureType::EcdsaK256 => {
303            return Err(Error::Key(
304                SignstarCryptoKeyError::UnsupportedSignatureType {
305                    signature_type,
306                    context: "the NetHSM backend does not support it",
307                },
308            ));
309        }
310        // RSA-PKCS#1 signing scheme needs to wrap the digest value
311        // in an DER-encoded ASN.1 DigestInfo structure which captures
312        // the hash used.
313        // See: https://www.rfc-editor.org/rfc/rfc8017#appendix-A.2.4
314        SignatureType::Pkcs1 => picky_asn1_der::to_vec(&DigestInfo {
315            oid,
316            digest: digest.to_vec().into(),
317        })
318        .map_err(|e| {
319            error!("Encoding signature to PKCS#1 format failed: {e:?}");
320            SignstarCryptoSignerError::Hsm {
321                context: "preparing digest data",
322                source: Box::new(e),
323            }
324        })?
325        .into(),
326        // ECDSA may need to truncate the digest if it's too long
327        // See: https://www.rfc-editor.org/rfc/rfc9580#section-5.2.3.2
328        SignatureType::EcdsaP224 => digest[..usize::min(28, digest.len())].into(),
329        SignatureType::EcdsaP256 => digest[..usize::min(32, digest.len())].into(),
330        SignatureType::EcdsaP384 => digest[..usize::min(48, digest.len())].into(),
331
332        // All other schemes that we use will not need any kind of
333        // digest transformations.
334        SignatureType::EdDsa | SignatureType::EcdsaP521 => digest.into(),
335        SignatureType::PssSha1
336        | SignatureType::PssSha224
337        | SignatureType::PssSha256
338        | SignatureType::PssSha384
339        | SignatureType::PssSha512 => {
340            return Err(
341                SignstarCryptoSignerError::UnsupportedSignatureAlgorithm(signature_type).into(),
342            );
343        }
344    })
345}
346
347/// Parses raw signature bytes as vector of algorithm-specific multiple precision integers (MPIs).
348///
349/// MPIs (see [arbitrary-precision arithmetic]) are handled in an algorithm specific way.
350/// This function prepares raw signature bytes for technology specific use.
351///
352/// # Errors
353///
354/// Returns an error if
355///
356/// - parsing DER-encoded ECDSA signature fails
357/// - EdDSA signature is of wrong length
358/// - the signature type is not supported
359///
360/// [arbitrary-precision arithmetic]: https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic
361fn raw_signature_to_mpis(sig_type: SignatureType, sig: &[u8]) -> Result<Vec<Vec<u8>>, Error> {
362    use SignatureType;
363    Ok(match sig_type {
364        SignatureType::EcdsaK256 => {
365            return Err(Error::Key(
366                SignstarCryptoKeyError::UnsupportedSignatureType {
367                    signature_type: sig_type,
368                    context: "the NetHSM backend does not support it",
369                },
370            ));
371        }
372        SignatureType::EcdsaP224
373        | SignatureType::EcdsaP256
374        | SignatureType::EcdsaP384
375        | SignatureType::EcdsaP521 => {
376            let sig: EcdsaSignatureValue = picky_asn1_der::from_bytes(sig).map_err(|e| {
377                error!("DER decoding error when parsing ECDSA signature: {e:?}");
378                SignstarCryptoSignerError::Hsm {
379                    context: "DER decoding ECDSA signature",
380                    source: Box::new(e),
381                }
382            })?;
383            vec![
384                sig.r.as_unsigned_bytes_be().into(),
385                sig.s.as_unsigned_bytes_be().into(),
386            ]
387        }
388        SignatureType::EdDsa => {
389            if sig.len() != 64 {
390                error!(
391                    "Signature length should be exactly 64 bytes but is: {}",
392                    sig.len()
393                );
394                return Err(SignstarCryptoSignerError::InvalidSignature {
395                    context: "decoding EdDSA signature",
396                    signature_type: sig_type,
397                }
398                .into());
399            }
400
401            vec![sig[..32].into(), sig[32..].into()]
402        }
403        SignatureType::Pkcs1 => {
404            // RSA
405            vec![sig.into()]
406        }
407        SignatureType::PssSha1
408        | SignatureType::PssSha224
409        | SignatureType::PssSha256
410        | SignatureType::PssSha384
411        | SignatureType::PssSha512 => {
412            error!("Unsupported signature type: {sig_type}");
413            return Err(SignstarCryptoSignerError::InvalidSignature {
414                context: "parsing signature",
415                signature_type: sig_type,
416            }
417            .into());
418        }
419    })
420}
421
422#[cfg(test)]
423mod tests {
424    use rstest::rstest;
425    use testresult::TestResult;
426
427    use super::*;
428
429    #[test]
430    fn parse_rsa_signature_produces_valid_data() -> TestResult {
431        let sig = raw_signature_to_mpis(SignatureType::Pkcs1, &[0, 1, 2])?;
432        assert_eq!(sig.len(), 1);
433        assert_eq!(&sig[0].as_ref(), &[0, 1, 2]);
434
435        Ok(())
436    }
437
438    #[test]
439    fn parse_ed25519_signature_produces_valid_data() -> TestResult {
440        let sig = raw_signature_to_mpis(
441            SignatureType::EdDsa,
442            &[
443                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,
444                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,
445                1, 1, 1, 1, 1, 1, 1, 1,
446            ],
447        )?;
448        assert_eq!(sig.len(), 2);
449        assert_eq!(sig[0].as_ref(), vec![2; 32]);
450        assert_eq!(sig[1].as_ref(), vec![1; 32]);
451
452        Ok(())
453    }
454
455    #[test]
456    fn parse_p256_signature_produces_valid_data() -> TestResult {
457        let sig = raw_signature_to_mpis(
458            SignatureType::EcdsaP256,
459            &[
460                48, 70, 2, 33, 0, 193, 176, 219, 0, 133, 254, 212, 239, 236, 122, 85, 239, 73, 161,
461                179, 53, 100, 172, 103, 45, 123, 21, 169, 28, 59, 150, 72, 92, 242, 9, 53, 143, 2,
462                33, 0, 165, 1, 144, 97, 102, 109, 66, 50, 185, 234, 211, 150, 253, 228, 210, 126,
463                26, 0, 189, 184, 230, 163, 36, 203, 232, 161, 12, 75, 121, 171, 45, 107,
464            ],
465        )?;
466        assert_eq!(sig.len(), 2);
467        assert_eq!(
468            sig[0].as_ref(),
469            [
470                193, 176, 219, 0, 133, 254, 212, 239, 236, 122, 85, 239, 73, 161, 179, 53, 100,
471                172, 103, 45, 123, 21, 169, 28, 59, 150, 72, 92, 242, 9, 53, 143
472            ]
473        );
474        assert_eq!(
475            sig[1].as_ref(),
476            [
477                165, 1, 144, 97, 102, 109, 66, 50, 185, 234, 211, 150, 253, 228, 210, 126, 26, 0,
478                189, 184, 230, 163, 36, 203, 232, 161, 12, 75, 121, 171, 45, 107
479            ]
480        );
481
482        Ok(())
483    }
484
485    #[test]
486    fn parse_p384_signature_produces_valid_data() -> TestResult {
487        let sig = raw_signature_to_mpis(
488            SignatureType::EcdsaP384,
489            &[
490                48, 101, 2, 49, 0, 134, 13, 108, 74, 135, 234, 174, 105, 208, 46, 109, 18, 77, 21,
491                177, 59, 73, 150, 228, 26, 244, 134, 187, 217, 172, 34, 2, 1, 229, 123, 105, 202,
492                132, 233, 72, 41, 243, 138, 127, 107, 135, 95, 139, 19, 121, 179, 170, 27, 2, 48,
493                44, 80, 117, 90, 18, 137, 36, 190, 8, 60, 201, 235, 242, 168, 164, 245, 119, 136,
494                207, 178, 237, 64, 117, 69, 218, 189, 209, 110, 2, 9, 191, 194, 70, 50, 227, 47, 6,
495                34, 8, 135, 43, 188, 236, 192, 184, 227, 59, 40,
496            ],
497        )?;
498        assert_eq!(sig.len(), 2);
499        assert_eq!(
500            sig[0].as_ref(),
501            [
502                134, 13, 108, 74, 135, 234, 174, 105, 208, 46, 109, 18, 77, 21, 177, 59, 73, 150,
503                228, 26, 244, 134, 187, 217, 172, 34, 2, 1, 229, 123, 105, 202, 132, 233, 72, 41,
504                243, 138, 127, 107, 135, 95, 139, 19, 121, 179, 170, 27
505            ]
506        );
507        assert_eq!(
508            sig[1].as_ref(),
509            [
510                44, 80, 117, 90, 18, 137, 36, 190, 8, 60, 201, 235, 242, 168, 164, 245, 119, 136,
511                207, 178, 237, 64, 117, 69, 218, 189, 209, 110, 2, 9, 191, 194, 70, 50, 227, 47, 6,
512                34, 8, 135, 43, 188, 236, 192, 184, 227, 59, 40
513            ]
514        );
515
516        Ok(())
517    }
518
519    #[test]
520    fn parse_p521_signature_produces_valid_data() -> TestResult {
521        let sig = raw_signature_to_mpis(
522            SignatureType::EcdsaP521,
523            &[
524                48, 129, 136, 2, 66, 0, 203, 246, 21, 57, 217, 6, 101, 73, 103, 113, 98, 39, 223,
525                246, 199, 136, 238, 213, 134, 163, 153, 151, 116, 237, 207, 181, 107, 183, 204,
526                110, 97, 160, 95, 160, 193, 3, 219, 46, 105, 191, 0, 139, 124, 234, 90, 125, 114,
527                115, 205, 109, 15, 193, 166, 100, 224, 108, 87, 143, 240, 65, 41, 93, 164, 166, 2,
528                2, 66, 1, 203, 115, 121, 219, 49, 18, 3, 101, 130, 153, 95, 80, 27, 148, 249, 221,
529                198, 251, 149, 118, 119, 32, 44, 160, 24, 125, 72, 161, 168, 71, 48, 138, 223, 200,
530                37, 124, 234, 17, 237, 246, 13, 123, 102, 151, 83, 95, 186, 161, 112, 41, 158, 138,
531                144, 55, 23, 110, 100, 185, 237, 13, 174, 83, 4, 153, 34,
532            ],
533        )?;
534        assert_eq!(sig.len(), 2);
535        assert_eq!(
536            sig[0].as_ref(),
537            [
538                203, 246, 21, 57, 217, 6, 101, 73, 103, 113, 98, 39, 223, 246, 199, 136, 238, 213,
539                134, 163, 153, 151, 116, 237, 207, 181, 107, 183, 204, 110, 97, 160, 95, 160, 193,
540                3, 219, 46, 105, 191, 0, 139, 124, 234, 90, 125, 114, 115, 205, 109, 15, 193, 166,
541                100, 224, 108, 87, 143, 240, 65, 41, 93, 164, 166, 2
542            ]
543        );
544        assert_eq!(
545            sig[1].as_ref(),
546            [
547                1, 203, 115, 121, 219, 49, 18, 3, 101, 130, 153, 95, 80, 27, 148, 249, 221, 198,
548                251, 149, 118, 119, 32, 44, 160, 24, 125, 72, 161, 168, 71, 48, 138, 223, 200, 37,
549                124, 234, 17, 237, 246, 13, 123, 102, 151, 83, 95, 186, 161, 112, 41, 158, 138,
550                144, 55, 23, 110, 100, 185, 237, 13, 174, 83, 4, 153, 34
551            ]
552        );
553
554        Ok(())
555    }
556
557    #[test]
558    fn rsa_digest_info_is_wrapped_sha1() -> TestResult {
559        let hash = AlgorithmIdentifier::new_sha(ShaVariant::SHA1);
560        let data = prepare_digest_data_for_openpgp(SignatureType::Pkcs1, hash, &[0; 20])?;
561
562        assert_eq!(
563            data,
564            &[
565                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,
566                0, 0, 0, 0, 0, 0, 0, 0, 0, 0
567            ][..]
568        );
569
570        Ok(())
571    }
572
573    #[test]
574    fn rsa_digest_info_is_wrapped_sha512() -> TestResult {
575        let hash = AlgorithmIdentifier::new_sha(ShaVariant::SHA2_512);
576        let data = prepare_digest_data_for_openpgp(SignatureType::Pkcs1, hash, &[0; 64])?;
577
578        assert_eq!(
579            data,
580            &[
581                48, 81, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 4, 64, 0, 0, 0, 0, 0,
582                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
583                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
584                0, 0, 0
585            ][..]
586        );
587
588        Ok(())
589    }
590
591    #[rstest]
592    #[case(SignatureType::EcdsaP256, 32)]
593    #[case(SignatureType::EcdsaP384, 48)]
594    #[case(SignatureType::EcdsaP521, 64)]
595    fn ecdsa_wrapped_up_to_max_len(
596        #[case] sig_type: SignatureType,
597        #[case] max_len: usize,
598    ) -> TestResult {
599        // the digest value is irrelevant - just the size of the digest
600        let digest = [0; 512 / 8];
601        let hash = AlgorithmIdentifier::new_sha(ShaVariant::SHA2_512);
602        let data = prepare_digest_data_for_openpgp(sig_type, hash, &digest)?;
603
604        // The data to be signed size needs to be truncated to the value specific the the curve
605        // being used. If the digest is short enough to be smaller than the curve specific field
606        // size the digest is used as a whole.
607        assert_eq!(
608            data.len(),
609            usize::min(max_len, digest.len()),
610            "the data to be signed's length ({}) cannot exceed maximum length imposed by the curve ({})",
611            data.len(),
612            max_len
613        );
614
615        Ok(())
616    }
617
618    #[rstest]
619    fn eddsa_is_not_wrapped() -> TestResult {
620        // the digest value is irrelevant - just the size of the digest
621        let digest = &[0; 512 / 8][..];
622
623        let hash = AlgorithmIdentifier::new_sha(ShaVariant::SHA2_512);
624        let data = prepare_digest_data_for_openpgp(SignatureType::EdDsa, hash, digest)?;
625
626        assert_eq!(data, digest);
627
628        Ok(())
629    }
630}