1 //! Bindings to winapi's `PCCERT_CONTEXT` APIs.
2 
3 use std::ffi::{CStr, OsString};
4 use std::io;
5 use std::mem;
6 use std::os::windows::prelude::*;
7 use std::ptr;
8 use std::slice;
9 use winapi::shared::minwindef as winapi;
10 use winapi::shared::ntdef;
11 use winapi::shared::winerror;
12 use winapi::um::wincrypt;
13 
14 use crate::Inner;
15 use crate::ncrypt_key::NcryptKey;
16 use crate::crypt_prov::{CryptProv, ProviderType};
17 use crate::cert_store::CertStore;
18 
19 /// A supported hashing algorithm
20 pub struct HashAlgorithm(winapi::DWORD, usize);
21 
22 #[allow(missing_docs)]
23 impl HashAlgorithm {
md5() -> HashAlgorithm24     pub fn md5() -> HashAlgorithm {
25         HashAlgorithm(wincrypt::CALG_MD5, 16)
26     }
27 
sha1() -> HashAlgorithm28     pub fn sha1() -> HashAlgorithm{
29         HashAlgorithm(wincrypt::CALG_SHA1, 20)
30     }
31 
sha256() -> HashAlgorithm32     pub fn sha256() -> HashAlgorithm {
33         HashAlgorithm(wincrypt::CALG_SHA_256, 32)
34     }
35 
sha384() -> HashAlgorithm36     pub fn sha384() -> HashAlgorithm {
37         HashAlgorithm(wincrypt::CALG_SHA_384, 48)
38     }
39 
sha512() -> HashAlgorithm40     pub fn sha512() -> HashAlgorithm {
41         HashAlgorithm(wincrypt::CALG_SHA_512, 64)
42     }
43 }
44 
45 /// Wrapper of a winapi certificate, or a `PCCERT_CONTEXT`.
46 #[derive(Debug)]
47 pub struct CertContext(wincrypt::PCCERT_CONTEXT);
48 
49 unsafe impl Sync for CertContext {}
50 unsafe impl Send for CertContext {}
51 
52 impl Drop for CertContext {
drop(&mut self)53     fn drop(&mut self) {
54         unsafe {
55             wincrypt::CertFreeCertificateContext(self.0);
56         }
57     }
58 }
59 
60 impl Clone for CertContext {
clone(&self) -> CertContext61     fn clone(&self) -> CertContext {
62         unsafe { CertContext(wincrypt::CertDuplicateCertificateContext(self.0)) }
63     }
64 }
65 
66 inner!(CertContext, wincrypt::PCCERT_CONTEXT);
67 
68 impl CertContext {
69     /// Decodes a DER-formatted X509 certificate.
new(data: &[u8]) -> io::Result<CertContext>70     pub fn new(data: &[u8]) -> io::Result<CertContext> {
71         let ret = unsafe {
72             wincrypt::CertCreateCertificateContext(wincrypt::X509_ASN_ENCODING |
73                                                    wincrypt::PKCS_7_ASN_ENCODING,
74                                                    data.as_ptr(),
75                                                    data.len() as winapi::DWORD)
76         };
77         if ret.is_null() {
78             Err(io::Error::last_os_error())
79         } else {
80             Ok(CertContext(ret))
81         }
82     }
83 
84     /// Get certificate in binary DER form
to_der<'a>(&'a self) -> &'a [u8]85     pub fn to_der<'a>(&'a self) -> &'a [u8] {
86         self.get_encoded_bytes()
87     }
88 
89     /// Certificate subject public key info
subject_public_key_info_der(&self) -> io::Result<Vec<u8>>90     pub fn subject_public_key_info_der(&self) -> io::Result<Vec<u8>> {
91         unsafe {
92             let mut len:u32 = 0;
93             let ok = wincrypt::CryptEncodeObjectEx(wincrypt::X509_ASN_ENCODING,
94                                                    wincrypt::CERT_INFO_SUBJECT_PUBLIC_KEY_INFO_FLAG as *const u32 as *const _,
95                                                    &(*(*self.0).pCertInfo).SubjectPublicKeyInfo as *const wincrypt::CERT_PUBLIC_KEY_INFO as _,
96                                                    0,
97                                                    ptr::null_mut(),
98                                                    ptr::null_mut(),
99                                                    &mut len as *mut _);
100             if ok != winapi::TRUE {
101                 return Err(io::Error::last_os_error());
102             }
103             if len > 0 {
104                 let mut buf = vec![0; len as usize];
105                 let ok = wincrypt::CryptEncodeObjectEx(wincrypt::X509_ASN_ENCODING,
106                                                   wincrypt::CERT_INFO_SUBJECT_PUBLIC_KEY_INFO_FLAG as *const u32 as *const _,
107                                                   &(*(*self.0).pCertInfo).SubjectPublicKeyInfo as *const wincrypt::CERT_PUBLIC_KEY_INFO as _,
108                                                   0,
109                                                   ptr::null_mut(),
110                                                   buf.as_mut_ptr() as _,
111                                                   &mut len as *mut _);
112                 if ok != winapi::TRUE {
113                     return Err(io::Error::last_os_error());
114                 }
115                 return Ok(buf);
116             }
117         }
118         Err(io::Error::last_os_error())
119     }
120 
121     /// Decodes a PEM-formatted X509 certificate.
from_pem(pem: &str) -> io::Result<CertContext>122     pub fn from_pem(pem: &str) -> io::Result<CertContext> {
123         unsafe {
124             assert!(pem.len() <= winapi::DWORD::max_value() as usize);
125 
126             let mut len = 0;
127             let ok = wincrypt::CryptStringToBinaryA(pem.as_ptr() as ntdef::LPCSTR,
128                                                     pem.len() as winapi::DWORD,
129                                                     wincrypt::CRYPT_STRING_BASE64HEADER,
130                                                     ptr::null_mut(),
131                                                     &mut len,
132                                                     ptr::null_mut(),
133                                                     ptr::null_mut());
134             if ok != winapi::TRUE {
135                 return Err(io::Error::last_os_error());
136             }
137 
138             let mut buf = vec![0; len as usize];
139             let ok = wincrypt::CryptStringToBinaryA(pem.as_ptr() as ntdef::LPCSTR,
140                                                     pem.len() as winapi::DWORD,
141                                                     wincrypt::CRYPT_STRING_BASE64HEADER,
142                                                     buf.as_mut_ptr(),
143                                                     &mut len,
144                                                     ptr::null_mut(),
145                                                     ptr::null_mut());
146             if ok != winapi::TRUE {
147                 return Err(io::Error::last_os_error());
148             }
149 
150             CertContext::new(&buf)
151         }
152     }
153 
154     /// Get certificate as PEM-formatted X509 certificate.
to_pem(&self) -> io::Result<String>155     pub fn to_pem(&self) -> io::Result<String> {
156         unsafe {
157             let mut len = 0;
158             let ok = wincrypt::CryptBinaryToStringA(
159                 (*self.0).pbCertEncoded,
160                 (*self.0).cbCertEncoded,
161                 wincrypt::CRYPT_STRING_BASE64HEADER,
162                 ptr::null_mut(),
163                 &mut len,
164             );
165             if ok != winapi::TRUE {
166                 return Err(io::Error::last_os_error());
167             }
168 
169             let mut buf = vec![0; len as usize];
170             let ok = wincrypt::CryptBinaryToStringA(
171                 (*self.0).pbCertEncoded,
172                 (*self.0).cbCertEncoded,
173                 wincrypt::CRYPT_STRING_BASE64HEADER,
174                 buf.as_mut_ptr(),
175                 &mut len,
176             );
177             if ok != winapi::TRUE {
178                 return Err(io::Error::last_os_error());
179             }
180 
181             Ok(CStr::from_ptr(buf.as_ptr()).to_string_lossy().into_owned())
182         }
183     }
184 
185     /// Returns a hash of this certificate
fingerprint(&self, alg: HashAlgorithm) -> io::Result<Vec<u8>>186     pub fn fingerprint(&self, alg: HashAlgorithm) -> io::Result<Vec<u8>> {
187         unsafe {
188             let mut buf = vec![0u8; alg.1];
189             let mut len = buf.len() as winapi::DWORD;
190 
191             let ret = wincrypt::CryptHashCertificate(0,
192                                                      alg.0,
193                                                      0,
194                                                      (*self.0).pbCertEncoded,
195                                                      (*self.0).cbCertEncoded,
196                                                      buf.as_mut_ptr(),
197                                                      &mut len);
198 
199             if ret != winapi::TRUE {
200                 return Err(io::Error::last_os_error());
201             }
202             Ok(buf)
203         }
204     }
205 
206     /// Returns the sha1 hash of this certificate
207     ///
208     /// The sha1 is returned as a 20-byte array representing the bits of the
209     /// sha1 hash.
210     #[deprecated(note = "please use fingerprint instead")]
sha1(&self) -> io::Result<[u8; 20]>211     pub fn sha1(&self) -> io::Result<[u8; 20]> {
212         let mut out = [0u8; 20];
213         out.copy_from_slice(&self.fingerprint(HashAlgorithm::sha1())?);
214         Ok(out)
215     }
216 
217     /// Returns the `<SIGNATURE>/<HASH>` string representing the certificate
218     /// signature.
219     ///
220     /// The `<SIGNATURE>` value identifies the CNG public key
221     /// algorithm. The `<HASH>` value identifies the CNG hash algorithm.
222     ///
223     /// Common examples are:
224     ///
225     /// * `RSA/SHA1`
226     /// * `RSA/SHA256`
227     /// * `ECDSA/SHA256`
sign_hash_algorithms(&self) -> io::Result<String>228     pub fn sign_hash_algorithms(&self) -> io::Result<String> {
229         self.get_string(wincrypt::CERT_SIGN_HASH_CNG_ALG_PROP_ID)
230     }
231 
232     /// Returns the signature hash.
signature_hash(&self) -> io::Result<Vec<u8>>233     pub fn signature_hash(&self) -> io::Result<Vec<u8>> {
234         self.get_bytes(wincrypt::CERT_SIGNATURE_HASH_PROP_ID)
235     }
236 
237     /// Returns the property displayed by the certificate UI. This property
238     /// allows the user to describe the certificate's use.
description(&self) -> io::Result<Vec<u8>>239     pub fn description(&self) -> io::Result<Vec<u8>> {
240         self.get_bytes(wincrypt::CERT_DESCRIPTION_PROP_ID)
241     }
242 
243     /// Returns a string that contains the display name for the certificate.
friendly_name(&self) -> io::Result<String>244     pub fn friendly_name(&self) -> io::Result<String> {
245         self.get_string(wincrypt::CERT_FRIENDLY_NAME_PROP_ID)
246     }
247 
248     /// Configures the string that contains the display name for this
249     /// certificate.
set_friendly_name(&self, name: &str) -> io::Result<()>250     pub fn set_friendly_name(&self, name: &str) -> io::Result<()> {
251         self.set_string(wincrypt::CERT_FRIENDLY_NAME_PROP_ID, name)
252     }
253 
254     /// Verifies the time validity of this certificate relative to the system's
255     /// current time.
is_time_valid(&self) -> io::Result<bool>256     pub fn is_time_valid(&self) -> io::Result<bool> {
257         let ret = unsafe { wincrypt::CertVerifyTimeValidity(ptr::null_mut(), (*self.0).pCertInfo) };
258         Ok(ret == 0)
259     }
260 
261     /// Returns a builder used to acquire the private key corresponding to this certificate.
private_key<'a>(&'a self) -> AcquirePrivateKeyOptions<'a>262     pub fn private_key<'a>(&'a self) -> AcquirePrivateKeyOptions<'a> {
263         AcquirePrivateKeyOptions {
264             cert: self,
265             flags: 0,
266         }
267     }
268 
269     /// Deletes this certificate from its certificate store.
delete(self) -> io::Result<()>270     pub fn delete(self) -> io::Result<()> {
271         unsafe {
272             let ret = wincrypt::CertDeleteCertificateFromStore(self.0);
273             mem::forget(self);
274             if ret == winapi::TRUE {
275                 Ok(())
276             } else {
277                 Err(io::Error::last_os_error())
278             }
279         }
280     }
281 
282     /// Returns a builder used to set the private key associated with this certificate.
set_key_prov_info<'a>(&'a self) -> SetKeyProvInfo<'a>283     pub fn set_key_prov_info<'a>(&'a self) -> SetKeyProvInfo<'a> {
284         SetKeyProvInfo {
285             cert: self,
286             container: None,
287             provider: None,
288             type_: 0,
289             flags: 0,
290             key_spec: 0,
291         }
292     }
293 
294     /// Returns the valid uses for this certificate
valid_uses(&self) -> io::Result<ValidUses>295     pub fn valid_uses(&self) -> io::Result<ValidUses> {
296         unsafe {
297             let mut buf_len = 0;
298             let ok = wincrypt::CertGetEnhancedKeyUsage(self.0, 0, ptr::null_mut(), &mut buf_len);
299 
300             if ok != winapi::TRUE {
301                 return Err(io::Error::last_os_error());
302             }
303 
304             let mut buf = vec![0u8; buf_len as usize];
305             let cert_enhkey_usage = buf.as_mut_ptr() as *mut wincrypt::CERT_ENHKEY_USAGE;
306 
307             let ok = wincrypt::CertGetEnhancedKeyUsage(self.0, 0, cert_enhkey_usage, &mut buf_len);
308             if ok != winapi::TRUE {
309                 return Err(io::Error::last_os_error());
310             }
311 
312             let use_cnt = (*cert_enhkey_usage).cUsageIdentifier;
313             if use_cnt == 0 {
314                 let last_error = io::Error::last_os_error();
315                 match last_error.raw_os_error() {
316                     Some(winerror::CRYPT_E_NOT_FOUND) => return Ok(ValidUses::All),
317                     Some(0) => (),
318                     _ => return Err(last_error),
319                 };
320             }
321 
322             let mut oids: Vec<String> = Vec::with_capacity(use_cnt as usize);
323             for i in 0..use_cnt {
324                 let oid_ptr = (*cert_enhkey_usage).rgpszUsageIdentifier;
325                 oids.push(
326                     CStr::from_ptr(*(oid_ptr.offset(i as isize)))
327                         .to_string_lossy()
328                         .into_owned(),
329                 );
330             }
331             Ok(ValidUses::Oids(oids))
332         }
333     }
334 
335     /// For a remote certificate, returns a certificate store containing any intermediate
336     /// certificates provided by the remote sender.
cert_store(&self) -> Option<CertStore>337     pub fn cert_store(&self) -> Option<CertStore> {
338         unsafe {
339             let chain = (*self.0).hCertStore;
340             if chain.is_null() {
341                 None
342             } else {
343                 Some(CertStore::from_inner(wincrypt::CertDuplicateStore(chain)))
344             }
345         }
346     }
347 
get_encoded_bytes<'a>(&'a self) -> &'a [u8]348     fn get_encoded_bytes<'a>(&'a self) -> &'a [u8] {
349         unsafe {
350             let cert_ctx = *self.0;
351             slice::from_raw_parts(cert_ctx.pbCertEncoded, cert_ctx.cbCertEncoded as usize)
352         }
353     }
354 
get_bytes(&self, prop: winapi::DWORD) -> io::Result<Vec<u8>>355     fn get_bytes(&self, prop: winapi::DWORD) -> io::Result<Vec<u8>> {
356         unsafe {
357             let mut len = 0;
358             let ret =
359                 wincrypt::CertGetCertificateContextProperty(self.0, prop, ptr::null_mut(), &mut len);
360             if ret != winapi::TRUE {
361                 return Err(io::Error::last_os_error());
362             }
363 
364             let mut buf = vec![0u8; len as usize];
365             let ret = wincrypt::CertGetCertificateContextProperty(self.0,
366                                                                   prop,
367                                                                   buf.as_mut_ptr() as winapi::LPVOID,
368                                                                   &mut len);
369             if ret != winapi::TRUE {
370                 return Err(io::Error::last_os_error());
371             }
372             Ok(buf)
373         }
374     }
375 
get_string(&self, prop: winapi::DWORD) -> io::Result<String>376     fn get_string(&self, prop: winapi::DWORD) -> io::Result<String> {
377         unsafe {
378             let mut len = 0;
379             let ret =
380                 wincrypt::CertGetCertificateContextProperty(self.0, prop, ptr::null_mut(), &mut len);
381             if ret != winapi::TRUE {
382                 return Err(io::Error::last_os_error());
383             }
384 
385             // Divide by 2 b/c `len` is the byte length, but we're allocating
386             // u16 pairs which are 2 bytes each.
387             let amt = (len / 2) as usize;
388             let mut buf = vec![0u16; amt];
389             let ret = wincrypt::CertGetCertificateContextProperty(self.0,
390                                                                   prop,
391                                                                   buf.as_mut_ptr() as winapi::LPVOID,
392                                                                   &mut len);
393             if ret != winapi::TRUE {
394                 return Err(io::Error::last_os_error());
395             }
396 
397             // Chop off the trailing nul byte
398             Ok(OsString::from_wide(&buf[..amt - 1]).into_string().unwrap())
399         }
400     }
401 
set_string(&self, prop: winapi::DWORD, s: &str) -> io::Result<()>402     fn set_string(&self, prop: winapi::DWORD, s: &str) -> io::Result<()> {
403         unsafe {
404             let data = s.encode_utf16().chain(Some(0)).collect::<Vec<_>>();
405             let data = wincrypt::CRYPT_DATA_BLOB {
406                 cbData: (data.len() * 2) as winapi::DWORD,
407                 pbData: data.as_ptr() as *mut _,
408             };
409             let ret = wincrypt::CertSetCertificateContextProperty(self.0,
410                                                                   prop,
411                                                                   0,
412                                                                   &data as *const _ as *const _);
413             if ret != winapi::TRUE {
414                 Err(io::Error::last_os_error())
415             } else {
416                 Ok(())
417             }
418         }
419     }
420 }
421 
422 impl PartialEq for CertContext {
eq(&self, other: &CertContext) -> bool423     fn eq(&self, other: &CertContext) -> bool {
424         self.get_encoded_bytes() == other.get_encoded_bytes()
425     }
426 }
427 
428 /// A builder type for certificate private key lookup.
429 pub struct AcquirePrivateKeyOptions<'a> {
430     cert: &'a CertContext,
431     flags: winapi::DWORD,
432 }
433 
434 impl<'a> AcquirePrivateKeyOptions<'a> {
435     /// If set, the certificate's public key will be compared with the private key to ensure a
436     /// match.
compare_key(&mut self, compare_key: bool) -> &mut AcquirePrivateKeyOptions<'a>437     pub fn compare_key(&mut self, compare_key: bool) -> &mut AcquirePrivateKeyOptions<'a> {
438         self.flag(wincrypt::CRYPT_ACQUIRE_COMPARE_KEY_FLAG, compare_key)
439     }
440 
441     /// If set, the lookup will not display any user interface, even if that causes the lookup to
442     /// fail.
silent(&mut self, silent: bool) -> &mut AcquirePrivateKeyOptions<'a>443     pub fn silent(&mut self, silent: bool) -> &mut AcquirePrivateKeyOptions<'a> {
444         self.flag(wincrypt::CRYPT_ACQUIRE_SILENT_FLAG, silent)
445     }
446 
flag(&mut self, flag: winapi::DWORD, set: bool) -> &mut AcquirePrivateKeyOptions<'a>447     fn flag(&mut self, flag: winapi::DWORD, set: bool) -> &mut AcquirePrivateKeyOptions<'a> {
448         if set {
449             self.flags |= flag;
450         } else {
451             self.flags &= !flag;
452         }
453         self
454     }
455 
456     /// Acquires the private key handle.
acquire(&self) -> io::Result<PrivateKey>457     pub fn acquire(&self) -> io::Result<PrivateKey> {
458         unsafe {
459             let flags = self.flags | wincrypt::CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG;
460             let mut handle = 0;
461             let mut spec = 0;
462             let mut free = winapi::FALSE;
463             let res = wincrypt::CryptAcquireCertificatePrivateKey(self.cert.0,
464                                                                   flags,
465                                                                   ptr::null_mut(),
466                                                                   &mut handle,
467                                                                   &mut spec,
468                                                                   &mut free);
469             if res != winapi::TRUE {
470                 return Err(io::Error::last_os_error());
471             }
472             assert!(free == winapi::TRUE);
473             if spec & wincrypt::CERT_NCRYPT_KEY_SPEC != 0 {
474                 Ok(PrivateKey::NcryptKey(NcryptKey::from_inner(handle)))
475             } else {
476                 Ok(PrivateKey::CryptProv(CryptProv::from_inner(handle)))
477             }
478         }
479     }
480 }
481 
482 /// The private key associated with a certificate context.
483 pub enum PrivateKey {
484     /// A CryptoAPI provider.
485     CryptProv(CryptProv),
486     /// A CNG provider.
487     NcryptKey(NcryptKey),
488 }
489 
490 /// A builder used to set the private key associated with a certificate.
491 pub struct SetKeyProvInfo<'a> {
492     cert: &'a CertContext,
493     container: Option<Vec<u16>>,
494     provider: Option<Vec<u16>>,
495     type_: winapi::DWORD,
496     flags: winapi::DWORD,
497     key_spec: winapi::DWORD,
498 }
499 
500 impl<'a> SetKeyProvInfo<'a> {
501     /// The name of the key container.
502     ///
503     /// If `type_` is not provided, this specifies the name of the key withing
504     /// the CNG key storage provider.
container(&mut self, container: &str) -> &mut SetKeyProvInfo<'a>505     pub fn container(&mut self, container: &str) -> &mut SetKeyProvInfo<'a> {
506         self.container = Some(container.encode_utf16().chain(Some(0)).collect());
507         self
508     }
509 
510     /// The name of the CSP.
511     ///
512     /// If `type_` is not provided, this contains the name of the CNG key
513     /// storage provider.
provider(&mut self, provider: &str) -> &mut SetKeyProvInfo<'a>514     pub fn provider(&mut self, provider: &str) -> &mut SetKeyProvInfo<'a> {
515         self.provider = Some(provider.encode_utf16().chain(Some(0)).collect());
516         self
517     }
518 
519     /// Sets the CSP type.
520     ///
521     /// If not provided, the key container is one of the CNG key storage
522     /// providers.
type_(&mut self, type_: ProviderType) -> &mut SetKeyProvInfo<'a>523     pub fn type_(&mut self, type_: ProviderType) -> &mut SetKeyProvInfo<'a> {
524         self.type_ = type_.as_raw();
525         self
526     }
527 
528     /// If set, the handle to the key provider can be kept open for subsequent
529     /// calls to cryptographic functions.
keep_open(&mut self, keep_open: bool) -> &mut SetKeyProvInfo<'a>530     pub fn keep_open(&mut self, keep_open: bool) -> &mut SetKeyProvInfo<'a> {
531         self.flag(wincrypt::CERT_SET_KEY_PROV_HANDLE_PROP_ID, keep_open)
532     }
533 
534     /// If set, the key container contains machine keys.
machine_keyset(&mut self, machine_keyset: bool) -> &mut SetKeyProvInfo<'a>535     pub fn machine_keyset(&mut self, machine_keyset: bool) -> &mut SetKeyProvInfo<'a> {
536         self.flag(wincrypt::CRYPT_MACHINE_KEYSET, machine_keyset)
537     }
538 
539     /// If set, the key container will attempt to open keys without any user
540     /// interface prompts.
silent(&mut self, silent: bool) -> &mut SetKeyProvInfo<'a>541     pub fn silent(&mut self, silent: bool) -> &mut SetKeyProvInfo<'a> {
542         self.flag(wincrypt::CRYPT_SILENT, silent)
543     }
544 
flag(&mut self, flag: winapi::DWORD, on: bool) -> &mut SetKeyProvInfo<'a>545     fn flag(&mut self, flag: winapi::DWORD, on: bool) -> &mut SetKeyProvInfo<'a> {
546         if on {
547             self.flags |= flag;
548         } else {
549             self.flags &= !flag;
550         }
551         self
552     }
553 
554     /// The specification of the private key to retrieve.
key_spec(&mut self, key_spec: KeySpec) -> &mut SetKeyProvInfo<'a>555     pub fn key_spec(&mut self, key_spec: KeySpec) -> &mut SetKeyProvInfo<'a> {
556         self.key_spec = key_spec.0;
557         self
558     }
559 
560     /// Sets the private key for this certificate.
set(&mut self) -> io::Result<()>561     pub fn set(&mut self) -> io::Result<()> {
562         unsafe {
563             let container = self.container.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null());
564             let provider = self.provider.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null());
565 
566             let info = wincrypt::CRYPT_KEY_PROV_INFO {
567                 pwszContainerName: container as *mut _,
568                 pwszProvName: provider as *mut _,
569                 dwProvType: self.type_,
570                 dwFlags: self.flags,
571                 cProvParam: 0,
572                 rgProvParam: ptr::null_mut(),
573                 dwKeySpec: self.key_spec,
574             };
575 
576             let res =
577                 wincrypt::CertSetCertificateContextProperty(self.cert.0,
578                                                             wincrypt::CERT_KEY_PROV_INFO_PROP_ID,
579                                                             0,
580                                                             &info as *const _ as *const _);
581             if res == winapi::TRUE {
582                 Ok(())
583             } else {
584                 Err(io::Error::last_os_error())
585             }
586         }
587     }
588 }
589 
590 /// The specification of a private key.
591 #[derive(Copy, Clone)]
592 pub struct KeySpec(winapi::DWORD);
593 
594 impl KeySpec {
595     /// A key used to encrypt/decrypt session keys.
key_exchange() -> KeySpec596     pub fn key_exchange() -> KeySpec {
597         KeySpec(wincrypt::AT_KEYEXCHANGE)
598     }
599 
600     /// A key used to create and verify digital signatures.
signature() -> KeySpec601     pub fn signature() -> KeySpec {
602         KeySpec(wincrypt::AT_SIGNATURE)
603     }
604 }
605 
606 /// Valid uses of a Certificate - All, or specific OIDs
607 pub enum ValidUses {
608     /// Certificate is valid for all uses
609     All,
610 
611     /// Certificate is valid for uses specified. No entries means that the certificate
612     /// has no valid uses.
613     Oids(Vec<String>),
614 }
615 
616 #[cfg(test)]
617 mod test {
618     use super::*;
619 
620     #[test]
decode()621     fn decode() {
622         let der = include_bytes!("../test/cert.der");
623         let pem = include_str!("../test/cert.pem");
624 
625         let der = CertContext::new(der).unwrap();
626         let pem = CertContext::from_pem(pem).unwrap();
627         assert_eq!(der, pem);
628     }
629 
630     #[test]
certcontext_to_der()631     fn certcontext_to_der() {
632         let der = include_bytes!("../test/cert.der");
633         let cert = CertContext::new(der).unwrap();
634         let der2 = CertContext::to_der(&cert);
635         assert_eq!(der as &[u8], der2);
636     }
637 
638     #[test]
certcontext_to_pem()639     fn certcontext_to_pem() {
640         let der = include_bytes!("../test/cert.der");
641         let pem1 = include_str!("../test/cert.pem").replace("\r", "");
642 
643         let der = CertContext::new(der).unwrap();
644         let pem2 = CertContext::to_pem(&der).unwrap().replace("\r", "");
645         assert_eq!(pem1, pem2);
646     }
647 
648     #[test]
fingerprint()649     fn fingerprint() {
650         let der = include_bytes!("../test/cert.der");
651         let pem = include_str!("../test/cert.pem");
652 
653         let der = CertContext::new(der).unwrap();
654         let pem = CertContext::from_pem(pem).unwrap();
655 
656         let hash = der.fingerprint(HashAlgorithm::sha1()).unwrap();
657         assert_eq!(hash, vec![‎
658             0x59, 0x17, 0x2D, 0x93, 0x13, 0xE8, 0x44, 0x59, 0xBC, 0xFF,
659             0x27, 0xF9, 0x67, 0xE7, 0x9E, 0x6E, 0x92, 0x17, 0xE5, 0x84
660         ]);
661         assert_eq!(hash, pem.fingerprint(HashAlgorithm::sha1()).unwrap());
662 
663         let hash = der.fingerprint(HashAlgorithm::sha256()).unwrap();
664         assert_eq!(hash, vec![
665             0x47, 0x12, 0xB9, 0x39, 0xFB, 0xCB, 0x42, 0xA6, 0xB5, 0x10,
666             0x1B, 0x42, 0x13, 0x9A, 0x25, 0xB1, 0x4F, 0x81, 0xB4, 0x18,
667             0xFA, 0xCA, 0xBD, 0x37, 0x87, 0x46, 0xF1, 0x2F, 0x85, 0xCC,
668             0x65, 0x44
669         ]);
670         assert_eq!(hash, pem.fingerprint(HashAlgorithm::sha256()).unwrap());
671     }
672 }
673