/*
 *  Copyright 2014-2026 The GmSSL Project. All Rights Reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the License); you may
 *  not use this file except in compliance with the License.
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 */


/*
References:
  1. GM/T 0010-2012 SM2 Cryptography Message Syntax Specification
  2. RFC 2315 PKCS #7 Cryptographic Message Syntax Version 1.5
  3. RFC 5652 Cryptographic Message Syntax (CMS)
*/

#ifndef GMSSL_CMS_H
#define GMSSL_CMS_H


#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <gmssl/x509.h>
#include <gmssl/x509_key.h>


#ifdef __cplusplus
extern "C" {
#endif

enum {
	CMS_version_v1 = 1,
};


/*
ContentType:
	OID_cms_data
	OID_cms_signed_data
	OID_cms_enveloped_data
	OID_cms_signed_and_enveloped_data
	OID_cms_encrypted_data
	OID_cms_key_agreement_info
*/
const char *cms_content_type_name(int oid);
int cms_content_type_from_name(const char *name);
int cms_content_type_to_der(int oid, uint8_t **out, size_t *outlen);
int cms_content_type_from_der(int *oid, const uint8_t **in, size_t *inlen);

/*
ContentInfo ::= SEQUENCE {
	contentType	OBJECT IDENTIFIER,
	content		[0] EXPLICIT ANY OPTIONAL }
*/
int cms_content_info_header_to_der(
	int content_type, size_t content_len,
	uint8_t **out, size_t *outlen);
int cms_content_info_to_der(
	int content_type,
	const uint8_t *content, size_t content_len,
	uint8_t **out, size_t *outlen);
int cms_content_info_from_der(
	int *content_type,
	const uint8_t **content, size_t *content_len, // content is the full TLV
	const uint8_t **in, size_t *inlen);
int cms_content_info_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);

/*
Data ::= OCTET STRING
*/
#define cms_data_to_der(d,dlen,out,outlen) asn1_octet_string_to_der(d,dlen,out,outlen)
#define cms_data_from_der(d,dlen,in,inlen) asn1_octet_string_from_der(d,dlen,in,inlen)
#define cms_data_print(fp,fmt,ind,label,d,dlen) format_bytes(fp,fmt,ind,label,d,dlen)

/*
EncryptedContentInfo ::= SEQUENCE {
	contentType			OBJECT IDENTIFIER,
	contentEncryptionAlgorithm	AlgorithmIdentifier,
	encryptedContent		[0] IMPLICIT OCTET STRING OPTIONAL,
	sharedInfo1			[1] IMPLICIT OCTET STRING OPTIONAL,
	sharedInfo2			[2] IMPLICIT OCTET STRING OPTIONAL }
*/
int cms_enced_content_info_to_der(
	int content_type,
	int enc_algor, const uint8_t *enc_iv, size_t enc_iv_len,
	const uint8_t *enced_content, size_t enced_content_len,
	const uint8_t *shared_info1, size_t shared_info1_len,
	const uint8_t *shared_info2, size_t shared_info2_len,
	uint8_t **out, size_t *outlen);
int cms_enced_content_info_from_der(
	int *content_type,
	int *enc_algor, const uint8_t **enc_iv, size_t *enc_iv_len,
	const uint8_t **enced_content, size_t *enced_content_len,
	const uint8_t **shared_info1, size_t *shared_info1_len,
	const uint8_t **shared_info2, size_t *shared_info2_len,
	const uint8_t **in, size_t *inlen);
int cms_enced_content_info_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);

int cms_enced_content_info_encrypt_to_der(
	int enc_algor,
	const uint8_t *key, size_t keylen,
	const uint8_t *iv, size_t ivlen,
	int content_type, const uint8_t *content, size_t content_len,
	const uint8_t *shared_info1, size_t shared_info1_len,
	const uint8_t *shared_info2, size_t shared_info2_len,
	uint8_t **out, size_t *outlen);
int cms_enced_content_info_decrypt_from_der(
	int *enc_algor,
	const uint8_t *key, size_t keylen,
	int *content_type, uint8_t *content, size_t *content_len,
	const uint8_t **shared_info1, size_t *shared_info1_len,
	const uint8_t **shared_info2, size_t *shared_info2_len,
	const uint8_t **in, size_t *inlen);

