security/nss/lib/smime/cmsmessage.c

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

mercurial