1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
//! OCSP example — build a certificate identifier and an OCSP request.
//!
//! This example shows the client-side construction of an OCSP request.
//! HTTP transport is the caller's responsibility; this example stops at the
//! DER-encoded request bytes that would be sent to the responder.
//!
//! Run with: cargo run --example ocsp -p native-ossl
use native_ossl::ocsp::{OcspCertId, OcspRequest, OcspResponseStatus};
use native_ossl::pkey::KeygenCtx;
use native_ossl::x509::{X509Builder, X509NameOwned};
fn make_cert(
priv_key: &native_ossl::pkey::Pkey<native_ossl::pkey::Private>,
pub_key: &native_ossl::pkey::Pkey<native_ossl::pkey::Public>,
cn: &[u8],
serial: i64,
) -> Result<native_ossl::x509::X509, Box<dyn std::error::Error>> {
let mut name = X509NameOwned::new()?;
name.add_entry_by_txt(c"CN", cn)?;
let cert = X509Builder::new()?
.set_version(2)?
.set_serial_number(serial)?
.set_not_before_offset(0)?
.set_not_after_offset(365 * 86400)?
.set_subject_name(&name)?
.set_issuer_name(&name)?
.set_public_key(pub_key)?
.sign(priv_key, None)?
.build();
Ok(cert)
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
// ── Build a minimal CA and end-entity certificate pair ───────────────────
let mut kgen = KeygenCtx::new(c"ED25519")?;
let ca_priv = kgen.generate()?;
let ca_pub = native_ossl::pkey::Pkey::<native_ossl::pkey::Public>::from(ca_priv.clone());
let ee_priv = kgen.generate()?;
let ee_pub = native_ossl::pkey::Pkey::<native_ossl::pkey::Public>::from(ee_priv.clone());
let ca_cert = make_cert(&ca_priv, &ca_pub, b"Test CA", 1)?;
let ee_cert = make_cert(&ee_priv, &ee_pub, b"end-entity.example.com", 42)?;
// ── Build a certificate identifier (SHA-1, the OCSP default) ─────────────
// Pass `None` for the digest to use SHA-1 — required by most deployed
// OCSP responders regardless of the certificate's signature algorithm.
let cert_id = OcspCertId::from_cert(None, &ee_cert, &ca_cert)?;
println!("OcspCertId created for serial 42");
// ── Build an OCSP request ─────────────────────────────────────────────────
let mut req = OcspRequest::new()?;
// add_cert_id consumes the cert_id (add0 semantics).
// Clone first if you need to reuse it later (e.g. for find_status).
req.add_cert_id(cert_id.clone())?;
let req_der = req.to_der()?;
println!("OCSP request DER: {} bytes", req_der.len());
println!("Hex: {}", hex::encode(&req_der));
// At this point `req_der` would be sent as the body of an HTTP POST
// to the OCSP responder URL found in the certificate's AIA extension.
// ── Parsing a response (demonstration with a constructed response) ────────
// We can't get a real network response in this example, but demonstrate
// what the status check looks like once the DER bytes arrive:
//
// let resp = OcspResponse::from_der(&resp_der)?;
// assert_eq!(resp.status(), OcspResponseStatus::Successful);
// let basic = resp.basic()?;
// basic.verify(&store, 0)?;
// if let Some(status) = basic.find_status(&cert_id)? {
// match status.cert_status {
// OcspCertStatus::Good => println!("certificate is valid"),
// OcspCertStatus::Revoked { reason } => println!("REVOKED: {reason}"),
// OcspCertStatus::Unknown => println!("responder does not know"),
// }
// }
let _ = OcspResponseStatus::Successful; // confirm type is accessible
println!("OcspResponseStatus variants accessible: OK");
Ok(())
}