/*
EncryptedData ::= SEQUENCE {
	version			INTEGER (1),
	encryptedContentInfo	EncryptedContentInfo }
*/
int cms_encrypted_data_to_der(
	int version,
	int content_type,
	int enc_algor, const uint8_t *iv, size_t ivlen,
	const uint8_t *enced_content, size_t enced_content_len,
	const uint8_t *shared_info1, size_t shared_info1_len,
	const uint8_t *shared_info2, size_t shared_info2_len,
	uint8_t **out, size_t *outlen);
int cms_encrypted_data_from_der(
	int *version,
	int *content_type,
	int *enc_algor, const uint8_t **iv, size_t *ivlen,
	const uint8_t **enced_content, size_t *enced_content_len,
	const uint8_t **shared_info1, size_t *shared_info1_len,
	const uint8_t **shared_info2, size_t *shared_info2_len,
	const uint8_t **in, size_t *inlen);
int cms_encrypted_data_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);

int cms_encrypted_data_encrypt_to_der(
	int enc_algor,
	const uint8_t *key, size_t keylen,
	const uint8_t *iv, size_t ivlen,
	int content_type, const uint8_t *content, size_t content_len,
	const uint8_t *shared_info1, size_t shared_info1_len,
	const uint8_t *shared_info2, size_t shared_info2_len,
	uint8_t **out, size_t *outlen);
int cms_encrypted_data_decrypt_from_der(
	int *enc_algor,
	const uint8_t *key, size_t keylen,
	int *content_type, uint8_t *content, size_t *content_len,
	const uint8_t **shared_info1, size_t *shared_info1_len,
	const uint8_t **shared_info2, size_t *shared_info2_len,
	const uint8_t **in, size_t *inlen);

/*
IssuerAndSerialNumber ::= SEQUENCE {
	isser		Name,
	serialNumber	INTEGER }
*/
int cms_issuer_and_serial_number_to_der(
	const uint8_t *issuer, size_t issuer_len,
	const uint8_t *serial_number, size_t serial_number_len,
	uint8_t **out, size_t *outlen);
int cms_issuer_and_serial_number_from_der(
	const uint8_t **issuer, size_t *issuer_len,
	const uint8_t **serial_number, size_t *serial_number_len,
	const uint8_t **in, size_t *inlen);
int cms_issuer_and_serial_number_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);

/*
SignerInfo ::= SEQUENCE {
	version				INTEGER (1),
	issuerAndSerialNumber		IssuerAndSerialNumber,
	digestAlgorithm			AlgorithmIdentifier,
	authenticatedAttributes		[0] IMPLICIT SET OF Attribute OPTINOAL,
	digestEncryptionAlgorithm	AlgorithmIdentifier,
	encryptedDigest			OCTET STRING,
	unauthenticatedAttributes       [1] IMPLICIT SET OF Attribute OPTINOAL, }
*/
int cms_signer_info_to_der(
	int version,
	const uint8_t *issuer, size_t issuer_len,
	const uint8_t *serial_number, size_t serial_number_len,
	int digest_algor,
	const uint8_t *authed_attrs, size_t authed_attrs_len,
	int signature_algor,
	const uint8_t *enced_digest, size_t enced_digest_len,
	const uint8_t *unauthed_attrs, size_t unauthed_attrs_len,
	uint8_t **out, size_t *outlen);
int cms_signer_info_from_der(
	int *version,
	const uint8_t **issuer, size_t *issuer_len,
	const uint8_t **serial_number, size_t *serial_number_len,
	int *digest_algor,
	const uint8_t **authed_attrs, size_t *authed_attrs_len,
	int *signature_algor,
	const uint8_t **enced_digest, size_t *enced_digest_len,
	const uint8_t **unauthed_attrs, size_t *unauthed_attrs_len,
	const uint8_t **in, size_t *inlen);
int cms_signer_info_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);

int cms_signer_info_sign_to_der(
	const SM3_CTX *sm3_ctx, const X509_KEY *x509_key,
	const uint8_t *issuer, size_t issuer_len,
	const uint8_t *serial_number, size_t serial_number_len,
	const uint8_t *authed_attrs, size_t authed_attrs_len,
	const uint8_t *unauthed_attrs, size_t unauthed_attrs_len,
	uint8_t **out, size_t *outlen);
int cms_signer_info_verify_from_der(
	const SM3_CTX *sm3_ctx, const uint8_t *certs, size_t certslen,
	const uint8_t **cert, size_t *certlen,
	const uint8_t **issuer, size_t *issuer_len,
	const uint8_t **serial, size_t *serial_len,
	const uint8_t **authed_attrs, size_t *authed_attrs_len,
	const uint8_t **unauthed_attrs, size_t *unauthed_attrs_len,
	const uint8_t **in, size_t *inlen);
/*
SignerInfos ::= SET OF SignerInfo;
*/
int cms_signer_infos_add_signer_info(
	uint8_t *d, size_t *dlen, size_t maxlen,
	const SM3_CTX *sm3_ctx, const X509_KEY *sign_key,
	const uint8_t *issuer, size_t issuer_len,
	const uint8_t *serial_number, size_t serial_number_len,
	const uint8_t *authed_attrs, size_t authed_attrs_len,
	const uint8_t *unauthed_attrs, size_t unauthed_attrs_len);
#define cms_signer_infos_to_der(d,dlen,out,outlen) asn1_set_to_der(d,dlen,out,outlen)
#define cms_signer_infos_from_der(d,dlen,in,inlen) asn1_set_from_der(d,dlen,in,inlen)
int cms_signer_infos_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);

int cms_digest_algors_to_der(const int *digest_algors, size_t digest_algors_cnt, uint8_t **out, size_t *outlen);
int cms_digest_algors_from_der(int *digest_algors, size_t *digest_algors_cnt, size_t max_digest_algors,
	const uint8_t **in, size_t *inlen);
int cms_digest_algors_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);

/*
SignedData ::= SEQUENCE {
	version			INTEGER (1),
	digestAlgorithms	SET OF AlgorithmIdentifier,
	contentInfo		ContentInfo,
	certificates		[0] IMPLICIT SET OF Certificate OPTIONAL,
	crls			[1] IMPLICIT SET OF CertificateRevocationList OPTIONAL,
	signerInfos		SET OF SignerInfo }
*/
int cms_signed_data_to_der(
	int version,
	const int *digest_algors, size_t digest_algors_cnt,
	const int content_type, const uint8_t *content, const size_t content_len,
	const uint8_t *certs, size_t certs_len,
	const uint8_t *crls, const size_t crls_len,
	const uint8_t *signer_infos, size_t signer_infos_len,
	uint8_t **out, size_t *outlen);
int cms_signed_data_from_der(
	int *version,
	int *digest_algors, size_t *digest_algors_cnt, size_t max_digest_algors,
	int *content_type, const uint8_t **content, size_t *content_len,
	const uint8_t **certs, size_t *certs_len,
	const uint8_t **crls, size_t *crls_len,
	const uint8_t **signer_infos, size_t *signer_infos_len,
	const uint8_t **in, size_t *inlen);
int cms_signed_data_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);


typedef struct {
	uint8_t *certs;
	size_t certs_len;
	X509_KEY *sign_key;
} CMS_CERTS_AND_KEY;

int cms_signed_data_sign_to_der(
	const CMS_CERTS_AND_KEY *signers, size_t signers_cnt,
	int content_type, const uint8_t *data, size_t datalen, // with OID_cms_data, `data` is the raw data
	const uint8_t *crls, size_t crls_len, // crls can be NULL
	uint8_t **out, size_t *outlen);
int cms_signed_data_verify_from_der(
	const uint8_t *extra_certs, size_t extra_certs_len,
	const uint8_t *extra_crls, size_t extra_crls_len,
	int *content_type, const uint8_t **content, size_t *content_len, // should we return raw data			
	const uint8_t **certs, size_t *certs_len,
	const uint8_t **crls, size_t *crls_len,
	const uint8_t **signer_infos, size_t *signer_infos_len,
	const uint8_t **in, size_t *inlen);


