Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
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 | } |