From b362ce6cee3540d64c6cf165b75961e99bb19744 Mon Sep 17 00:00:00 2001 From: Bernd Krietenstein Date: Fri, 13 Jan 2023 15:11:36 +0100 Subject: [PATCH 01/19] Prepared openssl-sys for pkcs7 and x509 extensions. --- openssl-sys/build/cfgs.rs | 3 + openssl-sys/src/handwritten/asn1.rs | 49 ++++- openssl-sys/src/handwritten/mod.rs | 2 + openssl-sys/src/handwritten/pkcs7.rs | 245 ++++++++++++++++++++++- openssl-sys/src/handwritten/types.rs | 16 +- openssl-sys/src/handwritten/x509.rs | 36 +++- openssl-sys/src/handwritten/x509_attr.rs | 60 ++++++ 7 files changed, 396 insertions(+), 15 deletions(-) create mode 100644 openssl-sys/src/handwritten/x509_attr.rs diff --git a/openssl-sys/build/cfgs.rs b/openssl-sys/build/cfgs.rs index d925d90ad7..960515f00f 100644 --- a/openssl-sys/build/cfgs.rs +++ b/openssl-sys/build/cfgs.rs @@ -31,6 +31,9 @@ pub fn get(openssl_version: Option, libressl_version: Option) -> Vec<& if libressl_version >= 0x2_09_01_00_0 { cfgs.push("libressl291"); } + if libressl_version >= 0x3_01_00_00_0 { + cfgs.push("libressl310"); + } if libressl_version >= 0x3_02_01_00_0 { cfgs.push("libressl321"); } diff --git a/openssl-sys/src/handwritten/asn1.rs b/openssl-sys/src/handwritten/asn1.rs index 844f9102a9..e866b1ea90 100644 --- a/openssl-sys/src/handwritten/asn1.rs +++ b/openssl-sys/src/handwritten/asn1.rs @@ -10,23 +10,60 @@ pub struct ASN1_ENCODING { extern "C" { pub fn ASN1_OBJECT_free(x: *mut ASN1_OBJECT); + pub fn OBJ_cmp(a: *const ASN1_OBJECT, b: *const ASN1_OBJECT) -> c_int; } +pub enum ASN1_OBJECT {} + stack!(stack_st_ASN1_OBJECT); +#[repr(C)] +pub struct ASN1_TYPE { + pub type_: c_int, + pub value: ASN1_TYPE_value, +} +#[repr(C)] +pub union ASN1_TYPE_value { + pub ptr: *mut c_char, + pub boolean: ASN1_BOOLEAN, + pub asn1_string: *mut ASN1_STRING, + pub object: *mut ASN1_OBJECT, + pub integer: *mut ASN1_INTEGER, + pub enumerated: *mut ASN1_ENUMERATED, + pub bit_string: *mut ASN1_BIT_STRING, + pub octet_string: *mut ASN1_OCTET_STRING, + pub printablestring: *mut ASN1_PRINTABLESTRING, + pub t61string: *mut ASN1_T61STRING, + pub ia5string: *mut ASN1_IA5STRING, + pub generalstring: *mut ASN1_GENERALSTRING, + pub bmpstring: *mut ASN1_BMPSTRING, + pub universalstring: *mut ASN1_UNIVERSALSTRING, + pub utctime: *mut ASN1_UTCTIME, + pub generalizedtime: *mut ASN1_GENERALIZEDTIME, + pub visiblestring: *mut ASN1_VISIBLESTRING, + pub utf8string: *mut ASN1_UTF8STRING, + /* + * set and sequence are left complete and still contain the set or + * sequence bytes + */ + pub set: *mut ASN1_STRING, + pub sequence: *mut ASN1_STRING, + pub asn1_value: *mut ASN1_VALUE, +} + extern "C" { pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING; #[cfg(any(ossl110, libressl273))] pub fn ASN1_STRING_get0_data(x: *const ASN1_STRING) -> *const c_uchar; #[cfg(any(all(ossl101, not(ossl110)), libressl))] pub fn ASN1_STRING_data(x: *mut ASN1_STRING) -> *mut c_uchar; - - pub fn ASN1_BIT_STRING_free(x: *mut ASN1_BIT_STRING); - + pub fn ASN1_STRING_new() -> *mut ASN1_STRING; pub fn ASN1_STRING_free(x: *mut ASN1_STRING); pub fn ASN1_STRING_length(x: *const ASN1_STRING) -> c_int; + pub fn ASN1_STRING_set(x: *mut ASN1_STRING, data: *const c_void, len_in: c_int) -> c_int; - pub fn ASN1_STRING_set(x: *mut ASN1_STRING, data: *const c_void, len: c_int) -> c_int; + pub fn ASN1_BIT_STRING_free(x: *mut ASN1_BIT_STRING); + pub fn ASN1_OCTET_STRING_free(x: *mut ASN1_OCTET_STRING); pub fn ASN1_GENERALIZEDTIME_free(tm: *mut ASN1_GENERALIZEDTIME); pub fn ASN1_GENERALIZEDTIME_print(b: *mut BIO, tm: *const ASN1_GENERALIZEDTIME) -> c_int; @@ -51,10 +88,14 @@ extern "C" { pub fn ASN1_TIME_set_string(s: *mut ASN1_TIME, str: *const c_char) -> c_int; #[cfg(ossl111)] pub fn ASN1_TIME_set_string_X509(s: *mut ASN1_TIME, str: *const c_char) -> c_int; + + pub fn ASN1_TYPE_free(x: *mut ASN1_TYPE); } const_ptr_api! { extern "C" { pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_uchar, s: #[const_ptr_if(any(ossl110, libressl280))] ASN1_STRING) -> c_int; + pub fn ASN1_STRING_type(x: #[const_ptr_if(any(ossl110, libressl280))] ASN1_STRING) -> c_int; + pub fn ASN1_generate_v3(str: #[const_ptr_if(any(ossl110, libressl280))] c_char, cnf: *mut X509V3_CTX) -> *mut ASN1_TYPE; } } diff --git a/openssl-sys/src/handwritten/mod.rs b/openssl-sys/src/handwritten/mod.rs index 28aa4aecd0..fea7549898 100644 --- a/openssl-sys/src/handwritten/mod.rs +++ b/openssl-sys/src/handwritten/mod.rs @@ -28,6 +28,7 @@ pub use self::stack::*; pub use self::tls1::*; pub use self::types::*; pub use self::x509::*; +pub use self::x509_attr::*; pub use self::x509_vfy::*; pub use self::x509v3::*; @@ -61,5 +62,6 @@ mod stack; mod tls1; mod types; mod x509; +mod x509_attr; mod x509_vfy; mod x509v3; diff --git a/openssl-sys/src/handwritten/pkcs7.rs b/openssl-sys/src/handwritten/pkcs7.rs index fc0239e7b8..2f76cab9c2 100644 --- a/openssl-sys/src/handwritten/pkcs7.rs +++ b/openssl-sys/src/handwritten/pkcs7.rs @@ -1,12 +1,195 @@ use libc::*; use *; -pub enum PKCS7_SIGNED {} -pub enum PKCS7_ENVELOPE {} -pub enum PKCS7_SIGN_ENVELOPE {} -pub enum PKCS7_DIGEST {} -pub enum PKCS7_ENCRYPT {} -pub enum PKCS7 {} +// use x509::stack_st_X509; +// use x509_attr::stack_st_X509_ATTRIBUTE; + +#[cfg(ossl300)] +#[repr(C)] +pub struct PKCS7_CTX { + libctx: *mut OSSL_LIB_CTX, + propq: *mut c_char, +} + +cfg_if! { + if #[cfg(any(ossl101, libressl251))] { + #[repr(C)] + pub struct PKCS7_SIGNED { + pub version: *mut ASN1_INTEGER, /* version 1 */ + pub md_algs: *mut stack_st_X509_ALGOR, /* md used */ + pub cert: *mut stack_st_X509, /* [ 0 ] */ + pub crl: *mut stack_st_X509_CRL, /* [ 1 ] */ + pub signer_info: *mut stack_st_PKCS7_SIGNER_INFO, + pub contents: *mut PKCS7, + } + } else { + pub enum PKCS7_SIGNED {} + } +} + +cfg_if! { + if #[cfg(any(ossl101, libressl251))] { + #[repr(C)] + pub struct PKCS7_ENC_CONTENT { + pub content_type: *mut ASN1_OBJECT, + pub algorithm: *mut X509_ALGOR, + pub enc_data: *mut ASN1_OCTET_STRING, /* [ 0 ] */ + pub cipher: *const EVP_CIPHER, + #[cfg(ossl300)] + pub ctx: *const PKCS7_CTX, + } + } else { + pub enum PKCS7_ENC_CONTENT {} + } +} + +cfg_if! { + if #[cfg(any(ossl101, libressl251))] { + #[repr(C)] + pub struct PKCS7_ENVELOPE { + pub version: *mut ASN1_INTEGER, /* version 0 */ + pub recipientinfo: *mut stack_st_PKCS7_RECIP_INFO, + pub enc_data: *mut PKCS7_ENC_CONTENT, + } + } else { + pub enum PKCS7_ENVELOPE {} + } +} + +cfg_if! { + if #[cfg(any(ossl101, libressl251))] { + #[repr(C)] + pub struct PKCS7_SIGN_ENVELOPE { + pub version: *mut ASN1_INTEGER, /* version 1 */ + pub md_algs: *mut stack_st_X509_ALGOR, /* md used */ + pub cert: *mut stack_st_X509, /* [ 0 ] */ + pub crl: *mut stack_st_X509_CRL, /* [ 1 ] */ + pub signer_info: *mut stack_st_PKCS7_SIGNER_INFO, + pub enc_data: *mut PKCS7_ENC_CONTENT, + pub recipientinfo: *mut stack_st_PKCS7_RECIP_INFO + } + } else { + pub enum PKCS7_SIGN_ENVELOPE {} + } +} + +cfg_if! { + if #[cfg(any(ossl101, libressl251))] { + #[repr(C)] + pub struct PKCS7_DIGEST { + pub version: *mut ASN1_INTEGER, /* version 0 */ + pub md: *mut X509_ALGOR, /* md used */ + pub contents: *mut PKCS7, + pub digest: *mut ASN1_OCTET_STRING, + } + } else { + pub enum PKCS7_DIGEST {} + } +} + +cfg_if! { + if #[cfg(any(ossl101, libressl251))] { + #[repr(C)] + pub struct PKCS7_ENCRYPT { + pub version: *mut ASN1_INTEGER, /* version 0 */ + pub enc_data: *mut PKCS7_ENC_CONTENT, + } + } else { + pub enum PKCS7_ENCRYPT {} + } +} + +extern "C" { + pub fn PKCS7_SIGNED_free(info: *mut PKCS7_SIGNED); + pub fn PKCS7_ENC_CONTENT_free(info: *mut PKCS7_ENC_CONTENT); + pub fn PKCS7_ENVELOPE_free(info: *mut PKCS7_ENVELOPE); + pub fn PKCS7_SIGN_ENVELOPE_free(info: *mut PKCS7_SIGN_ENVELOPE); + pub fn PKCS7_DIGEST_free(info: *mut PKCS7_DIGEST); + pub fn PKCS7_SIGNER_INFO_free(info: *mut PKCS7_SIGNER_INFO); +} + +cfg_if! { + if #[cfg(any(ossl101, libressl251))] { + #[repr(C)] + pub struct PKCS7 { + /* + * The following is non NULL if it contains ASN1 encoding of this + * structure + */ + pub asn1: *mut c_uchar, + pub length: c_long, + // # define PKCS7_S_HEADER 0 + // # define PKCS7_S_BODY 1 + // # define PKCS7_S_TAIL 2 + pub state: c_int, /* used during processing */ + pub detached: c_int, + pub type_: *mut ASN1_OBJECT, + /* content as defined by the type */ + /* + * all encryption/message digests are applied to the 'contents', leaving + * out the 'type' field. + */ + pub d: PKCS7_data, + #[cfg(ossl300)] + pub ctx: PKCS7_CTX, + } + #[repr(C)] + pub union PKCS7_data { + pub ptr: *mut c_char, + /* NID_pkcs7_data */ + pub data: *mut ASN1_OCTET_STRING, + /* NID_pkcs7_signed */ + pub sign: *mut PKCS7_SIGNED, + /* NID_pkcs7_enveloped */ + pub enveloped: *mut PKCS7_ENVELOPE, + /* NID_pkcs7_signedAndEnveloped */ + pub signed_and_enveloped: *mut PKCS7_SIGN_ENVELOPE, + /* NID_pkcs7_digest */ + pub digest: *mut PKCS7_DIGEST, + /* NID_pkcs7_encrypted */ + pub encrypted: *mut PKCS7_ENCRYPT, + /* Anything else */ + pub other: *mut ASN1_TYPE, + } + } else { + pub enum PKCS7 {} + } +} + +cfg_if! { + if #[cfg(any(ossl101, libressl))] { + #[repr(C)] + pub struct PKCS7_ISSUER_AND_SERIAL { + pub issuer: *mut X509_NAME, + pub serial: *mut ASN1_INTEGER, + } + } else { + pub enum PKCS7_ISSUER_AND_SERIAL {} + } +} + +cfg_if! { + if #[cfg(any(ossl101, libressl))] { + #[repr(C)] + pub struct PKCS7_SIGNER_INFO { + pub version: *mut ASN1_INTEGER, /* version 1 */ + pub issuer_and_serial: *mut PKCS7_ISSUER_AND_SERIAL, + pub digest_alg: *mut X509_ALGOR, + pub auth_attr: *mut stack_st_X509_ATTRIBUTE, /* [ 0 ] */ + pub digest_enc_alg: *mut X509_ALGOR, + pub enc_digest: *mut ASN1_OCTET_STRING, + pub unauth_attr: *mut stack_st_X509_ATTRIBUTE, /* [ 1 ] */ + pub pkey: *mut EVP_PKEY, /* The private key to sign with */ + #[cfg(ossl300)] + pub ctx: *const PKCS7_CTX, + } + } else { + pub enum PKCS7_SIGNER_INFO {} + } +} + +stack!(stack_st_PKCS7_SIGNER_INFO); +stack!(stack_st_PKCS7_RECIP_INFO); extern "C" { pub fn d2i_PKCS7(a: *mut *mut PKCS7, pp: *mut *const c_uchar, length: c_long) -> *mut PKCS7; @@ -15,6 +198,7 @@ extern "C" { const_ptr_api! { extern "C" { pub fn i2d_PKCS7(a: #[const_ptr_if(ossl300)] PKCS7, buf: *mut *mut u8) -> c_int; + pub fn i2d_PKCS7_bio(bio: *mut BIO, p7: #[const_ptr_if(ossl300)] PKCS7) -> c_int; } } @@ -67,4 +251,53 @@ extern "C" { ) -> c_int; pub fn SMIME_read_PKCS7(bio: *mut BIO, bcont: *mut *mut BIO) -> *mut PKCS7; + + pub fn PKCS7_new() -> *mut PKCS7; + + pub fn PKCS7_set_type(p7: *mut PKCS7, nid_pkcs7: c_int) -> c_int; + + pub fn PKCS7_add_certificate(p7: *mut PKCS7, x509: *mut X509) -> c_int; + + pub fn PKCS7_add_signature( + p7: *mut PKCS7, + x509: *mut X509, + pkey: *mut EVP_PKEY, + digest: *const EVP_MD, + ) -> *mut PKCS7_SIGNER_INFO; + + pub fn PKCS7_set_signed_attributes( + p7si: *mut PKCS7_SIGNER_INFO, + attributes: *mut stack_st_X509_ATTRIBUTE, + ) -> c_int; + + pub fn PKCS7_add_signed_attribute( + p7si: *mut PKCS7_SIGNER_INFO, + nid: c_int, + attrtype: c_int, + data: *mut c_void, + ) -> c_int; + + pub fn PKCS7_content_new(p7: *mut PKCS7, nid_pkcs7: c_int) -> c_int; + + pub fn PKCS7_dataInit(p7: *mut PKCS7, bio: *mut BIO) -> *mut BIO; + + pub fn PKCS7_dataFinal(p7: *mut PKCS7, bio: *mut BIO) -> c_int; + + pub fn PKCS7_get_signer_info(p7: *mut PKCS7) -> *mut stack_st_PKCS7_SIGNER_INFO; + + pub fn PKCS7_SIGNER_INFO_get0_algs( + si: *mut PKCS7_SIGNER_INFO, + pk: *mut *mut EVP_PKEY, + pdig: *mut *mut X509_ALGOR, + psig: *mut *mut X509_ALGOR, + ); +} + +const_ptr_api! { + extern "C" { + pub fn PKCS7_get_signed_attribute( + si: #[const_ptr_if(ossl300)] PKCS7_SIGNER_INFO, + nid: c_int + ) -> *mut ASN1_TYPE; + } } diff --git a/openssl-sys/src/handwritten/types.rs b/openssl-sys/src/handwritten/types.rs index 476578c051..addc599abb 100644 --- a/openssl-sys/src/handwritten/types.rs +++ b/openssl-sys/src/handwritten/types.rs @@ -3,14 +3,26 @@ use libc::*; #[allow(unused_imports)] use *; +#[derive(Copy, Clone)] +pub enum ASN1_BOOLEAN {} +pub enum ASN1_ENUMERATED {} pub enum ASN1_INTEGER {} pub enum ASN1_GENERALIZEDTIME {} pub enum ASN1_STRING {} pub enum ASN1_BIT_STRING {} pub enum ASN1_TIME {} -pub enum ASN1_TYPE {} pub enum ASN1_OBJECT {} pub enum ASN1_OCTET_STRING {} +pub enum ASN1_PRINTABLESTRING {} +pub enum ASN1_T61STRING {} +pub enum ASN1_IA5STRING {} +pub enum ASN1_GENERALSTRING {} +pub enum ASN1_BMPSTRING {} +pub enum ASN1_UNIVERSALSTRING {} +pub enum ASN1_UTCTIME {} +pub enum ASN1_VISIBLESTRING {} +pub enum ASN1_UTF8STRING {} +pub enum ASN1_VALUE {} pub enum bio_st {} // FIXME remove cfg_if! { @@ -325,6 +337,8 @@ cfg_if! { } } +stack!(stack_st_X509_ALGOR); + pub enum X509_LOOKUP_METHOD {} pub enum X509_NAME {} diff --git a/openssl-sys/src/handwritten/x509.rs b/openssl-sys/src/handwritten/x509.rs index 047f3df262..486f712c34 100644 --- a/openssl-sys/src/handwritten/x509.rs +++ b/openssl-sys/src/handwritten/x509.rs @@ -15,8 +15,6 @@ pub enum X509_EXTENSION {} stack!(stack_st_X509_EXTENSION); -stack!(stack_st_X509_ATTRIBUTE); - cfg_if! { if #[cfg(any(ossl110, libressl350))] { pub enum X509_REQ_INFO {} @@ -27,7 +25,7 @@ cfg_if! { pub version: *mut ::ASN1_INTEGER, pub subject: *mut ::X509_NAME, pubkey: *mut c_void, - pub attributes: *mut stack_st_X509_ATTRIBUTE, + pub attributes: *mut ::stack_st_X509_ATTRIBUTE, } } } @@ -271,9 +269,12 @@ extern "C" { pub fn X509_EXTENSION_free(ext: *mut X509_EXTENSION); + pub fn X509_ATTRIBUTE_free(attr: *mut ::X509_ATTRIBUTE); + pub fn X509_NAME_ENTRY_free(x: *mut X509_NAME_ENTRY); pub fn X509_NAME_new() -> *mut X509_NAME; + pub fn X509_NAME_cmp(x: *const X509_NAME, y: *const X509_NAME) -> c_int; pub fn X509_NAME_free(x: *mut X509_NAME); pub fn X509_new() -> *mut X509; @@ -359,6 +360,33 @@ const_ptr_api! { -> c_int; } } +extern "C" { + pub fn X509_REQ_get_attr_count(req: *const X509_REQ) -> c_int; + pub fn X509_REQ_get_attr_by_NID(req: *const X509_REQ, nid: c_int, lastpos: c_int) -> c_int; + pub fn X509_REQ_get_attr(req: *const X509_REQ, loc: c_int) -> *mut ::X509_ATTRIBUTE; + pub fn X509_REQ_delete_attr(req: *mut X509_REQ, loc: c_int) -> *mut ::X509_ATTRIBUTE; + pub fn X509_REQ_add1_attr_by_txt( + req: *mut X509_REQ, + attrname: *const c_char, + chtype: c_int, + bytes: *const c_uchar, + len: c_int, + ) -> c_int; + pub fn X509_REQ_add1_attr_by_NID( + req: *mut X509_REQ, + nid: c_int, + chtype: c_int, + bytes: *const c_uchar, + len: c_int, + ) -> c_int; + pub fn X509_REQ_add1_attr_by_OBJ( + req: *mut X509_REQ, + obj: *const ASN1_OBJECT, + chtype: c_int, + bytes: *const c_uchar, + len: c_int, + ) -> c_int; +} extern "C" { pub fn X509_set_pubkey(x: *mut X509, pkey: *mut EVP_PKEY) -> c_int; pub fn X509_REQ_verify(req: *mut X509_REQ, pkey: *mut EVP_PKEY) -> c_int; @@ -607,6 +635,7 @@ const_ptr_api! { pub fn X509_STORE_get0_objects(ctx: #[const_ptr_if(ossl300)] X509_STORE) -> *mut stack_st_X509_OBJECT; } } + #[cfg(any(ossl110, libressl270))] extern "C" { pub fn X509_OBJECT_get0_X509(x: *const X509_OBJECT) -> *mut X509; @@ -633,7 +662,6 @@ extern "C" { extern "C" { pub fn X509_cmp(a: *const X509, b: *const X509) -> c_int; - pub fn X509_NAME_cmp(a: *const X509_NAME, b: *const X509_NAME) -> c_int; pub fn X509_issuer_and_serial_cmp(a: *const X509, b: *const X509) -> c_int; pub fn X509_issuer_name_cmp(a: *const X509, b: *const X509) -> c_int; pub fn X509_subject_name_cmp(a: *const X509, b: *const X509) -> c_int; diff --git a/openssl-sys/src/handwritten/x509_attr.rs b/openssl-sys/src/handwritten/x509_attr.rs new file mode 100644 index 0000000000..b14be38619 --- /dev/null +++ b/openssl-sys/src/handwritten/x509_attr.rs @@ -0,0 +1,60 @@ +use libc::*; + +use *; + +pub enum X509_ATTRIBUTE {} + +stack!(stack_st_X509_ATTRIBUTE); + +extern "C" { + pub fn X509_ATTRIBUTE_new() -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_create( + nid: c_int, + atrtype: c_int, + value: *mut c_void, + ) -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_create_by_NID( + attr: *mut *mut X509_ATTRIBUTE, + nid: c_int, + atrtype: c_int, + data: *const c_void, + len: c_int, + ) -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_create_by_OBJ( + attr: *mut *mut X509_ATTRIBUTE, + obj: *const ASN1_OBJECT, + atrtype: c_int, + data: *const c_void, + len: c_int, + ) -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_create_by_txt( + attr: *mut *mut X509_ATTRIBUTE, + atrname: *const c_char, + atrtype: c_int, + bytes: *const c_uchar, + len: c_int, + ) -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_set1_object(attr: *mut X509_ATTRIBUTE, obj: *const ASN1_OBJECT) -> c_int; + pub fn X509_ATTRIBUTE_set1_data( + attr: *mut X509_ATTRIBUTE, + attrtype: c_int, + data: *const c_void, + len: c_int, + ) -> c_int; + pub fn X509_ATTRIBUTE_get0_data( + attr: *mut X509_ATTRIBUTE, + idx: c_int, + atrtype: c_int, + data: *mut c_void, + ) -> *mut c_void; + pub fn X509_ATTRIBUTE_get0_object(attr: *mut X509_ATTRIBUTE) -> *mut ASN1_OBJECT; + pub fn X509_ATTRIBUTE_get0_type(attr: *mut X509_ATTRIBUTE, idx: c_int) -> *mut ASN1_TYPE; + +} +const_ptr_api! { + extern "C" { + pub fn X509_ATTRIBUTE_count( + attr: #[const_ptr_if(any(ossl110, libressl291))] X509_ATTRIBUTE // const since OpenSSL v1.1.0 + ) -> c_int; + } +} From 015cbca7be103272e8d2fa40a58e26bfe8609f3c Mon Sep 17 00:00:00 2001 From: Bernd Krietenstein Date: Fri, 13 Jan 2023 15:58:03 +0100 Subject: [PATCH 02/19] X509, X509Req and related functionality (e.g. extensions, attributes). --- openssl/Cargo.toml | 1 + openssl/build.rs | 4 + openssl/examples/mk_certs.rs | 57 ++++- openssl/src/asn1.rs | 469 +++++++++++++++++++++++++++++----- openssl/src/bio.rs | 17 +- openssl/src/symm.rs | 1 + openssl/src/x509/extension.rs | 189 +++++++++++--- openssl/src/x509/mod.rs | 312 +++++++++++++++++++++- openssl/src/x509/tests.rs | 159 ++++++++++++ systest/build.rs | 9 +- 10 files changed, 1106 insertions(+), 112 deletions(-) diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index 1fd24448fd..0aea05c0ce 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -27,6 +27,7 @@ bitflags = "1.0" cfg-if = "1.0" foreign-types = "0.3.1" libc = "0.2" +num_enum = "0.5" once_cell = "1.5.2" openssl-macros = { version = "0.1.0", path = "../openssl-macros" } diff --git a/openssl/build.rs b/openssl/build.rs index fc6492292c..d8f8831b73 100644 --- a/openssl/build.rs +++ b/openssl/build.rs @@ -79,6 +79,10 @@ fn main() { println!("cargo:rustc-cfg=libressl291"); } + if version >= 0x3_01_00_00_0 { + println!("cargo:rustc-cfg=libressl310"); + } + if version >= 0x3_02_01_00_0 { println!("cargo:rustc-cfg=libressl321"); } diff --git a/openssl/examples/mk_certs.rs b/openssl/examples/mk_certs.rs index e944af06bc..36967de9b9 100644 --- a/openssl/examples/mk_certs.rs +++ b/openssl/examples/mk_certs.rs @@ -5,14 +5,21 @@ use openssl::asn1::Asn1Time; use openssl::bn::{BigNum, MsbOption}; use openssl::error::ErrorStack; use openssl::hash::MessageDigest; +use openssl::nid::Nid; use openssl::pkey::{PKey, PKeyRef, Private}; use openssl::rsa::Rsa; +use openssl::stack::Stack; use openssl::x509::extension::{ - AuthorityKeyIdentifier, BasicConstraints, KeyUsage, SubjectAlternativeName, + AuthorityKeyIdentifier, BasicConstraints, ExtendedKeyUsage, KeyUsage, SubjectAlternativeName, SubjectKeyIdentifier, }; use openssl::x509::{X509NameBuilder, X509Ref, X509Req, X509ReqBuilder, X509VerifyResult, X509}; +fn mk_key_pair() -> Result, ErrorStack> { + let rsa = Rsa::generate(2048)?; + let key_pair = PKey::from_rsa(rsa)?; + Ok(key_pair) +} /// Make a CA certificate and private key fn mk_ca_cert() -> Result<(X509, PKey), ErrorStack> { let rsa = Rsa::generate(2048)?; @@ -78,6 +85,49 @@ fn mk_request(key_pair: &PKey) -> Result { Ok(req) } +/// Make a X509 request with the given private key and a challengePassword attribute +fn mk_request_with_attribute(key_pair: &PKey) -> Result { + let mut req_builder = X509ReqBuilder::new()?; + req_builder.set_pubkey(key_pair)?; + + let mut x509_name = X509NameBuilder::new()?; + x509_name.append_entry_by_text("CN", "myserver.localhost")?; + let x509_name = x509_name.build(); + + req_builder.set_version(0)?; // 0x00 -> Version: 1 + req_builder.set_subject_name(&x509_name)?; + let extensions = { + let context = req_builder.x509v3_context(None); + let mut ext_stack = Stack::new()?; + ext_stack.push( + KeyUsage::new() + .digital_signature() + .key_encipherment() + .build()?, + )?; + ext_stack.push(ExtendedKeyUsage::new().server_auth().build()?)?; + ext_stack.push( + SubjectAlternativeName::new() + .dns("myserver.localhost") + .build(&context)?, + )?; + ext_stack.push( + SubjectAlternativeName::new() + .ip("127.0.0.1") + .build(&context)?, + )?; + ext_stack.push(SubjectAlternativeName::new().ip("::1").build(&context)?)?; + ext_stack + }; + req_builder.add_extensions(&extensions)?; + req_builder + .add_attribute_by_nid(Nid::PKCS9_CHALLENGEPASSWORD, "my_secret_challenge_password")?; + + req_builder.sign(key_pair, MessageDigest::sha256())?; + let req = req_builder.build(); + Ok(req) +} + /// Make a certificate and private key signed by the given CA cert and private key fn mk_ca_signed_cert( ca_cert: &X509Ref, @@ -147,6 +197,11 @@ fn real_main() -> Result<(), ErrorStack> { ver_err => println!("Failed to verify certificate: {}", ver_err), }; + let server_key_pair = mk_key_pair()?; + let csr = mk_request_with_attribute(&server_key_pair)?; + println!("CSR with challengePassword was created:"); + println!("{}", std::str::from_utf8(&csr.to_pem()?).unwrap()); + Ok(()) } diff --git a/openssl/src/asn1.rs b/openssl/src/asn1.rs index 55de049c08..130e356533 100644 --- a/openssl/src/asn1.rs +++ b/openssl/src/asn1.rs @@ -39,7 +39,9 @@ use crate::bio::MemBio; use crate::bn::{BigNum, BigNumRef}; use crate::error::ErrorStack; use crate::nid::Nid; +use crate::stack::Stackable; use crate::string::OpensslString; +use crate::util::ForeignTypeRefExt; use crate::{cvt, cvt_p}; use openssl_macros::corresponds; @@ -84,77 +86,106 @@ impl fmt::Display for Asn1GeneralizedTimeRef { } } -/// The type of an ASN.1 value. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct Asn1Type(c_int); - -#[allow(missing_docs)] // no need to document the constants -impl Asn1Type { - pub const EOC: Asn1Type = Asn1Type(ffi::V_ASN1_EOC); - - pub const BOOLEAN: Asn1Type = Asn1Type(ffi::V_ASN1_BOOLEAN); - - pub const INTEGER: Asn1Type = Asn1Type(ffi::V_ASN1_INTEGER); - - pub const BIT_STRING: Asn1Type = Asn1Type(ffi::V_ASN1_BIT_STRING); - - pub const OCTET_STRING: Asn1Type = Asn1Type(ffi::V_ASN1_OCTET_STRING); - - pub const NULL: Asn1Type = Asn1Type(ffi::V_ASN1_NULL); - - pub const OBJECT: Asn1Type = Asn1Type(ffi::V_ASN1_OBJECT); - - pub const OBJECT_DESCRIPTOR: Asn1Type = Asn1Type(ffi::V_ASN1_OBJECT_DESCRIPTOR); - - pub const EXTERNAL: Asn1Type = Asn1Type(ffi::V_ASN1_EXTERNAL); - - pub const REAL: Asn1Type = Asn1Type(ffi::V_ASN1_REAL); - - pub const ENUMERATED: Asn1Type = Asn1Type(ffi::V_ASN1_ENUMERATED); - - pub const UTF8STRING: Asn1Type = Asn1Type(ffi::V_ASN1_UTF8STRING); - - pub const SEQUENCE: Asn1Type = Asn1Type(ffi::V_ASN1_SEQUENCE); - - pub const SET: Asn1Type = Asn1Type(ffi::V_ASN1_SET); - - pub const NUMERICSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_NUMERICSTRING); - - pub const PRINTABLESTRING: Asn1Type = Asn1Type(ffi::V_ASN1_PRINTABLESTRING); - - pub const T61STRING: Asn1Type = Asn1Type(ffi::V_ASN1_T61STRING); - - pub const TELETEXSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_TELETEXSTRING); - - pub const VIDEOTEXSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_VIDEOTEXSTRING); - - pub const IA5STRING: Asn1Type = Asn1Type(ffi::V_ASN1_IA5STRING); - - pub const UTCTIME: Asn1Type = Asn1Type(ffi::V_ASN1_UTCTIME); - - pub const GENERALIZEDTIME: Asn1Type = Asn1Type(ffi::V_ASN1_GENERALIZEDTIME); - - pub const GRAPHICSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_GRAPHICSTRING); - - pub const ISO64STRING: Asn1Type = Asn1Type(ffi::V_ASN1_ISO64STRING); - - pub const VISIBLESTRING: Asn1Type = Asn1Type(ffi::V_ASN1_VISIBLESTRING); - - pub const GENERALSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_GENERALSTRING); - - pub const UNIVERSALSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_UNIVERSALSTRING); +/// See ASN.1 specification for the meaning of Asn1TagValues (e.g. https://www.itu.int/en/ITU-T/asn1) +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct Asn1TagValue(c_int); + +impl Asn1TagValue { + /// End-of-contents marker + pub const EOC: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_EOC); + /// Boolean value + pub const BOOLEAN: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_BOOLEAN); + /// Integer value + pub const INTEGER: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_INTEGER); + /// Bit string + pub const BIT_STRING: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_BIT_STRING); + /// Octet string + pub const OCTET_STRING: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_OCTET_STRING); + /// No-data present + pub const NULL: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_NULL); + /// Representation of the ASN1 OBJECT IDENTIFIER (OID) type + pub const OBJECT: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_OBJECT); + /// ASN.1 ObjectDescriptor + pub const OBJECT_DESCRIPTOR: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_OBJECT_DESCRIPTOR); + /// Hmmm... + pub const EXTERNAL: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_EXTERNAL); + /// ASN.1 Real + pub const REAL: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_REAL); + /// Signed integers of any size + pub const ENUMERATED: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_ENUMERATED); + /// UTF-8 string + pub const UTF8STRING: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_UTF8STRING); + /// ASN.1 sequence + pub const SEQUENCE: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_SEQUENCE); + /// ASN.1 set + pub const SET: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_SET); + /// Numeric string to hold characters 0-9 and space + pub const NUMERICSTRING: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_NUMERICSTRING); + /// A string holding printable characters "A"-"Z","a"-"z","0"-"9",space and "'()+,-./:=?" + pub const PRINTABLESTRING: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_PRINTABLESTRING); + /// ASN.1 Teletex string + pub const T61STRING: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_T61STRING); + /// ASN.1 Teletex string + pub const TELETEXSTRING: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_T61STRING); + /// ASN.1 VideotexString + pub const VIDEOTEXSTRING: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_VIDEOTEXSTRING); + /// "International Alphabet 5" string + pub const IA5STRING: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_IA5STRING); + /// Time representation in ASCII + pub const UTCTIME: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_UTCTIME); + /// Another time representation in ASCII + pub const GENERALIZEDTIME: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_GENERALIZEDTIME); + /// String based on "International Register of Coded Character Sets to be used with Escape + /// Sequences". + pub const GRAPHICSTRING: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_GRAPHICSTRING); + /// String excluding invisible characters. Iso64String is an alias of this type + pub const VISIBLESTRING: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_VISIBLESTRING); + /// See `Asn1TagValue::VISIBLESTRING` + pub const ISO64STRING: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_VISIBLESTRING); + /// String based on "International Register of Coded Character Sets to be used with Escape + /// Sequences". + pub const GENERALSTRING: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_GENERALSTRING); + /// Another universal string type that is rareley used after Unicode became the de-facto + /// standard. + pub const UNIVERSALSTRING: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_UNIVERSALSTRING); + /// "Basic Multilingual Plane" string + pub const BMPSTRING: Asn1TagValue = Asn1TagValue(ffi::V_ASN1_BMPSTRING); + + /// Returns the integer representation of `Padding`. + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn as_raw(&self) -> c_int { + self.0 + } +} - pub const BMPSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_BMPSTRING); +// The type of an ASN.1 value. +foreign_type_and_impl_send_sync! { + type CType = ffi::ASN1_TYPE; + fn drop = ffi::ASN1_TYPE_free; + /// ASN.1 type + /// + /// The OpenSSL ASN1_TYPE holds a type information as well as an ASN.1 value of that type. + /// Attributes are normally returned by OpenSSL as (generic) ASN1_TYPE. + pub struct Asn1Type; + /// Reference to an [`Asn1Type`] + pub struct Asn1TypeRef; +} - /// Constructs an `Asn1Type` from a raw OpenSSL value. - pub fn from_raw(value: c_int) -> Self { - Asn1Type(value) +impl Asn1TypeRef { + /// The type of the value, the Asn1Type contains. + /// Returns `None`, if the + pub fn typ(&self) -> Asn1TagValue { + unsafe { + let asn1type = self.as_ptr(); + Asn1TagValue((*asn1type).type_ as c_int) + } } +} - /// Returns the raw OpenSSL value represented by this type. - pub fn as_raw(&self) -> c_int { - self.0 - } +/// Must be implemented by all ASN.1 object structs +pub trait FromAsn1Type { + /// Returns a `T` for the value, that is contained in the Asn1Type + fn from_asn1type(ty: &Asn1TypeRef) -> Option<&T>; } /// Difference between two ASN1 times. @@ -429,6 +460,57 @@ foreign_type_and_impl_send_sync! { pub struct Asn1StringRef; } +impl Asn1String { + /// Create a new and empty ASN1_STRING. + /// + /// OpenSSL internally sets the string type to `V_ASN1_OCTET_STRING`. Use `type_new()` for + /// other `Asn1Type`s. + /// Note: according to OpenSSL documentation, the type is undefined. However, implementation + /// sets it to `V_ASN1_OCTET_STRING`. + /// + #[corresponds(ASN1_STRING_new)] + pub fn new() -> Result { + unsafe { + let asn1_string = cvt_p(ffi::ASN1_STRING_new()).map(Asn1String)?; + Ok(asn1_string) + } + } + + /// Create a new and empty ASN1_STRING of a given type. + /// + /// `ty` is the ASN1 type of the string. + /// + #[corresponds(ASN1_STRING_type_new)] + pub fn type_new(ty: Asn1TagValue) -> Result { + assert!( + [ + Asn1TagValue::BIT_STRING, + Asn1TagValue::BMPSTRING, + Asn1TagValue::ENUMERATED, + Asn1TagValue::GENERALSTRING, + Asn1TagValue::GENERALIZEDTIME, + Asn1TagValue::IA5STRING, + Asn1TagValue::INTEGER, + Asn1TagValue::OCTET_STRING, + Asn1TagValue::PRINTABLESTRING, + Asn1TagValue::T61STRING, + Asn1TagValue::TELETEXSTRING, + Asn1TagValue::UNIVERSALSTRING, + Asn1TagValue::UTCTIME, + Asn1TagValue::UTF8STRING, + Asn1TagValue::VISIBLESTRING, + Asn1TagValue::VIDEOTEXSTRING, + ] + .contains(&ty), + "Unsupported Asn1Type for Asn1String" + ); + unsafe { + let asn1_string = cvt_p(ffi::ASN1_STRING_type_new(ty.as_raw())).map(Asn1String)?; + Ok(asn1_string) + } + } +} + impl Asn1StringRef { /// Converts the ASN.1 underlying format to UTF8 /// @@ -469,6 +551,44 @@ impl Asn1StringRef { pub fn is_empty(&self) -> bool { self.len() == 0 } + + /// Set the value of an ASN1_STRING + /// + /// `value` is consumed by this method. The value is copied by OpenSSL. + /// + /// This can be used for `V_ASN1_OCTET_STRING` as well as for other string types like UTF-8: + /// + /// ``` + /// use openssl::nid::Nid; + /// use openssl::asn1::{Asn1Object, Asn1String, Asn1TagValue, Asn1Type}; + /// + /// // Octet string + /// let mut octet_string_asn1: Asn1String = Asn1String::new().unwrap(); + /// let octet: [u8; 3] = [1, 2, 3]; + /// octet_string_asn1.set(&octet).unwrap(); + /// + /// // Add a printable string + /// let mut printable_string_asn1 = Asn1String::type_new(Asn1TagValue::PRINTABLESTRING).unwrap(); + /// printable_string_asn1.set("A printable string".as_bytes()).unwrap(); + /// + /// // Add an ASN1 object (OpenSSL 1.1.1 and higher) + /// let asn1object = Asn1Object::from_nid(&Nid::PKCS7_DATA).unwrap(); + /// let mut object_string_asn1: Asn1String = Asn1String::new().unwrap(); + /// #[cfg(ossl111)] object_string_asn1.set(asn1object.as_slice()).unwrap(); + /// ``` + /// + #[corresponds(ASN1_STRING_set)] + pub fn set(&mut self, value: &[u8]) -> Result<(), ErrorStack> { + unsafe { + let value_len = value.len(); + cvt(ffi::ASN1_STRING_set( + self.as_ptr(), + value.as_ptr() as *mut _, + value_len as c_int, + )) + .map(|_| ()) + } + } } impl fmt::Debug for Asn1StringRef { @@ -480,6 +600,89 @@ impl fmt::Debug for Asn1StringRef { } } +impl FromAsn1Type for Asn1StringRef { + fn from_asn1type(ty: &Asn1TypeRef) -> Option<&Asn1StringRef> { + unsafe { + unsafe fn from_asn1type_ptr(ty: &Asn1TypeRef) -> &Asn1StringRef { + Asn1StringRef::from_const_ptr( + (*ty.as_ptr()).value.asn1_string as *const ffi::ASN1_STRING, + ) + } + match ty.typ() { + Asn1TagValue::BIT_STRING => Some(from_asn1type_ptr(ty)), + Asn1TagValue::BMPSTRING => Some(from_asn1type_ptr(ty)), + Asn1TagValue::ENUMERATED => Some(from_asn1type_ptr(ty)), + Asn1TagValue::GENERALSTRING => Some(from_asn1type_ptr(ty)), + Asn1TagValue::GENERALIZEDTIME => Some(from_asn1type_ptr(ty)), + Asn1TagValue::GRAPHICSTRING => Some(from_asn1type_ptr(ty)), + Asn1TagValue::IA5STRING => Some(from_asn1type_ptr(ty)), + Asn1TagValue::INTEGER => Some(from_asn1type_ptr(ty)), + Asn1TagValue::NUMERICSTRING => Some(from_asn1type_ptr(ty)), + Asn1TagValue::OCTET_STRING => Some(from_asn1type_ptr(ty)), + Asn1TagValue::PRINTABLESTRING => Some(from_asn1type_ptr(ty)), + Asn1TagValue::T61STRING => Some(from_asn1type_ptr(ty)), + Asn1TagValue::UNIVERSALSTRING => Some(from_asn1type_ptr(ty)), + Asn1TagValue::UTCTIME => Some(from_asn1type_ptr(ty)), + Asn1TagValue::UTF8STRING => Some(from_asn1type_ptr(ty)), + Asn1TagValue::VIDEOTEXSTRING => Some(from_asn1type_ptr(ty)), + Asn1TagValue::VISIBLESTRING => Some(from_asn1type_ptr(ty)), + _ => None, // Not a string type. Conversion not supported. + } + } + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::ASN1_OCTET_STRING; + fn drop = ffi::ASN1_OCTET_STRING_free; + /// ASN.1 type used by OpenSSL for octet strings + /// + pub struct Asn1OctetString; + /// A reference to an [`Asn1OctetString`]. + pub struct Asn1OctetStringRef; +} + +impl Asn1OctetStringRef { + /// Return the octet string as an array of bytes. + #[corresponds(ASN1_STRING_get0_data)] + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr() as *mut _), self.len()) } + } + + /// Returns the number of bytes in the string. + #[corresponds(ASN1_STRING_length)] + pub fn len(&self) -> usize { + unsafe { ffi::ASN1_STRING_length(self.as_ptr() as *const _) as usize } + } + + /// Determines if the string is empty. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } +} + +impl fmt::Debug for Asn1OctetStringRef { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.write_str(&format!("{:x?}", self.as_slice())) + } +} + +impl FromAsn1Type for Asn1OctetStringRef { + fn from_asn1type(ty: &Asn1TypeRef) -> Option<&Asn1OctetStringRef> { + unsafe { + unsafe fn from_asn1type_ptr(ty: &Asn1TypeRef) -> &Asn1OctetStringRef { + Asn1OctetStringRef::from_const_ptr( + (*ty.as_ptr()).value.asn1_string as *const ffi::ASN1_OCTET_STRING, + ) + } + match ty.typ() { + Asn1TagValue::OCTET_STRING => Some(from_asn1type_ptr(ty)), + _ => None, // Wrong or not even a string type. Conversion not supported. + } + } + } +} + foreign_type_and_impl_send_sync! { type CType = ffi::ASN1_INTEGER; fn drop = ffi::ASN1_INTEGER_free; @@ -605,6 +808,17 @@ impl Asn1Object { } } + /// Constructs an ASN.1 Object Identifier from an OID. + #[corresponds(OBJ_nid2obj)] + #[allow(clippy::should_implement_trait)] + pub fn from_nid(nid: &Nid) -> Result { + unsafe { + ffi::init(); + let obj: *mut ffi::ASN1_OBJECT = cvt_p(ffi::OBJ_nid2obj(nid.as_raw()))?; + Ok(Asn1Object::from_ptr(obj)) + } + } + /// Return the OID as an DER encoded array of bytes. This is the ASN.1 /// value, not including tag or length. /// @@ -619,6 +833,10 @@ impl Asn1Object { } } +impl Stackable for Asn1Object { + type StackType = ffi::stack_st_ASN1_OBJECT; +} + impl Asn1ObjectRef { /// Returns the NID associated with this OID. pub fn nid(&self) -> Nid { @@ -626,6 +844,14 @@ impl Asn1ObjectRef { } } +impl PartialEq for Asn1ObjectRef { + /// Compare two `Asn1Object`s + #[corresponds(OBJ_cmp)] + fn eq(&self, other: &Self) -> bool { + unsafe { ffi::OBJ_cmp(self.as_ptr(), other.as_ptr()) == 0 } + } +} + impl fmt::Display for Asn1ObjectRef { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { unsafe { @@ -664,6 +890,8 @@ cfg_if! { #[cfg(test)] mod tests { use super::*; + #[cfg(not(boringssl))] + use std::ptr::null_mut; use crate::bn::BigNum; use crate::nid::Nid; @@ -750,6 +978,16 @@ mod tests { assert_eq!(object.nid(), Nid::SHA256); } + #[test] + #[cfg(ossl111)] + fn object_from_nid() { + let object = Asn1Object::from_nid(&Nid::PKCS7_DATA).unwrap(); + assert_eq!( + object.as_slice(), + &[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01,] + ); + } + #[test] fn object_from_str_with_invalid_input() { Asn1Object::from_str("NOT AN OID") @@ -766,4 +1004,101 @@ mod tests { &[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01], ); } + + #[test] + #[cfg(not(boringssl))] + fn asn1_type_type() { + let null = null_mut(); + unsafe { + // Create an ASN.1 type object + let s = CString::new("IA5STRING:Hello Test").unwrap(); + cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + let s_ptr = s.as_ptr() as *const _; + } else { + let s_ptr = s.as_ptr() as *mut _; + } + } + let at: Asn1Type = cvt_p(ffi::ASN1_generate_v3(s_ptr, null)) + .map(|p| Asn1Type::from_ptr(p)) + .unwrap(); + assert_eq!(at.as_ref().typ(), Asn1TagValue::IA5STRING); + } + } + + // Check (deprecated) `pub const Asn1Type::...` et al. + #[test] + #[cfg(not(boringssl))] + #[allow(deprecated)] + fn asn1_type_type_compatibility() { + let null = null_mut(); + unsafe { + // Create an ASN.1 type object + let s = CString::new("UTF8String:Hällö Test").unwrap(); + cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + let s_ptr = s.as_ptr() as *const _; + } else { + let s_ptr = s.as_ptr() as *mut _; + } + } + let at: Asn1Type = cvt_p(ffi::ASN1_generate_v3(s_ptr, null)) + .map(|p| Asn1Type::from_ptr(p)) + .unwrap(); + assert_eq!(at.as_ref().typ(), Asn1TagValue::UTF8STRING); + } + } + + #[test] + #[cfg(not(boringssl))] + fn asn1_string_from_asn1_type() { + let null = null_mut(); + unsafe { + // Create an ASN.1 type object + let s = CString::new("PRINTABLESTRING:Hello Test").unwrap(); + cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + let s_ptr = s.as_ptr() as *const _; + } else { + let s_ptr = s.as_ptr() as *mut _; + } + } + let at: Asn1Type = cvt_p(ffi::ASN1_generate_v3(s_ptr, null)) + .map(|p| Asn1Type::from_ptr(p)) + .unwrap(); + assert_eq!(at.as_ref().typ(), Asn1TagValue::PRINTABLESTRING); + // Get string content from Asn1Type + let asn1stringref: &Asn1StringRef = Asn1StringRef::from_asn1type(at.as_ref()).unwrap(); + let osslstring: OpensslString = asn1stringref.as_utf8().unwrap(); + let string: &str = osslstring.as_ref(); + assert_eq!("Hello Test", string); + } + } + + #[test] + #[cfg(not(boringssl))] + fn asn1_octet_string_from_asn1_type() { + let null = null_mut(); + unsafe { + // Create an ASN.1 type object + let s = CString::new("FORMAT:ASCII,OCTETSTRING:1234567890").unwrap(); + cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + let s_ptr = s.as_ptr() as *const _; + } else { + let s_ptr = s.as_ptr() as *mut _; + } + } + let at: Asn1Type = cvt_p(ffi::ASN1_generate_v3(s_ptr, null)) + .map(|p| Asn1Type::from_ptr(p)) + .unwrap(); + assert_eq!(at.as_ref().typ(), Asn1TagValue::OCTET_STRING); + // Get string content from Asn1Type + let asn1octetstringref: &Asn1OctetStringRef = + Asn1OctetStringRef::from_asn1type(at.as_ref()).unwrap(); + let stringdata: Vec = Vec::from(asn1octetstringref.as_slice()); + let string = String::from_utf8(stringdata).unwrap(); + assert_eq!("1234567890", string); + } + } } diff --git a/openssl/src/bio.rs b/openssl/src/bio.rs index 6a72552adc..3ba703b46b 100644 --- a/openssl/src/bio.rs +++ b/openssl/src/bio.rs @@ -21,7 +21,7 @@ impl<'a> MemBioSlice<'a> { pub fn new(buf: &'a [u8]) -> Result, ErrorStack> { ffi::init(); - assert!(buf.len() <= c_int::max_value() as usize); + assert!(buf.len() <= c_int::MAX as usize); let bio = unsafe { cvt_p(BIO_new_mem_buf( buf.as_ptr() as *const _, @@ -37,6 +37,21 @@ impl<'a> MemBioSlice<'a> { } } +// A reference to an OpenSSL memory BIO (binary IO). +#[cfg(not(boringssl))] +pub struct MemBioRef(*mut ffi::BIO); + +#[cfg(not(boringssl))] +impl MemBioRef { + pub fn as_ptr(&self) -> *mut ffi::BIO { + self.0 + } + + pub unsafe fn from_ptr(bio: *mut ffi::BIO) -> MemBioRef { + MemBioRef(bio) + } +} + pub struct MemBio(*mut ffi::BIO); impl Drop for MemBio { diff --git a/openssl/src/symm.rs b/openssl/src/symm.rs index 911a7ab2e7..9666cec10c 100644 --- a/openssl/src/symm.rs +++ b/openssl/src/symm.rs @@ -1248,6 +1248,7 @@ mod tests { } #[test] + #[cfg(not(ossl300))] fn test_des_ede3_cbc() { let pt = "54686973206973206120746573742e"; let ct = "6f2867cfefda048a4046ef7e556c7132"; diff --git a/openssl/src/x509/extension.rs b/openssl/src/x509/extension.rs index ebbea1c885..5bf108f96e 100644 --- a/openssl/src/x509/extension.rs +++ b/openssl/src/x509/extension.rs @@ -16,6 +16,7 @@ //! //! let extension: X509Extension = bc.build().unwrap(); //! ``` +use cfg_if::cfg_if; use std::fmt::Write; use crate::error::ErrorStack; @@ -218,22 +219,84 @@ impl KeyUsage { } } -/// An extension consisting of a list of usages indicating purposes -/// for which the certificate public key can be used for. -pub struct ExtendedKeyUsage { - critical: bool, - server_auth: bool, - client_auth: bool, - code_signing: bool, - email_protection: bool, - time_stamping: bool, - ms_code_ind: bool, - ms_code_com: bool, - ms_ctl_sign: bool, - ms_sgc: bool, - ms_efs: bool, - ns_sgc: bool, - other: Vec, +#[cfg(not(boringssl))] +impl From for KeyUsage { + fn from(flags: u32) -> Self { + let mut ku = KeyUsage::new(); + if flags & ffi::X509v3_KU_DIGITAL_SIGNATURE > 0 { + ku.digital_signature(); + } + if flags & ffi::X509v3_KU_NON_REPUDIATION > 0 { + ku.non_repudiation(); + } + if flags & ffi::X509v3_KU_KEY_ENCIPHERMENT > 0 { + ku.key_encipherment(); + } + if flags & ffi::X509v3_KU_DATA_ENCIPHERMENT > 0 { + ku.data_encipherment(); + } + if flags & ffi::X509v3_KU_KEY_AGREEMENT > 0 { + ku.key_agreement(); + } + if flags & ffi::X509v3_KU_KEY_CERT_SIGN > 0 { + ku.key_cert_sign(); + } + if flags & ffi::X509v3_KU_CRL_SIGN > 0 { + ku.crl_sign(); + } + if flags & ffi::X509v3_KU_ENCIPHER_ONLY > 0 { + ku.encipher_only(); + } + if flags & ffi::X509v3_KU_DECIPHER_ONLY > 0 { + ku.decipher_only(); + } + ku + } +} + +cfg_if! { + if #[cfg(ossl110)] { + /// An extension consisting of a list of usages indicating purposes + /// for which the certificate public key can be used for. + pub struct ExtendedKeyUsage { + critical: bool, + server_auth: bool, + client_auth: bool, + code_signing: bool, + email_protection: bool, + time_stamping: bool, + ocsp_signing: bool, + ms_code_ind: bool, + ms_code_com: bool, + ms_ctl_sign: bool, + ms_sgc: bool, + ms_efs: bool, + ns_sgc: bool, + dvcs: bool, + any_extended_key_usage: bool, + other: Vec, + } + } else { + /// An extension consisting of a list of usages indicating purposes + /// for which the certificate public key can be used for. + pub struct ExtendedKeyUsage { + critical: bool, + server_auth: bool, + client_auth: bool, + code_signing: bool, + email_protection: bool, + time_stamping: bool, + ocsp_signing: bool, + ms_code_ind: bool, + ms_code_com: bool, + ms_ctl_sign: bool, + ms_sgc: bool, + ms_efs: bool, + ns_sgc: bool, + dvcs: bool, + other: Vec, + } + } } impl Default for ExtendedKeyUsage { @@ -243,22 +306,50 @@ impl Default for ExtendedKeyUsage { } impl ExtendedKeyUsage { - /// Construct a new `ExtendedKeyUsage` extension. - pub fn new() -> ExtendedKeyUsage { - ExtendedKeyUsage { - critical: false, - server_auth: false, - client_auth: false, - code_signing: false, - email_protection: false, - time_stamping: false, - ms_code_ind: false, - ms_code_com: false, - ms_ctl_sign: false, - ms_sgc: false, - ms_efs: false, - ns_sgc: false, - other: vec![], + cfg_if! { + if #[cfg(ossl110)] { + /// Construct a new `ExtendedKeyUsage` extension. + pub fn new() -> ExtendedKeyUsage { + ExtendedKeyUsage { + critical: false, + server_auth: false, + client_auth: false, + code_signing: false, + email_protection: false, + time_stamping: false, + ocsp_signing: false, + ms_code_ind: false, + ms_code_com: false, + ms_ctl_sign: false, + ms_sgc: false, + ms_efs: false, + ns_sgc: false, + dvcs: false, + any_extended_key_usage: false, + other: vec![], + } + } + } else { + /// Construct a new `ExtendedKeyUsage` extension. + pub fn new() -> ExtendedKeyUsage { + ExtendedKeyUsage { + critical: false, + server_auth: false, + client_auth: false, + code_signing: false, + email_protection: false, + time_stamping: false, + ocsp_signing: false, + ms_code_ind: false, + ms_code_com: false, + ms_ctl_sign: false, + ms_sgc: false, + ms_efs: false, + ns_sgc: false, + dvcs: false, + other: vec![], + } + } } } @@ -298,6 +389,12 @@ impl ExtendedKeyUsage { self } + /// Sets the `OCSPSigning` flag to `true`. + pub fn ocsp_signing(&mut self) -> &mut ExtendedKeyUsage { + self.ocsp_signing = true; + self + } + /// Sets the `msCodeInd` flag to `true`. pub fn ms_code_ind(&mut self) -> &mut ExtendedKeyUsage { self.ms_code_ind = true; @@ -334,6 +431,22 @@ impl ExtendedKeyUsage { self } + /// Sets the `DVCS` flag to `true`. + pub fn dvcs(&mut self) -> &mut ExtendedKeyUsage { + self.dvcs = true; + self + } + + cfg_if! { + if #[cfg(ossl110)] { + /// Sets the `anyExtendedKeyUsage` flag to `true`. + pub fn any_extended_key_usage(&mut self) -> &mut ExtendedKeyUsage { + self.any_extended_key_usage = true; + self + } + } + } + /// Sets a flag not already defined. pub fn other(&mut self, other: &str) -> &mut ExtendedKeyUsage { self.other.push(other.to_owned()); @@ -355,12 +468,24 @@ impl ExtendedKeyUsage { "emailProtection", ); append(&mut value, &mut first, self.time_stamping, "timeStamping"); + append(&mut value, &mut first, self.ocsp_signing, "OCSPSigning"); append(&mut value, &mut first, self.ms_code_ind, "msCodeInd"); append(&mut value, &mut first, self.ms_code_com, "msCodeCom"); append(&mut value, &mut first, self.ms_ctl_sign, "msCTLSign"); append(&mut value, &mut first, self.ms_sgc, "msSGC"); append(&mut value, &mut first, self.ms_efs, "msEFS"); append(&mut value, &mut first, self.ns_sgc, "nsSGC"); + append(&mut value, &mut first, self.dvcs, "DVCS"); + cfg_if! { + if #[cfg(ossl110)] { + append( + &mut value, + &mut first, + self.any_extended_key_usage, + "anyExtendedKeyUsage" + ); + } + } for other in &self.other { append(&mut value, &mut first, true, other); } diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index 514935c8cb..1e54d882f3 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -9,7 +9,7 @@ use cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; -use libc::{c_int, c_long, c_uint}; +use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_void}; use std::cmp::{self, Ordering}; use std::error::Error; use std::ffi::{CStr, CString}; @@ -18,12 +18,16 @@ use std::marker::PhantomData; use std::mem; use std::path::Path; use std::ptr; +use std::ptr::null_mut; use std::slice; use std::str; use crate::asn1::{ - Asn1BitStringRef, Asn1IntegerRef, Asn1ObjectRef, Asn1StringRef, Asn1TimeRef, Asn1Type, + Asn1BitStringRef, Asn1IntegerRef, Asn1Object, Asn1ObjectRef, Asn1OctetStringRef, Asn1String, + Asn1StringRef, Asn1TagValue, Asn1TimeRef, Asn1TypeRef, }; +#[cfg(ossl110)] +use crate::bio::MemBio; use crate::bio::MemBioSlice; use crate::conf::ConfRef; use crate::error::ErrorStack; @@ -450,6 +454,34 @@ impl X509Ref { } } + /// Returns this certificate's key usage extension value, if it exists. + #[corresponds(X509_get_ext_d2i)] + pub fn key_usage(&self) -> Option<&Asn1BitStringRef> { + unsafe { + let ptr = ffi::X509_get_ext_d2i( + self.as_ptr(), + ffi::NID_key_usage, + ptr::null_mut(), + ptr::null_mut(), + ); + Asn1BitStringRef::from_const_ptr_opt(ptr as *const _) + } + } + + /// Returns this certificate's extended key usage extension value, if it exists. + #[corresponds(X509_get_ext_d2i)] + pub fn extended_key_usage(&self) -> Option> { + unsafe { + let ptr = ffi::X509_get_ext_d2i( + self.as_ptr(), + ffi::NID_ext_key_usage, + ptr::null_mut(), + ptr::null_mut(), + ); + Stack::from_ptr_opt(ptr as *mut _) + } + } + #[corresponds(X509_get_pubkey)] pub fn public_key(&self) -> Result, ErrorStack> { unsafe { @@ -572,6 +604,62 @@ impl X509Ref { } } + /// Returns the certificate's extensions. + #[corresponds(X509_get0_extensions)] + #[cfg(ossl110)] + pub fn extensions(&self) -> Result<&StackRef, ErrorStack> { + unsafe { + let result = ffi::X509_get0_extensions(self.as_ptr() as *const _); + if result.is_null() { + return Err(ErrorStack::get()); + } + Ok(StackRef::from_const_ptr(result)) + } + } + + /// Returns the location of an extension within a certificate. + #[corresponds(X509_get_ext_by_NID)] + pub fn get_extension_by_nid(&self, nid: &Nid) -> Option { + unsafe { + let pos: i32 = ffi::X509_get_ext_by_NID( + self.as_ptr(), + nid.as_raw(), + -1, // start search from first extension + ); + if pos == -1 { + None + } else { + Some(pos) + } + } + } + + /// Returns the X509 extension at position `pos` in an X509 certificate. + pub fn get_extension(&self, pos: i32) -> Result<&X509ExtensionRef, ErrorStack> { + unsafe { + let ptr = cvt_p(ffi::X509_get_ext(self.as_ptr(), pos as c_int))?; + Ok(X509ExtensionRef::from_ptr(ptr)) + } + } + + /// Returns the certificates key usage extension flags. If the extension is not present in the + /// certificate, 0 will be returned. + /// Note: this does not include the critical flag. + #[cfg(ossl110)] + #[corresponds(X509_get_key_usage)] + pub fn key_usage_flags(&self) -> u32 { + unsafe { ffi::X509_get_key_usage(self.as_ptr()) } + } + + /// Returns the certificates extended key usage extension flags. If the extension is not + /// present in the certificate, 0 will be returned. + /// Note: this does not include the critical flag. + #[cfg(ossl110)] + #[corresponds(X509_get_extended_key_usage)] + pub fn extended_key_usage_flags(&self) -> u32 { + unsafe { ffi::X509_get_extended_key_usage(self.as_ptr()) } + } + to_pem! { /// Serializes the certificate into a PEM-encoded X509 structure. /// @@ -726,8 +814,28 @@ impl fmt::Debug for X509 { if let Ok(public_key) = &self.public_key() { debug_struct.field("public_key", public_key); }; - // TODO: Print extensions once they are supported on the X509 struct. - + cfg_if! { if #[cfg(ossl110)] { + unsafe { + let extensions = ffi::X509_get0_extensions(self.as_ptr() as *const _); + let title = CString::new("X509 Extensions").unwrap(); + if !extensions.is_null() { + if let Ok(bio) = MemBio::new() { + let result = cvt(ffi::X509V3_extensions_print( + bio.as_ptr(), + title.as_ptr() as *const _, + extensions, + 0, + 4, + )); + if result.is_ok() { + if let Ok(ext_str) = String::from_utf8(bio.get_buf().to_vec()) { + debug_struct.field("X509 Extensions", &ext_str); + } + } + } + } + } + }}; debug_struct.finish() } } @@ -774,6 +882,75 @@ impl PartialEq for X509 { impl Eq for X509 {} +foreign_type_and_impl_send_sync! { + type CType = ffi::X509_ATTRIBUTE; + fn drop = ffi::X509_ATTRIBUTE_free; + + /// Permit additional fields to be added to an `X509` v3 certificate. + pub struct X509Attribute; + /// Reference to `X509Attribute`. + pub struct X509AttributeRef; +} + +impl Stackable for X509Attribute { + type StackType = ffi::stack_st_X509_ATTRIBUTE; +} + +impl X509Attribute { + /// Creates an X509 attribute, which can be added to X509 certificates, signing requests and + /// PKCS7 messages. + /// + /// The attribute type is derived from the ASN1 string value. So be sure to use + /// Asn1String::type_new() for strings other than octet strings. + /// + pub fn from_string(nid: Nid, value: Asn1String) -> Result { + unsafe { + let asn1_type = cvt(ffi::ASN1_STRING_type(value.as_ptr()))?; + let attribute = cvt_p(ffi::X509_ATTRIBUTE_create( + nid.as_raw(), + asn1_type, + value.as_ptr() as *mut c_void, + )); + #[allow(clippy::forget_copy)] + mem::forget(value); // Asn1String does not implement the Copy trait, so clippy is wrong here. + attribute.map(X509Attribute) + } + } + + /// Creates an X509 attribute from an `Asn1Object`. + pub fn from_object(nid: Nid, value: Asn1Object) -> Result { + unsafe { + let asn1_type = Asn1TagValue::OBJECT; + let attribute = cvt_p(ffi::X509_ATTRIBUTE_create( + nid.as_raw(), + asn1_type.as_raw(), + value.as_ptr() as *mut c_void, + )); + #[allow(clippy::forget_copy)] + mem::forget(value); // Asn1String does not implement the Copy trait, so clippy is wrong here. + attribute.map(X509Attribute) + } + } +} + +impl X509AttributeRef { + /// Get object id (NID) of attribute + pub fn object(&self) -> Result<&Asn1ObjectRef, ErrorStack> { + unsafe { + let object_ptr = cvt_p(ffi::X509_ATTRIBUTE_get0_object(self.as_ptr()))?; + Ok(Asn1ObjectRef::from_ptr(object_ptr)) + } + } + + /// Get an item from the list of `ASN1_TYPE`s. + pub fn typ(&self, idx: isize) -> Result<&Asn1TypeRef, ErrorStack> { + unsafe { + let type_ptr = cvt_p(ffi::X509_ATTRIBUTE_get0_type(self.as_ptr(), idx as c_int))?; + Ok(Asn1TypeRef::from_ptr(type_ptr)) + } + } +} + /// A context object required to construct certain `X509` extension values. pub struct X509v3Context<'a>(ffi::X509V3_CTX, PhantomData<(&'a X509Ref, &'a ConfRef)>); @@ -834,7 +1011,7 @@ impl X509Extension { pub fn new_nid( conf: Option<&ConfRef>, context: Option<&X509v3Context<'_>>, - name: Nid, + nid: Nid, value: &str, ) -> Result { let value = CString::new(value).unwrap(); @@ -842,10 +1019,52 @@ impl X509Extension { ffi::init(); let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr); let context = context.map_or(ptr::null_mut(), X509v3Context::as_ptr); - let name = name.as_raw(); + let nid = nid.as_raw(); let value = value.as_ptr() as *mut _; - cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context, name, value)).map(X509Extension) + cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context, nid, value)).map(X509Extension) + } + } + + /// Create a new X509 extension with OID `oid`. The raw value is used instead of a config + /// string as in `new()` and `new_nid()`. + pub fn create_by_obj( + critical: bool, + oid: &Asn1ObjectRef, + value: &[u8], + ) -> Result { + let ex = null_mut(); + let mut octet_string = Asn1String::type_new(Asn1TagValue::OCTET_STRING)?; + octet_string.set(value)?; + unsafe { + cvt_p(ffi::X509_EXTENSION_create_by_OBJ( + ex, + oid.as_ptr(), + c_int::from(critical), + octet_string.as_ptr() as *mut ffi::ASN1_OCTET_STRING, + )) + .map(X509Extension) + } + } + + /// Create a new X509 extension with NID `nid`. The raw value is used instead of a config + /// string as in `new()` and `new_nid()`. + pub fn create_by_nid( + critical: bool, + nid: &Nid, + value: &[u8], + ) -> Result { + let ex = null_mut(); + let mut octet_string = Asn1String::type_new(Asn1TagValue::OCTET_STRING)?; + octet_string.set(value)?; + unsafe { + cvt_p(ffi::X509_EXTENSION_create_by_NID( + ex, + nid.as_raw(), + c_int::from(critical), + octet_string.as_ptr() as *mut ffi::ASN1_OCTET_STRING, + )) + .map(X509Extension) } } @@ -861,6 +1080,29 @@ impl X509Extension { } } +impl X509ExtensionRef { + /// Returns true, if the extension is marked as critical. + pub fn is_critical(&self) -> bool { + unsafe { ffi::X509_EXTENSION_get_critical(self.as_ptr()) == 1 } + } + + /// Returns the extension type. + pub fn object(&self) -> Result<&Asn1ObjectRef, ErrorStack> { + unsafe { + let ptr = cvt_p(ffi::X509_EXTENSION_get_object(self.as_ptr()))?; + Ok(Asn1ObjectRef::from_ptr(ptr)) + } + } + + /// Returns the extension data (DER). + pub fn data(&self) -> Result<&Asn1OctetStringRef, ErrorStack> { + unsafe { + let ptr = cvt_p(ffi::X509_EXTENSION_get_data(self.as_ptr()))?; + Ok(Asn1OctetStringRef::from_ptr(ptr)) + } + } +} + /// A builder used to construct an `X509Name`. pub struct X509NameBuilder(X509Name); @@ -919,7 +1161,7 @@ impl X509NameBuilder { &mut self, field: &str, value: &str, - ty: Asn1Type, + ty: Asn1TagValue, ) -> Result<(), ErrorStack> { unsafe { let field = CString::new(field).unwrap(); @@ -967,7 +1209,7 @@ impl X509NameBuilder { &mut self, field: Nid, value: &str, - ty: Asn1Type, + ty: Asn1TagValue, ) -> Result<(), ErrorStack> { unsafe { assert!(value.len() <= c_int::max_value() as usize); @@ -1073,6 +1315,14 @@ impl X509NameRef { to_der, ffi::i2d_X509_NAME } + + /// Compares the X509NameRef with an`other` X509NameRef + /// Returns 0 if equal. + #[corresponds(X509_NAME_cmp)] + #[allow(clippy::unnecessary_cast)] + pub fn cmp_with(&self, other: &X509NameRef) -> i32 { + unsafe { ffi::X509_NAME_cmp(self.as_ptr() as *const _, other.as_ptr() as *const _) as i32 } + } } impl fmt::Debug for X509NameRef { @@ -1258,6 +1508,38 @@ impl X509ReqBuilder { } } + /// Permits an attribute to be added to the certificate or certificate request. + pub fn add_attribute(&mut self, name: &str, value: &str) -> Result<(), ErrorStack> { + let name = CString::new(name).unwrap(); + let len = value.len(); + let value = CString::new(value).unwrap(); + unsafe { + cvt(ffi::X509_REQ_add1_attr_by_txt( + self.0.as_ptr(), + name.as_ptr() as *const c_char, + ffi::MBSTRING_UTF8, + value.as_ptr() as *const c_uchar, + len as c_int, + )) + .map(|_| ()) + } + } + + pub fn add_attribute_by_nid(&mut self, nid: Nid, value: &str) -> Result<(), ErrorStack> { + let len = value.len(); + let value = CString::new(value).unwrap(); + unsafe { + cvt(ffi::X509_REQ_add1_attr_by_NID( + self.0.as_ptr(), + nid.as_raw(), + ffi::MBSTRING_UTF8, + value.as_ptr() as *const c_uchar, + len as c_int, + )) + .map(|_| ()) + } + } + /// Sign the request using a private key. /// /// This corresponds to [`X509_REQ_sign`]. @@ -1412,6 +1694,18 @@ impl X509ReqRef { } } +impl fmt::Debug for X509Req { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut debug_struct = formatter.debug_struct("X509Req"); + debug_struct.field("version", &self.version()); + debug_struct.field("subject", &self.subject_name()); + if let Ok(public_key) = &self.public_key() { + debug_struct.field("public_key", public_key); + }; + debug_struct.finish() + } +} + /// The result of peer certificate verification. #[derive(Copy, Clone, PartialEq, Eq)] pub struct X509VerifyResult(c_int); diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs index 6a61b0ffc3..d62dab0576 100644 --- a/openssl/src/x509/tests.rs +++ b/openssl/src/x509/tests.rs @@ -1,3 +1,5 @@ +#[cfg(ossl110)] +use crate::asn1::Asn1Object; use std::cmp::Ordering; use crate::asn1::Asn1Time; @@ -615,6 +617,163 @@ fn test_name_cmp() { assert_eq!(Ordering::Greater, subject.try_cmp(issuer).unwrap()); } +#[cfg(ossl110)] +fn prepare_cert_builder() -> (X509Builder, PKey) { + let rsa = Rsa::generate(2048).unwrap(); + let pkey = PKey::from_rsa(rsa).unwrap(); + let mut name = X509Name::builder().unwrap(); + name.append_entry_by_nid(Nid::COMMONNAME, "Example Name") + .unwrap(); + let name = name.build(); + let mut builder = X509::builder().unwrap(); + builder.set_version(2).unwrap(); // 2 -> X509v3 + builder.set_subject_name(&name).unwrap(); + builder.set_issuer_name(&name).unwrap(); + builder.set_pubkey(&pkey).unwrap(); + (builder, pkey) +} + +#[test] +#[cfg(ossl110)] +#[cfg(not(boringssl))] +fn test_key_usage() { + // Create an X.509 certificate with an extended key usage extension. + let (mut builder, pkey) = prepare_cert_builder(); + builder + .append_extension( + KeyUsage::new() + .digital_signature() + .non_repudiation() + .key_encipherment() + .data_encipherment() + .key_agreement() + .key_cert_sign() + //.crl_sign() + .decipher_only() + .encipher_only() + .build() + .unwrap(), + ) + .unwrap(); + builder.sign(&pkey, MessageDigest::sha256()).unwrap(); + let cert = builder.build(); + + let ku_bit_string = cert.key_usage().unwrap(); + assert_eq!(ku_bit_string.len(), 2); + let mut ku_bits: u32 = 0; + ku_bits |= ku_bit_string.as_slice()[0] as u32; + ku_bits |= (ku_bit_string.as_slice()[1] as u32) << 8; + assert!(ku_bits & ffi::X509v3_KU_DIGITAL_SIGNATURE > 0); + assert!(ku_bits & ffi::X509v3_KU_NON_REPUDIATION > 0); + assert!(ku_bits & ffi::X509v3_KU_KEY_ENCIPHERMENT > 0); + assert!(ku_bits & ffi::X509v3_KU_DATA_ENCIPHERMENT > 0); + assert!(ku_bits & ffi::X509v3_KU_KEY_AGREEMENT > 0); + assert!(ku_bits & ffi::X509v3_KU_KEY_CERT_SIGN > 0); + assert_eq!(ku_bits & ffi::X509v3_KU_CRL_SIGN, 0); + assert!(ku_bits & ffi::X509v3_KU_ENCIPHER_ONLY > 0); + assert!(ku_bits & ffi::X509v3_KU_DECIPHER_ONLY > 0); +} + +#[test] +#[cfg(ossl110)] +fn test_key_usage_data() { + // Create an X.509 certificate with an extended key usage extension. + let (mut builder, pkey) = prepare_cert_builder(); + builder + .append_extension(KeyUsage::new().key_cert_sign().build().unwrap()) + .unwrap(); + builder.sign(&pkey, MessageDigest::sha256()).unwrap(); + let cert = builder.build(); + + let ku_ext_pos = cert.get_extension_by_nid(&Nid::KEY_USAGE).unwrap(); + let ku_ext = cert.get_extension(ku_ext_pos).unwrap(); + assert!(!ku_ext.is_critical()); + assert_eq!( + ku_ext.object().unwrap(), + Asn1Object::from_nid(&Nid::KEY_USAGE).unwrap().as_ref() + ); + assert_eq!( + ku_ext.data().unwrap().as_slice(), + [0x03, 0x02, 0x02, 0x04,] // BIT STRING (6 bit) 000001 + ); +} + +#[test] +#[cfg(ossl110)] +fn test_extended_key_usage() { + // Create an X.509 certificate with an extended key usage extension. + let (mut builder, pkey) = prepare_cert_builder(); + builder + .append_extension( + ExtendedKeyUsage::new() + .critical() + .server_auth() + .build() + .unwrap(), + ) + .unwrap(); + builder.sign(&pkey, MessageDigest::sha256()).unwrap(); + let cert = builder.build(); + + let asn1obj_stack = cert.extended_key_usage().unwrap(); + assert_eq!(asn1obj_stack.get(0).unwrap().nid(), Nid::SERVER_AUTH) +} + +#[test] +#[cfg(ossl110)] +fn test_extended_key_usage_data() { + // Create an X.509 certificate with an extended key usage extension. + let (mut builder, pkey) = prepare_cert_builder(); + builder + .append_extension( + ExtendedKeyUsage::new() + .critical() + .server_auth() + .build() + .unwrap(), + ) + .unwrap(); + builder.sign(&pkey, MessageDigest::sha256()).unwrap(); + let cert = builder.build(); + + let eku_ext_pos = cert.get_extension_by_nid(&Nid::EXT_KEY_USAGE).unwrap(); + let eku_ext = cert.get_extension(eku_ext_pos).unwrap(); + assert!(eku_ext.is_critical()); + assert_eq!( + eku_ext.object().unwrap(), + Asn1Object::from_nid(&Nid::EXT_KEY_USAGE).unwrap().as_ref() + ); + assert_eq!( + eku_ext.data().unwrap().as_slice(), + [ + 0x30, 0x0a, // SEQUENCE LENGTH=10 + 0x06, 0x08, // OBJECT IDENTIFIER LENGTH=8 + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01 // 1.3.6.1.5.5.7.3.1 (serverAuth) + ] + ); +} + +#[test] +#[cfg(ossl110)] +fn test_extended_key_usage_flags() { + // Create an X.509 certificate with an extended key usage extension. + let (mut builder, pkey) = prepare_cert_builder(); + builder + .append_extension( + ExtendedKeyUsage::new() + .critical() + .client_auth() + .build() + .unwrap(), + ) + .unwrap(); + builder.sign(&pkey, MessageDigest::sha256()).unwrap(); + let cert = builder.build(); + let eku_flags = cert.extended_key_usage_flags(); + assert!(eku_flags & ffi::XKU_SSL_SERVER == 0); + assert!(eku_flags & ffi::XKU_SSL_CLIENT == ffi::XKU_SSL_CLIENT); +} + #[test] #[cfg(any(ossl102, libressl261))] fn test_verify_param_set_time_fails_verification() { diff --git a/systest/build.rs b/systest/build.rs index e54438114b..02c820b3e7 100644 --- a/systest/build.rs +++ b/systest/build.rs @@ -108,7 +108,10 @@ fn main() { || s.starts_with("CRYPTO_EX_") }); cfg.skip_struct(|s| { - s == "ProbeResult" || s == "X509_OBJECT_data" // inline union + s == "ProbeResult" || + s == "X509_OBJECT_data" || // inline union + s == "PKCS7_data" || + s == "ASN1_TYPE_value" }); cfg.skip_fn(move |s| { s == "CRYPTO_memcmp" || // uses volatile @@ -128,7 +131,9 @@ fn main() { cfg.skip_field_type(|s, field| { (s == "EVP_PKEY" && field == "pkey") || // union (s == "GENERAL_NAME" && field == "d") || // union - (s == "X509_OBJECT" && field == "data") // union + (s == "X509_OBJECT" && field == "data") || // union + (s == "PKCS7" && field == "d") || // union + (s == "ASN1_TYPE" && field == "value") // union }); cfg.skip_signededness(|s| { s.ends_with("_cb") From d4b37fa9df2836e9ee270e9dda737ee42c2d6b70 Mon Sep 17 00:00:00 2001 From: Bernd Krietenstein Date: Fri, 13 Jan 2023 16:28:10 +0100 Subject: [PATCH 03/19] Removed `MemBioRef`, which is not needed, yet. --- openssl/src/bio.rs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/openssl/src/bio.rs b/openssl/src/bio.rs index 3ba703b46b..ab59beb107 100644 --- a/openssl/src/bio.rs +++ b/openssl/src/bio.rs @@ -37,21 +37,6 @@ impl<'a> MemBioSlice<'a> { } } -// A reference to an OpenSSL memory BIO (binary IO). -#[cfg(not(boringssl))] -pub struct MemBioRef(*mut ffi::BIO); - -#[cfg(not(boringssl))] -impl MemBioRef { - pub fn as_ptr(&self) -> *mut ffi::BIO { - self.0 - } - - pub unsafe fn from_ptr(bio: *mut ffi::BIO) -> MemBioRef { - MemBioRef(bio) - } -} - pub struct MemBio(*mut ffi::BIO); impl Drop for MemBio { From 27de92a59152eba1887219d38c923d926c4e5bbe Mon Sep 17 00:00:00 2001 From: Bernd Krietenstein Date: Fri, 13 Jan 2023 16:42:51 +0100 Subject: [PATCH 04/19] Added PKCS7 functionality --- openssl/src/bio.rs | 15 + openssl/src/pkcs7.rs | 666 +++++++++++++++++++++++++++++++++++++- openssl/test/cert2.pem | 26 ++ openssl/test/root-ca2.key | 54 ++++ openssl/test/root-ca2.pem | 31 ++ 5 files changed, 785 insertions(+), 7 deletions(-) create mode 100644 openssl/test/cert2.pem create mode 100644 openssl/test/root-ca2.key create mode 100644 openssl/test/root-ca2.pem diff --git a/openssl/src/bio.rs b/openssl/src/bio.rs index ab59beb107..3ba703b46b 100644 --- a/openssl/src/bio.rs +++ b/openssl/src/bio.rs @@ -37,6 +37,21 @@ impl<'a> MemBioSlice<'a> { } } +// A reference to an OpenSSL memory BIO (binary IO). +#[cfg(not(boringssl))] +pub struct MemBioRef(*mut ffi::BIO); + +#[cfg(not(boringssl))] +impl MemBioRef { + pub fn as_ptr(&self) -> *mut ffi::BIO { + self.0 + } + + pub unsafe fn from_ptr(bio: *mut ffi::BIO) -> MemBioRef { + MemBioRef(bio) + } +} + pub struct MemBio(*mut ffi::BIO); impl Drop for MemBio { diff --git a/openssl/src/pkcs7.rs b/openssl/src/pkcs7.rs index ae4571db85..d8433a5e07 100644 --- a/openssl/src/pkcs7.rs +++ b/openssl/src/pkcs7.rs @@ -1,19 +1,147 @@ use bitflags::bitflags; use foreign_types::{ForeignType, ForeignTypeRef}; -use libc::c_int; +use libc::{c_int, c_void}; use std::mem; use std::ptr; -use crate::bio::{MemBio, MemBioSlice}; +use crate::asn1::{Asn1IntegerRef, Asn1Object, Asn1OctetStringRef, Asn1TypeRef}; +use crate::bio::{MemBio, MemBioRef, MemBioSlice}; use crate::error::ErrorStack; +use crate::hash::MessageDigest; +use crate::nid::Nid; use crate::pkey::{HasPrivate, PKeyRef}; -use crate::stack::{Stack, StackRef}; +use crate::stack::{Stack, StackRef, Stackable}; use crate::symm::Cipher; +use crate::util::ForeignTypeRefExt; use crate::x509::store::X509StoreRef; -use crate::x509::{X509Ref, X509}; +use crate::x509::{X509AlgorithmRef, X509Attribute, X509NameRef, X509Ref, X509}; use crate::{cvt, cvt_p}; use openssl_macros::corresponds; +foreign_type_and_impl_send_sync! { + type CType = ffi::PKCS7_SIGNER_INFO; + fn drop = ffi::PKCS7_SIGNER_INFO_free; + + /// A PKCS#7 SignerInfo structure. + pub struct Pkcs7SignerInfo; + + /// Reference to `Pkcs7SignerInfo` + pub struct Pkcs7SignerInfoRef; +} + +impl Pkcs7SignerInfo { + pub fn as_ptr(&self) -> *mut ffi::PKCS7_SIGNER_INFO { + self.0 + } +} + +impl Pkcs7SignerInfoRef { + /// Set signed attributes in a PKCS#7 structure. + /// + /// `attributes` is a stack of the attributes to be added. + /// + #[corresponds(PKCS7_set_signed_attributes)] + pub fn set_signed_attributes( + &self, + attributes: &StackRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::PKCS7_set_signed_attributes( + self.as_ptr(), + attributes.as_ptr(), + ))?; + Ok(()) + } + } + + /// Returns the issuer's subject name. + /// + /// This corresponds to `PKCS7_SIGNER_INFO`'s `issuer_and_serial.issuer` field.` + pub fn subject_name(&self) -> &X509NameRef { + unsafe { + let ias = (*self.as_ptr()).issuer_and_serial; + assert!(!ias.is_null()); + + let issuer = (*ias).issuer; + X509NameRef::from_const_ptr_opt(issuer).expect("subject name must not be null") + } + } + + /// Returns the issuer's serial number. + /// + /// This corresponds to `PKCS7_SIGNER_INFO`'s `issuer_and_serial.serial` field. + pub fn serial_number(&self) -> &Asn1IntegerRef { + unsafe { + let ias = (*self.as_ptr()).issuer_and_serial; + assert!(!ias.is_null()); + + let serial = (*ias).serial; + Asn1IntegerRef::from_const_ptr_opt(serial).expect("serial number must not be null") + } + } + + /// Returns the signature's digest algorithm. + pub fn digest_algorithm(&self) -> &X509AlgorithmRef { + unsafe { + let mut algor = ptr::null_mut(); + ffi::PKCS7_SIGNER_INFO_get0_algs( + self.as_ptr(), + ptr::null_mut(), + &mut algor, + ptr::null_mut(), + ); + + X509AlgorithmRef::from_const_ptr_opt(algor).expect("digest algorithm must not be null") + } + } + + /// Returns the signature's digest encryption algorithm. + pub fn digest_encryption_algorithm(&self) -> &X509AlgorithmRef { + unsafe { + let mut algor = ptr::null_mut(); + ffi::PKCS7_SIGNER_INFO_get0_algs( + self.as_ptr(), + ptr::null_mut(), + ptr::null_mut(), + &mut algor, + ); + + X509AlgorithmRef::from_const_ptr_opt(algor) + .expect("digest encryption algorithm must not be null") + } + } + + /// Returns the raw signature. + /// + /// This corresponds to `PKCS7_SIGNER_INFO`'s `enc_digest` field. + pub fn signature(&self) -> &Asn1OctetStringRef { + unsafe { + // ASN1_OCTET_STRING is a typedef of ASN1_STRING + let ptr = (*self.as_ptr()).enc_digest as *mut ffi::ASN1_OCTET_STRING; + Asn1OctetStringRef::from_const_ptr_opt(ptr).expect("signature must not be null") + } + } + + /// Get an authenticated (signed) attribute + pub fn get_signed_attribute(&self, nid: Nid) -> Result<&Asn1TypeRef, ErrorStack> { + unsafe { + let type_ptr = cvt_p(ffi::PKCS7_get_signed_attribute(self.as_ptr(), nid.as_raw()))?; + Ok(Asn1TypeRef::from_ptr(type_ptr)) + } + } +} + +impl Stackable for Pkcs7SignerInfo { + type StackType = ffi::stack_st_PKCS7_SIGNER_INFO; +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::PKCS7_SIGNED; + fn drop = ffi::PKCS7_SIGNED_free; + pub struct Pkcs7Signed; + pub struct Pkcs7SignedRef; +} + foreign_type_and_impl_send_sync! { type CType = ffi::PKCS7; fn drop = ffi::PKCS7_free; @@ -51,6 +179,16 @@ bitflags! { } impl Pkcs7 { + /// Create a new an empty PKCS#7 object. + /// + #[corresponds(PKCS7_new)] + pub fn new() -> Result { + unsafe { + let pkcs7 = cvt_p(ffi::PKCS7_new()).map(Pkcs7)?; + Ok(pkcs7) + } + } + from_pem! { /// Deserializes a PEM-encoded PKCS#7 signature /// @@ -269,7 +407,7 @@ impl Pkcs7Ref { ))?; // The returned stack is owned by the caller, but the certs inside are not! Our stack interface can't deal - // with that, so instead we just manually bump the refcount of the certs so that the whole stack is properly + // with that, so instead we just manually bump up the refcount of the certs so that the whole stack is properly // owned. let stack = Stack::::from_ptr(ptr); for cert in &stack { @@ -279,17 +417,287 @@ impl Pkcs7Ref { Ok(stack) } } + + /// Set the type of a PKCS#7 structure + /// + /// `nid` is type's Nid. Allowed values are + /// - Nid::PKCS7_SIGNED + /// - Nid::PKCS7_DATA + /// - Nid::PKCS7_SIGNEDANDENVELOPED + /// - Nid::PKCS7_ENVELOPED + /// - Nid::PKCS7_ENCRYPTED + /// - Nid::PKCS7_DIGEST + /// + #[corresponds(PKCS7_set_type)] + /// + pub fn set_type(&mut self, nid: Nid) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::PKCS7_set_type(self.as_ptr(), nid.as_raw())).map(|_| ()) } + } + + /// Query the type of the Pkcs7Ref + #[corresponds(PKCS7_type_is_signed)] + pub fn is_signed(&self) -> bool { + unsafe { + let pkcs7: *mut ffi::PKCS7 = self.as_ptr(); + let pkcs7_type: Asn1Object = Asn1Object::from_ptr((*pkcs7).type_); + pkcs7_type.nid() == Nid::PKCS7_SIGNED + } + } + + /// Query the type of the Pkcs7Ref + #[corresponds(PKCS7_type_is_encrypted)] + pub fn is_encrypted(&self) -> bool { + unsafe { + let pkcs7: *mut ffi::PKCS7 = self.as_ptr(); + let pkcs7_type: Asn1Object = Asn1Object::from_ptr((*pkcs7).type_); + pkcs7_type.nid() == Nid::PKCS7_ENCRYPTED + } + } + + /// Query the type of the Pkcs7Ref + #[corresponds(PKCS7_type_is_enveloped)] + pub fn is_enveloped(&self) -> bool { + unsafe { + let pkcs7: *mut ffi::PKCS7 = self.as_ptr(); + let pkcs7_type: Asn1Object = Asn1Object::from_ptr((*pkcs7).type_); + pkcs7_type.nid() == Nid::PKCS7_ENVELOPED + } + } + + /// Query the type of the Pkcs7Ref + #[corresponds(PKCS7_type_is_signedAndEnveloped)] + pub fn is_signed_and_enveloped(&self) -> bool { + unsafe { + let pkcs7: *mut ffi::PKCS7 = self.as_ptr(); + let pkcs7_type: Asn1Object = Asn1Object::from_ptr((*pkcs7).type_); + pkcs7_type.nid() == Nid::PKCS7_SIGNEDANDENVELOPED + } + } + + /// Query the type of the Pkcs7Ref + #[corresponds(PKCS7_type_is_data)] + pub fn is_data(&self) -> bool { + unsafe { + let pkcs7: *mut ffi::PKCS7 = self.as_ptr(); + let pkcs7_type: Asn1Object = Asn1Object::from_ptr((*pkcs7).type_); + pkcs7_type.nid() == Nid::PKCS7_DATA + } + } + + /// Query the type of the Pkcs7Ref + #[corresponds(PKCS7_type_is_digest)] + pub fn is_digest(&self) -> bool { + unsafe { + let pkcs7: *mut ffi::PKCS7 = self.as_ptr(); + let pkcs7_type: Asn1Object = Asn1Object::from_ptr((*pkcs7).type_); + pkcs7_type.nid() == Nid::PKCS7_DIGEST + } + } + + /// Add the signer certificate to a PKCS#7 structure + /// + /// `cert` is the signer's certificate. + /// + /// This method moves the ownership of `cert` to the PKCS7 structure. + /// + #[corresponds(PKCS7_add_certificate)] + /// + pub fn add_certificate(&self, cert: X509) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::PKCS7_add_certificate(self.as_ptr(), cert.as_ptr()))?; + mem::forget(cert); + Ok(()) + } + } + + /// Add signature information to the PKCS#7 structure. + /// + /// `cert` is the signer's certificate. `pkey` is the signer's (private) key. The optional + /// `algorithm` is the hash algorithm to be used. + /// + /// Returns a signer info structure, which can be used to add signed attributes. `cert` is not + /// consumed by this method (actually by `PKCS7_add_signature`), but `pkey` is. Create a clone + /// before calling `add_signature()`, if you need the key later.: + /// ``` + /// use openssl::hash::MessageDigest; + /// use openssl::pkcs7::Pkcs7; + /// use openssl::pkey::PKey; + /// use openssl::rsa::Rsa; + /// use openssl::x509::X509; + /// + /// let cert = X509::from_pem("-----BEGIN CERTIFICATE-----\n\ + /// MIICsTCCAZmgAwIBAgIBADANBgkqhkiG9w0BAQsFADAcMRowGAYDVQQDDBFJU0VD\n\ + /// IFRlc3QgUm9vdCBDQTAeFw0yMTEyMTUwOTM4MDVaFw0zMTEyMTMwOTM4MDVaMBwx\n\ + /// GjAYBgNVBAMMEUlTRUMgVGVzdCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOC\n\ + /// AQ8AMIIBCgKCAQEAt/0hnw55JtLXN4QjFhmkZ5mSSWQM3Zlz8+n9wq99jkDXEUJ8\n\ + /// YGoHxpBTb9vz4BXwVcR/3GWtdJ/h5VQinBYcZLwtz5iel4IC7pl40a8Kcco3hm6U\n\ + /// +qve9wz2YS8coQ1+zQ/pqKxDOLN60BYVkuxZeC4yrg8ovL5YftKzeVmFUjDJ/vdI\n\ + /// RyDScFpso2UoW6mklW/C94ciJH6O9m9dd2nWow1vUfHJlAEm8nPRxJRQH1bROxmc\n\ + /// 5hLHMjY5wFD/jo31jzxSeZxNhLTKDwn8nG1AGoHaudUNtAF25tzcU6nLKt6BIS+g\n\ + /// wqavL3kwp+1O/GwLPQb4xXmPs2+f2M08XMbVKwIDAQABMA0GCSqGSIb3DQEBCwUA\n\ + /// A4IBAQCKWDHBLlLPDmb1C5FOcJ/wqdwCzkbZEBs3qsiim5EDkt9+nqAfwyn0K+G8\n\ + /// BLJU+6kgeGW1Z0t3RqJdAq2r+7bfMVF8ubJ4zEu5xJAz9UppI4XZ8sZ8iS5rZ3hq\n\ + /// zjU+7G8Lnu9gEh18q5foi59Wx0jjMyIOWh8O9j3P0JjLxAR8v4rKlYp89/A+vWfb\n\ + /// TAj31LhWWTa0kiDP9Wd8cMWCjurv7Wq7U4K9gHMHpmUclxs1ByHtFdd61OXSdfBx\n\ + /// P1Te4tjxQpVo5zURkwOfZoOC6ikAOYoTAYNHP/qwsX2+KnL/JeGCcU4WtoWIp8mt\n\ + /// HkHgG5EBGoJmLFNFeQWB2yaqAhfD\n\ + /// -----END CERTIFICATE-----".as_bytes()).unwrap(); + /// let rsa = Rsa::generate(2048).unwrap(); + /// let signer_key = PKey::from_rsa(rsa).unwrap(); + /// let pkcs7 = Pkcs7::new().unwrap(); + /// let signer_info = &pkcs7.add_signature( + /// &cert, + /// &signer_key, + /// Some(MessageDigest::sha256()) + /// ); + /// ``` + /// + #[corresponds(PKCS7_add_signature)] + pub fn add_signature( + &self, + cert: &X509Ref, + pkey: &PKeyRef, + algorithm: Option, + ) -> Result<&Pkcs7SignerInfoRef, ErrorStack> + where + PT: HasPrivate, + { + unsafe { + cvt_p(ffi::PKCS7_add_signature( + self.as_ptr(), + cert.as_ptr(), + pkey.as_ptr(), + match algorithm { + Some(a) => a.as_ptr(), + None => ptr::null(), + }, + )) + .map(|ptr| Pkcs7SignerInfoRef::from_ptr(ptr)) + } + } + + /// Add the payload to a PKCS#7 structure. + /// The PKCS#7 structure must be either of type NID_pkcs7_signed or NID_pkcs7_digest. + /// Finalize a PKCS#7 structure. If the structure's type is `Nid::PKCS7_SIGNED` or + /// `Nid::PKCS7_SIGNEDANDENVELOPED`, it will be signed. + /// + /// The `content_type` must be a PKCS#7 typeAllowed values are + /// - Nid::PKCS7_SIGNED + /// - Nid::PKCS7_DATA + /// - Nid::PKCS7_SIGNEDANDENVELOPED + /// - Nid::PKCS7_ENVELOPED + /// - Nid::PKCS7_ENCRYPTED + /// - Nid::PKCS7_DIGEST + /// `content` is the payload of type `content_type`. + /// + pub fn add_content(&self, content_type: Nid, content: &[u8]) -> Result { + unsafe { + // Initialize content + cvt(ffi::PKCS7_content_new(self.as_ptr(), content_type.as_raw())).map(|_| ())?; + // Write content + let bcont_bio = ptr::null_mut(); + let bio = cvt_p(ffi::PKCS7_dataInit(self.as_ptr(), bcont_bio)) + .map(|ptr| MemBioRef::from_ptr(ptr))?; + if content.is_empty() { + // Empty content is allowed + Ok(bio) + } else { + let content_length = content.len() as c_int; + let len = ffi::BIO_write( + bio.as_ptr(), + content.as_ptr() as *const c_void, + content_length, + ); + if len == content_length { + Ok(bio) + } else { + Err(ErrorStack::get()) + } + } + } + } + + /// Finalize a PKCS#7 structure. If the structure's type is `Nid::PKCS7_SIGNED` or + /// `Nid::PKCS7_SIGNEDANDENVELOPED`, it will be signed. + /// + #[corresponds(PKCS7_dataFinal)] + pub fn finalize(&self, content_bio: &MemBioRef) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::PKCS7_dataFinal(self.as_ptr(), content_bio.as_ptr())).map(|_| ()) } + } + + /// Get the certificates stored to a PKCS#7 structure + /// + // Unfortunately, there is no corresponding function in openssl as for signer_info. Thus, + // we have to enter openssl's internal PKCS7 struct. This is also, what openssl does, when e.g. + // `openssl pkcs7 -in pkcs7.pem -print-certs` is called. + // + pub fn certificates(&self) -> Result, ErrorStack> { + unsafe { + let pkcs7: *mut ffi::PKCS7 = self.as_ptr(); + let pkcs7_type: Asn1Object = Asn1Object::from_ptr((*pkcs7).type_); + let cert_ptr: *mut ffi::stack_st_X509 = (*(*pkcs7).d.sign).cert; + let mut certs: Stack = Stack::new()?; + if !cert_ptr.is_null() { + let pkcs7_certs: Stack = match pkcs7_type.nid() { + Nid::PKCS7_SIGNED => Stack::from_ptr((*(*pkcs7).d.sign).cert), + Nid::PKCS7_SIGNEDANDENVELOPED => { + Stack::from_ptr((*(*pkcs7).d.signed_and_enveloped).cert) + } + _ => Stack::new()?, + }; + + for cert_ref in &pkcs7_certs { + // Note: `to_owned()` increases the openssl reference count of the cert, so the + // stack becomes an additional owner of the certs. + let cert = cert_ref.to_owned(); + certs.push(cert)?; + } + mem::forget(pkcs7_certs); // Otherwise, certs would be removed from self, when this method returns + } + Ok(certs) + } + } + + /// Retrieve the SignerInfo entries from the PKCS#7 structure. + #[corresponds(PKCS7_get_signer_info)] + pub fn signer_info(&self) -> Option<&StackRef> { + unsafe { + let ptr = ffi::PKCS7_get_signer_info(self.as_ptr()); + if ptr.is_null() { + return None; + } + + // The returned value is not owned by the caller. + Some(StackRef::::from_ptr(ptr)) + } + } } #[cfg(test)] mod tests { + #[cfg(ossl111)] + use crate::asn1::Asn1TagValue; + use cfg_if::cfg_if; + cfg_if! { + if #[cfg(ossl111)] { + pub use crate::asn1::{Asn1Integer, Asn1Object, Asn1String, Asn1Time, Asn1Type}; + use crate::pkcs7::{Pkcs7, Pkcs7Flags, Pkcs7SignerInfoRef}; + use crate::x509::{X509Attribute, X509Name, X509Req, X509}; + } else { + use crate::asn1::{Asn1Integer, Asn1Time}; + use crate::pkcs7::{Pkcs7, Pkcs7Flags}; + use crate::x509::{X509Name, X509Req, X509}; + } + } + use crate::bn::{BigNum, MsbOption}; use crate::hash::MessageDigest; - use crate::pkcs7::{Pkcs7, Pkcs7Flags}; + use crate::nid::Nid; use crate::pkey::PKey; + use crate::rsa::Rsa; use crate::stack::Stack; use crate::symm::Cipher; + use crate::x509::extension::{ExtendedKeyUsage, KeyUsage, SubjectAlternativeName}; use crate::x509::store::X509StoreBuilder; - use crate::x509::X509; #[test] fn encrypt_decrypt_test() { @@ -434,6 +842,45 @@ mod tests { assert_eq!(signer_certs.len(), 1); let signer_digest = signer_certs[0].digest(MessageDigest::sha256()).unwrap(); assert_eq!(*cert_digest, *signer_digest); + + let signer_info = pkcs7.signer_info().unwrap(); + assert_eq!(signer_info.len(), 1); + assert_eq!( + signer_info[0].serial_number().to_bn().unwrap(), + cert.serial_number().to_bn().unwrap() + ); + + let cert_subject = cert + .subject_name() + .entries() + .map(|e| (e.data().as_slice(), e.object().nid())) + .collect::>(); + let signer_subject = cert + .subject_name() + .entries() + .map(|e| (e.data().as_slice(), e.object().nid())) + .collect::>(); + assert_eq!(cert_subject, signer_subject); + + cfg_if! { + if #[cfg(any(ossl102, libressl310))] { + assert_eq!( + signer_info[0].digest_algorithm().object().nid(), + Nid::SHA256 + ); + } else { + assert_eq!( + signer_info[0].digest_algorithm().object().nid(), + Nid::SHA1 + ); + } + } + assert_eq!( + signer_info[0].digest_encryption_algorithm().object().nid(), + Nid::RSAENCRYPTION + ); + + assert!(!signer_info[0].signature().is_empty()); } #[test] @@ -443,4 +890,209 @@ mod tests { assert!(result.is_err()); } + + #[test] + fn enveloped_pkcs7() { + fn get_serial() -> Asn1Integer { + let mut big_number = BigNum::new().unwrap(); + big_number.rand(128, MsbOption::MAYBE_ZERO, true).unwrap(); + Asn1Integer::from_bn(&big_number).unwrap() + } + + // Create an X.509 certificate for encryption + let days: u32 = 365 * 10; + let not_before = Asn1Time::days_from_now(0).unwrap(); + let not_after = Asn1Time::days_from_now(days).unwrap(); + let serial = get_serial(); + let rsa = Rsa::generate(2048).unwrap(); + let pkey = PKey::from_rsa(rsa).unwrap(); + let mut name = X509Name::builder().unwrap(); + name.append_entry_by_nid(Nid::COMMONNAME, "Example Name") + .unwrap(); + name.append_entry_by_nid(Nid::COUNTRYNAME, "DE").unwrap(); + name.append_entry_by_nid(Nid::STATEORPROVINCENAME, "Example State") + .unwrap(); + name.append_entry_by_nid(Nid::LOCALITYNAME, "Example Town") + .unwrap(); + name.append_entry_by_nid(Nid::ORGANIZATIONNAME, "Example Company") + .unwrap(); + name.append_entry_by_nid(Nid::ORGANIZATIONALUNITNAME, "Example Unit") + .unwrap(); + name.append_entry_by_nid(Nid::PKCS9_EMAILADDRESS, "info@example.com") + .unwrap(); + let name = name.build(); + let mut builder = X509::builder().unwrap(); + builder.set_version(2).unwrap(); // 2 -> X509v3 + builder.set_serial_number(&serial).unwrap(); + builder.set_subject_name(&name).unwrap(); + builder.set_issuer_name(&name).unwrap(); + builder.set_not_before(not_before.as_ref()).unwrap(); + builder.set_not_after(not_after.as_ref()).unwrap(); + builder.set_pubkey(&pkey).unwrap(); + builder.sign(&pkey, MessageDigest::sha256()).unwrap(); + let encryption_cert = builder.build(); + + // Create a CSR + let challenge_password = "chaIIenge-passsw0rd"; + let mut builder = X509Req::builder().unwrap(); + builder.set_version(0).unwrap(); // 0x00 -> Version: 1 + builder.set_subject_name(&name).unwrap(); + // set SANs + // set KeyUsage to digital signature and key encipherment + let extensions = { + let context = builder.x509v3_context(None); + let mut ext_stack = Stack::new().unwrap(); + ext_stack + .push( + KeyUsage::new() + .digital_signature() + .key_encipherment() + .build() + .unwrap(), + ) + .unwrap(); + ext_stack + .push(ExtendedKeyUsage::new().server_auth().build().unwrap()) + .unwrap(); + ext_stack + .push( + SubjectAlternativeName::new() + .dns("server.example.com") + .build(&context) + .unwrap(), + ) + .unwrap(); + ext_stack + .push( + SubjectAlternativeName::new() + .ip("127.0.0.1") + .build(&context) + .unwrap(), + ) + .unwrap(); + ext_stack + .push( + SubjectAlternativeName::new() + .ip("::1") + .build(&context) + .unwrap(), + ) + .unwrap(); + ext_stack + }; + builder.add_extensions(&extensions).unwrap(); + builder + .add_attribute_by_nid(Nid::PKCS9_CHALLENGEPASSWORD, challenge_password) + .unwrap(); + builder.set_pubkey(&pkey).unwrap(); + builder.sign(&pkey, MessageDigest::sha256()).unwrap(); + let csr = builder.build(); + + // Create an enveloped PKCS #7 object + let cipher = Cipher::aes_256_cbc(); + let mut encryption_certs: Stack = Stack::new().unwrap(); + encryption_certs.push(encryption_cert).unwrap(); + + // Encrypt the CSR -> pkcsPKIEnvelope (PKCS#7 envelopedData) + let enveloped_data: Pkcs7 = Pkcs7::encrypt( + &encryption_certs, + &csr.to_der().unwrap(), + cipher, + Pkcs7Flags::BINARY, + ) + .unwrap(); + + enveloped_data.to_pem().unwrap(); + + assert!(enveloped_data.is_enveloped()); + } + + #[test] + #[cfg(ossl111)] + fn signed_pkcs7() { + fn get_serial() -> Asn1Integer { + let mut big_number = BigNum::new().unwrap(); + big_number.rand(128, MsbOption::MAYBE_ZERO, true).unwrap(); + Asn1Integer::from_bn(&big_number).unwrap() + } + + // Make signer key + let rsa = Rsa::generate(2048).unwrap(); + let signer_key = PKey::from_rsa(rsa).unwrap(); + + // Make signer cert + let days: u32 = 365 * 10; + let not_before = Asn1Time::days_from_now(0).unwrap(); + let not_after = Asn1Time::days_from_now(days).unwrap(); + let serial = get_serial(); + let mut name = X509Name::builder().unwrap(); + name.append_entry_by_nid(Nid::COMMONNAME, "test.example.com") + .unwrap(); + let name = name.build(); + let mut builder = X509::builder().unwrap(); + builder.set_version(2).unwrap(); // 2 -> X509v3 + builder.set_serial_number(&serial).unwrap(); + builder.set_subject_name(&name).unwrap(); + builder.set_issuer_name(&name).unwrap(); + builder.set_not_before(not_before.as_ref()).unwrap(); + builder.set_not_after(not_after.as_ref()).unwrap(); + builder.set_pubkey(&signer_key).unwrap(); + builder.sign(&signer_key, MessageDigest::sha256()).unwrap(); + let signer_cert = builder.build(); + + // Now make signed pkcs7 + let mut signed_pkcs7 = Pkcs7::new().unwrap(); + + // Set PKCS7 type + signed_pkcs7.set_type(Nid::PKCS7_SIGNED).unwrap(); + + // Add client certificate + let signer_cert_clone = signer_cert.clone(); + signed_pkcs7.add_certificate(signer_cert_clone).unwrap(); + + // Add signature + let signer_info: &Pkcs7SignerInfoRef = signed_pkcs7 + .add_signature(&signer_cert, &signer_key, Some(MessageDigest::sha256())) + .unwrap(); + + // Add some signed attributes + let mut attributes: Stack = Stack::new().unwrap(); + + // Add an octet string + let sender_nonce_id: Nid = + Nid::create("2.16.840.1.113733.1.9.5", "senderNonce", "senderNonce").unwrap(); + let mut sender_nonce_asn1: Asn1String = Asn1String::new().unwrap(); + let sender_nonce: [u8; 3] = [1, 2, 3]; + sender_nonce_asn1.set(&sender_nonce).unwrap(); + let sender_nonce_attr = + X509Attribute::from_string(sender_nonce_id, sender_nonce_asn1).unwrap(); + attributes.push(sender_nonce_attr).unwrap(); + + // Add a printable string + let trans_id: Nid = Nid::create("2.16.840.1.113733.1.9.7", "transId", "transId").unwrap(); + let mut transaction_id_asn1 = Asn1String::type_new(Asn1TagValue::PRINTABLESTRING).unwrap(); + transaction_id_asn1.set("tid_1".as_bytes()).unwrap(); + let transaction_id_attr = + X509Attribute::from_string(trans_id, transaction_id_asn1).unwrap(); + attributes.push(transaction_id_attr).unwrap(); + + // Add an ASN1 object + let asn1object = Asn1Object::from_nid(&Nid::PKCS7_DATA).unwrap(); + let mut content_type_asn1: Asn1String = Asn1String::new().unwrap(); + content_type_asn1.set(asn1object.as_slice()).unwrap(); + let content_type_attr = + X509Attribute::from_string(Nid::PKCS9_CONTENTTYPE, content_type_asn1).unwrap(); + attributes.push(content_type_attr).unwrap(); + + signer_info.set_signed_attributes(&attributes).unwrap(); + + // Sign + let data: [u8; 1] = [42]; + let bio = signed_pkcs7.add_content(Nid::PKCS7_DATA, &data).unwrap(); + + // Finalize + signed_pkcs7.finalize(&bio).unwrap(); + + assert!(signed_pkcs7.is_signed()); + } } diff --git a/openssl/test/cert2.pem b/openssl/test/cert2.pem new file mode 100644 index 0000000000..379925429d --- /dev/null +++ b/openssl/test/cert2.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEeDCCAmCgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBIMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHc2NlcC1jYTEQMA4GA1UECxMHU0NFUCBDQTEVMBMGA1UEAxMMVEVT +VCBTQ0VQIENBMB4XDTIyMDUxMDE0MTkyOFoXDTIzMDUxMDE0MTkyOFowFjEUMBIG +A1UEAxMLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQC5pJF1s1FTy3x7oJTgjxBPD37fDQPDoZLQSeFSChjgDRdCg13+xPVqrJ+NcR9G +MJdhXAN7R9AoyJiI/467haeuC7WHqWlfER07KChwLr7RkRDPc+TOvMnKmKqvWZIO +gsFcg+lQdNnSQHHamepsAGi2AaWRrEsODek3pBxEYw/jSngrLxxNKYTInmYyP2p1 +N2kHnnQXfTdxBGdlXzjdJwr8g73ixk3uHacZvsmrYo++dHEVNO1nCqoF6za4fzdF +UzYXuPJIggzYW/VbJ0NHcnqhDfk+u+4hyyUXbdTunAKP3KhsVqnmO7RGPm6rVPga +D/UFSQgsDBuSfN/J05jLvYgBAgMBAAGjgZ4wgZswDgYDVR0PAQH/BAQDAgSwMB0G +A1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMB0GA1Ud +DgQWBBQ2CawZBB9YZSEbGB672WF3BMWJgDAfBgNVHSMEGDAWgBTMVT45k6oLXwnI ++GIfyIgMhFxsDjAcBgNVHREEFTATggtleGFtcGxlLmNvbYcEfwAAATANBgkqhkiG +9w0BAQsFAAOCAgEAZiRvPbLNukTFax2l78V7soE16+3PXMo0jIlLI2hgRccFNVwi +RlW93omxenGNbFvTqiWQhwBVP8goq36nhizmue00Vfp+ETtcOMGCrB1hm0OKjGvg +3al0Sc/u7BAULJd3RBwVmm8pI2Fxace5n9o5TZeY6FnddA3gTIHuSaiUtQcAyP2p +FS1hhuySEx3zwPzTrbTtLwxC5xoDXJKL6N5YsLOsqInmxs0XYQtYQOjT29TvYtDz +kwhxpkguqSKIujLSuju4Y1fgy/zzMHrg2LlJdTreDhj0bWzHx1JFVu2vqrZ6ZLoU +Hm5JLgm8DrOsoF8RpS07WCFugAvFFJZ4Qi/Nn/zKXVvF3ubtqGrytlgAtPJpee0R +aLE7CzeGlxfRNi9g/U/e11Z4feT8B+yvJdzccaFjdotCD230OH2VSAEq7ghz/UxU +Z1kddq72/9+E4Y6Ldwimyg8+YW/HxtJDHOMzcfGVo8/x2gLCUMPRN4XHTkLlog+m +YZESXJQje1h3YSaz2zc6KfpPa3l7gxAgj0HKCQOmpaqdwI70owmLPUNfJyllt8aN +CY14iCHHwJCud1ujr9ig9qTQJYjfruelnF7DYAi0iesb8pFx1DkVLsTJS7RT4xDL +P7BpFXAcQtQsZZeOAbbWh2jRhKYaLvZe77MyKUsqpi/xN+ypFySon9kvgQQ= +-----END CERTIFICATE----- diff --git a/openssl/test/root-ca2.key b/openssl/test/root-ca2.key new file mode 100644 index 0000000000..9564e7489f --- /dev/null +++ b/openssl/test/root-ca2.key @@ -0,0 +1,54 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,0aed91e6d3417888 + +9NXYqh5ekxHNhHeyhXJloEtdBaSjWTUNEVnJiNr0/Lz0DAqzSFV8sZ927Bf1g8Ef +jYGkFbESZA7xQ4pDRac081WthvVVzayw1v6wz4yA7vRJaZi3Ixi7nECnrCg7JH1v +mWXyTgPvPQjCB726fuJt9oGcvS0iGQyLlLp3MDDEA4c10hxONiV+ocSFb9OcAdVr +k/v7g2tBHoV6dlDo/YRxizJmezpQfWm59lMS51dPNNyrln7EaMrC0CPzuPE0vhoa +92VKbyE0CoXBuYoLNrTl9EXVGhURsxDbVrHzfhFaC/izpyPy79dSNMpWJMENH6UR +Le2C8/UpDtrsq9lECE8iUd0OgUSKVCo4RQK7hMaFiLS+rsqfeMcUA+861FTUhC+W +JfZJLVJOED3e5f9deLybLODZkn2Go9B2jSWsAxqhmk6hbQxWs/DJRFPKdvaYTRmD +IscRm1ClWtq3RWVI4ND10QdKU1285Mo/iGBa1+6m7Gqd+fSyGs1ccHIXT5Ekez1O +nEwkUJ7nGExhrCxBMiCE//YeN54jFRbnWuB+O7uyywQUQyidM1ZpqvL5SV/FzR3M +tgvjcsGcgwhLg4QZKQRVr/zw8VVP35os/BBAzXWI6BWEJGeTUd9sdMVAXVq/HuTD +J8bAnDSDkw4+pMeoIoFEFVACpjvOSLY547jaJvVQuOI4/tEuie8sLq8xo1sjFP/j +UIWxJ8JZpU4df0NlZzM24InDT2TI0YWMzQU5OsjCP3e0cuJgSrdsgo5TvFU7Cz9Q +B4v00//8knEnjQdbT1uCuCHbayliVmKss3g2oH9M8YlWG/VThSnbg4RuGWlofZw+ +zUBaIZHL2L132kOcvOs22J3GyC0vG0OhrjbLDZjaqeD7WjI0jzsak5OluI/7t/e2 +ExZnteAgNTZgqqv7MNyXP9NMYmjS2D32wslSP67evMpWiP0TN95IvdOsVwDwbinA +X9BYNBk7GuIwW+GZCaYnsVeOo7TRPBKDbGsEm9uBMnwTItyqXg+Tq4mU/HiLIMb2 +8w6lzr+9b2uVTINd1WQL8C179dVT3LpwZq5HCTfcQfJYEmNPsZHBO+tSR/UH71+9 +iWTWuuM0P728zq4Mk6u2Mj3x/WIq00kO/i2+MX/Gqux+KJUjD3f84Gu5N3Jz6/aD +PrTtq5Z5e/QrhLJa4I3UO8OB30i7G0QFXbxAtU8bjJvd7mCWw4Z7ykJbHK9aq45D +y7oxgahKsjgZVyWzD3qnnXKRsBO6ih0BxfTu4H0neylQkVGGaJEXQFlxoNkBEKU9 +TjEZdHxIR0HoahOC9/J+lAkxRo5K7lYRj/FfORt4ql5zIebp97CTy13wLgLOOohK +OKbQsIwmKccrVozIQ8hd8ubnBwurQhiSqfk4X54Elk89kHJZLsRtmfg+G1Jfvr1b +l6Ycv5b99Uf05Mr85BgZJfO5GLdkKZ+sBTmSDr/hMxdmjMqJzUQiflD9WkGDYvs+ ++poFRK31YUvTvg438akyboe+QmBzn+S/dWJ4Nu9dxiQL12iTP+NoFTD/ZXs5TJXQ +XJxyF/pwxHx2DzSkeJkUvSSTyjZ5+Z55LsrCHsxtQiitklItjtFc/SMngnBtKQt1 +E2+1kPn63zs7HExu5CkGw40P+FahdO3hJKlpuUfoI1BidVwJAXLWvoUpDnWiZIdJ +Bhn8QFwoRNZxzTW9mYUFk+0sslg6RAn+hgdNJabVBBIepgf52E24DEwopvrT4lwV +7+WOhGIr8gXddEcInrq8wCmUpkMMLM2ZaXIi+meBshEWFuHL7voQvz04fI6xcNcE +Yk631Rk9q77F2IkCrQVoYnJvdyZkHFmiMnevj1q2wIsixTFXAmA574UYiNn5te+v +O3tHiJjskpPVTIgSTIl7WVSfLtuZlxvVloG104H5AbTx/Gz/VqFuoFpAewInA+yg +Ehex57VFurCTCGXIbrB4pvSYr1pr6WmwS/tQnx2MSo/nD+1g5Q/ZmF+/9PyZlrLP +ccu0j9D/LTRoBnw4sGlITKAmS++uk4RGlDTz8KYq7381YyP/bozS6+JxSTeEuo2k +2W92dnwmI6in/1acF6ptGzBrL9lU+yzdOtsuciBNf5YRFPIU/Y6yCNMOWiUcWdCm ++FoJa24GpJBkLSu4XpoX8ZVRI0lV2Ve9yMSBtyT6wpHYbAosajkeOGsZV3wGVc9+ +BQfcLGOaV1rXdr232bvEvhk9fC2I2+shGmJbWhL0iqzhJ2iGa3CFELZbyM0+pvDv +rvLoPIuhRjP+nmPYpDHuY6LpFz4YUnjbcaeNdhj81jMCfmwf6e4s5LtDEo9Vnn3X +5JGzdT/uJvI+A9w3qeCmzof2yHRnGEzkYnTB6Ui8VlWDkNzQ/fTYnEqB1pKPNCRi +qfYlsMPneyGsoP7A01xYbr9648dAVTr/95S9getpp9HtuLux8GXLa01OGM11xU7m +xX9PQADyN3/aukmWhJ/KZhRxSWaLJ45r6tRVWu6qgTHGn0gJ/4iwrPqQVl0CfFgw +008mMZ/UYJKN3XRKGRU7mrCbwnDupG918/VHeS35Elyst4nktmBw1KVCYsGc8zF6 +Rtcm+G4jIAtc5cqiICT45N28hrxgWYgnzLAPzzMesqQJJRrUENOgS+lNRXYtWbzN +t1qsaYOHCJa+IWSAzbmUbH9RuPTyBDDk8fc0CL8iHG7K/VybHNk+s3J7zd4uwjKK +XKNs3FG4E6DNnngDHybHHPhtjLtaZbsyzDNXzgOcXwVVxgzPwZrIanwEV960oGe4 +AWDouG6hmxiTBn0+vensuOssJnE3+2y32wfEgkZakZqJWy2YtQAlAGhko517mfYl +Pq9+dHuyAIpNB7JHvKvqEvUfjvFArdPfF8H1m+T9aUUWGvSwF526FBs57ygrGWfp +0aYw2sWrcopBFjWbBujR1KYYDA406DM1rHz/lniy1ruOakjBfWL2GqR/gCYT7nf9 +IxsMkBd7tc9FD0zA3UYZcaom9uI4ImkXPjFTQpQuG0JCvPuzfQHEhcJcRngflRKh +I8rzp9wUCO1u203+TlhczHO4fNjK1DXP6zGXszWcXto+amRo8MdJ547qgEWVmn8n +lmoOUgA7yD9BtMH0hG180i7JtAJNzN16CRdgG4MAbRgu/p1dTTwJ5lbgPT9VfaQH +-----END RSA PRIVATE KEY----- diff --git a/openssl/test/root-ca2.pem b/openssl/test/root-ca2.pem new file mode 100644 index 0000000000..e1646776b5 --- /dev/null +++ b/openssl/test/root-ca2.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFTTCCAzWgAwIBAgIBATANBgkqhkiG9w0BAQsFADBIMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHc2NlcC1jYTEQMA4GA1UECxMHU0NFUCBDQTEVMBMGA1UEAxMMVEVT +VCBTQ0VQIENBMB4XDTIyMDUxMDE0MTg1N1oXDTMyMDUxMDE0MTg1N1owSDELMAkG +A1UEBhMCVVMxEDAOBgNVBAoTB3NjZXAtY2ExEDAOBgNVBAsTB1NDRVAgQ0ExFTAT +BgNVBAMTDFRFU1QgU0NFUCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBAMFO5FgQBz2/MrhLvv7ho97kn3z/YBhMQc1WRuVYRdF54Jma3Pfvnn9d36/b +ZHn7JZc1M3DPczkAfetF+c3tiQS5SU8CjcuQAgWpH47sxtCYYhmjyY6J4ii+BL2u +iQQ6Eg1GAQqp100uW95qUm2DAupE0RqwyWKts54mjkA3NhPRYRMN4tVVELJf1RZ7 +E+Igyy1XQIFrFU6Ki6edACGRuZUdRvJR3d4r3LWUL0ylXSkTPIFmmTuiVykHPNCY +knksrsSN9tvqGox/LcYpXJ3s7ENDb6weGNCzg/zaO1FZKat9ZCORXN9Sosc3VtNh +eOaFRN3FybtVgPRf539SbC9WKpZIeHTMLx879Fuwga1h8WwB/yaQO4QlLc8i8g2u +Az9DBwpPC2c0HcpPIFzoXLR6kj465Lax08L2lK3QYL1DmdYcwhayi2lkZgaakij7 +Wd3UwztQcmYQzbVc0R/IDsZ5ibAFQszZEeP5qH9k8mUwrR6tAM7r1c+eCkov6vh6 +Rz4JoQqpZIISlgowYco+8NS1nhEs3P57XpPmuS6FMFLW5WYyYapJNKXbzgXaxech +4SStGgmIJOrIa0gWNXgbr0Rlr9/qZkADtO6X5W3TQcFmxWI4c0DuNGwT9VrlmPln +TeuDhr4xHH9fNVKr1NF9IUdb9vCCN++N+awdNuYbsT/Zma11AgMBAAGjQjBAMA4G +A1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTMVT45k6oL +XwnI+GIfyIgMhFxsDjANBgkqhkiG9w0BAQsFAAOCAgEAeAuvJy1r0HbF8R8gsRpP +RFPBrN7nZ9iMhMkLrO7tZgXzrQBVtO//2h6JZdT4QV2rjxzSyF4HuaWRxBdoey31 +dhCfUG3yCvR5sAuYCa0VV/urMGRj61n6Q16S8qt9PPF7UCEyFe/Kqld/4mNthiIH +fzPrtD8KPoc5z1XKnOG8KWliBkjtlprjSrYjwDuzy4RGlY2OWTnJcb3wOfw1r2sa +xK921+3ExzgQSfk/m2t1SB7eCCkbWr9lENkrUqtOj8N59ItR4ARBQA9Wr+6u8oq8 +wxC0tmjdNvNZwp7WnzOBKMKJIkHXa4URgfrDkV+gRdyIG1b+wdpCbEQpwip1l6Vr +6+LKchtBesXDlSr/gQGVYOYbnNdaGk3rNXB9s62TAKYBB3px/jxociJpjALpBYpr +ObXO6oYskDW2GHMh2dwpT3Mm2jg1P7MUmpTn/nVDHTAq8Ay2JoQMUxw9hBF+lLK8 +iLd0HDaXgkhQrpsLYP/98BlhGcAR/5KldOnAZn7W207h/uogxDUEzbnrd93GK3Sd +uuM9hoGgFo7uNcGborxNKwrHlrlfu1yHoTeiR8INO5WU9A/5wtopujX8I5/Lktw4 +MW7KJxskaChfU6FkL928vylvlbGcOseaiA1lhjRBr70SWDQa7O4xXJcZklZlMbil +YyZ1z7XyUBtBI2Vw1q/cj1U= +-----END CERTIFICATE----- From 6d6944767c30cd43fefec920eb29ef1acf4e55b9 Mon Sep 17 00:00:00 2001 From: Bernd Krietenstein Date: Fri, 13 Jan 2023 15:11:36 +0100 Subject: [PATCH 05/19] Prepared openssl-sys for pkcs7 and x509 extensions. --- openssl-sys/build/cfgs.rs | 3 + openssl-sys/src/handwritten/asn1.rs | 49 ++++- openssl-sys/src/handwritten/mod.rs | 2 + openssl-sys/src/handwritten/pkcs7.rs | 245 ++++++++++++++++++++++- openssl-sys/src/handwritten/types.rs | 16 +- openssl-sys/src/handwritten/x509.rs | 36 +++- openssl-sys/src/handwritten/x509_attr.rs | 60 ++++++ 7 files changed, 396 insertions(+), 15 deletions(-) create mode 100644 openssl-sys/src/handwritten/x509_attr.rs diff --git a/openssl-sys/build/cfgs.rs b/openssl-sys/build/cfgs.rs index d925d90ad7..960515f00f 100644 --- a/openssl-sys/build/cfgs.rs +++ b/openssl-sys/build/cfgs.rs @@ -31,6 +31,9 @@ pub fn get(openssl_version: Option, libressl_version: Option) -> Vec<& if libressl_version >= 0x2_09_01_00_0 { cfgs.push("libressl291"); } + if libressl_version >= 0x3_01_00_00_0 { + cfgs.push("libressl310"); + } if libressl_version >= 0x3_02_01_00_0 { cfgs.push("libressl321"); } diff --git a/openssl-sys/src/handwritten/asn1.rs b/openssl-sys/src/handwritten/asn1.rs index 844f9102a9..e866b1ea90 100644 --- a/openssl-sys/src/handwritten/asn1.rs +++ b/openssl-sys/src/handwritten/asn1.rs @@ -10,23 +10,60 @@ pub struct ASN1_ENCODING { extern "C" { pub fn ASN1_OBJECT_free(x: *mut ASN1_OBJECT); + pub fn OBJ_cmp(a: *const ASN1_OBJECT, b: *const ASN1_OBJECT) -> c_int; } +pub enum ASN1_OBJECT {} + stack!(stack_st_ASN1_OBJECT); +#[repr(C)] +pub struct ASN1_TYPE { + pub type_: c_int, + pub value: ASN1_TYPE_value, +} +#[repr(C)] +pub union ASN1_TYPE_value { + pub ptr: *mut c_char, + pub boolean: ASN1_BOOLEAN, + pub asn1_string: *mut ASN1_STRING, + pub object: *mut ASN1_OBJECT, + pub integer: *mut ASN1_INTEGER, + pub enumerated: *mut ASN1_ENUMERATED, + pub bit_string: *mut ASN1_BIT_STRING, + pub octet_string: *mut ASN1_OCTET_STRING, + pub printablestring: *mut ASN1_PRINTABLESTRING, + pub t61string: *mut ASN1_T61STRING, + pub ia5string: *mut ASN1_IA5STRING, + pub generalstring: *mut ASN1_GENERALSTRING, + pub bmpstring: *mut ASN1_BMPSTRING, + pub universalstring: *mut ASN1_UNIVERSALSTRING, + pub utctime: *mut ASN1_UTCTIME, + pub generalizedtime: *mut ASN1_GENERALIZEDTIME, + pub visiblestring: *mut ASN1_VISIBLESTRING, + pub utf8string: *mut ASN1_UTF8STRING, + /* + * set and sequence are left complete and still contain the set or + * sequence bytes + */ + pub set: *mut ASN1_STRING, + pub sequence: *mut ASN1_STRING, + pub asn1_value: *mut ASN1_VALUE, +} + extern "C" { pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING; #[cfg(any(ossl110, libressl273))] pub fn ASN1_STRING_get0_data(x: *const ASN1_STRING) -> *const c_uchar; #[cfg(any(all(ossl101, not(ossl110)), libressl))] pub fn ASN1_STRING_data(x: *mut ASN1_STRING) -> *mut c_uchar; - - pub fn ASN1_BIT_STRING_free(x: *mut ASN1_BIT_STRING); - + pub fn ASN1_STRING_new() -> *mut ASN1_STRING; pub fn ASN1_STRING_free(x: *mut ASN1_STRING); pub fn ASN1_STRING_length(x: *const ASN1_STRING) -> c_int; + pub fn ASN1_STRING_set(x: *mut ASN1_STRING, data: *const c_void, len_in: c_int) -> c_int; - pub fn ASN1_STRING_set(x: *mut ASN1_STRING, data: *const c_void, len: c_int) -> c_int; + pub fn ASN1_BIT_STRING_free(x: *mut ASN1_BIT_STRING); + pub fn ASN1_OCTET_STRING_free(x: *mut ASN1_OCTET_STRING); pub fn ASN1_GENERALIZEDTIME_free(tm: *mut ASN1_GENERALIZEDTIME); pub fn ASN1_GENERALIZEDTIME_print(b: *mut BIO, tm: *const ASN1_GENERALIZEDTIME) -> c_int; @@ -51,10 +88,14 @@ extern "C" { pub fn ASN1_TIME_set_string(s: *mut ASN1_TIME, str: *const c_char) -> c_int; #[cfg(ossl111)] pub fn ASN1_TIME_set_string_X509(s: *mut ASN1_TIME, str: *const c_char) -> c_int; + + pub fn ASN1_TYPE_free(x: *mut ASN1_TYPE); } const_ptr_api! { extern "C" { pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_uchar, s: #[const_ptr_if(any(ossl110, libressl280))] ASN1_STRING) -> c_int; + pub fn ASN1_STRING_type(x: #[const_ptr_if(any(ossl110, libressl280))] ASN1_STRING) -> c_int; + pub fn ASN1_generate_v3(str: #[const_ptr_if(any(ossl110, libressl280))] c_char, cnf: *mut X509V3_CTX) -> *mut ASN1_TYPE; } } diff --git a/openssl-sys/src/handwritten/mod.rs b/openssl-sys/src/handwritten/mod.rs index 28aa4aecd0..fea7549898 100644 --- a/openssl-sys/src/handwritten/mod.rs +++ b/openssl-sys/src/handwritten/mod.rs @@ -28,6 +28,7 @@ pub use self::stack::*; pub use self::tls1::*; pub use self::types::*; pub use self::x509::*; +pub use self::x509_attr::*; pub use self::x509_vfy::*; pub use self::x509v3::*; @@ -61,5 +62,6 @@ mod stack; mod tls1; mod types; mod x509; +mod x509_attr; mod x509_vfy; mod x509v3; diff --git a/openssl-sys/src/handwritten/pkcs7.rs b/openssl-sys/src/handwritten/pkcs7.rs index fc0239e7b8..2f76cab9c2 100644 --- a/openssl-sys/src/handwritten/pkcs7.rs +++ b/openssl-sys/src/handwritten/pkcs7.rs @@ -1,12 +1,195 @@ use libc::*; use *; -pub enum PKCS7_SIGNED {} -pub enum PKCS7_ENVELOPE {} -pub enum PKCS7_SIGN_ENVELOPE {} -pub enum PKCS7_DIGEST {} -pub enum PKCS7_ENCRYPT {} -pub enum PKCS7 {} +// use x509::stack_st_X509; +// use x509_attr::stack_st_X509_ATTRIBUTE; + +#[cfg(ossl300)] +#[repr(C)] +pub struct PKCS7_CTX { + libctx: *mut OSSL_LIB_CTX, + propq: *mut c_char, +} + +cfg_if! { + if #[cfg(any(ossl101, libressl251))] { + #[repr(C)] + pub struct PKCS7_SIGNED { + pub version: *mut ASN1_INTEGER, /* version 1 */ + pub md_algs: *mut stack_st_X509_ALGOR, /* md used */ + pub cert: *mut stack_st_X509, /* [ 0 ] */ + pub crl: *mut stack_st_X509_CRL, /* [ 1 ] */ + pub signer_info: *mut stack_st_PKCS7_SIGNER_INFO, + pub contents: *mut PKCS7, + } + } else { + pub enum PKCS7_SIGNED {} + } +} + +cfg_if! { + if #[cfg(any(ossl101, libressl251))] { + #[repr(C)] + pub struct PKCS7_ENC_CONTENT { + pub content_type: *mut ASN1_OBJECT, + pub algorithm: *mut X509_ALGOR, + pub enc_data: *mut ASN1_OCTET_STRING, /* [ 0 ] */ + pub cipher: *const EVP_CIPHER, + #[cfg(ossl300)] + pub ctx: *const PKCS7_CTX, + } + } else { + pub enum PKCS7_ENC_CONTENT {} + } +} + +cfg_if! { + if #[cfg(any(ossl101, libressl251))] { + #[repr(C)] + pub struct PKCS7_ENVELOPE { + pub version: *mut ASN1_INTEGER, /* version 0 */ + pub recipientinfo: *mut stack_st_PKCS7_RECIP_INFO, + pub enc_data: *mut PKCS7_ENC_CONTENT, + } + } else { + pub enum PKCS7_ENVELOPE {} + } +} + +cfg_if! { + if #[cfg(any(ossl101, libressl251))] { + #[repr(C)] + pub struct PKCS7_SIGN_ENVELOPE { + pub version: *mut ASN1_INTEGER, /* version 1 */ + pub md_algs: *mut stack_st_X509_ALGOR, /* md used */ + pub cert: *mut stack_st_X509, /* [ 0 ] */ + pub crl: *mut stack_st_X509_CRL, /* [ 1 ] */ + pub signer_info: *mut stack_st_PKCS7_SIGNER_INFO, + pub enc_data: *mut PKCS7_ENC_CONTENT, + pub recipientinfo: *mut stack_st_PKCS7_RECIP_INFO + } + } else { + pub enum PKCS7_SIGN_ENVELOPE {} + } +} + +cfg_if! { + if #[cfg(any(ossl101, libressl251))] { + #[repr(C)] + pub struct PKCS7_DIGEST { + pub version: *mut ASN1_INTEGER, /* version 0 */ + pub md: *mut X509_ALGOR, /* md used */ + pub contents: *mut PKCS7, + pub digest: *mut ASN1_OCTET_STRING, + } + } else { + pub enum PKCS7_DIGEST {} + } +} + +cfg_if! { + if #[cfg(any(ossl101, libressl251))] { + #[repr(C)] + pub struct PKCS7_ENCRYPT { + pub version: *mut ASN1_INTEGER, /* version 0 */ + pub enc_data: *mut PKCS7_ENC_CONTENT, + } + } else { + pub enum PKCS7_ENCRYPT {} + } +} + +extern "C" { + pub fn PKCS7_SIGNED_free(info: *mut PKCS7_SIGNED); + pub fn PKCS7_ENC_CONTENT_free(info: *mut PKCS7_ENC_CONTENT); + pub fn PKCS7_ENVELOPE_free(info: *mut PKCS7_ENVELOPE); + pub fn PKCS7_SIGN_ENVELOPE_free(info: *mut PKCS7_SIGN_ENVELOPE); + pub fn PKCS7_DIGEST_free(info: *mut PKCS7_DIGEST); + pub fn PKCS7_SIGNER_INFO_free(info: *mut PKCS7_SIGNER_INFO); +} + +cfg_if! { + if #[cfg(any(ossl101, libressl251))] { + #[repr(C)] + pub struct PKCS7 { + /* + * The following is non NULL if it contains ASN1 encoding of this + * structure + */ + pub asn1: *mut c_uchar, + pub length: c_long, + // # define PKCS7_S_HEADER 0 + // # define PKCS7_S_BODY 1 + // # define PKCS7_S_TAIL 2 + pub state: c_int, /* used during processing */ + pub detached: c_int, + pub type_: *mut ASN1_OBJECT, + /* content as defined by the type */ + /* + * all encryption/message digests are applied to the 'contents', leaving + * out the 'type' field. + */ + pub d: PKCS7_data, + #[cfg(ossl300)] + pub ctx: PKCS7_CTX, + } + #[repr(C)] + pub union PKCS7_data { + pub ptr: *mut c_char, + /* NID_pkcs7_data */ + pub data: *mut ASN1_OCTET_STRING, + /* NID_pkcs7_signed */ + pub sign: *mut PKCS7_SIGNED, + /* NID_pkcs7_enveloped */ + pub enveloped: *mut PKCS7_ENVELOPE, + /* NID_pkcs7_signedAndEnveloped */ + pub signed_and_enveloped: *mut PKCS7_SIGN_ENVELOPE, + /* NID_pkcs7_digest */ + pub digest: *mut PKCS7_DIGEST, + /* NID_pkcs7_encrypted */ + pub encrypted: *mut PKCS7_ENCRYPT, + /* Anything else */ + pub other: *mut ASN1_TYPE, + } + } else { + pub enum PKCS7 {} + } +} + +cfg_if! { + if #[cfg(any(ossl101, libressl))] { + #[repr(C)] + pub struct PKCS7_ISSUER_AND_SERIAL { + pub issuer: *mut X509_NAME, + pub serial: *mut ASN1_INTEGER, + } + } else { + pub enum PKCS7_ISSUER_AND_SERIAL {} + } +} + +cfg_if! { + if #[cfg(any(ossl101, libressl))] { + #[repr(C)] + pub struct PKCS7_SIGNER_INFO { + pub version: *mut ASN1_INTEGER, /* version 1 */ + pub issuer_and_serial: *mut PKCS7_ISSUER_AND_SERIAL, + pub digest_alg: *mut X509_ALGOR, + pub auth_attr: *mut stack_st_X509_ATTRIBUTE, /* [ 0 ] */ + pub digest_enc_alg: *mut X509_ALGOR, + pub enc_digest: *mut ASN1_OCTET_STRING, + pub unauth_attr: *mut stack_st_X509_ATTRIBUTE, /* [ 1 ] */ + pub pkey: *mut EVP_PKEY, /* The private key to sign with */ + #[cfg(ossl300)] + pub ctx: *const PKCS7_CTX, + } + } else { + pub enum PKCS7_SIGNER_INFO {} + } +} + +stack!(stack_st_PKCS7_SIGNER_INFO); +stack!(stack_st_PKCS7_RECIP_INFO); extern "C" { pub fn d2i_PKCS7(a: *mut *mut PKCS7, pp: *mut *const c_uchar, length: c_long) -> *mut PKCS7; @@ -15,6 +198,7 @@ extern "C" { const_ptr_api! { extern "C" { pub fn i2d_PKCS7(a: #[const_ptr_if(ossl300)] PKCS7, buf: *mut *mut u8) -> c_int; + pub fn i2d_PKCS7_bio(bio: *mut BIO, p7: #[const_ptr_if(ossl300)] PKCS7) -> c_int; } } @@ -67,4 +251,53 @@ extern "C" { ) -> c_int; pub fn SMIME_read_PKCS7(bio: *mut BIO, bcont: *mut *mut BIO) -> *mut PKCS7; + + pub fn PKCS7_new() -> *mut PKCS7; + + pub fn PKCS7_set_type(p7: *mut PKCS7, nid_pkcs7: c_int) -> c_int; + + pub fn PKCS7_add_certificate(p7: *mut PKCS7, x509: *mut X509) -> c_int; + + pub fn PKCS7_add_signature( + p7: *mut PKCS7, + x509: *mut X509, + pkey: *mut EVP_PKEY, + digest: *const EVP_MD, + ) -> *mut PKCS7_SIGNER_INFO; + + pub fn PKCS7_set_signed_attributes( + p7si: *mut PKCS7_SIGNER_INFO, + attributes: *mut stack_st_X509_ATTRIBUTE, + ) -> c_int; + + pub fn PKCS7_add_signed_attribute( + p7si: *mut PKCS7_SIGNER_INFO, + nid: c_int, + attrtype: c_int, + data: *mut c_void, + ) -> c_int; + + pub fn PKCS7_content_new(p7: *mut PKCS7, nid_pkcs7: c_int) -> c_int; + + pub fn PKCS7_dataInit(p7: *mut PKCS7, bio: *mut BIO) -> *mut BIO; + + pub fn PKCS7_dataFinal(p7: *mut PKCS7, bio: *mut BIO) -> c_int; + + pub fn PKCS7_get_signer_info(p7: *mut PKCS7) -> *mut stack_st_PKCS7_SIGNER_INFO; + + pub fn PKCS7_SIGNER_INFO_get0_algs( + si: *mut PKCS7_SIGNER_INFO, + pk: *mut *mut EVP_PKEY, + pdig: *mut *mut X509_ALGOR, + psig: *mut *mut X509_ALGOR, + ); +} + +const_ptr_api! { + extern "C" { + pub fn PKCS7_get_signed_attribute( + si: #[const_ptr_if(ossl300)] PKCS7_SIGNER_INFO, + nid: c_int + ) -> *mut ASN1_TYPE; + } } diff --git a/openssl-sys/src/handwritten/types.rs b/openssl-sys/src/handwritten/types.rs index 476578c051..addc599abb 100644 --- a/openssl-sys/src/handwritten/types.rs +++ b/openssl-sys/src/handwritten/types.rs @@ -3,14 +3,26 @@ use libc::*; #[allow(unused_imports)] use *; +#[derive(Copy, Clone)] +pub enum ASN1_BOOLEAN {} +pub enum ASN1_ENUMERATED {} pub enum ASN1_INTEGER {} pub enum ASN1_GENERALIZEDTIME {} pub enum ASN1_STRING {} pub enum ASN1_BIT_STRING {} pub enum ASN1_TIME {} -pub enum ASN1_TYPE {} pub enum ASN1_OBJECT {} pub enum ASN1_OCTET_STRING {} +pub enum ASN1_PRINTABLESTRING {} +pub enum ASN1_T61STRING {} +pub enum ASN1_IA5STRING {} +pub enum ASN1_GENERALSTRING {} +pub enum ASN1_BMPSTRING {} +pub enum ASN1_UNIVERSALSTRING {} +pub enum ASN1_UTCTIME {} +pub enum ASN1_VISIBLESTRING {} +pub enum ASN1_UTF8STRING {} +pub enum ASN1_VALUE {} pub enum bio_st {} // FIXME remove cfg_if! { @@ -325,6 +337,8 @@ cfg_if! { } } +stack!(stack_st_X509_ALGOR); + pub enum X509_LOOKUP_METHOD {} pub enum X509_NAME {} diff --git a/openssl-sys/src/handwritten/x509.rs b/openssl-sys/src/handwritten/x509.rs index 047f3df262..486f712c34 100644 --- a/openssl-sys/src/handwritten/x509.rs +++ b/openssl-sys/src/handwritten/x509.rs @@ -15,8 +15,6 @@ pub enum X509_EXTENSION {} stack!(stack_st_X509_EXTENSION); -stack!(stack_st_X509_ATTRIBUTE); - cfg_if! { if #[cfg(any(ossl110, libressl350))] { pub enum X509_REQ_INFO {} @@ -27,7 +25,7 @@ cfg_if! { pub version: *mut ::ASN1_INTEGER, pub subject: *mut ::X509_NAME, pubkey: *mut c_void, - pub attributes: *mut stack_st_X509_ATTRIBUTE, + pub attributes: *mut ::stack_st_X509_ATTRIBUTE, } } } @@ -271,9 +269,12 @@ extern "C" { pub fn X509_EXTENSION_free(ext: *mut X509_EXTENSION); + pub fn X509_ATTRIBUTE_free(attr: *mut ::X509_ATTRIBUTE); + pub fn X509_NAME_ENTRY_free(x: *mut X509_NAME_ENTRY); pub fn X509_NAME_new() -> *mut X509_NAME; + pub fn X509_NAME_cmp(x: *const X509_NAME, y: *const X509_NAME) -> c_int; pub fn X509_NAME_free(x: *mut X509_NAME); pub fn X509_new() -> *mut X509; @@ -359,6 +360,33 @@ const_ptr_api! { -> c_int; } } +extern "C" { + pub fn X509_REQ_get_attr_count(req: *const X509_REQ) -> c_int; + pub fn X509_REQ_get_attr_by_NID(req: *const X509_REQ, nid: c_int, lastpos: c_int) -> c_int; + pub fn X509_REQ_get_attr(req: *const X509_REQ, loc: c_int) -> *mut ::X509_ATTRIBUTE; + pub fn X509_REQ_delete_attr(req: *mut X509_REQ, loc: c_int) -> *mut ::X509_ATTRIBUTE; + pub fn X509_REQ_add1_attr_by_txt( + req: *mut X509_REQ, + attrname: *const c_char, + chtype: c_int, + bytes: *const c_uchar, + len: c_int, + ) -> c_int; + pub fn X509_REQ_add1_attr_by_NID( + req: *mut X509_REQ, + nid: c_int, + chtype: c_int, + bytes: *const c_uchar, + len: c_int, + ) -> c_int; + pub fn X509_REQ_add1_attr_by_OBJ( + req: *mut X509_REQ, + obj: *const ASN1_OBJECT, + chtype: c_int, + bytes: *const c_uchar, + len: c_int, + ) -> c_int; +} extern "C" { pub fn X509_set_pubkey(x: *mut X509, pkey: *mut EVP_PKEY) -> c_int; pub fn X509_REQ_verify(req: *mut X509_REQ, pkey: *mut EVP_PKEY) -> c_int; @@ -607,6 +635,7 @@ const_ptr_api! { pub fn X509_STORE_get0_objects(ctx: #[const_ptr_if(ossl300)] X509_STORE) -> *mut stack_st_X509_OBJECT; } } + #[cfg(any(ossl110, libressl270))] extern "C" { pub fn X509_OBJECT_get0_X509(x: *const X509_OBJECT) -> *mut X509; @@ -633,7 +662,6 @@ extern "C" { extern "C" { pub fn X509_cmp(a: *const X509, b: *const X509) -> c_int; - pub fn X509_NAME_cmp(a: *const X509_NAME, b: *const X509_NAME) -> c_int; pub fn X509_issuer_and_serial_cmp(a: *const X509, b: *const X509) -> c_int; pub fn X509_issuer_name_cmp(a: *const X509, b: *const X509) -> c_int; pub fn X509_subject_name_cmp(a: *const X509, b: *const X509) -> c_int; diff --git a/openssl-sys/src/handwritten/x509_attr.rs b/openssl-sys/src/handwritten/x509_attr.rs new file mode 100644 index 0000000000..b14be38619 --- /dev/null +++ b/openssl-sys/src/handwritten/x509_attr.rs @@ -0,0 +1,60 @@ +use libc::*; + +use *; + +pub enum X509_ATTRIBUTE {} + +stack!(stack_st_X509_ATTRIBUTE); + +extern "C" { + pub fn X509_ATTRIBUTE_new() -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_create( + nid: c_int, + atrtype: c_int, + value: *mut c_void, + ) -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_create_by_NID( + attr: *mut *mut X509_ATTRIBUTE, + nid: c_int, + atrtype: c_int, + data: *const c_void, + len: c_int, + ) -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_create_by_OBJ( + attr: *mut *mut X509_ATTRIBUTE, + obj: *const ASN1_OBJECT, + atrtype: c_int, + data: *const c_void, + len: c_int, + ) -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_create_by_txt( + attr: *mut *mut X509_ATTRIBUTE, + atrname: *const c_char, + atrtype: c_int, + bytes: *const c_uchar, + len: c_int, + ) -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_set1_object(attr: *mut X509_ATTRIBUTE, obj: *const ASN1_OBJECT) -> c_int; + pub fn X509_ATTRIBUTE_set1_data( + attr: *mut X509_ATTRIBUTE, + attrtype: c_int, + data: *const c_void, + len: c_int, + ) -> c_int; + pub fn X509_ATTRIBUTE_get0_data( + attr: *mut X509_ATTRIBUTE, + idx: c_int, + atrtype: c_int, + data: *mut c_void, + ) -> *mut c_void; + pub fn X509_ATTRIBUTE_get0_object(attr: *mut X509_ATTRIBUTE) -> *mut ASN1_OBJECT; + pub fn X509_ATTRIBUTE_get0_type(attr: *mut X509_ATTRIBUTE, idx: c_int) -> *mut ASN1_TYPE; + +} +const_ptr_api! { + extern "C" { + pub fn X509_ATTRIBUTE_count( + attr: #[const_ptr_if(any(ossl110, libressl291))] X509_ATTRIBUTE // const since OpenSSL v1.1.0 + ) -> c_int; + } +} From d2e30181e586929abf1ee93d5c8152f8d034385c Mon Sep 17 00:00:00 2001 From: Bernd Krietenstein Date: Fri, 13 Jan 2023 16:17:48 +0100 Subject: [PATCH 06/19] Fixed systest. --- systest/build.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/systest/build.rs b/systest/build.rs index e54438114b..02c820b3e7 100644 --- a/systest/build.rs +++ b/systest/build.rs @@ -108,7 +108,10 @@ fn main() { || s.starts_with("CRYPTO_EX_") }); cfg.skip_struct(|s| { - s == "ProbeResult" || s == "X509_OBJECT_data" // inline union + s == "ProbeResult" || + s == "X509_OBJECT_data" || // inline union + s == "PKCS7_data" || + s == "ASN1_TYPE_value" }); cfg.skip_fn(move |s| { s == "CRYPTO_memcmp" || // uses volatile @@ -128,7 +131,9 @@ fn main() { cfg.skip_field_type(|s, field| { (s == "EVP_PKEY" && field == "pkey") || // union (s == "GENERAL_NAME" && field == "d") || // union - (s == "X509_OBJECT" && field == "data") // union + (s == "X509_OBJECT" && field == "data") || // union + (s == "PKCS7" && field == "d") || // union + (s == "ASN1_TYPE" && field == "value") // union }); cfg.skip_signededness(|s| { s.ends_with("_cb") From 920ec61a584053b719b547ee0fb444f5087e0377 Mon Sep 17 00:00:00 2001 From: Bernd Krietenstein Date: Mon, 16 Jan 2023 14:37:54 +0100 Subject: [PATCH 07/19] Trigger build From b821f00a1d0fa45a653d401538e68977a332ab71 Mon Sep 17 00:00:00 2001 From: Bernd Krietenstein Date: Fri, 24 Feb 2023 17:29:33 +0100 Subject: [PATCH 08/19] Fixed review comments. --- openssl-sys/src/handwritten/asn1.rs | 7 --- openssl-sys/src/handwritten/object.rs | 1 + openssl-sys/src/handwritten/pkcs7.rs | 18 +++++- openssl-sys/src/handwritten/types.rs | 9 +-- openssl-sys/src/handwritten/x509.rs | 70 +++++++++++++++++++++++- openssl-sys/src/handwritten/x509_attr.rs | 60 -------------------- 6 files changed, 88 insertions(+), 77 deletions(-) diff --git a/openssl-sys/src/handwritten/asn1.rs b/openssl-sys/src/handwritten/asn1.rs index e866b1ea90..6e1f8c9b66 100644 --- a/openssl-sys/src/handwritten/asn1.rs +++ b/openssl-sys/src/handwritten/asn1.rs @@ -10,11 +10,8 @@ pub struct ASN1_ENCODING { extern "C" { pub fn ASN1_OBJECT_free(x: *mut ASN1_OBJECT); - pub fn OBJ_cmp(a: *const ASN1_OBJECT, b: *const ASN1_OBJECT) -> c_int; } -pub enum ASN1_OBJECT {} - stack!(stack_st_ASN1_OBJECT); #[repr(C)] @@ -42,10 +39,6 @@ pub union ASN1_TYPE_value { pub generalizedtime: *mut ASN1_GENERALIZEDTIME, pub visiblestring: *mut ASN1_VISIBLESTRING, pub utf8string: *mut ASN1_UTF8STRING, - /* - * set and sequence are left complete and still contain the set or - * sequence bytes - */ pub set: *mut ASN1_STRING, pub sequence: *mut ASN1_STRING, pub asn1_value: *mut ASN1_VALUE, diff --git a/openssl-sys/src/handwritten/object.rs b/openssl-sys/src/handwritten/object.rs index d2c525b806..5b4599c20a 100644 --- a/openssl-sys/src/handwritten/object.rs +++ b/openssl-sys/src/handwritten/object.rs @@ -27,4 +27,5 @@ extern "C" { pub fn OBJ_length(obj: *const ASN1_OBJECT) -> libc::size_t; #[cfg(ossl111)] pub fn OBJ_get0_data(obj: *const ASN1_OBJECT) -> *const c_uchar; + pub fn OBJ_cmp(a: *const ASN1_OBJECT, b: *const ASN1_OBJECT) -> c_int; } diff --git a/openssl-sys/src/handwritten/pkcs7.rs b/openssl-sys/src/handwritten/pkcs7.rs index 2f76cab9c2..332586515a 100644 --- a/openssl-sys/src/handwritten/pkcs7.rs +++ b/openssl-sys/src/handwritten/pkcs7.rs @@ -1,9 +1,6 @@ use libc::*; use *; -// use x509::stack_st_X509; -// use x509_attr::stack_st_X509_ATTRIBUTE; - #[cfg(ossl300)] #[repr(C)] pub struct PKCS7_CTX { @@ -106,6 +103,9 @@ extern "C" { pub fn PKCS7_SIGN_ENVELOPE_free(info: *mut PKCS7_SIGN_ENVELOPE); pub fn PKCS7_DIGEST_free(info: *mut PKCS7_DIGEST); pub fn PKCS7_SIGNER_INFO_free(info: *mut PKCS7_SIGNER_INFO); + pub fn PKCS7_ENCRYPT_free(enc: *mut PKCS7_ENCRYPT); + pub fn PKCS7_ISSUER_AND_SERIAL_free(ias: *mut PKCS7_ISSUER_AND_SERIAL); + pub fn PKCS7_RECIP_INFO_free(info: *mut PKCS7_RECIP_INFO); } cfg_if! { @@ -189,6 +189,18 @@ cfg_if! { } stack!(stack_st_PKCS7_SIGNER_INFO); + +#[repr(C)] +pub struct PKCS7_RECIP_INFO { + pub version: *mut ASN1_INTEGER, /* version 0 */ + pub issuer_and_serial: *mut PKCS7_ISSUER_AND_SERIAL, + pub key_enc_algor: *mut X509_ALGOR, + pub enc_key: *mut ASN1_OCTET_STRING, + pub cert: *mut X509, /* get the pub-key from this */ + #[cfg(ossl300)] + pub ctx: *const PKCS7_CTX, +} + stack!(stack_st_PKCS7_RECIP_INFO); extern "C" { diff --git a/openssl-sys/src/handwritten/types.rs b/openssl-sys/src/handwritten/types.rs index addc599abb..181340d486 100644 --- a/openssl-sys/src/handwritten/types.rs +++ b/openssl-sys/src/handwritten/types.rs @@ -3,16 +3,18 @@ use libc::*; #[allow(unused_imports)] use *; -#[derive(Copy, Clone)] -pub enum ASN1_BOOLEAN {} +pub enum ASN1_OBJECT {} +pub enum ASN1_VALUE {} + +pub type ASN1_BOOLEAN = c_int; pub enum ASN1_ENUMERATED {} pub enum ASN1_INTEGER {} pub enum ASN1_GENERALIZEDTIME {} pub enum ASN1_STRING {} pub enum ASN1_BIT_STRING {} pub enum ASN1_TIME {} -pub enum ASN1_OBJECT {} pub enum ASN1_OCTET_STRING {} +pub enum ASN1_NULL {} pub enum ASN1_PRINTABLESTRING {} pub enum ASN1_T61STRING {} pub enum ASN1_IA5STRING {} @@ -22,7 +24,6 @@ pub enum ASN1_UNIVERSALSTRING {} pub enum ASN1_UTCTIME {} pub enum ASN1_VISIBLESTRING {} pub enum ASN1_UTF8STRING {} -pub enum ASN1_VALUE {} pub enum bio_st {} // FIXME remove cfg_if! { diff --git a/openssl-sys/src/handwritten/x509.rs b/openssl-sys/src/handwritten/x509.rs index 486f712c34..fc94bbb741 100644 --- a/openssl-sys/src/handwritten/x509.rs +++ b/openssl-sys/src/handwritten/x509.rs @@ -15,6 +15,10 @@ pub enum X509_EXTENSION {} stack!(stack_st_X509_EXTENSION); +pub enum X509_ATTRIBUTE {} + +stack!(stack_st_X509_ATTRIBUTE); + cfg_if! { if #[cfg(any(ossl110, libressl350))] { pub enum X509_REQ_INFO {} @@ -269,8 +273,6 @@ extern "C" { pub fn X509_EXTENSION_free(ext: *mut X509_EXTENSION); - pub fn X509_ATTRIBUTE_free(attr: *mut ::X509_ATTRIBUTE); - pub fn X509_NAME_ENTRY_free(x: *mut X509_NAME_ENTRY); pub fn X509_NAME_new() -> *mut X509_NAME; @@ -689,6 +691,68 @@ pub struct X509_PURPOSE { const_ptr_api! { extern "C" { pub fn X509_PURPOSE_get_by_sname(sname: #[const_ptr_if(any(ossl110, libressl280))] c_char) -> c_int; - pub fn X509_PURPOSE_get0(idx: c_int) -> *mut X509_PURPOSE; + } +} +extern "C" { + pub fn X509_PURPOSE_get0(idx: c_int) -> *mut X509_PURPOSE; +} + +extern "C" { + pub fn X509_ATTRIBUTE_new() -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_free(attr: *mut ::X509_ATTRIBUTE); + pub fn X509_ATTRIBUTE_create( + nid: c_int, + atrtype: c_int, + value: *mut c_void, + ) -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_create_by_NID( + attr: *mut *mut X509_ATTRIBUTE, + nid: c_int, + atrtype: c_int, + data: *const c_void, + len: c_int, + ) -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_create_by_OBJ( + attr: *mut *mut X509_ATTRIBUTE, + obj: *const ASN1_OBJECT, + atrtype: c_int, + data: *const c_void, + len: c_int, + ) -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_create_by_txt( + attr: *mut *mut X509_ATTRIBUTE, + atrname: *const c_char, + atrtype: c_int, + bytes: *const c_uchar, + len: c_int, + ) -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_set1_object(attr: *mut X509_ATTRIBUTE, obj: *const ASN1_OBJECT) -> c_int; + pub fn X509_ATTRIBUTE_set1_data( + attr: *mut X509_ATTRIBUTE, + attrtype: c_int, + data: *const c_void, + len: c_int, + ) -> c_int; + pub fn X509_ATTRIBUTE_get0_data( + attr: *mut X509_ATTRIBUTE, + idx: c_int, + atrtype: c_int, + data: *mut c_void, + ) -> *mut c_void; + pub fn X509_ATTRIBUTE_get0_object(attr: *mut X509_ATTRIBUTE) -> *mut ASN1_OBJECT; + pub fn X509_ATTRIBUTE_get0_type(attr: *mut X509_ATTRIBUTE, idx: c_int) -> *mut ASN1_TYPE; + pub fn d2i_X509_ATTRIBUTE( + a: *mut *mut X509_ATTRIBUTE, + pp: *mut *const c_uchar, + length: c_long, + ) -> *mut X509_ATTRIBUTE; +} +const_ptr_api! { + extern "C" { + pub fn X509_ATTRIBUTE_count( + attr: #[const_ptr_if(any(ossl110, libressl280))] X509_ATTRIBUTE // const since OpenSSL v1.1.0 + ) -> c_int; + pub fn i2d_X509_ATTRIBUTE(x: #[const_ptr_if(ossl300)] X509_ATTRIBUTE, buf: *mut *mut u8) -> c_int; + pub fn X509_ATTRIBUTE_dup(x: #[const_ptr_if(ossl300)] X509_ATTRIBUTE) -> *mut X509_ATTRIBUTE; } } diff --git a/openssl-sys/src/handwritten/x509_attr.rs b/openssl-sys/src/handwritten/x509_attr.rs index b14be38619..e69de29bb2 100644 --- a/openssl-sys/src/handwritten/x509_attr.rs +++ b/openssl-sys/src/handwritten/x509_attr.rs @@ -1,60 +0,0 @@ -use libc::*; - -use *; - -pub enum X509_ATTRIBUTE {} - -stack!(stack_st_X509_ATTRIBUTE); - -extern "C" { - pub fn X509_ATTRIBUTE_new() -> *mut X509_ATTRIBUTE; - pub fn X509_ATTRIBUTE_create( - nid: c_int, - atrtype: c_int, - value: *mut c_void, - ) -> *mut X509_ATTRIBUTE; - pub fn X509_ATTRIBUTE_create_by_NID( - attr: *mut *mut X509_ATTRIBUTE, - nid: c_int, - atrtype: c_int, - data: *const c_void, - len: c_int, - ) -> *mut X509_ATTRIBUTE; - pub fn X509_ATTRIBUTE_create_by_OBJ( - attr: *mut *mut X509_ATTRIBUTE, - obj: *const ASN1_OBJECT, - atrtype: c_int, - data: *const c_void, - len: c_int, - ) -> *mut X509_ATTRIBUTE; - pub fn X509_ATTRIBUTE_create_by_txt( - attr: *mut *mut X509_ATTRIBUTE, - atrname: *const c_char, - atrtype: c_int, - bytes: *const c_uchar, - len: c_int, - ) -> *mut X509_ATTRIBUTE; - pub fn X509_ATTRIBUTE_set1_object(attr: *mut X509_ATTRIBUTE, obj: *const ASN1_OBJECT) -> c_int; - pub fn X509_ATTRIBUTE_set1_data( - attr: *mut X509_ATTRIBUTE, - attrtype: c_int, - data: *const c_void, - len: c_int, - ) -> c_int; - pub fn X509_ATTRIBUTE_get0_data( - attr: *mut X509_ATTRIBUTE, - idx: c_int, - atrtype: c_int, - data: *mut c_void, - ) -> *mut c_void; - pub fn X509_ATTRIBUTE_get0_object(attr: *mut X509_ATTRIBUTE) -> *mut ASN1_OBJECT; - pub fn X509_ATTRIBUTE_get0_type(attr: *mut X509_ATTRIBUTE, idx: c_int) -> *mut ASN1_TYPE; - -} -const_ptr_api! { - extern "C" { - pub fn X509_ATTRIBUTE_count( - attr: #[const_ptr_if(any(ossl110, libressl291))] X509_ATTRIBUTE // const since OpenSSL v1.1.0 - ) -> c_int; - } -} From d77c6518873b063de9cc6bca4f708b765ffbb284 Mon Sep 17 00:00:00 2001 From: Bernd Krietenstein Date: Fri, 24 Feb 2023 17:37:23 +0100 Subject: [PATCH 09/19] Removed emtpy x509_attr.rs --- openssl-sys/src/handwritten/mod.rs | 2 -- openssl-sys/src/handwritten/x509_attr.rs | 0 2 files changed, 2 deletions(-) delete mode 100644 openssl-sys/src/handwritten/x509_attr.rs diff --git a/openssl-sys/src/handwritten/mod.rs b/openssl-sys/src/handwritten/mod.rs index fea7549898..28aa4aecd0 100644 --- a/openssl-sys/src/handwritten/mod.rs +++ b/openssl-sys/src/handwritten/mod.rs @@ -28,7 +28,6 @@ pub use self::stack::*; pub use self::tls1::*; pub use self::types::*; pub use self::x509::*; -pub use self::x509_attr::*; pub use self::x509_vfy::*; pub use self::x509v3::*; @@ -62,6 +61,5 @@ mod stack; mod tls1; mod types; mod x509; -mod x509_attr; mod x509_vfy; mod x509v3; diff --git a/openssl-sys/src/handwritten/x509_attr.rs b/openssl-sys/src/handwritten/x509_attr.rs deleted file mode 100644 index e69de29bb2..0000000000 From 0bd4876a951f2fe7da227daa2ee2e67cc7ee3ed3 Mon Sep 17 00:00:00 2001 From: Bernd Krietenstein Date: Fri, 24 Feb 2023 17:57:16 +0100 Subject: [PATCH 10/19] clippy. --- openssl-sys/src/handwritten/x509.rs | 6 +++--- openssl/src/sign.rs | 2 +- openssl/src/x509/mod.rs | 12 ++++++++++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/openssl-sys/src/handwritten/x509.rs b/openssl-sys/src/handwritten/x509.rs index fc94bbb741..46ec3e14a9 100644 --- a/openssl-sys/src/handwritten/x509.rs +++ b/openssl-sys/src/handwritten/x509.rs @@ -365,8 +365,8 @@ const_ptr_api! { extern "C" { pub fn X509_REQ_get_attr_count(req: *const X509_REQ) -> c_int; pub fn X509_REQ_get_attr_by_NID(req: *const X509_REQ, nid: c_int, lastpos: c_int) -> c_int; - pub fn X509_REQ_get_attr(req: *const X509_REQ, loc: c_int) -> *mut ::X509_ATTRIBUTE; - pub fn X509_REQ_delete_attr(req: *mut X509_REQ, loc: c_int) -> *mut ::X509_ATTRIBUTE; + pub fn X509_REQ_get_attr(req: *const X509_REQ, loc: c_int) -> *mut X509_ATTRIBUTE; + pub fn X509_REQ_delete_attr(req: *mut X509_REQ, loc: c_int) -> *mut X509_ATTRIBUTE; pub fn X509_REQ_add1_attr_by_txt( req: *mut X509_REQ, attrname: *const c_char, @@ -699,7 +699,7 @@ extern "C" { extern "C" { pub fn X509_ATTRIBUTE_new() -> *mut X509_ATTRIBUTE; - pub fn X509_ATTRIBUTE_free(attr: *mut ::X509_ATTRIBUTE); + pub fn X509_ATTRIBUTE_free(attr: *mut X509_ATTRIBUTE); pub fn X509_ATTRIBUTE_create( nid: c_int, atrtype: c_int, diff --git a/openssl/src/sign.rs b/openssl/src/sign.rs index 9cfda48105..51738651c6 100644 --- a/openssl/src/sign.rs +++ b/openssl/src/sign.rs @@ -711,7 +711,7 @@ mod test { #[cfg(not(boringssl))] fn test_hmac(ty: MessageDigest, tests: &[(Vec, Vec, Vec)]) { - for &(ref key, ref data, ref res) in tests.iter() { + for (key, data, res) in tests.iter() { let pkey = PKey::hmac(key).unwrap(); let mut signer = Signer::new(ty, &pkey).unwrap(); signer.update(data).unwrap(); diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index d29a21e4af..2da41bd1a5 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -388,7 +388,10 @@ impl X509Ref { /// Returns the hash of the certificates subject #[corresponds(X509_subject_name_hash)] pub fn subject_name_hash(&self) -> u32 { - unsafe { ffi::X509_subject_name_hash(self.as_ptr()) as u32 } + #[allow(clippy::unnecessary_cast)] + unsafe { + ffi::X509_subject_name_hash(self.as_ptr()) as u32 + } } /// Returns this certificate's issuer name. @@ -403,7 +406,10 @@ impl X509Ref { /// Returns the hash of the certificates issuer #[corresponds(X509_issuer_name_hash)] pub fn issuer_name_hash(&self) -> u32 { - unsafe { ffi::X509_issuer_name_hash(self.as_ptr()) as u32 } + #[allow(clippy::unnecessary_cast)] + unsafe { + ffi::X509_issuer_name_hash(self.as_ptr()) as u32 + } } /// Returns this certificate's subject alternative name entries, if they exist. @@ -545,6 +551,7 @@ impl X509Ref { /// Note that `0` return value stands for version 1, `1` for version 2 and so on. #[corresponds(X509_get_version)] #[cfg(ossl110)] + #[allow(clippy::unnecessary_cast)] pub fn version(&self) -> i32 { unsafe { ffi::X509_get_version(self.as_ptr()) as i32 } } @@ -1359,6 +1366,7 @@ impl X509ReqRef { /// This corresponds to [`X509_REQ_get_version`] /// /// [`X509_REQ_get_version`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_version.html + #[allow(clippy::unnecessary_cast)] pub fn version(&self) -> i32 { unsafe { X509_REQ_get_version(self.as_ptr()) as i32 } } From 9f8c82161361da1eef0169fce7e4cac2b6094e53 Mon Sep 17 00:00:00 2001 From: Bernd Krietenstein Date: Mon, 27 Feb 2023 08:16:05 +0100 Subject: [PATCH 11/19] Removed invalid path operator. --- openssl-sys/src/handwritten/x509.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openssl-sys/src/handwritten/x509.rs b/openssl-sys/src/handwritten/x509.rs index 46ec3e14a9..917b41e425 100644 --- a/openssl-sys/src/handwritten/x509.rs +++ b/openssl-sys/src/handwritten/x509.rs @@ -29,7 +29,7 @@ cfg_if! { pub version: *mut ::ASN1_INTEGER, pub subject: *mut ::X509_NAME, pubkey: *mut c_void, - pub attributes: *mut ::stack_st_X509_ATTRIBUTE, + pub attributes: *mut stack_st_X509_ATTRIBUTE, } } } From f13427168389420bc21011903ddb21c9d59be351 Mon Sep 17 00:00:00 2001 From: Bernd Krietenstein Date: Mon, 27 Feb 2023 09:44:10 +0100 Subject: [PATCH 12/19] Removed unnecessary cfg_if's. --- openssl-sys/src/handwritten/pkcs7.rs | 252 +++++++++++---------------- 1 file changed, 97 insertions(+), 155 deletions(-) diff --git a/openssl-sys/src/handwritten/pkcs7.rs b/openssl-sys/src/handwritten/pkcs7.rs index 332586515a..60dcfe0d64 100644 --- a/openssl-sys/src/handwritten/pkcs7.rs +++ b/openssl-sys/src/handwritten/pkcs7.rs @@ -8,92 +8,51 @@ pub struct PKCS7_CTX { propq: *mut c_char, } -cfg_if! { - if #[cfg(any(ossl101, libressl251))] { - #[repr(C)] - pub struct PKCS7_SIGNED { - pub version: *mut ASN1_INTEGER, /* version 1 */ - pub md_algs: *mut stack_st_X509_ALGOR, /* md used */ - pub cert: *mut stack_st_X509, /* [ 0 ] */ - pub crl: *mut stack_st_X509_CRL, /* [ 1 ] */ - pub signer_info: *mut stack_st_PKCS7_SIGNER_INFO, - pub contents: *mut PKCS7, - } - } else { - pub enum PKCS7_SIGNED {} - } +#[repr(C)] +pub struct PKCS7_SIGNED { + pub version: *mut ASN1_INTEGER, /* version 1 */ + pub md_algs: *mut stack_st_X509_ALGOR, /* md used */ + pub cert: *mut stack_st_X509, /* [ 0 ] */ + pub crl: *mut stack_st_X509_CRL, /* [ 1 ] */ + pub signer_info: *mut stack_st_PKCS7_SIGNER_INFO, + pub contents: *mut PKCS7, } - -cfg_if! { - if #[cfg(any(ossl101, libressl251))] { - #[repr(C)] - pub struct PKCS7_ENC_CONTENT { - pub content_type: *mut ASN1_OBJECT, - pub algorithm: *mut X509_ALGOR, - pub enc_data: *mut ASN1_OCTET_STRING, /* [ 0 ] */ - pub cipher: *const EVP_CIPHER, - #[cfg(ossl300)] - pub ctx: *const PKCS7_CTX, - } - } else { - pub enum PKCS7_ENC_CONTENT {} - } +#[repr(C)] +pub struct PKCS7_ENC_CONTENT { + pub content_type: *mut ASN1_OBJECT, + pub algorithm: *mut X509_ALGOR, + pub enc_data: *mut ASN1_OCTET_STRING, /* [ 0 ] */ + pub cipher: *const EVP_CIPHER, + #[cfg(ossl300)] + pub ctx: *const PKCS7_CTX, } - -cfg_if! { - if #[cfg(any(ossl101, libressl251))] { - #[repr(C)] - pub struct PKCS7_ENVELOPE { - pub version: *mut ASN1_INTEGER, /* version 0 */ - pub recipientinfo: *mut stack_st_PKCS7_RECIP_INFO, - pub enc_data: *mut PKCS7_ENC_CONTENT, - } - } else { - pub enum PKCS7_ENVELOPE {} - } +#[repr(C)] +pub struct PKCS7_ENVELOPE { + pub version: *mut ASN1_INTEGER, /* version 0 */ + pub recipientinfo: *mut stack_st_PKCS7_RECIP_INFO, + pub enc_data: *mut PKCS7_ENC_CONTENT, } - -cfg_if! { - if #[cfg(any(ossl101, libressl251))] { - #[repr(C)] - pub struct PKCS7_SIGN_ENVELOPE { - pub version: *mut ASN1_INTEGER, /* version 1 */ - pub md_algs: *mut stack_st_X509_ALGOR, /* md used */ - pub cert: *mut stack_st_X509, /* [ 0 ] */ - pub crl: *mut stack_st_X509_CRL, /* [ 1 ] */ - pub signer_info: *mut stack_st_PKCS7_SIGNER_INFO, - pub enc_data: *mut PKCS7_ENC_CONTENT, - pub recipientinfo: *mut stack_st_PKCS7_RECIP_INFO - } - } else { - pub enum PKCS7_SIGN_ENVELOPE {} - } +#[repr(C)] +pub struct PKCS7_SIGN_ENVELOPE { + pub version: *mut ASN1_INTEGER, /* version 1 */ + pub md_algs: *mut stack_st_X509_ALGOR, /* md used */ + pub cert: *mut stack_st_X509, /* [ 0 ] */ + pub crl: *mut stack_st_X509_CRL, /* [ 1 ] */ + pub signer_info: *mut stack_st_PKCS7_SIGNER_INFO, + pub enc_data: *mut PKCS7_ENC_CONTENT, + pub recipientinfo: *mut stack_st_PKCS7_RECIP_INFO } - -cfg_if! { - if #[cfg(any(ossl101, libressl251))] { - #[repr(C)] - pub struct PKCS7_DIGEST { - pub version: *mut ASN1_INTEGER, /* version 0 */ - pub md: *mut X509_ALGOR, /* md used */ - pub contents: *mut PKCS7, - pub digest: *mut ASN1_OCTET_STRING, - } - } else { - pub enum PKCS7_DIGEST {} - } +#[repr(C)] +pub struct PKCS7_DIGEST { + pub version: *mut ASN1_INTEGER, /* version 0 */ + pub md: *mut X509_ALGOR, /* md used */ + pub contents: *mut PKCS7, + pub digest: *mut ASN1_OCTET_STRING, } - -cfg_if! { - if #[cfg(any(ossl101, libressl251))] { - #[repr(C)] - pub struct PKCS7_ENCRYPT { - pub version: *mut ASN1_INTEGER, /* version 0 */ - pub enc_data: *mut PKCS7_ENC_CONTENT, - } - } else { - pub enum PKCS7_ENCRYPT {} - } +#[repr(C)] +pub struct PKCS7_ENCRYPT { + pub version: *mut ASN1_INTEGER, /* version 0 */ + pub enc_data: *mut PKCS7_ENC_CONTENT, } extern "C" { @@ -108,84 +67,67 @@ extern "C" { pub fn PKCS7_RECIP_INFO_free(info: *mut PKCS7_RECIP_INFO); } -cfg_if! { - if #[cfg(any(ossl101, libressl251))] { - #[repr(C)] - pub struct PKCS7 { - /* - * The following is non NULL if it contains ASN1 encoding of this - * structure - */ - pub asn1: *mut c_uchar, - pub length: c_long, - // # define PKCS7_S_HEADER 0 - // # define PKCS7_S_BODY 1 - // # define PKCS7_S_TAIL 2 - pub state: c_int, /* used during processing */ - pub detached: c_int, - pub type_: *mut ASN1_OBJECT, - /* content as defined by the type */ - /* - * all encryption/message digests are applied to the 'contents', leaving - * out the 'type' field. - */ - pub d: PKCS7_data, - #[cfg(ossl300)] - pub ctx: PKCS7_CTX, - } - #[repr(C)] - pub union PKCS7_data { - pub ptr: *mut c_char, - /* NID_pkcs7_data */ - pub data: *mut ASN1_OCTET_STRING, - /* NID_pkcs7_signed */ - pub sign: *mut PKCS7_SIGNED, - /* NID_pkcs7_enveloped */ - pub enveloped: *mut PKCS7_ENVELOPE, - /* NID_pkcs7_signedAndEnveloped */ - pub signed_and_enveloped: *mut PKCS7_SIGN_ENVELOPE, - /* NID_pkcs7_digest */ - pub digest: *mut PKCS7_DIGEST, - /* NID_pkcs7_encrypted */ - pub encrypted: *mut PKCS7_ENCRYPT, - /* Anything else */ - pub other: *mut ASN1_TYPE, - } - } else { - pub enum PKCS7 {} - } +#[repr(C)] +pub struct PKCS7 { + /* + * The following is non NULL if it contains ASN1 encoding of this + * structure + */ + pub asn1: *mut c_uchar, + pub length: c_long, + // # define PKCS7_S_HEADER 0 + // # define PKCS7_S_BODY 1 + // # define PKCS7_S_TAIL 2 + pub state: c_int, /* used during processing */ + pub detached: c_int, + pub type_: *mut ASN1_OBJECT, + /* content as defined by the type */ + /* + * all encryption/message digests are applied to the 'contents', leaving + * out the 'type' field. + */ + pub d: PKCS7_data, + #[cfg(ossl300)] + pub ctx: PKCS7_CTX, } -cfg_if! { - if #[cfg(any(ossl101, libressl))] { - #[repr(C)] - pub struct PKCS7_ISSUER_AND_SERIAL { - pub issuer: *mut X509_NAME, - pub serial: *mut ASN1_INTEGER, - } - } else { - pub enum PKCS7_ISSUER_AND_SERIAL {} - } +#[repr(C)] +pub union PKCS7_data { + pub ptr: *mut c_char, + /* NID_pkcs7_data */ + pub data: *mut ASN1_OCTET_STRING, + /* NID_pkcs7_signed */ + pub sign: *mut PKCS7_SIGNED, + /* NID_pkcs7_enveloped */ + pub enveloped: *mut PKCS7_ENVELOPE, + /* NID_pkcs7_signedAndEnveloped */ + pub signed_and_enveloped: *mut PKCS7_SIGN_ENVELOPE, + /* NID_pkcs7_digest */ + pub digest: *mut PKCS7_DIGEST, + /* NID_pkcs7_encrypted */ + pub encrypted: *mut PKCS7_ENCRYPT, + /* Anything else */ + pub other: *mut ASN1_TYPE, } -cfg_if! { - if #[cfg(any(ossl101, libressl))] { - #[repr(C)] - pub struct PKCS7_SIGNER_INFO { - pub version: *mut ASN1_INTEGER, /* version 1 */ - pub issuer_and_serial: *mut PKCS7_ISSUER_AND_SERIAL, - pub digest_alg: *mut X509_ALGOR, - pub auth_attr: *mut stack_st_X509_ATTRIBUTE, /* [ 0 ] */ - pub digest_enc_alg: *mut X509_ALGOR, - pub enc_digest: *mut ASN1_OCTET_STRING, - pub unauth_attr: *mut stack_st_X509_ATTRIBUTE, /* [ 1 ] */ - pub pkey: *mut EVP_PKEY, /* The private key to sign with */ - #[cfg(ossl300)] - pub ctx: *const PKCS7_CTX, - } - } else { - pub enum PKCS7_SIGNER_INFO {} - } +#[repr(C)] +pub struct PKCS7_ISSUER_AND_SERIAL { + pub issuer: *mut X509_NAME, + pub serial: *mut ASN1_INTEGER, +} + +#[repr(C)] +pub struct PKCS7_SIGNER_INFO { + pub version: *mut ASN1_INTEGER, /* version 1 */ + pub issuer_and_serial: *mut PKCS7_ISSUER_AND_SERIAL, + pub digest_alg: *mut X509_ALGOR, + pub auth_attr: *mut stack_st_X509_ATTRIBUTE, /* [ 0 ] */ + pub digest_enc_alg: *mut X509_ALGOR, + pub enc_digest: *mut ASN1_OCTET_STRING, + pub unauth_attr: *mut stack_st_X509_ATTRIBUTE, /* [ 1 ] */ + pub pkey: *mut EVP_PKEY, /* The private key to sign with */ + #[cfg(ossl300)] + pub ctx: *const PKCS7_CTX, } stack!(stack_st_PKCS7_SIGNER_INFO); From 9c30e4e418c26c9e4adfff4bd64aae2713897564 Mon Sep 17 00:00:00 2001 From: Bernd Krietenstein Date: Mon, 27 Feb 2023 09:56:23 +0100 Subject: [PATCH 13/19] rustfmt hit me once more --- openssl-sys/src/handwritten/pkcs7.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/openssl-sys/src/handwritten/pkcs7.rs b/openssl-sys/src/handwritten/pkcs7.rs index 60dcfe0d64..754fc9e2b8 100644 --- a/openssl-sys/src/handwritten/pkcs7.rs +++ b/openssl-sys/src/handwritten/pkcs7.rs @@ -10,10 +10,10 @@ pub struct PKCS7_CTX { #[repr(C)] pub struct PKCS7_SIGNED { - pub version: *mut ASN1_INTEGER, /* version 1 */ + pub version: *mut ASN1_INTEGER, /* version 1 */ pub md_algs: *mut stack_st_X509_ALGOR, /* md used */ - pub cert: *mut stack_st_X509, /* [ 0 ] */ - pub crl: *mut stack_st_X509_CRL, /* [ 1 ] */ + pub cert: *mut stack_st_X509, /* [ 0 ] */ + pub crl: *mut stack_st_X509_CRL, /* [ 1 ] */ pub signer_info: *mut stack_st_PKCS7_SIGNER_INFO, pub contents: *mut PKCS7, } @@ -34,18 +34,18 @@ pub struct PKCS7_ENVELOPE { } #[repr(C)] pub struct PKCS7_SIGN_ENVELOPE { - pub version: *mut ASN1_INTEGER, /* version 1 */ + pub version: *mut ASN1_INTEGER, /* version 1 */ pub md_algs: *mut stack_st_X509_ALGOR, /* md used */ - pub cert: *mut stack_st_X509, /* [ 0 ] */ - pub crl: *mut stack_st_X509_CRL, /* [ 1 ] */ + pub cert: *mut stack_st_X509, /* [ 0 ] */ + pub crl: *mut stack_st_X509_CRL, /* [ 1 ] */ pub signer_info: *mut stack_st_PKCS7_SIGNER_INFO, pub enc_data: *mut PKCS7_ENC_CONTENT, - pub recipientinfo: *mut stack_st_PKCS7_RECIP_INFO + pub recipientinfo: *mut stack_st_PKCS7_RECIP_INFO, } #[repr(C)] pub struct PKCS7_DIGEST { pub version: *mut ASN1_INTEGER, /* version 0 */ - pub md: *mut X509_ALGOR, /* md used */ + pub md: *mut X509_ALGOR, /* md used */ pub contents: *mut PKCS7, pub digest: *mut ASN1_OCTET_STRING, } @@ -125,7 +125,7 @@ pub struct PKCS7_SIGNER_INFO { pub digest_enc_alg: *mut X509_ALGOR, pub enc_digest: *mut ASN1_OCTET_STRING, pub unauth_attr: *mut stack_st_X509_ATTRIBUTE, /* [ 1 ] */ - pub pkey: *mut EVP_PKEY, /* The private key to sign with */ + pub pkey: *mut EVP_PKEY, /* The private key to sign with */ #[cfg(ossl300)] pub ctx: *const PKCS7_CTX, } From ced6eb1467148f1364755046f62b8a2f3dad526d Mon Sep 17 00:00:00 2001 From: Bernd Krietenstein Date: Mon, 27 Feb 2023 13:57:17 +0100 Subject: [PATCH 14/19] Build trigger From 3a650ad3690bc5854246f987d2365e4264d6c4ff Mon Sep 17 00:00:00 2001 From: Bernd Krietenstein Date: Mon, 27 Feb 2023 15:23:46 +0100 Subject: [PATCH 15/19] Ignoring non-threadsafe test. --- openssl/src/asn1.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openssl/src/asn1.rs b/openssl/src/asn1.rs index 130e356533..b63061e871 100644 --- a/openssl/src/asn1.rs +++ b/openssl/src/asn1.rs @@ -1050,6 +1050,8 @@ mod tests { } #[test] + // Calls ffi::ASN1_generate_v3 which doesn't seem to be thread safe. This makes problems in CI. + #[ignore] #[cfg(not(boringssl))] fn asn1_string_from_asn1_type() { let null = null_mut(); From e376917194f4924f06c55cf10756b67598c63629 Mon Sep 17 00:00:00 2001 From: Bernd Krietenstein Date: Mon, 27 Feb 2023 15:25:46 +0100 Subject: [PATCH 16/19] Ignoring non-threadsafe test. --- openssl/src/asn1.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openssl/src/asn1.rs b/openssl/src/asn1.rs index 130e356533..b63061e871 100644 --- a/openssl/src/asn1.rs +++ b/openssl/src/asn1.rs @@ -1050,6 +1050,8 @@ mod tests { } #[test] + // Calls ffi::ASN1_generate_v3 which doesn't seem to be thread safe. This makes problems in CI. + #[ignore] #[cfg(not(boringssl))] fn asn1_string_from_asn1_type() { let null = null_mut(); From fc551fa58dfa9588f4f0f7344ca5c2647b468fd8 Mon Sep 17 00:00:00 2001 From: Bernd Krietenstein Date: Mon, 27 Feb 2023 16:44:53 +0100 Subject: [PATCH 17/19] Parallelized test calling `ASN1_generate_v3` --- openssl/Cargo.toml | 1 + openssl/src/asn1.rs | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index 0aea05c0ce..5f4cd7719b 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -35,3 +35,4 @@ ffi = { package = "openssl-sys", version = "0.9.80", path = "../openssl-sys" } [dev-dependencies] hex = "0.3" +serial_test = "1.0" diff --git a/openssl/src/asn1.rs b/openssl/src/asn1.rs index b63061e871..c332cabee0 100644 --- a/openssl/src/asn1.rs +++ b/openssl/src/asn1.rs @@ -1005,7 +1005,11 @@ mod tests { ); } + // Tests calling `ffi::ASN1_generate_v3` must not run in parallel. Spurious errors have been + // observed in CI and it looks like `ffi::ASN1_generate_v3` is not thread-safe. + #[test] + #[serial] #[cfg(not(boringssl))] fn asn1_type_type() { let null = null_mut(); @@ -1028,6 +1032,7 @@ mod tests { // Check (deprecated) `pub const Asn1Type::...` et al. #[test] + #[serial] #[cfg(not(boringssl))] #[allow(deprecated)] fn asn1_type_type_compatibility() { @@ -1050,8 +1055,7 @@ mod tests { } #[test] - // Calls ffi::ASN1_generate_v3 which doesn't seem to be thread safe. This makes problems in CI. - #[ignore] + #[serial] #[cfg(not(boringssl))] fn asn1_string_from_asn1_type() { let null = null_mut(); @@ -1078,6 +1082,7 @@ mod tests { } #[test] + #[serial] #[cfg(not(boringssl))] fn asn1_octet_string_from_asn1_type() { let null = null_mut(); From 5502e349cc2b98b45cba97033130190d92059e48 Mon Sep 17 00:00:00 2001 From: Bernd Krietenstein Date: Mon, 27 Feb 2023 17:23:51 +0100 Subject: [PATCH 18/19] Fixed `serial_test::serial` --- openssl/src/asn1.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openssl/src/asn1.rs b/openssl/src/asn1.rs index c332cabee0..5e54e0336f 100644 --- a/openssl/src/asn1.rs +++ b/openssl/src/asn1.rs @@ -1009,7 +1009,7 @@ mod tests { // observed in CI and it looks like `ffi::ASN1_generate_v3` is not thread-safe. #[test] - #[serial] + #[serial_test::serial] #[cfg(not(boringssl))] fn asn1_type_type() { let null = null_mut(); @@ -1032,7 +1032,7 @@ mod tests { // Check (deprecated) `pub const Asn1Type::...` et al. #[test] - #[serial] + #[serial_test::serial] #[cfg(not(boringssl))] #[allow(deprecated)] fn asn1_type_type_compatibility() { @@ -1055,7 +1055,7 @@ mod tests { } #[test] - #[serial] + #[serial_test::serial] #[cfg(not(boringssl))] fn asn1_string_from_asn1_type() { let null = null_mut(); @@ -1082,7 +1082,7 @@ mod tests { } #[test] - #[serial] + #[serial_test::serial] #[cfg(not(boringssl))] fn asn1_octet_string_from_asn1_type() { let null = null_mut(); From 8c41cf00aab4a87da1ff79785030ea4744fbdc93 Mon Sep 17 00:00:00 2001 From: Bernd Krietenstein Date: Fri, 10 Mar 2023 08:02:11 +0100 Subject: [PATCH 19/19] Trigger CI