mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-11 02:10:17 +01:00
44b7f056d9
bug1001332, 56b691c003ad, bug1086145, bug1054069, bug1155922, bug991783, bug1125025, bug1162521, bug1162644, bug1132941, bug1164364, bug1166205, bug1166163, bug1166515, bug1138554, bug1167046, bug1167043, bug1169451, bug1172128, bug1170322, bug102794, bug1128184, bug557830, bug1174648, bug1180244, bug1177784, bug1173413, bug1169174, bug1084669, bug951455, bug1183395, bug1177430, bug1183827, bug1160139, bug1154106, bug1142209, bug1185033, bug1193467, bug1182667(with sha512 changes backed out, which breaks VC6 compilation), bug1158489, bug337796
447 lines
10 KiB
C
447 lines
10 KiB
C
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
/*
|
|
* CMS User Define Types
|
|
*/
|
|
|
|
#include "cmslocal.h"
|
|
|
|
#include "prinit.h"
|
|
#include "pk11func.h"
|
|
#include "secitem.h"
|
|
#include "secoid.h"
|
|
#include "secerr.h"
|
|
#include "nss.h"
|
|
|
|
typedef struct nsscmstypeInfoStr nsscmstypeInfo;
|
|
struct nsscmstypeInfoStr {
|
|
SECOidTag type;
|
|
SEC_ASN1Template *template;
|
|
size_t size;
|
|
PRBool isData;
|
|
NSSCMSGenericWrapperDataDestroy destroy;
|
|
NSSCMSGenericWrapperDataCallback decode_before;
|
|
NSSCMSGenericWrapperDataCallback decode_after;
|
|
NSSCMSGenericWrapperDataCallback decode_end;
|
|
NSSCMSGenericWrapperDataCallback encode_start;
|
|
NSSCMSGenericWrapperDataCallback encode_before;
|
|
NSSCMSGenericWrapperDataCallback encode_after;
|
|
};
|
|
|
|
/* make sure the global tables are only initialized once */
|
|
static PRCallOnceType nsscmstypeOnce;
|
|
static PRCallOnceType nsscmstypeClearOnce;
|
|
/* lock for adding a new entry */
|
|
static PRLock *nsscmstypeAddLock;
|
|
/* lock for the hash table */
|
|
static PRLock *nsscmstypeHashLock;
|
|
/* the hash table itself */
|
|
static PLHashTable *nsscmstypeHash;
|
|
/* arena to hold all the hash table data */
|
|
static PLArenaPool *nsscmstypeArena;
|
|
|
|
/*
|
|
* clean up our global tables
|
|
*/
|
|
SECStatus
|
|
nss_cmstype_shutdown(void *appData, void *reserved)
|
|
{
|
|
if (nsscmstypeHashLock) {
|
|
PR_Lock(nsscmstypeHashLock);
|
|
}
|
|
if (nsscmstypeHash) {
|
|
PL_HashTableDestroy(nsscmstypeHash);
|
|
nsscmstypeHash = NULL;
|
|
}
|
|
if (nsscmstypeArena) {
|
|
PORT_FreeArena(nsscmstypeArena, PR_FALSE);
|
|
nsscmstypeArena = NULL;
|
|
}
|
|
if (nsscmstypeAddLock) {
|
|
PR_DestroyLock(nsscmstypeAddLock);
|
|
}
|
|
if (nsscmstypeHashLock) {
|
|
PRLock *oldLock = nsscmstypeHashLock;
|
|
nsscmstypeHashLock = NULL;
|
|
PR_Unlock(oldLock);
|
|
PR_DestroyLock(oldLock);
|
|
}
|
|
|
|
/* don't clear out the PR_ONCE data if we failed our inital call */
|
|
if (appData == NULL) {
|
|
nsscmstypeOnce = nsscmstypeClearOnce;
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
static PLHashNumber
|
|
nss_cmstype_hash_key(const void *key)
|
|
{
|
|
return (PLHashNumber)((char *)key - (char *)NULL);
|
|
}
|
|
|
|
static PRIntn
|
|
nss_cmstype_compare_keys(const void *v1, const void *v2)
|
|
{
|
|
PLHashNumber value1 = nss_cmstype_hash_key(v1);
|
|
PLHashNumber value2 = nss_cmstype_hash_key(v2);
|
|
|
|
return (value1 == value2);
|
|
}
|
|
|
|
/*
|
|
* initialize our hash tables, called once on the first attemat to register
|
|
* a new SMIME type.
|
|
*/
|
|
static PRStatus
|
|
nss_cmstype_init(void)
|
|
{
|
|
SECStatus rv;
|
|
|
|
nsscmstypeHashLock = PR_NewLock();
|
|
if (nsscmstypeHashLock == NULL) {
|
|
return PR_FAILURE;
|
|
}
|
|
nsscmstypeAddLock = PR_NewLock();
|
|
if (nsscmstypeHashLock == NULL) {
|
|
goto fail;
|
|
}
|
|
nsscmstypeHash = PL_NewHashTable(64, nss_cmstype_hash_key,
|
|
nss_cmstype_compare_keys, PL_CompareValues, NULL, NULL);
|
|
if (nsscmstypeHash == NULL) {
|
|
goto fail;
|
|
}
|
|
nsscmstypeArena = PORT_NewArena(2048);
|
|
if (nsscmstypeArena == NULL) {
|
|
goto fail;
|
|
}
|
|
rv = NSS_RegisterShutdown(nss_cmstype_shutdown, NULL);
|
|
if (rv != SECSuccess) {
|
|
goto fail;
|
|
}
|
|
return PR_SUCCESS;
|
|
|
|
fail:
|
|
nss_cmstype_shutdown(&nsscmstypeOnce, NULL);
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
|
|
/*
|
|
* look up and registered SIME type
|
|
*/
|
|
static const nsscmstypeInfo *
|
|
nss_cmstype_lookup(SECOidTag type)
|
|
{
|
|
nsscmstypeInfo *typeInfo = NULL;;
|
|
if (!nsscmstypeHash) {
|
|
return NULL;
|
|
}
|
|
PR_Lock(nsscmstypeHashLock);
|
|
if (nsscmstypeHash) {
|
|
typeInfo = PL_HashTableLookupConst(nsscmstypeHash, (void *)type);
|
|
}
|
|
PR_Unlock(nsscmstypeHashLock);
|
|
return typeInfo;
|
|
}
|
|
|
|
/*
|
|
* add a new type to the SMIME type table
|
|
*/
|
|
static SECStatus
|
|
nss_cmstype_add(SECOidTag type, nsscmstypeInfo *typeinfo)
|
|
{
|
|
PLHashEntry *entry;
|
|
|
|
if (!nsscmstypeHash) {
|
|
/* assert? this shouldn't happen */
|
|
return SECFailure;
|
|
}
|
|
PR_Lock(nsscmstypeHashLock);
|
|
/* this is really paranoia. If we really are racing nsscmstypeHash, we'll
|
|
* also be racing nsscmstypeHashLock... */
|
|
if (!nsscmstypeHash) {
|
|
PR_Unlock(nsscmstypeHashLock);
|
|
return SECFailure;
|
|
}
|
|
entry = PL_HashTableAdd(nsscmstypeHash, (void *)type, typeinfo);
|
|
PR_Unlock(nsscmstypeHashLock);
|
|
return entry ? SECSuccess : SECFailure;
|
|
}
|
|
|
|
|
|
/* helper functions to manage new content types
|
|
*/
|
|
|
|
PRBool
|
|
NSS_CMSType_IsWrapper(SECOidTag type)
|
|
{
|
|
const nsscmstypeInfo *typeInfo = NULL;
|
|
|
|
switch (type) {
|
|
case SEC_OID_PKCS7_SIGNED_DATA:
|
|
case SEC_OID_PKCS7_ENVELOPED_DATA:
|
|
case SEC_OID_PKCS7_DIGESTED_DATA:
|
|
case SEC_OID_PKCS7_ENCRYPTED_DATA:
|
|
return PR_TRUE;
|
|
default:
|
|
typeInfo = nss_cmstype_lookup(type);
|
|
if (typeInfo && !typeInfo->isData) {
|
|
return PR_TRUE;
|
|
}
|
|
}
|
|
return PR_FALSE;
|
|
}
|
|
|
|
PRBool
|
|
NSS_CMSType_IsData(SECOidTag type)
|
|
{
|
|
const nsscmstypeInfo *typeInfo = NULL;
|
|
|
|
switch (type) {
|
|
case SEC_OID_PKCS7_DATA:
|
|
return PR_TRUE;
|
|
default:
|
|
typeInfo = nss_cmstype_lookup(type);
|
|
if (typeInfo && typeInfo->isData) {
|
|
return PR_TRUE;
|
|
}
|
|
}
|
|
return PR_FALSE;
|
|
}
|
|
|
|
const SEC_ASN1Template *
|
|
NSS_CMSType_GetTemplate(SECOidTag type)
|
|
{
|
|
const nsscmstypeInfo *typeInfo = nss_cmstype_lookup(type);
|
|
|
|
if (typeInfo && typeInfo->template) {
|
|
return typeInfo->template;
|
|
}
|
|
return SEC_ASN1_GET(SEC_PointerToOctetStringTemplate);
|
|
}
|
|
|
|
size_t
|
|
NSS_CMSType_GetContentSize(SECOidTag type)
|
|
{
|
|
const nsscmstypeInfo *typeInfo = nss_cmstype_lookup(type);
|
|
|
|
if (typeInfo) {
|
|
return typeInfo->size;
|
|
}
|
|
return sizeof(SECItem *);
|
|
|
|
}
|
|
|
|
void
|
|
NSS_CMSGenericWrapperData_Destroy(SECOidTag type, NSSCMSGenericWrapperData *gd)
|
|
{
|
|
const nsscmstypeInfo *typeInfo = nss_cmstype_lookup(type);
|
|
|
|
if (typeInfo && typeInfo->destroy) {
|
|
(*typeInfo->destroy)(gd);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
SECStatus
|
|
NSS_CMSGenericWrapperData_Decode_BeforeData(SECOidTag type,
|
|
NSSCMSGenericWrapperData *gd)
|
|
{
|
|
const nsscmstypeInfo *typeInfo;
|
|
|
|
/* short cut common case */
|
|
if (type == SEC_OID_PKCS7_DATA) {
|
|
return SECSuccess;
|
|
}
|
|
|
|
typeInfo = nss_cmstype_lookup(type);
|
|
if (typeInfo) {
|
|
if (typeInfo->decode_before) {
|
|
return (*typeInfo->decode_before)(gd);
|
|
}
|
|
/* decoder ops optional for data tags */
|
|
if (typeInfo->isData) {
|
|
return SECSuccess;
|
|
}
|
|
}
|
|
/* expected a function, but none existed */
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
SECStatus
|
|
NSS_CMSGenericWrapperData_Decode_AfterData(SECOidTag type,
|
|
NSSCMSGenericWrapperData *gd)
|
|
{
|
|
const nsscmstypeInfo *typeInfo;
|
|
|
|
/* short cut common case */
|
|
if (type == SEC_OID_PKCS7_DATA) {
|
|
return SECSuccess;
|
|
}
|
|
|
|
typeInfo = nss_cmstype_lookup(type);
|
|
if (typeInfo) {
|
|
if (typeInfo->decode_after) {
|
|
return (*typeInfo->decode_after)(gd);
|
|
}
|
|
/* decoder ops optional for data tags */
|
|
if (typeInfo->isData) {
|
|
return SECSuccess;
|
|
}
|
|
}
|
|
/* expected a function, but none existed */
|
|
return SECFailure;
|
|
}
|
|
|
|
SECStatus
|
|
NSS_CMSGenericWrapperData_Decode_AfterEnd(SECOidTag type,
|
|
NSSCMSGenericWrapperData *gd)
|
|
{
|
|
const nsscmstypeInfo *typeInfo;
|
|
|
|
/* short cut common case */
|
|
if (type == SEC_OID_PKCS7_DATA) {
|
|
return SECSuccess;
|
|
}
|
|
|
|
typeInfo = nss_cmstype_lookup(type);
|
|
if (typeInfo) {
|
|
if (typeInfo->decode_end) {
|
|
return (*typeInfo->decode_end)(gd);
|
|
}
|
|
/* decoder ops optional for data tags */
|
|
if (typeInfo->isData) {
|
|
return SECSuccess;
|
|
}
|
|
}
|
|
/* expected a function, but none existed */
|
|
return SECFailure;
|
|
}
|
|
|
|
SECStatus
|
|
NSS_CMSGenericWrapperData_Encode_BeforeStart(SECOidTag type,
|
|
NSSCMSGenericWrapperData *gd)
|
|
{
|
|
const nsscmstypeInfo *typeInfo;
|
|
|
|
/* short cut common case */
|
|
if (type == SEC_OID_PKCS7_DATA) {
|
|
return SECSuccess;
|
|
}
|
|
|
|
typeInfo = nss_cmstype_lookup(type);
|
|
if (typeInfo) {
|
|
if (typeInfo->encode_start) {
|
|
return (*typeInfo->encode_start)(gd);
|
|
}
|
|
/* decoder ops optional for data tags */
|
|
if (typeInfo->isData) {
|
|
return SECSuccess;
|
|
}
|
|
}
|
|
/* expected a function, but none existed */
|
|
return SECFailure;
|
|
}
|
|
|
|
SECStatus
|
|
NSS_CMSGenericWrapperData_Encode_BeforeData(SECOidTag type,
|
|
NSSCMSGenericWrapperData *gd)
|
|
{
|
|
const nsscmstypeInfo *typeInfo;
|
|
|
|
/* short cut common case */
|
|
if (type == SEC_OID_PKCS7_DATA) {
|
|
return SECSuccess;
|
|
}
|
|
|
|
typeInfo = nss_cmstype_lookup(type);
|
|
if (typeInfo) {
|
|
if (typeInfo->encode_before) {
|
|
return (*typeInfo->encode_before)(gd);
|
|
}
|
|
/* decoder ops optional for data tags */
|
|
if (typeInfo->isData) {
|
|
return SECSuccess;
|
|
}
|
|
}
|
|
/* expected a function, but none existed */
|
|
return SECFailure;
|
|
}
|
|
|
|
SECStatus
|
|
NSS_CMSGenericWrapperData_Encode_AfterData(SECOidTag type,
|
|
NSSCMSGenericWrapperData *gd)
|
|
{
|
|
const nsscmstypeInfo *typeInfo;
|
|
|
|
/* short cut common case */
|
|
if (type == SEC_OID_PKCS7_DATA) {
|
|
return SECSuccess;
|
|
}
|
|
|
|
typeInfo = nss_cmstype_lookup(type);
|
|
if (typeInfo) {
|
|
if (typeInfo->encode_after) {
|
|
return (*typeInfo->encode_after)(gd);
|
|
}
|
|
/* decoder ops optional for data tags */
|
|
if (typeInfo->isData) {
|
|
return SECSuccess;
|
|
}
|
|
}
|
|
/* expected a function, but none existed */
|
|
return SECFailure;
|
|
}
|
|
|
|
|
|
SECStatus
|
|
NSS_CMSType_RegisterContentType(SECOidTag type,
|
|
SEC_ASN1Template *asn1Template, size_t size,
|
|
NSSCMSGenericWrapperDataDestroy destroy,
|
|
NSSCMSGenericWrapperDataCallback decode_before,
|
|
NSSCMSGenericWrapperDataCallback decode_after,
|
|
NSSCMSGenericWrapperDataCallback decode_end,
|
|
NSSCMSGenericWrapperDataCallback encode_start,
|
|
NSSCMSGenericWrapperDataCallback encode_before,
|
|
NSSCMSGenericWrapperDataCallback encode_after,
|
|
PRBool isData)
|
|
{
|
|
PRStatus rc;
|
|
SECStatus rv;
|
|
nsscmstypeInfo *typeInfo;
|
|
const nsscmstypeInfo *exists;
|
|
|
|
rc = PR_CallOnce( &nsscmstypeOnce, nss_cmstype_init);
|
|
if (rc == PR_FAILURE) {
|
|
return SECFailure;
|
|
}
|
|
PR_Lock(nsscmstypeAddLock);
|
|
exists = nss_cmstype_lookup(type);
|
|
if (exists) {
|
|
PR_Unlock(nsscmstypeAddLock);
|
|
/* already added */
|
|
return SECSuccess;
|
|
}
|
|
typeInfo = PORT_ArenaNew(nsscmstypeArena, nsscmstypeInfo);
|
|
typeInfo->type = type;
|
|
typeInfo->size = size;
|
|
typeInfo->isData = isData;
|
|
typeInfo->template = asn1Template;
|
|
typeInfo->destroy = destroy;
|
|
typeInfo->decode_before = decode_before;
|
|
typeInfo->decode_after = decode_after;
|
|
typeInfo->decode_end = decode_end;
|
|
typeInfo->encode_start = encode_start;
|
|
typeInfo->encode_before = encode_before;
|
|
typeInfo->encode_after = encode_after;
|
|
rv = nss_cmstype_add(type, typeInfo);
|
|
PR_Unlock(nsscmstypeAddLock);
|
|
return rv;
|
|
}
|
|
|