1 #[cfg(test)]
2 mod signature_hash_algorithm_test;
3
4 use std::fmt;
5
6 use crate::crypto::*;
7 use crate::error::*;
8
9 // HashAlgorithm is used to indicate the hash algorithm used
10 // https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-18
11 // Supported hash hash algorithms
12 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
13 pub enum HashAlgorithm {
14 Md2 = 0, // Blacklisted
15 Md5 = 1, // Blacklisted
16 Sha1 = 2, // Blacklisted
17 Sha224 = 3,
18 Sha256 = 4,
19 Sha384 = 5,
20 Sha512 = 6,
21 Ed25519 = 8,
22 Unsupported,
23 }
24
25 impl From<u8> for HashAlgorithm {
from(val: u8) -> Self26 fn from(val: u8) -> Self {
27 match val {
28 0 => HashAlgorithm::Md2,
29 1 => HashAlgorithm::Md5,
30 2 => HashAlgorithm::Sha1,
31 3 => HashAlgorithm::Sha224,
32 4 => HashAlgorithm::Sha256,
33 5 => HashAlgorithm::Sha384,
34 6 => HashAlgorithm::Sha512,
35 8 => HashAlgorithm::Ed25519,
36 _ => HashAlgorithm::Unsupported,
37 }
38 }
39 }
40
41 impl fmt::Display for HashAlgorithm {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result42 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43 match *self {
44 HashAlgorithm::Md2 => write!(f, "md2"),
45 HashAlgorithm::Md5 => write!(f, "md5"), // [RFC3279]
46 HashAlgorithm::Sha1 => write!(f, "sha-1"), // [RFC3279]
47 HashAlgorithm::Sha224 => write!(f, "sha-224"), // [RFC4055]
48 HashAlgorithm::Sha256 => write!(f, "sha-256"), // [RFC4055]
49 HashAlgorithm::Sha384 => write!(f, "sha-384"), // [RFC4055]
50 HashAlgorithm::Sha512 => write!(f, "sha-512"), // [RFC4055]
51 HashAlgorithm::Ed25519 => write!(f, "null"), // [RFC4055]
52 _ => write!(f, "unknown or unsupported hash algorithm"),
53 }
54 }
55 }
56
57 impl HashAlgorithm {
insecure(&self) -> bool58 pub(crate) fn insecure(&self) -> bool {
59 matches!(
60 *self,
61 HashAlgorithm::Md2 | HashAlgorithm::Md5 | HashAlgorithm::Sha1
62 )
63 }
64
invalid(&self) -> bool65 pub(crate) fn invalid(&self) -> bool {
66 matches!(*self, HashAlgorithm::Md2)
67 }
68 }
69
70 // https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-16
71 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
72 pub enum SignatureAlgorithm {
73 Rsa = 1,
74 Ecdsa = 3,
75 Ed25519 = 7,
76 Unsupported,
77 }
78
79 impl From<u8> for SignatureAlgorithm {
from(val: u8) -> Self80 fn from(val: u8) -> Self {
81 match val {
82 1 => SignatureAlgorithm::Rsa,
83 3 => SignatureAlgorithm::Ecdsa,
84 7 => SignatureAlgorithm::Ed25519,
85 _ => SignatureAlgorithm::Unsupported,
86 }
87 }
88 }
89
90 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
91 pub struct SignatureHashAlgorithm {
92 pub hash: HashAlgorithm,
93 pub signature: SignatureAlgorithm,
94 }
95
96 impl SignatureHashAlgorithm {
97 // is_compatible checks that given private key is compatible with the signature scheme.
is_compatible(&self, private_key: &CryptoPrivateKey) -> bool98 pub(crate) fn is_compatible(&self, private_key: &CryptoPrivateKey) -> bool {
99 match &private_key.kind {
100 CryptoPrivateKeyKind::Ed25519(_) => self.signature == SignatureAlgorithm::Ed25519,
101 CryptoPrivateKeyKind::Ecdsa256(_) => self.signature == SignatureAlgorithm::Ecdsa,
102 CryptoPrivateKeyKind::Rsa256(_) => self.signature == SignatureAlgorithm::Rsa,
103 }
104 }
105 }
106
default_signature_schemes() -> Vec<SignatureHashAlgorithm>107 pub(crate) fn default_signature_schemes() -> Vec<SignatureHashAlgorithm> {
108 vec![
109 SignatureHashAlgorithm {
110 hash: HashAlgorithm::Sha256,
111 signature: SignatureAlgorithm::Ecdsa,
112 },
113 SignatureHashAlgorithm {
114 hash: HashAlgorithm::Sha384,
115 signature: SignatureAlgorithm::Ecdsa,
116 },
117 SignatureHashAlgorithm {
118 hash: HashAlgorithm::Sha512,
119 signature: SignatureAlgorithm::Ecdsa,
120 },
121 SignatureHashAlgorithm {
122 hash: HashAlgorithm::Sha256,
123 signature: SignatureAlgorithm::Rsa,
124 },
125 SignatureHashAlgorithm {
126 hash: HashAlgorithm::Sha384,
127 signature: SignatureAlgorithm::Rsa,
128 },
129 SignatureHashAlgorithm {
130 hash: HashAlgorithm::Sha512,
131 signature: SignatureAlgorithm::Rsa,
132 },
133 SignatureHashAlgorithm {
134 hash: HashAlgorithm::Ed25519,
135 signature: SignatureAlgorithm::Ed25519,
136 },
137 ]
138 }
139
140 // select Signature Scheme returns most preferred and compatible scheme.
select_signature_scheme( sigs: &[SignatureHashAlgorithm], private_key: &CryptoPrivateKey, ) -> Result<SignatureHashAlgorithm>141 pub(crate) fn select_signature_scheme(
142 sigs: &[SignatureHashAlgorithm],
143 private_key: &CryptoPrivateKey,
144 ) -> Result<SignatureHashAlgorithm> {
145 for ss in sigs {
146 if ss.is_compatible(private_key) {
147 return Ok(*ss);
148 }
149 }
150
151 Err(Error::ErrNoAvailableSignatureSchemes)
152 }
153
154 // SignatureScheme identifies a signature algorithm supported by TLS. See
155 // RFC 8446, Section 4.2.3.
156 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
157 pub enum SignatureScheme {
158 // RSASSA-PKCS1-v1_5 algorithms.
159 Pkcs1WithSha256 = 0x0401,
160 Pkcs1WithSha384 = 0x0501,
161 Pkcs1WithSha512 = 0x0601,
162
163 // RSASSA-PSS algorithms with public key OID rsaEncryption.
164 PssWithSha256 = 0x0804,
165 PssWithSha384 = 0x0805,
166 PssWithSha512 = 0x0806,
167
168 // ECDSA algorithms. Only constrained to a specific curve in TLS 1.3.
169 EcdsaWithP256AndSha256 = 0x0403,
170 EcdsaWithP384AndSha384 = 0x0503,
171 EcdsaWithP521AndSha512 = 0x0603,
172
173 // EdDSA algorithms.
174 Ed25519 = 0x0807,
175
176 // Legacy signature and hash algorithms for TLS 1.2.
177 Pkcs1WithSha1 = 0x0201,
178 EcdsaWithSha1 = 0x0203,
179 }
180
181 // parse_signature_schemes translates []tls.SignatureScheme to []signatureHashAlgorithm.
182 // It returns default signature scheme list if no SignatureScheme is passed.
parse_signature_schemes( sigs: &[u16], insecure_hashes: bool, ) -> Result<Vec<SignatureHashAlgorithm>>183 pub(crate) fn parse_signature_schemes(
184 sigs: &[u16],
185 insecure_hashes: bool,
186 ) -> Result<Vec<SignatureHashAlgorithm>> {
187 if sigs.is_empty() {
188 return Ok(default_signature_schemes());
189 }
190
191 let mut out = vec![];
192 for ss in sigs {
193 let sig: SignatureAlgorithm = ((*ss & 0xFF) as u8).into();
194 if sig == SignatureAlgorithm::Unsupported {
195 return Err(Error::ErrInvalidSignatureAlgorithm);
196 }
197 let h: HashAlgorithm = (((*ss >> 8) & 0xFF) as u8).into();
198 if h == HashAlgorithm::Unsupported || h.invalid() {
199 return Err(Error::ErrInvalidHashAlgorithm);
200 }
201 if h.insecure() && !insecure_hashes {
202 continue;
203 }
204 out.push(SignatureHashAlgorithm {
205 hash: h,
206 signature: sig,
207 })
208 }
209
210 if out.is_empty() {
211 Err(Error::ErrNoAvailableSignatureSchemes)
212 } else {
213 Ok(out)
214 }
215 }
216