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 "secitem.h" 51 52#include <security_asn1/secerr.h> 53#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h> 54 55/* 56 * SecCmsContentInfoCreate - create a content info 57 * 58 * version is set in the _Finalize procedures for each content type 59 */ 60 61/* 62 * SecCmsContentInfoDestroy - destroy a CMS contentInfo and all of its sub-pieces. 63 */ 64void 65SecCmsContentInfoDestroy(SecCmsContentInfoRef cinfo) 66{ 67 SECOidTag kind; 68 69 kind = SecCmsContentInfoGetContentTypeTag(cinfo); 70 switch (kind) { 71 case SEC_OID_PKCS7_ENVELOPED_DATA: 72 SecCmsEnvelopedDataDestroy(cinfo->content.envelopedData); 73 break; 74 case SEC_OID_PKCS7_SIGNED_DATA: 75 SecCmsSignedDataDestroy(cinfo->content.signedData); 76 break; 77 case SEC_OID_PKCS7_ENCRYPTED_DATA: 78 SecCmsEncryptedDataDestroy(cinfo->content.encryptedData); 79 break; 80 case SEC_OID_PKCS7_DIGESTED_DATA: 81 SecCmsDigestedDataDestroy(cinfo->content.digestedData); 82 break; 83 default: 84 /* XXX Anything else that needs to be "manually" freed/destroyed? */ 85 break; 86 } 87 if (cinfo->digcx) { 88 /* must destroy digest objects */ 89 SecCmsDigestContextCancel(cinfo->digcx); 90 cinfo->digcx = NULL; 91 } 92 if (cinfo->bulkkey) 93 CFRelease(cinfo->bulkkey); 94 /* @@@ private key is only here as a workaround for 3401088. Note this *must* be released after bulkkey */ 95 if (cinfo->privkey) 96 CFRelease(cinfo->privkey); 97 98 if (cinfo->ciphcx) { 99 SecCmsCipherContextDestroy(cinfo->ciphcx); 100 cinfo->ciphcx = NULL; 101 } 102 103 /* we live in a pool, so no need to worry about storage */ 104} 105 106/* 107 * SecCmsContentInfoGetChildContentInfo - get content's contentInfo (if it exists) 108 */ 109SecCmsContentInfoRef 110SecCmsContentInfoGetChildContentInfo(SecCmsContentInfoRef cinfo) 111{ 112 void *ptr = NULL; 113 SecCmsContentInfoRef ccinfo = NULL; 114 SECOidTag tag = SecCmsContentInfoGetContentTypeTag(cinfo); 115 switch (tag) { 116 case SEC_OID_PKCS7_SIGNED_DATA: 117 ptr = (void *)cinfo->content.signedData; 118 ccinfo = &(cinfo->content.signedData->contentInfo); 119 break; 120 case SEC_OID_PKCS7_ENVELOPED_DATA: 121 ptr = (void *)cinfo->content.envelopedData; 122 ccinfo = &(cinfo->content.envelopedData->contentInfo); 123 break; 124 case SEC_OID_PKCS7_DIGESTED_DATA: 125 ptr = (void *)cinfo->content.digestedData; 126 ccinfo = &(cinfo->content.digestedData->contentInfo); 127 break; 128 case SEC_OID_PKCS7_ENCRYPTED_DATA: 129 ptr = (void *)cinfo->content.encryptedData; 130 ccinfo = &(cinfo->content.encryptedData->contentInfo); 131 break; 132 case SEC_OID_PKCS7_DATA: 133 case SEC_OID_OTHER: 134 default: 135 break; 136 } 137 return (ptr ? ccinfo : NULL); 138} 139 140/* 141 * SecCmsContentInfoSetContent - set content type & content 142 */ 143OSStatus 144SecCmsContentInfoSetContent(SecCmsMessageRef cmsg, SecCmsContentInfoRef cinfo, SECOidTag type, void *ptr) 145{ 146 OSStatus rv; 147 148 cinfo->contentTypeTag = SECOID_FindOIDByTag(type); 149 if (cinfo->contentTypeTag == NULL) 150 return paramErr; 151 152 /* do not copy the oid, just create a reference */ 153 rv = SECITEM_CopyItem (cmsg->poolp, &(cinfo->contentType), &(cinfo->contentTypeTag->oid)); 154 if (rv != SECSuccess) 155 return memFullErr; 156 157 cinfo->content.pointer = ptr; 158 159 if (type != SEC_OID_PKCS7_DATA) { 160 /* as we always have some inner data, 161 * we need to set it to something, just to fool the encoder enough to work on it 162 * and get us into nss_cms_encoder_notify at that point */ 163 cinfo->rawContent = SECITEM_AllocItem(cmsg->poolp, NULL, 1); 164 if (cinfo->rawContent == NULL) { 165 PORT_SetError(SEC_ERROR_NO_MEMORY); 166 return memFullErr; 167 } 168 } 169 170 return noErr; 171} 172 173/* 174 * SecCmsContentInfoSetContentXXXX - typesafe wrappers for SecCmsContentInfoSetContent 175 */ 176 177/* 178 * data == NULL -> pass in data via SecCmsEncoderUpdate 179 * data != NULL -> take this data 180 */ 181OSStatus 182SecCmsContentInfoSetContentData(SecCmsMessageRef cmsg, SecCmsContentInfoRef cinfo, CSSM_DATA_PTR data, Boolean detached) 183{ 184 if (SecCmsContentInfoSetContent(cmsg, cinfo, SEC_OID_PKCS7_DATA, (void *)data) != SECSuccess) 185 return PORT_GetError(); 186 cinfo->rawContent = (detached) ? 187 NULL : (data) ? 188 data : SECITEM_AllocItem(cmsg->poolp, NULL, 1); 189 return noErr; 190} 191 192OSStatus 193SecCmsContentInfoSetContentSignedData(SecCmsMessageRef cmsg, SecCmsContentInfoRef cinfo, SecCmsSignedDataRef sigd) 194{ 195 return SecCmsContentInfoSetContent(cmsg, cinfo, SEC_OID_PKCS7_SIGNED_DATA, (void *)sigd); 196} 197 198OSStatus 199SecCmsContentInfoSetContentEnvelopedData(SecCmsMessageRef cmsg, SecCmsContentInfoRef cinfo, SecCmsEnvelopedDataRef envd) 200{ 201 return SecCmsContentInfoSetContent(cmsg, cinfo, SEC_OID_PKCS7_ENVELOPED_DATA, (void *)envd); 202} 203 204OSStatus 205SecCmsContentInfoSetContentDigestedData(SecCmsMessageRef cmsg, SecCmsContentInfoRef cinfo, SecCmsDigestedDataRef digd) 206{ 207 return SecCmsContentInfoSetContent(cmsg, cinfo, SEC_OID_PKCS7_DIGESTED_DATA, (void *)digd); 208} 209 210OSStatus 211SecCmsContentInfoSetContentEncryptedData(SecCmsMessageRef cmsg, SecCmsContentInfoRef cinfo, SecCmsEncryptedDataRef encd) 212{ 213 return SecCmsContentInfoSetContent(cmsg, cinfo, SEC_OID_PKCS7_ENCRYPTED_DATA, (void *)encd); 214} 215 216OSStatus 217SecCmsContentInfoSetContentOther(SecCmsMessageRef cmsg, SecCmsContentInfoRef cinfo, CSSM_DATA_PTR data, Boolean detached, const CSSM_OID *eContentType) 218{ 219 SECStatus srtn; 220 SECOidData *tmpOidData; 221 222 /* just like SecCmsContentInfoSetContentData, except override the contentType and 223 * contentTypeTag. This OID is for encoding... */ 224 srtn = SECITEM_CopyItem (cmsg->poolp, &(cinfo->contentType), eContentType); 225 if (srtn != SECSuccess) { 226 return memFullErr; 227 } 228 229 /* this serves up a contentTypeTag with an empty OID */ 230 tmpOidData = SECOID_FindOIDByTag(SEC_OID_OTHER); 231 /* but that's const: cook up a new one we can write to */ 232 cinfo->contentTypeTag = (SECOidData *)PORT_ArenaZAlloc(cmsg->poolp, sizeof(SECOidData)); 233 *cinfo->contentTypeTag = *tmpOidData; 234 /* now fill in the OID */ 235 srtn = SECITEM_CopyItem (cmsg->poolp, &(cinfo->contentTypeTag->oid), eContentType); 236 if (srtn != SECSuccess) { 237 return memFullErr; 238 } 239 cinfo->content.pointer = data; 240 cinfo->rawContent = (detached) ? 241 NULL : (data) ? 242 data : SECITEM_AllocItem(cmsg->poolp, NULL, 1); 243 return noErr; 244} 245 246 247/* 248 * SecCmsContentInfoGetContent - get pointer to inner content 249 * 250 * needs to be casted... 251 */ 252void * 253SecCmsContentInfoGetContent(SecCmsContentInfoRef cinfo) 254{ 255 SECOidTag tag = (cinfo && cinfo->contentTypeTag) 256 ? cinfo->contentTypeTag->offset 257 : cinfo->contentType.Data ? SEC_OID_OTHER : SEC_OID_UNKNOWN; 258 switch (tag) { 259 case SEC_OID_PKCS7_DATA: 260 case SEC_OID_PKCS7_SIGNED_DATA: 261 case SEC_OID_PKCS7_ENVELOPED_DATA: 262 case SEC_OID_PKCS7_DIGESTED_DATA: 263 case SEC_OID_PKCS7_ENCRYPTED_DATA: 264 case SEC_OID_OTHER: 265 return cinfo->content.pointer; 266 default: 267 return NULL; 268 } 269} 270 271/* 272 * SecCmsContentInfoGetInnerContent - get pointer to innermost content 273 * 274 * this is typically only called by SecCmsMessageGetContent() 275 */ 276CSSM_DATA_PTR 277SecCmsContentInfoGetInnerContent(SecCmsContentInfoRef cinfo) 278{ 279 SECOidTag tag; 280 281 for(;;) { 282 tag = SecCmsContentInfoGetContentTypeTag(cinfo); 283 switch (tag) { 284 case SEC_OID_PKCS7_DATA: 285 case SEC_OID_OTHER: 286 /* end of recursion - every message has to have a data cinfo */ 287 return cinfo->content.data; 288 case SEC_OID_PKCS7_DIGESTED_DATA: 289 case SEC_OID_PKCS7_ENCRYPTED_DATA: 290 case SEC_OID_PKCS7_ENVELOPED_DATA: 291 case SEC_OID_PKCS7_SIGNED_DATA: 292 cinfo = SecCmsContentInfoGetChildContentInfo(cinfo); 293 if (cinfo == NULL) { 294 return NULL; 295 } 296 /* else recurse */ 297 break; 298 case SEC_OID_PKCS9_ID_CT_TSTInfo: 299 /* end of recursion - every message has to have a data cinfo */ 300 return cinfo->rawContent; 301 default: 302 PORT_Assert(0); 303 return NULL; 304 } 305 } 306 /* NOT REACHED */ 307 return NULL; 308} 309 310/* 311 * SecCmsContentInfoGetContentType{Tag,OID} - find out (saving pointer to lookup result 312 * for future reference) and return the inner content type. 313 */ 314SECOidTag 315SecCmsContentInfoGetContentTypeTag(SecCmsContentInfoRef cinfo) 316{ 317 if (cinfo->contentTypeTag == NULL) 318 cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType)); 319 320 if (cinfo->contentTypeTag == NULL) 321 return SEC_OID_OTHER; // was...SEC_OID_UNKNOWN OK? 322 323 return cinfo->contentTypeTag->offset; 324} 325 326CSSM_DATA_PTR 327SecCmsContentInfoGetContentTypeOID(SecCmsContentInfoRef cinfo) 328{ 329 if (cinfo->contentTypeTag == NULL) 330 cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType)); 331 332 if (cinfo->contentTypeTag == NULL) { 333 /* if we have an OID but we just don't recognize it, return that */ 334 if(cinfo->contentType.Data != NULL) { 335 return &cinfo->contentType; 336 } 337 else { 338 return NULL; 339 } 340 } 341 return &(cinfo->contentTypeTag->oid); 342} 343 344/* 345 * SecCmsContentInfoGetContentEncAlgTag - find out (saving pointer to lookup result 346 * for future reference) and return the content encryption algorithm tag. 347 */ 348SECOidTag 349SecCmsContentInfoGetContentEncAlgTag(SecCmsContentInfoRef cinfo) 350{ 351 if (cinfo->contentEncAlgTag == SEC_OID_UNKNOWN) 352 cinfo->contentEncAlgTag = SECOID_GetAlgorithmTag(&(cinfo->contentEncAlg)); 353 354 return cinfo->contentEncAlgTag; 355} 356 357/* 358 * SecCmsContentInfoGetContentEncAlg - find out and return the content encryption algorithm tag. 359 */ 360SECAlgorithmID * 361SecCmsContentInfoGetContentEncAlg(SecCmsContentInfoRef cinfo) 362{ 363 return &(cinfo->contentEncAlg); 364} 365 366OSStatus 367SecCmsContentInfoSetContentEncAlg(SecArenaPoolRef pool, SecCmsContentInfoRef cinfo, 368 SECOidTag bulkalgtag, CSSM_DATA_PTR parameters, int keysize) 369{ 370 PLArenaPool *poolp = (PLArenaPool *)pool; 371 OSStatus rv; 372 373 rv = SECOID_SetAlgorithmID(poolp, &(cinfo->contentEncAlg), bulkalgtag, parameters); 374 if (rv != SECSuccess) 375 return SECFailure; 376 cinfo->keysize = keysize; 377 return SECSuccess; 378} 379 380OSStatus 381SecCmsContentInfoSetContentEncAlgID(SecArenaPoolRef pool, SecCmsContentInfoRef cinfo, 382 SECAlgorithmID *algid, int keysize) 383{ 384 PLArenaPool *poolp = (PLArenaPool *)pool; 385 OSStatus rv; 386 387 rv = SECOID_CopyAlgorithmID(poolp, &(cinfo->contentEncAlg), algid); 388 if (rv != SECSuccess) 389 return SECFailure; 390 if (keysize >= 0) 391 cinfo->keysize = keysize; 392 return SECSuccess; 393} 394 395void 396SecCmsContentInfoSetBulkKey(SecCmsContentInfoRef cinfo, SecSymmetricKeyRef bulkkey) 397{ 398 const CSSM_KEY *cssmKey = NULL; 399 400 cinfo->bulkkey = bulkkey; 401 CFRetain(cinfo->bulkkey); 402 SecKeyGetCSSMKey(cinfo->bulkkey, &cssmKey); 403 cinfo->keysize = cssmKey ? cssmKey->KeyHeader.LogicalKeySizeInBits : 0; 404} 405 406SecSymmetricKeyRef 407SecCmsContentInfoGetBulkKey(SecCmsContentInfoRef cinfo) 408{ 409 if (cinfo->bulkkey == NULL) 410 return NULL; 411 412 CFRetain(cinfo->bulkkey); 413 return cinfo->bulkkey; 414} 415 416int 417SecCmsContentInfoGetBulkKeySize(SecCmsContentInfoRef cinfo) 418{ 419 return cinfo->keysize; 420} 421