Bury all NSS specifics into a separate source
- Not everybody needs/wants the certified monster that NSS is (along with all its quirks), this leaves room for alternative compile-time selectable crypto backends. Besides that, we get a clean functionality separation for the PGP parser and the cryptography parts. - The whole crypto abstraction works inspired + somewhat based on Michael Schroeder's similar patch in Suse, kudos. - TODO: port beecrypt support from Suse to the new interface.
This commit is contained in:
parent
85b90e4176
commit
3db9a10577
|
@ -17,6 +17,8 @@ librpmio_la_SOURCES = \
|
|||
rpmstring.c rpmfileutil.c \
|
||||
rpmkeyring.c
|
||||
|
||||
librpmio_la_SOURCES += digest_nss.c
|
||||
|
||||
librpmio_la_LDFLAGS = -version-info 2:0:0
|
||||
librpmio_la_LIBADD = \
|
||||
../misc/libmisc.la \
|
||||
|
|
151
rpmio/digest.c
151
rpmio/digest.c
|
@ -8,22 +8,6 @@
|
|||
|
||||
#include "debug.h"
|
||||
|
||||
#ifdef SHA_DEBUG
|
||||
#define DPRINTF(_a) fprintf _a
|
||||
#else
|
||||
#define DPRINTF(_a)
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* MD5/SHA1 digest private data.
|
||||
*/
|
||||
struct DIGEST_CTX_s {
|
||||
rpmDigestFlags flags; /*!< Bit(s) to control digest operation. */
|
||||
HASHContext *hashctx; /*!< Internal NSS hash context. */
|
||||
int algo; /*!< Used hash algorithm */
|
||||
};
|
||||
|
||||
#define DIGESTS_MAX 11
|
||||
struct rpmDigestBundle_s {
|
||||
int index_min; /*!< Smallest index of active digest */
|
||||
|
@ -109,138 +93,3 @@ DIGEST_CTX rpmDigestBundleDupCtx(rpmDigestBundle bundle, int algo)
|
|||
return dup;
|
||||
}
|
||||
|
||||
DIGEST_CTX
|
||||
rpmDigestDup(DIGEST_CTX octx)
|
||||
{
|
||||
DIGEST_CTX nctx = NULL;
|
||||
if (octx) {
|
||||
HASHContext *hctx = HASH_Clone(octx->hashctx);
|
||||
if (hctx) {
|
||||
nctx = memcpy(xcalloc(1, sizeof(*nctx)), octx, sizeof(*nctx));
|
||||
nctx->hashctx = hctx;
|
||||
}
|
||||
}
|
||||
return nctx;
|
||||
}
|
||||
|
||||
RPM_GNUC_PURE
|
||||
static HASH_HashType getHashType(int hashalgo)
|
||||
{
|
||||
switch (hashalgo) {
|
||||
case PGPHASHALGO_MD5:
|
||||
return HASH_AlgMD5;
|
||||
break;
|
||||
case PGPHASHALGO_MD2:
|
||||
return HASH_AlgMD2;
|
||||
break;
|
||||
case PGPHASHALGO_SHA1:
|
||||
return HASH_AlgSHA1;
|
||||
break;
|
||||
case PGPHASHALGO_SHA256:
|
||||
return HASH_AlgSHA256;
|
||||
break;
|
||||
case PGPHASHALGO_SHA384:
|
||||
return HASH_AlgSHA384;
|
||||
break;
|
||||
case PGPHASHALGO_SHA512:
|
||||
return HASH_AlgSHA512;
|
||||
break;
|
||||
case PGPHASHALGO_RIPEMD160:
|
||||
case PGPHASHALGO_TIGER192:
|
||||
case PGPHASHALGO_HAVAL_5_160:
|
||||
default:
|
||||
return HASH_AlgNULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
rpmDigestLength(int hashalgo)
|
||||
{
|
||||
return HASH_ResultLen(getHashType(hashalgo));
|
||||
}
|
||||
|
||||
DIGEST_CTX
|
||||
rpmDigestInit(int hashalgo, rpmDigestFlags flags)
|
||||
{
|
||||
HASH_HashType type = getHashType(hashalgo);
|
||||
HASHContext *hashctx = NULL;
|
||||
DIGEST_CTX ctx = NULL;
|
||||
|
||||
if (type == HASH_AlgNULL || rpmInitCrypto() < 0)
|
||||
goto exit;
|
||||
|
||||
if ((hashctx = HASH_Create(type)) != NULL) {
|
||||
ctx = xcalloc(1, sizeof(*ctx));
|
||||
ctx->flags = flags;
|
||||
ctx->algo = hashalgo;
|
||||
ctx->hashctx = hashctx;
|
||||
HASH_Begin(ctx->hashctx);
|
||||
}
|
||||
|
||||
DPRINTF((stderr, "*** Init(%x) ctx %p hashctx %p\n", flags, ctx, ctx->hashctx));
|
||||
exit:
|
||||
return ctx;
|
||||
}
|
||||
|
||||
int
|
||||
rpmDigestUpdate(DIGEST_CTX ctx, const void * data, size_t len)
|
||||
{
|
||||
size_t partlen;
|
||||
const unsigned char *ptr = data;
|
||||
|
||||
if (ctx == NULL)
|
||||
return -1;
|
||||
|
||||
DPRINTF((stderr, "*** Update(%p,%p,%zd) hashctx %p \"%s\"\n", ctx, data, len, ctx->hashctx, ((char *)data)));
|
||||
partlen = ~(unsigned int)0xFF;
|
||||
while (len > 0) {
|
||||
if (len < partlen) {
|
||||
partlen = len;
|
||||
}
|
||||
HASH_Update(ctx->hashctx, ptr, partlen);
|
||||
ptr += partlen;
|
||||
len -= partlen;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
rpmDigestFinal(DIGEST_CTX ctx, void ** datap, size_t *lenp, int asAscii)
|
||||
{
|
||||
unsigned char * digest;
|
||||
unsigned int digestlen;
|
||||
|
||||
if (ctx == NULL)
|
||||
return -1;
|
||||
digestlen = HASH_ResultLenContext(ctx->hashctx);
|
||||
digest = xmalloc(digestlen);
|
||||
|
||||
DPRINTF((stderr, "*** Final(%p,%p,%p,%zd) hashctx %p digest %p\n", ctx, datap, lenp, asAscii, ctx->hashctx, digest));
|
||||
/* FIX: check rc */
|
||||
HASH_End(ctx->hashctx, digest, (unsigned int *) &digestlen, digestlen);
|
||||
|
||||
/* Return final digest. */
|
||||
if (!asAscii) {
|
||||
if (lenp) *lenp = digestlen;
|
||||
if (datap) {
|
||||
*datap = digest;
|
||||
digest = NULL;
|
||||
}
|
||||
} else {
|
||||
if (lenp) *lenp = (2*digestlen) + 1;
|
||||
if (datap) {
|
||||
const uint8_t * s = (const uint8_t *) digest;
|
||||
*datap = pgpHexStr(s, digestlen);
|
||||
}
|
||||
}
|
||||
if (digest) {
|
||||
memset(digest, 0, digestlen); /* In case it's sensitive */
|
||||
free(digest);
|
||||
}
|
||||
HASH_Destroy(ctx->hashctx);
|
||||
memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
#ifndef _RPMDIGEST_H
|
||||
#define _RPMDIGEST_H
|
||||
|
||||
#include <nss.h>
|
||||
#include <sechash.h>
|
||||
#include <keyhi.h>
|
||||
#include <cryptohi.h>
|
||||
|
||||
#include <rpm/rpmpgp.h>
|
||||
#include "rpmio/base64.h"
|
||||
|
||||
|
@ -64,4 +59,26 @@ pgpDigAlg pgpSignatureNew(int algo);
|
|||
|
||||
pgpDigAlg pgpDigAlgFree(pgpDigAlg da);
|
||||
|
||||
/** \ingroup rpmpgp
|
||||
* Return no. of bits in a multiprecision integer.
|
||||
* @param p pointer to multiprecision integer
|
||||
* @return no. of bits
|
||||
*/
|
||||
static inline
|
||||
unsigned int pgpMpiBits(const uint8_t *p)
|
||||
{
|
||||
return ((p[0] << 8) | p[1]);
|
||||
}
|
||||
|
||||
/** \ingroup rpmpgp
|
||||
* Return no. of bytes in a multiprecision integer.
|
||||
* @param p pointer to multiprecision integer
|
||||
* @return no. of bytes
|
||||
*/
|
||||
static inline
|
||||
size_t pgpMpiLen(const uint8_t *p)
|
||||
{
|
||||
return (2 + ((pgpMpiBits(p)+7)>>3));
|
||||
}
|
||||
|
||||
#endif /* _RPMDIGEST_H */
|
||||
|
|
|
@ -0,0 +1,519 @@
|
|||
#include "system.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <nss.h>
|
||||
#include <sechash.h>
|
||||
#include <keyhi.h>
|
||||
#include <cryptohi.h>
|
||||
|
||||
#include <rpm/rpmlog.h>
|
||||
#include "rpmio/digest.h"
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
static int _crypto_initialized = 0;
|
||||
static int _new_process = 1;
|
||||
|
||||
/**
|
||||
* MD5/SHA1 digest private data.
|
||||
*/
|
||||
struct DIGEST_CTX_s {
|
||||
rpmDigestFlags flags; /*!< Bit(s) to control digest operation. */
|
||||
HASHContext *hashctx; /*!< Internal NSS hash context. */
|
||||
int algo; /*!< Used hash algorithm */
|
||||
};
|
||||
|
||||
/*
|
||||
* Only flag for re-initialization here, in the common case the child
|
||||
* exec()'s something else shutting down NSS here would be waste of time.
|
||||
*/
|
||||
static void at_forkchild(void)
|
||||
{
|
||||
_new_process = 1;
|
||||
}
|
||||
|
||||
int rpmInitCrypto(void)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
/* Lazy NSS shutdown for re-initialization after fork() */
|
||||
if (_new_process && _crypto_initialized) {
|
||||
rpmFreeCrypto();
|
||||
}
|
||||
|
||||
/* Initialize NSS if not already done */
|
||||
if (!_crypto_initialized) {
|
||||
if (NSS_NoDB_Init(NULL) != SECSuccess) {
|
||||
rc = -1;
|
||||
} else {
|
||||
_crypto_initialized = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Register one post-fork handler per process */
|
||||
if (_new_process) {
|
||||
if (pthread_atfork(NULL, NULL, at_forkchild) != 0) {
|
||||
rpmlog(RPMLOG_WARNING, _("Failed to register fork handler: %m\n"));
|
||||
}
|
||||
_new_process = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int rpmFreeCrypto(void)
|
||||
{
|
||||
int rc = 0;
|
||||
if (_crypto_initialized) {
|
||||
rc = (NSS_Shutdown() != SECSuccess);
|
||||
_crypto_initialized = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
DIGEST_CTX rpmDigestDup(DIGEST_CTX octx)
|
||||
{
|
||||
DIGEST_CTX nctx = NULL;
|
||||
if (octx) {
|
||||
HASHContext *hctx = HASH_Clone(octx->hashctx);
|
||||
if (hctx) {
|
||||
nctx = memcpy(xcalloc(1, sizeof(*nctx)), octx, sizeof(*nctx));
|
||||
nctx->hashctx = hctx;
|
||||
}
|
||||
}
|
||||
return nctx;
|
||||
}
|
||||
|
||||
RPM_GNUC_PURE
|
||||
static HASH_HashType getHashType(int hashalgo)
|
||||
{
|
||||
switch (hashalgo) {
|
||||
case PGPHASHALGO_MD5:
|
||||
return HASH_AlgMD5;
|
||||
break;
|
||||
case PGPHASHALGO_MD2:
|
||||
return HASH_AlgMD2;
|
||||
break;
|
||||
case PGPHASHALGO_SHA1:
|
||||
return HASH_AlgSHA1;
|
||||
break;
|
||||
case PGPHASHALGO_SHA256:
|
||||
return HASH_AlgSHA256;
|
||||
break;
|
||||
case PGPHASHALGO_SHA384:
|
||||
return HASH_AlgSHA384;
|
||||
break;
|
||||
case PGPHASHALGO_SHA512:
|
||||
return HASH_AlgSHA512;
|
||||
break;
|
||||
case PGPHASHALGO_RIPEMD160:
|
||||
case PGPHASHALGO_TIGER192:
|
||||
case PGPHASHALGO_HAVAL_5_160:
|
||||
default:
|
||||
return HASH_AlgNULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
size_t rpmDigestLength(int hashalgo)
|
||||
{
|
||||
return HASH_ResultLen(getHashType(hashalgo));
|
||||
}
|
||||
|
||||
DIGEST_CTX rpmDigestInit(int hashalgo, rpmDigestFlags flags)
|
||||
{
|
||||
HASH_HashType type = getHashType(hashalgo);
|
||||
HASHContext *hashctx = NULL;
|
||||
DIGEST_CTX ctx = NULL;
|
||||
|
||||
if (type == HASH_AlgNULL || rpmInitCrypto() < 0)
|
||||
goto exit;
|
||||
|
||||
if ((hashctx = HASH_Create(type)) != NULL) {
|
||||
ctx = xcalloc(1, sizeof(*ctx));
|
||||
ctx->flags = flags;
|
||||
ctx->algo = hashalgo;
|
||||
ctx->hashctx = hashctx;
|
||||
HASH_Begin(ctx->hashctx);
|
||||
}
|
||||
|
||||
exit:
|
||||
return ctx;
|
||||
}
|
||||
|
||||
int rpmDigestUpdate(DIGEST_CTX ctx, const void * data, size_t len)
|
||||
{
|
||||
size_t partlen;
|
||||
const unsigned char *ptr = data;
|
||||
|
||||
if (ctx == NULL)
|
||||
return -1;
|
||||
|
||||
partlen = ~(unsigned int)0xFF;
|
||||
while (len > 0) {
|
||||
if (len < partlen) {
|
||||
partlen = len;
|
||||
}
|
||||
HASH_Update(ctx->hashctx, ptr, partlen);
|
||||
ptr += partlen;
|
||||
len -= partlen;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rpmDigestFinal(DIGEST_CTX ctx, void ** datap, size_t *lenp, int asAscii)
|
||||
{
|
||||
unsigned char * digest;
|
||||
unsigned int digestlen;
|
||||
|
||||
if (ctx == NULL)
|
||||
return -1;
|
||||
digestlen = HASH_ResultLenContext(ctx->hashctx);
|
||||
digest = xmalloc(digestlen);
|
||||
|
||||
/* FIX: check rc */
|
||||
HASH_End(ctx->hashctx, digest, (unsigned int *) &digestlen, digestlen);
|
||||
|
||||
/* Return final digest. */
|
||||
if (!asAscii) {
|
||||
if (lenp) *lenp = digestlen;
|
||||
if (datap) {
|
||||
*datap = digest;
|
||||
digest = NULL;
|
||||
}
|
||||
} else {
|
||||
if (lenp) *lenp = (2*digestlen) + 1;
|
||||
if (datap) {
|
||||
const uint8_t * s = (const uint8_t *) digest;
|
||||
*datap = pgpHexStr(s, digestlen);
|
||||
}
|
||||
}
|
||||
if (digest) {
|
||||
memset(digest, 0, digestlen); /* In case it's sensitive */
|
||||
free(digest);
|
||||
}
|
||||
HASH_Destroy(ctx->hashctx);
|
||||
memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pgpMpiSet(unsigned int lbits, uint8_t *dest,
|
||||
const uint8_t * p, const uint8_t * pend)
|
||||
{
|
||||
unsigned int mbits = pgpMpiBits(p);
|
||||
unsigned int nbits;
|
||||
size_t nbytes;
|
||||
uint8_t *t = dest;
|
||||
unsigned int ix;
|
||||
|
||||
if ((p + ((mbits+7) >> 3)) > pend)
|
||||
return 1;
|
||||
|
||||
if (mbits > lbits)
|
||||
return 1;
|
||||
|
||||
nbits = (lbits > mbits ? lbits : mbits);
|
||||
nbytes = ((nbits + 7) >> 3);
|
||||
ix = (nbits - mbits) >> 3;
|
||||
|
||||
if (ix > 0)
|
||||
memset(t, '\0', ix);
|
||||
memcpy(t+ix, p+2, nbytes-ix);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SECItem *pgpMpiItem(PRArenaPool *arena, SECItem *item,
|
||||
const uint8_t *p, const uint8_t *pend)
|
||||
{
|
||||
size_t nbytes = pgpMpiLen(p)-2;
|
||||
|
||||
if (p + nbytes + 2 > pend)
|
||||
return NULL;
|
||||
|
||||
if (item == NULL) {
|
||||
if ((item=SECITEM_AllocItem(arena, item, nbytes)) == NULL)
|
||||
return item;
|
||||
} else {
|
||||
if (arena != NULL)
|
||||
item->data = PORT_ArenaGrow(arena, item->data, item->len, nbytes);
|
||||
else
|
||||
item->data = PORT_Realloc(item->data, nbytes);
|
||||
|
||||
if (item->data == NULL) {
|
||||
if (arena == NULL)
|
||||
SECITEM_FreeItem(item, PR_TRUE);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(item->data, p+2, nbytes);
|
||||
item->len = nbytes;
|
||||
return item;
|
||||
}
|
||||
|
||||
static SECKEYPublicKey *pgpNewPublicKey(KeyType type)
|
||||
{
|
||||
PRArenaPool *arena;
|
||||
SECKEYPublicKey *key;
|
||||
|
||||
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
||||
if (arena == NULL)
|
||||
return NULL;
|
||||
|
||||
key = PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey));
|
||||
|
||||
if (key == NULL) {
|
||||
PORT_FreeArena(arena, PR_FALSE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
key->keyType = type;
|
||||
key->pkcs11ID = CK_INVALID_HANDLE;
|
||||
key->pkcs11Slot = NULL;
|
||||
key->arena = arena;
|
||||
return key;
|
||||
}
|
||||
|
||||
#ifndef DSA_SUBPRIME_LEN
|
||||
#define DSA_SUBPRIME_LEN 20
|
||||
#endif
|
||||
|
||||
static int pgpSetSigMpiDSA(pgpDigAlg pgpsig, int num,
|
||||
const uint8_t *p, const uint8_t *pend)
|
||||
{
|
||||
SECItem *sig = pgpsig->data;
|
||||
int lbits = DSA_SUBPRIME_LEN * 8;
|
||||
int rc = 1; /* assume failure */
|
||||
|
||||
switch (num) {
|
||||
case 0:
|
||||
sig = pgpsig->data = SECITEM_AllocItem(NULL, NULL, 2*DSA_SUBPRIME_LEN);
|
||||
memset(sig->data, 0, 2 * DSA_SUBPRIME_LEN);
|
||||
rc = pgpMpiSet(lbits, sig->data, p, pend);
|
||||
break;
|
||||
case 1:
|
||||
if (sig && pgpMpiSet(lbits, sig->data+DSA_SUBPRIME_LEN, p, pend) == 0) {
|
||||
SECItem *signew = SECITEM_AllocItem(NULL, NULL, 0);
|
||||
if (signew && DSAU_EncodeDerSig(signew, sig) == SECSuccess) {
|
||||
SECITEM_FreeItem(sig, PR_TRUE);
|
||||
pgpsig->data = signew;
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pgpSetKeyMpiDSA(pgpDigAlg pgpkey, int num,
|
||||
const uint8_t *p, const uint8_t *pend)
|
||||
{
|
||||
SECItem *mpi = NULL;
|
||||
SECKEYPublicKey *key = pgpkey->data;
|
||||
|
||||
if (key == NULL)
|
||||
key = pgpkey->data = pgpNewPublicKey(dsaKey);
|
||||
|
||||
if (key) {
|
||||
switch (num) {
|
||||
case 0:
|
||||
mpi = pgpMpiItem(key->arena, &key->u.dsa.params.prime, p, pend);
|
||||
break;
|
||||
case 1:
|
||||
mpi = pgpMpiItem(key->arena, &key->u.dsa.params.subPrime, p, pend);
|
||||
break;
|
||||
case 2:
|
||||
mpi = pgpMpiItem(key->arena, &key->u.dsa.params.base, p, pend);
|
||||
break;
|
||||
case 3:
|
||||
mpi = pgpMpiItem(key->arena, &key->u.dsa.publicValue, p, pend);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (mpi == NULL);
|
||||
}
|
||||
|
||||
static int pgpVerifySigDSA(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
|
||||
uint8_t *hash, size_t hashlen, int hash_algo)
|
||||
{
|
||||
SECItem digest = { .type = siBuffer, .data = hash, .len = hashlen };
|
||||
SECOidTag sigalg = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
|
||||
SECStatus rc;
|
||||
|
||||
/* XXX VFY_VerifyDigest() is deprecated in NSS 3.12 */
|
||||
rc = VFY_VerifyDigest(&digest, pgpkey->data, pgpsig->data, sigalg, NULL);
|
||||
|
||||
return (rc != SECSuccess);
|
||||
}
|
||||
|
||||
static int pgpSetSigMpiRSA(pgpDigAlg pgpsig, int num,
|
||||
const uint8_t *p, const uint8_t *pend)
|
||||
{
|
||||
SECItem *sigitem = NULL;
|
||||
|
||||
if (num == 0) {
|
||||
sigitem = pgpMpiItem(NULL, pgpsig->data, p, pend);
|
||||
if (sigitem)
|
||||
pgpsig->data = sigitem;
|
||||
}
|
||||
return (sigitem == NULL);
|
||||
}
|
||||
|
||||
static int pgpSetKeyMpiRSA(pgpDigAlg pgpkey, int num,
|
||||
const uint8_t *p, const uint8_t *pend)
|
||||
{
|
||||
SECItem *kitem = NULL;
|
||||
SECKEYPublicKey *key = pgpkey->data;
|
||||
|
||||
if (key == NULL)
|
||||
key = pgpkey->data = pgpNewPublicKey(rsaKey);
|
||||
|
||||
if (key) {
|
||||
switch (num) {
|
||||
case 0:
|
||||
kitem = pgpMpiItem(key->arena, &key->u.rsa.modulus, p, pend);
|
||||
break;
|
||||
case 1:
|
||||
kitem = pgpMpiItem(key->arena, &key->u.rsa.publicExponent, p, pend);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (kitem == NULL);
|
||||
}
|
||||
|
||||
static int pgpVerifySigRSA(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
|
||||
uint8_t *hash, size_t hashlen, int hash_algo)
|
||||
{
|
||||
SECItem digest = { .type = siBuffer, .data = hash, .len = hashlen };
|
||||
SECItem *sig = pgpsig->data;
|
||||
SECKEYPublicKey *key = pgpkey->data;
|
||||
SECItem *padded = NULL;
|
||||
SECOidTag sigalg;
|
||||
SECStatus rc = SECFailure;
|
||||
size_t siglen, padlen;
|
||||
|
||||
switch (hash_algo) {
|
||||
case PGPHASHALGO_MD5:
|
||||
sigalg = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
|
||||
break;
|
||||
case PGPHASHALGO_MD2:
|
||||
sigalg = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION;
|
||||
break;
|
||||
case PGPHASHALGO_SHA1:
|
||||
sigalg = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
|
||||
break;
|
||||
case PGPHASHALGO_SHA256:
|
||||
sigalg = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
|
||||
break;
|
||||
case PGPHASHALGO_SHA384:
|
||||
sigalg = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
|
||||
break;
|
||||
case PGPHASHALGO_SHA512:
|
||||
sigalg = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
|
||||
break;
|
||||
default:
|
||||
return 1; /* dont bother with unknown hash types */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Zero-pad signature to expected size if necessary */
|
||||
siglen = SECKEY_SignatureLen(key);
|
||||
padlen = siglen - sig->len;
|
||||
if (padlen) {
|
||||
padded = SECITEM_AllocItem(NULL, NULL, siglen);
|
||||
if (padded == NULL)
|
||||
return 1;
|
||||
memset(padded->data, 0, padlen);
|
||||
memcpy(padded->data + padlen, sig->data, sig->len);
|
||||
sig = padded;
|
||||
}
|
||||
|
||||
/* XXX VFY_VerifyDigest() is deprecated in NSS 3.12 */
|
||||
rc = VFY_VerifyDigest(&digest, key, sig, sigalg, NULL);
|
||||
|
||||
if (padded)
|
||||
SECITEM_ZfreeItem(padded, PR_TRUE);
|
||||
|
||||
return (rc != SECSuccess);
|
||||
}
|
||||
|
||||
static void pgpFreeSigRSADSA(pgpDigAlg sa)
|
||||
{
|
||||
SECITEM_ZfreeItem(sa->data, PR_TRUE);
|
||||
sa->data = NULL;
|
||||
}
|
||||
|
||||
static void pgpFreeKeyRSADSA(pgpDigAlg ka)
|
||||
{
|
||||
SECKEY_DestroyPublicKey(ka->data);
|
||||
ka->data = NULL;
|
||||
}
|
||||
|
||||
static int pgpSetMpiNULL(pgpDigAlg pgpkey, int num,
|
||||
const uint8_t *p, const uint8_t *pend)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int pgpVerifyNULL(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
|
||||
uint8_t *hash, size_t hashlen, int hash_algo)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
pgpDigAlg pgpPubkeyNew(int algo)
|
||||
{
|
||||
pgpDigAlg ka = xcalloc(1, sizeof(*ka));;
|
||||
|
||||
switch (algo) {
|
||||
case PGPPUBKEYALGO_RSA:
|
||||
ka->setmpi = pgpSetKeyMpiRSA;
|
||||
ka->free = pgpFreeKeyRSADSA;
|
||||
ka->mpis = 2;
|
||||
break;
|
||||
case PGPPUBKEYALGO_DSA:
|
||||
ka->setmpi = pgpSetKeyMpiDSA;
|
||||
ka->free = pgpFreeKeyRSADSA;
|
||||
ka->mpis = 4;
|
||||
break;
|
||||
default:
|
||||
ka->setmpi = pgpSetMpiNULL;
|
||||
ka->mpis = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
ka->verify = pgpVerifyNULL; /* keys can't be verified */
|
||||
|
||||
return ka;
|
||||
}
|
||||
|
||||
pgpDigAlg pgpSignatureNew(int algo)
|
||||
{
|
||||
pgpDigAlg sa = xcalloc(1, sizeof(*sa));
|
||||
|
||||
switch (algo) {
|
||||
case PGPPUBKEYALGO_RSA:
|
||||
sa->setmpi = pgpSetSigMpiRSA;
|
||||
sa->free = pgpFreeSigRSADSA;
|
||||
sa->verify = pgpVerifySigRSA;
|
||||
sa->mpis = 1;
|
||||
break;
|
||||
case PGPPUBKEYALGO_DSA:
|
||||
sa->setmpi = pgpSetSigMpiDSA;
|
||||
sa->free = pgpFreeSigRSADSA;
|
||||
sa->verify = pgpVerifySigDSA;
|
||||
sa->mpis = 2;
|
||||
break;
|
||||
default:
|
||||
sa->setmpi = pgpSetMpiNULL;
|
||||
sa->verify = pgpVerifyNULL;
|
||||
sa->mpis = -1;
|
||||
break;
|
||||
}
|
||||
return sa;
|
||||
}
|
||||
|
403
rpmio/rpmpgp.c
403
rpmio/rpmpgp.c
|
@ -5,8 +5,8 @@
|
|||
|
||||
#include "system.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <netinet/in.h>
|
||||
#include <rpm/rpmstring.h>
|
||||
#include <rpm/rpmlog.h>
|
||||
|
||||
|
@ -17,9 +17,6 @@
|
|||
|
||||
static int _print = 0;
|
||||
|
||||
static int _crypto_initialized = 0;
|
||||
static int _new_process = 1;
|
||||
|
||||
typedef const struct pgpValTbl_s {
|
||||
int val;
|
||||
char const * const str;
|
||||
|
@ -242,28 +239,6 @@ static void pgpPrtVal(const char * pre, pgpValTbl vs, uint8_t val)
|
|||
fprintf(stderr, "%s(%u)", pgpValStr(vs, val), (unsigned)val);
|
||||
}
|
||||
|
||||
/** \ingroup rpmpgp
|
||||
* Return no. of bits in a multiprecision integer.
|
||||
* @param p pointer to multiprecision integer
|
||||
* @return no. of bits
|
||||
*/
|
||||
static
|
||||
unsigned int pgpMpiBits(const uint8_t *p)
|
||||
{
|
||||
return ((p[0] << 8) | p[1]);
|
||||
}
|
||||
|
||||
/** \ingroup rpmpgp
|
||||
* Return no. of bytes in a multiprecision integer.
|
||||
* @param p pointer to multiprecision integer
|
||||
* @return no. of bytes
|
||||
*/
|
||||
static
|
||||
size_t pgpMpiLen(const uint8_t *p)
|
||||
{
|
||||
return (2 + ((pgpMpiBits(p)+7)>>3));
|
||||
}
|
||||
|
||||
/** \ingroup rpmpgp
|
||||
* Return hex formatted representation of a multiprecision integer.
|
||||
* @param p bytes
|
||||
|
@ -296,90 +271,6 @@ int pgpValTok(pgpValTbl vs, const char * s, const char * se)
|
|||
} while ((++vs)->val != -1);
|
||||
return vs->val;
|
||||
}
|
||||
/**
|
||||
* @return 0 on success
|
||||
*/
|
||||
static int pgpMpiSet(unsigned int lbits, uint8_t *dest,
|
||||
const uint8_t * p, const uint8_t * pend)
|
||||
{
|
||||
unsigned int mbits = pgpMpiBits(p);
|
||||
unsigned int nbits;
|
||||
size_t nbytes;
|
||||
uint8_t *t = dest;
|
||||
unsigned int ix;
|
||||
|
||||
if ((p + ((mbits+7) >> 3)) > pend)
|
||||
return 1;
|
||||
|
||||
if (mbits > lbits)
|
||||
return 1;
|
||||
|
||||
nbits = (lbits > mbits ? lbits : mbits);
|
||||
nbytes = ((nbits + 7) >> 3);
|
||||
ix = (nbits - mbits) >> 3;
|
||||
|
||||
if (ix > 0)
|
||||
memset(t, '\0', ix);
|
||||
memcpy(t+ix, p+2, nbytes-ix);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return NULL on error
|
||||
*/
|
||||
static SECItem *pgpMpiItem(PRArenaPool *arena, SECItem *item,
|
||||
const uint8_t *p, const uint8_t *pend)
|
||||
{
|
||||
size_t nbytes = pgpMpiLen(p)-2;
|
||||
|
||||
if (p + nbytes + 2 > pend)
|
||||
return NULL;
|
||||
|
||||
if (item == NULL) {
|
||||
if ((item=SECITEM_AllocItem(arena, item, nbytes)) == NULL)
|
||||
return item;
|
||||
} else {
|
||||
if (arena != NULL)
|
||||
item->data = PORT_ArenaGrow(arena, item->data, item->len, nbytes);
|
||||
else
|
||||
item->data = PORT_Realloc(item->data, nbytes);
|
||||
|
||||
if (item->data == NULL) {
|
||||
if (arena == NULL)
|
||||
SECITEM_FreeItem(item, PR_TRUE);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(item->data, p+2, nbytes);
|
||||
item->len = nbytes;
|
||||
return item;
|
||||
}
|
||||
/*@=boundswrite@*/
|
||||
|
||||
static SECKEYPublicKey *pgpNewPublicKey(KeyType type)
|
||||
{
|
||||
PRArenaPool *arena;
|
||||
SECKEYPublicKey *key;
|
||||
|
||||
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
||||
if (arena == NULL)
|
||||
return NULL;
|
||||
|
||||
key = PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey));
|
||||
|
||||
if (key == NULL) {
|
||||
PORT_FreeArena(arena, PR_FALSE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
key->keyType = type;
|
||||
key->pkcs11ID = CK_INVALID_HANDLE;
|
||||
key->pkcs11Slot = NULL;
|
||||
key->arena = arena;
|
||||
return key;
|
||||
}
|
||||
|
||||
/** \ingroup rpmpgp
|
||||
* Decode length from 1, 2, or 5 octet body length encoding, used in
|
||||
|
@ -580,248 +471,6 @@ static int pgpPrtSubType(const uint8_t *h, size_t hlen, pgpSigType sigtype,
|
|||
return (hlen != 0); /* non-zero hlen is an error */
|
||||
}
|
||||
|
||||
#ifndef DSA_SUBPRIME_LEN
|
||||
#define DSA_SUBPRIME_LEN 20
|
||||
#endif
|
||||
|
||||
static int pgpSetSigMpiDSA(pgpDigAlg pgpsig, int num,
|
||||
const uint8_t *p, const uint8_t *pend)
|
||||
{
|
||||
SECItem *sig = pgpsig->data;
|
||||
int lbits = DSA_SUBPRIME_LEN * 8;
|
||||
int rc = 1; /* assume failure */
|
||||
|
||||
switch (num) {
|
||||
case 0:
|
||||
sig = pgpsig->data = SECITEM_AllocItem(NULL, NULL, 2*DSA_SUBPRIME_LEN);
|
||||
memset(sig->data, 0, 2 * DSA_SUBPRIME_LEN);
|
||||
rc = pgpMpiSet(lbits, sig->data, p, pend);
|
||||
break;
|
||||
case 1:
|
||||
if (sig && pgpMpiSet(lbits, sig->data+DSA_SUBPRIME_LEN, p, pend) == 0) {
|
||||
SECItem *signew = SECITEM_AllocItem(NULL, NULL, 0);
|
||||
if (signew && DSAU_EncodeDerSig(signew, sig) == SECSuccess) {
|
||||
SECITEM_FreeItem(sig, PR_TRUE);
|
||||
pgpsig->data = signew;
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pgpSetKeyMpiDSA(pgpDigAlg pgpkey, int num,
|
||||
const uint8_t *p, const uint8_t *pend)
|
||||
{
|
||||
SECItem *mpi = NULL;
|
||||
SECKEYPublicKey *key = pgpkey->data;
|
||||
|
||||
if (key == NULL)
|
||||
key = pgpkey->data = pgpNewPublicKey(dsaKey);
|
||||
|
||||
if (key) {
|
||||
switch (num) {
|
||||
case 0:
|
||||
mpi = pgpMpiItem(key->arena, &key->u.dsa.params.prime, p, pend);
|
||||
break;
|
||||
case 1:
|
||||
mpi = pgpMpiItem(key->arena, &key->u.dsa.params.subPrime, p, pend);
|
||||
break;
|
||||
case 2:
|
||||
mpi = pgpMpiItem(key->arena, &key->u.dsa.params.base, p, pend);
|
||||
break;
|
||||
case 3:
|
||||
mpi = pgpMpiItem(key->arena, &key->u.dsa.publicValue, p, pend);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (mpi == NULL);
|
||||
}
|
||||
|
||||
static int pgpVerifySigDSA(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
|
||||
uint8_t *hash, size_t hashlen, int hash_algo)
|
||||
{
|
||||
SECItem digest = { .type = siBuffer, .data = hash, .len = hashlen };
|
||||
SECOidTag sigalg = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
|
||||
SECStatus rc;
|
||||
|
||||
/* XXX VFY_VerifyDigest() is deprecated in NSS 3.12 */
|
||||
rc = VFY_VerifyDigest(&digest, pgpkey->data, pgpsig->data, sigalg, NULL);
|
||||
|
||||
return (rc != SECSuccess);
|
||||
}
|
||||
|
||||
static int pgpSetSigMpiRSA(pgpDigAlg pgpsig, int num,
|
||||
const uint8_t *p, const uint8_t *pend)
|
||||
{
|
||||
SECItem *sigitem = NULL;
|
||||
|
||||
if (num == 0) {
|
||||
sigitem = pgpMpiItem(NULL, pgpsig->data, p, pend);
|
||||
if (sigitem)
|
||||
pgpsig->data = sigitem;
|
||||
}
|
||||
return (sigitem == NULL);
|
||||
}
|
||||
|
||||
static int pgpSetKeyMpiRSA(pgpDigAlg pgpkey, int num,
|
||||
const uint8_t *p, const uint8_t *pend)
|
||||
{
|
||||
SECItem *kitem = NULL;
|
||||
SECKEYPublicKey *key = pgpkey->data;
|
||||
|
||||
if (key == NULL)
|
||||
key = pgpkey->data = pgpNewPublicKey(rsaKey);
|
||||
|
||||
if (key) {
|
||||
switch (num) {
|
||||
case 0:
|
||||
kitem = pgpMpiItem(key->arena, &key->u.rsa.modulus, p, pend);
|
||||
break;
|
||||
case 1:
|
||||
kitem = pgpMpiItem(key->arena, &key->u.rsa.publicExponent, p, pend);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (kitem == NULL);
|
||||
}
|
||||
|
||||
static int pgpVerifySigRSA(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
|
||||
uint8_t *hash, size_t hashlen, int hash_algo)
|
||||
{
|
||||
SECItem digest = { .type = siBuffer, .data = hash, .len = hashlen };
|
||||
SECItem *sig = pgpsig->data;
|
||||
SECKEYPublicKey *key = pgpkey->data;
|
||||
SECItem *padded = NULL;
|
||||
SECOidTag sigalg;
|
||||
SECStatus rc = SECFailure;
|
||||
size_t siglen, padlen;
|
||||
|
||||
switch (hash_algo) {
|
||||
case PGPHASHALGO_MD5:
|
||||
sigalg = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
|
||||
break;
|
||||
case PGPHASHALGO_MD2:
|
||||
sigalg = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION;
|
||||
break;
|
||||
case PGPHASHALGO_SHA1:
|
||||
sigalg = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
|
||||
break;
|
||||
case PGPHASHALGO_SHA256:
|
||||
sigalg = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
|
||||
break;
|
||||
case PGPHASHALGO_SHA384:
|
||||
sigalg = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
|
||||
break;
|
||||
case PGPHASHALGO_SHA512:
|
||||
sigalg = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
|
||||
break;
|
||||
default:
|
||||
return 1; /* dont bother with unknown hash types */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Zero-pad signature to expected size if necessary */
|
||||
siglen = SECKEY_SignatureLen(key);
|
||||
padlen = siglen - sig->len;
|
||||
if (padlen) {
|
||||
padded = SECITEM_AllocItem(NULL, NULL, siglen);
|
||||
if (padded == NULL)
|
||||
return 1;
|
||||
memset(padded->data, 0, padlen);
|
||||
memcpy(padded->data + padlen, sig->data, sig->len);
|
||||
sig = padded;
|
||||
}
|
||||
|
||||
/* XXX VFY_VerifyDigest() is deprecated in NSS 3.12 */
|
||||
rc = VFY_VerifyDigest(&digest, key, sig, sigalg, NULL);
|
||||
|
||||
if (padded)
|
||||
SECITEM_ZfreeItem(padded, PR_TRUE);
|
||||
|
||||
return (rc != SECSuccess);
|
||||
}
|
||||
|
||||
static void pgpFreeSigRSADSA(pgpDigAlg sa)
|
||||
{
|
||||
SECITEM_ZfreeItem(sa->data, PR_TRUE);
|
||||
sa->data = NULL;
|
||||
}
|
||||
|
||||
static void pgpFreeKeyRSADSA(pgpDigAlg ka)
|
||||
{
|
||||
SECKEY_DestroyPublicKey(ka->data);
|
||||
ka->data = NULL;
|
||||
}
|
||||
|
||||
static int pgpSetMpiNULL(pgpDigAlg pgpkey, int num,
|
||||
const uint8_t *p, const uint8_t *pend)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int pgpVerifyNULL(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
|
||||
uint8_t *hash, size_t hashlen, int hash_algo)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
pgpDigAlg pgpPubkeyNew(int algo)
|
||||
{
|
||||
pgpDigAlg ka = xcalloc(1, sizeof(*ka));;
|
||||
|
||||
switch (algo) {
|
||||
case PGPPUBKEYALGO_RSA:
|
||||
ka->setmpi = pgpSetKeyMpiRSA;
|
||||
ka->free = pgpFreeKeyRSADSA;
|
||||
ka->mpis = 2;
|
||||
break;
|
||||
case PGPPUBKEYALGO_DSA:
|
||||
ka->setmpi = pgpSetKeyMpiDSA;
|
||||
ka->free = pgpFreeKeyRSADSA;
|
||||
ka->mpis = 4;
|
||||
break;
|
||||
default:
|
||||
ka->setmpi = pgpSetMpiNULL;
|
||||
ka->mpis = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
ka->verify = pgpVerifyNULL; /* keys can't be verified */
|
||||
|
||||
return ka;
|
||||
}
|
||||
|
||||
pgpDigAlg pgpSignatureNew(int algo)
|
||||
{
|
||||
pgpDigAlg sa = xcalloc(1, sizeof(*sa));
|
||||
|
||||
switch (algo) {
|
||||
case PGPPUBKEYALGO_RSA:
|
||||
sa->setmpi = pgpSetSigMpiRSA;
|
||||
sa->free = pgpFreeSigRSADSA;
|
||||
sa->verify = pgpVerifySigRSA;
|
||||
sa->mpis = 1;
|
||||
break;
|
||||
case PGPPUBKEYALGO_DSA:
|
||||
sa->setmpi = pgpSetSigMpiDSA;
|
||||
sa->free = pgpFreeSigRSADSA;
|
||||
sa->verify = pgpVerifySigDSA;
|
||||
sa->mpis = 2;
|
||||
break;
|
||||
default:
|
||||
sa->setmpi = pgpSetMpiNULL;
|
||||
sa->verify = pgpVerifyNULL;
|
||||
sa->mpis = -1;
|
||||
break;
|
||||
}
|
||||
return sa;
|
||||
}
|
||||
|
||||
pgpDigAlg pgpDigAlgFree(pgpDigAlg alg)
|
||||
{
|
||||
if (alg) {
|
||||
|
@ -1514,51 +1163,3 @@ char * pgpArmorWrap(int atype, const unsigned char * s, size_t ns)
|
|||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only flag for re-initialization here, in the common case the child
|
||||
* exec()'s something else shutting down NSS here would be waste of time.
|
||||
*/
|
||||
static void at_forkchild(void)
|
||||
{
|
||||
_new_process = 1;
|
||||
}
|
||||
|
||||
int rpmInitCrypto(void)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
/* Lazy NSS shutdown for re-initialization after fork() */
|
||||
if (_new_process && _crypto_initialized) {
|
||||
rpmFreeCrypto();
|
||||
}
|
||||
|
||||
/* Initialize NSS if not already done */
|
||||
if (!_crypto_initialized) {
|
||||
if (NSS_NoDB_Init(NULL) != SECSuccess) {
|
||||
rc = -1;
|
||||
} else {
|
||||
_crypto_initialized = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Register one post-fork handler per process */
|
||||
if (_new_process) {
|
||||
if (pthread_atfork(NULL, NULL, at_forkchild) != 0) {
|
||||
rpmlog(RPMLOG_WARNING, _("Failed to register fork handler: %m\n"));
|
||||
}
|
||||
_new_process = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int rpmFreeCrypto(void)
|
||||
{
|
||||
int rc = 0;
|
||||
if (_crypto_initialized) {
|
||||
rc = (NSS_Shutdown() != SECSuccess);
|
||||
_crypto_initialized = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue