1 use serde::{de, ser, Deserialize, Serialize};
2 use std::fmt;
3 
4 #[derive(Debug, PartialEq, Clone, Copy)]
5 #[repr(u8)]
6 pub enum Version {
7     V1 = 0x00,
8     V2 = 0x01,
9     V3 = 0x02,
10 }
11 
12 impl Default for Version {
default() -> Self13     fn default() -> Self {
14         Self::V1
15     }
16 }
17 
18 impl Version {
from_u8(v: u8) -> Option<Self>19     pub fn from_u8(v: u8) -> Option<Self> {
20         match v {
21             0x00 => Some(Self::V1),
22             0x01 => Some(Self::V2),
23             0x02 => Some(Self::V3),
24             _ => None,
25         }
26     }
27 }
28 
29 impl Serialize for Version {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: ser::Serializer,30     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
31     where
32         S: ser::Serializer,
33     {
34         serializer.serialize_u8(*self as u8)
35     }
36 }
37 
38 impl<'de> Deserialize<'de> for Version {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: de::Deserializer<'de>,39     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
40     where
41         D: de::Deserializer<'de>,
42     {
43         struct Visitor;
44 
45         impl<'de> de::Visitor<'de> for Visitor {
46             type Value = Version;
47 
48             fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
49                 write!(formatter, "a valid version number")
50             }
51 
52             fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
53             where
54                 E: de::Error,
55             {
56                 let version = Version::from_u8(v).ok_or_else(|| {
57                     E::invalid_value(
58                         de::Unexpected::Other("invalid version number"),
59                         &"a valid integer representing a supported version number (0, 1 or 2)",
60                     )
61                 })?;
62 
63                 if version != Version::V3 {
64                     return Err(E::invalid_value(
65                         de::Unexpected::Other("unsupported certificate version"),
66                         &"only V3 certificate are supported",
67                     ));
68                 }
69 
70                 Ok(version)
71             }
72         }
73 
74         deserializer.deserialize_u8(Visitor)
75     }
76 }
77 
78 #[cfg(test)]
79 mod tests {
80     use super::*;
81     use picky_asn1::wrapper::{ApplicationTag9, Implicit};
82     use picky_asn1_der::Asn1DerError;
83 
84     #[derive(Serialize, Deserialize, Debug, PartialEq)]
85     struct OptionalVersionTestStruct {
86         #[serde(skip_serializing_if = "version_is_default")]
87         version: Implicit<ApplicationTag9<Version>>,
88         other_non_optional_integer: u8,
89     }
90 
version_is_default(version: &Implicit<ApplicationTag9<Version>>) -> bool91     fn version_is_default(version: &Implicit<ApplicationTag9<Version>>) -> bool {
92         (version.0).0 == Version::V1
93     }
94 
95     #[test]
optional_version()96     fn optional_version() {
97         let buffer_with_version: [u8; 10] = [0x30, 0x08, 0xA9, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x6E];
98 
99         let non_default = OptionalVersionTestStruct {
100             version: ApplicationTag9(Version::V3).into(),
101             other_non_optional_integer: 0x6E,
102         };
103 
104         check_serde!(non_default: OptionalVersionTestStruct in buffer_with_version);
105 
106         let buffer_without_version: [u8; 5] = [0x30, 0x03, 0x02, 0x01, 0x6E];
107 
108         let default = OptionalVersionTestStruct {
109             version: ApplicationTag9(Version::default()).into(),
110             other_non_optional_integer: 0x6E,
111         };
112 
113         check_serde!(default: OptionalVersionTestStruct in buffer_without_version);
114     }
115 
116     #[test]
unsupported_version()117     fn unsupported_version() {
118         let buffer: [u8; 3] = [0x02, 0x01, 0x0F];
119 
120         let version: picky_asn1_der::Result<Version> = picky_asn1_der::from_bytes(&buffer);
121         match version {
122             Err(Asn1DerError::Message(msg)) => assert_eq!(
123                 msg,
124                 "invalid value: invalid version number, expected a valid integer \
125                  representing a supported version number (0, 1 or 2)"
126             ),
127             Err(err) => panic!("invalid error: {}", err),
128             Ok(_) => panic!("parsing should have failed but did not"),
129         }
130     }
131 }
132