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
; 
 325     return encalg
;              /* maybe it is already the right algid */ 
 328 const SecAsn1Template 
* 
 329 SecCmsUtilGetTemplateByTypeTag(SECOidTag type
) 
 331     const SecAsn1Template 
*template; 
 332     extern const SecAsn1Template SecCmsSignedDataTemplate
[]; 
 333     extern const SecAsn1Template SecCmsEnvelopedDataTemplate
[]; 
 334     extern const SecAsn1Template SecCmsEncryptedDataTemplate
[]; 
 335     extern const SecAsn1Template SecCmsDigestedDataTemplate
[]; 
 338     case SEC_OID_PKCS7_SIGNED_DATA
: 
 339         template = SecCmsSignedDataTemplate
; 
 341     case SEC_OID_PKCS7_ENVELOPED_DATA
: 
 342         template = SecCmsEnvelopedDataTemplate
; 
 344     case SEC_OID_PKCS7_ENCRYPTED_DATA
: 
 345         template = SecCmsEncryptedDataTemplate
; 
 347     case SEC_OID_PKCS7_DIGESTED_DATA
: 
 348         template = SecCmsDigestedDataTemplate
; 
 351     case SEC_OID_PKCS7_DATA
: 
 359 SecCmsUtilGetSizeByTypeTag(SECOidTag type
) 
 364     case SEC_OID_PKCS7_SIGNED_DATA
: 
 365         size 
= sizeof(SecCmsSignedData
); 
 367     case SEC_OID_PKCS7_ENVELOPED_DATA
: 
 368         size 
= sizeof(SecCmsEnvelopedData
); 
 370     case SEC_OID_PKCS7_ENCRYPTED_DATA
: 
 371         size 
= sizeof(SecCmsEncryptedData
); 
 373     case SEC_OID_PKCS7_DIGESTED_DATA
: 
 374         size 
= sizeof(SecCmsDigestedData
); 
 377     case SEC_OID_PKCS7_DATA
: 
 385 SecCmsContentGetContentInfo(void *msg
, SECOidTag type
) 
 388     SecCmsContentInfoRef cinfo
; 
 394     case SEC_OID_PKCS7_SIGNED_DATA
: 
 395         cinfo 
= &(c
.signedData
->contentInfo
); 
 397     case SEC_OID_PKCS7_ENVELOPED_DATA
: 
 398         cinfo 
= &(c
.envelopedData
->contentInfo
); 
 400     case SEC_OID_PKCS7_ENCRYPTED_DATA
: 
 401         cinfo 
= &(c
.encryptedData
->contentInfo
); 
 403     case SEC_OID_PKCS7_DIGESTED_DATA
: 
 404         cinfo 
= &(c
.digestedData
->contentInfo
); 
 412 // @@@ Return CFStringRef and do localization. 
 414 SecCmsUtilVerificationStatusToString(SecCmsVerificationStatus vs
) 
 417     case SecCmsVSUnverified
:                    return "Unverified"; 
 418     case SecCmsVSGoodSignature
:                 return "GoodSignature"; 
 419     case SecCmsVSBadSignature
:                  return "BadSignature"; 
 420     case SecCmsVSDigestMismatch
:                return "DigestMismatch"; 
 421     case SecCmsVSSigningCertNotFound
:           return "SigningCertNotFound"; 
 422     case SecCmsVSSigningCertNotTrusted
:         return "SigningCertNotTrusted"; 
 423     case SecCmsVSSignatureAlgorithmUnknown
:     return "SignatureAlgorithmUnknown"; 
 424     case SecCmsVSSignatureAlgorithmUnsupported
: return "SignatureAlgorithmUnsupported"; 
 425     case SecCmsVSMalformedSignature
:            return "MalformedSignature"; 
 426     case SecCmsVSProcessingError
:               return "ProcessingError"; 
 427     default:                                    return "Unknown";