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