security/nss/lib/smime/cmsudf.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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 User Define Types
michael@0 7 */
michael@0 8
michael@0 9 #include "cmslocal.h"
michael@0 10
michael@0 11 #include "prinit.h"
michael@0 12 #include "pk11func.h"
michael@0 13 #include "secitem.h"
michael@0 14 #include "secoid.h"
michael@0 15 #include "secerr.h"
michael@0 16 #include "nss.h"
michael@0 17
michael@0 18 typedef struct nsscmstypeInfoStr nsscmstypeInfo;
michael@0 19 struct nsscmstypeInfoStr {
michael@0 20 SECOidTag type;
michael@0 21 SEC_ASN1Template *template;
michael@0 22 size_t size;
michael@0 23 PRBool isData;
michael@0 24 NSSCMSGenericWrapperDataDestroy destroy;
michael@0 25 NSSCMSGenericWrapperDataCallback decode_before;
michael@0 26 NSSCMSGenericWrapperDataCallback decode_after;
michael@0 27 NSSCMSGenericWrapperDataCallback decode_end;
michael@0 28 NSSCMSGenericWrapperDataCallback encode_start;
michael@0 29 NSSCMSGenericWrapperDataCallback encode_before;
michael@0 30 NSSCMSGenericWrapperDataCallback encode_after;
michael@0 31 };
michael@0 32
michael@0 33 /* make sure the global tables are only initialized once */
michael@0 34 static PRCallOnceType nsscmstypeOnce;
michael@0 35 static PRCallOnceType nsscmstypeClearOnce;
michael@0 36 /* lock for adding a new entry */
michael@0 37 static PRLock *nsscmstypeAddLock;
michael@0 38 /* lock for the hash table */
michael@0 39 static PRLock *nsscmstypeHashLock;
michael@0 40 /* the hash table itself */
michael@0 41 static PLHashTable *nsscmstypeHash;
michael@0 42 /* arena to hold all the hash table data */
michael@0 43 static PLArenaPool *nsscmstypeArena;
michael@0 44
michael@0 45 /*
michael@0 46 * clean up our global tables
michael@0 47 */
michael@0 48 SECStatus
michael@0 49 nss_cmstype_shutdown(void *appData, void *reserved)
michael@0 50 {
michael@0 51 if (nsscmstypeHashLock) {
michael@0 52 PR_Lock(nsscmstypeHashLock);
michael@0 53 }
michael@0 54 if (nsscmstypeHash) {
michael@0 55 PL_HashTableDestroy(nsscmstypeHash);
michael@0 56 nsscmstypeHash = NULL;
michael@0 57 }
michael@0 58 if (nsscmstypeArena) {
michael@0 59 PORT_FreeArena(nsscmstypeArena, PR_FALSE);
michael@0 60 nsscmstypeArena = NULL;
michael@0 61 }
michael@0 62 if (nsscmstypeAddLock) {
michael@0 63 PR_DestroyLock(nsscmstypeAddLock);
michael@0 64 }
michael@0 65 if (nsscmstypeHashLock) {
michael@0 66 PRLock *oldLock = nsscmstypeHashLock;
michael@0 67 nsscmstypeHashLock = NULL;
michael@0 68 PR_Unlock(oldLock);
michael@0 69 PR_DestroyLock(oldLock);
michael@0 70 }
michael@0 71
michael@0 72 /* don't clear out the PR_ONCE data if we failed our inital call */
michael@0 73 if (appData == NULL) {
michael@0 74 nsscmstypeOnce = nsscmstypeClearOnce;
michael@0 75 }
michael@0 76 return SECSuccess;
michael@0 77 }
michael@0 78
michael@0 79 static PLHashNumber
michael@0 80 nss_cmstype_hash_key(const void *key)
michael@0 81 {
michael@0 82 return (PLHashNumber) key;
michael@0 83 }
michael@0 84
michael@0 85 static PRIntn
michael@0 86 nss_cmstype_compare_keys(const void *v1, const void *v2)
michael@0 87 {
michael@0 88 PLHashNumber value1 = (PLHashNumber) v1;
michael@0 89 PLHashNumber value2 = (PLHashNumber) v2;
michael@0 90
michael@0 91 return (value1 == value2);
michael@0 92 }
michael@0 93
michael@0 94 /*
michael@0 95 * initialize our hash tables, called once on the first attemat to register
michael@0 96 * a new SMIME type.
michael@0 97 */
michael@0 98 static PRStatus
michael@0 99 nss_cmstype_init(void)
michael@0 100 {
michael@0 101 SECStatus rv;
michael@0 102
michael@0 103 nsscmstypeHashLock = PR_NewLock();
michael@0 104 if (nsscmstypeHashLock == NULL) {
michael@0 105 return PR_FAILURE;
michael@0 106 }
michael@0 107 nsscmstypeAddLock = PR_NewLock();
michael@0 108 if (nsscmstypeHashLock == NULL) {
michael@0 109 goto fail;
michael@0 110 }
michael@0 111 nsscmstypeHash = PL_NewHashTable(64, nss_cmstype_hash_key,
michael@0 112 nss_cmstype_compare_keys, PL_CompareValues, NULL, NULL);
michael@0 113 if (nsscmstypeHash == NULL) {
michael@0 114 goto fail;
michael@0 115 }
michael@0 116 nsscmstypeArena = PORT_NewArena(2048);
michael@0 117 if (nsscmstypeArena == NULL) {
michael@0 118 goto fail;
michael@0 119 }
michael@0 120 rv = NSS_RegisterShutdown(nss_cmstype_shutdown, NULL);
michael@0 121 if (rv != SECSuccess) {
michael@0 122 goto fail;
michael@0 123 }
michael@0 124 return PR_SUCCESS;
michael@0 125
michael@0 126 fail:
michael@0 127 nss_cmstype_shutdown(&nsscmstypeOnce, NULL);
michael@0 128 return PR_FAILURE;
michael@0 129 }
michael@0 130
michael@0 131
michael@0 132 /*
michael@0 133 * look up and registered SIME type
michael@0 134 */
michael@0 135 static const nsscmstypeInfo *
michael@0 136 nss_cmstype_lookup(SECOidTag type)
michael@0 137 {
michael@0 138 nsscmstypeInfo *typeInfo = NULL;;
michael@0 139 if (!nsscmstypeHash) {
michael@0 140 return NULL;
michael@0 141 }
michael@0 142 PR_Lock(nsscmstypeHashLock);
michael@0 143 if (nsscmstypeHash) {
michael@0 144 typeInfo = PL_HashTableLookupConst(nsscmstypeHash, (void *)type);
michael@0 145 }
michael@0 146 PR_Unlock(nsscmstypeHashLock);
michael@0 147 return typeInfo;
michael@0 148 }
michael@0 149
michael@0 150 /*
michael@0 151 * add a new type to the SMIME type table
michael@0 152 */
michael@0 153 static SECStatus
michael@0 154 nss_cmstype_add(SECOidTag type, nsscmstypeInfo *typeinfo)
michael@0 155 {
michael@0 156 PLHashEntry *entry;
michael@0 157
michael@0 158 if (!nsscmstypeHash) {
michael@0 159 /* assert? this shouldn't happen */
michael@0 160 return SECFailure;
michael@0 161 }
michael@0 162 PR_Lock(nsscmstypeHashLock);
michael@0 163 /* this is really paranoia. If we really are racing nsscmstypeHash, we'll
michael@0 164 * also be racing nsscmstypeHashLock... */
michael@0 165 if (!nsscmstypeHash) {
michael@0 166 PR_Unlock(nsscmstypeHashLock);
michael@0 167 return SECFailure;
michael@0 168 }
michael@0 169 entry = PL_HashTableAdd(nsscmstypeHash, (void *)type, typeinfo);
michael@0 170 PR_Unlock(nsscmstypeHashLock);
michael@0 171 return entry ? SECSuccess : SECFailure;
michael@0 172 }
michael@0 173
michael@0 174
michael@0 175 /* helper functions to manage new content types
michael@0 176 */
michael@0 177
michael@0 178 PRBool
michael@0 179 NSS_CMSType_IsWrapper(SECOidTag type)
michael@0 180 {
michael@0 181 const nsscmstypeInfo *typeInfo = NULL;
michael@0 182
michael@0 183 switch (type) {
michael@0 184 case SEC_OID_PKCS7_SIGNED_DATA:
michael@0 185 case SEC_OID_PKCS7_ENVELOPED_DATA:
michael@0 186 case SEC_OID_PKCS7_DIGESTED_DATA:
michael@0 187 case SEC_OID_PKCS7_ENCRYPTED_DATA:
michael@0 188 return PR_TRUE;
michael@0 189 default:
michael@0 190 typeInfo = nss_cmstype_lookup(type);
michael@0 191 if (typeInfo && !typeInfo->isData) {
michael@0 192 return PR_TRUE;
michael@0 193 }
michael@0 194 }
michael@0 195 return PR_FALSE;
michael@0 196 }
michael@0 197
michael@0 198 PRBool
michael@0 199 NSS_CMSType_IsData(SECOidTag type)
michael@0 200 {
michael@0 201 const nsscmstypeInfo *typeInfo = NULL;
michael@0 202
michael@0 203 switch (type) {
michael@0 204 case SEC_OID_PKCS7_DATA:
michael@0 205 return PR_TRUE;
michael@0 206 default:
michael@0 207 typeInfo = nss_cmstype_lookup(type);
michael@0 208 if (typeInfo && typeInfo->isData) {
michael@0 209 return PR_TRUE;
michael@0 210 }
michael@0 211 }
michael@0 212 return PR_FALSE;
michael@0 213 }
michael@0 214
michael@0 215 const SEC_ASN1Template *
michael@0 216 NSS_CMSType_GetTemplate(SECOidTag type)
michael@0 217 {
michael@0 218 const nsscmstypeInfo *typeInfo = nss_cmstype_lookup(type);
michael@0 219
michael@0 220 if (typeInfo && typeInfo->template) {
michael@0 221 return typeInfo->template;
michael@0 222 }
michael@0 223 return SEC_ASN1_GET(SEC_PointerToOctetStringTemplate);
michael@0 224 }
michael@0 225
michael@0 226 size_t
michael@0 227 NSS_CMSType_GetContentSize(SECOidTag type)
michael@0 228 {
michael@0 229 const nsscmstypeInfo *typeInfo = nss_cmstype_lookup(type);
michael@0 230
michael@0 231 if (typeInfo) {
michael@0 232 return typeInfo->size;
michael@0 233 }
michael@0 234 return sizeof(SECItem *);
michael@0 235
michael@0 236 }
michael@0 237
michael@0 238 void
michael@0 239 NSS_CMSGenericWrapperData_Destroy(SECOidTag type, NSSCMSGenericWrapperData *gd)
michael@0 240 {
michael@0 241 const nsscmstypeInfo *typeInfo = nss_cmstype_lookup(type);
michael@0 242
michael@0 243 if (typeInfo && typeInfo->destroy) {
michael@0 244 (*typeInfo->destroy)(gd);
michael@0 245 }
michael@0 246
michael@0 247 }
michael@0 248
michael@0 249
michael@0 250 SECStatus
michael@0 251 NSS_CMSGenericWrapperData_Decode_BeforeData(SECOidTag type,
michael@0 252 NSSCMSGenericWrapperData *gd)
michael@0 253 {
michael@0 254 const nsscmstypeInfo *typeInfo;
michael@0 255
michael@0 256 /* short cut common case */
michael@0 257 if (type == SEC_OID_PKCS7_DATA) {
michael@0 258 return SECSuccess;
michael@0 259 }
michael@0 260
michael@0 261 typeInfo = nss_cmstype_lookup(type);
michael@0 262 if (typeInfo) {
michael@0 263 if (typeInfo->decode_before) {
michael@0 264 return (*typeInfo->decode_before)(gd);
michael@0 265 }
michael@0 266 /* decoder ops optional for data tags */
michael@0 267 if (typeInfo->isData) {
michael@0 268 return SECSuccess;
michael@0 269 }
michael@0 270 }
michael@0 271 /* expected a function, but none existed */
michael@0 272 return SECFailure;
michael@0 273
michael@0 274 }
michael@0 275
michael@0 276 SECStatus
michael@0 277 NSS_CMSGenericWrapperData_Decode_AfterData(SECOidTag type,
michael@0 278 NSSCMSGenericWrapperData *gd)
michael@0 279 {
michael@0 280 const nsscmstypeInfo *typeInfo;
michael@0 281
michael@0 282 /* short cut common case */
michael@0 283 if (type == SEC_OID_PKCS7_DATA) {
michael@0 284 return SECSuccess;
michael@0 285 }
michael@0 286
michael@0 287 typeInfo = nss_cmstype_lookup(type);
michael@0 288 if (typeInfo) {
michael@0 289 if (typeInfo->decode_after) {
michael@0 290 return (*typeInfo->decode_after)(gd);
michael@0 291 }
michael@0 292 /* decoder ops optional for data tags */
michael@0 293 if (typeInfo->isData) {
michael@0 294 return SECSuccess;
michael@0 295 }
michael@0 296 }
michael@0 297 /* expected a function, but none existed */
michael@0 298 return SECFailure;
michael@0 299 }
michael@0 300
michael@0 301 SECStatus
michael@0 302 NSS_CMSGenericWrapperData_Decode_AfterEnd(SECOidTag type,
michael@0 303 NSSCMSGenericWrapperData *gd)
michael@0 304 {
michael@0 305 const nsscmstypeInfo *typeInfo;
michael@0 306
michael@0 307 /* short cut common case */
michael@0 308 if (type == SEC_OID_PKCS7_DATA) {
michael@0 309 return SECSuccess;
michael@0 310 }
michael@0 311
michael@0 312 typeInfo = nss_cmstype_lookup(type);
michael@0 313 if (typeInfo) {
michael@0 314 if (typeInfo->decode_end) {
michael@0 315 return (*typeInfo->decode_end)(gd);
michael@0 316 }
michael@0 317 /* decoder ops optional for data tags */
michael@0 318 if (typeInfo->isData) {
michael@0 319 return SECSuccess;
michael@0 320 }
michael@0 321 }
michael@0 322 /* expected a function, but none existed */
michael@0 323 return SECFailure;
michael@0 324 }
michael@0 325
michael@0 326 SECStatus
michael@0 327 NSS_CMSGenericWrapperData_Encode_BeforeStart(SECOidTag type,
michael@0 328 NSSCMSGenericWrapperData *gd)
michael@0 329 {
michael@0 330 const nsscmstypeInfo *typeInfo;
michael@0 331
michael@0 332 /* short cut common case */
michael@0 333 if (type == SEC_OID_PKCS7_DATA) {
michael@0 334 return SECSuccess;
michael@0 335 }
michael@0 336
michael@0 337 typeInfo = nss_cmstype_lookup(type);
michael@0 338 if (typeInfo) {
michael@0 339 if (typeInfo->encode_start) {
michael@0 340 return (*typeInfo->encode_start)(gd);
michael@0 341 }
michael@0 342 /* decoder ops optional for data tags */
michael@0 343 if (typeInfo->isData) {
michael@0 344 return SECSuccess;
michael@0 345 }
michael@0 346 }
michael@0 347 /* expected a function, but none existed */
michael@0 348 return SECFailure;
michael@0 349 }
michael@0 350
michael@0 351 SECStatus
michael@0 352 NSS_CMSGenericWrapperData_Encode_BeforeData(SECOidTag type,
michael@0 353 NSSCMSGenericWrapperData *gd)
michael@0 354 {
michael@0 355 const nsscmstypeInfo *typeInfo;
michael@0 356
michael@0 357 /* short cut common case */
michael@0 358 if (type == SEC_OID_PKCS7_DATA) {
michael@0 359 return SECSuccess;
michael@0 360 }
michael@0 361
michael@0 362 typeInfo = nss_cmstype_lookup(type);
michael@0 363 if (typeInfo) {
michael@0 364 if (typeInfo->encode_before) {
michael@0 365 return (*typeInfo->encode_before)(gd);
michael@0 366 }
michael@0 367 /* decoder ops optional for data tags */
michael@0 368 if (typeInfo->isData) {
michael@0 369 return SECSuccess;
michael@0 370 }
michael@0 371 }
michael@0 372 /* expected a function, but none existed */
michael@0 373 return SECFailure;
michael@0 374 }
michael@0 375
michael@0 376 SECStatus
michael@0 377 NSS_CMSGenericWrapperData_Encode_AfterData(SECOidTag type,
michael@0 378 NSSCMSGenericWrapperData *gd)
michael@0 379 {
michael@0 380 const nsscmstypeInfo *typeInfo;
michael@0 381
michael@0 382 /* short cut common case */
michael@0 383 if (type == SEC_OID_PKCS7_DATA) {
michael@0 384 return SECSuccess;
michael@0 385 }
michael@0 386
michael@0 387 typeInfo = nss_cmstype_lookup(type);
michael@0 388 if (typeInfo) {
michael@0 389 if (typeInfo->encode_after) {
michael@0 390 return (*typeInfo->encode_after)(gd);
michael@0 391 }
michael@0 392 /* decoder ops optional for data tags */
michael@0 393 if (typeInfo->isData) {
michael@0 394 return SECSuccess;
michael@0 395 }
michael@0 396 }
michael@0 397 /* expected a function, but none existed */
michael@0 398 return SECFailure;
michael@0 399 }
michael@0 400
michael@0 401
michael@0 402 SECStatus
michael@0 403 NSS_CMSType_RegisterContentType(SECOidTag type,
michael@0 404 SEC_ASN1Template *asn1Template, size_t size,
michael@0 405 NSSCMSGenericWrapperDataDestroy destroy,
michael@0 406 NSSCMSGenericWrapperDataCallback decode_before,
michael@0 407 NSSCMSGenericWrapperDataCallback decode_after,
michael@0 408 NSSCMSGenericWrapperDataCallback decode_end,
michael@0 409 NSSCMSGenericWrapperDataCallback encode_start,
michael@0 410 NSSCMSGenericWrapperDataCallback encode_before,
michael@0 411 NSSCMSGenericWrapperDataCallback encode_after,
michael@0 412 PRBool isData)
michael@0 413 {
michael@0 414 PRStatus rc;
michael@0 415 SECStatus rv;
michael@0 416 nsscmstypeInfo *typeInfo;
michael@0 417 const nsscmstypeInfo *exists;
michael@0 418
michael@0 419 rc = PR_CallOnce( &nsscmstypeOnce, nss_cmstype_init);
michael@0 420 if (rc == PR_FAILURE) {
michael@0 421 return SECFailure;
michael@0 422 }
michael@0 423 PR_Lock(nsscmstypeAddLock);
michael@0 424 exists = nss_cmstype_lookup(type);
michael@0 425 if (exists) {
michael@0 426 PR_Unlock(nsscmstypeAddLock);
michael@0 427 /* already added */
michael@0 428 return SECSuccess;
michael@0 429 }
michael@0 430 typeInfo = PORT_ArenaNew(nsscmstypeArena, nsscmstypeInfo);
michael@0 431 typeInfo->type = type;
michael@0 432 typeInfo->size = size;
michael@0 433 typeInfo->isData = isData;
michael@0 434 typeInfo->template = asn1Template;
michael@0 435 typeInfo->destroy = destroy;
michael@0 436 typeInfo->decode_before = decode_before;
michael@0 437 typeInfo->decode_after = decode_after;
michael@0 438 typeInfo->decode_end = decode_end;
michael@0 439 typeInfo->encode_start = encode_start;
michael@0 440 typeInfo->encode_before = encode_before;
michael@0 441 typeInfo->encode_after = encode_after;
michael@0 442 rv = nss_cmstype_add(type, typeInfo);
michael@0 443 PR_Unlock(nsscmstypeAddLock);
michael@0 444 return rv;
michael@0 445 }
michael@0 446

mercurial