Back to index

lightning-sunbird  0.9+nobinonly
Functions
cmsenvdata.c File Reference
#include "cmslocal.h"
#include "cert.h"
#include "key.h"
#include "secasn1.h"
#include "secitem.h"
#include "secoid.h"
#include "pk11func.h"
#include "secerr.h"
#include "secpkcs5.h"

Go to the source code of this file.

Functions

NSSCMSEnvelopedData * NSS_CMSEnvelopedData_Create (NSSCMSMessage *cmsg, SECOidTag algorithm, int keysize)
void NSS_CMSEnvelopedData_Destroy (NSSCMSEnvelopedData *edp)
NSSCMSContentInfo * NSS_CMSEnvelopedData_GetContentInfo (NSSCMSEnvelopedData *envd)
SECStatus NSS_CMSEnvelopedData_AddRecipient (NSSCMSEnvelopedData *edp, NSSCMSRecipientInfo *rip)
SECStatus NSS_CMSEnvelopedData_Encode_BeforeStart (NSSCMSEnvelopedData *envd)
SECStatus NSS_CMSEnvelopedData_Encode_BeforeData (NSSCMSEnvelopedData *envd)
SECStatus NSS_CMSEnvelopedData_Encode_AfterData (NSSCMSEnvelopedData *envd)
SECStatus NSS_CMSEnvelopedData_Decode_BeforeData (NSSCMSEnvelopedData *envd)
SECStatus NSS_CMSEnvelopedData_Decode_AfterData (NSSCMSEnvelopedData *envd)
SECStatus NSS_CMSEnvelopedData_Decode_AfterEnd (NSSCMSEnvelopedData *envd)

Function Documentation

SECStatus NSS_CMSEnvelopedData_AddRecipient ( NSSCMSEnvelopedData *  edp,
NSSCMSRecipientInfo *  rip 
)

Definition at line 127 of file cmsenvdata.c.

{
    void *mark;
    SECStatus rv;

    /* XXX compare pools, if not same, copy rip into edp's pool */

    PR_ASSERT(edp != NULL);
    PR_ASSERT(rip != NULL);

    mark = PORT_ArenaMark(edp->cmsg->poolp);

    rv = NSS_CMSArray_Add(edp->cmsg->poolp, (void ***)&(edp->recipientInfos), (void *)rip);
    if (rv != SECSuccess) {
       PORT_ArenaRelease(edp->cmsg->poolp, mark);
       return SECFailure;
    }

    PORT_ArenaUnmark (edp->cmsg->poolp, mark);
    return SECSuccess;
}
NSSCMSEnvelopedData* NSS_CMSEnvelopedData_Create ( NSSCMSMessage *  cmsg,
SECOidTag  algorithm,
int  keysize 
)

Definition at line 58 of file cmsenvdata.c.

{
    void *mark;
    NSSCMSEnvelopedData *envd;
    PLArenaPool *poolp;
    SECStatus rv;

    poolp = cmsg->poolp;

    mark = PORT_ArenaMark(poolp);

    envd = (NSSCMSEnvelopedData *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSEnvelopedData));
    if (envd == NULL)
       goto loser;

    envd->cmsg = cmsg;

    /* version is set in NSS_CMSEnvelopedData_Encode_BeforeStart() */

    rv = NSS_CMSContentInfo_SetContentEncAlg(poolp, &(envd->contentInfo), algorithm, NULL, keysize);
    if (rv != SECSuccess)
       goto loser;

    PORT_ArenaUnmark(poolp, mark);
    return envd;

loser:
    PORT_ArenaRelease(poolp, mark);
    return NULL;
}
SECStatus NSS_CMSEnvelopedData_Decode_AfterData ( NSSCMSEnvelopedData *  envd)

Definition at line 402 of file cmsenvdata.c.

{
    if (envd && envd->contentInfo.ciphcx) {
       NSS_CMSCipherContext_Destroy(envd->contentInfo.ciphcx);
       envd->contentInfo.ciphcx = NULL;
    }

    return SECSuccess;
}
SECStatus NSS_CMSEnvelopedData_Decode_AfterEnd ( NSSCMSEnvelopedData *  envd)

Definition at line 416 of file cmsenvdata.c.

{
    /* apply final touches */
    return SECSuccess;
}
SECStatus NSS_CMSEnvelopedData_Decode_BeforeData ( NSSCMSEnvelopedData *  envd)

Definition at line 315 of file cmsenvdata.c.

