Back to index

lightning-sunbird  0.9+nobinonly
Classes | Enumerations | Functions | Variables
secvfy.c File Reference
#include <stdio.h>
#include "cryptohi.h"
#include "sechash.h"
#include "keyhi.h"
#include "secasn1.h"
#include "secoid.h"
#include "pk11func.h"
#include "secdig.h"
#include "secerr.h"
#include "secport.h"

Go to the source code of this file.

Classes

struct  VFYContextStr
union  VFYContextStr.u

Enumerations

enum  VerifyType {
  VFY_RSA, VFY_DSA, VFY_ECDSA, VFY_RSA,
  VFY_DSA, VFY_ECDSA
}

Functions

static SECStatus DecryptSigBlock (SECOidTag *tagp, unsigned char *digest, unsigned int *digestlen, unsigned int maxdigestlen, SECKEYPublicKey *key, const SECItem *sig, char *wincx)
static SECStatus decodeECorDSASignature (SECOidTag algid, SECItem *sig, unsigned char *dsig, unsigned int len)
static SECStatus decodeSigAlg (SECOidTag alg, const SECItem *params, const SECKEYPublicKey *key, SECOidTag *hashalg)
static VFYContext * vfy_CreateContextPrivate (const SECKEYPublicKey *key, const SECItem *sig, SECOidTag algid, const SECItem *params, void *wincx)
VFYContext * VFY_CreateContext (SECKEYPublicKey *key, SECItem *sig, SECOidTag algid, void *wincx)
void VFY_DestroyContext (VFYContext *cx, PRBool freeit)
SECStatus VFY_Begin (VFYContext *cx)
SECStatus VFY_Update (VFYContext *cx, unsigned char *input, unsigned inputLen)
SECStatus VFY_EndWithSignature (VFYContext *cx, SECItem *sig)
SECStatus VFY_End (VFYContext *cx)
SECStatus VFY_VerifyDigest (SECItem *digest, SECKEYPublicKey *key, SECItem *sig, SECOidTag algid, void *wincx)
static SECStatus vfy_VerifyDataPrivate (const unsigned char *buf, int len, const SECKEYPublicKey *key, const SECItem *sig, SECOidTag algid, const SECItem *params, void *wincx)
SECStatus VFY_VerifyData (unsigned char *buf, int len, SECKEYPublicKey *key, SECItem *sig, SECOidTag algid, void *wincx)
SECStatus VFY_VerifyDataWithAlgorithmID (const unsigned char *buf, int len, const SECKEYPublicKey *key, const SECItem *sig, const SECAlgorithmID *sigAlgorithm, SECOidTag *reserved, void *wincx)

Variables

static const SEC_ASN1Template hashParameterTemplate []

Class Documentation

union VFYContextStr.u

Definition at line 135 of file secvfy.c.

Class Members
unsigned char buffer
unsigned char dsasig
unsigned char ecdsasig
unsigned char rsadigest

Enumeration Type Documentation

enum VerifyType
Enumerator:
VFY_RSA 
VFY_DSA 
VFY_ECDSA 
VFY_RSA 
VFY_DSA 
VFY_ECDSA 

Definition at line 120 of file secvfy.c.


Function Documentation

static SECStatus decodeECorDSASignature ( SECOidTag  algid,
SECItem *  sig,
unsigned char *  dsig,
unsigned int  len 
) [static]

