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