| 1 | #![allow (clippy::upper_case_acronyms)] |
| 2 | #![allow (non_camel_case_types)] |
| 3 | use crate::crypto::KeyExchangeAlgorithm; |
| 4 | use crate::msgs::codec::{Codec, Reader}; |
| 5 | |
| 6 | enum_builder! { |
| 7 | /// The `HashAlgorithm` TLS protocol enum. Values in this enum are taken |
| 8 | /// from the various RFCs covering TLS, and are listed by IANA. |
| 9 | /// The `Unknown` item is used when processing unrecognised ordinals. |
| 10 | #[repr(u8)] |
| 11 | pub enum HashAlgorithm { |
| 12 | NONE => 0x00, |
| 13 | MD5 => 0x01, |
| 14 | SHA1 => 0x02, |
| 15 | SHA224 => 0x03, |
| 16 | SHA256 => 0x04, |
| 17 | SHA384 => 0x05, |
| 18 | SHA512 => 0x06, |
| 19 | } |
| 20 | } |
| 21 | |
| 22 | enum_builder! { |
| 23 | /// The `ClientCertificateType` TLS protocol enum. Values in this enum are taken |
| 24 | /// from the various RFCs covering TLS, and are listed by IANA. |
| 25 | /// The `Unknown` item is used when processing unrecognised ordinals. |
| 26 | #[repr(u8)] |
| 27 | pub(crate) enum ClientCertificateType { |
| 28 | RSASign => 0x01, |
| 29 | DSSSign => 0x02, |
| 30 | RSAFixedDH => 0x03, |
| 31 | DSSFixedDH => 0x04, |
| 32 | RSAEphemeralDH => 0x05, |
| 33 | DSSEphemeralDH => 0x06, |
| 34 | FortezzaDMS => 0x14, |
| 35 | ECDSASign => 0x40, |
| 36 | RSAFixedECDH => 0x41, |
| 37 | ECDSAFixedECDH => 0x42, |
| 38 | } |
| 39 | } |
| 40 | |
| 41 | enum_builder! { |
| 42 | /// The `Compression` TLS protocol enum. Values in this enum are taken |
| 43 | /// from the various RFCs covering TLS, and are listed by IANA. |
| 44 | /// The `Unknown` item is used when processing unrecognised ordinals. |
| 45 | #[repr(u8)] |
| 46 | pub enum Compression { |
| 47 | Null => 0x00, |
| 48 | Deflate => 0x01, |
| 49 | LSZ => 0x40, |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | enum_builder! { |
| 54 | /// The `AlertLevel` TLS protocol enum. Values in this enum are taken |
| 55 | /// from the various RFCs covering TLS, and are listed by IANA. |
| 56 | /// The `Unknown` item is used when processing unrecognised ordinals. |
| 57 | #[repr(u8)] |
| 58 | pub enum AlertLevel { |
| 59 | Warning => 0x01, |
| 60 | Fatal => 0x02, |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | enum_builder! { |
| 65 | /// The `HeartbeatMessageType` TLS protocol enum. Values in this enum are taken |
| 66 | /// from the various RFCs covering TLS, and are listed by IANA. |
| 67 | /// The `Unknown` item is used when processing unrecognised ordinals. |
| 68 | #[repr(u8)] |
| 69 | pub(crate) enum HeartbeatMessageType { |
| 70 | Request => 0x01, |
| 71 | Response => 0x02, |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | enum_builder! { |
| 76 | /// The `ExtensionType` TLS protocol enum. Values in this enum are taken |
| 77 | /// from the various RFCs covering TLS, and are listed by IANA. |
| 78 | /// The `Unknown` item is used when processing unrecognised ordinals. |
| 79 | #[repr(u16)] |
| 80 | pub enum ExtensionType { |
| 81 | ServerName => 0x0000, |
| 82 | MaxFragmentLength => 0x0001, |
| 83 | ClientCertificateUrl => 0x0002, |
| 84 | TrustedCAKeys => 0x0003, |
| 85 | TruncatedHMAC => 0x0004, |
| 86 | StatusRequest => 0x0005, |
| 87 | UserMapping => 0x0006, |
| 88 | ClientAuthz => 0x0007, |
| 89 | ServerAuthz => 0x0008, |
| 90 | CertificateType => 0x0009, |
| 91 | EllipticCurves => 0x000a, |
| 92 | ECPointFormats => 0x000b, |
| 93 | SRP => 0x000c, |
| 94 | SignatureAlgorithms => 0x000d, |
| 95 | UseSRTP => 0x000e, |
| 96 | Heartbeat => 0x000f, |
| 97 | ALProtocolNegotiation => 0x0010, |
| 98 | SCT => 0x0012, |
| 99 | ClientCertificateType => 0x0013, |
| 100 | ServerCertificateType => 0x0014, |
| 101 | Padding => 0x0015, |
| 102 | ExtendedMasterSecret => 0x0017, |
| 103 | CompressCertificate => 0x001b, |
| 104 | SessionTicket => 0x0023, |
| 105 | PreSharedKey => 0x0029, |
| 106 | EarlyData => 0x002a, |
| 107 | SupportedVersions => 0x002b, |
| 108 | Cookie => 0x002c, |
| 109 | PSKKeyExchangeModes => 0x002d, |
| 110 | TicketEarlyDataInfo => 0x002e, |
| 111 | CertificateAuthorities => 0x002f, |
| 112 | OIDFilters => 0x0030, |
| 113 | PostHandshakeAuth => 0x0031, |
| 114 | SignatureAlgorithmsCert => 0x0032, |
| 115 | KeyShare => 0x0033, |
| 116 | TransportParameters => 0x0039, |
| 117 | NextProtocolNegotiation => 0x3374, |
| 118 | ChannelId => 0x754f, |
| 119 | RenegotiationInfo => 0xff01, |
| 120 | TransportParametersDraft => 0xffa5, |
| 121 | EncryptedClientHello => 0xfe0d, // https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-18#section-11.1 |
| 122 | EncryptedClientHelloOuterExtensions => 0xfd00, // https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-18#section-5.1 |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | impl ExtensionType { |
| 127 | /// Returns true if the extension type can be compressed in an "inner" client hello for ECH. |
| 128 | /// |
| 129 | /// This function should only return true for extension types where the inner hello and outer |
| 130 | /// hello extensions values will always be identical. Extensions that may be identical |
| 131 | /// sometimes (e.g. server name, cert compression methods), but not always, SHOULD NOT be |
| 132 | /// compressed. |
| 133 | /// |
| 134 | /// See [draft-ietf-esni-18 §5](https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-18#section-5) |
| 135 | /// and [draft-ietf-esni-18 §10.5](https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-18#section-10.5) |
| 136 | /// for more information. |
| 137 | pub(crate) fn ech_compress(&self) -> bool { |
| 138 | // We match which extensions we will compress with BoringSSL and Go's stdlib. |
| 139 | matches!( |
| 140 | self, |
| 141 | Self::StatusRequest |
| 142 | | Self::EllipticCurves |
| 143 | | Self::SignatureAlgorithms |
| 144 | | Self::SignatureAlgorithmsCert |
| 145 | | Self::ALProtocolNegotiation |
| 146 | | Self::SupportedVersions |
| 147 | | Self::Cookie |
| 148 | | Self::KeyShare |
| 149 | | Self::PSKKeyExchangeModes |
| 150 | ) |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | enum_builder! { |
| 155 | /// The `ServerNameType` TLS protocol enum. Values in this enum are taken |
| 156 | /// from the various RFCs covering TLS, and are listed by IANA. |
| 157 | /// The `Unknown` item is used when processing unrecognised ordinals. |
| 158 | #[repr(u8)] |
| 159 | pub(crate) enum ServerNameType { |
| 160 | HostName => 0x00, |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | enum_builder! { |
| 165 | /// The `NamedCurve` TLS protocol enum. Values in this enum are taken |
| 166 | /// from the various RFCs covering TLS, and are listed by IANA. |
| 167 | /// The `Unknown` item is used when processing unrecognised ordinals. |
| 168 | /// |
| 169 | /// This enum is used for recognizing elliptic curve parameters advertised |
| 170 | /// by a peer during a TLS handshake. It is **not** a list of curves that |
| 171 | /// Rustls supports. See [`crate::crypto::ring::kx_group`] for the list of supported |
| 172 | /// elliptic curve groups. |
| 173 | #[repr(u16)] |
| 174 | pub(crate) enum NamedCurve { |
| 175 | sect163k1 => 0x0001, |
| 176 | sect163r1 => 0x0002, |
| 177 | sect163r2 => 0x0003, |
| 178 | sect193r1 => 0x0004, |
| 179 | sect193r2 => 0x0005, |
| 180 | sect233k1 => 0x0006, |
| 181 | sect233r1 => 0x0007, |
| 182 | sect239k1 => 0x0008, |
| 183 | sect283k1 => 0x0009, |
| 184 | sect283r1 => 0x000a, |
| 185 | sect409k1 => 0x000b, |
| 186 | sect409r1 => 0x000c, |
| 187 | sect571k1 => 0x000d, |
| 188 | sect571r1 => 0x000e, |
| 189 | secp160k1 => 0x000f, |
| 190 | secp160r1 => 0x0010, |
| 191 | secp160r2 => 0x0011, |
| 192 | secp192k1 => 0x0012, |
| 193 | secp192r1 => 0x0013, |
| 194 | secp224k1 => 0x0014, |
| 195 | secp224r1 => 0x0015, |
| 196 | secp256k1 => 0x0016, |
| 197 | secp256r1 => 0x0017, |
| 198 | secp384r1 => 0x0018, |
| 199 | secp521r1 => 0x0019, |
| 200 | brainpoolp256r1 => 0x001a, |
| 201 | brainpoolp384r1 => 0x001b, |
| 202 | brainpoolp512r1 => 0x001c, |
| 203 | X25519 => 0x001d, |
| 204 | X448 => 0x001e, |
| 205 | arbitrary_explicit_prime_curves => 0xff01, |
| 206 | arbitrary_explicit_char2_curves => 0xff02, |
| 207 | } |
| 208 | } |
| 209 | |
| 210 | enum_builder! { |
| 211 | /// The `NamedGroup` TLS protocol enum. Values in this enum are taken |
| 212 | /// from the various RFCs covering TLS, and are listed by IANA. |
| 213 | /// The `Unknown` item is used when processing unrecognised ordinals. |
| 214 | #[repr(u16)] |
| 215 | pub enum NamedGroup { |
| 216 | secp256r1 => 0x0017, |
| 217 | secp384r1 => 0x0018, |
| 218 | secp521r1 => 0x0019, |
| 219 | X25519 => 0x001d, |
| 220 | X448 => 0x001e, |
| 221 | FFDHE2048 => 0x0100, |
| 222 | FFDHE3072 => 0x0101, |
| 223 | FFDHE4096 => 0x0102, |
| 224 | FFDHE6144 => 0x0103, |
| 225 | FFDHE8192 => 0x0104, |
| 226 | MLKEM512 => 0x0200, |
| 227 | MLKEM768 => 0x0201, |
| 228 | MLKEM1024 => 0x0202, |
| 229 | secp256r1MLKEM768 => 0x11eb, |
| 230 | X25519MLKEM768 => 0x11ec, |
| 231 | } |
| 232 | } |
| 233 | |
| 234 | impl NamedGroup { |
| 235 | /// Return the key exchange algorithm associated with this `NamedGroup` |
| 236 | pub fn key_exchange_algorithm(self) -> KeyExchangeAlgorithm { |
| 237 | match u16::from(self) { |
| 238 | x: u16 if (0x100..0x200).contains(&x) => KeyExchangeAlgorithm::DHE, |
| 239 | _ => KeyExchangeAlgorithm::ECDHE, |
| 240 | } |
| 241 | } |
| 242 | } |
| 243 | |
| 244 | enum_builder! { |
| 245 | /// The `ECPointFormat` TLS protocol enum. Values in this enum are taken |
| 246 | /// from the various RFCs covering TLS, and are listed by IANA. |
| 247 | /// The `Unknown` item is used when processing unrecognised ordinals. |
| 248 | #[repr(u8)] |
| 249 | pub enum ECPointFormat { |
| 250 | Uncompressed => 0x00, |
| 251 | ANSIX962CompressedPrime => 0x01, |
| 252 | ANSIX962CompressedChar2 => 0x02, |
| 253 | } |
| 254 | } |
| 255 | |
| 256 | impl ECPointFormat { |
| 257 | pub(crate) const SUPPORTED: [Self; 1] = [Self::Uncompressed]; |
| 258 | } |
| 259 | |
| 260 | enum_builder! { |
| 261 | /// The `HeartbeatMode` TLS protocol enum. Values in this enum are taken |
| 262 | /// from the various RFCs covering TLS, and are listed by IANA. |
| 263 | /// The `Unknown` item is used when processing unrecognised ordinals. |
| 264 | #[repr(u8)] |
| 265 | pub(crate) enum HeartbeatMode { |
| 266 | PeerAllowedToSend => 0x01, |
| 267 | PeerNotAllowedToSend => 0x02, |
| 268 | } |
| 269 | } |
| 270 | |
| 271 | enum_builder! { |
| 272 | /// The `ECCurveType` TLS protocol enum. Values in this enum are taken |
| 273 | /// from the various RFCs covering TLS, and are listed by IANA. |
| 274 | /// The `Unknown` item is used when processing unrecognised ordinals. |
| 275 | #[repr(u8)] |
| 276 | pub(crate) enum ECCurveType { |
| 277 | ExplicitPrime => 0x01, |
| 278 | ExplicitChar2 => 0x02, |
| 279 | NamedCurve => 0x03, |
| 280 | } |
| 281 | } |
| 282 | |
| 283 | enum_builder! { |
| 284 | /// The `PSKKeyExchangeMode` TLS protocol enum. Values in this enum are taken |
| 285 | /// from the various RFCs covering TLS, and are listed by IANA. |
| 286 | /// The `Unknown` item is used when processing unrecognised ordinals. |
| 287 | #[repr(u8)] |
| 288 | pub enum PSKKeyExchangeMode { |
| 289 | PSK_KE => 0x00, |
| 290 | PSK_DHE_KE => 0x01, |
| 291 | } |
| 292 | } |
| 293 | |
| 294 | enum_builder! { |
| 295 | /// The `KeyUpdateRequest` TLS protocol enum. Values in this enum are taken |
| 296 | /// from the various RFCs covering TLS, and are listed by IANA. |
| 297 | /// The `Unknown` item is used when processing unrecognised ordinals. |
| 298 | #[repr(u8)] |
| 299 | pub enum KeyUpdateRequest { |
| 300 | UpdateNotRequested => 0x00, |
| 301 | UpdateRequested => 0x01, |
| 302 | } |
| 303 | } |
| 304 | |
| 305 | enum_builder! { |
| 306 | /// The `CertificateStatusType` TLS protocol enum. Values in this enum are taken |
| 307 | /// from the various RFCs covering TLS, and are listed by IANA. |
| 308 | /// The `Unknown` item is used when processing unrecognised ordinals. |
| 309 | #[repr(u8)] |
| 310 | pub enum CertificateStatusType { |
| 311 | OCSP => 0x01, |
| 312 | } |
| 313 | } |
| 314 | |
| 315 | enum_builder! { |
| 316 | /// The `CertificateType` enum sent in the cert_type extensions. |
| 317 | /// Values in this enum are taken from the various RFCs covering TLS, and are listed by IANA. |
| 318 | /// |
| 319 | /// [RFC 6091 Section 5]: <https://datatracker.ietf.org/doc/html/rfc6091#section-5> |
| 320 | /// [RFC 7250 Section 7]: <https://datatracker.ietf.org/doc/html/rfc7250#section-7> |
| 321 | #[repr(u8)] |
| 322 | pub enum CertificateType { |
| 323 | X509 => 0x00, |
| 324 | RawPublicKey => 0x02, |
| 325 | } |
| 326 | } |
| 327 | |
| 328 | enum_builder! { |
| 329 | /// The Key Encapsulation Mechanism (`Kem`) type for HPKE operations. |
| 330 | /// Listed by IANA, as specified in [RFC 9180 Section 7.1] |
| 331 | /// |
| 332 | /// [RFC 9180 Section 7.1]: <https://datatracker.ietf.org/doc/html/rfc9180#kemid-values> |
| 333 | #[repr(u16)] |
| 334 | pub enum HpkeKem { |
| 335 | DHKEM_P256_HKDF_SHA256 => 0x0010, |
| 336 | DHKEM_P384_HKDF_SHA384 => 0x0011, |
| 337 | DHKEM_P521_HKDF_SHA512 => 0x0012, |
| 338 | DHKEM_X25519_HKDF_SHA256 => 0x0020, |
| 339 | DHKEM_X448_HKDF_SHA512 => 0x0021, |
| 340 | } |
| 341 | } |
| 342 | |
| 343 | enum_builder! { |
| 344 | /// The Key Derivation Function (`Kdf`) type for HPKE operations. |
| 345 | /// Listed by IANA, as specified in [RFC 9180 Section 7.2] |
| 346 | /// |
| 347 | /// [RFC 9180 Section 7.2]: <https://datatracker.ietf.org/doc/html/rfc9180#name-key-derivation-functions-kd> |
| 348 | #[repr(u16)] |
| 349 | pub enum HpkeKdf { |
| 350 | HKDF_SHA256 => 0x0001, |
| 351 | HKDF_SHA384 => 0x0002, |
| 352 | HKDF_SHA512 => 0x0003, |
| 353 | } |
| 354 | } |
| 355 | |
| 356 | impl Default for HpkeKdf { |
| 357 | // TODO(XXX): revisit the default configuration. This is just what Cloudflare ships right now. |
| 358 | fn default() -> Self { |
| 359 | Self::HKDF_SHA256 |
| 360 | } |
| 361 | } |
| 362 | |
| 363 | enum_builder! { |
| 364 | /// The Authenticated Encryption with Associated Data (`Aead`) type for HPKE operations. |
| 365 | /// Listed by IANA, as specified in [RFC 9180 Section 7.3] |
| 366 | /// |
| 367 | /// [RFC 9180 Section 7.3]: <https://datatracker.ietf.org/doc/html/rfc9180#name-authenticated-encryption-wi> |
| 368 | #[repr(u16)] |
| 369 | pub enum HpkeAead { |
| 370 | AES_128_GCM => 0x0001, |
| 371 | AES_256_GCM => 0x0002, |
| 372 | CHACHA20_POLY_1305 => 0x0003, |
| 373 | EXPORT_ONLY => 0xFFFF, |
| 374 | } |
| 375 | } |
| 376 | |
| 377 | impl HpkeAead { |
| 378 | /// Returns the length of the tag for the AEAD algorithm, or none if the AEAD is EXPORT_ONLY. |
| 379 | pub(crate) fn tag_len(&self) -> Option<usize> { |
| 380 | match self { |
| 381 | // See RFC 9180 Section 7.3, column `Nt`, the length in bytes of the authentication tag |
| 382 | // for the algorithm. |
| 383 | // https://www.rfc-editor.org/rfc/rfc9180.html#section-7.3 |
| 384 | Self::AES_128_GCM | Self::AES_256_GCM | Self::CHACHA20_POLY_1305 => Some(16), |
| 385 | _ => None, |
| 386 | } |
| 387 | } |
| 388 | } |
| 389 | |
| 390 | impl Default for HpkeAead { |
| 391 | // TODO(XXX): revisit the default configuration. This is just what Cloudflare ships right now. |
| 392 | fn default() -> Self { |
| 393 | Self::AES_128_GCM |
| 394 | } |
| 395 | } |
| 396 | |
| 397 | enum_builder! { |
| 398 | /// The Encrypted Client Hello protocol version (`EchVersion`). |
| 399 | /// |
| 400 | /// Specified in [draft-ietf-tls-esni Section 4]. |
| 401 | /// TODO(XXX): Update reference once RFC is published. |
| 402 | /// |
| 403 | /// [draft-ietf-tls-esni Section 4]: <https://www.ietf.org/archive/id/draft-ietf-tls-esni-17.html#section-4> |
| 404 | #[repr(u16)] |
| 405 | pub enum EchVersion { |
| 406 | V18 => 0xfe0d, |
| 407 | } |
| 408 | } |
| 409 | |
| 410 | #[cfg (test)] |
| 411 | pub(crate) mod tests { |
| 412 | // These tests are intended to provide coverage and |
| 413 | // check panic-safety of relatively unused values. |
| 414 | |
| 415 | use std::prelude::v1::*; |
| 416 | |
| 417 | use super::*; |
| 418 | |
| 419 | #[test ] |
| 420 | fn test_enums() { |
| 421 | test_enum8::<HashAlgorithm>(HashAlgorithm::NONE, HashAlgorithm::SHA512); |
| 422 | test_enum8::<ClientCertificateType>( |
| 423 | ClientCertificateType::RSASign, |
| 424 | ClientCertificateType::ECDSAFixedECDH, |
| 425 | ); |
| 426 | test_enum8::<Compression>(Compression::Null, Compression::LSZ); |
| 427 | test_enum8::<AlertLevel>(AlertLevel::Warning, AlertLevel::Fatal); |
| 428 | test_enum8::<HeartbeatMessageType>( |
| 429 | HeartbeatMessageType::Request, |
| 430 | HeartbeatMessageType::Response, |
| 431 | ); |
| 432 | test_enum16::<ExtensionType>(ExtensionType::ServerName, ExtensionType::RenegotiationInfo); |
| 433 | test_enum8::<ServerNameType>(ServerNameType::HostName, ServerNameType::HostName); |
| 434 | test_enum16::<NamedCurve>( |
| 435 | NamedCurve::sect163k1, |
| 436 | NamedCurve::arbitrary_explicit_char2_curves, |
| 437 | ); |
| 438 | test_enum16::<NamedGroup>(NamedGroup::secp256r1, NamedGroup::FFDHE8192); |
| 439 | test_enum8::<ECPointFormat>( |
| 440 | ECPointFormat::Uncompressed, |
| 441 | ECPointFormat::ANSIX962CompressedChar2, |
| 442 | ); |
| 443 | test_enum8::<HeartbeatMode>( |
| 444 | HeartbeatMode::PeerAllowedToSend, |
| 445 | HeartbeatMode::PeerNotAllowedToSend, |
| 446 | ); |
| 447 | test_enum8::<ECCurveType>(ECCurveType::ExplicitPrime, ECCurveType::NamedCurve); |
| 448 | test_enum8::<PSKKeyExchangeMode>( |
| 449 | PSKKeyExchangeMode::PSK_KE, |
| 450 | PSKKeyExchangeMode::PSK_DHE_KE, |
| 451 | ); |
| 452 | test_enum8::<KeyUpdateRequest>( |
| 453 | KeyUpdateRequest::UpdateNotRequested, |
| 454 | KeyUpdateRequest::UpdateRequested, |
| 455 | ); |
| 456 | test_enum8::<CertificateStatusType>( |
| 457 | CertificateStatusType::OCSP, |
| 458 | CertificateStatusType::OCSP, |
| 459 | ); |
| 460 | test_enum8::<CertificateType>(CertificateType::X509, CertificateType::RawPublicKey); |
| 461 | } |
| 462 | |
| 463 | pub(crate) fn test_enum8<T: for<'a> Codec<'a>>(first: T, last: T) { |
| 464 | let first_v = get8(&first); |
| 465 | let last_v = get8(&last); |
| 466 | |
| 467 | for val in first_v..last_v + 1 { |
| 468 | let mut buf = Vec::new(); |
| 469 | val.encode(&mut buf); |
| 470 | assert_eq!(buf.len(), 1); |
| 471 | |
| 472 | let t = T::read_bytes(&buf).unwrap(); |
| 473 | assert_eq!(val, get8(&t)); |
| 474 | } |
| 475 | } |
| 476 | |
| 477 | pub(crate) fn test_enum16<T: for<'a> Codec<'a>>(first: T, last: T) { |
| 478 | let first_v = get16(&first); |
| 479 | let last_v = get16(&last); |
| 480 | |
| 481 | for val in first_v..last_v + 1 { |
| 482 | let mut buf = Vec::new(); |
| 483 | val.encode(&mut buf); |
| 484 | assert_eq!(buf.len(), 2); |
| 485 | |
| 486 | let t = T::read_bytes(&buf).unwrap(); |
| 487 | assert_eq!(val, get16(&t)); |
| 488 | } |
| 489 | } |
| 490 | |
| 491 | fn get8<T: for<'a> Codec<'a>>(enum_value: &T) -> u8 { |
| 492 | let enc = enum_value.get_encoding(); |
| 493 | assert_eq!(enc.len(), 1); |
| 494 | enc[0] |
| 495 | } |
| 496 | |
| 497 | fn get16<T: for<'a> Codec<'a>>(enum_value: &T) -> u16 { |
| 498 | let enc = enum_value.get_encoding(); |
| 499 | assert_eq!(enc.len(), 2); |
| 500 | (enc[0] as u16 >> 8) | (enc[1] as u16) |
| 501 | } |
| 502 | } |
| 503 | |