Coverage Report

Created: 2025-10-29 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rcgen-0.14.2/src/sign_algo.rs
Line
Count
Source
1
use std::fmt;
2
use std::hash::{Hash, Hasher};
3
4
use yasna::models::ObjectIdentifier;
5
use yasna::DERWriter;
6
use yasna::Tag;
7
8
#[cfg(feature = "crypto")]
9
use crate::ring_like::signature::{self, EcdsaSigningAlgorithm, EdDSAParameters, RsaEncoding};
10
use crate::Error;
11
12
#[cfg(feature = "crypto")]
13
#[derive(Clone, Copy, Debug)]
14
pub(crate) enum SignAlgo {
15
  EcDsa(&'static EcdsaSigningAlgorithm),
16
  EdDsa(&'static EdDSAParameters),
17
  Rsa(&'static dyn RsaEncoding),
18
}
19
20
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
21
pub(crate) enum SignatureAlgorithmParams {
22
  /// Omit the parameters
23
  None,
24
  /// Write null parameters
25
  Null,
26
  /// RSASSA-PSS-params as per RFC 4055
27
  RsaPss {
28
    hash_algorithm: &'static [u64],
29
    salt_length: u64,
30
  },
31
}
32
33
/// Signature algorithm type
34
#[derive(Clone)]
35
pub struct SignatureAlgorithm {
36
  oids_sign_alg: &'static [&'static [u64]],
37
  #[cfg(feature = "crypto")]
38
  pub(crate) sign_alg: SignAlgo,
39
  oid_components: &'static [u64],
40
  params: SignatureAlgorithmParams,
41
}
42
43
impl fmt::Debug for SignatureAlgorithm {
44
0
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45
    use algo::*;
46
0
    if self == &PKCS_RSA_SHA256 {
47
0
      write!(f, "PKCS_RSA_SHA256")
48
0
    } else if self == &PKCS_RSA_SHA384 {
49
0
      write!(f, "PKCS_RSA_SHA384")
50
0
    } else if self == &PKCS_RSA_SHA512 {
51
0
      write!(f, "PKCS_RSA_SHA512")
52
0
    } else if self == &PKCS_RSA_PSS_SHA256 {
53
0
      write!(f, "PKCS_RSA_PSS_SHA256")
54
0
    } else if self == &PKCS_ECDSA_P256_SHA256 {
55
0
      write!(f, "PKCS_ECDSA_P256_SHA256")
56
0
    } else if self == &PKCS_ECDSA_P384_SHA384 {
57
0
      write!(f, "PKCS_ECDSA_P384_SHA384")
58
0
    } else if self == &PKCS_ED25519 {
59
0
      write!(f, "PKCS_ED25519")
60
    } else {
61
      #[cfg(feature = "aws_lc_rs")]
62
0
      if self == &PKCS_ECDSA_P521_SHA512 {
63
0
        return write!(f, "PKCS_ECDSA_P521_SHA512");
64
0
      }
65
66
0
      write!(f, "Unknown")
67
    }
68
0
  }
69
}
70
71
impl PartialEq for SignatureAlgorithm {
72
0
  fn eq(&self, other: &Self) -> bool {
73
0
    (self.oids_sign_alg, self.oid_components) == (other.oids_sign_alg, other.oid_components)
74
0
  }
75
}
76
77
impl Eq for SignatureAlgorithm {}
78
79
/// The `Hash` trait is not derived, but implemented according to impl of the `PartialEq` trait
80
impl Hash for SignatureAlgorithm {
81
0
  fn hash<H: Hasher>(&self, state: &mut H) {
82
    // see SignatureAlgorithm::eq(), just this field is compared
83
0
    self.oids_sign_alg.hash(state);
84
0
  }
85
}
86
impl SignatureAlgorithm {
87
0
  pub(crate) fn iter() -> std::slice::Iter<'static, &'static SignatureAlgorithm> {
88
    use algo::*;
89
    static ALGORITHMS: &[&SignatureAlgorithm] = &[
90
      &PKCS_RSA_SHA256,
91
      &PKCS_RSA_SHA384,
92
      &PKCS_RSA_SHA512,
93
      //&PKCS_RSA_PSS_SHA256,
94
      &PKCS_ECDSA_P256_SHA256,
95
      &PKCS_ECDSA_P384_SHA384,
96
      #[cfg(feature = "aws_lc_rs")]
97
      &PKCS_ECDSA_P521_SHA512,
98
      &PKCS_ED25519,
99
    ];
100
0
    ALGORITHMS.iter()
101
0
  }
102
103
  /// Retrieve the SignatureAlgorithm for the provided OID
104
0
  pub fn from_oid(oid: &[u64]) -> Result<&'static SignatureAlgorithm, Error> {
105
0
    for algo in Self::iter() {
106
0
      if algo.oid_components == oid {
107
0
        return Ok(algo);
108
0
      }
109
    }
110
0
    Err(Error::UnsupportedSignatureAlgorithm)
111
0
  }
112
}
113
114
/// The list of supported signature algorithms
115
pub(crate) mod algo {
116
  use crate::oid::*;
117
118
  use super::*;
119
120
  /// RSA signing with PKCS#1 1.5 padding and SHA-256 hashing as per [RFC 4055](https://tools.ietf.org/html/rfc4055)
121
  pub static PKCS_RSA_SHA256: SignatureAlgorithm = SignatureAlgorithm {
122
    oids_sign_alg: &[RSA_ENCRYPTION],
123
    #[cfg(feature = "crypto")]
124
    sign_alg: SignAlgo::Rsa(&signature::RSA_PKCS1_SHA256),
125
    // sha256WithRSAEncryption in RFC 4055
126
    oid_components: &[1, 2, 840, 113549, 1, 1, 11],
127
    params: SignatureAlgorithmParams::Null,
128
  };
129
130
  /// RSA signing with PKCS#1 1.5 padding and SHA-256 hashing as per [RFC 4055](https://tools.ietf.org/html/rfc4055)
131
  pub static PKCS_RSA_SHA384: SignatureAlgorithm = SignatureAlgorithm {
132
    oids_sign_alg: &[RSA_ENCRYPTION],
133
    #[cfg(feature = "crypto")]
134
    sign_alg: SignAlgo::Rsa(&signature::RSA_PKCS1_SHA384),
135
    // sha384WithRSAEncryption in RFC 4055
136
    oid_components: &[1, 2, 840, 113549, 1, 1, 12],
137
    params: SignatureAlgorithmParams::Null,
138
  };
139
140
  /// RSA signing with PKCS#1 1.5 padding and SHA-512 hashing as per [RFC 4055](https://tools.ietf.org/html/rfc4055)
141
  pub static PKCS_RSA_SHA512: SignatureAlgorithm = SignatureAlgorithm {
142
    oids_sign_alg: &[RSA_ENCRYPTION],
143
    #[cfg(feature = "crypto")]
144
    sign_alg: SignAlgo::Rsa(&signature::RSA_PKCS1_SHA512),
145
    // sha512WithRSAEncryption in RFC 4055
146
    oid_components: &[1, 2, 840, 113549, 1, 1, 13],
147
    params: SignatureAlgorithmParams::Null,
148
  };
149
150
  // TODO: not really sure whether the certs we generate actually work.
151
  // Both openssl and webpki reject them. It *might* be possible that openssl
152
  // accepts the certificate if the key is a proper RSA-PSS key, but ring doesn't
153
  // support those: https://github.com/briansmith/ring/issues/1353
154
  //
155
  /// RSA signing with PKCS#1 2.1 RSASSA-PSS padding and SHA-256 hashing as per [RFC 4055](https://tools.ietf.org/html/rfc4055)
156
  pub(crate) static PKCS_RSA_PSS_SHA256: SignatureAlgorithm = SignatureAlgorithm {
157
    // We could also use RSA_ENCRYPTION here, but it's recommended
158
    // to use ID-RSASSA-PSS if possible.
159
    oids_sign_alg: &[RSASSA_PSS],
160
    #[cfg(feature = "crypto")]
161
    sign_alg: SignAlgo::Rsa(&signature::RSA_PSS_SHA256),
162
    oid_components: RSASSA_PSS, //&[1, 2, 840, 113549, 1, 1, 13],
163
    // rSASSA-PSS-SHA256-Params in RFC 4055
164
    params: SignatureAlgorithmParams::RsaPss {
165
      // id-sha256 in https://datatracker.ietf.org/doc/html/rfc4055#section-2.1
166
      hash_algorithm: &[2, 16, 840, 1, 101, 3, 4, 2, 1],
167
      salt_length: 20,
168
    },
169
  };
170
171
  /// ECDSA signing using the P-256 curves and SHA-256 hashing as per [RFC 5758](https://tools.ietf.org/html/rfc5758#section-3.2)
172
  pub static PKCS_ECDSA_P256_SHA256: SignatureAlgorithm = SignatureAlgorithm {
173
    oids_sign_alg: &[EC_PUBLIC_KEY, EC_SECP_256_R1],
174
    #[cfg(feature = "crypto")]
175
    sign_alg: SignAlgo::EcDsa(&signature::ECDSA_P256_SHA256_ASN1_SIGNING),
176
    // ecdsa-with-SHA256 in RFC 5758
177
    oid_components: &[1, 2, 840, 10045, 4, 3, 2],
178
    params: SignatureAlgorithmParams::None,
179
  };
180
181
  /// ECDSA signing using the P-384 curves and SHA-384 hashing as per [RFC 5758](https://tools.ietf.org/html/rfc5758#section-3.2)
182
  pub static PKCS_ECDSA_P384_SHA384: SignatureAlgorithm = SignatureAlgorithm {
183
    oids_sign_alg: &[EC_PUBLIC_KEY, EC_SECP_384_R1],
184
    #[cfg(feature = "crypto")]
185
    sign_alg: SignAlgo::EcDsa(&signature::ECDSA_P384_SHA384_ASN1_SIGNING),
186
    // ecdsa-with-SHA384 in RFC 5758
187
    oid_components: &[1, 2, 840, 10045, 4, 3, 3],
188
    params: SignatureAlgorithmParams::None,
189
  };
190
  /// ECDSA signing using the P-521 curves and SHA-512 hashing as per [RFC 5758](https://tools.ietf.org/html/rfc5758#section-3.2)
191
  /// Currently this is only supported with the `aws_lc_rs` feature
192
  #[cfg(feature = "aws_lc_rs")]
193
  pub static PKCS_ECDSA_P521_SHA512: SignatureAlgorithm = SignatureAlgorithm {
194
    oids_sign_alg: &[EC_PUBLIC_KEY, EC_SECP_521_R1],
195
    #[cfg(feature = "crypto")]
196
    sign_alg: SignAlgo::EcDsa(&signature::ECDSA_P521_SHA512_ASN1_SIGNING),
197
    // ecdsa-with-SHA512 in RFC 5758
198
    oid_components: &[1, 2, 840, 10045, 4, 3, 4],
199
    params: SignatureAlgorithmParams::None,
200
  };
201
202
  /// ED25519 curve signing as per [RFC 8410](https://tools.ietf.org/html/rfc8410)
203
  pub static PKCS_ED25519: SignatureAlgorithm = SignatureAlgorithm {
204
    // id-Ed25519 in RFC 8410
205
    oids_sign_alg: &[&[1, 3, 101, 112]],
206
    #[cfg(feature = "crypto")]
207
    sign_alg: SignAlgo::EdDsa(&signature::ED25519),
208
    // id-Ed25519 in RFC 8410
209
    oid_components: &[1, 3, 101, 112],
210
    params: SignatureAlgorithmParams::None,
211
  };
212
}
213
// Signature algorithm IDs as per https://tools.ietf.org/html/rfc4055
214
impl SignatureAlgorithm {
215
0
  fn alg_ident_oid(&self) -> ObjectIdentifier {
216
0
    ObjectIdentifier::from_slice(self.oid_components)
217
0
  }
218
0
  fn write_params(&self, writer: &mut yasna::DERWriterSeq) {
219
0
    match self.params {
220
0
      SignatureAlgorithmParams::None => (),
221
0
      SignatureAlgorithmParams::Null => {
222
0
        writer.next().write_null();
223
0
      },
224
      SignatureAlgorithmParams::RsaPss {
225
0
        hash_algorithm,
226
0
        salt_length,
227
      } => {
228
0
        writer.next().write_sequence(|writer| {
229
          // https://datatracker.ietf.org/doc/html/rfc4055#section-3.1
230
231
0
          let oid = ObjectIdentifier::from_slice(hash_algorithm);
232
          // hashAlgorithm
233
0
          writer.next().write_tagged(Tag::context(0), |writer| {
234
0
            writer.write_sequence(|writer| {
235
0
              writer.next().write_oid(&oid);
236
0
            });
237
0
          });
238
          // maskGenAlgorithm
239
0
          writer.next().write_tagged(Tag::context(1), |writer| {
240
0
            writer.write_sequence(|writer| {
241
              // id-mgf1 in RFC 4055
242
              const ID_MGF1: &[u64] = &[1, 2, 840, 113549, 1, 1, 8];
243
0
              let oid = ObjectIdentifier::from_slice(ID_MGF1);
244
0
              writer.next().write_oid(&oid);
245
0
              writer.next().write_sequence(|writer| {
246
0
                let oid = ObjectIdentifier::from_slice(hash_algorithm);
247
0
                writer.next().write_oid(&oid);
248
0
                writer.next().write_null();
249
0
              });
250
0
            });
251
0
          });
252
          // saltLength
253
0
          writer.next().write_tagged(Tag::context(2), |writer| {
254
0
            writer.write_u64(salt_length);
255
0
          });
256
          // We *must* omit the trailerField element as per RFC 4055 section 3.1
257
0
        })
258
      },
259
    }
260
0
  }
261
  /// Writes the algorithm identifier as it appears inside a signature
262
0
  pub(crate) fn write_alg_ident(&self, writer: DERWriter) {
263
0
    writer.write_sequence(|writer| {
264
0
      writer.next().write_oid(&self.alg_ident_oid());
265
0
      self.write_params(writer);
266
0
    });
267
0
  }
268
  /// Writes the algorithm identifier as it appears inside subjectPublicKeyInfo
269
0
  pub(crate) fn write_oids_sign_alg(&self, writer: DERWriter) {
270
0
    writer.write_sequence(|writer| {
271
0
      for oid in self.oids_sign_alg {
272
0
        let oid = ObjectIdentifier::from_slice(oid);
273
0
        writer.next().write_oid(&oid);
274
0
      }
275
0
      self.write_params(writer);
276
0
    });
277
0
  }
278
}