/src/mozilla-central/security/nss/lib/smime/cmsutil.c
Line | Count | Source (jump to first uncovered line) |
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 miscellaneous utility functions. |
7 | | */ |
8 | | |
9 | | #include "cmslocal.h" |
10 | | |
11 | | #include "cert.h" |
12 | | #include "keyhi.h" |
13 | | #include "secasn1.h" |
14 | | #include "secitem.h" |
15 | | #include "secoid.h" |
16 | | #include "pk11func.h" |
17 | | #include "secerr.h" |
18 | | #include "sechash.h" |
19 | | |
20 | | /* |
21 | | * NSS_CMSArray_SortByDER - sort array of objects by objects' DER encoding |
22 | | * |
23 | | * make sure that the order of the objects guarantees valid DER (which must be |
24 | | * in lexigraphically ascending order for a SET OF); if reordering is necessary it |
25 | | * will be done in place (in objs). |
26 | | */ |
27 | | SECStatus |
28 | | NSS_CMSArray_SortByDER(void **objs, const SEC_ASN1Template *objtemplate, void **objs2) |
29 | 0 | { |
30 | 0 | PLArenaPool *poolp; |
31 | 0 | int num_objs; |
32 | 0 | SECItem **enc_objs; |
33 | 0 | SECStatus rv = SECFailure; |
34 | 0 | int i; |
35 | 0 |
|
36 | 0 | if (objs == NULL) /* already sorted */ |
37 | 0 | return SECSuccess; |
38 | 0 | |
39 | 0 | num_objs = NSS_CMSArray_Count((void **)objs); |
40 | 0 | if (num_objs == 0 || num_objs == 1) /* already sorted. */ |
41 | 0 | return SECSuccess; |
42 | 0 | |
43 | 0 | poolp = PORT_NewArena(1024); /* arena for temporaries */ |
44 | 0 | if (poolp == NULL) |
45 | 0 | return SECFailure; /* no memory; nothing we can do... */ |
46 | 0 | |
47 | 0 | /* |
48 | 0 | * Allocate arrays to hold the individual encodings which we will use |
49 | 0 | * for comparisons and the reordered attributes as they are sorted. |
50 | 0 | */ |
51 | 0 | enc_objs = (SECItem **)PORT_ArenaZAlloc(poolp, (num_objs + 1) * sizeof(SECItem *)); |
52 | 0 | if (enc_objs == NULL) |
53 | 0 | goto loser; |
54 | 0 | |
55 | 0 | /* DER encode each individual object. */ |
56 | 0 | for (i = 0; i < num_objs; i++) { |
57 | 0 | enc_objs[i] = SEC_ASN1EncodeItem(poolp, NULL, objs[i], objtemplate); |
58 | 0 | if (enc_objs[i] == NULL) |
59 | 0 | goto loser; |
60 | 0 | } |
61 | 0 | enc_objs[num_objs] = NULL; |
62 | 0 |
|
63 | 0 | /* now compare and sort objs by the order of enc_objs */ |
64 | 0 | NSS_CMSArray_Sort((void **)enc_objs, NSS_CMSUtil_DERCompare, objs, objs2); |
65 | 0 |
|
66 | 0 | rv = SECSuccess; |
67 | 0 |
|
68 | 0 | loser: |
69 | 0 | PORT_FreeArena(poolp, PR_FALSE); |
70 | 0 | return rv; |
71 | 0 | } |
72 | | |
73 | | /* |
74 | | * NSS_CMSUtil_DERCompare - for use with NSS_CMSArray_Sort to |
75 | | * sort arrays of SECItems containing DER |
76 | | */ |
77 | | int |
78 | | NSS_CMSUtil_DERCompare(void *a, void *b) |
79 | 0 | { |
80 | 0 | SECItem *der1 = (SECItem *)a; |
81 | 0 | SECItem *der2 = (SECItem *)b; |
82 | 0 | unsigned int j; |
83 | 0 |
|
84 | 0 | /* |
85 | 0 | * Find the lowest (lexigraphically) encoding. One that is |
86 | 0 | * shorter than all the rest is known to be "less" because each |
87 | 0 | * attribute is of the same type (a SEQUENCE) and so thus the |
88 | 0 | * first octet of each is the same, and the second octet is |
89 | 0 | * the length (or the length of the length with the high bit |
90 | 0 | * set, followed by the length, which also works out to always |
91 | 0 | * order the shorter first). Two (or more) that have the |
92 | 0 | * same length need to be compared byte by byte until a mismatch |
93 | 0 | * is found. |
94 | 0 | */ |
95 | 0 | if (der1->len != der2->len) |
96 | 0 | return (der1->len < der2->len) ? -1 : 1; |
97 | 0 | |
98 | 0 | for (j = 0; j < der1->len; j++) { |
99 | 0 | if (der1->data[j] == der2->data[j]) |
100 | 0 | continue; |
101 | 0 | return (der1->data[j] < der2->data[j]) ? -1 : 1; |
102 | 0 | } |
103 | 0 | return 0; |
104 | 0 | } |
105 | | |
106 | | /* |
107 | | * NSS_CMSAlgArray_GetIndexByAlgID - find a specific algorithm in an array of |
108 | | * algorithms. |
109 | | * |
110 | | * algorithmArray - array of algorithm IDs |
111 | | * algid - algorithmid of algorithm to pick |
112 | | * |
113 | | * Returns: |
114 | | * An integer containing the index of the algorithm in the array or -1 if |
115 | | * algorithm was not found. |
116 | | */ |
117 | | int |
118 | | NSS_CMSAlgArray_GetIndexByAlgID(SECAlgorithmID **algorithmArray, SECAlgorithmID *algid) |
119 | 0 | { |
120 | 0 | int i; |
121 | 0 |
|
122 | 0 | if (algorithmArray == NULL || algorithmArray[0] == NULL) |
123 | 0 | return -1; |
124 | 0 | |
125 | 0 | for (i = 0; algorithmArray[i] != NULL; i++) { |
126 | 0 | if (SECOID_CompareAlgorithmID(algorithmArray[i], algid) == SECEqual) |
127 | 0 | break; /* bingo */ |
128 | 0 | } |
129 | 0 |
|
130 | 0 | if (algorithmArray[i] == NULL) |
131 | 0 | return -1; /* not found */ |
132 | 0 | |
133 | 0 | return i; |
134 | 0 | } |
135 | | |
136 | | /* |
137 | | * NSS_CMSAlgArray_GetIndexByAlgTag - find a specific algorithm in an array of |
138 | | * algorithms. |
139 | | * |
140 | | * algorithmArray - array of algorithm IDs |
141 | | * algtag - algorithm tag of algorithm to pick |
142 | | * |
143 | | * Returns: |
144 | | * An integer containing the index of the algorithm in the array or -1 if |
145 | | * algorithm was not found. |
146 | | */ |
147 | | int |
148 | | NSS_CMSAlgArray_GetIndexByAlgTag(SECAlgorithmID **algorithmArray, |
149 | | SECOidTag algtag) |
150 | 0 | { |
151 | 0 | SECOidData *algid; |
152 | 0 | int i = -1; |
153 | 0 |
|
154 | 0 | if (algorithmArray == NULL || algorithmArray[0] == NULL) |
155 | 0 | return i; |
156 | 0 | |
157 | | #ifdef ORDER_N_SQUARED |
158 | | for (i = 0; algorithmArray[i] != NULL; i++) { |
159 | | algid = SECOID_FindOID(&(algorithmArray[i]->algorithm)); |
160 | | if (algid->offset == algtag) |
161 | | break; /* bingo */ |
162 | | } |
163 | | #else |
164 | 0 | algid = SECOID_FindOIDByTag(algtag); |
165 | 0 | if (!algid) |
166 | 0 | return i; |
167 | 0 | for (i = 0; algorithmArray[i] != NULL; i++) { |
168 | 0 | if (SECITEM_ItemsAreEqual(&algorithmArray[i]->algorithm, &algid->oid)) |
169 | 0 | break; /* bingo */ |
170 | 0 | } |
171 | 0 | #endif |
172 | 0 |
|
173 | 0 | if (algorithmArray[i] == NULL) |
174 | 0 | return -1; /* not found */ |
175 | 0 | |
176 | 0 | return i; |
177 | 0 | } |
178 | | |
179 | | /* |
180 | | * Map a sign algorithm to a digest algorithm. |
181 | | * This is used to handle incorrectly formatted packages sent to us |
182 | | * from Windows 2003. |
183 | | */ |
184 | | SECOidTag |
185 | | NSS_CMSUtil_MapSignAlgs(SECOidTag signAlg) |
186 | 0 | { |
187 | 0 | switch (signAlg) { |
188 | 0 | case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: |
189 | 0 | return SEC_OID_MD2; |
190 | 0 | break; |
191 | 0 | case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: |
192 | 0 | return SEC_OID_MD5; |
193 | 0 | break; |
194 | 0 | case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: |
195 | 0 | case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: |
196 | 0 | case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: |
197 | 0 | return SEC_OID_SHA1; |
198 | 0 | break; |
199 | 0 | case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: |
200 | 0 | case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: |
201 | 0 | return SEC_OID_SHA256; |
202 | 0 | break; |
203 | 0 | case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: |
204 | 0 | case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: |
205 | 0 | return SEC_OID_SHA384; |
206 | 0 | break; |
207 | 0 | case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: |
208 | 0 | case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: |
209 | 0 | return SEC_OID_SHA512; |
210 | 0 | break; |
211 | 0 | default: |
212 | 0 | break; |
213 | 0 | } |
214 | 0 | /* not one of the algtags incorrectly sent to us*/ |
215 | 0 | return signAlg; |
216 | 0 | } |
217 | | |
218 | | const SECHashObject * |
219 | | NSS_CMSUtil_GetHashObjByAlgID(SECAlgorithmID *algid) |
220 | 0 | { |
221 | 0 | SECOidTag oidTag = SECOID_FindOIDTag(&(algid->algorithm)); |
222 | 0 | const SECHashObject *digobj = HASH_GetHashObjectByOidTag(oidTag); |
223 | 0 |
|
224 | 0 | return digobj; |
225 | 0 | } |
226 | | |
227 | | const SEC_ASN1Template * |
228 | | NSS_CMSUtil_GetTemplateByTypeTag(SECOidTag type) |
229 | 0 | { |
230 | 0 | const SEC_ASN1Template *template; |
231 | 0 | extern const SEC_ASN1Template NSSCMSSignedDataTemplate[]; |
232 | 0 | extern const SEC_ASN1Template NSSCMSEnvelopedDataTemplate[]; |
233 | 0 | extern const SEC_ASN1Template NSSCMSEncryptedDataTemplate[]; |
234 | 0 | extern const SEC_ASN1Template NSSCMSDigestedDataTemplate[]; |
235 | 0 |
|
236 | 0 | switch (type) { |
237 | 0 | case SEC_OID_PKCS7_SIGNED_DATA: |
238 | 0 | template = NSSCMSSignedDataTemplate; |
239 | 0 | break; |
240 | 0 | case SEC_OID_PKCS7_ENVELOPED_DATA: |
241 | 0 | template = NSSCMSEnvelopedDataTemplate; |
242 | 0 | break; |
243 | 0 | case SEC_OID_PKCS7_ENCRYPTED_DATA: |
244 | 0 | template = NSSCMSEncryptedDataTemplate; |
245 | 0 | break; |
246 | 0 | case SEC_OID_PKCS7_DIGESTED_DATA: |
247 | 0 | template = NSSCMSDigestedDataTemplate; |
248 | 0 | break; |
249 | 0 | default: |
250 | 0 | template = NSS_CMSType_GetTemplate(type); |
251 | 0 | break; |
252 | 0 | } |
253 | 0 | return template; |
254 | 0 | } |
255 | | |
256 | | size_t |
257 | | NSS_CMSUtil_GetSizeByTypeTag(SECOidTag type) |
258 | 0 | { |
259 | 0 | size_t size; |
260 | 0 |
|
261 | 0 | switch (type) { |
262 | 0 | case SEC_OID_PKCS7_SIGNED_DATA: |
263 | 0 | size = sizeof(NSSCMSSignedData); |
264 | 0 | break; |
265 | 0 | case SEC_OID_PKCS7_ENVELOPED_DATA: |
266 | 0 | size = sizeof(NSSCMSEnvelopedData); |
267 | 0 | break; |
268 | 0 | case SEC_OID_PKCS7_ENCRYPTED_DATA: |
269 | 0 | size = sizeof(NSSCMSEncryptedData); |
270 | 0 | break; |
271 | 0 | case SEC_OID_PKCS7_DIGESTED_DATA: |
272 | 0 | size = sizeof(NSSCMSDigestedData); |
273 | 0 | break; |
274 | 0 | default: |
275 | 0 | size = NSS_CMSType_GetContentSize(type); |
276 | 0 | break; |
277 | 0 | } |
278 | 0 | return size; |
279 | 0 | } |
280 | | |
281 | | NSSCMSContentInfo * |
282 | | NSS_CMSContent_GetContentInfo(void *msg, SECOidTag type) |
283 | 0 | { |
284 | 0 | NSSCMSContent c; |
285 | 0 | NSSCMSContentInfo *cinfo = NULL; |
286 | 0 |
|
287 | 0 | if (!msg) |
288 | 0 | return cinfo; |
289 | 0 | c.pointer = msg; |
290 | 0 | switch (type) { |
291 | 0 | case SEC_OID_PKCS7_SIGNED_DATA: |
292 | 0 | cinfo = &(c.signedData->contentInfo); |
293 | 0 | break; |
294 | 0 | case SEC_OID_PKCS7_ENVELOPED_DATA: |
295 | 0 | cinfo = &(c.envelopedData->contentInfo); |
296 | 0 | break; |
297 | 0 | case SEC_OID_PKCS7_ENCRYPTED_DATA: |
298 | 0 | cinfo = &(c.encryptedData->contentInfo); |
299 | 0 | break; |
300 | 0 | case SEC_OID_PKCS7_DIGESTED_DATA: |
301 | 0 | cinfo = &(c.digestedData->contentInfo); |
302 | 0 | break; |
303 | 0 | default: |
304 | 0 | cinfo = NULL; |
305 | 0 | if (NSS_CMSType_IsWrapper(type)) { |
306 | 0 | cinfo = &(c.genericData->contentInfo); |
307 | 0 | } |
308 | 0 | } |
309 | 0 | return cinfo; |
310 | 0 | } |
311 | | |
312 | | const char * |
313 | | NSS_CMSUtil_VerificationStatusToString(NSSCMSVerificationStatus vs) |
314 | | { |
315 | | switch (vs) { |
316 | | case NSSCMSVS_Unverified: |
317 | | return "Unverified"; |
318 | | case NSSCMSVS_GoodSignature: |
319 | | return "GoodSignature"; |
320 | | case NSSCMSVS_BadSignature: |
321 | | return "BadSignature"; |
322 | | case NSSCMSVS_DigestMismatch: |
323 | | return "DigestMismatch"; |
324 | | case NSSCMSVS_SigningCertNotFound: |
325 | | return "SigningCertNotFound"; |
326 | | case NSSCMSVS_SigningCertNotTrusted: |
327 | | return "SigningCertNotTrusted"; |
328 | | case NSSCMSVS_SignatureAlgorithmUnknown: |
329 | | return "SignatureAlgorithmUnknown"; |
330 | | case NSSCMSVS_SignatureAlgorithmUnsupported: |
331 | | return "SignatureAlgorithmUnsupported"; |
332 | | case NSSCMSVS_MalformedSignature: |
333 | | return "MalformedSignature"; |
334 | | case NSSCMSVS_ProcessingError: |
335 | | return "ProcessingError"; |
336 | | default: |
337 | | return "Unknown"; |
338 | | } |
339 | | } |
340 | | |
341 | | SECStatus |
342 | | NSS_CMSDEREncode(NSSCMSMessage *cmsg, SECItem *input, SECItem *derOut, |
343 | | PLArenaPool *arena) |
344 | 0 | { |
345 | 0 | NSSCMSEncoderContext *ecx; |
346 | 0 | SECStatus rv = SECSuccess; |
347 | 0 | if (!cmsg || !derOut || !arena) { |
348 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
349 | 0 | return SECFailure; |
350 | 0 | } |
351 | 0 | ecx = NSS_CMSEncoder_Start(cmsg, 0, 0, derOut, arena, 0, 0, 0, 0, 0, 0); |
352 | 0 | if (!ecx) { |
353 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
354 | 0 | return SECFailure; |
355 | 0 | } |
356 | 0 | if (input) { |
357 | 0 | rv = NSS_CMSEncoder_Update(ecx, (const char *)input->data, input->len); |
358 | 0 | if (rv) { |
359 | 0 | PORT_SetError(SEC_ERROR_BAD_DATA); |
360 | 0 | } |
361 | 0 | } |
362 | 0 | rv |= NSS_CMSEncoder_Finish(ecx); |
363 | 0 | if (rv) { |
364 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
365 | 0 | } |
366 | 0 | return rv; |
367 | 0 | } |