/*
RecipientInfo ::= SEQUENCE {
	version				INTEGER (1),
	issuerAndSerialNumber		IssuerAndSerialNumber,
	keyEncryptionAlgorithm		AlgorithmIdentifier,
	encryptedKey			OCTET STRING -- DER-encoding of SM2Cipher
}

DER-encoding length of RecipientInfo is not fixed (caused by INTEGERs)
*/
int cms_recipient_info_to_der(
	int version,
	const uint8_t *issuer, size_t issuer_len,
	const uint8_t *serial_number, size_t serial_number_len,
	int public_key_enc_algor,
	const uint8_t *enced_key, size_t enced_key_len,
	uint8_t **out, size_t *outlen);
int cms_recipient_info_from_der(
	int *version,
	const uint8_t **issuer, size_t *issuer_len,
	const uint8_t **serial_number, size_t *serial_number_len,
	int *pke_algor, const uint8_t **params, size_t *params_len,// sm2encrypt has no params, but ECIES might have params
	const uint8_t **enced_key, size_t *enced_key_len,
	const uint8_t **in, size_t *inlen);
int cms_recipient_info_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);


int cms_recipient_info_encrypt_to_der(
	const X509_KEY *public_key,
	const uint8_t *issuer, size_t issuer_len,
	const uint8_t *serial, size_t serial_len,
	const uint8_t *in, size_t inlen,
	uint8_t **out, size_t *outlen);
int cms_recipient_info_decrypt_from_der(
	const X509_KEY *sm2_key,
	const uint8_t *rcpt_issuer, size_t rcpt_issuer_len,
	const uint8_t *rcpt_serial, size_t rcpt_serial_len,
	uint8_t *out, size_t *outlen, size_t maxlen,
	const uint8_t **in, size_t *inlen);

int cms_recipient_infos_add_recipient_info(
	uint8_t *d, size_t *dlen, size_t maxlen,
	const X509_KEY *public_key,
	const uint8_t *issuer, size_t issuer_len,
	const uint8_t *serial, size_t serial_len,
	const uint8_t *in, size_t inlen);
#define cms_recipient_infos_to_der(d,dlen,out,outlen) asn1_set_to_der(d,dlen,out,outlen)
#define cms_recipient_infos_from_der(d,dlen,in,inlen) asn1_set_from_der(d,dlen,in,inlen)
int cms_recipient_infos_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);

/*
EnvelopedData ::= SEQUENCE {
	version			Version,
	recipientInfos		SET OF RecipientInfo,
	encryptedContentInfo	EncryptedContentInfo }
*/
int cms_enveloped_data_to_der(
	int version,
	const uint8_t *rcpt_infos, size_t rcpt_infos_len,
	int content_type,
	int enc_algor, const uint8_t *enc_iv, size_t enc_iv_len,
	const uint8_t *enced_content, size_t enced_content_len,
	const uint8_t *shared_info1, size_t shared_info1_len,
	const uint8_t *shared_info2, size_t shared_info2_len,
	uint8_t **out, size_t *outlen);
int cms_enveloped_data_from_der(
	int *version,
	const uint8_t **rcpt_infos, size_t *rcpt_infos_len,
	const uint8_t **enced_content_info, size_t *enced_content_info_len,
	const uint8_t **in, size_t *inlen);
int cms_enveloped_data_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);

int cms_enveloped_data_encrypt_to_der(
	const uint8_t *rcpt_certs, size_t rcpt_certs_len,
	int enc_algor, const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
	int content_type, const uint8_t *content, size_t content_len,
	const uint8_t *shared_info1, size_t shared_info1_len,
	const uint8_t *shared_info2, size_t shared_info2_len,
	uint8_t **out, size_t *outlen);
// issuer/serial must be extracted from cert via x509_cert_get_issuer_and_serial_number()
// to get canonical DER encoding; raw bytes may differ after ASN.1 INTEGER normalization.
int cms_enveloped_data_decrypt_from_der(
	const X509_KEY *sm2_key,
	const uint8_t *issuer, size_t issuer_len,
	const uint8_t *serial_number, size_t serial_number_len,
	int *content_type, uint8_t *content, size_t *content_len,
	const uint8_t **rcpt_infos, size_t *rcpt_infos_len,
	const uint8_t **shared_info1, size_t *shared_info1_len,
	const uint8_t **shared_info2, size_t *shared_info2_len,
	const uint8_t **in, size_t *inlen);

/*
SignedAndEnvelopedData ::= SEQUENCE {
	version			INTEGER (1),
	recipientInfos		SET OF RecipientInfo,
	digestAlgorithms	SET OF AlgorithmIdentifier,
	encryptedContentInfo	EncryptedContentInfo,
	certificates		[0] IMPLICIT SET OF Certificate OPTIONAL,
	crls			[1] IMPLICIT SET OF CertificateRevocationList OPTIONAL,
	signerInfos		SET OF SignerInfo }
*/
int cms_signed_and_enveloped_data_to_der(
	int version,
	const uint8_t *rcpt_infos, size_t rcpt_infos_len,
	const int *digest_algors, size_t digest_algors_cnt,
	int content_type,
	int enc_algor, const uint8_t *iv, size_t ivlen,
	const uint8_t *enced_content, size_t enced_content_len,
	const uint8_t *shared_info1, size_t shared_info1_len,
	const uint8_t *shared_info2, size_t shared_info2_len,
	const uint8_t *certs, size_t certs_len,
	const uint8_t *crls, size_t crls_len,
	const uint8_t *signer_infos, size_t signer_infos_len,
	uint8_t **out, size_t *outlen);
int cms_signed_and_enveloped_data_from_der(
	int *version,
	const uint8_t **rcpt_infos, size_t *rcpt_infos_len,
	int *digest_algors, size_t *digest_algors_cnt, size_t max_digest_algors,
	const uint8_t **enced_content_info, size_t *enced_content_info_len,
	const uint8_t **certs, size_t *certs_len,
	const uint8_t **crls, size_t *crls_len,
	const uint8_t **signer_infos, size_t *signer_infos_len,
	const uint8_t **in, size_t *inlen);
int cms_signed_and_enveloped_data_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);

int cms_signed_and_enveloped_data_encipher_to_der(
	const CMS_CERTS_AND_KEY *signers, size_t signers_cnt,
	const uint8_t *rcpt_certs, size_t rcpt_certs_len,
	int enc_algor, const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
	int content_type, const uint8_t *content, size_t content_len,
	const uint8_t *signers_crls, size_t signers_crls_len,
	const uint8_t *shared_info1, size_t shared_info1_len,
	const uint8_t *shared_info2, size_t shared_info2_len,
	uint8_t **out, size_t *outlen);
// rcpt_issuer/rcpt_serial must be from x509_cert_get_issuer_and_serial_number() (see above).
int cms_signed_and_enveloped_data_decipher_from_der(
	const X509_KEY *rcpt_key,
	const uint8_t *rcpt_issuer, size_t rcpt_issuer_len,
	const uint8_t *rcpt_serial, size_t rcpt_serial_len,
	int *content_type, uint8_t *content, size_t *content_len,
	const uint8_t **prcpt_infos, size_t *prcpt_infos_len,
	const uint8_t **shared_info1, size_t *shared_info1_len,
	const uint8_t **shared_info2, size_t *shared_info2_len,
	const uint8_t **certs, size_t *certs_len,
	const uint8_t **crls, size_t *crls_len,
	const uint8_t **psigner_infos, size_t *psigner_infos_len,
	const uint8_t *extra_certs, size_t extra_certs_len,
	const uint8_t *extra_crls, size_t extra_crls_len,
	const uint8_t **in, size_t *inlen);

/*
KeyAgreementInfo ::= SEQUENCE {
	version			INTEGER (1),
	tempPublicKeyR		SM2PublicKey,
	userCertificate		Certificate,
	userID			OCTET STRING }
*/
int cms_key_agreement_info_to_der(
	int version,
	const X509_KEY *temp_public_key_r,
	const uint8_t *user_cert, size_t user_cert_len,
	const uint8_t *user_id, size_t user_id_len,
	uint8_t **out, size_t *outlen);
int cms_key_agreement_info_from_der(
	int *version,
	X509_KEY *temp_public_key_r,
	const uint8_t **user_cert, size_t *user_cert_len,
	const uint8_t **user_id, size_t *user_id_len,
	const uint8_t **in, size_t *inlen);
int cms_key_agreement_info_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);




// generate ContentInfo, type == data
int cms_set_data(uint8_t *cms, size_t *cmslen,
	const uint8_t *d, size_t dlen);

int cms_encrypt(
	uint8_t *cms, size_t *cmslen,
	int enc_algor, const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
	int content_type, const uint8_t *content, size_t content_len,
	const uint8_t *shared_info1, size_t shared_info1_len,
	const uint8_t *shared_info2, size_t shared_info2_len);

int cms_decrypt(
	const uint8_t *cms, size_t cmslen, // should be ContentInfo (type encryptedData)
	int *enc_algor, const uint8_t *key, size_t keylen,
	int *content_type, uint8_t *content, size_t *content_len,
	const uint8_t **shared_info1, size_t *shared_info1_len,
	const uint8_t **shared_info2, size_t *shared_info2_len);

int cms_sign(
	uint8_t *cms, size_t *cms_len,
	const CMS_CERTS_AND_KEY *signers, size_t signers_cnt,
	int content_type, const uint8_t *content, size_t content_len,
	const uint8_t *crls, size_t crls_len);

int cms_verify(
	const uint8_t *cms, size_t cms_len,
	const uint8_t *extra_certs, size_t extra_certs_len,
	const uint8_t *extra_crls, size_t extra_crls_len,
	int *content_type, const uint8_t **content, size_t *content_len,
	const uint8_t **certs, size_t *certs_len,
	const uint8_t **crls, size_t *crls_len,
	const uint8_t **signer_infos, size_t *signer_infos_len);

int cms_envelop(
	uint8_t *cms, size_t *cms_len,
	const uint8_t *rcpt_certs, size_t rcpt_certs_len,
	int enc_algor, const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
	int content_type, const uint8_t *content, size_t content_len,
	const uint8_t *shared_info1, size_t shared_info1_len,
	const uint8_t *shared_info2, size_t shared_info2_len);

int cms_deenvelop(
	const uint8_t *cms, size_t cms_len,
	const X509_KEY *rcpt_key, const uint8_t *rcpt_cert, size_t rcpt_cert_len,
	int *content_type, uint8_t *content, size_t *content_len,
	const uint8_t **rcpt_infos, size_t *rcpt_infos_len,
	const uint8_t **shared_info1, size_t *shared_info1_len,
	const uint8_t **shared_info2, size_t *shared_info2_len);

int cms_sign_and_envelop(
	uint8_t *cms, size_t *cms_len,
	const CMS_CERTS_AND_KEY *signers, size_t signers_cnt,
	const uint8_t *rcpt_certs, size_t rcpt_certs_len,
	int enc_algor, const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
	int content_type, const uint8_t *content, size_t content_len,
	const uint8_t *signers_crls, size_t signers_crls_len,
	const uint8_t *shared_info1, size_t shared_info1_len,
	const uint8_t *shared_info2, size_t shared_info2_len);

int cms_deenvelop_and_verify(
	const uint8_t *cms, size_t cms_len,
	const X509_KEY *rcpt_key, const uint8_t *rcpt_cert, size_t rcpt_cert_len,
	const uint8_t *extra_signer_certs, size_t extra_signer_certs_len,
	const uint8_t *extra_signer_crls, size_t extra_signer_crls_len,
	int *content_type, uint8_t *content, size_t *content_len,
	const uint8_t **rcpt_infos, size_t *rcpt_infos_len,
	const uint8_t **signer_infos, size_t *signer_infos_len,
	const uint8_t **signer_certs, size_t *signer_certs_len,
	const uint8_t **signer_crls, size_t *signer_crls_len,
	const uint8_t **shared_info1, size_t *shared_info1_len,
	const uint8_t **shared_info2, size_t *shared_info2_len);

// create ContentInfo, type == keyAgreementInfo
int cms_set_key_agreement_info(
	uint8_t *cms, size_t *cms_len,
	const X509_KEY *temp_public_key_r,
	const uint8_t *user_cert, size_t user_cert_len,
	const uint8_t *user_id, size_t user_id_len);

#define PEM_CMS "CMS"
int cms_to_pem(const uint8_t *cms, size_t cms_len, FILE *fp);
int cms_from_pem(uint8_t *cms, size_t *cms_len, size_t maxlen, FILE *fp);


int cms_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *a, size_t alen);


#ifdef __cplusplus
}
#endif
#endif
