1/* 2 * The contents of this file are subject to the Mozilla Public 3 * License Version 1.1 (the "License"); you may not use this file 4 * except in compliance with the License. You may obtain a copy of 5 * the License at http://www.mozilla.org/MPL/ 6 * 7 * Software distributed under the License is distributed on an "AS 8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 9 * implied. See the License for the specific language governing 10 * rights and limitations under the License. 11 * 12 * The Original Code is the Netscape security libraries. 13 * 14 * The Initial Developer of the Original Code is Netscape 15 * Communications Corporation. Portions created by Netscape are 16 * Copyright (C) 1994-2000 Netscape Communications Corporation. All 17 * Rights Reserved. 18 * 19 * Contributor(s): 20 * 21 * Alternatively, the contents of this file may be used under the 22 * terms of the GNU General Public License Version 2 or later (the 23 * "GPL"), in which case the provisions of the GPL are applicable 24 * instead of those above. If you wish to allow use of your 25 * version of this file only under the terms of the GPL and not to 26 * allow others to use your version of this file under the MPL, 27 * indicate your decision by deleting the provisions above and 28 * replace them with the notice and other provisions required by 29 * the GPL. If you do not delete the provisions above, a recipient 30 * may use your version of this file under either the MPL or the 31 * GPL. 32 */ 33 34/* 35 * CMS contentInfo methods. 36 */ 37 38#include <Security/SecCmsContentInfo.h> 39 40#include <Security/SecCmsDigestContext.h> 41#include <Security/SecCmsDigestedData.h> 42#include <Security/SecCmsEncryptedData.h> 43#include <Security/SecCmsEnvelopedData.h> 44#include <Security/SecCmsSignedData.h> 45 46#include "cmslocal.h" 47 48//#include "pk11func.h" 49#include "secoid.h" 50#include "SecAsn1Item.h" 51 52#include <security_asn1/secerr.h> 53#include <security_asn1/secport.h> 54 55#include <Security/SecBase.h> 56 57/* 58 * SecCmsContentInfoDestroy - destroy a CMS contentInfo and all of its sub-pieces. 59 */ 60void 61SecCmsContentInfoDestroy(SecCmsContentInfoRef cinfo) 62{ 63 SECOidTag kind; 64 65 kind = SecCmsContentInfoGetContentTypeTag(cinfo); 66 switch (kind) { 67 case SEC_OID_PKCS7_ENVELOPED_DATA: 68 SecCmsEnvelopedDataDestroy(cinfo->content.envelopedData); 69 break; 70 case SEC_OID_PKCS7_SIGNED_DATA: 71 SecCmsSignedDataDestroy(cinfo->content.signedData); 72 break; 73 case SEC_OID_PKCS7_ENCRYPTED_DATA: 74 SecCmsEncryptedDataDestroy(cinfo->content.encryptedData); 75 break; 76 case SEC_OID_PKCS7_DIGESTED_DATA: 77 SecCmsDigestedDataDestroy(cinfo->content.digestedData); 78 break; 79 default: 80 /* XXX Anything else that needs to be "manually" freed/destroyed? */ 81 break; 82 } 83 if (cinfo->digcx) { 84 /* must destroy digest objects */ 85 SecCmsDigestContextCancel(cinfo->digcx); 86 cinfo->digcx = NULL; 87 } 88 if (cinfo->bulkkey) 89 CFRelease(cinfo->bulkkey); 90 /* @@@ private key is only here as a workaround for 3401088. Note this *must* be released after bulkkey */ 91 if (cinfo->privkey) 92 CFRelease(cinfo->privkey); 93 94 if (cinfo->ciphcx) { 95 SecCmsCipherContextDestroy(cinfo->ciphcx); 96 cinfo->ciphcx = NULL; 97 } 98 99 /* we live in a pool, so no need to worry about storage */ 100} 101 102/* 103 * SecCmsContentInfoGetChildContentInfo - get content's contentInfo (if it exists) 104 */ 105SecCmsContentInfoRef 106SecCmsContentInfoGetChildContentInfo(SecCmsContentInfoRef cinfo) 107{ 108 void *ptr = NULL; 109 SecCmsContentInfoRef ccinfo = NULL; 110 SECOidTag tag = SecCmsContentInfoGetContentTypeTag(cinfo); 111 switch (tag) { 112 case SEC_OID_PKCS7_SIGNED_DATA: 113 ptr = (void *)cinfo->content.signedData; 114 ccinfo = &(cinfo->content.signedData->contentInfo); 115 break; 116 case SEC_OID_PKCS7_ENVELOPED_DATA: 117 ptr = (void *)cinfo->content.envelopedData; 118 ccinfo = &(cinfo->content.envelopedData->contentInfo); 119 break; 120 case SEC_OID_PKCS7_DIGESTED_DATA: 121 ptr = (void *)cinfo->content.digestedData; 122 ccinfo = &(cinfo->content.digestedData->contentInfo); 123 break; 124 case SEC_OID_PKCS7_ENCRYPTED_DATA: 125 ptr = (void *)cinfo->content.encryptedData; 126 ccinfo = &(cinfo->content.encryptedData->contentInfo); 127 break; 128 case SEC_OID_PKCS7_DATA: 129 default: 130 break; 131 } 132 return (ptr ? ccinfo : NULL); 133} 134 135/* 136 * SecCmsContentInfoSetContent - set content type & content 137 */ 138OSStatus 139SecCmsContentInfoSetContent(SecCmsContentInfoRef cinfo, SECOidTag type, void *ptr) 140{ 141 OSStatus rv; 142 143 cinfo->contentTypeTag = SECOID_FindOIDByTag(type); 144 if (cinfo->contentTypeTag == NULL) 145 return errSecParam; 146 147 /* do not copy the oid, just create a reference */ 148 rv = SECITEM_CopyItem (cinfo->cmsg->poolp, &(cinfo->contentType), &(cinfo->contentTypeTag->oid)); 149 if (rv != SECSuccess) 150 return errSecAllocate; 151 152 cinfo->content.pointer = ptr; 153 154 if (type != SEC_OID_PKCS7_DATA) { 155 /* as we always have some inner data, 156 * we need to set it to something, just to fool the encoder enough to work on it 157 * and get us into nss_cms_encoder_notify at that point */ 158 cinfo->rawContent = SECITEM_AllocItem(cinfo->cmsg->poolp, NULL, 1); 159 if (cinfo->rawContent == NULL) { 160 PORT_SetError(SEC_ERROR_NO_MEMORY); 161 return errSecAllocate; 162 } 163 } 164 165 return errSecSuccess; 166} 167 168/* 169 * SecCmsContentInfoSetContentXXXX - typesafe wrappers for SecCmsContentInfoSetContent 170 */ 171 172/* 173 * data == NULL -> pass in data via SecCmsEncoderUpdate 174 * data != NULL -> take this data 175 */ 176OSStatus 177SecCmsContentInfoSetContentData(SecCmsContentInfoRef cinfo, CFDataRef dataRef, Boolean detached) 178{ 179 SecAsn1Item * data = NULL; 180 if (dataRef) { 181 /* @@@ Fixme CFRetain the passed in data rather than 182 always copying it for performance. */ 183 data = PORT_ArenaAlloc(cinfo->cmsg->poolp, sizeof(SecAsn1Item)); 184 data->Length = CFDataGetLength(dataRef); 185 if (data->Length) { 186 data->Data = PORT_ArenaAlloc(cinfo->cmsg->poolp, data->Length); 187 memcpy(data->Data, CFDataGetBytePtr(dataRef), data->Length); 188 } 189 else 190 data->Data = NULL; 191 } 192 193 if (SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_DATA, (void *)data) != SECSuccess) 194 return PORT_GetError(); 195 cinfo->rawContent = (detached) ? 196 NULL : (data) ? 197 data : SECITEM_AllocItem(cinfo->cmsg->poolp, NULL, 1); 198 return errSecSuccess; 199} 200 201OSStatus 202SecCmsContentInfoSetContentSignedData(SecCmsContentInfoRef cinfo, SecCmsSignedDataRef sigd) 203{ 204 return SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_SIGNED_DATA, (void *)sigd); 205} 206 207OSStatus 208SecCmsContentInfoSetContentEnvelopedData(SecCmsContentInfoRef cinfo, SecCmsEnvelopedDataRef envd) 209{ 210 return SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_ENVELOPED_DATA, (void *)envd); 211} 212 213OSStatus 214SecCmsContentInfoSetContentDigestedData(SecCmsContentInfoRef cinfo, SecCmsDigestedDataRef digd) 215{ 216 return SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_DIGESTED_DATA, (void *)digd); 217} 218 219OSStatus 220SecCmsContentInfoSetContentEncryptedData(SecCmsContentInfoRef cinfo, SecCmsEncryptedDataRef encd) 221{ 222 return SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_ENCRYPTED_DATA, (void *)encd); 223} 224 225/* 226 * SecCmsContentInfoGetContent - get pointer to inner content 227 * 228 * needs to be casted... 229 */ 230void * 231SecCmsContentInfoGetContent(SecCmsContentInfoRef cinfo) 232{ 233 SECOidTag tag = (cinfo && cinfo->contentTypeTag) 234 ? cinfo->contentTypeTag->offset 235 : SEC_OID_UNKNOWN; 236 switch (tag) { 237 case SEC_OID_PKCS7_DATA: 238 case SEC_OID_PKCS7_SIGNED_DATA: 239 case SEC_OID_PKCS7_ENVELOPED_DATA: 240 case SEC_OID_PKCS7_DIGESTED_DATA: 241 case SEC_OID_PKCS7_ENCRYPTED_DATA: 242 return cinfo->content.pointer; 243 default: 244 return NULL; 245 } 246} 247 248/* 249 * SecCmsContentInfoGetInnerContent - get pointer to innermost content 250 * 251 * this is typically only called by SecCmsMessageGetContent() 252 */ 253const SecAsn1Item * 254SecCmsContentInfoGetInnerContent(SecCmsContentInfoRef cinfo) 255{ 256 SecCmsContentInfoRef ccinfo; 257 SECOidTag tag; 258 SecAsn1Item * pItem; 259 260 tag = SecCmsContentInfoGetContentTypeTag(cinfo); 261 switch (tag) { 262 case SEC_OID_PKCS7_DATA: 263 /* end of recursion - every message has to have a data cinfo */ 264 pItem = cinfo->content.data; 265 break; 266 case SEC_OID_PKCS7_DIGESTED_DATA: 267 case SEC_OID_PKCS7_ENCRYPTED_DATA: 268 case SEC_OID_PKCS7_ENVELOPED_DATA: 269 case SEC_OID_PKCS7_SIGNED_DATA: 270 ccinfo = SecCmsContentInfoGetChildContentInfo(cinfo); 271 if (ccinfo == NULL) 272 pItem = NULL; 273 else 274 pItem = SecCmsContentInfoGetContent(ccinfo); 275 break; 276 default: 277 PORT_Assert(0); 278 pItem = NULL; 279 break; 280 } 281 return pItem; 282} 283 284/* 285 * SecCmsContentInfoGetContentType{Tag,OID} - find out (saving pointer to lookup result 286 * for future reference) and return the inner content type. 287 */ 288SECOidTag 289SecCmsContentInfoGetContentTypeTag(SecCmsContentInfoRef cinfo) 290{ 291 if (cinfo->contentTypeTag == NULL) 292 cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType)); 293 294 if (cinfo->contentTypeTag == NULL) 295 return SEC_OID_UNKNOWN; 296 297 return cinfo->contentTypeTag->offset; 298} 299 300SecAsn1Oid * 301SecCmsContentInfoGetContentTypeOID(SecCmsContentInfoRef cinfo) 302{ 303 if (cinfo->contentTypeTag == NULL) 304 cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType)); 305 306 if (cinfo->contentTypeTag == NULL) 307 return NULL; 308 309 return &(cinfo->contentTypeTag->oid); 310} 311 312/* 313 * SecCmsContentInfoGetContentEncAlgTag - find out (saving pointer to lookup result 314 * for future reference) and return the content encryption algorithm tag. 315 */ 316SECOidTag 317SecCmsContentInfoGetContentEncAlgTag(SecCmsContentInfoRef cinfo) 318{ 319 if (cinfo->contentEncAlgTag == SEC_OID_UNKNOWN) 320 cinfo->contentEncAlgTag = SECOID_GetAlgorithmTag(&(cinfo->contentEncAlg)); 321 322 return cinfo->contentEncAlgTag; 323} 324 325/* 326 * SecCmsContentInfoGetContentEncAlg - find out and return the content encryption algorithm tag. 327 */ 328SECAlgorithmID * 329SecCmsContentInfoGetContentEncAlg(SecCmsContentInfoRef cinfo) 330{ 331 return &(cinfo->contentEncAlg); 332} 333 334OSStatus 335SecCmsContentInfoSetContentEncAlg(SecCmsContentInfoRef cinfo, 336 SECOidTag bulkalgtag, const SecAsn1Item *parameters, int keysize) 337{ 338 PLArenaPool *poolp = cinfo->cmsg->poolp; 339 OSStatus rv; 340 341 rv = SECOID_SetAlgorithmID(poolp, &(cinfo->contentEncAlg), bulkalgtag, parameters); 342 if (rv != SECSuccess) 343 return SECFailure; 344 cinfo->keysize = keysize; 345 return SECSuccess; 346} 347 348OSStatus 349SecCmsContentInfoSetContentEncAlgID(SecCmsContentInfoRef cinfo, 350 SECAlgorithmID *algid, int keysize) 351{ 352 PLArenaPool *poolp = cinfo->cmsg->poolp; 353 OSStatus rv; 354 355 rv = SECOID_CopyAlgorithmID(poolp, &(cinfo->contentEncAlg), algid); 356 if (rv != SECSuccess) 357 return SECFailure; 358 if (keysize >= 0) 359 cinfo->keysize = keysize; 360 return SECSuccess; 361} 362 363void 364SecCmsContentInfoSetBulkKey(SecCmsContentInfoRef cinfo, SecSymmetricKeyRef bulkkey) 365{ 366#ifdef USE_CDSA_CRYPTO 367 const CSSM_KEY *cssmKey = NULL; 368#endif 369 cinfo->bulkkey = bulkkey; 370 CFRetain(cinfo->bulkkey); 371#ifdef USE_CDSA_CRYPTO 372 SecKeyGetCSSMKey(cinfo->bulkkey, &cssmKey); 373 cinfo->keysize = cssmKey ? cssmKey->KeyHeader.LogicalKeySizeInBits : 0; 374#else 375 /* This cast should be always safe, there should be SecSymmetricKeyRef API to get the size anyway */ 376 cinfo->keysize = (int)CFDataGetLength((CFDataRef)bulkkey) * 8; 377#endif 378} 379 380SecSymmetricKeyRef 381SecCmsContentInfoGetBulkKey(SecCmsContentInfoRef cinfo) 382{ 383 if (cinfo->bulkkey == NULL) 384 return NULL; 385 386 CFRetain(cinfo->bulkkey); 387 return cinfo->bulkkey; 388} 389 390int 391SecCmsContentInfoGetBulkKeySize(SecCmsContentInfoRef cinfo) 392{ 393 return cinfo->keysize; 394} 395