Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
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/. */
5 /*
6 * CMS miscellaneous utility functions.
7 */
9 #include "cmslocal.h"
11 #include "cert.h"
12 #include "key.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"
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 {
30 PLArenaPool *poolp;
31 int num_objs;
32 SECItem **enc_objs;
33 SECStatus rv = SECFailure;
34 int i;
36 if (objs == NULL) /* already sorted */
37 return SECSuccess;
39 num_objs = NSS_CMSArray_Count((void **)objs);
40 if (num_objs == 0 || num_objs == 1) /* already sorted. */
41 return SECSuccess;
43 poolp = PORT_NewArena (1024); /* arena for temporaries */
44 if (poolp == NULL)
45 return SECFailure; /* no memory; nothing we can do... */
47 /*
48 * Allocate arrays to hold the individual encodings which we will use
49 * for comparisons and the reordered attributes as they are sorted.
50 */
51 enc_objs = (SECItem **)PORT_ArenaZAlloc(poolp, (num_objs + 1) * sizeof(SECItem *));
52 if (enc_objs == NULL)
53 goto loser;
55 /* DER encode each individual object. */
56 for (i = 0; i < num_objs; i++) {
57 enc_objs[i] = SEC_ASN1EncodeItem(poolp, NULL, objs[i], objtemplate);
58 if (enc_objs[i] == NULL)
59 goto loser;
60 }
61 enc_objs[num_objs] = NULL;
63 /* now compare and sort objs by the order of enc_objs */
64 NSS_CMSArray_Sort((void **)enc_objs, NSS_CMSUtil_DERCompare, objs, objs2);
66 rv = SECSuccess;
68 loser:
69 PORT_FreeArena (poolp, PR_FALSE);
70 return rv;
71 }
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 {
80 SECItem *der1 = (SECItem *)a;
81 SECItem *der2 = (SECItem *)b;
82 unsigned int j;
84 /*
85 * Find the lowest (lexigraphically) encoding. One that is
86 * shorter than all the rest is known to be "less" because each
87 * attribute is of the same type (a SEQUENCE) and so thus the
88 * first octet of each is the same, and the second octet is
89 * the length (or the length of the length with the high bit
90 * set, followed by the length, which also works out to always
91 * order the shorter first). Two (or more) that have the
92 * same length need to be compared byte by byte until a mismatch
93 * is found.
94 */
95 if (der1->len != der2->len)
96 return (der1->len < der2->len) ? -1 : 1;
98 for (j = 0; j < der1->len; j++) {
99 if (der1->data[j] == der2->data[j])
100 continue;
101 return (der1->data[j] < der2->data[j]) ? -1 : 1;
102 }
103 return 0;
104 }
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 {
120 int i;
122 if (algorithmArray == NULL || algorithmArray[0] == NULL)
123 return -1;
125 for (i = 0; algorithmArray[i] != NULL; i++) {
126 if (SECOID_CompareAlgorithmID(algorithmArray[i], algid) == SECEqual)
127 break; /* bingo */
128 }
130 if (algorithmArray[i] == NULL)
131 return -1; /* not found */
133 return i;
134 }
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 {
151 SECOidData *algid;
152 int i = -1;
154 if (algorithmArray == NULL || algorithmArray[0] == NULL)
155 return i;
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 algid = SECOID_FindOIDByTag(algtag);
165 if (!algid)
166 return i;
167 for (i = 0; algorithmArray[i] != NULL; i++) {
168 if (SECITEM_ItemsAreEqual(&algorithmArray[i]->algorithm, &algid->oid))
169 break; /* bingo */
170 }
171 #endif
173 if (algorithmArray[i] == NULL)
174 return -1; /* not found */
176 return i;
177 }
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 {
187 switch (signAlg) {
188 case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
189 return SEC_OID_MD2;
190 break;
191 case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
192 return SEC_OID_MD5;
193 break;
194 case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
195 case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
196 case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST:
197 return SEC_OID_SHA1;
198 break;
199 case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
200 case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE:
201 return SEC_OID_SHA256;
202 break;
203 case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
204 case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE:
205 return SEC_OID_SHA384;
206 break;
207 case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
208 case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE:
209 return SEC_OID_SHA512;
210 break;
211 default:
212 break;
213 }
214 /* not one of the algtags incorrectly sent to us*/
215 return signAlg;
216 }
218 const SECHashObject *
219 NSS_CMSUtil_GetHashObjByAlgID(SECAlgorithmID *algid)
220 {
221 SECOidTag oidTag = SECOID_FindOIDTag(&(algid->algorithm));
222 const SECHashObject *digobj = HASH_GetHashObjectByOidTag(oidTag);
224 return digobj;
225 }
227 const SEC_ASN1Template *
228 NSS_CMSUtil_GetTemplateByTypeTag(SECOidTag type)
229 {
230 const SEC_ASN1Template *template;
231 extern const SEC_ASN1Template NSSCMSSignedDataTemplate[];
232 extern const SEC_ASN1Template NSSCMSEnvelopedDataTemplate[];
233 extern const SEC_ASN1Template NSSCMSEncryptedDataTemplate[];
234 extern const SEC_ASN1Template NSSCMSDigestedDataTemplate[];
236 switch (type) {
237 case SEC_OID_PKCS7_SIGNED_DATA:
238 template = NSSCMSSignedDataTemplate;
239 break;
240 case SEC_OID_PKCS7_ENVELOPED_DATA:
241 template = NSSCMSEnvelopedDataTemplate;
242 break;
243 case SEC_OID_PKCS7_ENCRYPTED_DATA:
244 template = NSSCMSEncryptedDataTemplate;
245 break;
246 case SEC_OID_PKCS7_DIGESTED_DATA:
247 template = NSSCMSDigestedDataTemplate;
248 break;
249 default:
250 template = NSS_CMSType_GetTemplate(type);
251 break;
252 }
253 return template;
254 }
256 size_t
257 NSS_CMSUtil_GetSizeByTypeTag(SECOidTag type)
258 {
259 size_t size;
261 switch (type) {
262 case SEC_OID_PKCS7_SIGNED_DATA:
263 size = sizeof(NSSCMSSignedData);
264 break;
265 case SEC_OID_PKCS7_ENVELOPED_DATA:
266 size = sizeof(NSSCMSEnvelopedData);
267 break;
268 case SEC_OID_PKCS7_ENCRYPTED_DATA:
269 size = sizeof(NSSCMSEncryptedData);
270 break;
271 case SEC_OID_PKCS7_DIGESTED_DATA:
272 size = sizeof(NSSCMSDigestedData);
273 break;
274 default:
275 size = NSS_CMSType_GetContentSize(type);
276 break;
277 }
278 return size;
279 }
281 NSSCMSContentInfo *
282 NSS_CMSContent_GetContentInfo(void *msg, SECOidTag type)
283 {
284 NSSCMSContent c;
285 NSSCMSContentInfo *cinfo = NULL;
287 if (!msg)
288 return cinfo;
289 c.pointer = msg;
290 switch (type) {
291 case SEC_OID_PKCS7_SIGNED_DATA:
292 cinfo = &(c.signedData->contentInfo);
293 break;
294 case SEC_OID_PKCS7_ENVELOPED_DATA:
295 cinfo = &(c.envelopedData->contentInfo);
296 break;
297 case SEC_OID_PKCS7_ENCRYPTED_DATA:
298 cinfo = &(c.encryptedData->contentInfo);
299 break;
300 case SEC_OID_PKCS7_DIGESTED_DATA:
301 cinfo = &(c.digestedData->contentInfo);
302 break;
303 default:
304 cinfo = NULL;
305 if (NSS_CMSType_IsWrapper(type)) {
306 cinfo = &(c.genericData->contentInfo);
307 }
308 }
309 return cinfo;
310 }
312 const char *
313 NSS_CMSUtil_VerificationStatusToString(NSSCMSVerificationStatus vs)
314 {
315 switch (vs) {
316 case NSSCMSVS_Unverified: return "Unverified";
317 case NSSCMSVS_GoodSignature: return "GoodSignature";
318 case NSSCMSVS_BadSignature: return "BadSignature";
319 case NSSCMSVS_DigestMismatch: return "DigestMismatch";
320 case NSSCMSVS_SigningCertNotFound: return "SigningCertNotFound";
321 case NSSCMSVS_SigningCertNotTrusted: return "SigningCertNotTrusted";
322 case NSSCMSVS_SignatureAlgorithmUnknown: return "SignatureAlgorithmUnknown";
323 case NSSCMSVS_SignatureAlgorithmUnsupported: return "SignatureAlgorithmUnsupported";
324 case NSSCMSVS_MalformedSignature: return "MalformedSignature";
325 case NSSCMSVS_ProcessingError: return "ProcessingError";
326 default: return "Unknown";
327 }
328 }
330 SECStatus
331 NSS_CMSDEREncode(NSSCMSMessage *cmsg, SECItem *input, SECItem *derOut,
332 PLArenaPool *arena)
333 {
334 NSSCMSEncoderContext *ecx;
335 SECStatus rv = SECSuccess;
336 if (!cmsg || !derOut || !arena) {
337 PORT_SetError(SEC_ERROR_INVALID_ARGS);
338 return SECFailure;
339 }
340 ecx = NSS_CMSEncoder_Start(cmsg, 0, 0, derOut, arena, 0, 0, 0, 0, 0, 0);
341 if (!ecx) {
342 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
343 return SECFailure;
344 }
345 if (input) {
346 rv = NSS_CMSEncoder_Update(ecx, (const char*)input->data, input->len);
347 if (rv) {
348 PORT_SetError(SEC_ERROR_BAD_DATA);
349 }
350 }
351 rv |= NSS_CMSEncoder_Finish(ecx);
352 if (rv) {
353 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
354 }
355 return rv;
356 }