1use std::fmt;
6use std::ops::Deref;
7use std::result;
8
9use reader::RawObject;
10use syntax::Value;
11
12#[derive(Debug, Clone)]
13pub enum Object {
14 Trust(Trust),
15 Certificate(Certificate),
16}
17
18pub type Asn1 = Blob;
20
21#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
23pub struct Blob(Vec<u8>);
24
25impl Deref for Blob {
26 type Target = Vec<u8>;
27 fn deref(&self) -> &Vec<u8> {
28 &self.0
29 }
30}
31
32impl fmt::Debug for Blob {
33 fn fmt(&self, fmt: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
34 write!(fmt, "&{:?}", self.0)
39 }
40}
41
42#[derive(Debug, Clone)]
43pub struct Trust {
44 pub label: String,
46 pub issuer: Asn1,
47 pub serial: Asn1,
48 pub tls_server_trust: TrustLevel,
49 pub email_trust: TrustLevel,
50 pub code_signing_trust: TrustLevel,
51 pub md5: Option<Blob>,
57 pub sha1: Option<Blob>,
58}
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
61pub enum TrustLevel {
62 Distrust,
63 MustVerify,
64 TrustedDelegator,
65}
66
67impl TrustLevel {
68 pub fn from_str(s: &str) -> Option<Self> {
69 match s {
70 "CKT_NSS_NOT_TRUSTED" => Some(TrustLevel::Distrust),
71 "CKT_NSS_MUST_VERIFY_TRUST" => Some(TrustLevel::MustVerify),
72 "CKT_NSS_TRUSTED_DELEGATOR" => Some(TrustLevel::TrustedDelegator),
73 _ => None
74 }
75 }
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79pub enum Usage {
80 TlsServer,
81 Email,
82 CodeSigning,
83}
84
85impl Trust {
86 pub fn trust_level(&self, usage: Usage) -> TrustLevel {
87 match usage {
88 Usage::TlsServer => self.tls_server_trust,
89 Usage::Email => self.email_trust,
90 Usage::CodeSigning => self.code_signing_trust,
91 }
92 }
93}
94
95#[derive(Debug, Clone)]
96pub struct Certificate {
97 pub label: String,
98 pub cert: Asn1,
99 pub issuer: Asn1,
100 pub serial: Asn1,
101 pub subject: Asn1,
102}
103
104#[derive(Debug, Clone, PartialEq, Eq)]
105pub struct TypeError {
107 pub got: String,
108 pub expected: &'static str,
109 pub key: &'static str,
110}
111
112#[derive(Debug, Clone, PartialEq, Eq)]
113pub struct ValueError {
115 pub got: String,
116 pub attr_type: &'static str,
117 pub key: &'static str,
118}
119
120quick_error!{
121 #[derive(Debug, Clone, PartialEq, Eq)]
122 pub enum StructureError {
123 MissingKey(key: &'static str) {
124 description("missing key")
125 from()
126 }
127 TypeError(err: TypeError) {
128 description("unexpected attribute type")
129 from()
130 }
131 ValueError(err: ValueError) {
132 description("unexpected attribute value")
133 from()
134 }
135 }
136}
137use self::StructureError::MissingKey;
138
139pub type Result<T> = result::Result<T, StructureError>;
140
141fn take_bin(obj: &mut RawObject, key: &'static str) -> Result<Blob> {
142 match obj.remove(key) {
143 None => Err(MissingKey(key)),
144 Some(Value::Binary(val)) => Ok(Blob(val)),
145 Some(val) => Err(TypeError {
146 got: val.into_type(),
147 expected: "MULTILINE_OCTAL",
148 key: key
149 }.into()),
150 }
151}
152fn take_str(obj: &mut RawObject, key: &'static str) -> Result<String> {
153 match obj.remove(key) {
154 None => Err(MissingKey(key)),
155 Some(Value::String(val)) => Ok(val),
156 Some(val) => Err(TypeError {
157 got: val.into_type(),
158 expected: "UTF8",
159 key: key
160 }.into()),
161 }
162}
163fn take_tok<R, F>(obj: &mut RawObject, key: &'static str, exp_ty: &'static str, xlate: F)
164 -> Result<R>
165 where F: for<'a> FnOnce(&'a str) -> Option<R>
166{
167 let type_error = |got_ty| Err(TypeError {
168 got: got_ty,
169 expected: exp_ty,
170 key: key,
171 }.into());
172 match obj.remove(key) {
173 None => Err(MissingKey(key)),
174 Some(Value::Token(got_ty, val)) => if got_ty == exp_ty {
175 match xlate(&val) {
176 Some(res) => Ok(res),
177 None => Err(ValueError {
178 got: val,
179 attr_type: exp_ty,
180 key: key
181 }.into())
182 }
183 } else {
184 type_error(got_ty)
185 },
186 Some(val) => type_error(val.into_type()),
187 }
188}
189
190fn optionalize<T>(r: Result<T>) -> Result<Option<T>> {
191 match r {
192 Ok(thing) => Ok(Some(thing)),
193 Err(MissingKey(_)) => Ok(None),
194 Err(err) => Err(err)
195 }
196}
197
198impl Certificate {
199 pub fn from_raw(mut obj: RawObject) -> Result<Certificate> {
200 let obj = &mut obj;
201 try!(take_tok(obj, "CKA_CERTIFICATE_TYPE", "CK_CERTIFICATE_TYPE", |cert_type| {
202 if cert_type == "CKC_X_509" { Some(()) } else { None }
203 }));
204 Ok(Certificate {
205 cert: try!(take_bin(obj, "CKA_VALUE")),
206 label: try!(take_str(obj, "CKA_LABEL")),
207 issuer: try!(take_bin(obj, "CKA_ISSUER")),
208 serial: try!(take_bin(obj, "CKA_SERIAL_NUMBER")),
209 subject: try!(take_bin(obj, "CKA_SUBJECT")),
210 })
211 }
212}
213
214fn take_trust_level(obj: &mut RawObject, key: &'static str) -> Result<TrustLevel> {
215 take_tok(obj, key, "CK_TRUST", TrustLevel::from_str)
216}
217
218impl Trust {
219 pub fn from_raw(mut obj: RawObject) -> Result<Trust> {
220 let obj = &mut obj;
221 Ok(Trust {
222 label: try!(take_str(obj, "CKA_LABEL")),
223 issuer: try!(take_bin(obj, "CKA_ISSUER")),
224 serial: try!(take_bin(obj, "CKA_SERIAL_NUMBER")),
225 tls_server_trust: try!(take_trust_level(obj, "CKA_TRUST_SERVER_AUTH")),
226 email_trust: try!(take_trust_level(obj, "CKA_TRUST_EMAIL_PROTECTION")),
227 code_signing_trust: try!(take_trust_level(obj, "CKA_TRUST_CODE_SIGNING")),
228 md5: try!(optionalize(take_bin(obj, "CKA_CERT_MD5_HASH"))),
229 sha1: try!(optionalize(take_bin(obj, "CKA_CERT_SHA1_HASH"))),
230 })
231 }
232}
233
234enum ObjClass {
235 Certificate,
236 Trust,
237 Other,
238}
239
240fn take_class(obj: &mut RawObject) -> Result<ObjClass> {
241 take_tok(obj, "CKA_CLASS", "CK_OBJECT_CLASS", |cls| Some(match cls {
242 "CKO_CERTIFICATE" => ObjClass::Certificate,
243 "CKO_NSS_TRUST" => ObjClass::Trust,
244 _ => ObjClass::Other,
245 }))
246}
247
248impl Object {
249 pub fn from_raw(mut obj: RawObject) -> Result<Option<Object>> {
250 match try!(take_class(&mut obj)) {
251 ObjClass::Certificate =>
252 Ok(Some(Object::Certificate(try!(Certificate::from_raw(obj))))),
253 ObjClass::Trust =>
254 Ok(Some(Object::Trust(try!(Trust::from_raw(obj))))),
255 _ => Ok(None),
257 }
258 }
259}