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 */ 60OSStatus 61SecCmsArraySortByDER(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 101loser: 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 */ 110int 111SecCmsUtilDERCompare(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 */ 150int 151SecCmsAlgArrayGetIndexByAlgID(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 */ 180int 181SecCmsAlgArrayGetIndexByAlgTag(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 212CSSM_CC_HANDLE 213SecCmsUtilGetHashObjByAlgID(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 */ 236SECOidTag 237SecCmsUtilMakeSignatureAlgorithm(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 284const SecAsn1Template * 285SecCmsUtilGetTemplateByTypeTag(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 315size_t 316SecCmsUtilGetSizeByTypeTag(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 341SecCmsContentInfoRef 342SecCmsContentGetContentInfo(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. 370const char * 371SecCmsUtilVerificationStatusToString(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 388OSStatus 389SecArenaPoolCreate(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 404loser: 405 return status; 406} 407 408void 409SecArenaPoolFree(SecArenaPoolRef arena, Boolean zero) 410{ 411 PORT_FreeArena((PLArenaPool *)arena, zero); 412} 413