security/nss/lib/smime/cmsmessage.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial