security/nss/lib/smime/cmsencdata.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 /*
michael@0 6 * CMS encryptedData methods.
michael@0 7 */
michael@0 8
michael@0 9 #include "cmslocal.h"
michael@0 10
michael@0 11 #include "key.h"
michael@0 12 #include "secasn1.h"
michael@0 13 #include "secitem.h"
michael@0 14 #include "secoid.h"
michael@0 15 #include "pk11func.h"
michael@0 16 #include "prtime.h"
michael@0 17 #include "secerr.h"
michael@0 18 #include "secpkcs5.h"
michael@0 19
michael@0 20 /*
michael@0 21 * NSS_CMSEncryptedData_Create - create an empty encryptedData object.
michael@0 22 *
michael@0 23 * "algorithm" specifies the bulk encryption algorithm to use.
michael@0 24 * "keysize" is the key size.
michael@0 25 *
michael@0 26 * An error results in a return value of NULL and an error set.
michael@0 27 * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
michael@0 28 */
michael@0 29 NSSCMSEncryptedData *
michael@0 30 NSS_CMSEncryptedData_Create(NSSCMSMessage *cmsg, SECOidTag algorithm,
michael@0 31 int keysize)
michael@0 32 {
michael@0 33 void *mark;
michael@0 34 NSSCMSEncryptedData *encd;
michael@0 35 PLArenaPool *poolp;
michael@0 36 SECAlgorithmID *pbe_algid;
michael@0 37 SECStatus rv;
michael@0 38
michael@0 39 poolp = cmsg->poolp;
michael@0 40
michael@0 41 mark = PORT_ArenaMark(poolp);
michael@0 42
michael@0 43 encd = PORT_ArenaZNew(poolp, NSSCMSEncryptedData);
michael@0 44 if (encd == NULL)
michael@0 45 goto loser;
michael@0 46
michael@0 47 encd->cmsg = cmsg;
michael@0 48
michael@0 49 /* version is set in NSS_CMSEncryptedData_Encode_BeforeStart() */
michael@0 50
michael@0 51 if (!SEC_PKCS5IsAlgorithmPBEAlgTag(algorithm)) {
michael@0 52 rv = NSS_CMSContentInfo_SetContentEncAlg(poolp, &(encd->contentInfo),
michael@0 53 algorithm, NULL, keysize);
michael@0 54 } else {
michael@0 55 /* Assume password-based-encryption.
michael@0 56 * Note: we can't generate pkcs5v2 from this interface.
michael@0 57 * PK11_CreateBPEAlgorithmID generates pkcs5v2 by accepting
michael@0 58 * non-PBE oids and assuming that they are pkcs5v2 oids, but
michael@0 59 * NSS_CMSEncryptedData_Create accepts non-PBE oids as regular
michael@0 60 * CMS encrypted data, so we can't tell NSS_CMS_EncryptedData_Create
michael@0 61 * to create pkcs5v2 PBEs */
michael@0 62 pbe_algid = PK11_CreatePBEAlgorithmID(algorithm, 1, NULL);
michael@0 63 if (pbe_algid == NULL) {
michael@0 64 rv = SECFailure;
michael@0 65 } else {
michael@0 66 rv = NSS_CMSContentInfo_SetContentEncAlgID(poolp,
michael@0 67 &(encd->contentInfo), pbe_algid, keysize);
michael@0 68 SECOID_DestroyAlgorithmID (pbe_algid, PR_TRUE);
michael@0 69 }
michael@0 70 }
michael@0 71 if (rv != SECSuccess)
michael@0 72 goto loser;
michael@0 73
michael@0 74 PORT_ArenaUnmark(poolp, mark);
michael@0 75 return encd;
michael@0 76
michael@0 77 loser:
michael@0 78 PORT_ArenaRelease(poolp, mark);
michael@0 79 return NULL;
michael@0 80 }
michael@0 81
michael@0 82 /*
michael@0 83 * NSS_CMSEncryptedData_Destroy - destroy an encryptedData object
michael@0 84 */
michael@0 85 void
michael@0 86 NSS_CMSEncryptedData_Destroy(NSSCMSEncryptedData *encd)
michael@0 87 {
michael@0 88 /* everything's in a pool, so don't worry about the storage */
michael@0 89 NSS_CMSContentInfo_Destroy(&(encd->contentInfo));
michael@0 90 return;
michael@0 91 }
michael@0 92
michael@0 93 /*
michael@0 94 * NSS_CMSEncryptedData_GetContentInfo - return pointer to encryptedData object's contentInfo
michael@0 95 */
michael@0 96 NSSCMSContentInfo *
michael@0 97 NSS_CMSEncryptedData_GetContentInfo(NSSCMSEncryptedData *encd)
michael@0 98 {
michael@0 99 return &(encd->contentInfo);
michael@0 100 }
michael@0 101
michael@0 102 /*
michael@0 103 * NSS_CMSEncryptedData_Encode_BeforeStart - do all the necessary things to a EncryptedData
michael@0 104 * before encoding begins.
michael@0 105 *
michael@0 106 * In particular:
michael@0 107 * - set the correct version value.
michael@0 108 * - get the encryption key
michael@0 109 */
michael@0 110 SECStatus
michael@0 111 NSS_CMSEncryptedData_Encode_BeforeStart(NSSCMSEncryptedData *encd)
michael@0 112 {
michael@0 113 int version;
michael@0 114 PK11SymKey *bulkkey = NULL;
michael@0 115 SECItem *dummy;
michael@0 116 NSSCMSContentInfo *cinfo = &(encd->contentInfo);
michael@0 117
michael@0 118 if (NSS_CMSArray_IsEmpty((void **)encd->unprotectedAttr))
michael@0 119 version = NSS_CMS_ENCRYPTED_DATA_VERSION;
michael@0 120 else
michael@0 121 version = NSS_CMS_ENCRYPTED_DATA_VERSION_UPATTR;
michael@0 122
michael@0 123 dummy = SEC_ASN1EncodeInteger (encd->cmsg->poolp, &(encd->version), version);
michael@0 124 if (dummy == NULL)
michael@0 125 return SECFailure;
michael@0 126
michael@0 127 /* now get content encryption key (bulk key) by using our cmsg callback */
michael@0 128 if (encd->cmsg->decrypt_key_cb)
michael@0 129 bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg,
michael@0 130 NSS_CMSContentInfo_GetContentEncAlg(cinfo));
michael@0 131 if (bulkkey == NULL)
michael@0 132 return SECFailure;
michael@0 133
michael@0 134 /* store the bulk key in the contentInfo so that the encoder can find it */
michael@0 135 NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey);
michael@0 136 PK11_FreeSymKey (bulkkey);
michael@0 137
michael@0 138 return SECSuccess;
michael@0 139 }
michael@0 140
michael@0 141 /*
michael@0 142 * NSS_CMSEncryptedData_Encode_BeforeData - set up encryption
michael@0 143 */
michael@0 144 SECStatus
michael@0 145 NSS_CMSEncryptedData_Encode_BeforeData(NSSCMSEncryptedData *encd)
michael@0 146 {
michael@0 147 NSSCMSContentInfo *cinfo;
michael@0 148 PK11SymKey *bulkkey;
michael@0 149 SECAlgorithmID *algid;
michael@0 150 SECStatus rv;
michael@0 151
michael@0 152 cinfo = &(encd->contentInfo);
michael@0 153
michael@0 154 /* find bulkkey and algorithm - must have been set by NSS_CMSEncryptedData_Encode_BeforeStart */
michael@0 155 bulkkey = NSS_CMSContentInfo_GetBulkKey(cinfo);
michael@0 156 if (bulkkey == NULL)
michael@0 157 return SECFailure;
michael@0 158 algid = NSS_CMSContentInfo_GetContentEncAlg(cinfo);
michael@0 159 if (algid == NULL)
michael@0 160 return SECFailure;
michael@0 161
michael@0 162 rv = NSS_CMSContentInfo_Private_Init(cinfo);
michael@0 163 if (rv != SECSuccess) {
michael@0 164 return SECFailure;
michael@0 165 }
michael@0 166 /* this may modify algid (with IVs generated in a token).
michael@0 167 * it is therefore essential that algid is a pointer to the "real" contentEncAlg,
michael@0 168 * not just to a copy */
michael@0 169 cinfo->privateInfo->ciphcx = NSS_CMSCipherContext_StartEncrypt(encd->cmsg->poolp, bulkkey, algid);
michael@0 170 PK11_FreeSymKey(bulkkey);
michael@0 171 if (cinfo->privateInfo->ciphcx == NULL)
michael@0 172 return SECFailure;
michael@0 173
michael@0 174 return SECSuccess;
michael@0 175 }
michael@0 176
michael@0 177 /*
michael@0 178 * NSS_CMSEncryptedData_Encode_AfterData - finalize this encryptedData for encoding
michael@0 179 */
michael@0 180 SECStatus
michael@0 181 NSS_CMSEncryptedData_Encode_AfterData(NSSCMSEncryptedData *encd)
michael@0 182 {
michael@0 183 if (encd->contentInfo.privateInfo && encd->contentInfo.privateInfo->ciphcx) {
michael@0 184 NSS_CMSCipherContext_Destroy(encd->contentInfo.privateInfo->ciphcx);
michael@0 185 encd->contentInfo.privateInfo->ciphcx = NULL;
michael@0 186 }
michael@0 187
michael@0 188 /* nothing to do after data */
michael@0 189 return SECSuccess;
michael@0 190 }
michael@0 191
michael@0 192
michael@0 193 /*
michael@0 194 * NSS_CMSEncryptedData_Decode_BeforeData - find bulk key & set up decryption
michael@0 195 */
michael@0 196 SECStatus
michael@0 197 NSS_CMSEncryptedData_Decode_BeforeData(NSSCMSEncryptedData *encd)
michael@0 198 {
michael@0 199 PK11SymKey *bulkkey = NULL;
michael@0 200 NSSCMSContentInfo *cinfo;
michael@0 201 SECAlgorithmID *bulkalg;
michael@0 202 SECStatus rv = SECFailure;
michael@0 203
michael@0 204 cinfo = &(encd->contentInfo);
michael@0 205
michael@0 206 bulkalg = NSS_CMSContentInfo_GetContentEncAlg(cinfo);
michael@0 207
michael@0 208 if (encd->cmsg->decrypt_key_cb == NULL) /* no callback? no key../ */
michael@0 209 goto loser;
michael@0 210
michael@0 211 bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg, bulkalg);
michael@0 212 if (bulkkey == NULL)
michael@0 213 /* no success finding a bulk key */
michael@0 214 goto loser;
michael@0 215
michael@0 216 NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey);
michael@0 217
michael@0 218 rv = NSS_CMSContentInfo_Private_Init(cinfo);
michael@0 219 if (rv != SECSuccess) {
michael@0 220 goto loser;
michael@0 221 }
michael@0 222 rv = SECFailure;
michael@0 223
michael@0 224 cinfo->privateInfo->ciphcx = NSS_CMSCipherContext_StartDecrypt(bulkkey, bulkalg);
michael@0 225 if (cinfo->privateInfo->ciphcx == NULL)
michael@0 226 goto loser; /* error has been set by NSS_CMSCipherContext_StartDecrypt */
michael@0 227
michael@0 228
michael@0 229 /* we are done with (this) bulkkey now. */
michael@0 230 PK11_FreeSymKey(bulkkey);
michael@0 231
michael@0 232 rv = SECSuccess;
michael@0 233
michael@0 234 loser:
michael@0 235 return rv;
michael@0 236 }
michael@0 237
michael@0 238 /*
michael@0 239 * NSS_CMSEncryptedData_Decode_AfterData - finish decrypting this encryptedData's content
michael@0 240 */
michael@0 241 SECStatus
michael@0 242 NSS_CMSEncryptedData_Decode_AfterData(NSSCMSEncryptedData *encd)
michael@0 243 {
michael@0 244 if (encd->contentInfo.privateInfo && encd->contentInfo.privateInfo->ciphcx) {
michael@0 245 NSS_CMSCipherContext_Destroy(encd->contentInfo.privateInfo->ciphcx);
michael@0 246 encd->contentInfo.privateInfo->ciphcx = NULL;
michael@0 247 }
michael@0 248
michael@0 249 return SECSuccess;
michael@0 250 }
michael@0 251
michael@0 252 /*
michael@0 253 * NSS_CMSEncryptedData_Decode_AfterEnd - finish decoding this encryptedData
michael@0 254 */
michael@0 255 SECStatus
michael@0 256 NSS_CMSEncryptedData_Decode_AfterEnd(NSSCMSEncryptedData *encd)
michael@0 257 {
michael@0 258 /* apply final touches */
michael@0 259 return SECSuccess;
michael@0 260 }

mercurial