{
    NSSCMSRecipientInfo *ri;
    PK11SymKey *bulkkey = NULL;
    SECOidTag bulkalgtag;
    SECAlgorithmID *bulkalg;
    SECStatus rv = SECFailure;
    NSSCMSContentInfo *cinfo;
    NSSCMSRecipient **recipient_list = NULL;
    NSSCMSRecipient *recipient;
    int rlIndex;

    if (NSS_CMSArray_Count((void **)envd->recipientInfos) == 0) {
       PORT_SetError(SEC_ERROR_BAD_DATA);
#if 0
       PORT_SetErrorString("No recipient data in envelope.");
#endif
       goto loser;
    }

    /* look if one of OUR cert's issuerSN is on the list of recipients, and if so,  */
    /* get the cert and private key for it right away */
    recipient_list = nss_cms_recipient_list_create(envd->recipientInfos);
    if (recipient_list == NULL)
       goto loser;

    /* what about multiple recipientInfos that match?
     * especially if, for some reason, we could not produce a bulk key with the first match?!
     * we could loop & feed partial recipient_list to PK11_FindCertAndKeyByRecipientList...
     * maybe later... */
    rlIndex = PK11_FindCertAndKeyByRecipientListNew(recipient_list, envd->cmsg->pwfn_arg);

    /* if that fails, then we're not an intended recipient and cannot decrypt */
    if (rlIndex < 0) {
       PORT_SetError(SEC_ERROR_NOT_A_RECIPIENT);
#if 0
       PORT_SetErrorString("Cannot decrypt data because proper key cannot be found.");
#endif
       goto loser;
    }

    recipient = recipient_list[rlIndex];
    if (!recipient->cert || !recipient->privkey) {
       /* XXX should set an error code ?!? */
       goto loser;
    }
    /* get a pointer to "our" recipientinfo */
    ri = envd->recipientInfos[recipient->riIndex];

    cinfo = &(envd->contentInfo);
    bulkalgtag = NSS_CMSContentInfo_GetContentEncAlgTag(cinfo);
    if (bulkalgtag == SEC_OID_UNKNOWN) {
       PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
    } else 
       bulkkey = 
           NSS_CMSRecipientInfo_UnwrapBulkKey(ri,recipient->subIndex,
                                              recipient->cert,
                                              recipient->privkey,
                                              bulkalgtag);
    if (bulkkey == NULL) {
       /* no success finding a bulk key */
       goto loser;
    }

    NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey);

    bulkalg = NSS_CMSContentInfo_GetContentEncAlg(cinfo);

    cinfo->ciphcx = NSS_CMSCipherContext_StartDecrypt(bulkkey, bulkalg);
    if (cinfo->ciphcx == NULL)
       goto loser;          /* error has been set by NSS_CMSCipherContext_StartDecrypt */


    rv = SECSuccess;

loser:
    if (bulkkey)
       PK11_FreeSymKey(bulkkey);
    if (recipient_list != NULL)
       nss_cms_recipient_list_destroy(recipient_list);
    return rv;
}
void NSS_CMSEnvelopedData_Destroy ( NSSCMSEnvelopedData *  edp)

Definition at line 93 of file cmsenvdata.c.

{
    NSSCMSRecipientInfo **recipientinfos;
    NSSCMSRecipientInfo *ri;

    if (edp == NULL)
       return;

    recipientinfos = edp->recipientInfos;
    if (recipientinfos == NULL)
       return;

    while ((ri = *recipientinfos++) != NULL)
       NSS_CMSRecipientInfo_Destroy(ri);

   NSS_CMSContentInfo_Destroy(&(edp->contentInfo));

}
SECStatus NSS_CMSEnvelopedData_Encode_AfterData ( NSSCMSEnvelopedData *  envd)

Definition at line 299 of file cmsenvdata.c.

{
    if (envd->contentInfo.ciphcx) {
       NSS_CMSCipherContext_Destroy(envd->contentInfo.ciphcx);
       envd->contentInfo.ciphcx = NULL;
    }

    /* nothing else to do after data */
    return SECSuccess;
}
SECStatus NSS_CMSEnvelopedData_Encode_BeforeData ( NSSCMSEnvelopedData *  envd)

Definition at line 268 of file cmsenvdata.c.

{
    NSSCMSContentInfo *cinfo;
    PK11SymKey *bulkkey;
    SECAlgorithmID *algid;

    cinfo = &(envd->contentInfo);

    /* find bulkkey and algorithm - must have been set by NSS_CMSEnvelopedData_Encode_BeforeStart */
    bulkkey = NSS_CMSContentInfo_GetBulkKey(cinfo);
    if (bulkkey == NULL)
       return SECFailure;
    algid = NSS_CMSContentInfo_GetContentEncAlg(cinfo);
    if (algid == NULL)
       return SECFailure;

    /* this may modify algid (with IVs generated in a token).
     * it is essential that algid is a pointer to the contentEncAlg data, not a
     * pointer to a copy! */
    cinfo->ciphcx = NSS_CMSCipherContext_StartEncrypt(envd->cmsg->poolp, bulkkey, algid);
    PK11_FreeSymKey(bulkkey);
    if (cinfo->ciphcx == NULL)
       return SECFailure;

    return SECSuccess;
}
SECStatus NSS_CMSEnvelopedData_Encode_BeforeStart ( NSSCMSEnvelopedData *  envd)

Definition at line 162 of file cmsenvdata.c.

{
    int version;
    NSSCMSRecipientInfo **recipientinfos;
    NSSCMSContentInfo *cinfo;
    PK11SymKey *bulkkey = NULL;
    SECOidTag bulkalgtag;
    CK_MECHANISM_TYPE type;
    PK11SlotInfo *slot;
    SECStatus rv;
    SECItem *dummy;
    PLArenaPool *poolp;
    extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[];
    void *mark = NULL;
    int i;

    poolp = envd->cmsg->poolp;
    cinfo = &(envd->contentInfo);

    recipientinfos = envd->recipientInfos;
    if (recipientinfos == NULL) {
       PORT_SetError(SEC_ERROR_BAD_DATA);
#if 0
       PORT_SetErrorString("Cannot find recipientinfos to encode.");
#endif
       goto loser;
    }

    version = NSS_CMS_ENVELOPED_DATA_VERSION_REG;
    if (envd->originatorInfo != NULL || envd->unprotectedAttr != NULL) {
       version = NSS_CMS_ENVELOPED_DATA_VERSION_ADV;
    } else {
       for (i = 0; recipientinfos[i] != NULL; i++) {
           if (NSS_CMSRecipientInfo_GetVersion(recipientinfos[i]) != 0) {
              version = NSS_CMS_ENVELOPED_DATA_VERSION_ADV;
              break;
           }
       }
    }
    dummy = SEC_ASN1EncodeInteger(poolp, &(envd->version), version);
    if (dummy == NULL)
       goto loser;

    /* now we need to have a proper content encryption algorithm
     * on the SMIME level, we would figure one out by looking at SMIME capabilities
     * we cannot do that on our level, so if none is set already, we'll just go
     * with one of the mandatory algorithms (3DES) */
    if ((bulkalgtag = NSS_CMSContentInfo_GetContentEncAlgTag(cinfo)) == SEC_OID_UNKNOWN) {
       rv = NSS_CMSContentInfo_SetContentEncAlg(poolp, cinfo, SEC_OID_DES_EDE3_CBC, NULL, 168);
       if (rv != SECSuccess)
           goto loser;
       bulkalgtag = SEC_OID_DES_EDE3_CBC;
    } 

    /* generate a random bulk key suitable for content encryption alg */
    type = PK11_AlgtagToMechanism(bulkalgtag);
    slot = PK11_GetBestSlot(type, envd->cmsg->pwfn_arg);
    if (slot == NULL)
       goto loser;   /* error has been set by PK11_GetBestSlot */

    /* this is expensive... */
    bulkkey = PK11_KeyGen(slot, type, NULL, NSS_CMSContentInfo_GetBulkKeySize(cinfo) / 8, envd->cmsg->pwfn_arg);
    PK11_FreeSlot(slot);
    if (bulkkey == NULL)
       goto loser;   /* error has been set by PK11_KeyGen */

    mark = PORT_ArenaMark(poolp);

    /* Encrypt the bulk key with the public key of each recipient.  */
    for (i = 0; recipientinfos[i] != NULL; i++) {
       rv = NSS_CMSRecipientInfo_WrapBulkKey(recipientinfos[i], bulkkey, bulkalgtag);
       if (rv != SECSuccess)
           goto loser;      /* error has been set by NSS_CMSRecipientInfo_EncryptBulkKey */
                     /* could be: alg not supported etc. */
    }

    /* the recipientinfos are all finished. now sort them by DER for SET OF encoding */
    rv = NSS_CMSArray_SortByDER((void **)envd->recipientInfos, NSSCMSRecipientInfoTemplate, NULL);
    if (rv != SECSuccess)
       goto loser;   /* error has been set by NSS_CMSArray_SortByDER */

    /* store the bulk key in the contentInfo so that the encoder can find it */
    NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey);

    PORT_ArenaUnmark(poolp, mark);

    PK11_FreeSymKey(bulkkey);

    return SECSuccess;

loser:
    if (mark != NULL)
       PORT_ArenaRelease (poolp, mark);
    if (bulkkey)
       PK11_FreeSymKey(bulkkey);

    return SECFailure;
}
NSSCMSContentInfo* NSS_CMSEnvelopedData_GetContentInfo ( NSSCMSEnvelopedData *  envd)

Definition at line 116 of file cmsenvdata.c.

{
    return &(envd->contentInfo);
}