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 { 26 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 { 42 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 { 58 pub(crate) fn insecure(&self) -> bool { 59 matches!( 60 *self, 61 HashAlgorithm::Md2 | HashAlgorithm::Md5 | HashAlgorithm::Sha1 62 ) 63 } 64 65 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 { 80 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. 98 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 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. 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. 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