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