security/nss/lib/smime/cmsencdata.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/smime/cmsencdata.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,260 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +/*
     1.9 + * CMS encryptedData methods.
    1.10 + */
    1.11 +
    1.12 +#include "cmslocal.h"
    1.13 +
    1.14 +#include "key.h"
    1.15 +#include "secasn1.h"
    1.16 +#include "secitem.h"
    1.17 +#include "secoid.h"
    1.18 +#include "pk11func.h"
    1.19 +#include "prtime.h"
    1.20 +#include "secerr.h"
    1.21 +#include "secpkcs5.h"
    1.22 +
    1.23 +/*
    1.24 + * NSS_CMSEncryptedData_Create - create an empty encryptedData object.
    1.25 + *
    1.26 + * "algorithm" specifies the bulk encryption algorithm to use.
    1.27 + * "keysize" is the key size.
    1.28 + * 
    1.29 + * An error results in a return value of NULL and an error set.
    1.30 + * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
    1.31 + */
    1.32 +NSSCMSEncryptedData *
    1.33 +NSS_CMSEncryptedData_Create(NSSCMSMessage *cmsg, SECOidTag algorithm, 
    1.34 +			    int keysize)
    1.35 +{
    1.36 +    void *mark;
    1.37 +    NSSCMSEncryptedData *encd;
    1.38 +    PLArenaPool *poolp;
    1.39 +    SECAlgorithmID *pbe_algid;
    1.40 +    SECStatus rv;
    1.41 +
    1.42 +    poolp = cmsg->poolp;
    1.43 +
    1.44 +    mark = PORT_ArenaMark(poolp);
    1.45 +
    1.46 +    encd = PORT_ArenaZNew(poolp, NSSCMSEncryptedData);
    1.47 +    if (encd == NULL)
    1.48 +	goto loser;
    1.49 +
    1.50 +    encd->cmsg = cmsg;
    1.51 +
    1.52 +    /* version is set in NSS_CMSEncryptedData_Encode_BeforeStart() */
    1.53 +
    1.54 +    if (!SEC_PKCS5IsAlgorithmPBEAlgTag(algorithm)) {
    1.55 +	rv = NSS_CMSContentInfo_SetContentEncAlg(poolp, &(encd->contentInfo), 
    1.56 +						 algorithm, NULL, keysize);
    1.57 +    } else {
    1.58 +	/* Assume password-based-encryption.  
    1.59 +	 * Note: we can't generate pkcs5v2 from this interface.
    1.60 +	 * PK11_CreateBPEAlgorithmID generates pkcs5v2 by accepting
    1.61 +	 * non-PBE oids and assuming that they are pkcs5v2 oids, but
    1.62 +	 * NSS_CMSEncryptedData_Create accepts non-PBE oids as regular
    1.63 +	 * CMS encrypted data, so we can't tell NSS_CMS_EncryptedData_Create
    1.64 +	 * to create pkcs5v2 PBEs */
    1.65 +	pbe_algid = PK11_CreatePBEAlgorithmID(algorithm, 1, NULL);
    1.66 +	if (pbe_algid == NULL) {
    1.67 +	    rv = SECFailure;
    1.68 +	} else {
    1.69 +	    rv = NSS_CMSContentInfo_SetContentEncAlgID(poolp, 
    1.70 +				&(encd->contentInfo), pbe_algid, keysize);
    1.71 +	    SECOID_DestroyAlgorithmID (pbe_algid, PR_TRUE);
    1.72 +	}
    1.73 +    }
    1.74 +    if (rv != SECSuccess)
    1.75 +	goto loser;
    1.76 +
    1.77 +    PORT_ArenaUnmark(poolp, mark);
    1.78 +    return encd;
    1.79 +
    1.80 +loser:
    1.81 +    PORT_ArenaRelease(poolp, mark);
    1.82 +    return NULL;
    1.83 +}
    1.84 +
    1.85 +/*
    1.86 + * NSS_CMSEncryptedData_Destroy - destroy an encryptedData object
    1.87 + */
    1.88 +void
    1.89 +NSS_CMSEncryptedData_Destroy(NSSCMSEncryptedData *encd)
    1.90 +{
    1.91 +    /* everything's in a pool, so don't worry about the storage */
    1.92 +    NSS_CMSContentInfo_Destroy(&(encd->contentInfo));
    1.93 +    return;
    1.94 +}
    1.95 +
    1.96 +/*
    1.97 + * NSS_CMSEncryptedData_GetContentInfo - return pointer to encryptedData object's contentInfo
    1.98 + */
    1.99 +NSSCMSContentInfo *
   1.100 +NSS_CMSEncryptedData_GetContentInfo(NSSCMSEncryptedData *encd)
   1.101 +{
   1.102 +    return &(encd->contentInfo);
   1.103 +}
   1.104 +
   1.105 +/*
   1.106 + * NSS_CMSEncryptedData_Encode_BeforeStart - do all the necessary things to a EncryptedData
   1.107 + *     before encoding begins.
   1.108 + *
   1.109 + * In particular:
   1.110 + *  - set the correct version value.
   1.111 + *  - get the encryption key
   1.112 + */
   1.113 +SECStatus
   1.114 +NSS_CMSEncryptedData_Encode_BeforeStart(NSSCMSEncryptedData *encd)
   1.115 +{
   1.116 +    int version;
   1.117 +    PK11SymKey *bulkkey = NULL;
   1.118 +    SECItem *dummy;
   1.119 +    NSSCMSContentInfo *cinfo = &(encd->contentInfo);
   1.120 +
   1.121 +    if (NSS_CMSArray_IsEmpty((void **)encd->unprotectedAttr))
   1.122 +	version = NSS_CMS_ENCRYPTED_DATA_VERSION;
   1.123 +    else
   1.124 +	version = NSS_CMS_ENCRYPTED_DATA_VERSION_UPATTR;
   1.125 +    
   1.126 +    dummy = SEC_ASN1EncodeInteger (encd->cmsg->poolp, &(encd->version), version);
   1.127 +    if (dummy == NULL)
   1.128 +	return SECFailure;
   1.129 +
   1.130 +    /* now get content encryption key (bulk key) by using our cmsg callback */
   1.131 +    if (encd->cmsg->decrypt_key_cb)
   1.132 +	bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg, 
   1.133 +		    NSS_CMSContentInfo_GetContentEncAlg(cinfo));
   1.134 +    if (bulkkey == NULL)
   1.135 +	return SECFailure;
   1.136 +
   1.137 +    /* store the bulk key in the contentInfo so that the encoder can find it */
   1.138 +    NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey);
   1.139 +    PK11_FreeSymKey (bulkkey);
   1.140 +
   1.141 +    return SECSuccess;
   1.142 +}
   1.143 +
   1.144 +/*
   1.145 + * NSS_CMSEncryptedData_Encode_BeforeData - set up encryption
   1.146 + */
   1.147 +SECStatus
   1.148 +NSS_CMSEncryptedData_Encode_BeforeData(NSSCMSEncryptedData *encd)
   1.149 +{
   1.150 +    NSSCMSContentInfo *cinfo;
   1.151 +    PK11SymKey *bulkkey;
   1.152 +    SECAlgorithmID *algid;
   1.153 +    SECStatus rv;
   1.154 +
   1.155 +    cinfo = &(encd->contentInfo);
   1.156 +
   1.157 +    /* find bulkkey and algorithm - must have been set by NSS_CMSEncryptedData_Encode_BeforeStart */
   1.158 +    bulkkey = NSS_CMSContentInfo_GetBulkKey(cinfo);
   1.159 +    if (bulkkey == NULL)
   1.160 +	return SECFailure;
   1.161 +    algid = NSS_CMSContentInfo_GetContentEncAlg(cinfo);
   1.162 +    if (algid == NULL)
   1.163 +	return SECFailure;
   1.164 +
   1.165 +    rv = NSS_CMSContentInfo_Private_Init(cinfo);
   1.166 +    if (rv != SECSuccess) {
   1.167 +	return SECFailure;
   1.168 +    }
   1.169 +    /* this may modify algid (with IVs generated in a token).
   1.170 +     * it is therefore essential that algid is a pointer to the "real" contentEncAlg,
   1.171 +     * not just to a copy */
   1.172 +    cinfo->privateInfo->ciphcx = NSS_CMSCipherContext_StartEncrypt(encd->cmsg->poolp, bulkkey, algid);
   1.173 +    PK11_FreeSymKey(bulkkey);
   1.174 +    if (cinfo->privateInfo->ciphcx == NULL)
   1.175 +	return SECFailure;
   1.176 +
   1.177 +    return SECSuccess;
   1.178 +}
   1.179 +
   1.180 +/*
   1.181 + * NSS_CMSEncryptedData_Encode_AfterData - finalize this encryptedData for encoding
   1.182 + */
   1.183 +SECStatus
   1.184 +NSS_CMSEncryptedData_Encode_AfterData(NSSCMSEncryptedData *encd)
   1.185 +{
   1.186 +    if (encd->contentInfo.privateInfo && encd->contentInfo.privateInfo->ciphcx) {
   1.187 +	NSS_CMSCipherContext_Destroy(encd->contentInfo.privateInfo->ciphcx);
   1.188 +	encd->contentInfo.privateInfo->ciphcx = NULL;
   1.189 +    }
   1.190 +
   1.191 +    /* nothing to do after data */
   1.192 +    return SECSuccess;
   1.193 +}
   1.194 +
   1.195 +
   1.196 +/*
   1.197 + * NSS_CMSEncryptedData_Decode_BeforeData - find bulk key & set up decryption
   1.198 + */
   1.199 +SECStatus
   1.200 +NSS_CMSEncryptedData_Decode_BeforeData(NSSCMSEncryptedData *encd)
   1.201 +{
   1.202 +    PK11SymKey *bulkkey = NULL;
   1.203 +    NSSCMSContentInfo *cinfo;
   1.204 +    SECAlgorithmID *bulkalg;
   1.205 +    SECStatus rv = SECFailure;
   1.206 +
   1.207 +    cinfo = &(encd->contentInfo);
   1.208 +
   1.209 +    bulkalg = NSS_CMSContentInfo_GetContentEncAlg(cinfo);
   1.210 +
   1.211 +    if (encd->cmsg->decrypt_key_cb == NULL)	/* no callback? no key../ */
   1.212 +	goto loser;
   1.213 +
   1.214 +    bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg, bulkalg);
   1.215 +    if (bulkkey == NULL)
   1.216 +	/* no success finding a bulk key */
   1.217 +	goto loser;
   1.218 +
   1.219 +    NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey);
   1.220 +
   1.221 +    rv = NSS_CMSContentInfo_Private_Init(cinfo);
   1.222 +    if (rv != SECSuccess) {
   1.223 +	goto loser;
   1.224 +    }
   1.225 +    rv = SECFailure;
   1.226 +
   1.227 +    cinfo->privateInfo->ciphcx = NSS_CMSCipherContext_StartDecrypt(bulkkey, bulkalg);
   1.228 +    if (cinfo->privateInfo->ciphcx == NULL)
   1.229 +	goto loser;		/* error has been set by NSS_CMSCipherContext_StartDecrypt */
   1.230 +
   1.231 +
   1.232 +    /* we are done with (this) bulkkey now. */
   1.233 +    PK11_FreeSymKey(bulkkey);
   1.234 +
   1.235 +    rv = SECSuccess;
   1.236 +
   1.237 +loser:
   1.238 +    return rv;
   1.239 +}
   1.240 +
   1.241 +/*
   1.242 + * NSS_CMSEncryptedData_Decode_AfterData - finish decrypting this encryptedData's content
   1.243 + */
   1.244 +SECStatus
   1.245 +NSS_CMSEncryptedData_Decode_AfterData(NSSCMSEncryptedData *encd)
   1.246 +{
   1.247 +    if (encd->contentInfo.privateInfo && encd->contentInfo.privateInfo->ciphcx) {
   1.248 +	NSS_CMSCipherContext_Destroy(encd->contentInfo.privateInfo->ciphcx);
   1.249 +	encd->contentInfo.privateInfo->ciphcx = NULL;
   1.250 +    }
   1.251 +
   1.252 +    return SECSuccess;
   1.253 +}
   1.254 +
   1.255 +/*
   1.256 + * NSS_CMSEncryptedData_Decode_AfterEnd - finish decoding this encryptedData
   1.257 + */
   1.258 +SECStatus
   1.259 +NSS_CMSEncryptedData_Decode_AfterEnd(NSSCMSEncryptedData *encd)
   1.260 +{
   1.261 +    /* apply final touches */
   1.262 +    return SECSuccess;
   1.263 +}

mercurial