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