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