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