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