security/nss/lib/smime/cmsutil.c

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

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

mercurial