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/
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.
12 * The Original Code is the Netscape security libraries.
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
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
35 * CMS miscellaneous utility functions.
38 #include <Security/SecCmsEncoder.h> /* @@@ Remove this when we move the Encoder method. */
39 #include <Security/SecCmsSignerInfo.h>
43 #include "SecAsn1Item.h"
47 #include <security_asn1/secasn1.h>
48 #include <security_asn1/secerr.h>
49 #include <security_asn1/secport.h>
52 #include <Security/cssmapi.h>
53 #include <Security/cssmapple.h>
54 #include <Security/SecBase.h>
57 #include <CommonCrypto/CommonDigest.h>
58 #include <Security/SecBase.h>
64 * SecCmsArraySortByDER - sort array of objects by objects' DER encoding
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).
71 SecCmsArraySortByDER(void **objs
, const SecAsn1Template
*objtemplate
, void **objs2
)
75 SecAsn1Item
**enc_objs
;
76 OSStatus rv
= SECFailure
;
79 if (objs
== NULL
) /* already sorted */
82 num_objs
= SecCmsArrayCount((void **)objs
);
83 if (num_objs
== 0 || num_objs
== 1) /* already sorted. */
86 poolp
= PORT_NewArena (1024); /* arena for temporaries */
88 return SECFailure
; /* no memory; nothing we can do... */
91 * Allocate arrays to hold the individual encodings which we will use
92 * for comparisons and the reordered attributes as they are sorted.
94 // Security check to prevent under-allocation
95 if (num_objs
<0 || num_objs
>=(int)((INT_MAX
/sizeof(SecAsn1Item
*))-1)) {
98 enc_objs
= (SecAsn1Item
**)PORT_ArenaZAlloc(poolp
, (num_objs
+ 1) * sizeof(SecAsn1Item
*));
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
)
108 enc_objs
[num_objs
] = NULL
;
110 /* now compare and sort objs by the order of enc_objs */
111 SecCmsArraySort((void **)enc_objs
, SecCmsUtilDERCompare
, objs
, objs2
);
116 PORT_FreeArena (poolp
, PR_FALSE
);
121 * SecCmsUtilDERCompare - for use with SecCmsArraySort to
122 * sort arrays of SecAsn1Items containing DER
125 SecCmsUtilDERCompare(void *a
, void *b
)
127 SecAsn1Item
* der1
= (SecAsn1Item
*)a
;
128 SecAsn1Item
* der2
= (SecAsn1Item
*)b
;
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
141 if (der1
->Length
!= der2
->Length
)
142 return (der1
->Length
< der2
->Length
) ? -1 : 1;
145 return memcmp(der1
->Data
, der2
->Data
, der1
->Length
);
148 for (j
= 0; j
< der1
->Length
; j
++) {
149 if (der1
->Data
[j
] == der2
->Data
[j
])
151 return (der1
->Data
[j
] < der2
->Data
[j
]) ? -1 : 1;
158 * SecCmsAlgArrayGetIndexByAlgID - find a specific algorithm in an array of
161 * algorithmArray - array of algorithm IDs
162 * algid - algorithmid of algorithm to pick
165 * An integer containing the index of the algorithm in the array or -1 if
166 * algorithm was not found.
169 SecCmsAlgArrayGetIndexByAlgID(SECAlgorithmID
**algorithmArray
, SECAlgorithmID
*algid
)
173 if (algorithmArray
== NULL
|| algorithmArray
[0] == NULL
)
176 for (i
= 0; algorithmArray
[i
] != NULL
; i
++) {
177 if (SECOID_CompareAlgorithmID(algorithmArray
[i
], algid
) == SECEqual
)
181 if (algorithmArray
[i
] == NULL
)
182 return -1; /* not found */
188 * SecCmsAlgArrayGetIndexByAlgTag - find a specific algorithm in an array of
191 * algorithmArray - array of algorithm IDs
192 * algtag - algorithm tag of algorithm to pick
195 * An integer containing the index of the algorithm in the array or -1 if
196 * algorithm was not found.
199 SecCmsAlgArrayGetIndexByAlgTag(SECAlgorithmID
**algorithmArray
,
205 if (algorithmArray
== NULL
|| algorithmArray
[0] == NULL
)
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
)
215 algid
= SECOID_FindOIDByTag(algtag
);
218 for (i
= 0; algorithmArray
[i
] != NULL
; i
++) {
219 if (SECITEM_ItemsAreEqual(&algorithmArray
[i
]->algorithm
, &algid
->oid
))
224 if (algorithmArray
[i
] == NULL
)
225 return -1; /* not found */
235 SecCmsUtilGetHashObjByAlgID(SECAlgorithmID
*algid
)
237 SECOidData
*oidData
= SECOID_FindOID(&(algid
->algorithm
));
241 CSSM_ALGORITHMS alg
= oidData
->cssmAlgorithm
;
244 CSSM_CC_HANDLE digobj
;
245 CSSM_CSP_HANDLE cspHandle
= SecCspHandleForAlgorithm(alg
);
247 if (!CSSM_CSP_CreateDigestContext(cspHandle
, alg
, &digobj
))
252 switch (oidData
->offset
) {
254 digobj
= calloc(1, sizeof(CC_SHA1_CTX
));
255 CC_SHA1_Init(digobj
);
258 digobj
= calloc(1, sizeof(CC_MD5_CTX
));
262 digobj
= calloc(1, sizeof(CC_SHA256_CTX
));
263 CC_SHA224_Init(digobj
);
266 digobj
= calloc(1, sizeof(CC_SHA256_CTX
));
267 CC_SHA256_Init(digobj
);
270 digobj
= calloc(1, sizeof(CC_SHA512_CTX
));
271 CC_SHA384_Init(digobj
);
274 digobj
= calloc(1, sizeof(CC_SHA512_CTX
));
275 CC_SHA512_Init(digobj
);
288 * XXX I would *really* like to not have to do this, but the current
289 * signing interface gives me little choice.
292 SecCmsUtilMakeSignatureAlgorithm(SECOidTag hashalg
, SECOidTag encalg
)
295 case SEC_OID_PKCS1_RSA_ENCRYPTION
:
298 return SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION
;
300 return SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION
;
302 return SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION
;
304 return SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION
;
306 return SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION
;
308 return SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION
;
310 return SEC_OID_UNKNOWN
;
312 case SEC_OID_ANSIX9_DSA_SIGNATURE
:
313 case SEC_OID_MISSI_KEA_DSS
:
314 case SEC_OID_MISSI_DSS
:
317 return SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST
;
319 return SEC_OID_UNKNOWN
;
321 case SEC_OID_EC_PUBLIC_KEY
:
324 * Note this is only used when signing and verifying signed attributes,
325 * In which case we really do want the combined ECDSA_WithSHA1 alg...
328 return SEC_OID_ECDSA_WithSHA1
;
330 return SEC_OID_ECDSA_WITH_SHA256
;
332 return SEC_OID_ECDSA_WITH_SHA384
;
334 return SEC_OID_ECDSA_WITH_SHA512
;
336 return SEC_OID_UNKNOWN
;
342 return encalg
; /* maybe it is already the right algid */
345 const SecAsn1Template
*
346 SecCmsUtilGetTemplateByTypeTag(SECOidTag type
)
348 const SecAsn1Template
*template;
349 extern const SecAsn1Template SecCmsSignedDataTemplate
[];
350 extern const SecAsn1Template SecCmsEnvelopedDataTemplate
[];
351 extern const SecAsn1Template SecCmsEncryptedDataTemplate
[];
352 extern const SecAsn1Template SecCmsDigestedDataTemplate
[];
355 case SEC_OID_PKCS7_SIGNED_DATA
:
356 template = SecCmsSignedDataTemplate
;
358 case SEC_OID_PKCS7_ENVELOPED_DATA
:
359 template = SecCmsEnvelopedDataTemplate
;
361 case SEC_OID_PKCS7_ENCRYPTED_DATA
:
362 template = SecCmsEncryptedDataTemplate
;
364 case SEC_OID_PKCS7_DIGESTED_DATA
:
365 template = SecCmsDigestedDataTemplate
;
368 case SEC_OID_PKCS7_DATA
:
376 SecCmsUtilGetSizeByTypeTag(SECOidTag type
)
381 case SEC_OID_PKCS7_SIGNED_DATA
:
382 size
= sizeof(SecCmsSignedData
);
384 case SEC_OID_PKCS7_ENVELOPED_DATA
:
385 size
= sizeof(SecCmsEnvelopedData
);
387 case SEC_OID_PKCS7_ENCRYPTED_DATA
:
388 size
= sizeof(SecCmsEncryptedData
);
390 case SEC_OID_PKCS7_DIGESTED_DATA
:
391 size
= sizeof(SecCmsDigestedData
);
394 case SEC_OID_PKCS7_DATA
:
402 SecCmsContentGetContentInfo(void *msg
, SECOidTag type
)
405 SecCmsContentInfoRef cinfo
;
411 case SEC_OID_PKCS7_SIGNED_DATA
:
412 cinfo
= &(c
.signedData
->contentInfo
);
414 case SEC_OID_PKCS7_ENVELOPED_DATA
:
415 cinfo
= &(c
.envelopedData
->contentInfo
);
417 case SEC_OID_PKCS7_ENCRYPTED_DATA
:
418 cinfo
= &(c
.encryptedData
->contentInfo
);
420 case SEC_OID_PKCS7_DIGESTED_DATA
:
421 cinfo
= &(c
.digestedData
->contentInfo
);
429 // @@@ Return CFStringRef and do localization.
431 SecCmsUtilVerificationStatusToString(SecCmsVerificationStatus vs
)
434 case SecCmsVSUnverified
: return "Unverified";
435 case SecCmsVSGoodSignature
: return "GoodSignature";
436 case SecCmsVSBadSignature
: return "BadSignature";
437 case SecCmsVSDigestMismatch
: return "DigestMismatch";
438 case SecCmsVSSigningCertNotFound
: return "SigningCertNotFound";
439 case SecCmsVSSigningCertNotTrusted
: return "SigningCertNotTrusted";
440 case SecCmsVSSignatureAlgorithmUnknown
: return "SignatureAlgorithmUnknown";
441 case SecCmsVSSignatureAlgorithmUnsupported
: return "SignatureAlgorithmUnsupported";
442 case SecCmsVSMalformedSignature
: return "MalformedSignature";
443 case SecCmsVSProcessingError
: return "ProcessingError";
444 default: return "Unknown";