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