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 message methods. 36 */ 37 38#include <Security/SecCmsMessage.h> 39 40#include <Security/SecCmsContentInfo.h> 41#include <Security/SecCmsSignedData.h> 42 43#include "cmslocal.h" 44 45#include "secitem.h" 46#include "secoid.h" 47 48#include <security_asn1/secasn1.h> 49#include <security_asn1/secerr.h> 50 51/* 52 * SecCmsMessageCreate - create a CMS message object 53 * 54 * "poolp" - arena to allocate memory from, or NULL if new arena should be created 55 */ 56SecCmsMessageRef 57SecCmsMessageCreate(SecArenaPoolRef pool) 58{ 59 PLArenaPool *poolp = (PLArenaPool *)pool; 60 void *mark = NULL; 61 SecCmsMessageRef cmsg; 62 Boolean poolp_is_ours = PR_FALSE; 63 64 if (poolp == NULL) { 65 poolp = PORT_NewArena (1024); /* XXX what is right value? */ 66 if (poolp == NULL) 67 return NULL; 68 poolp_is_ours = PR_TRUE; 69 } 70 71 if (!poolp_is_ours) 72 mark = PORT_ArenaMark(poolp); 73 74 cmsg = (SecCmsMessageRef)PORT_ArenaZAlloc (poolp, sizeof(SecCmsMessage)); 75 if (cmsg == NULL) { 76 if (!poolp_is_ours) { 77 if (mark) { 78 PORT_ArenaRelease(poolp, mark); 79 } 80 } else 81 PORT_FreeArena(poolp, PR_FALSE); 82 return NULL; 83 } 84 85 cmsg->poolp = poolp; 86 cmsg->poolp_is_ours = poolp_is_ours; 87 cmsg->refCount = 1; 88 89 if (mark) 90 PORT_ArenaUnmark(poolp, mark); 91 92 return cmsg; 93} 94 95/* 96 * SecCmsMessageSetEncodingParams - set up a CMS message object for encoding or decoding 97 * 98 * "cmsg" - message object 99 * "pwfn", pwfn_arg" - callback function for getting token password 100 * "decrypt_key_cb", "decrypt_key_cb_arg" - callback function for getting bulk key for encryptedData 101 * "detached_digestalgs", "detached_digests" - digests from detached content 102 */ 103void 104SecCmsMessageSetEncodingParams(SecCmsMessageRef cmsg, 105 PK11PasswordFunc pwfn, void *pwfn_arg, 106 SecCmsGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg, 107 SECAlgorithmID **detached_digestalgs, CSSM_DATA_PTR *detached_digests) 108{ 109#if 0 110 // @@@ Deal with password stuff. 111 if (pwfn) 112 PK11_SetPasswordFunc(pwfn); 113#endif 114 cmsg->pwfn_arg = pwfn_arg; 115 cmsg->decrypt_key_cb = decrypt_key_cb; 116 cmsg->decrypt_key_cb_arg = decrypt_key_cb_arg; 117 cmsg->detached_digestalgs = detached_digestalgs; 118 cmsg->detached_digests = detached_digests; 119} 120 121/* 122 * SecCmsMessageDestroy - destroy a CMS message and all of its sub-pieces. 123 */ 124void 125SecCmsMessageDestroy(SecCmsMessageRef cmsg) 126{ 127 PORT_Assert (cmsg->refCount > 0); 128 if (cmsg->refCount <= 0) /* oops */ 129 return; 130 131 cmsg->refCount--; /* thread safety? */ 132 if (cmsg->refCount > 0) 133 return; 134 135 SecCmsContentInfoDestroy(&(cmsg->contentInfo)); 136 137 /* if poolp is not NULL, cmsg is the owner of its arena */ 138 if (cmsg->poolp_is_ours) 139 PORT_FreeArena (cmsg->poolp, PR_FALSE); /* XXX clear it? */ 140} 141 142/* 143 * SecCmsMessageCopy - return a copy of the given message. 144 * 145 * The copy may be virtual or may be real -- either way, the result needs 146 * to be passed to SecCmsMessageDestroy later (as does the original). 147 */ 148SecCmsMessageRef 149SecCmsMessageCopy(SecCmsMessageRef cmsg) 150{ 151 if (cmsg == NULL) 152 return NULL; 153 154 PORT_Assert (cmsg->refCount > 0); 155 156 cmsg->refCount++; /* XXX chrisk thread safety? */ 157 return cmsg; 158} 159 160/* 161 * SecCmsMessageGetArena - return a pointer to the message's arena pool 162 */ 163SecArenaPoolRef 164SecCmsMessageGetArena(SecCmsMessageRef cmsg) 165{ 166 return (SecArenaPoolRef)cmsg->poolp; 167} 168 169/* 170 * SecCmsMessageGetContentInfo - return a pointer to the top level contentInfo 171 */ 172SecCmsContentInfoRef 173SecCmsMessageGetContentInfo(SecCmsMessageRef cmsg) 174{ 175 return &(cmsg->contentInfo); 176} 177 178/* 179 * Return a pointer to the actual content. 180 * In the case of those types which are encrypted, this returns the *plain* content. 181 * In case of nested contentInfos, this descends and retrieves the innermost content. 182 */ 183CSSM_DATA_PTR 184SecCmsMessageGetContent(SecCmsMessageRef cmsg) 185{ 186 /* this is a shortcut */ 187 SecCmsContentInfoRef cinfo = SecCmsMessageGetContentInfo(cmsg); 188 CSSM_DATA_PTR pItem = SecCmsContentInfoGetInnerContent(cinfo); 189 return pItem; 190} 191 192/* 193 * SecCmsMessageContentLevelCount - count number of levels of CMS content objects in this message 194 * 195 * CMS data content objects do not count. 196 */ 197int 198SecCmsMessageContentLevelCount(SecCmsMessageRef cmsg) 199{ 200 int count = 0; 201 SecCmsContentInfoRef cinfo; 202 203 /* walk down the chain of contentinfos */ 204 for (cinfo = &(cmsg->contentInfo); cinfo != NULL; ) { 205 count++; 206 cinfo = SecCmsContentInfoGetChildContentInfo(cinfo); 207 } 208 return count; 209} 210 211/* 212 * SecCmsMessageContentLevel - find content level #n 213 * 214 * CMS data content objects do not count. 215 */ 216SecCmsContentInfoRef 217SecCmsMessageContentLevel(SecCmsMessageRef cmsg, int n) 218{ 219 int count = 0; 220 SecCmsContentInfoRef cinfo; 221 222 /* walk down the chain of contentinfos */ 223 for (cinfo = &(cmsg->contentInfo); cinfo != NULL && count < n; cinfo = SecCmsContentInfoGetChildContentInfo(cinfo)) { 224 count++; 225 } 226 227 return cinfo; 228} 229 230/* 231 * SecCmsMessageContainsCertsOrCrls - see if message contains certs along the way 232 */ 233Boolean 234SecCmsMessageContainsCertsOrCrls(SecCmsMessageRef cmsg) 235{ 236 SecCmsContentInfoRef cinfo; 237 238 /* descend into CMS message */ 239 for (cinfo = &(cmsg->contentInfo); cinfo != NULL; cinfo = SecCmsContentInfoGetChildContentInfo(cinfo)) { 240 if (SecCmsContentInfoGetContentTypeTag(cinfo) != SEC_OID_PKCS7_SIGNED_DATA) 241 continue; /* next level */ 242 243 if (SecCmsSignedDataContainsCertsOrCrls(cinfo->content.signedData)) 244 return PR_TRUE; 245 } 246 return PR_FALSE; 247} 248 249/* 250 * SecCmsMessageIsEncrypted - see if message contains a encrypted submessage 251 */ 252Boolean 253SecCmsMessageIsEncrypted(SecCmsMessageRef cmsg) 254{ 255 SecCmsContentInfoRef cinfo; 256 257 /* walk down the chain of contentinfos */ 258 for (cinfo = &(cmsg->contentInfo); cinfo != NULL; cinfo = SecCmsContentInfoGetChildContentInfo(cinfo)) 259 { 260 switch (SecCmsContentInfoGetContentTypeTag(cinfo)) { 261 case SEC_OID_PKCS7_ENVELOPED_DATA: 262 case SEC_OID_PKCS7_ENCRYPTED_DATA: 263 return PR_TRUE; 264 default: 265 break; 266 } 267 } 268 return PR_FALSE; 269} 270 271/* 272 * SecCmsMessageIsSigned - see if message contains a signed submessage 273 * 274 * If the CMS message has a SignedData with a signature (not just a SignedData) 275 * return true; false otherwise. This can/should be called before calling 276 * VerifySignature, which will always indicate failure if no signature is 277 * present, but that does not mean there even was a signature! 278 * Note that the content itself can be empty (detached content was sent 279 * another way); it is the presence of the signature that matters. 280 */ 281Boolean 282SecCmsMessageIsSigned(SecCmsMessageRef cmsg) 283{ 284 SecCmsContentInfoRef cinfo; 285 286 /* walk down the chain of contentinfos */ 287 for (cinfo = &(cmsg->contentInfo); cinfo != NULL; cinfo = SecCmsContentInfoGetChildContentInfo(cinfo)) 288 { 289 switch (SecCmsContentInfoGetContentTypeTag(cinfo)) { 290 case SEC_OID_PKCS7_SIGNED_DATA: 291 if (!SecCmsArrayIsEmpty((void **)cinfo->content.signedData->signerInfos)) 292 return PR_TRUE; 293 break; 294 default: 295 break; 296 } 297 } 298 return PR_FALSE; 299} 300 301/* 302 * SecCmsMessageIsContentEmpty - see if content is empty 303 * 304 * returns PR_TRUE is innermost content length is < minLen 305 * XXX need the encrypted content length (why?) 306 */ 307Boolean 308SecCmsMessageIsContentEmpty(SecCmsMessageRef cmsg, unsigned int minLen) 309{ 310 CSSM_DATA_PTR item = NULL; 311 312 if (cmsg == NULL) 313 return PR_TRUE; 314 315 item = SecCmsContentInfoGetContent(SecCmsMessageGetContentInfo(cmsg)); 316 317 if (!item) { 318 return PR_TRUE; 319 } else if(item->Length <= minLen) { 320 return PR_TRUE; 321 } 322 323 return PR_FALSE; 324} 325 326/* 327 * SecCmsMessageContainsTSTInfo - see if message contains a TimeStamping info block 328 */ 329Boolean 330SecCmsMessageContainsTSTInfo(SecCmsMessageRef cmsg) 331{ 332 SecCmsContentInfoRef cinfo; 333 334 /* walk down the chain of contentinfos */ 335 for (cinfo = &(cmsg->contentInfo); cinfo != NULL; cinfo = SecCmsContentInfoGetChildContentInfo(cinfo)) 336 { 337 switch (SecCmsContentInfoGetContentTypeTag(cinfo)) 338 { 339 case SEC_OID_PKCS9_ID_CT_TSTInfo: 340 // TSTInfo is in cinfo->rawContent->Data 341 return PR_TRUE; 342 default: 343 break; 344 } 345 } 346 return PR_FALSE; 347} 348 349void 350SecCmsMessageSetTSACallback(SecCmsMessageRef cmsg, SecCmsTSACallback tsaCallback) 351{ 352 if (cmsg) 353 cmsg->tsaCallback = tsaCallback; 354} 355 356void 357SecCmsMessageSetTSAContext(SecCmsMessageRef cmsg, const void *tsaContext) //CFTypeRef 358{ 359 if (cmsg) 360 cmsg->tsaContext = tsaContext; 361} 362 363