diff --git a/Cargo.lock b/Cargo.lock index 6120dd7d4..10dc6075a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -518,6 +518,16 @@ dependencies = [ "libc", ] +[[package]] +name = "ocsp" +version = "0.0.1" +dependencies = [ + "der", + "hex-literal", + "spki", + "x509", +] + [[package]] name = "oorandom" version = "11.1.3" @@ -574,6 +584,7 @@ dependencies = [ "der", "hex-literal", "spki", + "x509", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index fd3318139..1cd59bbac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "const-oid", "der", "der/derive", + "ocsp", "pem-rfc7468", "pkcs1", "pkcs5", diff --git a/ocsp/Cargo.toml b/ocsp/Cargo.toml new file mode 100644 index 000000000..029ea5646 --- /dev/null +++ b/ocsp/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "ocsp" +version = "0.0.1" +description = """ +Pure Rust implementation of the X.509 Internet Public Key Infrastructure +Online Certificate Status Protocol - OCSP formats as described in RFC 6960 +""" +authors = ["RustCrypto Developers"] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/RustCrypto/formats/tree/master/x509" +categories = ["cryptography", "data-structures", "encoding", "no-std"] +keywords = ["crypto", "x.509"] +readme = "README.md" +edition = "2021" +rust-version = "1.57" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +der = { version = "0.6.0-pre.1", features = ["oid", "derive", "alloc"], path = "../der" } +x509 = { version = "0.0.1", path = "../x509" } +spki = { version = "=0.6.0-pre.0", path = "../spki" } + +[dev-dependencies] +hex-literal = "0.3" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/ocsp/README.md b/ocsp/README.md new file mode 100644 index 000000000..ff65e5799 --- /dev/null +++ b/ocsp/README.md @@ -0,0 +1,60 @@ +# [RustCrypto]: X.509 + +[![crate][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +[![Build Status][build-image]][build-link] +![Apache2/MIT licensed][license-image] +![Rust Version][rustc-image] +[![Project Chat][chat-image]][chat-link] + +Pure Rust implementation of the X.509 Internet Public Key Infrastructure +Online Certificate Status Protocol - OCSP formats as described in [RFC 6960]. + +[Documentation][docs-link] + +## Status + +tl;dr: not ready to use. + +This is a work-in-progress implementation which is at an early stage of +development. + +## Minimum Supported Rust Version + +This crate requires **Rust 1.57** at a minimum. + +We may change the MSRV in the future, but it will be accompanied by a minor +version bump. + +## License + +Licensed under either of: + +- [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) +- [MIT license](http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +[//]: # (badges) + +[crate-image]: https://img.shields.io/crates/v/x509.svg +[crate-link]: https://crates.io/crates/x509 +[docs-image]: https://docs.rs/x509/badge.svg +[docs-link]: https://docs.rs/x509/ +[build-image]: https://github.com/RustCrypto/formats/actions/workflows/x509.yml/badge.svg +[build-link]: https://github.com/RustCrypto/formats/actions/workflows/x509.yml +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.57+-blue.svg +[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg +[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/300570-formats + +[//]: # (links) + +[RustCrypto]: https://github.com/rustcrypto +[RFC 6960]: https://datatracker.ietf.org/doc/html/rfc6960 diff --git a/ocsp/src/lib.rs b/ocsp/src/lib.rs new file mode 100644 index 000000000..f7cc3d707 --- /dev/null +++ b/ocsp/src/lib.rs @@ -0,0 +1,5 @@ +//! The ocsp module features encoders and decoders for the structures defined in [RFC 6960](https://datatracker.ietf.org/doc/html/rfc6960). + +pub mod ocsp; + +extern crate alloc; diff --git a/ocsp/src/ocsp.rs b/ocsp/src/ocsp.rs new file mode 100644 index 000000000..46c7d576f --- /dev/null +++ b/ocsp/src/ocsp.rs @@ -0,0 +1,395 @@ +use der::asn1::{BitString, Ia5String, ObjectIdentifier, OctetString, UIntBytes}; +use der::asn1::{GeneralizedTime, Null}; +use der::{Any, Choice, Enumerated, Sequence}; +use spki::AlgorithmIdentifier; +use x509::ext::pkix::name::GeneralName; +use x509::ext::pkix::{AuthorityInfoAccessSyntax, CrlReason}; +use x509::ext::Extensions; +use x509::name::Name; +use x509::Certificate; + +/// ```text +/// OCSPRequest ::= SEQUENCE { +/// tbsRequest TBSRequest, +/// optionalSignature [0] EXPLICIT Signature OPTIONAL } +/// ``` +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct OcspRequest<'a> { + pub tbs_request: TbsRequest<'a>, + + #[asn1(context_specific = "0", optional = "true", tag_mode = "EXPLICIT")] + pub optional_signature: Option>, +} + +/// ```text +/// TBSRequest ::= SEQUENCE { +/// version [0] EXPLICIT Version DEFAULT v1, +/// requestorName [1] EXPLICIT GeneralName OPTIONAL, +/// requestList SEQUENCE OF Request, +/// requestExtensions [2] EXPLICIT Extensions OPTIONAL } +/// ``` +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct TbsRequest<'a> { + #[asn1( + context_specific = "0", + default = "Default::default", + tag_mode = "EXPLICIT" + )] + pub version: Version, + + #[asn1(context_specific = "1", optional = "true", tag_mode = "EXPLICIT")] + pub requestor_name: Option>, + + pub request_list: alloc::vec::Vec>, + + #[asn1(context_specific = "2", optional = "true", tag_mode = "EXPLICIT")] + pub request_extensions: Option>, +} + +/// ```text +/// Signature ::= SEQUENCE { +/// signatureAlgorithm AlgorithmIdentifier, +/// signature BIT STRING, +/// certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } +/// ``` +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct Signature<'a> { + pub signature_algorithm: AlgorithmIdentifier<'a>, + pub signature: BitString<'a>, + + #[asn1(context_specific = "0", optional = "true", tag_mode = "EXPLICIT")] + pub certs: Option>>, +} + +/// OCSP `Version` as defined in [RFC 6960 Section 4.1]. +/// +/// ```text +/// Version ::= INTEGER { v1(0) } +/// ``` +/// +#[derive(Clone, Debug, Copy, PartialEq, Eq, Enumerated)] +#[asn1(type = "INTEGER")] +#[repr(u8)] +#[allow(missing_docs)] +pub enum Version { + V1 = 0, +} + +impl Default for Version { + fn default() -> Self { + Self::V1 + } +} + +/// ```text +/// Request ::= SEQUENCE { +/// reqCert CertID, +/// singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL } +/// ``` +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct Request<'a> { + pub req_cert: CertId<'a>, + + #[asn1(context_specific = "0", optional = "true", tag_mode = "EXPLICIT")] + pub single_request_extensions: Option>, +} + +/// ```text +/// CertID ::= SEQUENCE { +/// hashAlgorithm AlgorithmIdentifier, +/// issuerNameHash OCTET STRING, -- Hash of issuer's DN +/// issuerKeyHash OCTET STRING, -- Hash of issuer's public key +/// serialNumber CertificateSerialNumber } +/// ``` +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct CertId<'a> { + pub hash_algorithm: AlgorithmIdentifier<'a>, + pub issuer_name_hash: OctetString<'a>, + pub issuer_key_hash: OctetString<'a>, + pub serial_number: UIntBytes<'a>, +} + +/// ```text +/// OCSPResponse ::= SEQUENCE { +/// responseStatus OCSPResponseStatus, +/// responseBytes [0] EXPLICIT ResponseBytes OPTIONAL } +/// ``` +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct OcspResponse<'a> { + pub response_status: OcspResponseStatus, + + #[asn1(context_specific = "0", optional = "true", tag_mode = "EXPLICIT")] + pub response_bytes: Option>, +} + +/// ```text +/// OCSPResponseStatus ::= ENUMERATED { +/// successful (0), -- Response has valid confirmations +/// malformedRequest (1), -- Illegal confirmation request +/// internalError (2), -- Internal error in issuer +/// tryLater (3), -- Try again later +/// -- (4) is not used +/// sigRequired (5), -- Must sign the request +/// unauthorized (6) -- Request unauthorized +/// } +/// ``` +#[derive(Enumerated, Copy, Clone, Debug, Eq, PartialEq)] +#[repr(u32)] +#[allow(missing_docs)] +pub enum OcspResponseStatus { + Successful = 0, + MalformedRequest = 1, + InternalError = 2, + TryLater = 3, + SigRequired = 5, + Unauthorized = 6, +} + +/// ```text +/// ResponseBytes ::= SEQUENCE { +/// responseType OBJECT IDENTIFIER, +/// response OCTET STRING } +/// ``` +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct ResponseBytes<'a> { + pub response_type: ObjectIdentifier, + pub response: OctetString<'a>, +} + +/// ```text +/// BasicOCSPResponse ::= SEQUENCE { +/// tbsResponseData ResponseData, +/// signatureAlgorithm AlgorithmIdentifier, +/// signature BIT STRING, +/// certs \[0\] EXPLICIT SEQUENCE OF Certificate OPTIONAL } +/// ``` +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct BasicOcspResponse<'a> { + pub tbs_response_data: ResponseData<'a>, + pub signature_algorithm: AlgorithmIdentifier<'a>, + pub signature: BitString<'a>, + + #[asn1(context_specific = "0", optional = "true", tag_mode = "EXPLICIT")] + pub certs: Option>>, +} + +/// ```text +// ResponseData ::= SEQUENCE { +/// version [0] EXPLICIT Version DEFAULT v1, +/// responderID ResponderID, +/// producedAt GeneralizedTime, +/// responses SEQUENCE OF SingleResponse, +/// responseExtensions [1] EXPLICIT Extensions OPTIONAL } +/// ``` +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct ResponseData<'a> { + #[asn1( + context_specific = "0", + default = "Default::default", + tag_mode = "EXPLICIT" + )] + pub version: Version, + pub responder_id: ResponderId<'a>, + pub produced_at: GeneralizedTime, + pub responses: Vec>, + + #[asn1(context_specific = "1", optional = "true", tag_mode = "EXPLICIT")] + pub response_extensions: Option>, +} + +/// ```text +// ResponderID ::= CHOICE { +/// byName [1] Name, +/// byKey [2] KeyHash } +/// ``` +#[derive(Clone, Debug, Eq, PartialEq, Choice)] +#[allow(missing_docs)] +pub enum ResponderId<'a> { + #[asn1(context_specific = "1", tag_mode = "EXPLICIT", constructed = "true")] + ByName(Name<'a>), + + #[asn1(context_specific = "2", tag_mode = "EXPLICIT", constructed = "true")] + ByKey(KeyHash<'a>), +} + +/// ```text +/// KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key +/// -- (i.e., the SHA-1 hash of the value of the +/// -- BIT STRING subjectPublicKey [excluding +/// -- the tag, length, and number of unused +/// -- bits] in the responder's certificate) +/// ``` +pub type KeyHash<'a> = OctetString<'a>; + +/// ```text +// SingleResponse ::= SEQUENCE { +/// certID CertID, +/// certStatus CertStatus, +/// thisUpdate GeneralizedTime, +/// nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, +/// singleExtensions [1] EXPLICIT Extensions OPTIONAL } +/// ``` +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct SingleResponse<'a> { + pub cert_id: CertId<'a>, + pub cert_status: CertStatus, + pub this_update: GeneralizedTime, + + #[asn1(context_specific = "0", optional = "true", tag_mode = "EXPLICIT")] + pub next_update: Option, + + #[asn1(context_specific = "1", optional = "true", tag_mode = "EXPLICIT")] + pub single_request_extensions: Option>, +} + +/// ```text +/// CertStatus ::= CHOICE { +/// good [0] IMPLICIT NULL, +/// revoked [1] IMPLICIT RevokedInfo, +/// unknown [2] IMPLICIT UnknownInfo } +/// ``` +#[derive(Clone, Debug, Eq, PartialEq, Choice)] +#[allow(missing_docs)] +pub enum CertStatus { + #[asn1(context_specific = "0", tag_mode = "IMPLICIT")] + Good(Null), + + #[asn1(context_specific = "1", tag_mode = "IMPLICIT", constructed = "true")] + Revoked(RevokedInfo), + + #[asn1(context_specific = "2", tag_mode = "IMPLICIT")] + Unknown(UnknownInfo), +} + +/// ```text +// RevokedInfo ::= SEQUENCE { +/// revocationTime GeneralizedTime, +/// revocationReason [0] EXPLICIT CRLReason OPTIONAL } +/// ``` +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct RevokedInfo { + pub revocation_time: GeneralizedTime, + + #[asn1(context_specific = "0", optional = "true", tag_mode = "EXPLICIT")] + pub revocation_reason: Option, +} + +/// ```text +/// UnknownInfo ::= NULL +/// ``` +pub type UnknownInfo = Null; + +/// ```text +// ArchiveCutoff ::= GeneralizedTime +/// ``` +pub type ArchiveCutoff = GeneralizedTime; + +/// ```text +// AcceptableResponses ::= SEQUENCE OF OBJECT IDENTIFIER +/// ``` +pub type AcceptableResponses = Vec; + +/// ```text +/// ServiceLocator ::= SEQUENCE { +/// issuer Name, +/// locator AuthorityInfoAccessSyntax } +/// ``` +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct ServiceLocator<'a> { + pub issuer: Name<'a>, + pub locator: AuthorityInfoAccessSyntax<'a>, +} + +/// ```text +/// CrlID ::= SEQUENCE { +/// crlUrl [0] EXPLICIT IA5String OPTIONAL, +/// crlNum [1] EXPLICIT INTEGER OPTIONAL, +/// crlTime [2] EXPLICIT GeneralizedTime OPTIONAL } +/// ``` +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct CrlId<'a> { + #[asn1(context_specific = "0", optional = "true", tag_mode = "EXPLICIT")] + pub crl_url: Option>, + + #[asn1(context_specific = "1", optional = "true", tag_mode = "EXPLICIT")] + pub crl_num: Option>, + + #[asn1(context_specific = "2", optional = "true", tag_mode = "EXPLICIT")] + pub crl_time: Option, +} + +/// ```text +/// PreferredSignatureAlgorithms ::= SEQUENCE OF PreferredSignatureAlgorithm +/// ``` +pub type PreferredSignatureAlgorithms<'a> = Vec>; + +/// ```text +/// PreferredSignatureAlgorithm ::= SEQUENCE { +/// sigIdentifier AlgorithmIdentifier, +/// certIdentifier AlgorithmIdentifier OPTIONAL } +/// ``` +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct PreferredSignatureAlgorithm<'a> { + pub sig_identifier: AlgorithmIdentifier<'a>, + pub cert_identifier: Option>, +} + +// Object Identifiers +// id-pkix OBJECT IDENTIFIER ::= +// { iso(1) identified-organization(3) dod(6) internet(1) +// security(5) mechanisms(5) pkix(7) } +// id-kp OBJECT IDENTIFIER ::= { id-pkix 3 } + +/// id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } +pub const KP_OCSP_SIGNING: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.3.9"); + +// id-ad OBJECT IDENTIFIER ::= { id-pkix 48 } +// id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 } + +/// id-pkix-ocsp OBJECT IDENTIFIER ::= { id-ad-ocsp } +pub const OCSP: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.1"); + +/// id-pkix-ocsp-basic OBJECT IDENTIFIER ::= { id-pkix-ocsp 1 } +pub const OCSP_BASIC: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.1.1"); + +/// id-pkix-ocsp-nonce OBJECT IDENTIFIER ::= { id-pkix-ocsp 2 } +pub const OCSP_NONCE: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.1.2"); + +/// id-pkix-ocsp-crl OBJECT IDENTIFIER ::= { id-pkix-ocsp 3 } +pub const OCSP_CRL: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.1.3"); + +/// id-pkix-ocsp-response OBJECT IDENTIFIER ::= { id-pkix-ocsp 4 } +pub const OCSP_RESPONSE: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.1.4"); + +/// id-pkix-ocsp-nocheck OBJECT IDENTIFIER ::= { id-pkix-ocsp 5 } +pub const OCSP_NOCHECK: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.1.5"); + +/// id-pkix-ocsp-archive-cutoff OBJECT IDENTIFIER ::= { id-pkix-ocsp 6 } +pub const KP_OCSP_ARCHIVE_CUTOFF: ObjectIdentifier = + ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.1.6"); + +/// id-pkix-ocsp-service-locator OBJECT IDENTIFIER ::= { id-pkix-ocsp 7 } +pub const OCSP_SERVICE_LOCATOR: ObjectIdentifier = + ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.1.7"); + +/// id-pkix-ocsp-pref-sig-algs OBJECT IDENTIFIER ::= { id-pkix-ocsp 8 } +pub const OCSP_PREF_SIG_ALGS: ObjectIdentifier = + ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.1.8"); + +/// id-pkix-ocsp-extended-revoke OBJECT IDENTIFIER ::= { id-pkix-ocsp 9 } +pub const OCSP_EXTENDED_REVOKE: ObjectIdentifier = + ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.48.1.9"); diff --git a/ocsp/tests/ocsp.rs b/ocsp/tests/ocsp.rs new file mode 100644 index 000000000..063c37d4d --- /dev/null +++ b/ocsp/tests/ocsp.rs @@ -0,0 +1,296 @@ +use der::asn1::{Null, ObjectIdentifier}; +use der::{Decodable, Encodable}; +use hex_literal::hex; +use ocsp::ocsp::Version::V1; +use ocsp::ocsp::*; +use x509::ext::pkix::CrlReason; + +#[test] +fn decode_ocsp_req_ca_signed() { + // request generated using openssl via this command: + // openssl ocsp -noverify -no_nonce -respout ~/Desktop/ocspdigicert.resp + // -reqout ~/Desktop/ocspdigicert.req -issuer ~/Desktop/DigiCertGlobalCAG2.crt + // -cert ~/Desktop/amazon.der -url http://ocsp.digicert.com -header "HOST" "ocsp.digicert.com" -text + + pub const PKIXALG_SHA1: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.14.3.2.26"); + + let ocsp_req = + OcspRequest::from_der(&hex!("3051304F304D304B3049300906052B0E03021A05000414A87E303106E4E88565CFE952598FA6DA7C00532F0414246E2B2DD06A925151256901AA9A47A689E7402002100E4239AB85E2E6A27C52C6DE9B9078D9")[..]).unwrap(); + assert_eq!(ocsp_req.tbs_request.version, V1); + //assert!(ocsp_req.tbs_request.requestor_name.is_none()); + assert_eq!(ocsp_req.tbs_request.request_list.len(), 1); + let req = &ocsp_req.tbs_request.request_list[0]; + assert_eq!(req.req_cert.hash_algorithm.oid, PKIXALG_SHA1); + assert!(req.req_cert.hash_algorithm.parameters.is_some()); + assert_eq!( + req.req_cert + .hash_algorithm + .parameters + .to_vec() + .unwrap() + .as_slice(), + Null.to_vec().unwrap().as_slice() + ); + assert_eq!( + req.req_cert.issuer_name_hash.as_bytes(), + &hex!("A87E303106E4E88565CFE952598FA6DA7C00532F") + ); + assert_eq!( + req.req_cert.issuer_key_hash.as_bytes(), + &hex!("246E2B2DD06A925151256901AA9A47A689E74020") + ); + assert_eq!( + req.req_cert.serial_number.as_bytes(), + &hex!("0E4239AB85E2E6A27C52C6DE9B9078D9") + ); + + let reenc = ocsp_req.to_vec().unwrap(); + assert_eq!(reenc, &hex!("3051304F304D304B3049300906052B0E03021A05000414A87E303106E4E88565CFE952598FA6DA7C00532F0414246E2B2DD06A925151256901AA9A47A689E7402002100E4239AB85E2E6A27C52C6DE9B9078D9")[..]) +} + +#[test] +fn decode_ocsp_resp_ca_signed() { + // response generated using openssl via this command: + // openssl ocsp -noverify -no_nonce -respout ~/Desktop/ocspdigicert.resp + // -reqout ~/Desktop/ocspdigicert.req -issuer ~/Desktop/DigiCertGlobalCAG2.crt + // -cert ~/Desktop/amazon.der -url http://ocsp.digicert.com -header "HOST" "ocsp.digicert.com" -text + + // 308201D30A0100A08201CC308201C806092B0601050507300101048201B9308201B530819EA2160414246E2B2DD06A925151256901AA9A47A689E74020180F32303232303230323034313232355A307330713049300906052B0E03021A05000414A87E303106E4E88565CFE952598FA6DA7C00532F0414246E2B2DD06A925151256901AA9A47A689E7402002100E4239AB85E2E6A27C52C6DE9B9078D98000180F32303232303230323033353730315AA011180F32303232303230393033313230315A300D06092A864886F70D01010B0500038201010089DC0913BD91DB172C314AE8F78E6574950353618FFBBF2F12B1F134F21EC20063E66C60AC463BDB926A9D5B699EB39689032659D43C441863BAC9D8B7CC84137B558503D2631348EDA79AEC9FD4B69AE988F68A752470D3D4BA46F41B9FD41A974A5311BAA191AFBA370F0B051F035297FA76A2133B98FF471BDA4BFBFDA275B4FA1CF8377EEB2B2141F9C998ACE27C60F11E221D6732A5D538FEDF9A01D776E1877BCF70A8C953630B2C66752A66DF087C075794F5A2C0023C964CD73476EA2556F091F6C191B30B74E2523F668F32CE10AFB3D51CE053D4D41E62214B60171093AB915DBBA497F09B3C279127E1D25C7AA6A7048BBEA41A23F4F827BD108F + let ocsp_resp = + OcspResponse::from_der(&hex!("308201D30A0100A08201CC308201C806092B0601050507300101048201B9308201B530819EA2160414246E2B2DD06A925151256901AA9A47A689E74020180F32303232303230323034313232355A307330713049300906052B0E03021A05000414A87E303106E4E88565CFE952598FA6DA7C00532F0414246E2B2DD06A925151256901AA9A47A689E7402002100E4239AB85E2E6A27C52C6DE9B9078D98000180F32303232303230323033353730315AA011180F32303232303230393033313230315A300D06092A864886F70D01010B0500038201010089DC0913BD91DB172C314AE8F78E6574950353618FFBBF2F12B1F134F21EC20063E66C60AC463BDB926A9D5B699EB39689032659D43C441863BAC9D8B7CC84137B558503D2631348EDA79AEC9FD4B69AE988F68A752470D3D4BA46F41B9FD41A974A5311BAA191AFBA370F0B051F035297FA76A2133B98FF471BDA4BFBFDA275B4FA1CF8377EEB2B2141F9C998ACE27C60F11E221D6732A5D538FEDF9A01D776E1877BCF70A8C953630B2C66752A66DF087C075794F5A2C0023C964CD73476EA2556F091F6C191B30B74E2523F668F32CE10AFB3D51CE053D4D41E62214B60171093AB915DBBA497F09B3C279127E1D25C7AA6A7048BBEA41A23F4F827BD108F")[..]).unwrap(); + + assert_eq!(ocsp_resp.response_status, OcspResponseStatus::Successful); + assert!(ocsp_resp.response_bytes.is_some()); + let response_bytes = ocsp_resp.response_bytes.as_ref().unwrap(); + assert_eq!(response_bytes.response_type, OCSP_BASIC); + + pub const PKIXALG_SHA256_WITH_RSA_ENCRYPTION: ObjectIdentifier = + ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.11"); + pub const PKIXALG_SHA1: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.14.3.2.26"); + + let bor = BasicOcspResponse::from_der(response_bytes.response.as_bytes()).unwrap(); + assert_eq!( + bor.signature_algorithm.oid, + PKIXALG_SHA256_WITH_RSA_ENCRYPTION + ); + assert!(bor.signature_algorithm.parameters.is_some()); + assert_eq!( + bor.signature_algorithm + .parameters + .to_vec() + .unwrap() + .as_slice(), + Null.to_vec().unwrap().as_slice() + ); + + assert_eq!(bor.tbs_response_data.version, V1); + + match bor.tbs_response_data.responder_id { + ResponderId::ByKey(kh) => { + assert_eq!( + kh.as_bytes(), + &hex!("246E2B2DD06A925151256901AA9A47A689E74020") + ); + } + _ => { + panic!("Expected ByKey and got something else") + } + } + + assert_eq!( + bor.tbs_response_data + .produced_at + .to_unix_duration() + .as_secs(), + 1643775145 + ); + assert_eq!(bor.tbs_response_data.responses.len(), 1); + let sr = &bor.tbs_response_data.responses[0]; + assert_eq!(sr.cert_id.hash_algorithm.oid, PKIXALG_SHA1); + assert!(sr.cert_id.hash_algorithm.parameters.is_some()); + assert_eq!( + sr.cert_id + .hash_algorithm + .parameters + .to_vec() + .unwrap() + .as_slice(), + Null.to_vec().unwrap().as_slice() + ); + assert_eq!( + sr.cert_id.issuer_name_hash.as_bytes(), + &hex!("A87E303106E4E88565CFE952598FA6DA7C00532F") + ); + assert_eq!( + sr.cert_id.issuer_key_hash.as_bytes(), + &hex!("246E2B2DD06A925151256901AA9A47A689E74020") + ); + assert_eq!( + sr.cert_id.serial_number.as_bytes(), + &hex!("0E4239AB85E2E6A27C52C6DE9B9078D9") + ); + + match sr.cert_status { + CertStatus::Good(g) => { + assert_eq!( + g.to_vec().unwrap().as_slice(), + Null.to_vec().unwrap().as_slice() + ); + } + _ => { + panic!("Expected Good and got something other") + } + } + + assert_eq!(sr.this_update.to_unix_duration().as_secs(), 1643774221); + assert!(sr.next_update.is_some()); + assert_eq!( + sr.next_update.unwrap().to_unix_duration().as_secs(), + 1644376321 + ); + + let reenc = ocsp_resp.to_vec().unwrap(); + assert_eq!(reenc, &hex!("308201D30A0100A08201CC308201C806092B0601050507300101048201B9308201B530819EA2160414246E2B2DD06A925151256901AA9A47A689E74020180F32303232303230323034313232355A307330713049300906052B0E03021A05000414A87E303106E4E88565CFE952598FA6DA7C00532F0414246E2B2DD06A925151256901AA9A47A689E7402002100E4239AB85E2E6A27C52C6DE9B9078D98000180F32303232303230323033353730315AA011180F32303232303230393033313230315A300D06092A864886F70D01010B0500038201010089DC0913BD91DB172C314AE8F78E6574950353618FFBBF2F12B1F134F21EC20063E66C60AC463BDB926A9D5B699EB39689032659D43C441863BAC9D8B7CC84137B558503D2631348EDA79AEC9FD4B69AE988F68A752470D3D4BA46F41B9FD41A974A5311BAA191AFBA370F0B051F035297FA76A2133B98FF471BDA4BFBFDA275B4FA1CF8377EEB2B2141F9C998ACE27C60F11E221D6732A5D538FEDF9A01D776E1877BCF70A8C953630B2C66752A66DF087C075794F5A2C0023C964CD73476EA2556F091F6C191B30B74E2523F668F32CE10AFB3D51CE053D4D41E62214B60171093AB915DBBA497F09B3C279127E1D25C7AA6A7048BBEA41A23F4F827BD108F")[..]) +} + +#[test] +fn decode_ocsp_req_delegated() { + // request generated using openssl via this command: + // openssl ocsp -noverify -no_nonce -respout ~/Desktop/ocspdod.resp -reqout ~/Desktop/ocspdod.req + // -issuer ~/Desktop/email_ca_59.der -cert ~/Desktop/ee.der -url http://ocsp.disa.mil + // -header "HOST" "ocsp.disa.mil" -text + + pub const PKIXALG_SHA1: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.14.3.2.26"); + + let ocsp_req = + OcspRequest::from_der(&hex!("304530433041303F303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017467")[..]).unwrap(); + assert_eq!(ocsp_req.tbs_request.version, V1); + //assert!(ocsp_req.tbs_request.requestor_name.is_none()); + assert_eq!(ocsp_req.tbs_request.request_list.len(), 1); + let req = &ocsp_req.tbs_request.request_list[0]; + assert_eq!(req.req_cert.hash_algorithm.oid, PKIXALG_SHA1); + assert!(req.req_cert.hash_algorithm.parameters.is_some()); + assert_eq!( + req.req_cert + .hash_algorithm + .parameters + .to_vec() + .unwrap() + .as_slice(), + Null.to_vec().unwrap().as_slice() + ); + assert_eq!( + req.req_cert.issuer_name_hash.as_bytes(), + &hex!("0F0D5890F551D42ACF5431B7F42A321F7B74A473") + ); + assert_eq!( + req.req_cert.issuer_key_hash.as_bytes(), + &hex!("771441A65D9526D01DFF953B628CEAB7B55D3B92") + ); + assert_eq!(req.req_cert.serial_number.as_bytes(), &hex!("01017467")); + + let reenc = ocsp_req.to_vec().unwrap(); + assert_eq!(reenc, &hex!("304530433041303F303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017467")[..]) +} + +#[test] +fn decode_ocsp_resp_delegated() { + // response generated using openssl via this command: + // openssl ocsp -noverify -no_nonce -respout ~/Desktop/ocspdod.resp -reqout ~/Desktop/ocspdod.req + // -issuer ~/Desktop/email_ca_59.der -cert ~/Desktop/ee.der -url http://ocsp.disa.mil + // -header "HOST" "ocsp.disa.mil" -text + + // 308201D30A0100A08201CC308201C806092B0601050507300101048201B9308201B530819EA2160414246E2B2DD06A925151256901AA9A47A689E74020180F32303232303230323034313232355A307330713049300906052B0E03021A05000414A87E303106E4E88565CFE952598FA6DA7C00532F0414246E2B2DD06A925151256901AA9A47A689E7402002100E4239AB85E2E6A27C52C6DE9B9078D98000180F32303232303230323033353730315AA011180F32303232303230393033313230315A300D06092A864886F70D01010B0500038201010089DC0913BD91DB172C314AE8F78E6574950353618FFBBF2F12B1F134F21EC20063E66C60AC463BDB926A9D5B699EB39689032659D43C441863BAC9D8B7CC84137B558503D2631348EDA79AEC9FD4B69AE988F68A752470D3D4BA46F41B9FD41A974A5311BAA191AFBA370F0B051F035297FA76A2133B98FF471BDA4BFBFDA275B4FA1CF8377EEB2B2141F9C998ACE27C60F11E221D6732A5D538FEDF9A01D776E1877BCF70A8C953630B2C66752A66DF087C075794F5A2C0023C964CD73476EA2556F091F6C191B30B74E2523F668F32CE10AFB3D51CE053D4D41E62214B60171093AB915DBBA497F09B3C279127E1D25C7AA6A7048BBEA41A23F4F827BD108F + let ocsp_resp = + OcspResponse::from_der(&hex!("30820FA10A0100A0820F9A30820F9606092B060105050730010104820F8730820F83308209F1A2160414ADB0A9B2DDE9D444B4DF80F599598E84AC5EC687180F32303232303230333135303233365A308209C4307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017456A116180F32303231303532303138303635305AA0030A0104180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017457A116180F32303231303730373139353830355AA0030A0104180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017459A116180F32303231303532303138303634395AA0030A0104180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B9202040101745AA116180F32303231303132323136303832375AA0030A0104180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B9202040101745BA116180F32303231303731393138353734355AA0030A0101180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B9202040101745CA116180F32303231303132323136303832365AA0030A0104180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B9202040101745EA116180F32303231303432323132323332335AA0030A0104180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017460A116180F32303231303731393138353734335AA0030A0101180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017462A116180F32303231303932393136353734375AA0030A0103180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017464A116180F32303231303432323132323332325AA0030A0104180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017467A116180F32303231303932393136353734375AA0030A0103180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017477A116180F32303231303730313138313934365AA0030A0103180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017479A116180F32303232303130353138313532325AA0030A0103180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B9202040101747AA116180F32303231313130343131353932395AA0030A0101180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B9202040101747BA116180F32303231303730313138313934325AA0030A0103180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B9202040101747CA116180F32303232303130353138313532325AA0030A0103180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B9202040101747DA116180F32303231303231303136333032315AA0030A0104180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B9202040101747EA116180F32303231313130343131353932325AA0030A0101180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017480A116180F32303231303231303136333032305AA0030A0104180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017481A116180F32303231303132323133353031395AA0030A0104180F32303232303230333030333030305AA011180F32303232303231303031333030305A300D06092A864886F70D01010B050003820101008946FF8FF3009FC7265CB687D56960190379BEF6537FAC541A2306ED709B51AACD79B313331E297495AC4E26ABD94030CC407FDCE26CFC0B7A2BE1F226906182863FF1F140D628FA02B1D0BE1A1697E2F9C17AEF5FEC32AA4D120FAF0F58474AC2718964033076286DC358F5E96B08A5C83323CA4CA2B881D8FFA8E0EA3DB9A90863D378A3349EBF189030DA11891C6695950C5B93CBD440D998E67C0137655AC9DA40826B51211AD5985918336939131A4D1BF9E9A2A88CFB3C5059E3D1CE0D9B19F487EC018C60A0279E24270C7090006A4EC728E5C4A1F86829AFA236AF9979165DF1E7F0F5544217864F9C348ABF2B17C2FCD7DDE35838A99BC4A7256821A0820476308204723082046E30820356A0030201020203358762300D06092A864886F70D01010B0500305D310B300906035504061302555331183016060355040A130F552E532E20476F7665726E6D656E74310C300A060355040B1303446F44310C300A060355040B1303504B49311830160603550403130F444F4420454D41494C2043412D3539301E170D3232303132353030303035315A170D3232303331313030303035315A3064310B300906035504061302555331183016060355040A130F552E532E20476F7665726E6D656E74310C300A060355040B1303446F44310C300A060355040B1303504B49311F301D06035504031316444F44204E4950524E4554204F43535020313244203230820122300D06092A864886F70D01010105000382010F003082010A0282010100BF8A691DDB447562EFCDCB6C4DED76DDB200D1A188E01A3BA4EEEE1C42A7E5E78C0784C512F5CF64DD1A407A2EBC1F280761C1372351E03AED90C2DA0556066398E555EEE91C92988A62CDA1FD1F4E2E5F6EC6C022821C0D7C8B0E90E7CCF203CE8F102CBF4756D9B8CD09A2F16CF08F1E944311C8CD2120B98F6BCAEA1E60D1841A933815C8936BD20CC984FA1F5BF7AFFFFF2886DE53FDF3AE80E8394E09D441AE615693A78FE0051942B724147595DF049382897E26BBEA4E6902376C494F31141D1693005AA4E8AEBE4FEC342D10BFD90661935FB00D61A1FF7CB3B8FF45E473B3FFDD6D2C692FA8C0DE23373F1A6AD84109E7A9274008C5E94E28CE91850203010001A382012E3082012A301F0603551D23041830168014771441A65D9526D01DFF953B628CEAB7B55D3B92304606082B06010505070101043A3038303606082B06010505073002862A687474703A2F2F63726C2E646973612E6D696C2F7369676E2F444F44454D41494C43415F35392E63657230160603551D250101FF040C300A06082B06010505070309300E0603551D0F0101FF040403020780300F06092B060105050730010504020500301D0603551D0E04160414ADB0A9B2DDE9D444B4DF80F599598E84AC5EC68730670603551D200460305E300B0609608648016502010B24300B0609608648016502010B27300B0609608648016502010B2A300B0609608648016502010B3B300C060A6086480165030201030D300C060A60864801650302010311300C060A60864801650302010327300D06092A864886F70D01010B0500038201010047FE1DF6D439EF205C931F34B8C802B6E6D9C4EFEAFA7228FD07E56DFF17EEC18C250941EB46D5F416A02F2706A951A2A16435C589EE1059BB86EC38C7F07C2C6660C4B25C8918115FFD21A0D9798B860F878122B3781DCA004AFE869B4B88E0B8ABB4C3A255BC034B36ED82E4692AB765667E3036FC4BB2A53EF9B4654D5C8FDA62E1F6B9DFC7382FA9A3BEAC5EB35A105CB6FFD7B33D561DA77B886D17F58F9D6EDC722C9786E7C664598116F9ACB41282FB0C75EF6BA87BAE97249A42DF45FEC6AEB724C03D8EE5FF4FD7753AC0FE50CB6B746544D4A4DB977946D29183295B160538338FA2FB27F6BC84B5CBD658A431A8B87A9E20A57753BC8AB964B486")[..]).unwrap(); + + assert_eq!(ocsp_resp.response_status, OcspResponseStatus::Successful); + assert!(ocsp_resp.response_bytes.is_some()); + let response_bytes = ocsp_resp.response_bytes.as_ref().unwrap(); + assert_eq!(response_bytes.response_type, OCSP_BASIC); + + pub const PKIXALG_SHA256_WITH_RSA_ENCRYPTION: ObjectIdentifier = + ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.11"); + pub const PKIXALG_SHA1: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.14.3.2.26"); + + let bor = BasicOcspResponse::from_der(response_bytes.response.as_bytes()).unwrap(); + assert_eq!( + bor.signature_algorithm.oid, + PKIXALG_SHA256_WITH_RSA_ENCRYPTION + ); + assert!(bor.signature_algorithm.parameters.is_some()); + assert_eq!( + bor.signature_algorithm + .parameters + .to_vec() + .unwrap() + .as_slice(), + Null.to_vec().unwrap().as_slice() + ); + + assert_eq!(bor.tbs_response_data.version, V1); + + match bor.tbs_response_data.responder_id { + ResponderId::ByKey(kh) => { + assert_eq!( + kh.as_bytes(), + &hex!("ADB0A9B2DDE9D444B4DF80F599598E84AC5EC687") + ); + } + _ => { + panic!("Expected ByKey and got something else") + } + } + + assert_eq!( + bor.tbs_response_data + .produced_at + .to_unix_duration() + .as_secs(), + 1643900556 + ); + assert_eq!(bor.tbs_response_data.responses.len(), 20); + let sr = &bor.tbs_response_data.responses[10]; + + assert_eq!(sr.cert_id.hash_algorithm.oid, PKIXALG_SHA1); + assert!(sr.cert_id.hash_algorithm.parameters.is_some()); + assert_eq!( + sr.cert_id + .hash_algorithm + .parameters + .to_vec() + .unwrap() + .as_slice(), + Null.to_vec().unwrap().as_slice() + ); + assert_eq!( + sr.cert_id.issuer_name_hash.as_bytes(), + &hex!("0F0D5890F551D42ACF5431B7F42A321F7B74A473") + ); + assert_eq!( + sr.cert_id.issuer_key_hash.as_bytes(), + &hex!("771441A65D9526D01DFF953B628CEAB7B55D3B92") + ); + assert_eq!(sr.cert_id.serial_number.as_bytes(), &hex!("01017467")); + + match &sr.cert_status { + CertStatus::Revoked(ri) => { + assert!(ri.revocation_reason.is_some()); + assert_eq!(ri.revocation_reason.unwrap(), CrlReason::AffiliationChanged,); + assert_eq!(ri.revocation_time.to_unix_duration().as_secs(), 1632934667,); + } + _ => { + panic!("Expected Good and got something other") + } + } + + assert_eq!(sr.this_update.to_unix_duration().as_secs(), 1643848200); + assert!(sr.next_update.is_some()); + assert_eq!( + sr.next_update.unwrap().to_unix_duration().as_secs(), + 1644456600 + ); + + let reenc = ocsp_resp.to_vec().unwrap(); + assert_eq!(reenc, &hex!("30820FA10A0100A0820F9A30820F9606092B060105050730010104820F8730820F83308209F1A2160414ADB0A9B2DDE9D444B4DF80F599598E84AC5EC687180F32303232303230333135303233365A308209C4307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017456A116180F32303231303532303138303635305AA0030A0104180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017457A116180F32303231303730373139353830355AA0030A0104180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017459A116180F32303231303532303138303634395AA0030A0104180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B9202040101745AA116180F32303231303132323136303832375AA0030A0104180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B9202040101745BA116180F32303231303731393138353734355AA0030A0101180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B9202040101745CA116180F32303231303132323136303832365AA0030A0104180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B9202040101745EA116180F32303231303432323132323332335AA0030A0104180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017460A116180F32303231303731393138353734335AA0030A0101180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017462A116180F32303231303932393136353734375AA0030A0103180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017464A116180F32303231303432323132323332325AA0030A0104180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017467A116180F32303231303932393136353734375AA0030A0103180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017477A116180F32303231303730313138313934365AA0030A0103180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017479A116180F32303232303130353138313532325AA0030A0103180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B9202040101747AA116180F32303231313130343131353932395AA0030A0101180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B9202040101747BA116180F32303231303730313138313934325AA0030A0103180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B9202040101747CA116180F32303232303130353138313532325AA0030A0103180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B9202040101747DA116180F32303231303231303136333032315AA0030A0104180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B9202040101747EA116180F32303231313130343131353932325AA0030A0101180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017480A116180F32303231303231303136333032305AA0030A0104180F32303232303230333030333030305AA011180F32303232303231303031333030305A307B303D300906052B0E03021A050004140F0D5890F551D42ACF5431B7F42A321F7B74A4730414771441A65D9526D01DFF953B628CEAB7B55D3B92020401017481A116180F32303231303132323133353031395AA0030A0104180F32303232303230333030333030305AA011180F32303232303231303031333030305A300D06092A864886F70D01010B050003820101008946FF8FF3009FC7265CB687D56960190379BEF6537FAC541A2306ED709B51AACD79B313331E297495AC4E26ABD94030CC407FDCE26CFC0B7A2BE1F226906182863FF1F140D628FA02B1D0BE1A1697E2F9C17AEF5FEC32AA4D120FAF0F58474AC2718964033076286DC358F5E96B08A5C83323CA4CA2B881D8FFA8E0EA3DB9A90863D378A3349EBF189030DA11891C6695950C5B93CBD440D998E67C0137655AC9DA40826B51211AD5985918336939131A4D1BF9E9A2A88CFB3C5059E3D1CE0D9B19F487EC018C60A0279E24270C7090006A4EC728E5C4A1F86829AFA236AF9979165DF1E7F0F5544217864F9C348ABF2B17C2FCD7DDE35838A99BC4A7256821A0820476308204723082046E30820356A0030201020203358762300D06092A864886F70D01010B0500305D310B300906035504061302555331183016060355040A130F552E532E20476F7665726E6D656E74310C300A060355040B1303446F44310C300A060355040B1303504B49311830160603550403130F444F4420454D41494C2043412D3539301E170D3232303132353030303035315A170D3232303331313030303035315A3064310B300906035504061302555331183016060355040A130F552E532E20476F7665726E6D656E74310C300A060355040B1303446F44310C300A060355040B1303504B49311F301D06035504031316444F44204E4950524E4554204F43535020313244203230820122300D06092A864886F70D01010105000382010F003082010A0282010100BF8A691DDB447562EFCDCB6C4DED76DDB200D1A188E01A3BA4EEEE1C42A7E5E78C0784C512F5CF64DD1A407A2EBC1F280761C1372351E03AED90C2DA0556066398E555EEE91C92988A62CDA1FD1F4E2E5F6EC6C022821C0D7C8B0E90E7CCF203CE8F102CBF4756D9B8CD09A2F16CF08F1E944311C8CD2120B98F6BCAEA1E60D1841A933815C8936BD20CC984FA1F5BF7AFFFFF2886DE53FDF3AE80E8394E09D441AE615693A78FE0051942B724147595DF049382897E26BBEA4E6902376C494F31141D1693005AA4E8AEBE4FEC342D10BFD90661935FB00D61A1FF7CB3B8FF45E473B3FFDD6D2C692FA8C0DE23373F1A6AD84109E7A9274008C5E94E28CE91850203010001A382012E3082012A301F0603551D23041830168014771441A65D9526D01DFF953B628CEAB7B55D3B92304606082B06010505070101043A3038303606082B06010505073002862A687474703A2F2F63726C2E646973612E6D696C2F7369676E2F444F44454D41494C43415F35392E63657230160603551D250101FF040C300A06082B06010505070309300E0603551D0F0101FF040403020780300F06092B060105050730010504020500301D0603551D0E04160414ADB0A9B2DDE9D444B4DF80F599598E84AC5EC68730670603551D200460305E300B0609608648016502010B24300B0609608648016502010B27300B0609608648016502010B2A300B0609608648016502010B3B300C060A6086480165030201030D300C060A60864801650302010311300C060A60864801650302010327300D06092A864886F70D01010B0500038201010047FE1DF6D439EF205C931F34B8C802B6E6D9C4EFEAFA7228FD07E56DFF17EEC18C250941EB46D5F416A02F2706A951A2A16435C589EE1059BB86EC38C7F07C2C6660C4B25C8918115FFD21A0D9798B860F878122B3781DCA004AFE869B4B88E0B8ABB4C3A255BC034B36ED82E4692AB765667E3036FC4BB2A53EF9B4654D5C8FDA62E1F6B9DFC7382FA9A3BEAC5EB35A105CB6FFD7B33D561DA77B886D17F58F9D6EDC722C9786E7C664598116F9ACB41282FB0C75EF6BA87BAE97249A42DF45FEC6AEB724C03D8EE5FF4FD7753AC0FE50CB6B746544D4A4DB977946D29183295B160538338FA2FB27F6BC84B5CBD658A431A8B87A9E20A57753BC8AB964B486")[..]) +} diff --git a/pkcs7/Cargo.toml b/pkcs7/Cargo.toml index 68f31549c..3917c7cbe 100644 --- a/pkcs7/Cargo.toml +++ b/pkcs7/Cargo.toml @@ -17,6 +17,7 @@ rust-version = "1.57" [dependencies] der = { version = "=0.6.0-pre.1", features = ["oid"], path = "../der" } spki = { version = "=0.6.0-pre.0", path = "../spki" } +x509 = { version = "=0.0.1", path = "../x509" } [dev-dependencies] hex-literal = "0.3" diff --git a/pkcs7/src/cryptographic_message_syntax2004.rs b/pkcs7/src/cryptographic_message_syntax2004.rs new file mode 100644 index 000000000..c97e40811 --- /dev/null +++ b/pkcs7/src/cryptographic_message_syntax2004.rs @@ -0,0 +1,371 @@ +//! Selected structures from RFC5652 + +use core::cmp::Ordering; +use der::asn1::{BitString, OctetString, SetOf, SetOfVec, UIntBytes}; +use der::{Any, Choice, Decodable, Sequence, ValueOrd}; +use spki::{AlgorithmIdentifier, ObjectIdentifier}; +use x509::attr::AttributeTypeAndValue; +use x509::ext::pkix::SubjectKeyIdentifier; +use x509::name::Name; + +// Use 2004 suffix to distinguish from the enum in content_type.rs +/// ContentInfo ::= SEQUENCE { +/// contentType ContentType, +/// content \[0\] EXPLICIT ANY DEFINED BY contentType } +#[derive(Clone, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct ContentInfo2004<'a> { + pub content_type: ObjectIdentifier, + + #[asn1(context_specific = "0", tag_mode = "EXPLICIT")] + pub content: Any<'a>, +} + +/// SignedData ::= SEQUENCE { +/// version CMSVersion, +/// digestAlgorithms DigestAlgorithmIdentifiers, +/// encapContentInfo EncapsulatedContentInfo, +/// certificates \[0\] IMPLICIT CertificateSet OPTIONAL, +/// crls \[1\] IMPLICIT RevocationInfoChoices OPTIONAL, +/// signerInfos SignerInfos } +#[derive(Clone, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct SignedData<'a> { + pub version: u8, + pub digest_algorithms: DigestAlgorithmIdentifiers<'a>, + pub encap_content_info: EncapsulatedContentInfo<'a>, + + // Using Any as a means of deferring most of the decoding of the certificates (will still need + // to call to_vec on the resulting Any to restore tag and length values). + /// certificates \[0\] IMPLICIT CertificateSet OPTIONAL, + #[asn1(context_specific = "0", tag_mode = "IMPLICIT", optional = "true")] + pub certificates: Option>>, + + #[asn1(context_specific = "1", tag_mode = "IMPLICIT", optional = "true")] + pub crls: Option>>, + + pub signer_infos: SetOfVec>, +} + +/// DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier +pub type DigestAlgorithmIdentifiers<'a> = SetOfVec; + +/// EncapsulatedContentInfo ::= SEQUENCE { +/// eContentType ContentType, +/// eContent \[0\] EXPLICIT OCTET STRING OPTIONAL } +#[derive(Clone, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct EncapsulatedContentInfo<'a> { + pub econtent_type: ObjectIdentifier, + + #[asn1(context_specific = "0", tag_mode = "EXPLICIT", optional = "true")] + pub econtent: Option>, +} + +// ContentType ::= OBJECT IDENTIFIER + +/// SignerInfo ::= SEQUENCE { +/// version CMSVersion, +/// sid SignerIdentifier, +/// digestAlgorithm DigestAlgorithmIdentifier, +/// signedAttrs \[0\] IMPLICIT SignedAttributes OPTIONAL, +/// signatureAlgorithm SignatureAlgorithmIdentifier, +/// signature SignatureValue, +/// unsignedAttrs \[1\] IMPLICIT UnsignedAttributes OPTIONAL } +#[derive(Clone, Eq, PartialEq, PartialOrd, Sequence)] +#[allow(missing_docs)] +pub struct SignerInfo<'a> { + pub version: u8, + pub sid: SignerIdentifier<'a>, + pub digest_algorithm: AlgorithmIdentifier<'a>, + pub signed_attrs: SignedAttributes<'a>, + pub signature_algorithm: AlgorithmIdentifier<'a>, + pub signature: BitString<'a>, + pub unsigned_attrs: UnsignedAttributes<'a>, +} +impl ValueOrd for SignerInfo<'_> { + fn value_cmp(&self, _other: &Self) -> der::Result { + todo!() + } +} + +/// SignerIdentifier ::= CHOICE { +/// issuerAndSerialNumber IssuerAndSerialNumber, +/// subjectKeyIdentifier \[0\] SubjectKeyIdentifier } +#[derive(Clone, Eq, PartialEq, PartialOrd, Choice)] +#[allow(missing_docs)] +pub enum SignerIdentifier<'a> { + IssuerAndSerialNumber(IssuerAndSerialNumber<'a>), + + #[asn1(context_specific = "0", tag_mode = "EXPLICIT")] + SubjectKeyIdentifier(SubjectKeyIdentifier<'a>), +} + +/// SignedAttributes ::= SET SIZE (1..MAX) OF Attribute +pub type SignedAttributes<'a> = SetOf, 10>; + +/// UnsignedAttributes ::= SET SIZE (1..MAX) OF Attribute +pub type UnsignedAttributes<'a> = SetOf, 10>; + +/* + Attribute ::= SEQUENCE { + attrType OBJECT IDENTIFIER, + attrValues SET OF AttributeValue } + + AttributeValue ::= ANY + + SignatureValue ::= OCTET STRING + + EnvelopedData ::= SEQUENCE { + version CMSVersion, + originatorInfo \[0\] IMPLICIT OriginatorInfo OPTIONAL, + recipientInfos RecipientInfos, + encryptedContentInfo EncryptedContentInfo, + unprotectedAttrs \[1\] IMPLICIT UnprotectedAttributes OPTIONAL } + + OriginatorInfo ::= SEQUENCE { + certs \[0\] IMPLICIT CertificateSet OPTIONAL, + crls \[1\] IMPLICIT RevocationInfoChoices OPTIONAL } + + RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo + + EncryptedContentInfo ::= SEQUENCE { + contentType ContentType, + contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, + encryptedContent \[0\] IMPLICIT EncryptedContent OPTIONAL } + + EncryptedContent ::= OCTET STRING + + UnprotectedAttributes ::= SET SIZE (1..MAX) OF Attribute + + RecipientInfo ::= CHOICE { + ktri KeyTransRecipientInfo, + kari \[1\] KeyAgreeRecipientInfo, + kekri \[2\] KEKRecipientInfo, + pwri \[3\] PasswordRecipientInfo, + ori \[4\] OtherRecipientInfo } + + EncryptedKey ::= OCTET STRING + + KeyTransRecipientInfo ::= SEQUENCE { + version CMSVersion, -- always set to 0 or 2 + rid RecipientIdentifier, + keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + encryptedKey EncryptedKey } + + RecipientIdentifier ::= CHOICE { + issuerAndSerialNumber IssuerAndSerialNumber, + subjectKeyIdentifier \[0\] SubjectKeyIdentifier } + + KeyAgreeRecipientInfo ::= SEQUENCE { + version CMSVersion, -- always set to 3 + originator \[0\] EXPLICIT OriginatorIdentifierOrKey, + ukm \[1\] EXPLICIT UserKeyingMaterial OPTIONAL, + keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + recipientEncryptedKeys RecipientEncryptedKeys } + + OriginatorIdentifierOrKey ::= CHOICE { + issuerAndSerialNumber IssuerAndSerialNumber, + subjectKeyIdentifier \[0\] SubjectKeyIdentifier, + originatorKey \[1\] OriginatorPublicKey } + + OriginatorPublicKey ::= SEQUENCE { + algorithm AlgorithmIdentifier, + publicKey BIT STRING } + + RecipientEncryptedKeys ::= SEQUENCE OF RecipientEncryptedKey + + RecipientEncryptedKey ::= SEQUENCE { + rid KeyAgreeRecipientIdentifier, + encryptedKey EncryptedKey } + + KeyAgreeRecipientIdentifier ::= CHOICE { + issuerAndSerialNumber IssuerAndSerialNumber, + rKeyId \[0\] IMPLICIT RecipientKeyIdentifier } + + RecipientKeyIdentifier ::= SEQUENCE { + subjectKeyIdentifier SubjectKeyIdentifier, + date GeneralizedTime OPTIONAL, + other OtherKeyAttribute OPTIONAL } + + SubjectKeyIdentifier ::= OCTET STRING + + KEKRecipientInfo ::= SEQUENCE { + version CMSVersion, -- always set to 4 + kekid KEKIdentifier, + keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + encryptedKey EncryptedKey } + + KEKIdentifier ::= SEQUENCE { + keyIdentifier OCTET STRING, + date GeneralizedTime OPTIONAL, + other OtherKeyAttribute OPTIONAL } + + PasswordRecipientInfo ::= SEQUENCE { + version CMSVersion, -- always set to 0 + keyDerivationAlgorithm \[0\] KeyDerivationAlgorithmIdentifier + OPTIONAL, + keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + encryptedKey EncryptedKey } + + OtherRecipientInfo ::= SEQUENCE { + oriType OBJECT IDENTIFIER, + oriValue ANY DEFINED BY oriType } + + DigestedData ::= SEQUENCE { + version CMSVersion, + digestAlgorithm DigestAlgorithmIdentifier, + encapContentInfo EncapsulatedContentInfo, + digest Digest } + + Digest ::= OCTET STRING + + EncryptedData ::= SEQUENCE { + version CMSVersion, + encryptedContentInfo EncryptedContentInfo, + unprotectedAttrs \[1\] IMPLICIT UnprotectedAttributes OPTIONAL } + + AuthenticatedData ::= SEQUENCE { + version CMSVersion, + originatorInfo \[0\] IMPLICIT OriginatorInfo OPTIONAL, + recipientInfos RecipientInfos, + macAlgorithm MessageAuthenticationCodeAlgorithm, + digestAlgorithm \[1\] DigestAlgorithmIdentifier OPTIONAL, + encapContentInfo EncapsulatedContentInfo, + authAttrs \[2\] IMPLICIT AuthAttributes OPTIONAL, + mac MessageAuthenticationCode, + unauthAttrs \[3\] IMPLICIT UnauthAttributes OPTIONAL } + + AuthAttributes ::= SET SIZE (1..MAX) OF Attribute + + UnauthAttributes ::= SET SIZE (1..MAX) OF Attribute + + MessageAuthenticationCode ::= OCTET STRING + + DigestAlgorithmIdentifier ::= AlgorithmIdentifier + + SignatureAlgorithmIdentifier ::= AlgorithmIdentifier + + KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + + ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + + MessageAuthenticationCodeAlgorithm ::= AlgorithmIdentifier + + KeyDerivationAlgorithmIdentifier ::= AlgorithmIdentifier + + RevocationInfoChoices ::= SET OF RevocationInfoChoice + + RevocationInfoChoice ::= CHOICE { + crl CertificateList, + other \[1\] IMPLICIT OtherRevocationInfoFormat } + + OtherRevocationInfoFormat ::= SEQUENCE { + otherRevInfoFormat OBJECT IDENTIFIER, + otherRevInfo ANY DEFINED BY otherRevInfoFormat } + + CertificateChoices ::= CHOICE { + certificate Certificate, + extendedCertificate \[0\] IMPLICIT ExtendedCertificate, -- Obsolete + v1AttrCert \[1\] IMPLICIT AttributeCertificateV1, -- Obsolete + v2AttrCert \[2\] IMPLICIT AttributeCertificateV2, + other \[3\] IMPLICIT OtherCertificateFormat } + + AttributeCertificateV2 ::= AttributeCertificate + + OtherCertificateFormat ::= SEQUENCE { + otherCertFormat OBJECT IDENTIFIER, + otherCert ANY DEFINED BY otherCertFormat } + + CertificateSet ::= SET OF CertificateChoices +*/ + +/// IssuerAndSerialNumber ::= SEQUENCE { +/// issuer Name, +/// serialNumber CertificateSerialNumber } +#[derive(Clone, Eq, PartialEq, PartialOrd, Sequence)] +pub struct IssuerAndSerialNumber<'a> { + /// issuer Name, + pub issuer: Name<'a>, + /// serialNumber CertificateSerialNumber } + pub serial_number: UIntBytes<'a>, +} + +/* + CMSVersion ::= INTEGER { v0(0), v1(1), v2(2), v3(3), v4(4), v5(5) } + + UserKeyingMaterial ::= OCTET STRING + + OtherKeyAttribute ::= SEQUENCE { + keyAttrId OBJECT IDENTIFIER, + keyAttr ANY DEFINED BY keyAttrId OPTIONAL } + + -- Content Type Object Identifiers + + id-ct-contentInfo OBJECT IDENTIFIER ::= { iso(1) member-body(2) + us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-ct(1) 6 } + + id-data OBJECT IDENTIFIER ::= { iso(1) member-body(2) + us(840) rsadsi(113549) pkcs(1) pkcs7(7) 1 } + + id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2) + us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 } + + id-envelopedData OBJECT IDENTIFIER ::= { iso(1) member-body(2) + us(840) rsadsi(113549) pkcs(1) pkcs7(7) 3 } + + id-digestedData OBJECT IDENTIFIER ::= { iso(1) member-body(2) + us(840) rsadsi(113549) pkcs(1) pkcs7(7) 5 } + + id-encryptedData OBJECT IDENTIFIER ::= { iso(1) member-body(2) + us(840) rsadsi(113549) pkcs(1) pkcs7(7) 6 } + + id-ct-authData OBJECT IDENTIFIER ::= { iso(1) member-body(2) + us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-ct(1) 2 } + + -- The CMS Attributes + + MessageDigest ::= OCTET STRING + + SigningTime ::= Time + + Time ::= CHOICE { + utcTime UTCTime, + generalTime GeneralizedTime } + + Countersignature ::= SignerInfo + + -- Attribute Object Identifiers + + id-contentType OBJECT IDENTIFIER ::= { iso(1) member-body(2) + us(840) rsadsi(113549) pkcs(1) pkcs-9(9) 3 } + + id-messageDigest OBJECT IDENTIFIER ::= { iso(1) member-body(2) + us(840) rsadsi(113549) pkcs(1) pkcs-9(9) 4 } + + id-signingTime OBJECT IDENTIFIER ::= { iso(1) member-body(2) + us(840) rsadsi(113549) pkcs(1) pkcs-9(9) 5 } + + id-countersignature OBJECT IDENTIFIER ::= { iso(1) member-body(2) + us(840) rsadsi(113549) pkcs(1) pkcs-9(9) 6 } + + -- Obsolete Extended Certificate syntax from PKCS #6 + + ExtendedCertificateOrCertificate ::= CHOICE { + certificate Certificate, + extendedCertificate \[0\] IMPLICIT ExtendedCertificate } + + ExtendedCertificate ::= SEQUENCE { + extendedCertificateInfo ExtendedCertificateInfo, + signatureAlgorithm SignatureAlgorithmIdentifier, + signature Signature } + + ExtendedCertificateInfo ::= SEQUENCE { + version CMSVersion, + certificate Certificate, + attributes UnauthAttributes } + + Signature ::= BIT STRING + + END -- of CryptographicMessageSyntax2004 +*/ diff --git a/pkcs7/src/lib.rs b/pkcs7/src/lib.rs index 6a080bbf6..e066700fd 100644 --- a/pkcs7/src/lib.rs +++ b/pkcs7/src/lib.rs @@ -15,12 +15,15 @@ mod content_type; pub use crate::{content_info::ContentInfo, content_type::ContentType}; +pub mod cryptographic_message_syntax2004; pub mod data_content; pub mod encrypted_data_content; pub mod enveloped_data_content; use der::asn1::ObjectIdentifier; +extern crate alloc; + /// `pkcs-7` Object Identifier (OID). pub const PKCS_7_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.7"); diff --git a/pkcs7/tests/cryptographic_message_syntax2004.rs b/pkcs7/tests/cryptographic_message_syntax2004.rs new file mode 100644 index 000000000..e5b02cb6f --- /dev/null +++ b/pkcs7/tests/cryptographic_message_syntax2004.rs @@ -0,0 +1,23 @@ +use der::{Decodable, Encodable}; +use pkcs7::cryptographic_message_syntax2004::*; + +#[test] +fn signed_data_parse_test1() { + let der_encoded_sd = include_bytes!("examples/caCertsIssuedTofbcag4.p7c"); + let ci = ContentInfo2004::from_der(der_encoded_sd).unwrap(); + let content = ci.content.to_vec().unwrap(); + let _sd = SignedData::from_der(content.as_slice()).unwrap(); + //assert_eq!(1, sd.certificates.unwrap().len()); + + let der_encoded_sd = include_bytes!("examples/DODJITCINTEROPERABILITYROOTCA2_IT.p7c"); + let ci = ContentInfo2004::from_der(der_encoded_sd).unwrap(); + let content = ci.content.to_vec().unwrap(); + let sd = SignedData::from_der(content.as_slice()).unwrap(); + assert_eq!(1, sd.certificates.unwrap().len()); + + let der_encoded_sd = include_bytes!("examples/DODROOTCA3_IB.p7c"); + let ci = ContentInfo2004::from_der(der_encoded_sd).unwrap(); + let content = ci.content.to_vec().unwrap(); + let sd = SignedData::from_der(content.as_slice()).unwrap(); + assert_eq!(26, sd.certificates.unwrap().len()); +} diff --git a/pkcs7/tests/examples/DODJITCINTEROPERABILITYROOTCA2_IT.p7c b/pkcs7/tests/examples/DODJITCINTEROPERABILITYROOTCA2_IT.p7c new file mode 100644 index 000000000..a37ec8b7c Binary files /dev/null and b/pkcs7/tests/examples/DODJITCINTEROPERABILITYROOTCA2_IT.p7c differ diff --git a/pkcs7/tests/examples/DODROOTCA3_IB.p7c b/pkcs7/tests/examples/DODROOTCA3_IB.p7c new file mode 100644 index 000000000..d02b679f5 Binary files /dev/null and b/pkcs7/tests/examples/DODROOTCA3_IB.p7c differ diff --git a/pkcs7/tests/examples/caCertsIssuedTofbcag4.p7c b/pkcs7/tests/examples/caCertsIssuedTofbcag4.p7c new file mode 100644 index 000000000..cc8de7958 Binary files /dev/null and b/pkcs7/tests/examples/caCertsIssuedTofbcag4.p7c differ diff --git a/spki/src/algorithm.rs b/spki/src/algorithm.rs index 8997c4a60..678199f9a 100644 --- a/spki/src/algorithm.rs +++ b/spki/src/algorithm.rs @@ -14,7 +14,7 @@ use der::{Decodable, DecodeValue, Decoder, DerOrd, Encodable, Header, Sequence, /// ``` /// /// [RFC 5280 Section 4.1.1.2]: https://tools.ietf.org/html/rfc5280#section-4.1.1.2 -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd)] pub struct AlgorithmIdentifier<'a> { /// Algorithm OID, i.e. the `algorithm` field in the `AlgorithmIdentifier` /// ASN.1 schema. diff --git a/x509/Cargo.toml b/x509/Cargo.toml index a18ec4746..20802651d 100644 --- a/x509/Cargo.toml +++ b/x509/Cargo.toml @@ -12,7 +12,7 @@ categories = ["cryptography", "data-structures", "encoding", "no-std"] keywords = ["crypto"] readme = "README.md" edition = "2021" -rust-version = "1.56" +rust-version = "1.57" [dependencies] der = { version = "=0.6.0-pre.1", features = ["derive", "alloc", "flagset"], path = "../der" } diff --git a/x509/src/crl.rs b/x509/src/crl.rs new file mode 100644 index 000000000..b6655dbb9 --- /dev/null +++ b/x509/src/crl.rs @@ -0,0 +1,78 @@ +//! CertificateList [`CertificateList`] and TBSCertList [`TbsCertList`] as defined in RFC 5280 + +use crate::ext::Extensions; +use crate::name::Name; +use crate::time::Time; +use crate::Version; +use der::asn1::{BitString, UIntBytes}; +use der::Sequence; +use spki::AlgorithmIdentifier; + +///```text +/// CertificateList ::= SEQUENCE { +/// tbsCertList TBSCertList, +/// signatureAlgorithm AlgorithmIdentifier, +/// signatureValue BIT STRING } +/// ``` +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct CertificateList<'a> { + pub tbs_cert_list: TbsCertList<'a>, + pub signature_algorithm: AlgorithmIdentifier<'a>, + pub signature: BitString<'a>, +} + +/// Structure fabricated from the revokedCertificates definition in TBSCertList +/// +///```text +/// RevokedCert ::= SEQUENCE { +/// userCertificate CertificateSerialNumber, +/// revocationDate Time, +/// crlEntryExtensions Extensions OPTIONAL +/// } +/// ``` +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct RevokedCert<'a> { + pub serial_number: UIntBytes<'a>, + pub revocation_date: Time, + pub crl_entry_extensions: Option>, +} + +/// Structure fabricated from the revokedCertificates definition in TBSCertList +/// ```text +/// RevokedCerts ::= SEQUENCE OF RevokedCert; +/// ``` +pub type RevokedCerts<'a> = alloc::vec::Vec>; + +///```text +/// TBSCertList ::= SEQUENCE { +/// version Version OPTIONAL, +/// -- if present, MUST be v2 +/// signature AlgorithmIdentifier, +/// issuer Name, +/// thisUpdate Time, +/// nextUpdate Time OPTIONAL, +/// revokedCertificates SEQUENCE OF SEQUENCE { +/// userCertificate CertificateSerialNumber, +/// revocationDate Time, +/// crlEntryExtensions Extensions OPTIONAL +/// -- if present, version MUST be v2 +/// } OPTIONAL, +/// crlExtensions [0] EXPLICIT Extensions OPTIONAL +/// -- if present, version MUST be v2 +/// } +/// ``` +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[allow(missing_docs)] +pub struct TbsCertList<'a> { + pub version: Version, + pub signature: AlgorithmIdentifier<'a>, + pub issuer: Name<'a>, + pub this_update: Time, + pub next_update: Option