cmsutil.c (10940B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 /* 6 * CMS miscellaneous utility functions. 7 */ 8 9 #include "cmslocal.h" 10 11 #include "cert.h" 12 #include "keyhi.h" 13 #include "secasn1.h" 14 #include "secitem.h" 15 #include "secoid.h" 16 #include "pk11func.h" 17 #include "secerr.h" 18 #include "sechash.h" 19 20 /* 21 * NSS_CMSArray_SortByDER - sort array of objects by objects' DER encoding 22 * 23 * make sure that the order of the objects guarantees valid DER (which must be 24 * in lexigraphically ascending order for a SET OF); if reordering is necessary it 25 * will be done in place (in objs). 26 */ 27 SECStatus 28 NSS_CMSArray_SortByDER(void **objs, const SEC_ASN1Template *objtemplate, void **objs2) 29 { 30 PLArenaPool *poolp; 31 int num_objs; 32 SECItem **enc_objs; 33 SECStatus rv = SECFailure; 34 int i; 35 36 if (objs == NULL) /* already sorted */ 37 return SECSuccess; 38 39 num_objs = NSS_CMSArray_Count((void **)objs); 40 if (num_objs == 0 || num_objs == 1) /* already sorted. */ 41 return SECSuccess; 42 43 poolp = PORT_NewArena(1024); /* arena for temporaries */ 44 if (poolp == NULL) 45 return SECFailure; /* no memory; nothing we can do... */ 46 47 /* 48 * Allocate arrays to hold the individual encodings which we will use 49 * for comparisons and the reordered attributes as they are sorted. 50 */ 51 enc_objs = (SECItem **)PORT_ArenaZAlloc(poolp, (num_objs + 1) * sizeof(SECItem *)); 52 if (enc_objs == NULL) 53 goto loser; 54 55 /* DER encode each individual object. */ 56 for (i = 0; i < num_objs; i++) { 57 enc_objs[i] = SEC_ASN1EncodeItem(poolp, NULL, objs[i], objtemplate); 58 if (enc_objs[i] == NULL) 59 goto loser; 60 } 61 enc_objs[num_objs] = NULL; 62 63 /* now compare and sort objs by the order of enc_objs */ 64 NSS_CMSArray_Sort((void **)enc_objs, NSS_CMSUtil_DERCompare, objs, objs2); 65 66 rv = SECSuccess; 67 68 loser: 69 PORT_FreeArena(poolp, PR_FALSE); 70 return rv; 71 } 72 73 /* 74 * NSS_CMSUtil_DERCompare - for use with NSS_CMSArray_Sort to 75 * sort arrays of SECItems containing DER 76 */ 77 int 78 NSS_CMSUtil_DERCompare(void *a, void *b) 79 { 80 SECItem *der1 = (SECItem *)a; 81 SECItem *der2 = (SECItem *)b; 82 unsigned int j; 83 84 /* 85 * Find the lowest (lexigraphically) encoding. One that is 86 * shorter than all the rest is known to be "less" because each 87 * attribute is of the same type (a SEQUENCE) and so thus the 88 * first octet of each is the same, and the second octet is 89 * the length (or the length of the length with the high bit 90 * set, followed by the length, which also works out to always 91 * order the shorter first). Two (or more) that have the 92 * same length need to be compared byte by byte until a mismatch 93 * is found. 94 */ 95 if (der1->len != der2->len) 96 return (der1->len < der2->len) ? -1 : 1; 97 98 for (j = 0; j < der1->len; j++) { 99 if (der1->data[j] == der2->data[j]) 100 continue; 101 return (der1->data[j] < der2->data[j]) ? -1 : 1; 102 } 103 return 0; 104 } 105 106 /* 107 * NSS_CMSAlgArray_GetIndexByAlgID - find a specific algorithm in an array of 108 * algorithms. 109 * 110 * algorithmArray - array of algorithm IDs 111 * algid - algorithmid of algorithm to pick 112 * 113 * Returns: 114 * An integer containing the index of the algorithm in the array or -1 if 115 * algorithm was not found. 116 */ 117 int 118 NSS_CMSAlgArray_GetIndexByAlgID(SECAlgorithmID **algorithmArray, SECAlgorithmID *algid) 119 { 120 int i; 121 122 if (algorithmArray == NULL || algorithmArray[0] == NULL) 123 return -1; 124 125 for (i = 0; algorithmArray[i] != NULL; i++) { 126 if (SECOID_CompareAlgorithmID(algorithmArray[i], algid) == SECEqual) 127 break; /* bingo */ 128 } 129 130 if (algorithmArray[i] == NULL) 131 return -1; /* not found */ 132 133 return i; 134 } 135 136 /* 137 * NSS_CMSAlgArray_GetIndexByAlgTag - find a specific algorithm in an array of 138 * algorithms. 139 * 140 * algorithmArray - array of algorithm IDs 141 * algtag - algorithm tag of algorithm to pick 142 * 143 * Returns: 144 * An integer containing the index of the algorithm in the array or -1 if 145 * algorithm was not found. 146 */ 147 int 148 NSS_CMSAlgArray_GetIndexByAlgTag(SECAlgorithmID **algorithmArray, 149 SECOidTag algtag) 150 { 151 SECOidData *algid; 152 int i = -1; 153 154 if (algorithmArray == NULL || algorithmArray[0] == NULL) 155 return i; 156 157 #ifdef ORDER_N_SQUARED 158 for (i = 0; algorithmArray[i] != NULL; i++) { 159 algid = SECOID_FindOID(&(algorithmArray[i]->algorithm)); 160 if (algid->offset == algtag) 161 break; /* bingo */ 162 } 163 #else 164 algid = SECOID_FindOIDByTag(algtag); 165 if (!algid) 166 return i; 167 for (i = 0; algorithmArray[i] != NULL; i++) { 168 if (SECITEM_ItemsAreEqual(&algorithmArray[i]->algorithm, &algid->oid)) 169 break; /* bingo */ 170 } 171 #endif 172 173 if (algorithmArray[i] == NULL) 174 return -1; /* not found */ 175 176 return i; 177 } 178 179 /* 180 * Map a sign algorithm to a digest algorithm. 181 * This is used to handle incorrectly formatted packages sent to us 182 * from Windows 2003. 183 */ 184 SECOidTag 185 NSS_CMSUtil_MapSignAlgs(SECOidTag signAlg) 186 { 187 switch (signAlg) { 188 case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: 189 return SEC_OID_MD2; 190 break; 191 case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: 192 return SEC_OID_MD5; 193 break; 194 case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: 195 case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: 196 case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: 197 return SEC_OID_SHA1; 198 break; 199 case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: 200 case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: 201 return SEC_OID_SHA256; 202 break; 203 case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: 204 case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: 205 return SEC_OID_SHA384; 206 break; 207 case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: 208 case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: 209 return SEC_OID_SHA512; 210 break; 211 default: 212 break; 213 } 214 /* not one of the algtags incorrectly sent to us*/ 215 return signAlg; 216 } 217 218 const SECHashObject * 219 NSS_CMSUtil_GetHashObjByAlgID(SECAlgorithmID *algid) 220 { 221 SECOidTag oidTag = SECOID_FindOIDTag(&(algid->algorithm)); 222 const SECHashObject *digobj = HASH_GetHashObjectByOidTag(oidTag); 223 224 return digobj; 225 } 226 227 const SEC_ASN1Template * 228 NSS_CMSUtil_GetTemplateByTypeTag(SECOidTag type) 229 { 230 const SEC_ASN1Template *template; 231 extern const SEC_ASN1Template NSSCMSSignedDataTemplate[]; 232 extern const SEC_ASN1Template NSSCMSEnvelopedDataTemplate[]; 233 extern const SEC_ASN1Template NSSCMSEncryptedDataTemplate[]; 234 extern const SEC_ASN1Template NSSCMSDigestedDataTemplate[]; 235 236 switch (type) { 237 case SEC_OID_PKCS7_SIGNED_DATA: 238 template = NSSCMSSignedDataTemplate; 239 break; 240 case SEC_OID_PKCS7_ENVELOPED_DATA: 241 template = NSSCMSEnvelopedDataTemplate; 242 break; 243 case SEC_OID_PKCS7_ENCRYPTED_DATA: 244 template = NSSCMSEncryptedDataTemplate; 245 break; 246 case SEC_OID_PKCS7_DIGESTED_DATA: 247 template = NSSCMSDigestedDataTemplate; 248 break; 249 default: 250 template = NSS_CMSType_GetTemplate(type); 251 break; 252 } 253 return template; 254 } 255 256 size_t 257 NSS_CMSUtil_GetSizeByTypeTag(SECOidTag type) 258 { 259 size_t size; 260 261 switch (type) { 262 case SEC_OID_PKCS7_SIGNED_DATA: 263 size = sizeof(NSSCMSSignedData); 264 break; 265 case SEC_OID_PKCS7_ENVELOPED_DATA: 266 size = sizeof(NSSCMSEnvelopedData); 267 break; 268 case SEC_OID_PKCS7_ENCRYPTED_DATA: 269 size = sizeof(NSSCMSEncryptedData); 270 break; 271 case SEC_OID_PKCS7_DIGESTED_DATA: 272 size = sizeof(NSSCMSDigestedData); 273 break; 274 default: 275 size = NSS_CMSType_GetContentSize(type); 276 break; 277 } 278 return size; 279 } 280 281 NSSCMSContentInfo * 282 NSS_CMSContent_GetContentInfo(void *msg, SECOidTag type) 283 { 284 NSSCMSContent c; 285 NSSCMSContentInfo *cinfo = NULL; 286 287 if (!msg) 288 return cinfo; 289 c.pointer = msg; 290 switch (type) { 291 case SEC_OID_PKCS7_SIGNED_DATA: 292 cinfo = &(c.signedData->contentInfo); 293 break; 294 case SEC_OID_PKCS7_ENVELOPED_DATA: 295 cinfo = &(c.envelopedData->contentInfo); 296 break; 297 case SEC_OID_PKCS7_ENCRYPTED_DATA: 298 cinfo = &(c.encryptedData->contentInfo); 299 break; 300 case SEC_OID_PKCS7_DIGESTED_DATA: 301 cinfo = &(c.digestedData->contentInfo); 302 break; 303 default: 304 cinfo = NULL; 305 if (NSS_CMSType_IsWrapper(type)) { 306 cinfo = &(c.genericData->contentInfo); 307 } 308 } 309 /* We are using a union as a form of 'safe casting'. This 310 * syntax confuses cppcheck, so tell it it's OK (and any human 311 * who happens along to verify any other scanner warnings) */ 312 /* cppcheck-suppress returnDanglingLifetime */ 313 return cinfo; 314 } 315 316 const char * 317 NSS_CMSUtil_VerificationStatusToString(NSSCMSVerificationStatus vs) 318 { 319 switch (vs) { 320 case NSSCMSVS_Unverified: 321 return "Unverified"; 322 case NSSCMSVS_GoodSignature: 323 return "GoodSignature"; 324 case NSSCMSVS_BadSignature: 325 return "BadSignature"; 326 case NSSCMSVS_DigestMismatch: 327 return "DigestMismatch"; 328 case NSSCMSVS_SigningCertNotFound: 329 return "SigningCertNotFound"; 330 case NSSCMSVS_SigningCertNotTrusted: 331 return "SigningCertNotTrusted"; 332 case NSSCMSVS_SignatureAlgorithmUnknown: 333 return "SignatureAlgorithmUnknown"; 334 case NSSCMSVS_SignatureAlgorithmUnsupported: 335 return "SignatureAlgorithmUnsupported"; 336 case NSSCMSVS_MalformedSignature: 337 return "MalformedSignature"; 338 case NSSCMSVS_ProcessingError: 339 return "ProcessingError"; 340 default: 341 return "Unknown"; 342 } 343 } 344 345 SECStatus 346 NSS_CMSDEREncode(NSSCMSMessage *cmsg, SECItem *input, SECItem *derOut, 347 PLArenaPool *arena) 348 { 349 NSSCMSEncoderContext *ecx; 350 SECStatus rv = SECSuccess; 351 if (!cmsg || !derOut || !arena) { 352 PORT_SetError(SEC_ERROR_INVALID_ARGS); 353 return SECFailure; 354 } 355 ecx = NSS_CMSEncoder_Start(cmsg, 0, 0, derOut, arena, 0, 0, 0, 0, 0, 0); 356 if (!ecx) { 357 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 358 return SECFailure; 359 } 360 if (input) { 361 rv = NSS_CMSEncoder_Update(ecx, (const char *)input->data, input->len); 362 if (rv) { 363 PORT_SetError(SEC_ERROR_BAD_DATA); 364 } 365 } 366 rv |= NSS_CMSEncoder_Finish(ecx); 367 if (rv) { 368 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 369 } 370 return rv; 371 }