security/nss/lib/smime/cmsudf.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial