]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_smime/lib/cmsutil.c
Security-59306.101.1.tar.gz
[apple/security.git] / OSX / libsecurity_smime / lib / cmsutil.c
1 /*
2 * The contents of this file are subject to the Mozilla Public
3 * License Version 1.1 (the "License"); you may not use this file
4 * except in compliance with the License. You may obtain a copy of
5 * the License at http://www.mozilla.org/MPL/
6 *
7 * Software distributed under the License is distributed on an "AS
8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9 * implied. See the License for the specific language governing
10 * rights and limitations under the License.
11 *
12 * The Original Code is the Netscape security libraries.
13 *
14 * The Initial Developer of the Original Code is Netscape
15 * Communications Corporation. Portions created by Netscape are
16 * Copyright (C) 1994-2000 Netscape Communications Corporation. All
17 * Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * Alternatively, the contents of this file may be used under the
22 * terms of the GNU General Public License Version 2 or later (the
23 * "GPL"), in which case the provisions of the GPL are applicable
24 * instead of those above. If you wish to allow use of your
25 * version of this file only under the terms of the GPL and not to
26 * allow others to use your version of this file under the MPL,
27 * indicate your decision by deleting the provisions above and
28 * replace them with the notice and other provisions required by
29 * the GPL. If you do not delete the provisions above, a recipient
30 * may use your version of this file under either the MPL or the
31 * GPL.
32 */
33
34 /*
35 * CMS miscellaneous utility functions.
36 */
37
38 #include <Security/SecCmsEncoder.h> /* @@@ Remove this when we move the Encoder method. */
39 #include <Security/SecCmsSignerInfo.h>
40 #include "cmslocal.h"
41
42 #include "secitem.h"
43 #include "secoid.h"
44 #include "cryptohi.h"
45
46 #include <security_asn1/secasn1.h>
47 #include <security_asn1/secerr.h>
48 #include <Security/cssmapi.h>
49 #include <Security/cssmapple.h>
50 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
51 #include <CommonCrypto/CommonDigest.h>
52
53
54 /*
55 * SecCmsArraySortByDER - sort array of objects by objects' DER encoding
56 *
57 * make sure that the order of the objects guarantees valid DER (which must be
58 * in lexigraphically ascending order for a SET OF); if reordering is necessary it
59 * will be done in place (in objs).
60 */
61 OSStatus
62 SecCmsArraySortByDER(void **objs, const SecAsn1Template *objtemplate, void **objs2)
63 {
64 PRArenaPool *poolp;
65 int num_objs;
66 CSSM_DATA_PTR *enc_objs;
67 OSStatus rv = SECFailure;
68 int i;
69
70 if (objs == NULL) /* already sorted */
71 return SECSuccess;
72
73 num_objs = SecCmsArrayCount((void **)objs);
74 if (num_objs == 0 || num_objs == 1) /* already sorted. */
75 return SECSuccess;
76
77 poolp = PORT_NewArena (1024); /* arena for temporaries */
78 if (poolp == NULL)
79 return SECFailure; /* no memory; nothing we can do... */
80
81 /*
82 * Allocate arrays to hold the individual encodings which we will use
83 * for comparisons and the reordered attributes as they are sorted.
84 */
85 // Security check to prevent under-allocation
86 if (num_objs<0 || num_objs>=(int)((INT_MAX/sizeof(CSSM_DATA_PTR))-1)) {
87 goto loser;
88 }
89 enc_objs = (CSSM_DATA_PTR *)PORT_ArenaZAlloc(poolp, (num_objs + 1) * sizeof(CSSM_DATA_PTR));
90 if (enc_objs == NULL)
91 goto loser;
92
93 /* DER encode each individual object. */
94 for (i = 0; i < num_objs; i++) {
95 enc_objs[i] = SEC_ASN1EncodeItem(poolp, NULL, objs[i], objtemplate);
96 if (enc_objs[i] == NULL)
97 goto loser;
98 }
99 enc_objs[num_objs] = NULL;
100
101 /* now compare and sort objs by the order of enc_objs */
102 SecCmsArraySort((void **)enc_objs, SecCmsUtilDERCompare, objs, objs2);
103
104 rv = SECSuccess;
105
106 loser:
107 PORT_FreeArena (poolp, PR_FALSE);
108 return rv;
109 }
110
111 /*
112 * SecCmsUtilDERCompare - for use with SecCmsArraySort to
113 * sort arrays of CSSM_DATAs containing DER
114 */
115 int
116 SecCmsUtilDERCompare(void *a, void *b)
117 {
118 CSSM_DATA_PTR der1 = (CSSM_DATA_PTR)a;
119 CSSM_DATA_PTR der2 = (CSSM_DATA_PTR)b;
120 int j;
121
122 /*
123 * Find the lowest (lexigraphically) encoding. One that is
124 * shorter than all the rest is known to be "less" because each
125 * attribute is of the same type (a SEQUENCE) and so thus the
126 * first octet of each is the same, and the second octet is
127 * the length (or the length of the length with the high bit
128 * set, followed by the length, which also works out to always
129 * order the shorter first). Two (or more) that have the
130 * same length need to be compared byte by byte until a mismatch
131 * is found.
132 */
133 if (der1->Length != der2->Length)
134 return (der1->Length < der2->Length) ? -1 : 1;
135
136 for (j = 0; j < der1->Length; j++) {
137 if (der1->Data[j] == der2->Data[j])
138 continue;
139 return (der1->Data[j] < der2->Data[j]) ? -1 : 1;
140 }
141 return 0;
142 }
143
144 /*
145 * SecCmsAlgArrayGetIndexByAlgID - find a specific algorithm in an array of
146 * algorithms.
147 *
148 * algorithmArray - array of algorithm IDs
149 * algid - algorithmid of algorithm to pick
150 *
151 * Returns:
152 * An integer containing the index of the algorithm in the array or -1 if
153 * algorithm was not found.
154 */
155 int
156 SecCmsAlgArrayGetIndexByAlgID(SECAlgorithmID **algorithmArray, SECAlgorithmID *algid)
157 {
158 int i;
159
160 if (algorithmArray == NULL || algorithmArray[0] == NULL)
161 return -1;
162
163 for (i = 0; algorithmArray[i] != NULL; i++) {
164 if (SECOID_CompareAlgorithmID(algorithmArray[i], algid) == SECEqual)
165 break; /* bingo */
166 }
167
168 if (algorithmArray[i] == NULL)
169 return -1; /* not found */
170
171 return i;
172 }
173
174 /*
175 * SecCmsAlgArrayGetIndexByAlgTag - find a specific algorithm in an array of
176 * algorithms.
177 *
178 * algorithmArray - array of algorithm IDs
179 * algtag - algorithm tag of algorithm to pick
180 *
181 * Returns:
182 * An integer containing the index of the algorithm in the array or -1 if
183 * algorithm was not found.
184 */
185 int
186 SecCmsAlgArrayGetIndexByAlgTag(SECAlgorithmID **algorithmArray,
187 SECOidTag algtag)
188 {
189 SECOidData *algid;
190 int i = -1;
191
192 if (algorithmArray == NULL || algorithmArray[0] == NULL)
193 return i;
194
195 #ifdef ORDER_N_SQUARED
196 for (i = 0; algorithmArray[i] != NULL; i++) {
197 algid = SECOID_FindOID(&(algorithmArray[i]->algorithm));
198 if (algid->offset == algtag)
199 break; /* bingo */
200 }
201 #else
202 algid = SECOID_FindOIDByTag(algtag);
203 if (!algid)
204 return i;
205 for (i = 0; algorithmArray[i] != NULL; i++) {
206 if (SECITEM_ItemsAreEqual(&algorithmArray[i]->algorithm, &algid->oid))
207 break; /* bingo */
208 }
209 #endif
210
211 if (algorithmArray[i] == NULL)
212 return -1; /* not found */
213
214 return i;
215 }
216
217 void *
218 SecCmsUtilGetHashObjByAlgID(SECAlgorithmID *algid)
219 {
220 SECOidData *oidData = SECOID_FindOID(&(algid->algorithm));
221 if (oidData)
222 {
223 void *digobj = NULL;
224 switch (oidData->offset) {
225 case SEC_OID_SHA1:
226 digobj = calloc(1, sizeof(CC_SHA1_CTX));
227 CC_SHA1_Init(digobj);
228 break;
229 case SEC_OID_MD5:
230 digobj = calloc(1, sizeof(CC_MD5_CTX));
231 CC_MD5_Init(digobj);
232 break;
233 case SEC_OID_SHA224:
234 digobj = calloc(1, sizeof(CC_SHA256_CTX));
235 CC_SHA224_Init(digobj);
236 break;
237 case SEC_OID_SHA256:
238 digobj = calloc(1, sizeof(CC_SHA256_CTX));
239 CC_SHA256_Init(digobj);
240 break;
241 case SEC_OID_SHA384:
242 digobj = calloc(1, sizeof(CC_SHA512_CTX));
243 CC_SHA384_Init(digobj);
244 break;
245 case SEC_OID_SHA512:
246 digobj = calloc(1, sizeof(CC_SHA512_CTX));
247 CC_SHA512_Init(digobj);
248 break;
249 default:
250 break;
251 }
252 return digobj;
253 }
254
255 return 0;
256 }
257
258 /*
259 * XXX I would *really* like to not have to do this, but the current
260 * signing interface gives me little choice.
261 */
262 SECOidTag
263 SecCmsUtilMakeSignatureAlgorithm(SECOidTag hashalg, SECOidTag encalg)
264 {
265 switch (encalg) {
266 case SEC_OID_PKCS1_RSA_ENCRYPTION:
267 switch (hashalg) {
268 case SEC_OID_MD2:
269 return SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION;
270 case SEC_OID_MD5:
271 return SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
272 case SEC_OID_SHA1:
273 return SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
274 case SEC_OID_SHA256:
275 return SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
276 case SEC_OID_SHA384:
277 return SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
278 case SEC_OID_SHA512:
279 return SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
280 default:
281 return SEC_OID_UNKNOWN;
282 }
283 case SEC_OID_ANSIX9_DSA_SIGNATURE:
284 case SEC_OID_MISSI_KEA_DSS:
285 case SEC_OID_MISSI_DSS:
286 switch (hashalg) {
287 case SEC_OID_SHA1:
288 return SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
289 default:
290 return SEC_OID_UNKNOWN;
291 }
292 case SEC_OID_EC_PUBLIC_KEY:
293 switch(hashalg) {
294 /*
295 * Note this is only used when signing and verifying signed attributes,
296 * In which case we really do want the combined ECDSA_WithSHA1 alg...
297 */
298 case SEC_OID_SHA1:
299 return SEC_OID_ECDSA_WithSHA1;
300 case SEC_OID_SHA256:
301 return SEC_OID_ECDSA_WITH_SHA256;
302 case SEC_OID_SHA384:
303 return SEC_OID_ECDSA_WITH_SHA384;
304 case SEC_OID_SHA512:
305 return SEC_OID_ECDSA_WITH_SHA512;
306 default:
307 return SEC_OID_UNKNOWN;
308 }
309 default:
310 break;
311 }
312
313 return encalg; /* maybe it is already the right algid */
314 }
315
316 const SecAsn1Template *
317 SecCmsUtilGetTemplateByTypeTag(SECOidTag type)
318 {
319 const SecAsn1Template *template;
320 extern const SecAsn1Template SecCmsSignedDataTemplate[];
321 extern const SecAsn1Template SecCmsEnvelopedDataTemplate[];
322 extern const SecAsn1Template SecCmsEncryptedDataTemplate[];
323 extern const SecAsn1Template SecCmsDigestedDataTemplate[];
324
325 switch (type) {
326 case SEC_OID_PKCS7_SIGNED_DATA:
327 template = SecCmsSignedDataTemplate;
328 break;
329 case SEC_OID_PKCS7_ENVELOPED_DATA:
330 template = SecCmsEnvelopedDataTemplate;
331 break;
332 case SEC_OID_PKCS7_ENCRYPTED_DATA:
333 template = SecCmsEncryptedDataTemplate;
334 break;
335 case SEC_OID_PKCS7_DIGESTED_DATA:
336 template = SecCmsDigestedDataTemplate;
337 break;
338 default:
339 case SEC_OID_PKCS7_DATA:
340 case SEC_OID_OTHER:
341 template = NULL;
342 break;
343 }
344 return template;
345 }
346
347 size_t
348 SecCmsUtilGetSizeByTypeTag(SECOidTag type)
349 {
350 size_t size;
351
352 switch (type) {
353 case SEC_OID_PKCS7_SIGNED_DATA:
354 size = sizeof(SecCmsSignedData);
355 break;
356 case SEC_OID_PKCS7_ENVELOPED_DATA:
357 size = sizeof(SecCmsEnvelopedData);
358 break;
359 case SEC_OID_PKCS7_ENCRYPTED_DATA:
360 size = sizeof(SecCmsEncryptedData);
361 break;
362 case SEC_OID_PKCS7_DIGESTED_DATA:
363 size = sizeof(SecCmsDigestedData);
364 break;
365 default:
366 case SEC_OID_PKCS7_DATA:
367 size = 0;
368 break;
369 }
370 return size;
371 }
372
373 SecCmsContentInfoRef
374 SecCmsContentGetContentInfo(void *msg, SECOidTag type)
375 {
376 SecCmsContent c;
377 SecCmsContentInfoRef cinfo;
378
379 if (!msg)
380 return NULL;
381 c.pointer = msg;
382 switch (type) {
383 case SEC_OID_PKCS7_SIGNED_DATA:
384 cinfo = &(c.signedData->contentInfo);
385 break;
386 case SEC_OID_PKCS7_ENVELOPED_DATA:
387 cinfo = &(c.envelopedData->contentInfo);
388 break;
389 case SEC_OID_PKCS7_ENCRYPTED_DATA:
390 cinfo = &(c.encryptedData->contentInfo);
391 break;
392 case SEC_OID_PKCS7_DIGESTED_DATA:
393 cinfo = &(c.digestedData->contentInfo);
394 break;
395 default:
396 cinfo = NULL;
397 }
398 return cinfo;
399 }
400
401 // @@@ Return CFStringRef and do localization.
402 const char *
403 SecCmsUtilVerificationStatusToString(SecCmsVerificationStatus vs)
404 {
405 switch (vs) {
406 case SecCmsVSUnverified: return "Unverified";
407 case SecCmsVSGoodSignature: return "GoodSignature";
408 case SecCmsVSBadSignature: return "BadSignature";
409 case SecCmsVSDigestMismatch: return "DigestMismatch";
410 case SecCmsVSSigningCertNotFound: return "SigningCertNotFound";
411 case SecCmsVSSigningCertNotTrusted: return "SigningCertNotTrusted";
412 case SecCmsVSSignatureAlgorithmUnknown: return "SignatureAlgorithmUnknown";
413 case SecCmsVSSignatureAlgorithmUnsupported: return "SignatureAlgorithmUnsupported";
414 case SecCmsVSMalformedSignature: return "MalformedSignature";
415 case SecCmsVSProcessingError: return "ProcessingError";
416 default: return "Unknown";
417 }
418 }
419
420 OSStatus
421 SecArenaPoolCreate(size_t chunksize, SecArenaPoolRef *outArena)
422 {
423 OSStatus status;
424
425 if (!outArena) {
426 status = paramErr;
427 goto loser;
428 }
429
430 *outArena = (SecArenaPoolRef)PORT_NewArena(chunksize);
431 if (*outArena)
432 status = 0;
433 else
434 status = PORT_GetError();
435
436 loser:
437 return status;
438 }
439
440 void
441 SecArenaPoolFree(SecArenaPoolRef arena, Boolean zero)
442 {
443 PORT_FreeArena((PLArenaPool *)arena, zero);
444 }