From: Damian Hobson-Garcia Date: Thu, 13 May 2021 02:53:59 +0000 (+0900) Subject: Add RFC 5755 attribute certificate support X-Git-Tag: openssl-3.4.0-alpha1~648 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7dcee34c8f921ad65277e9a75fca4a7337fbed6d;p=thirdparty%2Fopenssl.git Add RFC 5755 attribute certificate support Add support for attribute certificates (v2) as described in RFC 5755 profile. Attribute certificates provide a mechanism to manage authorization information separately from the identity information provided by public key certificates. This initial patch adds the ASN.1 definitions and I/O API. Accessor functions for the certificate fields will be added in subsequent patches. Reviewed-by: Tomas Mraz Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/15857) --- diff --git a/build.info b/build.info index fdab98c103d..51d9184045b 100644 --- a/build.info +++ b/build.info @@ -44,6 +44,7 @@ DEPEND[]=include/openssl/asn1.h \ include/openssl/ui.h \ include/openssl/x509.h \ include/openssl/x509v3.h \ + include/openssl/x509_acert.h \ include/openssl/x509_vfy.h \ include/crypto/bn_conf.h include/crypto/dso_conf.h \ include/internal/param_names.h crypto/params_idx.c @@ -75,6 +76,7 @@ GENERATE[include/openssl/ssl.h]=include/openssl/ssl.h.in GENERATE[include/openssl/ui.h]=include/openssl/ui.h.in GENERATE[include/openssl/x509.h]=include/openssl/x509.h.in GENERATE[include/openssl/x509v3.h]=include/openssl/x509v3.h.in +GENERATE[include/openssl/x509_acert.h]=include/openssl/x509_acert.h.in GENERATE[include/openssl/x509_vfy.h]=include/openssl/x509_vfy.h.in GENERATE[include/crypto/bn_conf.h]=include/crypto/bn_conf.h.in GENERATE[include/crypto/dso_conf.h]=include/crypto/dso_conf.h.in diff --git a/crypto/asn1/asn1_item_list.c b/crypto/asn1/asn1_item_list.c index b5a83ba8914..ab0d500d650 100644 --- a/crypto/asn1/asn1_item_list.c +++ b/crypto/asn1/asn1_item_list.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "asn1_item_list.h" diff --git a/crypto/asn1/asn1_item_list.h b/crypto/asn1/asn1_item_list.h index 72299a7b6b3..fc59c2cdbab 100644 --- a/crypto/asn1/asn1_item_list.h +++ b/crypto/asn1/asn1_item_list.h @@ -150,6 +150,7 @@ static ASN1_ITEM_EXP *asn1_item_list[] = { ASN1_ITEM_ref(SXNET), ASN1_ITEM_ref(ISSUER_SIGN_TOOL), ASN1_ITEM_ref(USERNOTICE), + ASN1_ITEM_ref(X509_ACERT), ASN1_ITEM_ref(X509_ALGORS), ASN1_ITEM_ref(X509_ALGOR), ASN1_ITEM_ref(X509_ATTRIBUTE), diff --git a/crypto/x509/build.info b/crypto/x509/build.info index 3f70f3ff36d..2976b37e0fc 100644 --- a/crypto/x509/build.info +++ b/crypto/x509/build.info @@ -15,7 +15,8 @@ SOURCE[../../libcrypto]=\ v3_pcia.c v3_pci.c v3_ist.c \ pcy_cache.c pcy_node.c pcy_data.c pcy_map.c pcy_tree.c pcy_lib.c \ v3_asid.c v3_addr.c v3_tlsf.c v3_admis.c v3_no_rev_avail.c \ - v3_soa_id.c v3_no_ass.c v3_group_ac.c v3_single_use.c v3_ind_iss.c + v3_soa_id.c v3_no_ass.c v3_group_ac.c v3_single_use.c v3_ind_iss.c \ + x509_acert.c IF[{- !$disabled{'deprecated-3.0'} -}] SOURCE[../../libcrypto]=x509type.c diff --git a/crypto/x509/x509_acert.c b/crypto/x509/x509_acert.c new file mode 100644 index 00000000000..9a1c298d7a5 --- /dev/null +++ b/crypto/x509/x509_acert.c @@ -0,0 +1,75 @@ +/* + * Copyright 2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include "x509_acert.h" + +/* + * OpenSSL ASN.1 template translation of RFC 5755 4.1. + */ + +ASN1_SEQUENCE(OSSL_OBJECT_DIGEST_INFO) = { + ASN1_EMBED(OSSL_OBJECT_DIGEST_INFO, digestedObjectType, ASN1_ENUMERATED), + ASN1_OPT(OSSL_OBJECT_DIGEST_INFO, otherObjectTypeID, ASN1_OBJECT), + ASN1_EMBED(OSSL_OBJECT_DIGEST_INFO, digestAlgorithm, X509_ALGOR), + ASN1_EMBED(OSSL_OBJECT_DIGEST_INFO, objectDigest, ASN1_BIT_STRING), +} ASN1_SEQUENCE_END(OSSL_OBJECT_DIGEST_INFO) + +ASN1_SEQUENCE(OSSL_ISSUER_SERIAL) = { + ASN1_SEQUENCE_OF(OSSL_ISSUER_SERIAL, issuer, GENERAL_NAME), + ASN1_EMBED(OSSL_ISSUER_SERIAL, serial, ASN1_INTEGER), + ASN1_OPT(OSSL_ISSUER_SERIAL, issuerUID, ASN1_BIT_STRING), +} ASN1_SEQUENCE_END(OSSL_ISSUER_SERIAL) + +ASN1_SEQUENCE(X509_ACERT_ISSUER_V2FORM) = { + ASN1_SEQUENCE_OF_OPT(X509_ACERT_ISSUER_V2FORM, issuerName, GENERAL_NAME), + ASN1_IMP_OPT(X509_ACERT_ISSUER_V2FORM, baseCertificateId, OSSL_ISSUER_SERIAL, 0), + ASN1_IMP_OPT(X509_ACERT_ISSUER_V2FORM, objectDigestInfo, OSSL_OBJECT_DIGEST_INFO, 1), +} ASN1_SEQUENCE_END(X509_ACERT_ISSUER_V2FORM) + +ASN1_CHOICE(X509_ACERT_ISSUER) = { + ASN1_SEQUENCE_OF(X509_ACERT_ISSUER, u.v1Form, GENERAL_NAME), + ASN1_IMP(X509_ACERT_ISSUER, u.v2Form, X509_ACERT_ISSUER_V2FORM, 0), +} ASN1_CHOICE_END(X509_ACERT_ISSUER) + +ASN1_SEQUENCE(X509_HOLDER) = { + ASN1_IMP_OPT(X509_HOLDER, baseCertificateID, OSSL_ISSUER_SERIAL, 0), + ASN1_IMP_SEQUENCE_OF_OPT(X509_HOLDER, entityName, GENERAL_NAME, 1), + ASN1_IMP_OPT(X509_HOLDER, objectDigestInfo, OSSL_OBJECT_DIGEST_INFO, 2), +} ASN1_SEQUENCE_END(X509_HOLDER) + +ASN1_SEQUENCE(X509_ACERT_INFO) = { + ASN1_EMBED(X509_ACERT_INFO, version, ASN1_INTEGER), + ASN1_EMBED(X509_ACERT_INFO, holder, X509_HOLDER), + ASN1_EMBED(X509_ACERT_INFO, issuer, X509_ACERT_ISSUER), + ASN1_EMBED(X509_ACERT_INFO, signature, X509_ALGOR), + ASN1_EMBED(X509_ACERT_INFO, serialNumber, ASN1_INTEGER), + ASN1_EMBED(X509_ACERT_INFO, validityPeriod, X509_VAL), + ASN1_SEQUENCE_OF(X509_ACERT_INFO, attributes, X509_ATTRIBUTE), + ASN1_OPT(X509_ACERT_INFO, issuerUID, ASN1_BIT_STRING), + ASN1_SEQUENCE_OF_OPT(X509_ACERT_INFO, extensions, X509_EXTENSION), +} ASN1_SEQUENCE_END(X509_ACERT_INFO) + +ASN1_SEQUENCE(X509_ACERT) = { + ASN1_SIMPLE(X509_ACERT, acinfo, X509_ACERT_INFO), + ASN1_EMBED(X509_ACERT, sig_alg, X509_ALGOR), + ASN1_EMBED(X509_ACERT, signature, ASN1_BIT_STRING), +} ASN1_SEQUENCE_END(X509_ACERT) + +IMPLEMENT_ASN1_FUNCTIONS(X509_ACERT) +IMPLEMENT_ASN1_DUP_FUNCTION(X509_ACERT) +IMPLEMENT_ASN1_ALLOC_FUNCTIONS(X509_ACERT_INFO) +IMPLEMENT_ASN1_ALLOC_FUNCTIONS(OSSL_ISSUER_SERIAL) +IMPLEMENT_ASN1_ALLOC_FUNCTIONS(OSSL_OBJECT_DIGEST_INFO) +IMPLEMENT_ASN1_ALLOC_FUNCTIONS(X509_ACERT_ISSUER_V2FORM) + +IMPLEMENT_PEM_rw(X509_ACERT, X509_ACERT, PEM_STRING_ACERT, X509_ACERT) + diff --git a/crypto/x509/x509_acert.h b/crypto/x509/x509_acert.h new file mode 100644 index 00000000000..e2680d32973 --- /dev/null +++ b/crypto/x509/x509_acert.h @@ -0,0 +1,22 @@ +/* + * Copyright 2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef OSSL_CRYPTO_X509_X509_ACERT_H +# define OSSL_CRYPTO_X509_X509_ACERT_H + +#include + +# define X509_ACERT_ISSUER_V2 1 + +DECLARE_ASN1_ITEM(OSSL_OBJECT_DIGEST_INFO) +DECLARE_ASN1_ITEM(OSSL_ISSUER_SERIAL) +DECLARE_ASN1_ITEM(X509_ACERT_ISSUER_V2FORM) +DECLARE_ASN1_ITEM(X509_ACERT_ISSUER) +DECLARE_ASN1_ITEM(X509_HOLDER) +#endif diff --git a/crypto/x509/x_all.c b/crypto/x509/x_all.c index 3e4c852b70a..95c91a0f206 100644 --- a/crypto/x509/x_all.c +++ b/crypto/x509/x_all.c @@ -26,6 +26,7 @@ #include "internal/asn1.h" #include "crypto/pkcs7.h" #include "crypto/x509.h" +#include "crypto/x509_acert.h" #include "crypto/rsa.h" int X509_verify(X509 *a, EVP_PKEY *r) @@ -824,3 +825,25 @@ EVP_PKEY *d2i_PUBKEY_bio(BIO *bp, EVP_PKEY **a) { return ASN1_d2i_bio_of(EVP_PKEY, EVP_PKEY_new, d2i_PUBKEY, bp, a); } + +#ifndef OPENSSL_NO_STDIO +X509_ACERT *d2i_X509_ACERT_fp(FILE *fp, X509_ACERT **acert) +{ + return ASN1_item_d2i_fp(ASN1_ITEM_rptr(X509_ACERT), fp, acert); +} + +int i2d_X509_ACERT_fp(FILE *fp, const X509_ACERT *acert) +{ + return ASN1_item_i2d_fp(ASN1_ITEM_rptr(X509_ACERT), fp, acert); +} +#endif + +X509_ACERT *d2i_X509_ACERT_bio(BIO *bp, X509_ACERT **acert) +{ + return ASN1_item_d2i_bio(ASN1_ITEM_rptr(X509_ACERT), bp, acert); +} + +int i2d_X509_ACERT_bio(BIO *bp, const X509_ACERT *acert) +{ + return ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509_ACERT), bp, acert); +} diff --git a/doc/man3/PEM_read_bio_PrivateKey.pod b/doc/man3/PEM_read_bio_PrivateKey.pod index ac93920adde..6e521b268f0 100644 --- a/doc/man3/PEM_read_bio_PrivateKey.pod +++ b/doc/man3/PEM_read_bio_PrivateKey.pod @@ -26,6 +26,8 @@ PEM_write_bio_Parameters, PEM_read_bio_DSAparams, PEM_read_DSAparams, PEM_write_bio_DSAparams, PEM_write_DSAparams, PEM_read_bio_DHparams, PEM_read_DHparams, PEM_write_bio_DHparams, PEM_write_DHparams, PEM_read_bio_X509, PEM_read_X509, PEM_write_bio_X509, PEM_write_X509, +PEM_read_bio_X509_ACERT, PEM_read_X509_ACERT, +PEM_write_bio_X509_ACERT, PEM_write_X509_ACERT, PEM_read_bio_X509_AUX, PEM_read_X509_AUX, PEM_write_bio_X509_AUX, PEM_write_X509_AUX, PEM_read_bio_X509_REQ, PEM_read_X509_REQ, PEM_write_bio_X509_REQ, PEM_write_X509_REQ, PEM_write_bio_X509_REQ_NEW, @@ -108,6 +110,13 @@ PEM_write_bio_PKCS7, PEM_write_PKCS7 - PEM routines int PEM_write_bio_X509(BIO *bp, X509 *x); int PEM_write_X509(FILE *fp, X509 *x); + X509_ACERT *PEM_read_bio_X509_ACERT(BIO *bp, X509_ACERT **x, + pem_password_cb *cb, void *u); + X509_ACERT *PEM_read_X509_ACERT(FILE *fp, X509_ACERT **x, + pem_password_cb *cb, void *u); + int PEM_write_bio_X509_ACERT(BIO *bp, X509_ACERT *x); + int PEM_write_X509_ACERT(FILE *fp, X509_ACERT *x); + X509 *PEM_read_bio_X509_AUX(BIO *bp, X509 **x, pem_password_cb *cb, void *u); X509 *PEM_read_X509_AUX(FILE *fp, X509 **x, pem_password_cb *cb, void *u); int PEM_write_bio_X509_AUX(BIO *bp, X509 *x); @@ -287,6 +296,9 @@ The B functions process an X509 certificate using an X509 structure. They will also process a trusted X509 certificate but any trust settings are discarded. +The B functions process an X509 attribute certificate using +an X509_ACERT structure. + The B functions process a trusted X509 certificate using an X509 structure. diff --git a/doc/man3/X509_dup.pod b/doc/man3/X509_dup.pod index 86a259f025f..621427e3fbf 100644 --- a/doc/man3/X509_dup.pod +++ b/doc/man3/X509_dup.pod @@ -171,6 +171,10 @@ OSSL_CRMF_PKIPUBLICATIONINFO_new, OSSL_CRMF_SINGLEPUBINFO_free, OSSL_CRMF_SINGLEPUBINFO_it, OSSL_CRMF_SINGLEPUBINFO_new, +OSSL_ISSUER_SERIAL_free, +OSSL_ISSUER_SERIAL_new, +OSSL_OBJECT_DIGEST_INFO_free, +OSSL_OBJECT_DIGEST_INFO_new, OTHERNAME_free, OTHERNAME_new, PBE2PARAM_free, @@ -265,6 +269,15 @@ TS_TST_INFO_free, TS_TST_INFO_new, USERNOTICE_free, USERNOTICE_new, +X509_ACERT_dup, +X509_ACERT_free, +X509_ACERT_it, +X509_ACERT_new, +X509_ACERT_INFO_free, +X509_ACERT_INFO_it, +X509_ACERT_INFO_new, +X509_ACERT_ISSUER_V2FORM_free, +X509_ACERT_ISSUER_V2FORM_new, X509_ALGOR_free, X509_ALGOR_it, X509_ALGOR_new, diff --git a/doc/man3/d2i_X509.pod b/doc/man3/d2i_X509.pod index 00efb603581..6c4464deb46 100644 --- a/doc/man3/d2i_X509.pod +++ b/doc/man3/d2i_X509.pod @@ -157,6 +157,9 @@ d2i_USERNOTICE, d2i_X509, d2i_X509_bio, d2i_X509_fp, +d2i_X509_ACERT, +d2i_X509_ACERT_bio, +d2i_X509_ACERT_fp, d2i_X509_ALGOR, d2i_X509_ALGORS, d2i_X509_ATTRIBUTE, @@ -331,6 +334,9 @@ i2d_USERNOTICE, i2d_X509, i2d_X509_bio, i2d_X509_fp, +i2d_X509_ACERT, +i2d_X509_ACERT_bio, +i2d_X509_ACERT_fp, i2d_X509_ALGOR, i2d_X509_ALGORS, i2d_X509_ATTRIBUTE, diff --git a/include/crypto/x509_acert.h b/include/crypto/x509_acert.h new file mode 100644 index 00000000000..3223bf62344 --- /dev/null +++ b/include/crypto/x509_acert.h @@ -0,0 +1,66 @@ +/* + * Copyright 2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef OSSL_CRYPTO_X509_ACERT_H +# define OSSL_CRYPTO_X509_ACERT_H +# pragma once + +# include + +struct ossl_object_digest_info_st { + ASN1_ENUMERATED digestedObjectType; + ASN1_OBJECT *otherObjectTypeID; + X509_ALGOR digestAlgorithm; + ASN1_BIT_STRING objectDigest; +}; + +struct ossl_issuer_serial_st { + STACK_OF(GENERAL_NAME) *issuer; + ASN1_INTEGER serial; + ASN1_BIT_STRING *issuerUID; +}; + +struct X509_acert_issuer_v2form_st { + STACK_OF(GENERAL_NAME) *issuerName; + OSSL_ISSUER_SERIAL *baseCertificateId; + OSSL_OBJECT_DIGEST_INFO *objectDigestInfo; +}; + +typedef struct X509_acert_issuer_st { + int type; + union { + STACK_OF(GENERAL_NAME) *v1Form; + X509_ACERT_ISSUER_V2FORM *v2Form; + } u; +} X509_ACERT_ISSUER; + +typedef struct X509_holder_st { + OSSL_ISSUER_SERIAL *baseCertificateID; + STACK_OF(GENERAL_NAME) *entityName; + OSSL_OBJECT_DIGEST_INFO *objectDigestInfo; +} X509_HOLDER; + +struct X509_acert_info_st { + ASN1_INTEGER version; /* default of v2 */ + X509_HOLDER holder; + X509_ACERT_ISSUER issuer; + X509_ALGOR signature; + ASN1_INTEGER serialNumber; + X509_VAL validityPeriod; + STACK_OF(X509_ATTRIBUTE) *attributes; + ASN1_BIT_STRING *issuerUID; + X509_EXTENSIONS *extensions; +}; + +struct X509_acert_st { + X509_ACERT_INFO *acinfo; + X509_ALGOR sig_alg; + ASN1_BIT_STRING signature; +}; +#endif diff --git a/include/openssl/pem.h b/include/openssl/pem.h index 0446c77019a..6ea1a49a694 100644 --- a/include/openssl/pem.h +++ b/include/openssl/pem.h @@ -58,6 +58,7 @@ extern "C" { # define PEM_STRING_PARAMETERS "PARAMETERS" # define PEM_STRING_CMS "CMS" # define PEM_STRING_SM2PARAMETERS "SM2 PARAMETERS" +# define PEM_STRING_ACERT "ATTRIBUTE CERTIFICATE" # define PEM_TYPE_ENCRYPTED 10 # define PEM_TYPE_MIC_ONLY 20 diff --git a/include/openssl/x509_acert.h.in b/include/openssl/x509_acert.h.in new file mode 100644 index 00000000000..1d66af95457 --- /dev/null +++ b/include/openssl/x509_acert.h.in @@ -0,0 +1,48 @@ +/* + * {- join("\n * ", @autowarntext) -} + * + * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +{- +use OpenSSL::stackhash qw(generate_stack_macros); +-} + +#ifndef OPENSSL_X509_ACERT_H +# define OPENSSL_X509_ACERT_H +# pragma once + +# include +# include +# include + +typedef struct X509_acert_st X509_ACERT; +typedef struct X509_acert_info_st X509_ACERT_INFO; +typedef struct ossl_object_digest_info_st OSSL_OBJECT_DIGEST_INFO; +typedef struct ossl_issuer_serial_st OSSL_ISSUER_SERIAL; +typedef struct X509_acert_issuer_v2form_st X509_ACERT_ISSUER_V2FORM; + +DECLARE_ASN1_FUNCTIONS(X509_ACERT) +DECLARE_ASN1_DUP_FUNCTION(X509_ACERT) +DECLARE_ASN1_ITEM(X509_ACERT_INFO) +DECLARE_ASN1_ALLOC_FUNCTIONS(X509_ACERT_INFO) +DECLARE_ASN1_ALLOC_FUNCTIONS(OSSL_OBJECT_DIGEST_INFO) +DECLARE_ASN1_ALLOC_FUNCTIONS(OSSL_ISSUER_SERIAL) +DECLARE_ASN1_ALLOC_FUNCTIONS(X509_ACERT_ISSUER_V2FORM) + +# ifndef OPENSSL_NO_STDIO +X509_ACERT *d2i_X509_ACERT_fp(FILE *fp, X509_ACERT **acert); +int i2d_X509_ACERT_fp(FILE *fp, const X509_ACERT *acert); +# endif + +DECLARE_PEM_rw(X509_ACERT, X509_ACERT) + +X509_ACERT *d2i_X509_ACERT_bio(BIO *bp, X509_ACERT **acert); +int i2d_X509_ACERT_bio(BIO *bp, const X509_ACERT *acert); + +#endif diff --git a/util/libcrypto.num b/util/libcrypto.num index ec20d5490e5..dbba798a3b7 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5550,3 +5550,26 @@ OPENSSL_LH_doall_arg_thunk 5677 3_3_0 EXIST::FUNCTION: OSSL_HTTP_REQ_CTX_set_max_response_hdr_lines 5678 3_3_0 EXIST::FUNCTION:HTTP CRYPTO_atomic_store ? 3_4_0 EXIST::FUNCTION: CRYPTO_aligned_alloc ? 3_4_0 EXIST::FUNCTION: +d2i_X509_ACERT ? 3_4_0 EXIST::FUNCTION: +i2d_X509_ACERT ? 3_4_0 EXIST::FUNCTION: +X509_ACERT_free ? 3_4_0 EXIST::FUNCTION: +X509_ACERT_new ? 3_4_0 EXIST::FUNCTION: +X509_ACERT_it ? 3_4_0 EXIST::FUNCTION: +X509_ACERT_dup ? 3_4_0 EXIST::FUNCTION: +X509_ACERT_INFO_it ? 3_4_0 EXIST::FUNCTION: +X509_ACERT_INFO_free ? 3_4_0 EXIST::FUNCTION: +X509_ACERT_INFO_new ? 3_4_0 EXIST::FUNCTION: +OSSL_OBJECT_DIGEST_INFO_free ? 3_4_0 EXIST::FUNCTION: +OSSL_OBJECT_DIGEST_INFO_new ? 3_4_0 EXIST::FUNCTION: +OSSL_ISSUER_SERIAL_free ? 3_4_0 EXIST::FUNCTION: +OSSL_ISSUER_SERIAL_new ? 3_4_0 EXIST::FUNCTION: +X509_ACERT_ISSUER_V2FORM_free ? 3_4_0 EXIST::FUNCTION: +X509_ACERT_ISSUER_V2FORM_new ? 3_4_0 EXIST::FUNCTION: +d2i_X509_ACERT_fp ? 3_4_0 EXIST::FUNCTION:STDIO +i2d_X509_ACERT_fp ? 3_4_0 EXIST::FUNCTION:STDIO +PEM_read_X509_ACERT ? 3_4_0 EXIST::FUNCTION:STDIO +PEM_write_X509_ACERT ? 3_4_0 EXIST::FUNCTION:STDIO +PEM_read_bio_X509_ACERT ? 3_4_0 EXIST::FUNCTION: +PEM_write_bio_X509_ACERT ? 3_4_0 EXIST::FUNCTION: +d2i_X509_ACERT_bio ? 3_4_0 EXIST::FUNCTION: +i2d_X509_ACERT_bio ? 3_4_0 EXIST::FUNCTION: