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