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