1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/smime/cmsmessage.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,291 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/* 1.9 + * CMS message methods. 1.10 + */ 1.11 + 1.12 +#include "cmslocal.h" 1.13 + 1.14 +#include "cert.h" 1.15 +#include "secasn1.h" 1.16 +#include "secitem.h" 1.17 +#include "secoid.h" 1.18 +#include "pk11func.h" 1.19 +#include "secerr.h" 1.20 + 1.21 +/* 1.22 + * NSS_CMSMessage_Create - create a CMS message object 1.23 + * 1.24 + * "poolp" - arena to allocate memory from, or NULL if new arena should be created 1.25 + */ 1.26 +NSSCMSMessage * 1.27 +NSS_CMSMessage_Create(PLArenaPool *poolp) 1.28 +{ 1.29 + void *mark = NULL; 1.30 + NSSCMSMessage *cmsg; 1.31 + PRBool poolp_is_ours = PR_FALSE; 1.32 + 1.33 + if (poolp == NULL) { 1.34 + poolp = PORT_NewArena (1024); /* XXX what is right value? */ 1.35 + if (poolp == NULL) 1.36 + return NULL; 1.37 + poolp_is_ours = PR_TRUE; 1.38 + } 1.39 + 1.40 + if (!poolp_is_ours) 1.41 + mark = PORT_ArenaMark(poolp); 1.42 + 1.43 + cmsg = (NSSCMSMessage *)PORT_ArenaZAlloc (poolp, sizeof(NSSCMSMessage)); 1.44 + if (cmsg == NULL) { 1.45 + if (!poolp_is_ours) { 1.46 + if (mark) { 1.47 + PORT_ArenaRelease(poolp, mark); 1.48 + } 1.49 + } else 1.50 + PORT_FreeArena(poolp, PR_FALSE); 1.51 + return NULL; 1.52 + } 1.53 + NSS_CMSContentInfo_Private_Init(&(cmsg->contentInfo)); 1.54 + 1.55 + cmsg->poolp = poolp; 1.56 + cmsg->poolp_is_ours = poolp_is_ours; 1.57 + cmsg->refCount = 1; 1.58 + 1.59 + if (mark) 1.60 + PORT_ArenaUnmark(poolp, mark); 1.61 + 1.62 + return cmsg; 1.63 +} 1.64 + 1.65 +/* 1.66 + * NSS_CMSMessage_SetEncodingParams - set up a CMS message object for encoding or decoding 1.67 + * 1.68 + * "cmsg" - message object 1.69 + * "pwfn", pwfn_arg" - callback function for getting token password 1.70 + * "decrypt_key_cb", "decrypt_key_cb_arg" - callback function for getting bulk key for encryptedData 1.71 + * "detached_digestalgs", "detached_digests" - digests from detached content 1.72 + */ 1.73 +void 1.74 +NSS_CMSMessage_SetEncodingParams(NSSCMSMessage *cmsg, 1.75 + PK11PasswordFunc pwfn, void *pwfn_arg, 1.76 + NSSCMSGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg, 1.77 + SECAlgorithmID **detached_digestalgs, SECItem **detached_digests) 1.78 +{ 1.79 + if (pwfn) 1.80 + PK11_SetPasswordFunc(pwfn); 1.81 + cmsg->pwfn_arg = pwfn_arg; 1.82 + cmsg->decrypt_key_cb = decrypt_key_cb; 1.83 + cmsg->decrypt_key_cb_arg = decrypt_key_cb_arg; 1.84 + cmsg->detached_digestalgs = detached_digestalgs; 1.85 + cmsg->detached_digests = detached_digests; 1.86 +} 1.87 + 1.88 +/* 1.89 + * NSS_CMSMessage_Destroy - destroy a CMS message and all of its sub-pieces. 1.90 + */ 1.91 +void 1.92 +NSS_CMSMessage_Destroy(NSSCMSMessage *cmsg) 1.93 +{ 1.94 + PORT_Assert (cmsg->refCount > 0); 1.95 + if (cmsg->refCount <= 0) /* oops */ 1.96 + return; 1.97 + 1.98 + cmsg->refCount--; /* thread safety? */ 1.99 + if (cmsg->refCount > 0) 1.100 + return; 1.101 + 1.102 + NSS_CMSContentInfo_Destroy(&(cmsg->contentInfo)); 1.103 + 1.104 + /* if poolp is not NULL, cmsg is the owner of its arena */ 1.105 + if (cmsg->poolp_is_ours) 1.106 + PORT_FreeArena (cmsg->poolp, PR_FALSE); /* XXX clear it? */ 1.107 +} 1.108 + 1.109 +/* 1.110 + * NSS_CMSMessage_Copy - return a copy of the given message. 1.111 + * 1.112 + * The copy may be virtual or may be real -- either way, the result needs 1.113 + * to be passed to NSS_CMSMessage_Destroy later (as does the original). 1.114 + */ 1.115 +NSSCMSMessage * 1.116 +NSS_CMSMessage_Copy(NSSCMSMessage *cmsg) 1.117 +{ 1.118 + if (cmsg == NULL) 1.119 + return NULL; 1.120 + 1.121 + PORT_Assert (cmsg->refCount > 0); 1.122 + 1.123 + cmsg->refCount++; /* XXX chrisk thread safety? */ 1.124 + return cmsg; 1.125 +} 1.126 + 1.127 +/* 1.128 + * NSS_CMSMessage_GetArena - return a pointer to the message's arena pool 1.129 + */ 1.130 +PLArenaPool * 1.131 +NSS_CMSMessage_GetArena(NSSCMSMessage *cmsg) 1.132 +{ 1.133 + return cmsg->poolp; 1.134 +} 1.135 + 1.136 +/* 1.137 + * NSS_CMSMessage_GetContentInfo - return a pointer to the top level contentInfo 1.138 + */ 1.139 +NSSCMSContentInfo * 1.140 +NSS_CMSMessage_GetContentInfo(NSSCMSMessage *cmsg) 1.141 +{ 1.142 + return &(cmsg->contentInfo); 1.143 +} 1.144 + 1.145 +/* 1.146 + * Return a pointer to the actual content. 1.147 + * In the case of those types which are encrypted, this returns the *plain* content. 1.148 + * In case of nested contentInfos, this descends and retrieves the innermost content. 1.149 + */ 1.150 +SECItem * 1.151 +NSS_CMSMessage_GetContent(NSSCMSMessage *cmsg) 1.152 +{ 1.153 + /* this is a shortcut */ 1.154 + NSSCMSContentInfo * cinfo = NSS_CMSMessage_GetContentInfo(cmsg); 1.155 + SECItem * pItem = NSS_CMSContentInfo_GetInnerContent(cinfo); 1.156 + return pItem; 1.157 +} 1.158 + 1.159 +/* 1.160 + * NSS_CMSMessage_ContentLevelCount - count number of levels of CMS content objects in this message 1.161 + * 1.162 + * CMS data content objects do not count. 1.163 + */ 1.164 +int 1.165 +NSS_CMSMessage_ContentLevelCount(NSSCMSMessage *cmsg) 1.166 +{ 1.167 + int count = 0; 1.168 + NSSCMSContentInfo *cinfo; 1.169 + 1.170 + /* walk down the chain of contentinfos */ 1.171 + for (cinfo = &(cmsg->contentInfo); cinfo != NULL; ) { 1.172 + count++; 1.173 + cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo); 1.174 + } 1.175 + return count; 1.176 +} 1.177 + 1.178 +/* 1.179 + * NSS_CMSMessage_ContentLevel - find content level #n 1.180 + * 1.181 + * CMS data content objects do not count. 1.182 + */ 1.183 +NSSCMSContentInfo * 1.184 +NSS_CMSMessage_ContentLevel(NSSCMSMessage *cmsg, int n) 1.185 +{ 1.186 + int count = 0; 1.187 + NSSCMSContentInfo *cinfo; 1.188 + 1.189 + /* walk down the chain of contentinfos */ 1.190 + for (cinfo = &(cmsg->contentInfo); cinfo != NULL && count < n; cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) { 1.191 + count++; 1.192 + } 1.193 + 1.194 + return cinfo; 1.195 +} 1.196 + 1.197 +/* 1.198 + * NSS_CMSMessage_ContainsCertsOrCrls - see if message contains certs along the way 1.199 + */ 1.200 +PRBool 1.201 +NSS_CMSMessage_ContainsCertsOrCrls(NSSCMSMessage *cmsg) 1.202 +{ 1.203 + NSSCMSContentInfo *cinfo; 1.204 + 1.205 + /* descend into CMS message */ 1.206 + for (cinfo = &(cmsg->contentInfo); cinfo != NULL; cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) { 1.207 + if (!NSS_CMSType_IsData(NSS_CMSContentInfo_GetContentTypeTag(cinfo))) 1.208 + continue; /* next level */ 1.209 + 1.210 + if (NSS_CMSSignedData_ContainsCertsOrCrls(cinfo->content.signedData)) 1.211 + return PR_TRUE; 1.212 + /* callback here for generic wrappers? */ 1.213 + } 1.214 + return PR_FALSE; 1.215 +} 1.216 + 1.217 +/* 1.218 + * NSS_CMSMessage_IsEncrypted - see if message contains a encrypted submessage 1.219 + */ 1.220 +PRBool 1.221 +NSS_CMSMessage_IsEncrypted(NSSCMSMessage *cmsg) 1.222 +{ 1.223 + NSSCMSContentInfo *cinfo; 1.224 + 1.225 + /* walk down the chain of contentinfos */ 1.226 + for (cinfo = &(cmsg->contentInfo); cinfo != NULL; cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) 1.227 + { 1.228 + switch (NSS_CMSContentInfo_GetContentTypeTag(cinfo)) { 1.229 + case SEC_OID_PKCS7_ENVELOPED_DATA: 1.230 + case SEC_OID_PKCS7_ENCRYPTED_DATA: 1.231 + return PR_TRUE; 1.232 + default: 1.233 + /* callback here for generic wrappers? */ 1.234 + break; 1.235 + } 1.236 + } 1.237 + return PR_FALSE; 1.238 +} 1.239 + 1.240 +/* 1.241 + * NSS_CMSMessage_IsSigned - see if message contains a signed submessage 1.242 + * 1.243 + * If the CMS message has a SignedData with a signature (not just a SignedData) 1.244 + * return true; false otherwise. This can/should be called before calling 1.245 + * VerifySignature, which will always indicate failure if no signature is 1.246 + * present, but that does not mean there even was a signature! 1.247 + * Note that the content itself can be empty (detached content was sent 1.248 + * another way); it is the presence of the signature that matters. 1.249 + */ 1.250 +PRBool 1.251 +NSS_CMSMessage_IsSigned(NSSCMSMessage *cmsg) 1.252 +{ 1.253 + NSSCMSContentInfo *cinfo; 1.254 + 1.255 + /* walk down the chain of contentinfos */ 1.256 + for (cinfo = &(cmsg->contentInfo); cinfo != NULL; cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) 1.257 + { 1.258 + switch (NSS_CMSContentInfo_GetContentTypeTag(cinfo)) { 1.259 + case SEC_OID_PKCS7_SIGNED_DATA: 1.260 + if (!NSS_CMSArray_IsEmpty((void **)cinfo->content.signedData->signerInfos)) 1.261 + return PR_TRUE; 1.262 + break; 1.263 + default: 1.264 + /* callback here for generic wrappers? */ 1.265 + break; 1.266 + } 1.267 + } 1.268 + return PR_FALSE; 1.269 +} 1.270 + 1.271 +/* 1.272 + * NSS_CMSMessage_IsContentEmpty - see if content is empty 1.273 + * 1.274 + * returns PR_TRUE is innermost content length is < minLen 1.275 + * XXX need the encrypted content length (why?) 1.276 + */ 1.277 +PRBool 1.278 +NSS_CMSMessage_IsContentEmpty(NSSCMSMessage *cmsg, unsigned int minLen) 1.279 +{ 1.280 + SECItem *item = NULL; 1.281 + 1.282 + if (cmsg == NULL) 1.283 + return PR_TRUE; 1.284 + 1.285 + item = NSS_CMSContentInfo_GetContent(NSS_CMSMessage_GetContentInfo(cmsg)); 1.286 + 1.287 + if (!item) { 1.288 + return PR_TRUE; 1.289 + } else if(item->len <= minLen) { 1.290 + return PR_TRUE; 1.291 + } 1.292 + 1.293 + return PR_FALSE; 1.294 +}