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