gecko-dev/security/nss/lib/util/secdig.c

183 строки
4.5 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/. */
#include "secdig.h"
#include "secoid.h"
#include "secasn1.h"
#include "secerr.h"
/*
* XXX Want to have a SGN_DecodeDigestInfo, like:
* SGNDigestInfo *SGN_DecodeDigestInfo(SECItem *didata);
* that creates a pool and allocates from it and decodes didata into
* the newly allocated DigestInfo structure. Then fix secvfy.c (it
* will no longer need an arena itself) to call this and then call
* DestroyDigestInfo when it is done, then can remove the old template
* above and keep our new template static and "hidden".
*/
/*
* XXX It might be nice to combine the following two functions (create
* and encode). I think that is all anybody ever wants to do anyway.
*/
SECItem *
SGN_EncodeDigestInfo(PLArenaPool *poolp, SECItem *dest, SGNDigestInfo *diginfo)
{
return SEC_ASN1EncodeItem(poolp, dest, diginfo, sgn_DigestInfoTemplate);
}
SGNDigestInfo *
SGN_CreateDigestInfo(SECOidTag algorithm, const unsigned char *sig,
unsigned len)
{
SGNDigestInfo *di;
SECStatus rv;
PLArenaPool *arena;
SECItem *null_param;
SECItem dummy_value;
switch (algorithm) {
case SEC_OID_MD2:
case SEC_OID_MD5:
case SEC_OID_SHA1:
case SEC_OID_SHA224:
case SEC_OID_SHA256:
case SEC_OID_SHA384:
case SEC_OID_SHA512:
break;
default:
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return NULL;
}
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (arena == NULL) {
return NULL;
}
di = (SGNDigestInfo *)PORT_ArenaZAlloc(arena, sizeof(SGNDigestInfo));
if (di == NULL) {
PORT_FreeArena(arena, PR_FALSE);
return NULL;
}
di->arena = arena;
/*
* PKCS #1 specifies that the AlgorithmID must have a NULL parameter
* (as opposed to no parameter at all).
*/
dummy_value.data = NULL;
dummy_value.len = 0;
null_param = SEC_ASN1EncodeItem(NULL, NULL, &dummy_value, SEC_NullTemplate);
if (null_param == NULL) {
goto loser;
}
rv = SECOID_SetAlgorithmID(arena, &di->digestAlgorithm, algorithm,
null_param);
SECITEM_FreeItem(null_param, PR_TRUE);
if (rv != SECSuccess) {
goto loser;
}
di->digest.data = (unsigned char *)PORT_ArenaAlloc(arena, len);
if (di->digest.data == NULL) {
goto loser;
}
di->digest.len = len;
PORT_Memcpy(di->digest.data, sig, len);
return di;
loser:
SGN_DestroyDigestInfo(di);
return NULL;
}
SGNDigestInfo *
SGN_DecodeDigestInfo(SECItem *didata)
{
PLArenaPool *arena;
SGNDigestInfo *di;
SECStatus rv = SECFailure;
SECItem diCopy = { siBuffer, NULL, 0 };
arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
if (arena == NULL)
return NULL;
rv = SECITEM_CopyItem(arena, &diCopy, didata);
if (rv != SECSuccess) {
PORT_FreeArena(arena, PR_FALSE);
return NULL;
}
di = (SGNDigestInfo *)PORT_ArenaZAlloc(arena, sizeof(SGNDigestInfo));
if (di != NULL) {
di->arena = arena;
rv = SEC_QuickDERDecodeItem(arena, di, sgn_DigestInfoTemplate, &diCopy);
}
if ((di == NULL) || (rv != SECSuccess)) {
PORT_FreeArena(arena, PR_FALSE);
di = NULL;
}
return di;
}
void
SGN_DestroyDigestInfo(SGNDigestInfo *di)
{
if (di && di->arena) {
PORT_FreeArena(di->arena, PR_FALSE);
}
return;
}
SECStatus
SGN_CopyDigestInfo(PLArenaPool *poolp, SGNDigestInfo *a, SGNDigestInfo *b)
{
SECStatus rv;
void *mark;
if ((poolp == NULL) || (a == NULL) || (b == NULL))
return SECFailure;
mark = PORT_ArenaMark(poolp);
a->arena = poolp;
rv = SECOID_CopyAlgorithmID(poolp, &a->digestAlgorithm,
&b->digestAlgorithm);
if (rv == SECSuccess)
rv = SECITEM_CopyItem(poolp, &a->digest, &b->digest);
if (rv != SECSuccess) {
PORT_ArenaRelease(poolp, mark);
} else {
PORT_ArenaUnmark(poolp, mark);
}
return rv;
}
SECComparison
SGN_CompareDigestInfo(SGNDigestInfo *a, SGNDigestInfo *b)
{
SECComparison rv;
/* Check signature algorithm's */
rv = SECOID_CompareAlgorithmID(&a->digestAlgorithm, &b->digestAlgorithm);
if (rv)
return rv;
/* Compare signature block length's */
rv = SECITEM_CompareItem(&a->digest, &b->digest);
return rv;
}