/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/*
 * Header for CMS types.
 */

#ifndef _CMST_H_
#define _CMST_H_

#include "seccomon.h"
#include "secoidt.h"
#include "certt.h"
#include "secmodt.h"
#include "secmodt.h"

#include "plarena.h"

/* Non-opaque objects.  NOTE, though: I want them to be treated as
 * opaque as much as possible.  If I could hide them completely,
 * I would.  (I tried, but ran into trouble that was taking me too
 * much time to get out of.)  I still intend to try to do so.
 * In fact, the only type that "outsiders" should even *name* is
 * NSSCMSMessage, and they should not reference its fields.
 */
/* rjr: PKCS #11 cert handling (pk11cert.c) does use NSSCMSRecipientInfo's.
 * This is because when we search the recipient list for the cert and key we
 * want, we need to invert the order of the loops we used to have. The old
 * loops were:
 *
 *  For each recipient {
 *       find_cert = PK11_Find_AllCert(recipient->issuerSN);
 *       [which unrolls to... ]
 *       For each slot {
 *            Log into slot;
 *            search slot for cert;
 *      }
 *  }
 *
 *  the new loop searchs all the recipients at once on a slot. this allows
 *  PKCS #11 to order slots in such a way that logout slots don't get checked
 *  if we can find the cert on a logged in slot. This eliminates lots of
 *  spurious password prompts when smart cards are installed... so why this
 *  comment? If you make NSSCMSRecipientInfo completely opaque, you need
 *  to provide a non-opaque list of issuerSN's (the only field PKCS#11 needs
 *  and fix up pk11cert.c first. NOTE: Only S/MIME calls this special PKCS #11
 *  function.
 */

typedef struct NSSCMSMessageStr NSSCMSMessage;

typedef union NSSCMSContentUnion NSSCMSContent;
typedef struct NSSCMSContentInfoStr NSSCMSContentInfo;

typedef struct NSSCMSSignedDataStr NSSCMSSignedData;
typedef struct NSSCMSSignerInfoStr NSSCMSSignerInfo;
typedef struct NSSCMSSignerIdentifierStr NSSCMSSignerIdentifier;

typedef struct NSSCMSEnvelopedDataStr NSSCMSEnvelopedData;
typedef struct NSSCMSOriginatorInfoStr NSSCMSOriginatorInfo;
typedef struct NSSCMSRecipientInfoStr NSSCMSRecipientInfo;

typedef struct NSSCMSDigestedDataStr NSSCMSDigestedData;
typedef struct NSSCMSEncryptedDataStr NSSCMSEncryptedData;

typedef struct NSSCMSGenericWrapperDataStr NSSCMSGenericWrapperData;

typedef struct NSSCMSAttributeStr NSSCMSAttribute;

typedef struct NSSCMSDecoderContextStr NSSCMSDecoderContext;
typedef struct NSSCMSEncoderContextStr NSSCMSEncoderContext;

typedef struct NSSCMSCipherContextStr NSSCMSCipherContext;
typedef struct NSSCMSDigestContextStr NSSCMSDigestContext;

typedef struct NSSCMSContentInfoPrivateStr NSSCMSContentInfoPrivate;

typedef SECStatus (*NSSCMSGenericWrapperDataCallback)(NSSCMSGenericWrapperData *);
typedef void (*NSSCMSGenericWrapperDataDestroy)(NSSCMSGenericWrapperData *);

extern const SEC_ASN1Template NSSCMSGenericWrapperDataTemplate[];
extern const SEC_ASN1Template NSS_PointerToCMSGenericWrapperDataTemplate[];

SEC_ASN1_CHOOSER_DECLARE(NSS_PointerToCMSGenericWrapperDataTemplate)
SEC_ASN1_CHOOSER_DECLARE(NSSCMSGenericWrapperDataTemplate)

/*
 * Type of function passed to NSSCMSDecode or NSSCMSDecoderStart.
 * If specified, this is where the content bytes (only) will be "sent"
 * as they are recovered during the decoding.
 * And:
 * Type of function passed to NSSCMSEncode or NSSCMSEncoderStart.
 * This is where the DER-encoded bytes will be "sent".
 *
 * XXX Should just combine this with NSSCMSEncoderContentCallback type
 * and use a simpler, common name.
 */
typedef void (*NSSCMSContentCallback)(void *arg, const char *buf, unsigned long len);

/*
 * Type of function passed to NSSCMSDecode or NSSCMSDecoderStart
 * to retrieve the decryption key.  This function is intended to be
 * used for EncryptedData content info's which do not have a key available
 * in a certificate, etc.
 */
typedef PK11SymKey *(*NSSCMSGetDecryptKeyCallback)(void *arg, SECAlgorithmID *algid);

/* =============================================================================
 * ENCAPSULATED CONTENTINFO & CONTENTINFO
 */

union NSSCMSContentUnion {
    /* either unstructured */
    SECItem *data;
    /* or structured data */
    NSSCMSDigestedData *digestedData;
    NSSCMSEncryptedData *encryptedData;
    NSSCMSEnvelopedData *envelopedData;
    NSSCMSSignedData *signedData;
    NSSCMSGenericWrapperData *genericData;
    /* or anonymous pointer to something */
    void *pointer;
};

struct NSSCMSContentInfoStr {
    SECItem contentType;
    NSSCMSContent content;
    /* --------- local; not part of encoding --------- */
    SECOidData *contentTypeTag;

    /* additional info for encryptedData and envelopedData */
    /* we waste this space for signedData and digestedData. sue me. */

    SECAlgorithmID contentEncAlg;
    SECItem *rawContent; /* encrypted DER, optional */
                         /* XXXX bytes not encrypted, but encoded? */
    /* --------- local; not part of encoding --------- */
    PK11SymKey *bulkkey;                   /* bulk encryption key */
    int keysize;                           /* size of bulk encryption key
                                           * (only used by creation code) */
    SECOidTag contentEncAlgTag;            /* oid tag of encryption algorithm
                                           * (only used by creation code) */
    NSSCMSContentInfoPrivate *privateInfo; /* place for NSS private info */
    void *reserved;                        /* keep binary compatibility */
};

/* =============================================================================
 * MESSAGE
 */

struct NSSCMSMessageStr {
    NSSCMSContentInfo contentInfo; /* "outer" cinfo */
    /* --------- local; not part of encoding --------- */
    PLArenaPool *poolp;
    PRBool poolp_is_ours;
    int refCount;
    /* properties of the "inner" data */
    SECAlgorithmID **detached_digestalgs;
    SECItem **detached_digests;
    void *pwfn_arg;
    NSSCMSGetDecryptKeyCallback decrypt_key_cb;
    void *decrypt_key_cb_arg;
};

/* ============================================================================
 * GENERIC WRAPPER
 *
 * used for user defined types.
 */
struct NSSCMSGenericWrapperDataStr {
    NSSCMSContentInfo contentInfo;
    /* ---- local; not part of encoding ------ */
    NSSCMSMessage *cmsg;
    /* wrapperspecific data starts here */
};

/* =============================================================================
 * SIGNEDDATA
 */

struct NSSCMSSignedDataStr {
    SECItem version;
    SECAlgorithmID **digestAlgorithms;
    NSSCMSContentInfo contentInfo;
    SECItem **rawCerts;
    CERTSignedCrl **crls;
    NSSCMSSignerInfo **signerInfos;
    /* --------- local; not part of encoding --------- */
    NSSCMSMessage *cmsg; /* back pointer to message */
    SECItem **digests;
    CERTCertificate **certs;
    CERTCertificateList **certLists;
    CERTCertificate **tempCerts; /* temporary certs, needed
                                  * for example for signature
                                  * verification */
};
#define NSS_CMS_SIGNED_DATA_VERSION_BASIC 1 /* what we *create* */
#define NSS_CMS_SIGNED_DATA_VERSION_EXT 3   /* what we *create* */

typedef enum {
    NSSCMSVS_Unverified = 0,
    NSSCMSVS_GoodSignature = 1,
    NSSCMSVS_BadSignature = 2,
    NSSCMSVS_DigestMismatch = 3,
    NSSCMSVS_SigningCertNotFound = 4,
    NSSCMSVS_SigningCertNotTrusted = 5,
    NSSCMSVS_SignatureAlgorithmUnknown = 6,
    NSSCMSVS_SignatureAlgorithmUnsupported = 7,
    NSSCMSVS_MalformedSignature = 8,
    NSSCMSVS_ProcessingError = 9
} NSSCMSVerificationStatus;

typedef enum {
    NSSCMSSignerID_IssuerSN = 0,
    NSSCMSSignerID_SubjectKeyID = 1
} NSSCMSSignerIDSelector;

struct NSSCMSSignerIdentifierStr {
    NSSCMSSignerIDSelector identifierType;
    union {
        CERTIssuerAndSN *issuerAndSN;
        SECItem *subjectKeyID;
    } id;
};

struct NSSCMSSignerInfoStr {
    SECItem version;
    NSSCMSSignerIdentifier signerIdentifier;
    SECAlgorithmID digestAlg;
    NSSCMSAttribute **authAttr;
    SECAlgorithmID digestEncAlg;
    SECItem encDigest;
    NSSCMSAttribute **unAuthAttr;
    /* --------- local; not part of encoding --------- */
    NSSCMSMessage *cmsg; /* back pointer to message */
    CERTCertificate *cert;
    CERTCertificateList *certList;
    PRTime signingTime;
    NSSCMSVerificationStatus verificationStatus;
    SECKEYPrivateKey *signingKey; /* Used if we're using subjKeyID*/
    SECKEYPublicKey *pubKey;
};
#define NSS_CMS_SIGNER_INFO_VERSION_ISSUERSN 1 /* what we *create* */
#define NSS_CMS_SIGNER_INFO_VERSION_SUBJKEY 3  /* what we *create* */

typedef enum {
    NSSCMSCM_None = 0,
    NSSCMSCM_CertOnly = 1,
    NSSCMSCM_CertChain = 2,
    NSSCMSCM_CertChainWithRoot = 3
} NSSCMSCertChainMode;

/* =============================================================================
 * ENVELOPED DATA
 */
struct NSSCMSEnvelopedDataStr {
    SECItem version;
    NSSCMSOriginatorInfo *originatorInfo; /* optional */
    NSSCMSRecipientInfo **recipientInfos;
    NSSCMSContentInfo contentInfo;
    NSSCMSAttribute **unprotectedAttr;
    /* --------- local; not part of encoding --------- */
    NSSCMSMessage *cmsg; /* back pointer to message */
};
#define NSS_CMS_ENVELOPED_DATA_VERSION_REG 0 /* what we *create* */
#define NSS_CMS_ENVELOPED_DATA_VERSION_ADV 2 /* what we *create* */

struct NSSCMSOriginatorInfoStr {
    SECItem **rawCerts;
    CERTSignedCrl **crls;
    /* --------- local; not part of encoding --------- */
    CERTCertificate **certs;
};

/* -----------------------------------------------------------------------------
 * key transport recipient info
 */
typedef enum {
    NSSCMSRecipientID_IssuerSN = 0,
    NSSCMSRecipientID_SubjectKeyID = 1,
    NSSCMSRecipientID_BrandNew = 2
} NSSCMSRecipientIDSelector;

struct NSSCMSRecipientIdentifierStr {
    NSSCMSRecipientIDSelector identifierType;
    union {
        CERTIssuerAndSN *issuerAndSN;
        SECItem *subjectKeyID;
    } id;
};
typedef struct NSSCMSRecipientIdentifierStr NSSCMSRecipientIdentifier;

struct NSSCMSKeyTransRecipientInfoStr {
    SECItem version;
    NSSCMSRecipientIdentifier recipientIdentifier;
    SECAlgorithmID keyEncAlg;
    SECItem encKey;
};
typedef struct NSSCMSKeyTransRecipientInfoStr NSSCMSKeyTransRecipientInfo;

/*
 * View comments before NSSCMSRecipientInfoStr for purpose of this
 * structure.
 */
struct NSSCMSKeyTransRecipientInfoExStr {
    NSSCMSKeyTransRecipientInfo recipientInfo;
    int version; /* version of this structure (0) */
    SECKEYPublicKey *pubKey;
};

typedef struct NSSCMSKeyTransRecipientInfoExStr NSSCMSKeyTransRecipientInfoEx;

#define NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN 0 /* what we *create* */
#define NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY 2  /* what we *create* */

/* -----------------------------------------------------------------------------
 * key agreement recipient info
 */
struct NSSCMSOriginatorPublicKeyStr {
    SECAlgorithmID algorithmIdentifier;
    SECItem publicKey; /* bit string! */
};
typedef struct NSSCMSOriginatorPublicKeyStr NSSCMSOriginatorPublicKey;

typedef enum {
    NSSCMSOriginatorIDOrKey_IssuerSN = 0,
    NSSCMSOriginatorIDOrKey_SubjectKeyID = 1,
    NSSCMSOriginatorIDOrKey_OriginatorPublicKey = 2
} NSSCMSOriginatorIDOrKeySelector;

struct NSSCMSOriginatorIdentifierOrKeyStr {
    NSSCMSOriginatorIDOrKeySelector identifierType;
    union {
        CERTIssuerAndSN *issuerAndSN;                  /* static-static */
        SECItem *subjectKeyID;                         /* static-static */
        NSSCMSOriginatorPublicKey originatorPublicKey; /* ephemeral-static */
    } id;
};
typedef struct NSSCMSOriginatorIdentifierOrKeyStr NSSCMSOriginatorIdentifierOrKey;

struct NSSCMSRecipientKeyIdentifierStr {
    SECItem *subjectKeyIdentifier;
    SECItem *date;  /* optional */
    SECItem *other; /* optional */
};
typedef struct NSSCMSRecipientKeyIdentifierStr NSSCMSRecipientKeyIdentifier;

typedef enum {
    NSSCMSKeyAgreeRecipientID_IssuerSN = 0,
    NSSCMSKeyAgreeRecipientID_RKeyID = 1
} NSSCMSKeyAgreeRecipientIDSelector;

struct NSSCMSKeyAgreeRecipientIdentifierStr {
    NSSCMSKeyAgreeRecipientIDSelector identifierType;
    union {
        CERTIssuerAndSN *issuerAndSN;
        NSSCMSRecipientKeyIdentifier recipientKeyIdentifier;
    } id;
};
typedef struct NSSCMSKeyAgreeRecipientIdentifierStr NSSCMSKeyAgreeRecipientIdentifier;

struct NSSCMSRecipientEncryptedKeyStr {
    NSSCMSKeyAgreeRecipientIdentifier recipientIdentifier;
    SECItem encKey;
};
typedef struct NSSCMSRecipientEncryptedKeyStr NSSCMSRecipientEncryptedKey;

struct NSSCMSKeyAgreeRecipientInfoStr {
    SECItem version;
    NSSCMSOriginatorIdentifierOrKey originatorIdentifierOrKey;
    SECItem *ukm; /* optional */
    SECAlgorithmID keyEncAlg;
    NSSCMSRecipientEncryptedKey **recipientEncryptedKeys;
};
typedef struct NSSCMSKeyAgreeRecipientInfoStr NSSCMSKeyAgreeRecipientInfo;

#define NSS_CMS_KEYAGREE_RECIPIENT_INFO_VERSION 3 /* what we *create* */

/* -----------------------------------------------------------------------------
 * KEK recipient info
 */
struct NSSCMSKEKIdentifierStr {
    SECItem keyIdentifier;
    SECItem *date;  /* optional */
    SECItem *other; /* optional */
};
typedef struct NSSCMSKEKIdentifierStr NSSCMSKEKIdentifier;

struct NSSCMSKEKRecipientInfoStr {
    SECItem version;
    NSSCMSKEKIdentifier kekIdentifier;
    SECAlgorithmID keyEncAlg;
    SECItem encKey;
};
typedef struct NSSCMSKEKRecipientInfoStr NSSCMSKEKRecipientInfo;

#define NSS_CMS_KEK_RECIPIENT_INFO_VERSION 4 /* what we *create* */

/* -----------------------------------------------------------------------------
 * recipient info
 */

typedef enum {
    NSSCMSRecipientInfoID_KeyTrans = 0,
    NSSCMSRecipientInfoID_KeyAgree = 1,
    NSSCMSRecipientInfoID_KEK = 2
} NSSCMSRecipientInfoIDSelector;

/*
 * In order to preserve backwards binary compatibility when implementing
 * creation of Recipient Info's that uses subjectKeyID in the
 * keyTransRecipientInfo we need to stash a public key pointer in this
 * structure somewhere.  We figured out that NSSCMSKeyTransRecipientInfo
 * is the smallest member of the ri union.  We're in luck since that's
 * the very structure that would need to use the public key. So we created
 * a new structure NSSCMSKeyTransRecipientInfoEx which has a member
 * NSSCMSKeyTransRecipientInfo as the first member followed by a version
 * and a public key pointer.  This way we can keep backwards compatibility
 * without changing the size of this structure.
 *
 * BTW, size of structure:
 * NSSCMSKeyTransRecipientInfo:  9 ints, 4 pointers
 * NSSCMSKeyAgreeRecipientInfo: 12 ints, 8 pointers
 * NSSCMSKEKRecipientInfo:      10 ints, 7 pointers
 *
 * The new structure:
 * NSSCMSKeyTransRecipientInfoEx: sizeof(NSSCMSKeyTransRecipientInfo) +
 *                                1 int, 1 pointer
 */

struct NSSCMSRecipientInfoStr {
    NSSCMSRecipientInfoIDSelector recipientInfoType;
    union {
        NSSCMSKeyTransRecipientInfo keyTransRecipientInfo;
        NSSCMSKeyAgreeRecipientInfo keyAgreeRecipientInfo;
        NSSCMSKEKRecipientInfo kekRecipientInfo;
        NSSCMSKeyTransRecipientInfoEx keyTransRecipientInfoEx;
    } ri;
    /* --------- local; not part of encoding --------- */
    NSSCMSMessage *cmsg;   /* back pointer to message */
    CERTCertificate *cert; /* recipient's certificate */
};

/* =============================================================================
 * DIGESTED DATA
 */
struct NSSCMSDigestedDataStr {
    SECItem version;
    SECAlgorithmID digestAlg;
    NSSCMSContentInfo contentInfo;
    SECItem digest;
    /* --------- local; not part of encoding --------- */
    NSSCMSMessage *cmsg; /* back pointer */
    SECItem cdigest;     /* calculated digest */
};
#define NSS_CMS_DIGESTED_DATA_VERSION_DATA 0  /* what we *create* */
#define NSS_CMS_DIGESTED_DATA_VERSION_ENCAP 2 /* what we *create* */

/* =============================================================================
 * ENCRYPTED DATA
 */
struct NSSCMSEncryptedDataStr {
    SECItem version;
    NSSCMSContentInfo contentInfo;
    NSSCMSAttribute **unprotectedAttr; /* optional */
    /* --------- local; not part of encoding --------- */
    NSSCMSMessage *cmsg; /* back pointer */
};
#define NSS_CMS_ENCRYPTED_DATA_VERSION 0        /* what we *create* */
#define NSS_CMS_ENCRYPTED_DATA_VERSION_UPATTR 2 /* what we *create* */

/*
 * *****************************************************************************
 * *****************************************************************************
 * *****************************************************************************
 */

/*
 * See comment above about this type not really belonging to CMS.
 */
struct NSSCMSAttributeStr {
    /* The following fields make up an encoded Attribute: */
    SECItem type;
    SECItem **values; /* data may or may not be encoded */
    /* The following fields are not part of an encoded Attribute: */
    SECOidData *typeTag;
    PRBool encoded; /* when true, values are encoded */
};

#endif /* _CMST_H_ */