1//! The standard defining the format of public key certificates.
2//!
3//! An `X509` certificate binds an identity to a public key, and is either
4//! signed by a certificate authority (CA) or self-signed. An entity that gets
5//! a hold of a certificate can both verify your identity (via a CA) and encrypt
6//! data with the included public key. `X509` certificates are used in many
7//! Internet protocols, including SSL/TLS, which is the basis for HTTPS,
8//! the secure protocol for browsing the web.
9
10use cfg_if::cfg_if;
11use foreign_types::{ForeignType, ForeignTypeRef, Opaque};
12use libc::{c_int, c_long, c_uint, c_void};
13use std::cmp::{self, Ordering};
14use std::convert::{TryFrom, TryInto};
15use std::error::Error;
16use std::ffi::{CStr, CString};
17use std::fmt;
18use std::marker::PhantomData;
19use std::mem;
20use std::net::IpAddr;
21use std::path::Path;
22use std::ptr;
23use std::slice;
24use std::str;
25
26use crate::asn1::{
27 Asn1BitStringRef, Asn1Enumerated, Asn1IntegerRef, Asn1Object, Asn1ObjectRef,
28 Asn1OctetStringRef, Asn1StringRef, Asn1TimeRef, Asn1Type,
29};
30use crate::bio::MemBioSlice;
31use crate::conf::ConfRef;
32use crate::error::ErrorStack;
33use crate::ex_data::Index;
34use crate::hash::{DigestBytes, MessageDigest};
35use crate::nid::Nid;
36use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public};
37use crate::ssl::SslRef;
38use crate::stack::{Stack, StackRef, Stackable};
39use crate::string::OpensslString;
40use crate::util::{ForeignTypeExt, ForeignTypeRefExt};
41use crate::{cvt, cvt_n, cvt_p, cvt_p_const};
42use openssl_macros::corresponds;
43
44#[cfg(any(ossl102, boringssl, libressl261))]
45pub mod verify;
46
47pub mod extension;
48pub mod store;
49
50#[cfg(test)]
51mod tests;
52
53/// A type of X509 extension.
54///
55/// # Safety
56/// The value of NID and Output must match those in OpenSSL so that
57/// `Output::from_ptr_opt(*_get_ext_d2i(*, NID, ...))` is valid.
58pub unsafe trait ExtensionType {
59 const NID: Nid;
60 type Output: ForeignType;
61}
62
63foreign_type_and_impl_send_sync! {
64 type CType = ffi::X509_STORE_CTX;
65 fn drop = ffi::X509_STORE_CTX_free;
66
67 /// An `X509` certificate store context.
68 pub struct X509StoreContext;
69
70 /// A reference to an [`X509StoreContext`].
71 pub struct X509StoreContextRef;
72}
73
74impl X509StoreContext {
75 /// Returns the index which can be used to obtain a reference to the `Ssl` associated with a
76 /// context.
77 #[corresponds(SSL_get_ex_data_X509_STORE_CTX_idx)]
78 pub fn ssl_idx() -> Result<Index<X509StoreContext, SslRef>, ErrorStack> {
79 unsafe { cvt_n(ffi::SSL_get_ex_data_X509_STORE_CTX_idx()).map(|idx: i32| Index::from_raw(idx)) }
80 }
81
82 /// Creates a new `X509StoreContext` instance.
83 #[corresponds(X509_STORE_CTX_new)]
84 pub fn new() -> Result<X509StoreContext, ErrorStack> {
85 unsafe {
86 ffi::init();
87 cvt_p(ffi::X509_STORE_CTX_new()).map(op:X509StoreContext)
88 }
89 }
90}
91
92impl X509StoreContextRef {
93 /// Returns application data pertaining to an `X509` store context.
94 #[corresponds(X509_STORE_CTX_get_ex_data)]
95 pub fn ex_data<T>(&self, index: Index<X509StoreContext, T>) -> Option<&T> {
96 unsafe {
97 let data = ffi::X509_STORE_CTX_get_ex_data(self.as_ptr(), index.as_raw());
98 if data.is_null() {
99 None
100 } else {
101 Some(&*(data as *const T))
102 }
103 }
104 }
105
106 /// Returns the error code of the context.
107 #[corresponds(X509_STORE_CTX_get_error)]
108 pub fn error(&self) -> X509VerifyResult {
109 unsafe { X509VerifyResult::from_raw(ffi::X509_STORE_CTX_get_error(self.as_ptr())) }
110 }
111
112 /// Initializes this context with the given certificate, certificates chain and certificate
113 /// store. After initializing the context, the `with_context` closure is called with the prepared
114 /// context. As long as the closure is running, the context stays initialized and can be used
115 /// to e.g. verify a certificate. The context will be cleaned up, after the closure finished.
116 ///
117 /// * `trust` - The certificate store with the trusted certificates.
118 /// * `cert` - The certificate that should be verified.
119 /// * `cert_chain` - The certificates chain.
120 /// * `with_context` - The closure that is called with the initialized context.
121 ///
122 /// This corresponds to [`X509_STORE_CTX_init`] before calling `with_context` and to
123 /// [`X509_STORE_CTX_cleanup`] after calling `with_context`.
124 ///
125 /// [`X509_STORE_CTX_init`]: https://www.openssl.org/docs/manmaster/crypto/X509_STORE_CTX_init.html
126 /// [`X509_STORE_CTX_cleanup`]: https://www.openssl.org/docs/manmaster/crypto/X509_STORE_CTX_cleanup.html
127 pub fn init<F, T>(
128 &mut self,
129 trust: &store::X509StoreRef,
130 cert: &X509Ref,
131 cert_chain: &StackRef<X509>,
132 with_context: F,
133 ) -> Result<T, ErrorStack>
134 where
135 F: FnOnce(&mut X509StoreContextRef) -> Result<T, ErrorStack>,
136 {
137 struct Cleanup<'a>(&'a mut X509StoreContextRef);
138
139 impl<'a> Drop for Cleanup<'a> {
140 fn drop(&mut self) {
141 unsafe {
142 ffi::X509_STORE_CTX_cleanup(self.0.as_ptr());
143 }
144 }
145 }
146
147 unsafe {
148 cvt(ffi::X509_STORE_CTX_init(
149 self.as_ptr(),
150 trust.as_ptr(),
151 cert.as_ptr(),
152 cert_chain.as_ptr(),
153 ))?;
154
155 let cleanup = Cleanup(self);
156 with_context(cleanup.0)
157 }
158 }
159
160 /// Verifies the stored certificate.
161 ///
162 /// Returns `true` if verification succeeds. The `error` method will return the specific
163 /// validation error if the certificate was not valid.
164 ///
165 /// This will only work inside of a call to `init`.
166 #[corresponds(X509_verify_cert)]
167 pub fn verify_cert(&mut self) -> Result<bool, ErrorStack> {
168 unsafe { cvt_n(ffi::X509_verify_cert(self.as_ptr())).map(|n| n != 0) }
169 }
170
171 /// Set the error code of the context.
172 #[corresponds(X509_STORE_CTX_set_error)]
173 pub fn set_error(&mut self, result: X509VerifyResult) {
174 unsafe {
175 ffi::X509_STORE_CTX_set_error(self.as_ptr(), result.as_raw());
176 }
177 }
178
179 /// Returns a reference to the certificate which caused the error or None if
180 /// no certificate is relevant to the error.
181 #[corresponds(X509_STORE_CTX_get_current_cert)]
182 pub fn current_cert(&self) -> Option<&X509Ref> {
183 unsafe {
184 let ptr = ffi::X509_STORE_CTX_get_current_cert(self.as_ptr());
185 X509Ref::from_const_ptr_opt(ptr)
186 }
187 }
188
189 /// Returns a non-negative integer representing the depth in the certificate
190 /// chain where the error occurred. If it is zero it occurred in the end
191 /// entity certificate, one if it is the certificate which signed the end
192 /// entity certificate and so on.
193 #[corresponds(X509_STORE_CTX_get_error_depth)]
194 pub fn error_depth(&self) -> u32 {
195 unsafe { ffi::X509_STORE_CTX_get_error_depth(self.as_ptr()) as u32 }
196 }
197
198 /// Returns a reference to a complete valid `X509` certificate chain.
199 #[corresponds(X509_STORE_CTX_get0_chain)]
200 pub fn chain(&self) -> Option<&StackRef<X509>> {
201 unsafe {
202 let chain = X509_STORE_CTX_get0_chain(self.as_ptr());
203
204 if chain.is_null() {
205 None
206 } else {
207 Some(StackRef::from_ptr(chain))
208 }
209 }
210 }
211}
212
213/// A builder used to construct an `X509`.
214pub struct X509Builder(X509);
215
216impl X509Builder {
217 /// Creates a new builder.
218 #[corresponds(X509_new)]
219 pub fn new() -> Result<X509Builder, ErrorStack> {
220 unsafe {
221 ffi::init();
222 cvt_p(ffi::X509_new()).map(|p| X509Builder(X509(p)))
223 }
224 }
225
226 /// Sets the notAfter constraint on the certificate.
227 #[corresponds(X509_set1_notAfter)]
228 pub fn set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack> {
229 unsafe { cvt(X509_set1_notAfter(self.0.as_ptr(), not_after.as_ptr())).map(|_| ()) }
230 }
231
232 /// Sets the notBefore constraint on the certificate.
233 #[corresponds(X509_set1_notBefore)]
234 pub fn set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack> {
235 unsafe { cvt(X509_set1_notBefore(self.0.as_ptr(), not_before.as_ptr())).map(|_| ()) }
236 }
237
238 /// Sets the version of the certificate.
239 ///
240 /// Note that the version is zero-indexed; that is, a certificate corresponding to version 3 of
241 /// the X.509 standard should pass `2` to this method.
242 #[corresponds(X509_set_version)]
243 #[allow(clippy::useless_conversion)]
244 pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
245 unsafe { cvt(ffi::X509_set_version(self.0.as_ptr(), version as c_long)).map(|_| ()) }
246 }
247
248 /// Sets the serial number of the certificate.
249 #[corresponds(X509_set_serialNumber)]
250 pub fn set_serial_number(&mut self, serial_number: &Asn1IntegerRef) -> Result<(), ErrorStack> {
251 unsafe {
252 cvt(ffi::X509_set_serialNumber(
253 self.0.as_ptr(),
254 serial_number.as_ptr(),
255 ))
256 .map(|_| ())
257 }
258 }
259
260 /// Sets the issuer name of the certificate.
261 #[corresponds(X509_set_issuer_name)]
262 pub fn set_issuer_name(&mut self, issuer_name: &X509NameRef) -> Result<(), ErrorStack> {
263 unsafe {
264 cvt(ffi::X509_set_issuer_name(
265 self.0.as_ptr(),
266 issuer_name.as_ptr(),
267 ))
268 .map(|_| ())
269 }
270 }
271
272 /// Sets the subject name of the certificate.
273 ///
274 /// When building certificates, the `C`, `ST`, and `O` options are common when using the openssl command line tools.
275 /// The `CN` field is used for the common name, such as a DNS name.
276 ///
277 /// ```
278 /// use openssl::x509::{X509, X509NameBuilder};
279 ///
280 /// let mut x509_name = openssl::x509::X509NameBuilder::new().unwrap();
281 /// x509_name.append_entry_by_text("C", "US").unwrap();
282 /// x509_name.append_entry_by_text("ST", "CA").unwrap();
283 /// x509_name.append_entry_by_text("O", "Some organization").unwrap();
284 /// x509_name.append_entry_by_text("CN", "www.example.com").unwrap();
285 /// let x509_name = x509_name.build();
286 ///
287 /// let mut x509 = openssl::x509::X509::builder().unwrap();
288 /// x509.set_subject_name(&x509_name).unwrap();
289 /// ```
290 #[corresponds(X509_set_subject_name)]
291 pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
292 unsafe {
293 cvt(ffi::X509_set_subject_name(
294 self.0.as_ptr(),
295 subject_name.as_ptr(),
296 ))
297 .map(|_| ())
298 }
299 }
300
301 /// Sets the public key associated with the certificate.
302 #[corresponds(X509_set_pubkey)]
303 pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
304 where
305 T: HasPublic,
306 {
307 unsafe { cvt(ffi::X509_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
308 }
309
310 /// Returns a context object which is needed to create certain X509 extension values.
311 ///
312 /// Set `issuer` to `None` if the certificate will be self-signed.
313 #[corresponds(X509V3_set_ctx)]
314 pub fn x509v3_context<'a>(
315 &'a self,
316 issuer: Option<&'a X509Ref>,
317 conf: Option<&'a ConfRef>,
318 ) -> X509v3Context<'a> {
319 unsafe {
320 let mut ctx = mem::zeroed();
321
322 let issuer = match issuer {
323 Some(issuer) => issuer.as_ptr(),
324 None => self.0.as_ptr(),
325 };
326 let subject = self.0.as_ptr();
327 ffi::X509V3_set_ctx(
328 &mut ctx,
329 issuer,
330 subject,
331 ptr::null_mut(),
332 ptr::null_mut(),
333 0,
334 );
335
336 // nodb case taken care of since we zeroed ctx above
337 if let Some(conf) = conf {
338 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
339 }
340
341 X509v3Context(ctx, PhantomData)
342 }
343 }
344
345 /// Adds an X509 extension value to the certificate.
346 ///
347 /// This works just as `append_extension` except it takes ownership of the `X509Extension`.
348 pub fn append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack> {
349 self.append_extension2(&extension)
350 }
351
352 /// Adds an X509 extension value to the certificate.
353 #[corresponds(X509_add_ext)]
354 pub fn append_extension2(&mut self, extension: &X509ExtensionRef) -> Result<(), ErrorStack> {
355 unsafe {
356 cvt(ffi::X509_add_ext(self.0.as_ptr(), extension.as_ptr(), -1))?;
357 Ok(())
358 }
359 }
360
361 /// Signs the certificate with a private key.
362 #[corresponds(X509_sign)]
363 pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
364 where
365 T: HasPrivate,
366 {
367 unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), hash.as_ptr())).map(|_| ()) }
368 }
369
370 /// Consumes the builder, returning the certificate.
371 pub fn build(self) -> X509 {
372 self.0
373 }
374}
375
376foreign_type_and_impl_send_sync! {
377 type CType = ffi::X509;
378 fn drop = ffi::X509_free;
379
380 /// An `X509` public key certificate.
381 pub struct X509;
382 /// Reference to `X509`.
383 pub struct X509Ref;
384}
385
386impl X509Ref {
387 /// Returns this certificate's subject name.
388 #[corresponds(X509_get_subject_name)]
389 pub fn subject_name(&self) -> &X509NameRef {
390 unsafe {
391 let name = ffi::X509_get_subject_name(self.as_ptr());
392 X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null")
393 }
394 }
395
396 /// Returns the hash of the certificates subject
397 #[corresponds(X509_subject_name_hash)]
398 pub fn subject_name_hash(&self) -> u32 {
399 #[allow(clippy::unnecessary_cast)]
400 unsafe {
401 ffi::X509_subject_name_hash(self.as_ptr()) as u32
402 }
403 }
404
405 /// Returns this certificate's issuer name.
406 #[corresponds(X509_get_issuer_name)]
407 pub fn issuer_name(&self) -> &X509NameRef {
408 unsafe {
409 let name = ffi::X509_get_issuer_name(self.as_ptr());
410 X509NameRef::from_const_ptr_opt(name).expect("issuer name must not be null")
411 }
412 }
413
414 /// Returns the hash of the certificates issuer
415 #[corresponds(X509_issuer_name_hash)]
416 pub fn issuer_name_hash(&self) -> u32 {
417 #[allow(clippy::unnecessary_cast)]
418 unsafe {
419 ffi::X509_issuer_name_hash(self.as_ptr()) as u32
420 }
421 }
422
423 /// Returns this certificate's subject alternative name entries, if they exist.
424 #[corresponds(X509_get_ext_d2i)]
425 pub fn subject_alt_names(&self) -> Option<Stack<GeneralName>> {
426 unsafe {
427 let stack = ffi::X509_get_ext_d2i(
428 self.as_ptr(),
429 ffi::NID_subject_alt_name,
430 ptr::null_mut(),
431 ptr::null_mut(),
432 );
433 Stack::from_ptr_opt(stack as *mut _)
434 }
435 }
436
437 /// Returns this certificate's CRL distribution points, if they exist.
438 #[corresponds(X509_get_ext_d2i)]
439 pub fn crl_distribution_points(&self) -> Option<Stack<DistPoint>> {
440 unsafe {
441 let stack = ffi::X509_get_ext_d2i(
442 self.as_ptr(),
443 ffi::NID_crl_distribution_points,
444 ptr::null_mut(),
445 ptr::null_mut(),
446 );
447 Stack::from_ptr_opt(stack as *mut _)
448 }
449 }
450
451 /// Returns this certificate's issuer alternative name entries, if they exist.
452 #[corresponds(X509_get_ext_d2i)]
453 pub fn issuer_alt_names(&self) -> Option<Stack<GeneralName>> {
454 unsafe {
455 let stack = ffi::X509_get_ext_d2i(
456 self.as_ptr(),
457 ffi::NID_issuer_alt_name,
458 ptr::null_mut(),
459 ptr::null_mut(),
460 );
461 Stack::from_ptr_opt(stack as *mut _)
462 }
463 }
464
465 /// Returns this certificate's [`authority information access`] entries, if they exist.
466 ///
467 /// [`authority information access`]: https://tools.ietf.org/html/rfc5280#section-4.2.2.1
468 #[corresponds(X509_get_ext_d2i)]
469 pub fn authority_info(&self) -> Option<Stack<AccessDescription>> {
470 unsafe {
471 let stack = ffi::X509_get_ext_d2i(
472 self.as_ptr(),
473 ffi::NID_info_access,
474 ptr::null_mut(),
475 ptr::null_mut(),
476 );
477 Stack::from_ptr_opt(stack as *mut _)
478 }
479 }
480
481 /// Retrieves the path length extension from a certificate, if it exists.
482 #[corresponds(X509_get_pathlen)]
483 #[cfg(any(ossl110, boringssl))]
484 pub fn pathlen(&self) -> Option<u32> {
485 let v = unsafe { ffi::X509_get_pathlen(self.as_ptr()) };
486 u32::try_from(v).ok()
487 }
488
489 /// Returns this certificate's subject key id, if it exists.
490 #[corresponds(X509_get0_subject_key_id)]
491 #[cfg(any(ossl110, boringssl))]
492 pub fn subject_key_id(&self) -> Option<&Asn1OctetStringRef> {
493 unsafe {
494 let data = ffi::X509_get0_subject_key_id(self.as_ptr());
495 Asn1OctetStringRef::from_const_ptr_opt(data)
496 }
497 }
498
499 /// Returns this certificate's authority key id, if it exists.
500 #[corresponds(X509_get0_authority_key_id)]
501 #[cfg(any(ossl110, boringssl))]
502 pub fn authority_key_id(&self) -> Option<&Asn1OctetStringRef> {
503 unsafe {
504 let data = ffi::X509_get0_authority_key_id(self.as_ptr());
505 Asn1OctetStringRef::from_const_ptr_opt(data)
506 }
507 }
508
509 /// Returns this certificate's authority issuer name entries, if they exist.
510 #[corresponds(X509_get0_authority_issuer)]
511 #[cfg(ossl111d)]
512 pub fn authority_issuer(&self) -> Option<&StackRef<GeneralName>> {
513 unsafe {
514 let stack = ffi::X509_get0_authority_issuer(self.as_ptr());
515 StackRef::from_const_ptr_opt(stack)
516 }
517 }
518
519 /// Returns this certificate's authority serial number, if it exists.
520 #[corresponds(X509_get0_authority_serial)]
521 #[cfg(ossl111d)]
522 pub fn authority_serial(&self) -> Option<&Asn1IntegerRef> {
523 unsafe {
524 let r = ffi::X509_get0_authority_serial(self.as_ptr());
525 Asn1IntegerRef::from_const_ptr_opt(r)
526 }
527 }
528
529 #[corresponds(X509_get_pubkey)]
530 pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
531 unsafe {
532 let pkey = cvt_p(ffi::X509_get_pubkey(self.as_ptr()))?;
533 Ok(PKey::from_ptr(pkey))
534 }
535 }
536
537 /// Returns a digest of the DER representation of the certificate.
538 #[corresponds(X509_digest)]
539 pub fn digest(&self, hash_type: MessageDigest) -> Result<DigestBytes, ErrorStack> {
540 unsafe {
541 let mut digest = DigestBytes {
542 buf: [0; ffi::EVP_MAX_MD_SIZE as usize],
543 len: ffi::EVP_MAX_MD_SIZE as usize,
544 };
545 let mut len = ffi::EVP_MAX_MD_SIZE as c_uint;
546 cvt(ffi::X509_digest(
547 self.as_ptr(),
548 hash_type.as_ptr(),
549 digest.buf.as_mut_ptr() as *mut _,
550 &mut len,
551 ))?;
552 digest.len = len as usize;
553
554 Ok(digest)
555 }
556 }
557
558 #[deprecated(since = "0.10.9", note = "renamed to digest")]
559 pub fn fingerprint(&self, hash_type: MessageDigest) -> Result<Vec<u8>, ErrorStack> {
560 self.digest(hash_type).map(|b| b.to_vec())
561 }
562
563 /// Returns the certificate's Not After validity period.
564 #[corresponds(X509_getm_notAfter)]
565 pub fn not_after(&self) -> &Asn1TimeRef {
566 unsafe {
567 let date = X509_getm_notAfter(self.as_ptr());
568 Asn1TimeRef::from_const_ptr_opt(date).expect("not_after must not be null")
569 }
570 }
571
572 /// Returns the certificate's Not Before validity period.
573 #[corresponds(X509_getm_notBefore)]
574 pub fn not_before(&self) -> &Asn1TimeRef {
575 unsafe {
576 let date = X509_getm_notBefore(self.as_ptr());
577 Asn1TimeRef::from_const_ptr_opt(date).expect("not_before must not be null")
578 }
579 }
580
581 /// Returns the certificate's signature
582 #[corresponds(X509_get0_signature)]
583 pub fn signature(&self) -> &Asn1BitStringRef {
584 unsafe {
585 let mut signature = ptr::null();
586 X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr());
587 Asn1BitStringRef::from_const_ptr_opt(signature).expect("signature must not be null")
588 }
589 }
590
591 /// Returns the certificate's signature algorithm.
592 #[corresponds(X509_get0_signature)]
593 pub fn signature_algorithm(&self) -> &X509AlgorithmRef {
594 unsafe {
595 let mut algor = ptr::null();
596 X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr());
597 X509AlgorithmRef::from_const_ptr_opt(algor)
598 .expect("signature algorithm must not be null")
599 }
600 }
601
602 /// Returns the list of OCSP responder URLs specified in the certificate's Authority Information
603 /// Access field.
604 #[corresponds(X509_get1_ocsp)]
605 pub fn ocsp_responders(&self) -> Result<Stack<OpensslString>, ErrorStack> {
606 unsafe { cvt_p(ffi::X509_get1_ocsp(self.as_ptr())).map(|p| Stack::from_ptr(p)) }
607 }
608
609 /// Checks that this certificate issued `subject`.
610 #[corresponds(X509_check_issued)]
611 pub fn issued(&self, subject: &X509Ref) -> X509VerifyResult {
612 unsafe {
613 let r = ffi::X509_check_issued(self.as_ptr(), subject.as_ptr());
614 X509VerifyResult::from_raw(r)
615 }
616 }
617
618 /// Returns certificate version. If this certificate has no explicit version set, it defaults to
619 /// version 1.
620 ///
621 /// Note that `0` return value stands for version 1, `1` for version 2 and so on.
622 #[corresponds(X509_get_version)]
623 #[cfg(ossl110)]
624 #[allow(clippy::unnecessary_cast)]
625 pub fn version(&self) -> i32 {
626 unsafe { ffi::X509_get_version(self.as_ptr()) as i32 }
627 }
628
629 /// Check if the certificate is signed using the given public key.
630 ///
631 /// Only the signature is checked: no other checks (such as certificate chain validity)
632 /// are performed.
633 ///
634 /// Returns `true` if verification succeeds.
635 #[corresponds(X509_verify)]
636 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
637 where
638 T: HasPublic,
639 {
640 unsafe { cvt_n(ffi::X509_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
641 }
642
643 /// Returns this certificate's serial number.
644 #[corresponds(X509_get_serialNumber)]
645 pub fn serial_number(&self) -> &Asn1IntegerRef {
646 unsafe {
647 let r = ffi::X509_get_serialNumber(self.as_ptr());
648 Asn1IntegerRef::from_const_ptr_opt(r).expect("serial number must not be null")
649 }
650 }
651
652 /// Returns this certificate's "alias". This field is populated by
653 /// OpenSSL in some situations -- specifically OpenSSL will store a
654 /// PKCS#12 `friendlyName` in this field. This is not a part of the X.509
655 /// certificate itself, OpenSSL merely attaches it to this structure in
656 /// memory.
657 #[corresponds(X509_alias_get0)]
658 pub fn alias(&self) -> Option<&[u8]> {
659 unsafe {
660 let mut len = 0;
661 let ptr = ffi::X509_alias_get0(self.as_ptr(), &mut len);
662 if ptr.is_null() {
663 None
664 } else {
665 Some(slice::from_raw_parts(ptr, len as usize))
666 }
667 }
668 }
669
670 to_pem! {
671 /// Serializes the certificate into a PEM-encoded X509 structure.
672 ///
673 /// The output will have a header of `-----BEGIN CERTIFICATE-----`.
674 #[corresponds(PEM_write_bio_X509)]
675 to_pem,
676 ffi::PEM_write_bio_X509
677 }
678
679 to_der! {
680 /// Serializes the certificate into a DER-encoded X509 structure.
681 #[corresponds(i2d_X509)]
682 to_der,
683 ffi::i2d_X509
684 }
685
686 to_pem! {
687 /// Converts the certificate to human readable text.
688 #[corresponds(X509_print)]
689 to_text,
690 ffi::X509_print
691 }
692}
693
694impl ToOwned for X509Ref {
695 type Owned = X509;
696
697 fn to_owned(&self) -> X509 {
698 unsafe {
699 X509_up_ref(self.as_ptr());
700 X509::from_ptr(self.as_ptr())
701 }
702 }
703}
704
705impl Ord for X509Ref {
706 fn cmp(&self, other: &Self) -> cmp::Ordering {
707 // X509_cmp returns a number <0 for less than, 0 for equal and >0 for greater than.
708 // It can't fail if both pointers are valid, which we know is true.
709 let cmp: i32 = unsafe { ffi::X509_cmp(self.as_ptr(), b:other.as_ptr()) };
710 cmp.cmp(&0)
711 }
712}
713
714impl PartialOrd for X509Ref {
715 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
716 Some(self.cmp(other))
717 }
718}
719
720impl PartialOrd<X509> for X509Ref {
721 fn partial_cmp(&self, other: &X509) -> Option<cmp::Ordering> {
722 <X509Ref as PartialOrd<X509Ref>>::partial_cmp(self, other)
723 }
724}
725
726impl PartialEq for X509Ref {
727 fn eq(&self, other: &Self) -> bool {
728 self.cmp(other) == cmp::Ordering::Equal
729 }
730}
731
732impl PartialEq<X509> for X509Ref {
733 fn eq(&self, other: &X509) -> bool {
734 <X509Ref as PartialEq<X509Ref>>::eq(self, other)
735 }
736}
737
738impl Eq for X509Ref {}
739
740impl X509 {
741 /// Returns a new builder.
742 pub fn builder() -> Result<X509Builder, ErrorStack> {
743 X509Builder::new()
744 }
745
746 from_pem! {
747 /// Deserializes a PEM-encoded X509 structure.
748 ///
749 /// The input should have a header of `-----BEGIN CERTIFICATE-----`.
750 #[corresponds(PEM_read_bio_X509)]
751 from_pem,
752 X509,
753 ffi::PEM_read_bio_X509
754 }
755
756 from_der! {
757 /// Deserializes a DER-encoded X509 structure.
758 #[corresponds(d2i_X509)]
759 from_der,
760 X509,
761 ffi::d2i_X509
762 }
763
764 /// Deserializes a list of PEM-formatted certificates.
765 #[corresponds(PEM_read_bio_X509)]
766 pub fn stack_from_pem(pem: &[u8]) -> Result<Vec<X509>, ErrorStack> {
767 unsafe {
768 ffi::init();
769 let bio = MemBioSlice::new(pem)?;
770
771 let mut certs = vec![];
772 loop {
773 let r =
774 ffi::PEM_read_bio_X509(bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut());
775 if r.is_null() {
776 let e = ErrorStack::get();
777
778 if let Some(err) = e.errors().last() {
779 if err.library_code() == ffi::ERR_LIB_PEM as libc::c_int
780 && err.reason_code() == ffi::PEM_R_NO_START_LINE as libc::c_int
781 {
782 break;
783 }
784 }
785
786 return Err(e);
787 } else {
788 certs.push(X509(r));
789 }
790 }
791
792 Ok(certs)
793 }
794 }
795}
796
797impl Clone for X509 {
798 fn clone(&self) -> X509 {
799 X509Ref::to_owned(self)
800 }
801}
802
803impl fmt::Debug for X509 {
804 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
805 let serial = match &self.serial_number().to_bn() {
806 Ok(bn) => match bn.to_hex_str() {
807 Ok(hex) => hex.to_string(),
808 Err(_) => "".to_string(),
809 },
810 Err(_) => "".to_string(),
811 };
812 let mut debug_struct = formatter.debug_struct("X509");
813 debug_struct.field("serial_number", &serial);
814 debug_struct.field("signature_algorithm", &self.signature_algorithm().object());
815 debug_struct.field("issuer", &self.issuer_name());
816 debug_struct.field("subject", &self.subject_name());
817 if let Some(subject_alt_names) = &self.subject_alt_names() {
818 debug_struct.field("subject_alt_names", subject_alt_names);
819 }
820 debug_struct.field("not_before", &self.not_before());
821 debug_struct.field("not_after", &self.not_after());
822
823 if let Ok(public_key) = &self.public_key() {
824 debug_struct.field("public_key", public_key);
825 };
826 // TODO: Print extensions once they are supported on the X509 struct.
827
828 debug_struct.finish()
829 }
830}
831
832impl AsRef<X509Ref> for X509Ref {
833 fn as_ref(&self) -> &X509Ref {
834 self
835 }
836}
837
838impl Stackable for X509 {
839 type StackType = ffi::stack_st_X509;
840}
841
842impl Ord for X509 {
843 fn cmp(&self, other: &Self) -> cmp::Ordering {
844 X509Ref::cmp(self, other)
845 }
846}
847
848impl PartialOrd for X509 {
849 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
850 Some(self.cmp(other))
851 }
852}
853
854impl PartialOrd<X509Ref> for X509 {
855 fn partial_cmp(&self, other: &X509Ref) -> Option<cmp::Ordering> {
856 X509Ref::partial_cmp(self, other)
857 }
858}
859
860impl PartialEq for X509 {
861 fn eq(&self, other: &Self) -> bool {
862 X509Ref::eq(self, other)
863 }
864}
865
866impl PartialEq<X509Ref> for X509 {
867 fn eq(&self, other: &X509Ref) -> bool {
868 X509Ref::eq(self, other)
869 }
870}
871
872impl Eq for X509 {}
873
874/// A context object required to construct certain `X509` extension values.
875pub struct X509v3Context<'a>(ffi::X509V3_CTX, PhantomData<(&'a X509Ref, &'a ConfRef)>);
876
877impl<'a> X509v3Context<'a> {
878 pub fn as_ptr(&self) -> *mut ffi::X509V3_CTX {
879 &self.0 as *const _ as *mut _
880 }
881}
882
883foreign_type_and_impl_send_sync! {
884 type CType = ffi::X509_EXTENSION;
885 fn drop = ffi::X509_EXTENSION_free;
886
887 /// Permit additional fields to be added to an `X509` v3 certificate.
888 pub struct X509Extension;
889 /// Reference to `X509Extension`.
890 pub struct X509ExtensionRef;
891}
892
893impl Stackable for X509Extension {
894 type StackType = ffi::stack_st_X509_EXTENSION;
895}
896
897impl X509Extension {
898 /// Constructs an X509 extension value. See `man x509v3_config` for information on supported
899 /// names and their value formats.
900 ///
901 /// Some extension types, such as `subjectAlternativeName`, require an `X509v3Context` to be
902 /// provided.
903 ///
904 /// DO NOT CALL THIS WITH UNTRUSTED `value`: `value` is an OpenSSL
905 /// mini-language that can read arbitrary files.
906 ///
907 /// See the extension module for builder types which will construct certain common extensions.
908 ///
909 /// This function is deprecated, `X509Extension::new_from_der` or the
910 /// types in `x509::extension` should be used in its place.
911 #[deprecated(
912 note = "Use x509::extension types or new_from_der instead",
913 since = "0.10.51"
914 )]
915 pub fn new(
916 conf: Option<&ConfRef>,
917 context: Option<&X509v3Context<'_>>,
918 name: &str,
919 value: &str,
920 ) -> Result<X509Extension, ErrorStack> {
921 let name = CString::new(name).unwrap();
922 let value = CString::new(value).unwrap();
923 let mut ctx;
924 unsafe {
925 ffi::init();
926 let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
927 let context_ptr = match context {
928 Some(c) => c.as_ptr(),
929 None => {
930 ctx = mem::zeroed();
931
932 ffi::X509V3_set_ctx(
933 &mut ctx,
934 ptr::null_mut(),
935 ptr::null_mut(),
936 ptr::null_mut(),
937 ptr::null_mut(),
938 0,
939 );
940 &mut ctx
941 }
942 };
943 let name = name.as_ptr() as *mut _;
944 let value = value.as_ptr() as *mut _;
945
946 cvt_p(ffi::X509V3_EXT_nconf(conf, context_ptr, name, value)).map(X509Extension)
947 }
948 }
949
950 /// Constructs an X509 extension value. See `man x509v3_config` for information on supported
951 /// extensions and their value formats.
952 ///
953 /// Some extension types, such as `nid::SUBJECT_ALTERNATIVE_NAME`, require an `X509v3Context` to
954 /// be provided.
955 ///
956 /// DO NOT CALL THIS WITH UNTRUSTED `value`: `value` is an OpenSSL
957 /// mini-language that can read arbitrary files.
958 ///
959 /// See the extension module for builder types which will construct certain common extensions.
960 ///
961 /// This function is deprecated, `X509Extension::new_from_der` or the
962 /// types in `x509::extension` should be used in its place.
963 #[deprecated(
964 note = "Use x509::extension types or new_from_der instead",
965 since = "0.10.51"
966 )]
967 pub fn new_nid(
968 conf: Option<&ConfRef>,
969 context: Option<&X509v3Context<'_>>,
970 name: Nid,
971 value: &str,
972 ) -> Result<X509Extension, ErrorStack> {
973 let value = CString::new(value).unwrap();
974 let mut ctx;
975 unsafe {
976 ffi::init();
977 let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr);
978 let context_ptr = match context {
979 Some(c) => c.as_ptr(),
980 None => {
981 ctx = mem::zeroed();
982
983 ffi::X509V3_set_ctx(
984 &mut ctx,
985 ptr::null_mut(),
986 ptr::null_mut(),
987 ptr::null_mut(),
988 ptr::null_mut(),
989 0,
990 );
991 &mut ctx
992 }
993 };
994 let name = name.as_raw();
995 let value = value.as_ptr() as *mut _;
996
997 cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context_ptr, name, value)).map(X509Extension)
998 }
999 }
1000
1001 /// Constructs a new X509 extension value from its OID, whether it's
1002 /// critical, and its DER contents.
1003 ///
1004 /// The extent structure of the DER value will vary based on the
1005 /// extension type, and can generally be found in the RFC defining the
1006 /// extension.
1007 ///
1008 /// For common extension types, there are Rust APIs provided in
1009 /// `openssl::x509::extensions` which are more ergonomic.
1010 pub fn new_from_der(
1011 oid: &Asn1ObjectRef,
1012 critical: bool,
1013 der_contents: &Asn1OctetStringRef,
1014 ) -> Result<X509Extension, ErrorStack> {
1015 unsafe {
1016 cvt_p(ffi::X509_EXTENSION_create_by_OBJ(
1017 ptr::null_mut(),
1018 oid.as_ptr(),
1019 critical as _,
1020 der_contents.as_ptr(),
1021 ))
1022 .map(X509Extension)
1023 }
1024 }
1025
1026 pub(crate) unsafe fn new_internal(
1027 nid: Nid,
1028 critical: bool,
1029 value: *mut c_void,
1030 ) -> Result<X509Extension, ErrorStack> {
1031 ffi::init();
1032 cvt_p(ffi::X509V3_EXT_i2d(nid.as_raw(), critical as _, value)).map(X509Extension)
1033 }
1034
1035 /// Adds an alias for an extension
1036 ///
1037 /// # Safety
1038 ///
1039 /// This method modifies global state without locking and therefore is not thread safe
1040 #[cfg(not(libressl390))]
1041 #[corresponds(X509V3_EXT_add_alias)]
1042 #[deprecated(
1043 note = "Use x509::extension types or new_from_der and then this is not necessary",
1044 since = "0.10.51"
1045 )]
1046 pub unsafe fn add_alias(to: Nid, from: Nid) -> Result<(), ErrorStack> {
1047 ffi::init();
1048 cvt(ffi::X509V3_EXT_add_alias(to.as_raw(), from.as_raw())).map(|_| ())
1049 }
1050}
1051
1052impl X509ExtensionRef {
1053 to_der! {
1054 /// Serializes the Extension to its standard DER encoding.
1055 #[corresponds(i2d_X509_EXTENSION)]
1056 to_der,
1057 ffi::i2d_X509_EXTENSION
1058 }
1059}
1060
1061/// A builder used to construct an `X509Name`.
1062pub struct X509NameBuilder(X509Name);
1063
1064impl X509NameBuilder {
1065 /// Creates a new builder.
1066 pub fn new() -> Result<X509NameBuilder, ErrorStack> {
1067 unsafe {
1068 ffi::init();
1069 cvt_p(ffi::X509_NAME_new()).map(|p| X509NameBuilder(X509Name(p)))
1070 }
1071 }
1072
1073 /// Add a name entry
1074 #[corresponds(X509_NAME_add_entry)]
1075 #[cfg(any(ossl101, libressl350))]
1076 pub fn append_entry(&mut self, ne: &X509NameEntryRef) -> std::result::Result<(), ErrorStack> {
1077 unsafe {
1078 cvt(ffi::X509_NAME_add_entry(
1079 self.0.as_ptr(),
1080 ne.as_ptr(),
1081 -1,
1082 0,
1083 ))
1084 .map(|_| ())
1085 }
1086 }
1087
1088 /// Add a field entry by str.
1089 ///
1090 /// This corresponds to [`X509_NAME_add_entry_by_txt`].
1091 ///
1092 /// [`X509_NAME_add_entry_by_txt`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_txt.html
1093 pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> {
1094 unsafe {
1095 let field = CString::new(field).unwrap();
1096 assert!(value.len() <= crate::SLenType::max_value() as usize);
1097 cvt(ffi::X509_NAME_add_entry_by_txt(
1098 self.0.as_ptr(),
1099 field.as_ptr() as *mut _,
1100 ffi::MBSTRING_UTF8,
1101 value.as_ptr(),
1102 value.len() as crate::SLenType,
1103 -1,
1104 0,
1105 ))
1106 .map(|_| ())
1107 }
1108 }
1109
1110 /// Add a field entry by str with a specific type.
1111 ///
1112 /// This corresponds to [`X509_NAME_add_entry_by_txt`].
1113 ///
1114 /// [`X509_NAME_add_entry_by_txt`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_txt.html
1115 pub fn append_entry_by_text_with_type(
1116 &mut self,
1117 field: &str,
1118 value: &str,
1119 ty: Asn1Type,
1120 ) -> Result<(), ErrorStack> {
1121 unsafe {
1122 let field = CString::new(field).unwrap();
1123 assert!(value.len() <= crate::SLenType::max_value() as usize);
1124 cvt(ffi::X509_NAME_add_entry_by_txt(
1125 self.0.as_ptr(),
1126 field.as_ptr() as *mut _,
1127 ty.as_raw(),
1128 value.as_ptr(),
1129 value.len() as crate::SLenType,
1130 -1,
1131 0,
1132 ))
1133 .map(|_| ())
1134 }
1135 }
1136
1137 /// Add a field entry by NID.
1138 ///
1139 /// This corresponds to [`X509_NAME_add_entry_by_NID`].
1140 ///
1141 /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_NID.html
1142 pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> {
1143 unsafe {
1144 assert!(value.len() <= crate::SLenType::max_value() as usize);
1145 cvt(ffi::X509_NAME_add_entry_by_NID(
1146 self.0.as_ptr(),
1147 field.as_raw(),
1148 ffi::MBSTRING_UTF8,
1149 value.as_ptr() as *mut _,
1150 value.len() as crate::SLenType,
1151 -1,
1152 0,
1153 ))
1154 .map(|_| ())
1155 }
1156 }
1157
1158 /// Add a field entry by NID with a specific type.
1159 ///
1160 /// This corresponds to [`X509_NAME_add_entry_by_NID`].
1161 ///
1162 /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_NID.html
1163 pub fn append_entry_by_nid_with_type(
1164 &mut self,
1165 field: Nid,
1166 value: &str,
1167 ty: Asn1Type,
1168 ) -> Result<(), ErrorStack> {
1169 unsafe {
1170 assert!(value.len() <= crate::SLenType::max_value() as usize);
1171 cvt(ffi::X509_NAME_add_entry_by_NID(
1172 self.0.as_ptr(),
1173 field.as_raw(),
1174 ty.as_raw(),
1175 value.as_ptr() as *mut _,
1176 value.len() as crate::SLenType,
1177 -1,
1178 0,
1179 ))
1180 .map(|_| ())
1181 }
1182 }
1183
1184 /// Return an `X509Name`.
1185 pub fn build(self) -> X509Name {
1186 // Round-trip through bytes because OpenSSL is not const correct and
1187 // names in a "modified" state compute various things lazily. This can
1188 // lead to data-races because OpenSSL doesn't have locks or anything.
1189 X509Name::from_der(&self.0.to_der().unwrap()).unwrap()
1190 }
1191}
1192
1193foreign_type_and_impl_send_sync! {
1194 type CType = ffi::X509_NAME;
1195 fn drop = ffi::X509_NAME_free;
1196
1197 /// The names of an `X509` certificate.
1198 pub struct X509Name;
1199 /// Reference to `X509Name`.
1200 pub struct X509NameRef;
1201}
1202
1203impl X509Name {
1204 /// Returns a new builder.
1205 pub fn builder() -> Result<X509NameBuilder, ErrorStack> {
1206 X509NameBuilder::new()
1207 }
1208
1209 /// Loads subject names from a file containing PEM-formatted certificates.
1210 ///
1211 /// This is commonly used in conjunction with `SslContextBuilder::set_client_ca_list`.
1212 pub fn load_client_ca_file<P: AsRef<Path>>(file: P) -> Result<Stack<X509Name>, ErrorStack> {
1213 let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
1214 unsafe { cvt_p(ffi::SSL_load_client_CA_file(file.as_ptr())).map(|p| Stack::from_ptr(p)) }
1215 }
1216
1217 from_der! {
1218 /// Deserializes a DER-encoded X509 name structure.
1219 ///
1220 /// This corresponds to [`d2i_X509_NAME`].
1221 ///
1222 /// [`d2i_X509_NAME`]: https://www.openssl.org/docs/manmaster/man3/d2i_X509_NAME.html
1223 from_der,
1224 X509Name,
1225 ffi::d2i_X509_NAME
1226 }
1227}
1228
1229impl Stackable for X509Name {
1230 type StackType = ffi::stack_st_X509_NAME;
1231}
1232
1233impl X509NameRef {
1234 /// Returns the name entries by the nid.
1235 pub fn entries_by_nid(&self, nid: Nid) -> X509NameEntries<'_> {
1236 X509NameEntries {
1237 name: self,
1238 nid: Some(nid),
1239 loc: -1,
1240 }
1241 }
1242
1243 /// Returns an iterator over all `X509NameEntry` values
1244 pub fn entries(&self) -> X509NameEntries<'_> {
1245 X509NameEntries {
1246 name: self,
1247 nid: None,
1248 loc: -1,
1249 }
1250 }
1251
1252 /// Compare two names, like [`Ord`] but it may fail.
1253 ///
1254 /// With OpenSSL versions from 3.0.0 this may return an error if the underlying `X509_NAME_cmp`
1255 /// call fails.
1256 /// For OpenSSL versions before 3.0.0 it will never return an error, but due to a bug it may
1257 /// spuriously return `Ordering::Less` if the `X509_NAME_cmp` call fails.
1258 #[corresponds(X509_NAME_cmp)]
1259 pub fn try_cmp(&self, other: &X509NameRef) -> Result<Ordering, ErrorStack> {
1260 let cmp = unsafe { ffi::X509_NAME_cmp(self.as_ptr(), other.as_ptr()) };
1261 if cfg!(ossl300) && cmp == -2 {
1262 return Err(ErrorStack::get());
1263 }
1264 Ok(cmp.cmp(&0))
1265 }
1266
1267 /// Copies the name to a new `X509Name`.
1268 #[corresponds(X509_NAME_dup)]
1269 #[cfg(any(boringssl, ossl110, libressl270))]
1270 pub fn to_owned(&self) -> Result<X509Name, ErrorStack> {
1271 unsafe { cvt_p(ffi::X509_NAME_dup(self.as_ptr())).map(|n| X509Name::from_ptr(n)) }
1272 }
1273
1274 to_der! {
1275 /// Serializes the certificate into a DER-encoded X509 name structure.
1276 ///
1277 /// This corresponds to [`i2d_X509_NAME`].
1278 ///
1279 /// [`i2d_X509_NAME`]: https://www.openssl.org/docs/manmaster/crypto/i2d_X509_NAME.html
1280 to_der,
1281 ffi::i2d_X509_NAME
1282 }
1283}
1284
1285impl fmt::Debug for X509NameRef {
1286 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1287 formatter.debug_list().entries(self.entries()).finish()
1288 }
1289}
1290
1291/// A type to destructure and examine an `X509Name`.
1292pub struct X509NameEntries<'a> {
1293 name: &'a X509NameRef,
1294 nid: Option<Nid>,
1295 loc: c_int,
1296}
1297
1298impl<'a> Iterator for X509NameEntries<'a> {
1299 type Item = &'a X509NameEntryRef;
1300
1301 fn next(&mut self) -> Option<&'a X509NameEntryRef> {
1302 unsafe {
1303 match self.nid {
1304 Some(nid) => {
1305 // There is a `Nid` specified to search for
1306 self.loc =
1307 ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), nid.as_raw(), self.loc);
1308 if self.loc == -1 {
1309 return None;
1310 }
1311 }
1312 None => {
1313 // Iterate over all `Nid`s
1314 self.loc += 1;
1315 if self.loc >= ffi::X509_NAME_entry_count(self.name.as_ptr()) {
1316 return None;
1317 }
1318 }
1319 }
1320
1321 let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc);
1322
1323 Some(X509NameEntryRef::from_const_ptr_opt(entry).expect("entry must not be null"))
1324 }
1325 }
1326}
1327
1328foreign_type_and_impl_send_sync! {
1329 type CType = ffi::X509_NAME_ENTRY;
1330 fn drop = ffi::X509_NAME_ENTRY_free;
1331
1332 /// A name entry associated with a `X509Name`.
1333 pub struct X509NameEntry;
1334 /// Reference to `X509NameEntry`.
1335 pub struct X509NameEntryRef;
1336}
1337
1338impl X509NameEntryRef {
1339 /// Returns the field value of an `X509NameEntry`.
1340 ///
1341 /// This corresponds to [`X509_NAME_ENTRY_get_data`].
1342 ///
1343 /// [`X509_NAME_ENTRY_get_data`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_ENTRY_get_data.html
1344 pub fn data(&self) -> &Asn1StringRef {
1345 unsafe {
1346 let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr());
1347 Asn1StringRef::from_ptr(data)
1348 }
1349 }
1350
1351 /// Returns the `Asn1Object` value of an `X509NameEntry`.
1352 /// This is useful for finding out about the actual `Nid` when iterating over all `X509NameEntries`.
1353 ///
1354 /// This corresponds to [`X509_NAME_ENTRY_get_object`].
1355 ///
1356 /// [`X509_NAME_ENTRY_get_object`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_ENTRY_get_object.html
1357 pub fn object(&self) -> &Asn1ObjectRef {
1358 unsafe {
1359 let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr());
1360 Asn1ObjectRef::from_ptr(object)
1361 }
1362 }
1363}
1364
1365impl fmt::Debug for X509NameEntryRef {
1366 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1367 formatter.write_fmt(format_args!("{:?} = {:?}", self.object(), self.data()))
1368 }
1369}
1370
1371/// A builder used to construct an `X509Req`.
1372pub struct X509ReqBuilder(X509Req);
1373
1374impl X509ReqBuilder {
1375 /// Returns a builder for a certificate request.
1376 ///
1377 /// This corresponds to [`X509_REQ_new`].
1378 ///
1379 ///[`X509_REQ_new`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_new.html
1380 pub fn new() -> Result<X509ReqBuilder, ErrorStack> {
1381 unsafe {
1382 ffi::init();
1383 cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req(p)))
1384 }
1385 }
1386
1387 /// Set the numerical value of the version field.
1388 ///
1389 /// This corresponds to [`X509_REQ_set_version`].
1390 ///
1391 ///[`X509_REQ_set_version`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_set_version.html
1392 #[allow(clippy::useless_conversion)]
1393 pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> {
1394 unsafe {
1395 cvt(ffi::X509_REQ_set_version(
1396 self.0.as_ptr(),
1397 version as c_long,
1398 ))
1399 .map(|_| ())
1400 }
1401 }
1402
1403 /// Set the issuer name.
1404 ///
1405 /// This corresponds to [`X509_REQ_set_subject_name`].
1406 ///
1407 /// [`X509_REQ_set_subject_name`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_set_subject_name.html
1408 pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> {
1409 unsafe {
1410 cvt(ffi::X509_REQ_set_subject_name(
1411 self.0.as_ptr(),
1412 subject_name.as_ptr(),
1413 ))
1414 .map(|_| ())
1415 }
1416 }
1417
1418 /// Set the public key.
1419 ///
1420 /// This corresponds to [`X509_REQ_set_pubkey`].
1421 ///
1422 /// [`X509_REQ_set_pubkey`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_set_pubkey.html
1423 pub fn set_pubkey<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
1424 where
1425 T: HasPublic,
1426 {
1427 unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) }
1428 }
1429
1430 /// Return an `X509v3Context`. This context object can be used to construct
1431 /// certain `X509` extensions.
1432 pub fn x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a> {
1433 unsafe {
1434 let mut ctx = mem::zeroed();
1435
1436 ffi::X509V3_set_ctx(
1437 &mut ctx,
1438 ptr::null_mut(),
1439 ptr::null_mut(),
1440 self.0.as_ptr(),
1441 ptr::null_mut(),
1442 0,
1443 );
1444
1445 // nodb case taken care of since we zeroed ctx above
1446 if let Some(conf) = conf {
1447 ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr());
1448 }
1449
1450 X509v3Context(ctx, PhantomData)
1451 }
1452 }
1453
1454 /// Permits any number of extension fields to be added to the certificate.
1455 pub fn add_extensions(
1456 &mut self,
1457 extensions: &StackRef<X509Extension>,
1458 ) -> Result<(), ErrorStack> {
1459 unsafe {
1460 cvt(ffi::X509_REQ_add_extensions(
1461 self.0.as_ptr(),
1462 extensions.as_ptr(),
1463 ))
1464 .map(|_| ())
1465 }
1466 }
1467
1468 /// Sign the request using a private key.
1469 ///
1470 /// This corresponds to [`X509_REQ_sign`].
1471 ///
1472 /// [`X509_REQ_sign`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_sign.html
1473 pub fn sign<T>(&mut self, key: &PKeyRef<T>, hash: MessageDigest) -> Result<(), ErrorStack>
1474 where
1475 T: HasPrivate,
1476 {
1477 unsafe {
1478 cvt(ffi::X509_REQ_sign(
1479 self.0.as_ptr(),
1480 key.as_ptr(),
1481 hash.as_ptr(),
1482 ))
1483 .map(|_| ())
1484 }
1485 }
1486
1487 /// Returns the `X509Req`.
1488 pub fn build(self) -> X509Req {
1489 self.0
1490 }
1491}
1492
1493foreign_type_and_impl_send_sync! {
1494 type CType = ffi::X509_REQ;
1495 fn drop = ffi::X509_REQ_free;
1496
1497 /// An `X509` certificate request.
1498 pub struct X509Req;
1499 /// Reference to `X509Req`.
1500 pub struct X509ReqRef;
1501}
1502
1503impl X509Req {
1504 /// A builder for `X509Req`.
1505 pub fn builder() -> Result<X509ReqBuilder, ErrorStack> {
1506 X509ReqBuilder::new()
1507 }
1508
1509 from_pem! {
1510 /// Deserializes a PEM-encoded PKCS#10 certificate request structure.
1511 ///
1512 /// The input should have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1513 ///
1514 /// This corresponds to [`PEM_read_bio_X509_REQ`].
1515 ///
1516 /// [`PEM_read_bio_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/PEM_read_bio_X509_REQ.html
1517 from_pem,
1518 X509Req,
1519 ffi::PEM_read_bio_X509_REQ
1520 }
1521
1522 from_der! {
1523 /// Deserializes a DER-encoded PKCS#10 certificate request structure.
1524 ///
1525 /// This corresponds to [`d2i_X509_REQ`].
1526 ///
1527 /// [`d2i_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/d2i_X509_REQ.html
1528 from_der,
1529 X509Req,
1530 ffi::d2i_X509_REQ
1531 }
1532}
1533
1534impl X509ReqRef {
1535 to_pem! {
1536 /// Serializes the certificate request to a PEM-encoded PKCS#10 structure.
1537 ///
1538 /// The output will have a header of `-----BEGIN CERTIFICATE REQUEST-----`.
1539 ///
1540 /// This corresponds to [`PEM_write_bio_X509_REQ`].
1541 ///
1542 /// [`PEM_write_bio_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/PEM_write_bio_X509_REQ.html
1543 to_pem,
1544 ffi::PEM_write_bio_X509_REQ
1545 }
1546
1547 to_der! {
1548 /// Serializes the certificate request to a DER-encoded PKCS#10 structure.
1549 ///
1550 /// This corresponds to [`i2d_X509_REQ`].
1551 ///
1552 /// [`i2d_X509_REQ`]: https://www.openssl.org/docs/manmaster/crypto/i2d_X509_REQ.html
1553 to_der,
1554 ffi::i2d_X509_REQ
1555 }
1556
1557 to_pem! {
1558 /// Converts the request to human readable text.
1559 #[corresponds(X509_Req_print)]
1560 to_text,
1561 ffi::X509_REQ_print
1562 }
1563
1564 /// Returns the numerical value of the version field of the certificate request.
1565 ///
1566 /// This corresponds to [`X509_REQ_get_version`]
1567 ///
1568 /// [`X509_REQ_get_version`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_version.html
1569 #[allow(clippy::unnecessary_cast)]
1570 pub fn version(&self) -> i32 {
1571 unsafe { X509_REQ_get_version(self.as_ptr()) as i32 }
1572 }
1573
1574 /// Returns the subject name of the certificate request.
1575 ///
1576 /// This corresponds to [`X509_REQ_get_subject_name`]
1577 ///
1578 /// [`X509_REQ_get_subject_name`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_subject_name.html
1579 pub fn subject_name(&self) -> &X509NameRef {
1580 unsafe {
1581 let name = X509_REQ_get_subject_name(self.as_ptr());
1582 X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null")
1583 }
1584 }
1585
1586 /// Returns the public key of the certificate request.
1587 ///
1588 /// This corresponds to [`X509_REQ_get_pubkey"]
1589 ///
1590 /// [`X509_REQ_get_pubkey`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_pubkey.html
1591 pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
1592 unsafe {
1593 let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?;
1594 Ok(PKey::from_ptr(key))
1595 }
1596 }
1597
1598 /// Check if the certificate request is signed using the given public key.
1599 ///
1600 /// Returns `true` if verification succeeds.
1601 ///
1602 /// This corresponds to [`X509_REQ_verify"].
1603 ///
1604 /// [`X509_REQ_verify`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_verify.html
1605 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
1606 where
1607 T: HasPublic,
1608 {
1609 unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
1610 }
1611
1612 /// Returns the extensions of the certificate request.
1613 ///
1614 /// This corresponds to [`X509_REQ_get_extensions"]
1615 pub fn extensions(&self) -> Result<Stack<X509Extension>, ErrorStack> {
1616 unsafe {
1617 let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?;
1618 Ok(Stack::from_ptr(extensions))
1619 }
1620 }
1621}
1622
1623/// The reason that a certificate was revoked.
1624#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1625pub struct CrlReason(c_int);
1626
1627#[allow(missing_docs)] // no need to document the constants
1628impl CrlReason {
1629 pub const UNSPECIFIED: CrlReason = CrlReason(ffi::CRL_REASON_UNSPECIFIED);
1630 pub const KEY_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_KEY_COMPROMISE);
1631 pub const CA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_CA_COMPROMISE);
1632 pub const AFFILIATION_CHANGED: CrlReason = CrlReason(ffi::CRL_REASON_AFFILIATION_CHANGED);
1633 pub const SUPERSEDED: CrlReason = CrlReason(ffi::CRL_REASON_SUPERSEDED);
1634 pub const CESSATION_OF_OPERATION: CrlReason = CrlReason(ffi::CRL_REASON_CESSATION_OF_OPERATION);
1635 pub const CERTIFICATE_HOLD: CrlReason = CrlReason(ffi::CRL_REASON_CERTIFICATE_HOLD);
1636 pub const REMOVE_FROM_CRL: CrlReason = CrlReason(ffi::CRL_REASON_REMOVE_FROM_CRL);
1637 pub const PRIVILEGE_WITHDRAWN: CrlReason = CrlReason(ffi::CRL_REASON_PRIVILEGE_WITHDRAWN);
1638 pub const AA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_AA_COMPROMISE);
1639
1640 /// Constructs an `CrlReason` from a raw OpenSSL value.
1641 pub const fn from_raw(value: c_int) -> Self {
1642 CrlReason(value)
1643 }
1644
1645 /// Returns the raw OpenSSL value represented by this type.
1646 pub const fn as_raw(&self) -> c_int {
1647 self.0
1648 }
1649}
1650
1651foreign_type_and_impl_send_sync! {
1652 type CType = ffi::X509_REVOKED;
1653 fn drop = ffi::X509_REVOKED_free;
1654
1655 /// An `X509` certificate revocation status.
1656 pub struct X509Revoked;
1657 /// Reference to `X509Revoked`.
1658 pub struct X509RevokedRef;
1659}
1660
1661impl Stackable for X509Revoked {
1662 type StackType = ffi::stack_st_X509_REVOKED;
1663}
1664
1665impl X509Revoked {
1666 from_der! {
1667 /// Deserializes a DER-encoded certificate revocation status
1668 #[corresponds(d2i_X509_REVOKED)]
1669 from_der,
1670 X509Revoked,
1671 ffi::d2i_X509_REVOKED
1672 }
1673}
1674
1675impl X509RevokedRef {
1676 to_der! {
1677 /// Serializes the certificate request to a DER-encoded certificate revocation status
1678 #[corresponds(d2i_X509_REVOKED)]
1679 to_der,
1680 ffi::i2d_X509_REVOKED
1681 }
1682
1683 /// Copies the entry to a new `X509Revoked`.
1684 #[corresponds(X509_NAME_dup)]
1685 #[cfg(any(boringssl, ossl110, libressl270))]
1686 pub fn to_owned(&self) -> Result<X509Revoked, ErrorStack> {
1687 unsafe { cvt_p(ffi::X509_REVOKED_dup(self.as_ptr())).map(|n| X509Revoked::from_ptr(n)) }
1688 }
1689
1690 /// Get the date that the certificate was revoked
1691 #[corresponds(X509_REVOKED_get0_revocationDate)]
1692 pub fn revocation_date(&self) -> &Asn1TimeRef {
1693 unsafe {
1694 let r = X509_REVOKED_get0_revocationDate(self.as_ptr() as *const _);
1695 assert!(!r.is_null());
1696 Asn1TimeRef::from_ptr(r as *mut _)
1697 }
1698 }
1699
1700 /// Get the serial number of the revoked certificate
1701 #[corresponds(X509_REVOKED_get0_serialNumber)]
1702 pub fn serial_number(&self) -> &Asn1IntegerRef {
1703 unsafe {
1704 let r = X509_REVOKED_get0_serialNumber(self.as_ptr() as *const _);
1705 assert!(!r.is_null());
1706 Asn1IntegerRef::from_ptr(r as *mut _)
1707 }
1708 }
1709
1710 /// Get the criticality and value of an extension.
1711 ///
1712 /// This returns None if the extension is not present or occurs multiple times.
1713 #[corresponds(X509_REVOKED_get_ext_d2i)]
1714 pub fn extension<T: ExtensionType>(&self) -> Result<Option<(bool, T::Output)>, ErrorStack> {
1715 let mut critical = -1;
1716 let out = unsafe {
1717 // SAFETY: self.as_ptr() is a valid pointer to an X509_REVOKED.
1718 let ext = ffi::X509_REVOKED_get_ext_d2i(
1719 self.as_ptr(),
1720 T::NID.as_raw(),
1721 &mut critical as *mut _,
1722 ptr::null_mut(),
1723 );
1724 // SAFETY: Extensions's contract promises that the type returned by
1725 // OpenSSL here is T::Output.
1726 T::Output::from_ptr_opt(ext as *mut _)
1727 };
1728 match (critical, out) {
1729 (0, Some(out)) => Ok(Some((false, out))),
1730 (1, Some(out)) => Ok(Some((true, out))),
1731 // -1 means the extension wasn't found, -2 means multiple were found.
1732 (-1 | -2, _) => Ok(None),
1733 // A critical value of 0 or 1 suggests success, but a null pointer
1734 // was returned so something went wrong.
1735 (0 | 1, None) => Err(ErrorStack::get()),
1736 (c_int::MIN..=-2 | 2.., _) => panic!("OpenSSL should only return -2, -1, 0, or 1 for an extension's criticality but it returned {}", critical),
1737 }
1738 }
1739}
1740
1741/// The CRL entry extension identifying the reason for revocation see [`CrlReason`],
1742/// this is as defined in RFC 5280 Section 5.3.1.
1743pub enum ReasonCode {}
1744
1745// SAFETY: CertificateIssuer is defined to be a stack of GeneralName in the RFC
1746// and in OpenSSL.
1747unsafe impl ExtensionType for ReasonCode {
1748 const NID: Nid = Nid::from_raw(ffi::NID_crl_reason);
1749
1750 type Output = Asn1Enumerated;
1751}
1752
1753/// The CRL entry extension identifying the issuer of a certificate used in
1754/// indirect CRLs, as defined in RFC 5280 Section 5.3.3.
1755pub enum CertificateIssuer {}
1756
1757// SAFETY: CertificateIssuer is defined to be a stack of GeneralName in the RFC
1758// and in OpenSSL.
1759unsafe impl ExtensionType for CertificateIssuer {
1760 const NID: Nid = Nid::from_raw(ffi::NID_certificate_issuer);
1761
1762 type Output = Stack<GeneralName>;
1763}
1764
1765/// The CRL extension identifying how to access information and services for the issuer of the CRL
1766pub enum AuthorityInformationAccess {}
1767
1768// SAFETY: AuthorityInformationAccess is defined to be a stack of AccessDescription in the RFC
1769// and in OpenSSL.
1770unsafe impl ExtensionType for AuthorityInformationAccess {
1771 const NID: Nid = Nid::from_raw(ffi::NID_info_access);
1772
1773 type Output = Stack<AccessDescription>;
1774}
1775
1776foreign_type_and_impl_send_sync! {
1777 type CType = ffi::X509_CRL;
1778 fn drop = ffi::X509_CRL_free;
1779
1780 /// An `X509` certificate revocation list.
1781 pub struct X509Crl;
1782 /// Reference to `X509Crl`.
1783 pub struct X509CrlRef;
1784}
1785
1786/// The status of a certificate in a revoction list
1787///
1788/// Corresponds to the return value from the [`X509_CRL_get0_by_*`] methods.
1789///
1790/// [`X509_CRL_get0_by_*`]: https://www.openssl.org/docs/man1.1.0/man3/X509_CRL_get0_by_serial.html
1791pub enum CrlStatus<'a> {
1792 /// The certificate is not present in the list
1793 NotRevoked,
1794 /// The certificate is in the list and is revoked
1795 Revoked(&'a X509RevokedRef),
1796 /// The certificate is in the list, but has the "removeFromCrl" status.
1797 ///
1798 /// This can occur if the certificate was revoked with the "CertificateHold"
1799 /// reason, and has since been unrevoked.
1800 RemoveFromCrl(&'a X509RevokedRef),
1801}
1802
1803impl<'a> CrlStatus<'a> {
1804 // Helper used by the X509_CRL_get0_by_* methods to convert their return
1805 // value to the status enum.
1806 // Safety note: the returned CrlStatus must not outlive the owner of the
1807 // revoked_entry pointer.
1808 unsafe fn from_ffi_status(
1809 status: c_int,
1810 revoked_entry: *mut ffi::X509_REVOKED,
1811 ) -> CrlStatus<'a> {
1812 match status {
1813 0 => CrlStatus::NotRevoked,
1814 1 => {
1815 assert!(!revoked_entry.is_null());
1816 CrlStatus::Revoked(X509RevokedRef::from_ptr(revoked_entry))
1817 }
1818 2 => {
1819 assert!(!revoked_entry.is_null());
1820 CrlStatus::RemoveFromCrl(X509RevokedRef::from_ptr(revoked_entry))
1821 }
1822 _ => unreachable!(
1823 "{}",
1824 "X509_CRL_get0_by_{{serial,cert}} should only return 0, 1, or 2."
1825 ),
1826 }
1827 }
1828}
1829
1830impl X509Crl {
1831 from_pem! {
1832 /// Deserializes a PEM-encoded Certificate Revocation List
1833 ///
1834 /// The input should have a header of `-----BEGIN X509 CRL-----`.
1835 #[corresponds(PEM_read_bio_X509_CRL)]
1836 from_pem,
1837 X509Crl,
1838 ffi::PEM_read_bio_X509_CRL
1839 }
1840
1841 from_der! {
1842 /// Deserializes a DER-encoded Certificate Revocation List
1843 #[corresponds(d2i_X509_CRL)]
1844 from_der,
1845 X509Crl,
1846 ffi::d2i_X509_CRL
1847 }
1848}
1849
1850impl X509CrlRef {
1851 to_pem! {
1852 /// Serializes the certificate request to a PEM-encoded Certificate Revocation List.
1853 ///
1854 /// The output will have a header of `-----BEGIN X509 CRL-----`.
1855 #[corresponds(PEM_write_bio_X509_CRL)]
1856 to_pem,
1857 ffi::PEM_write_bio_X509_CRL
1858 }
1859
1860 to_der! {
1861 /// Serializes the certificate request to a DER-encoded Certificate Revocation List.
1862 #[corresponds(i2d_X509_CRL)]
1863 to_der,
1864 ffi::i2d_X509_CRL
1865 }
1866
1867 /// Get the stack of revocation entries
1868 pub fn get_revoked(&self) -> Option<&StackRef<X509Revoked>> {
1869 unsafe {
1870 let revoked = X509_CRL_get_REVOKED(self.as_ptr());
1871 if revoked.is_null() {
1872 None
1873 } else {
1874 Some(StackRef::from_ptr(revoked))
1875 }
1876 }
1877 }
1878
1879 /// Returns the CRL's `lastUpdate` time.
1880 #[corresponds(X509_CRL_get0_lastUpdate)]
1881 pub fn last_update(&self) -> &Asn1TimeRef {
1882 unsafe {
1883 let date = X509_CRL_get0_lastUpdate(self.as_ptr());
1884 assert!(!date.is_null());
1885 Asn1TimeRef::from_ptr(date as *mut _)
1886 }
1887 }
1888
1889 /// Returns the CRL's `nextUpdate` time.
1890 ///
1891 /// If the `nextUpdate` field is missing, returns `None`.
1892 #[corresponds(X509_CRL_get0_nextUpdate)]
1893 pub fn next_update(&self) -> Option<&Asn1TimeRef> {
1894 unsafe {
1895 let date = X509_CRL_get0_nextUpdate(self.as_ptr());
1896 Asn1TimeRef::from_const_ptr_opt(date)
1897 }
1898 }
1899
1900 /// Get the revocation status of a certificate by its serial number
1901 #[corresponds(X509_CRL_get0_by_serial)]
1902 pub fn get_by_serial<'a>(&'a self, serial: &Asn1IntegerRef) -> CrlStatus<'a> {
1903 unsafe {
1904 let mut ret = ptr::null_mut::<ffi::X509_REVOKED>();
1905 let status =
1906 ffi::X509_CRL_get0_by_serial(self.as_ptr(), &mut ret as *mut _, serial.as_ptr());
1907 CrlStatus::from_ffi_status(status, ret)
1908 }
1909 }
1910
1911 /// Get the revocation status of a certificate
1912 #[corresponds(X509_CRL_get0_by_cert)]
1913 pub fn get_by_cert<'a>(&'a self, cert: &X509) -> CrlStatus<'a> {
1914 unsafe {
1915 let mut ret = ptr::null_mut::<ffi::X509_REVOKED>();
1916 let status =
1917 ffi::X509_CRL_get0_by_cert(self.as_ptr(), &mut ret as *mut _, cert.as_ptr());
1918 CrlStatus::from_ffi_status(status, ret)
1919 }
1920 }
1921
1922 /// Get the issuer name from the revocation list.
1923 #[corresponds(X509_CRL_get_issuer)]
1924 pub fn issuer_name(&self) -> &X509NameRef {
1925 unsafe {
1926 let name = X509_CRL_get_issuer(self.as_ptr());
1927 assert!(!name.is_null());
1928 X509NameRef::from_ptr(name)
1929 }
1930 }
1931
1932 /// Check if the CRL is signed using the given public key.
1933 ///
1934 /// Only the signature is checked: no other checks (such as certificate chain validity)
1935 /// are performed.
1936 ///
1937 /// Returns `true` if verification succeeds.
1938 #[corresponds(X509_CRL_verify)]
1939 pub fn verify<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
1940 where
1941 T: HasPublic,
1942 {
1943 unsafe { cvt_n(ffi::X509_CRL_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
1944 }
1945
1946 /// Get the criticality and value of an extension.
1947 ///
1948 /// This returns None if the extension is not present or occurs multiple times.
1949 #[corresponds(X509_CRL_get_ext_d2i)]
1950 pub fn extension<T: ExtensionType>(&self) -> Result<Option<(bool, T::Output)>, ErrorStack> {
1951 let mut critical = -1;
1952 let out = unsafe {
1953 // SAFETY: self.as_ptr() is a valid pointer to an X509_CRL.
1954 let ext = ffi::X509_CRL_get_ext_d2i(
1955 self.as_ptr(),
1956 T::NID.as_raw(),
1957 &mut critical as *mut _,
1958 ptr::null_mut(),
1959 );
1960 // SAFETY: Extensions's contract promises that the type returned by
1961 // OpenSSL here is T::Output.
1962 T::Output::from_ptr_opt(ext as *mut _)
1963 };
1964 match (critical, out) {
1965 (0, Some(out)) => Ok(Some((false, out))),
1966 (1, Some(out)) => Ok(Some((true, out))),
1967 // -1 means the extension wasn't found, -2 means multiple were found.
1968 (-1 | -2, _) => Ok(None),
1969 // A critical value of 0 or 1 suggests success, but a null pointer
1970 // was returned so something went wrong.
1971 (0 | 1, None) => Err(ErrorStack::get()),
1972 (c_int::MIN..=-2 | 2.., _) => panic!("OpenSSL should only return -2, -1, 0, or 1 for an extension's criticality but it returned {}", critical),
1973 }
1974 }
1975}
1976
1977/// The result of peer certificate verification.
1978#[derive(Copy, Clone, PartialEq, Eq)]
1979pub struct X509VerifyResult(c_int);
1980
1981impl fmt::Debug for X509VerifyResult {
1982 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1983 fmt&mut DebugStruct<'_, '_>.debug_struct("X509VerifyResult")
1984 .field("code", &self.0)
1985 .field(name:"error", &self.error_string())
1986 .finish()
1987 }
1988}
1989
1990impl fmt::Display for X509VerifyResult {
1991 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1992 fmt.write_str(self.error_string())
1993 }
1994}
1995
1996impl Error for X509VerifyResult {}
1997
1998impl X509VerifyResult {
1999 /// Creates an `X509VerifyResult` from a raw error number.
2000 ///
2001 /// # Safety
2002 ///
2003 /// Some methods on `X509VerifyResult` are not thread safe if the error
2004 /// number is invalid.
2005 pub unsafe fn from_raw(err: c_int) -> X509VerifyResult {
2006 X509VerifyResult(err)
2007 }
2008
2009 /// Return the integer representation of an `X509VerifyResult`.
2010 #[allow(clippy::trivially_copy_pass_by_ref)]
2011 pub fn as_raw(&self) -> c_int {
2012 self.0
2013 }
2014
2015 /// Return a human readable error string from the verification error.
2016 ///
2017 /// This corresponds to [`X509_verify_cert_error_string`].
2018 ///
2019 /// [`X509_verify_cert_error_string`]: https://www.openssl.org/docs/manmaster/crypto/X509_verify_cert_error_string.html
2020 #[allow(clippy::trivially_copy_pass_by_ref)]
2021 pub fn error_string(&self) -> &'static str {
2022 ffi::init();
2023
2024 unsafe {
2025 let s = ffi::X509_verify_cert_error_string(self.0 as c_long);
2026 str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()
2027 }
2028 }
2029
2030 /// Successful peer certificate verification.
2031 pub const OK: X509VerifyResult = X509VerifyResult(ffi::X509_V_OK);
2032 /// Application verification failure.
2033 pub const APPLICATION_VERIFICATION: X509VerifyResult =
2034 X509VerifyResult(ffi::X509_V_ERR_APPLICATION_VERIFICATION);
2035}
2036
2037foreign_type_and_impl_send_sync! {
2038 type CType = ffi::GENERAL_NAME;
2039 fn drop = ffi::GENERAL_NAME_free;
2040
2041 /// An `X509` certificate alternative names.
2042 pub struct GeneralName;
2043 /// Reference to `GeneralName`.
2044 pub struct GeneralNameRef;
2045}
2046
2047impl GeneralName {
2048 unsafe fn new(
2049 type_: c_int,
2050 asn1_type: Asn1Type,
2051 value: &[u8],
2052 ) -> Result<GeneralName, ErrorStack> {
2053 ffi::init();
2054 let gn = GeneralName::from_ptr(cvt_p(ffi::GENERAL_NAME_new())?);
2055 (*gn.as_ptr()).type_ = type_;
2056 let s = cvt_p(ffi::ASN1_STRING_type_new(asn1_type.as_raw()))?;
2057 ffi::ASN1_STRING_set(s, value.as_ptr().cast(), value.len().try_into().unwrap());
2058
2059 #[cfg(boringssl)]
2060 {
2061 (*gn.as_ptr()).d.ptr = s.cast();
2062 }
2063 #[cfg(not(boringssl))]
2064 {
2065 (*gn.as_ptr()).d = s.cast();
2066 }
2067
2068 Ok(gn)
2069 }
2070
2071 pub(crate) fn new_email(email: &[u8]) -> Result<GeneralName, ErrorStack> {
2072 unsafe { GeneralName::new(ffi::GEN_EMAIL, Asn1Type::IA5STRING, email) }
2073 }
2074
2075 pub(crate) fn new_dns(dns: &[u8]) -> Result<GeneralName, ErrorStack> {
2076 unsafe { GeneralName::new(ffi::GEN_DNS, Asn1Type::IA5STRING, dns) }
2077 }
2078
2079 pub(crate) fn new_uri(uri: &[u8]) -> Result<GeneralName, ErrorStack> {
2080 unsafe { GeneralName::new(ffi::GEN_URI, Asn1Type::IA5STRING, uri) }
2081 }
2082
2083 pub(crate) fn new_ip(ip: IpAddr) -> Result<GeneralName, ErrorStack> {
2084 match ip {
2085 IpAddr::V4(addr) => unsafe {
2086 GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
2087 },
2088 IpAddr::V6(addr) => unsafe {
2089 GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets())
2090 },
2091 }
2092 }
2093
2094 pub(crate) fn new_rid(oid: Asn1Object) -> Result<GeneralName, ErrorStack> {
2095 unsafe {
2096 ffi::init();
2097 let gn = cvt_p(ffi::GENERAL_NAME_new())?;
2098 (*gn).type_ = ffi::GEN_RID;
2099
2100 #[cfg(boringssl)]
2101 {
2102 (*gn).d.registeredID = oid.as_ptr();
2103 }
2104 #[cfg(not(boringssl))]
2105 {
2106 (*gn).d = oid.as_ptr().cast();
2107 }
2108
2109 mem::forget(oid);
2110
2111 Ok(GeneralName::from_ptr(gn))
2112 }
2113 }
2114
2115 pub(crate) fn new_other_name(oid: Asn1Object, value: &[u8]) -> Result<GeneralName, ErrorStack> {
2116 unsafe {
2117 ffi::init();
2118
2119 let typ = cvt_p(ffi::d2i_ASN1_TYPE(
2120 ptr::null_mut(),
2121 &mut value.as_ptr().cast(),
2122 value.len().try_into().unwrap(),
2123 ))?;
2124
2125 let gn = cvt_p(ffi::GENERAL_NAME_new())?;
2126 (*gn).type_ = ffi::GEN_OTHERNAME;
2127
2128 if let Err(e) = cvt(ffi::GENERAL_NAME_set0_othername(
2129 gn,
2130 oid.as_ptr().cast(),
2131 typ,
2132 )) {
2133 ffi::GENERAL_NAME_free(gn);
2134 return Err(e);
2135 }
2136
2137 mem::forget(oid);
2138
2139 Ok(GeneralName::from_ptr(gn))
2140 }
2141 }
2142}
2143
2144impl GeneralNameRef {
2145 fn ia5_string(&self, ffi_type: c_int) -> Option<&str> {
2146 unsafe {
2147 if (*self.as_ptr()).type_ != ffi_type {
2148 return None;
2149 }
2150
2151 #[cfg(boringssl)]
2152 let d = (*self.as_ptr()).d.ptr;
2153 #[cfg(not(boringssl))]
2154 let d = (*self.as_ptr()).d;
2155
2156 let ptr = ASN1_STRING_get0_data(d as *mut _);
2157 let len = ffi::ASN1_STRING_length(d as *mut _);
2158
2159 #[allow(clippy::unnecessary_cast)]
2160 let slice = slice::from_raw_parts(ptr as *const u8, len as usize);
2161 // IA5Strings are stated to be ASCII (specifically IA5). Hopefully
2162 // OpenSSL checks that when loading a certificate but if not we'll
2163 // use this instead of from_utf8_unchecked just in case.
2164 str::from_utf8(slice).ok()
2165 }
2166 }
2167
2168 /// Returns the contents of this `GeneralName` if it is an `rfc822Name`.
2169 pub fn email(&self) -> Option<&str> {
2170 self.ia5_string(ffi::GEN_EMAIL)
2171 }
2172
2173 /// Returns the contents of this `GeneralName` if it is a `directoryName`.
2174 pub fn directory_name(&self) -> Option<&X509NameRef> {
2175 unsafe {
2176 if (*self.as_ptr()).type_ != ffi::GEN_DIRNAME {
2177 return None;
2178 }
2179
2180 #[cfg(boringssl)]
2181 let d = (*self.as_ptr()).d.ptr;
2182 #[cfg(not(boringssl))]
2183 let d = (*self.as_ptr()).d;
2184
2185 Some(X509NameRef::from_const_ptr(d as *const _))
2186 }
2187 }
2188
2189 /// Returns the contents of this `GeneralName` if it is a `dNSName`.
2190 pub fn dnsname(&self) -> Option<&str> {
2191 self.ia5_string(ffi::GEN_DNS)
2192 }
2193
2194 /// Returns the contents of this `GeneralName` if it is an `uniformResourceIdentifier`.
2195 pub fn uri(&self) -> Option<&str> {
2196 self.ia5_string(ffi::GEN_URI)
2197 }
2198
2199 /// Returns the contents of this `GeneralName` if it is an `iPAddress`.
2200 pub fn ipaddress(&self) -> Option<&[u8]> {
2201 unsafe {
2202 if (*self.as_ptr()).type_ != ffi::GEN_IPADD {
2203 return None;
2204 }
2205 #[cfg(boringssl)]
2206 let d: *const ffi::ASN1_STRING = std::mem::transmute((*self.as_ptr()).d);
2207 #[cfg(not(boringssl))]
2208 let d = (*self.as_ptr()).d;
2209
2210 let ptr = ASN1_STRING_get0_data(d as *mut _);
2211 let len = ffi::ASN1_STRING_length(d as *mut _);
2212
2213 #[allow(clippy::unnecessary_cast)]
2214 Some(slice::from_raw_parts(ptr as *const u8, len as usize))
2215 }
2216 }
2217}
2218
2219impl fmt::Debug for GeneralNameRef {
2220 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
2221 if let Some(email: &str) = self.email() {
2222 formatter.write_str(data:email)
2223 } else if let Some(dnsname: &str) = self.dnsname() {
2224 formatter.write_str(data:dnsname)
2225 } else if let Some(uri: &str) = self.uri() {
2226 formatter.write_str(data:uri)
2227 } else if let Some(ipaddress: &[u8]) = self.ipaddress() {
2228 let address: Result = <[u8; 16]>::try_from(ipaddress)
2229 .map(IpAddr::from)
2230 .or_else(|_| <[u8; 4]>::try_from(ipaddress).map(op:IpAddr::from));
2231 match address {
2232 Ok(a: IpAddr) => fmt::Debug::fmt(&a, f:formatter),
2233 Err(_) => fmt::Debug::fmt(self:ipaddress, f:formatter),
2234 }
2235 } else {
2236 formatter.write_str(data:"(empty)")
2237 }
2238 }
2239}
2240
2241impl Stackable for GeneralName {
2242 type StackType = ffi::stack_st_GENERAL_NAME;
2243}
2244
2245foreign_type_and_impl_send_sync! {
2246 type CType = ffi::DIST_POINT;
2247 fn drop = ffi::DIST_POINT_free;
2248
2249 /// A `X509` distribution point.
2250 pub struct DistPoint;
2251 /// Reference to `DistPoint`.
2252 pub struct DistPointRef;
2253}
2254
2255impl DistPointRef {
2256 /// Returns the name of this distribution point if it exists
2257 pub fn distpoint(&self) -> Option<&DistPointNameRef> {
2258 unsafe { DistPointNameRef::from_const_ptr_opt((*self.as_ptr()).distpoint) }
2259 }
2260}
2261
2262foreign_type_and_impl_send_sync! {
2263 type CType = ffi::DIST_POINT_NAME;
2264 fn drop = ffi::DIST_POINT_NAME_free;
2265
2266 /// A `X509` distribution point.
2267 pub struct DistPointName;
2268 /// Reference to `DistPointName`.
2269 pub struct DistPointNameRef;
2270}
2271
2272impl DistPointNameRef {
2273 /// Returns the contents of this DistPointName if it is a fullname.
2274 pub fn fullname(&self) -> Option<&StackRef<GeneralName>> {
2275 unsafe {
2276 if (*self.as_ptr()).type_ != 0 {
2277 return None;
2278 }
2279 StackRef::from_const_ptr_opt((*self.as_ptr()).name.fullname)
2280 }
2281 }
2282}
2283
2284impl Stackable for DistPoint {
2285 type StackType = ffi::stack_st_DIST_POINT;
2286}
2287
2288foreign_type_and_impl_send_sync! {
2289 type CType = ffi::ACCESS_DESCRIPTION;
2290 fn drop = ffi::ACCESS_DESCRIPTION_free;
2291
2292 /// `AccessDescription` of certificate authority information.
2293 pub struct AccessDescription;
2294 /// Reference to `AccessDescription`.
2295 pub struct AccessDescriptionRef;
2296}
2297
2298impl AccessDescriptionRef {
2299 /// Returns the access method OID.
2300 pub fn method(&self) -> &Asn1ObjectRef {
2301 unsafe { Asn1ObjectRef::from_ptr((*self.as_ptr()).method) }
2302 }
2303
2304 // Returns the access location.
2305 pub fn location(&self) -> &GeneralNameRef {
2306 unsafe { GeneralNameRef::from_ptr((*self.as_ptr()).location) }
2307 }
2308}
2309
2310impl Stackable for AccessDescription {
2311 type StackType = ffi::stack_st_ACCESS_DESCRIPTION;
2312}
2313
2314foreign_type_and_impl_send_sync! {
2315 type CType = ffi::X509_ALGOR;
2316 fn drop = ffi::X509_ALGOR_free;
2317
2318 /// An `X509` certificate signature algorithm.
2319 pub struct X509Algorithm;
2320 /// Reference to `X509Algorithm`.
2321 pub struct X509AlgorithmRef;
2322}
2323
2324impl X509AlgorithmRef {
2325 /// Returns the ASN.1 OID of this algorithm.
2326 pub fn object(&self) -> &Asn1ObjectRef {
2327 unsafe {
2328 let mut oid: *const ASN1_OBJECT = ptr::null();
2329 X509_ALGOR_get0(&mut oid, pptype:ptr::null_mut(), ppval:ptr::null_mut(), self.as_ptr());
2330 Asn1ObjectRef::from_const_ptr_opt(oid).expect(msg:"algorithm oid must not be null")
2331 }
2332 }
2333}
2334
2335foreign_type_and_impl_send_sync! {
2336 type CType = ffi::X509_OBJECT;
2337 fn drop = X509_OBJECT_free;
2338
2339 /// An `X509` or an X509 certificate revocation list.
2340 pub struct X509Object;
2341 /// Reference to `X509Object`
2342 pub struct X509ObjectRef;
2343}
2344
2345impl X509ObjectRef {
2346 pub fn x509(&self) -> Option<&X509Ref> {
2347 unsafe {
2348 let ptr: *mut X509 = X509_OBJECT_get0_X509(self.as_ptr());
2349 X509Ref::from_const_ptr_opt(ptr)
2350 }
2351 }
2352}
2353
2354impl Stackable for X509Object {
2355 type StackType = ffi::stack_st_X509_OBJECT;
2356}
2357
2358cfg_if! {
2359 if #[cfg(any(boringssl, ossl110, libressl273))] {
2360 use ffi::{X509_getm_notAfter, X509_getm_notBefore, X509_up_ref, X509_get0_signature};
2361 } else {
2362 #[allow(bad_style)]
2363 unsafe fn X509_getm_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME {
2364 (*(*(*x).cert_info).validity).notAfter
2365 }
2366
2367 #[allow(bad_style)]
2368 unsafe fn X509_getm_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME {
2369 (*(*(*x).cert_info).validity).notBefore
2370 }
2371
2372 #[allow(bad_style)]
2373 unsafe fn X509_up_ref(x: *mut ffi::X509) {
2374 ffi::CRYPTO_add_lock(
2375 &mut (*x).references,
2376 1,
2377 ffi::CRYPTO_LOCK_X509,
2378 "mod.rs\0".as_ptr() as *const _,
2379 line!() as c_int,
2380 );
2381 }
2382
2383 #[allow(bad_style)]
2384 unsafe fn X509_get0_signature(
2385 psig: *mut *const ffi::ASN1_BIT_STRING,
2386 palg: *mut *const ffi::X509_ALGOR,
2387 x: *const ffi::X509,
2388 ) {
2389 if !psig.is_null() {
2390 *psig = (*x).signature;
2391 }
2392 if !palg.is_null() {
2393 *palg = (*x).sig_alg;
2394 }
2395 }
2396 }
2397}
2398
2399cfg_if! {
2400 if #[cfg(any(boringssl, ossl110, libressl350))] {
2401 use ffi::{
2402 X509_ALGOR_get0, ASN1_STRING_get0_data, X509_STORE_CTX_get0_chain, X509_set1_notAfter,
2403 X509_set1_notBefore, X509_REQ_get_version, X509_REQ_get_subject_name,
2404 };
2405 } else {
2406 use ffi::{
2407 ASN1_STRING_data as ASN1_STRING_get0_data,
2408 X509_STORE_CTX_get_chain as X509_STORE_CTX_get0_chain,
2409 X509_set_notAfter as X509_set1_notAfter,
2410 X509_set_notBefore as X509_set1_notBefore,
2411 };
2412
2413 #[allow(bad_style)]
2414 unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long {
2415 ffi::ASN1_INTEGER_get((*(*x).req_info).version)
2416 }
2417
2418 #[allow(bad_style)]
2419 unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME {
2420 (*(*x).req_info).subject
2421 }
2422
2423 #[allow(bad_style)]
2424 unsafe fn X509_ALGOR_get0(
2425 paobj: *mut *const ffi::ASN1_OBJECT,
2426 pptype: *mut c_int,
2427 pval: *mut *mut ::libc::c_void,
2428 alg: *const ffi::X509_ALGOR,
2429 ) {
2430 if !paobj.is_null() {
2431 *paobj = (*alg).algorithm;
2432 }
2433 assert!(pptype.is_null());
2434 assert!(pval.is_null());
2435 }
2436 }
2437}
2438
2439cfg_if! {
2440 if #[cfg(any(ossl110, boringssl, libressl270))] {
2441 use ffi::X509_OBJECT_get0_X509;
2442 } else {
2443 #[allow(bad_style)]
2444 unsafe fn X509_OBJECT_get0_X509(x: *mut ffi::X509_OBJECT) -> *mut ffi::X509 {
2445 if (*x).type_ == ffi::X509_LU_X509 {
2446 (*x).data.x509
2447 } else {
2448 ptr::null_mut()
2449 }
2450 }
2451 }
2452}
2453
2454cfg_if! {
2455 if #[cfg(any(ossl110, libressl350, boringssl))] {
2456 use ffi::X509_OBJECT_free;
2457 } else {
2458 #[allow(bad_style)]
2459 unsafe fn X509_OBJECT_free(x: *mut ffi::X509_OBJECT) {
2460 ffi::X509_OBJECT_free_contents(x);
2461 ffi::CRYPTO_free(x as *mut libc::c_void);
2462 }
2463 }
2464}
2465
2466cfg_if! {
2467 if #[cfg(any(ossl110, libressl350, boringssl))] {
2468 use ffi::{
2469 X509_CRL_get_issuer, X509_CRL_get0_nextUpdate, X509_CRL_get0_lastUpdate,
2470 X509_CRL_get_REVOKED,
2471 X509_REVOKED_get0_revocationDate, X509_REVOKED_get0_serialNumber,
2472 };
2473 } else {
2474 #[allow(bad_style)]
2475 unsafe fn X509_CRL_get0_lastUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME {
2476 (*(*x).crl).lastUpdate
2477 }
2478 #[allow(bad_style)]
2479 unsafe fn X509_CRL_get0_nextUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME {
2480 (*(*x).crl).nextUpdate
2481 }
2482 #[allow(bad_style)]
2483 unsafe fn X509_CRL_get_issuer(x: *const ffi::X509_CRL) -> *mut ffi::X509_NAME {
2484 (*(*x).crl).issuer
2485 }
2486 #[allow(bad_style)]
2487 unsafe fn X509_CRL_get_REVOKED(x: *const ffi::X509_CRL) -> *mut ffi::stack_st_X509_REVOKED {
2488 (*(*x).crl).revoked
2489 }
2490 #[allow(bad_style)]
2491 unsafe fn X509_REVOKED_get0_serialNumber(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_INTEGER {
2492 (*x).serialNumber
2493 }
2494 #[allow(bad_style)]
2495 unsafe fn X509_REVOKED_get0_revocationDate(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_TIME {
2496 (*x).revocationDate
2497 }
2498 }
2499}
2500
2501#[derive(Copy, Clone, PartialEq, Eq)]
2502pub struct X509PurposeId(c_int);
2503
2504impl X509PurposeId {
2505 pub const SSL_CLIENT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_CLIENT);
2506 pub const SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_SERVER);
2507 pub const NS_SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_NS_SSL_SERVER);
2508 pub const SMIME_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_SIGN);
2509 pub const SMIME_ENCRYPT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_ENCRYPT);
2510 pub const CRL_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_CRL_SIGN);
2511 pub const ANY: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_ANY);
2512 pub const OCSP_HELPER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_OCSP_HELPER);
2513 pub const TIMESTAMP_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_TIMESTAMP_SIGN);
2514 #[cfg(ossl320)]
2515 pub const CODE_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_CODE_SIGN);
2516
2517 /// Constructs an `X509PurposeId` from a raw OpenSSL value.
2518 pub fn from_raw(id: c_int) -> Self {
2519 X509PurposeId(id)
2520 }
2521
2522 /// Returns the raw OpenSSL value represented by this type.
2523 pub fn as_raw(&self) -> c_int {
2524 self.0
2525 }
2526}
2527
2528/// A reference to an [`X509_PURPOSE`].
2529pub struct X509PurposeRef(Opaque);
2530
2531/// Implements a wrapper type for the static `X509_PURPOSE` table in OpenSSL.
2532impl ForeignTypeRef for X509PurposeRef {
2533 type CType = ffi::X509_PURPOSE;
2534}
2535
2536impl X509PurposeRef {
2537 /// Get the internal table index of an X509_PURPOSE for a given short name. Valid short
2538 /// names include
2539 /// - "sslclient",
2540 /// - "sslserver",
2541 /// - "nssslserver",
2542 /// - "smimesign",
2543 /// - "smimeencrypt",
2544 /// - "crlsign",
2545 /// - "any",
2546 /// - "ocsphelper",
2547 /// - "timestampsign"
2548 /// The index can be used with `X509PurposeRef::from_idx()` to get the purpose.
2549 #[allow(clippy::unnecessary_cast)]
2550 pub fn get_by_sname(sname: &str) -> Result<c_int, ErrorStack> {
2551 unsafe {
2552 let sname = CString::new(sname).unwrap();
2553 cfg_if! {
2554 if #[cfg(any(ossl110, libressl280, boringssl))] {
2555 let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *const _))?;
2556 } else {
2557 let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *mut _))?;
2558 }
2559 }
2560 Ok(purpose)
2561 }
2562 }
2563 /// Get an `X509PurposeRef` for a given index value. The index can be obtained from e.g.
2564 /// `X509PurposeRef::get_by_sname()`.
2565 #[corresponds(X509_PURPOSE_get0)]
2566 pub fn from_idx(idx: c_int) -> Result<&'static X509PurposeRef, ErrorStack> {
2567 unsafe {
2568 let ptr = cvt_p_const(ffi::X509_PURPOSE_get0(idx))?;
2569 Ok(X509PurposeRef::from_const_ptr(ptr))
2570 }
2571 }
2572
2573 /// Get the purpose value from an X509Purpose structure. This value is one of
2574 /// - `X509_PURPOSE_SSL_CLIENT`
2575 /// - `X509_PURPOSE_SSL_SERVER`
2576 /// - `X509_PURPOSE_NS_SSL_SERVER`
2577 /// - `X509_PURPOSE_SMIME_SIGN`
2578 /// - `X509_PURPOSE_SMIME_ENCRYPT`
2579 /// - `X509_PURPOSE_CRL_SIGN`
2580 /// - `X509_PURPOSE_ANY`
2581 /// - `X509_PURPOSE_OCSP_HELPER`
2582 /// - `X509_PURPOSE_TIMESTAMP_SIGN`
2583 pub fn purpose(&self) -> X509PurposeId {
2584 unsafe {
2585 cfg_if! {
2586 if #[cfg(any(ossl110, libressl280, boringssl))] {
2587 let x509_purpose = self.as_ptr() as *const ffi::X509_PURPOSE;
2588 } else {
2589 let x509_purpose = self.as_ptr() as *mut ffi::X509_PURPOSE;
2590 }
2591 }
2592 X509PurposeId::from_raw(ffi::X509_PURPOSE_get_id(x509_purpose))
2593 }
2594 }
2595}
2596