Definition at line 162 of file secvfy.c.

                                       {
    SECItem *dsasig = NULL; /* also used for ECDSA */
    SECStatus rv=SECSuccess;

    switch (algid) {
    case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
    case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE:
    case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE:
    case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE:
    case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST:
    case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST:
       if (len > MAX_ECKEY_LEN * 2) {
           PORT_SetError(SEC_ERROR_BAD_DER);
           return SECFailure;
       }
       /* fall through */
    case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST:
    case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST:
    case SEC_OID_ANSIX9_DSA_SIGNATURE:
       dsasig = DSAU_DecodeDerSigToLen(sig, len);

       if ((dsasig == NULL) || (dsasig->len != len)) {
           rv = SECFailure;
       } else {
           PORT_Memcpy(dsig, dsasig->data, dsasig->len);
       }
       break;
    default:
        if (sig->len != len) {
           rv = SECFailure;
       } else {
           PORT_Memcpy(dsig, sig->data, sig->len);
       }
       break;
    }

    if (dsasig != NULL) SECITEM_FreeItem(dsasig, PR_TRUE);
    if (rv == SECFailure) PORT_SetError(SEC_ERROR_BAD_DER);
    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static SECStatus decodeSigAlg ( SECOidTag  alg,
const SECItem *  params,
const SECKEYPublicKey *  key,
SECOidTag hashalg 
) [static]

Definition at line 223 of file secvfy.c.

{
    PRArenaPool *arena;
    SECStatus rv;
    SECItem oid;
    unsigned int len;
    PR_ASSERT(hashalg!=NULL);

    switch (alg) {
      /* We probably shouldn't be generating MD2 signatures either */
      case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
        *hashalg = SEC_OID_MD2;
       break;
      case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
        *hashalg = SEC_OID_MD5;
       break;
      case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
      case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE:
        *hashalg = SEC_OID_SHA1;
       break;

      case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE:
      case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
       *hashalg = SEC_OID_SHA256;
       break;
      case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE:
      case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
       *hashalg = SEC_OID_SHA384;
       break;
      case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE:
      case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
       *hashalg = SEC_OID_SHA512;
       break;
      case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST:
       /* This is an EC algorithm. Recommended means the largest
        * hash algorithm that is not truncated by the keysize of 
        * the EC algorithm. Note that key strength is in bytes and
        * algorithms are specified in bits. Never use an algorithm
        * weaker than sha1. */
       len = SECKEY_PublicKeyStrength((SECKEYPublicKey *)key);
       if (len < 28) { /* 28 bytes == 244 bits */
           *hashalg = SEC_OID_SHA1;
       } else if (len < 32) { /* 32 bytes == 256 bits */
           /* we don't support 244 bit hash algorithms */
           PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
           return SECFailure;
       } else if (len < 48) { /* 48 bytes == 384 bits */
           *hashalg = SEC_OID_SHA256;
       } else if (len < 64) { /* 48 bytes == 512 bits */
           *hashalg = SEC_OID_SHA384;
       } else {
           /* use the largest in this case */
           *hashalg = SEC_OID_SHA512;
       }
       break;
      case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST:
       if (params == NULL) {
           PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
           return SECFailure;
       }
       arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
       if (arena == NULL) {
           return SECFailure;
       }
       rv = SEC_QuickDERDecodeItem(arena, &oid, hashParameterTemplate, params);
       if (rv != SECSuccess) {
           PORT_FreeArena(arena, PR_FALSE);
           return rv;
       }

       *hashalg = SECOID_FindOIDTag(&oid);
       PORT_FreeArena(arena, PR_FALSE);
       if (*hashalg == SEC_OID_UNKNOWN) {
           PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
           return SECFailure;
       }
       break;

      /* what about normal DSA? */
      case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST:
      case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST:
      case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
        *hashalg = SEC_OID_SHA1;
       break;
      case SEC_OID_MISSI_DSS:
      case SEC_OID_MISSI_KEA_DSS:
      case SEC_OID_MISSI_KEA_DSS_OLD:
      case SEC_OID_MISSI_DSS_OLD:
        *hashalg = SEC_OID_SHA1;
       break;
      /* we don't implement MD4 hashes */
      case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
      default:
       return SECFailure;
    }
    return SECSuccess;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static SECStatus DecryptSigBlock ( SECOidTag tagp,
unsigned char *  digest,
unsigned int digestlen,
unsigned int  maxdigestlen,
SECKEYPublicKey *  key,
const SECItem *  sig,
char *  wincx 
) [static]

Definition at line 61 of file secvfy.c.

{
    SGNDigestInfo *di   = NULL;
    unsigned char *buf  = NULL;
    SECStatus      rv;
    SECOidTag      tag;
    SECItem        it;

    if (key == NULL) goto loser;

    it.len  = SECKEY_PublicKeyStrength(key);
    if (!it.len) goto loser;
    it.data = buf = (unsigned char *)PORT_Alloc(it.len);
    if (!buf) goto loser;

    /* decrypt the block */
    rv = PK11_VerifyRecover(key, (SECItem *)sig, &it, wincx);
    if (rv != SECSuccess) goto loser;

    di = SGN_DecodeDigestInfo(&it);
    if (di == NULL) goto sigloser;

    /*
    ** Finally we have the digest info; now we can extract the algorithm
    ** ID and the signature block
    */
    tag = SECOID_GetAlgorithmTag(&di->digestAlgorithm);
    /* Check that tag is an appropriate algorithm */
    if (tag == SEC_OID_UNKNOWN) {
       goto sigloser;
    }
    /* make sure the "parameters" are not too bogus. */
    if (di->digestAlgorithm.parameters.len > 2) {
       goto sigloser;
    }
    if (di->digest.len > maxdigestlen) {
       PORT_SetError(SEC_ERROR_OUTPUT_LEN);
       goto loser;
    }
    PORT_Memcpy(digest, di->digest.data, di->digest.len);
    *tagp = tag;
    *digestlen = di->digest.len;
    goto done;

  sigloser:
    PORT_SetError(SEC_ERROR_BAD_SIGNATURE);

  loser:
    rv = SECFailure;

  done:
    if (di   != NULL) SGN_DestroyDigestInfo(di);
    if (buf  != NULL) PORT_Free(buf);
    
    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

SECStatus VFY_Begin ( VFYContext *  cx)

Definition at line 428 of file secvfy.c.

{
    if (cx->hashcx != NULL) {
       (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
       cx->hashcx = NULL;
    }

    cx->hashobj = HASH_GetHashObjectByOidTag(cx->alg);
    if (!cx->hashobj) 
       return SECFailure;   /* error code is set */

    cx->hashcx = (*cx->hashobj->create)();
    if (cx->hashcx == NULL)
       return SECFailure;

    (*cx->hashobj->begin)(cx->hashcx);
    return SECSuccess;
}

Here is the call graph for this function:

Here is the caller graph for this function:

VFYContext* VFY_CreateContext ( SECKEYPublicKey *  key,
SECItem *  sig,
SECOidTag  algid,
void wincx 
)

Definition at line 404 of file secvfy.c.

{
   return vfy_CreateContextPrivate(key, sig, algid, NULL, wincx);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static VFYContext* vfy_CreateContextPrivate ( const SECKEYPublicKey *  key,
const SECItem *  sig,
SECOidTag  algid,
const SECItem *  params,
void wincx 
) [static]

Definition at line 323 of file secvfy.c.

{
    VFYContext *cx;
    SECStatus rv;
    unsigned int sigLen;

    cx = (VFYContext*) PORT_ZAlloc(sizeof(VFYContext));
    if (cx) {
        cx->wincx = wincx;
       cx->hasSignature = (sig != NULL);
       cx->sigAlg = algid;
       rv = SECSuccess;
       switch (key->keyType) {
       case rsaKey:
           cx->type = VFY_RSA;
           /* keep our own copy */
           cx->key = SECKEY_CopyPublicKey((SECKEYPublicKey *)key); 
           if (sig) {
              SECOidTag hashid = SEC_OID_UNKNOWN;
              unsigned int digestlen = 0;
              rv = DecryptSigBlock(&hashid, cx->u.buffer, &digestlen,
                     HASH_LENGTH_MAX, cx->key, sig, (char*)wincx);
              cx->alg = hashid;
              cx->rsadigestlen = digestlen;
           } else {
              rv = decodeSigAlg(algid, params, key, &cx->alg);
           }
           break;
       case fortezzaKey:
       case dsaKey:
       case ecKey:
           if (key->keyType == ecKey) {
               cx->type = VFY_ECDSA;
              /* Unlike DSA, ECDSA does not have a fixed signature length
               * (it depends on the key size)
               */
              sigLen = SECKEY_SignatureLen(key);
           } else {
               cx->type = VFY_DSA;
              sigLen = DSA_SIGNATURE_LEN;
           }
           if (sigLen == 0) {
              rv = SECFailure;
              break;
           }
           rv = decodeSigAlg(algid, params, key, &cx->alg);
           if (rv != SECSuccess) {
              break;
           }
           cx->key = SECKEY_CopyPublicKey((SECKEYPublicKey *)key);
           if (sig) {
               rv = decodeECorDSASignature(algid,sig,cx->u.buffer,sigLen);
           }
           break;
       default:
           rv = SECFailure;
           break;
       }
       if (rv) goto loser;
       switch (cx->alg) {
       case SEC_OID_MD2:
       case SEC_OID_MD5:
       case SEC_OID_SHA1:
       case SEC_OID_SHA256:
       case SEC_OID_SHA384:
       case SEC_OID_SHA512:
           break;
       default:
           PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
           goto loser;
       }
    }
    return cx;

  loser:
    VFY_DestroyContext(cx, PR_TRUE);
    return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void VFY_DestroyContext ( VFYContext *  cx,
PRBool  freeit 
)

Definition at line 411 of file secvfy.c.

{
    if (cx) {
       if (cx->hashcx != NULL) {
           (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
           cx->hashcx = NULL;
       }
       if (cx->key) {
           SECKEY_DestroyPublicKey(cx->key);
       }
       if (freeit) {
           PORT_ZFree(cx, sizeof(VFYContext));
       }
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

SECStatus VFY_End ( VFYContext *  cx)

Definition at line 527 of file secvfy.c.

Here is the call graph for this function:

Here is the caller graph for this function:

SECStatus VFY_EndWithSignature ( VFYContext *  cx,
SECItem *  sig 
)

Definition at line 459 of file secvfy.c.

{
    unsigned char final[HASH_LENGTH_MAX];
    unsigned part;
    SECItem hash,dsasig; /* dsasig is also used for ECDSA */
    SECStatus rv;

    if ((cx->hasSignature == PR_FALSE) && (sig == NULL)) {
       PORT_SetError(SEC_ERROR_INVALID_ARGS);
       return SECFailure;
    }

    if (cx->hashcx == NULL) {
       PORT_SetError(SEC_ERROR_INVALID_ARGS);
       return SECFailure;
    }
    (*cx->hashobj->end)(cx->hashcx, final, &part, sizeof(final));
    switch (cx->type) {
      case VFY_DSA:
      case VFY_ECDSA:
       dsasig.data = cx->u.buffer;
       if (cx->type == VFY_DSA) {
           dsasig.len = DSA_SIGNATURE_LEN;
       } else {
           dsasig.len = SECKEY_SignatureLen(cx->key);
       }
       if (dsasig.len == 0) {
           return SECFailure;
       }
       if (sig) {
           rv = decodeECorDSASignature(cx->sigAlg,sig,dsasig.data,
                                   dsasig.len);
           if (rv != SECSuccess) {
              PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
              return SECFailure;
           }
       } 
       hash.data = final;
       hash.len = part;
       if (PK11_Verify(cx->key,&dsasig,&hash,cx->wincx) != SECSuccess) {
              PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
              return SECFailure;
       }
       break;
      case VFY_RSA:
       if (sig) {
           SECOidTag hashid = SEC_OID_UNKNOWN;
           rv = DecryptSigBlock(&hashid, cx->u.buffer, &cx->rsadigestlen,
                  HASH_LENGTH_MAX, cx->key, sig, (char*)cx->wincx);
           if ((rv != SECSuccess) || (hashid != cx->alg)) {
              PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
              return SECFailure;
           }
       }
       if ((part != cx->rsadigestlen) ||
              PORT_Memcmp(final, cx->u.buffer, part)) {
           PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
           return SECFailure;
       }
       break;
      default:
       PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
       return SECFailure; /* shouldn't happen */
    }
    return SECSuccess;
}

Here is the call graph for this function:

Here is the caller graph for this function:

SECStatus VFY_Update ( VFYContext *  cx,
unsigned char *  input,
unsigned  inputLen 
)

Definition at line 448 of file secvfy.c.

{
    if (cx->hashcx == NULL) {
       PORT_SetError(SEC_ERROR_INVALID_ARGS);
       return SECFailure;
    }
    (*cx->hashobj->update)(cx->hashcx, input, inputLen);
    return SECSuccess;
}

Here is the call graph for this function:

SECStatus VFY_VerifyData ( unsigned char *  buf,
int  len,
SECKEYPublicKey *  key,
SECItem *  sig,
SECOidTag  algid,
void wincx 
)

Definition at line 612 of file secvfy.c.

{
    return vfy_VerifyDataPrivate(buf, len, key, sig, algid, NULL, wincx);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static SECStatus vfy_VerifyDataPrivate ( const unsigned char *  buf,
int  len,
const SECKEYPublicKey *  key,
const SECItem *  sig,
SECOidTag  algid,
const SECItem *  params,
void wincx 
) [static]

Definition at line 589 of file secvfy.c.

{
    SECStatus rv;
    VFYContext *cx;

    cx = vfy_CreateContextPrivate(key, sig, algid, params, wincx);
    if (cx == NULL)
       return SECFailure;

    rv = VFY_Begin(cx);
    if (rv == SECSuccess) {
       rv = VFY_Update(cx, (unsigned char *)buf, len);
       if (rv == SECSuccess)
           rv = VFY_End(cx);
    }

    VFY_DestroyContext(cx, PR_TRUE);
    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

SECStatus VFY_VerifyDataWithAlgorithmID ( const unsigned char *  buf,
int  len,
const SECKEYPublicKey *  key,
const SECItem *  sig,
const SECAlgorithmID *  sigAlgorithm,
SECOidTag reserved,
void wincx 
)

Definition at line 622 of file secvfy.c.

{
    /* the hash parameter is only provided to match the NSS 3.12 signature */
    PORT_Assert(reserved == NULL);
    if (reserved) {
       /* shouldn't happen, This function is not exported, and the only
        * NSS callers pass 'NULL' */
       PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
       return SECFailure;
    }
    return vfy_VerifyDataPrivate(buf, len, key, sig, 
           SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm),
           &sigAlgorithm->parameters, wincx);
}

Here is the call graph for this function:

Here is the caller graph for this function:

SECStatus VFY_VerifyDigest ( SECItem *  digest,
SECKEYPublicKey *  key,
SECItem *  sig,
SECOidTag  algid,
void wincx 
)

Definition at line 540 of file secvfy.c.

{
    SECStatus rv;
    VFYContext *cx;
    SECItem dsasig; /* also used for ECDSA */

    rv = SECFailure;

    cx = VFY_CreateContext(key, sig, algid, wincx);
    if (cx != NULL) {
       switch (key->keyType) {
       case rsaKey:
           if ((digest->len != cx->rsadigestlen) ||
              PORT_Memcmp(digest->data, cx->u.buffer, digest->len)) {
              PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
           } else {
              rv = SECSuccess;
           }
           break;
       case fortezzaKey:
       case dsaKey:
       case ecKey:
           dsasig.data = cx->u.buffer;
           if (key->keyType == ecKey) {
              dsasig.len = SECKEY_SignatureLen(cx->key);
           } else {
              /* magic size of dsa signature */
              dsasig.len = DSA_SIGNATURE_LEN;
           }
           if (dsasig.len == 0) {
              break;
           }
           if (PK11_Verify(cx->key, &dsasig, digest, cx->wincx)
              != SECSuccess) {
              PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
           } else {
              rv = SECSuccess;
           }
           break;
       default:
           break;
       }
       VFY_DestroyContext(cx, PR_TRUE);
    }
    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Initial value:
{
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECItem) },
    { SEC_ASN1_OBJECT_ID, 0 },
    { SEC_ASN1_SKIP_REST },
    { 0, }
}

Definition at line 204 of file secvfy.c.