Coverage Report

Created: 2026-06-02 06:27

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