security/nss/lib/cryptohi/secvfy.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /*
     2  * Verification stuff.
     3  *
     4  * This Source Code Form is subject to the terms of the Mozilla Public
     5  * License, v. 2.0. If a copy of the MPL was not distributed with this
     6  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     8 #include <stdio.h>
     9 #include "cryptohi.h"
    10 #include "sechash.h"
    11 #include "keyhi.h"
    12 #include "secasn1.h"
    13 #include "secoid.h"
    14 #include "pk11func.h"
    15 #include "pkcs1sig.h"
    16 #include "secdig.h"
    17 #include "secerr.h"
    18 #include "keyi.h"
    20 /*
    21 ** Recover the DigestInfo from an RSA PKCS#1 signature.
    22 **
    23 ** If givenDigestAlg != SEC_OID_UNKNOWN, copy givenDigestAlg to digestAlgOut.
    24 ** Otherwise, parse the DigestInfo structure and store the decoded digest
    25 ** algorithm into digestAlgOut.
    26 **
    27 ** Store the encoded DigestInfo into digestInfo.
    28 ** Store the DigestInfo length into digestInfoLen.
    29 **
    30 ** This function does *not* verify that the AlgorithmIdentifier in the
    31 ** DigestInfo identifies givenDigestAlg or that the DigestInfo is encoded
    32 ** correctly; verifyPKCS1DigestInfo does that.
    33 **
    34 ** XXX this is assuming that the signature algorithm has WITH_RSA_ENCRYPTION
    35 */
    36 static SECStatus
    37 recoverPKCS1DigestInfo(SECOidTag givenDigestAlg,
    38                        /*out*/ SECOidTag* digestAlgOut,
    39                        /*out*/ unsigned char** digestInfo,
    40                        /*out*/ unsigned int* digestInfoLen,
    41                        SECKEYPublicKey* key,
    42                        const SECItem* sig, void* wincx)
    43 {
    44     SGNDigestInfo* di = NULL;
    45     SECItem it;
    46     PRBool rv = SECSuccess;
    48     PORT_Assert(digestAlgOut);
    49     PORT_Assert(digestInfo);
    50     PORT_Assert(digestInfoLen);
    51     PORT_Assert(key);
    52     PORT_Assert(key->keyType == rsaKey);
    53     PORT_Assert(sig);
    55     it.data = NULL;
    56     it.len  = SECKEY_PublicKeyStrength(key);
    57     if (it.len != 0) {
    58         it.data = (unsigned char *)PORT_Alloc(it.len);
    59     }
    60     if (it.len == 0 || it.data == NULL ) {
    61         rv = SECFailure;
    62     }
    64     if (rv == SECSuccess) {
    65         /* decrypt the block */
    66         rv = PK11_VerifyRecover(key, sig, &it, wincx);
    67     }
    69     if (rv == SECSuccess) {
    70         if (givenDigestAlg != SEC_OID_UNKNOWN) {
    71             /* We don't need to parse the DigestInfo if the caller gave us the
    72              * digest algorithm to use. Later verifyPKCS1DigestInfo will verify
    73              * that the DigestInfo identifies the given digest algorithm and
    74              * that the DigestInfo is encoded absolutely correctly.
    75              */
    76             *digestInfoLen = it.len;
    77             *digestInfo = (unsigned char*)it.data;
    78             *digestAlgOut = givenDigestAlg;
    79             return SECSuccess;
    80         }
    81     }
    83     if (rv == SECSuccess) {
    84         /* The caller didn't specify a digest algorithm to use, so choose the
    85          * digest algorithm by parsing the AlgorithmIdentifier within the
    86          * DigestInfo.
    87          */
    88         di = SGN_DecodeDigestInfo(&it);
    89         if (!di) {
    90             rv = SECFailure;
    91         }
    92     }
    94     if (rv == SECSuccess) {
    95         *digestAlgOut = SECOID_GetAlgorithmTag(&di->digestAlgorithm);
    96         if (*digestAlgOut == SEC_OID_UNKNOWN) {
    97             rv = SECFailure;
    98         }
    99     }
   101     if (di) {
   102         SGN_DestroyDigestInfo(di);
   103     }
   105     if (rv == SECSuccess) {
   106         *digestInfoLen = it.len;
   107         *digestInfo = (unsigned char*)it.data;
   108     } else {
   109         if (it.data) {
   110             PORT_Free(it.data);
   111         }
   112         *digestInfo = NULL;
   113         *digestInfoLen = 0;
   114         PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
   115     }
   117     return rv;
   118 }
   120 struct VFYContextStr {
   121     SECOidTag hashAlg;  /* the hash algorithm */
   122     SECKEYPublicKey *key;
   123     /*
   124      * This buffer holds either the digest or the full signature
   125      * depending on the type of the signature (key->keyType).  It is
   126      * defined as a union to make sure it always has enough space.
   127      *
   128      * Use the "buffer" union member to reference the buffer.
   129      * Note: do not take the size of the "buffer" union member.  Take
   130      * the size of the union or some other union member instead.
   131      */
   132     union {
   133 	unsigned char buffer[1];
   135 	/* the full DSA signature... 40 bytes */
   136 	unsigned char dsasig[DSA_MAX_SIGNATURE_LEN];
   137 	/* the full ECDSA signature */
   138 	unsigned char ecdsasig[2 * MAX_ECKEY_LEN];
   139     } u;
   140     unsigned int pkcs1RSADigestInfoLen;
   141     /* the encoded DigestInfo from a RSA PKCS#1 signature */
   142     unsigned char *pkcs1RSADigestInfo;
   143     void * wincx;
   144     void *hashcx;
   145     const SECHashObject *hashobj;
   146     SECOidTag encAlg;  /* enc alg */
   147     PRBool hasSignature;  /* true if the signature was provided in the
   148                            * VFY_CreateContext call.  If false, the
   149                            * signature must be provided with a
   150                            * VFY_EndWithSignature call. */
   151 };
   153 static SECStatus
   154 verifyPKCS1DigestInfo(const VFYContext* cx, const SECItem* digest)
   155 {
   156   SECItem pkcs1DigestInfo;
   157   pkcs1DigestInfo.data = cx->pkcs1RSADigestInfo;
   158   pkcs1DigestInfo.len = cx->pkcs1RSADigestInfoLen;
   159   return _SGN_VerifyPKCS1DigestInfo(
   160            cx->hashAlg, digest, &pkcs1DigestInfo,
   161            PR_TRUE /*XXX: unsafeAllowMissingParameters*/);
   162 }
   164 /*
   165  * decode the ECDSA or DSA signature from it's DER wrapping.
   166  * The unwrapped/raw signature is placed in the buffer pointed
   167  * to by dsig and has enough room for len bytes.
   168  */
   169 static SECStatus
   170 decodeECorDSASignature(SECOidTag algid, const SECItem *sig, unsigned char *dsig,
   171 		       unsigned int len) {
   172     SECItem *dsasig = NULL; /* also used for ECDSA */
   173     SECStatus rv=SECSuccess;
   175     if ((algid != SEC_OID_ANSIX9_DSA_SIGNATURE) &&
   176 	(algid != SEC_OID_ANSIX962_EC_PUBLIC_KEY) ) {
   177         if (sig->len != len) {
   178 	    PORT_SetError(SEC_ERROR_BAD_DER);
   179 	    return SECFailure;
   180 	} 
   182 	PORT_Memcpy(dsig, sig->data, sig->len);
   183 	return SECSuccess;
   184     }
   186     if (algid ==  SEC_OID_ANSIX962_EC_PUBLIC_KEY) {
   187 	if (len > MAX_ECKEY_LEN * 2) {
   188 	    PORT_SetError(SEC_ERROR_BAD_DER);
   189 	    return SECFailure;
   190 	}
   191     }
   192     dsasig = DSAU_DecodeDerSigToLen((SECItem *)sig, len);
   194     if ((dsasig == NULL) || (dsasig->len != len)) {
   195 	rv = SECFailure;
   196     } else {
   197 	PORT_Memcpy(dsig, dsasig->data, dsasig->len);
   198     }
   200     if (dsasig != NULL) SECITEM_FreeItem(dsasig, PR_TRUE);
   201     if (rv == SECFailure) PORT_SetError(SEC_ERROR_BAD_DER);
   202     return rv;
   203 }
   205 const SEC_ASN1Template hashParameterTemplate[] =
   206 {
   207     { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECItem) },
   208     { SEC_ASN1_OBJECT_ID, 0 },
   209     { SEC_ASN1_SKIP_REST },
   210     { 0, }
   211 };
   213 /*
   214  * Pulls the hash algorithm, signing algorithm, and key type out of a
   215  * composite algorithm.
   216  *
   217  * sigAlg: the composite algorithm to dissect.
   218  * hashalg: address of a SECOidTag which will be set with the hash algorithm.
   219  * encalg: address of a SECOidTag which will be set with the signing alg.
   220  *
   221  * Returns: SECSuccess if the algorithm was acceptable, SECFailure if the
   222  *	algorithm was not found or was not a signing algorithm.
   223  */
   224 SECStatus
   225 sec_DecodeSigAlg(const SECKEYPublicKey *key, SECOidTag sigAlg, 
   226              const SECItem *param, SECOidTag *encalg, SECOidTag *hashalg)
   227 {
   228     int len;
   229     PLArenaPool *arena;
   230     SECStatus rv;
   231     SECItem oid;
   233     PR_ASSERT(hashalg!=NULL);
   234     PR_ASSERT(encalg!=NULL);
   236     switch (sigAlg) {
   237       /* We probably shouldn't be generating MD2 signatures either */
   238       case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
   239         *hashalg = SEC_OID_MD2;
   240 	break;
   241       case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
   242         *hashalg = SEC_OID_MD5;
   243 	break;
   244       case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
   245       case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE:
   246       case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE:
   247         *hashalg = SEC_OID_SHA1;
   248 	break;
   249       case SEC_OID_PKCS1_RSA_ENCRYPTION:
   250       case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
   251         *hashalg = SEC_OID_UNKNOWN; /* get it from the RSA signature */
   252 	break;
   254       case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE:
   255       case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION:
   256       case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST:
   257 	*hashalg = SEC_OID_SHA224;
   258 	break;
   259       case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE:
   260       case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
   261       case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST:
   262 	*hashalg = SEC_OID_SHA256;
   263 	break;
   264       case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE:
   265       case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
   266 	*hashalg = SEC_OID_SHA384;
   267 	break;
   268       case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE:
   269       case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
   270 	*hashalg = SEC_OID_SHA512;
   271 	break;
   273       /* what about normal DSA? */
   274       case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST:
   275       case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST:
   276       case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
   277         *hashalg = SEC_OID_SHA1;
   278 	break;
   279       case SEC_OID_MISSI_DSS:
   280       case SEC_OID_MISSI_KEA_DSS:
   281       case SEC_OID_MISSI_KEA_DSS_OLD:
   282       case SEC_OID_MISSI_DSS_OLD:
   283         *hashalg = SEC_OID_SHA1;
   284 	break;
   285       case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST:
   286 	/* This is an EC algorithm. Recommended means the largest
   287 	 * hash algorithm that is not reduced by the keysize of 
   288 	 * the EC algorithm. Note that key strength is in bytes and
   289 	 * algorithms are specified in bits. Never use an algorithm
   290 	 * weaker than sha1. */
   291 	len = SECKEY_PublicKeyStrength(key);
   292 	if (len < 28) { /* 28 bytes == 224 bits */
   293 	    *hashalg = SEC_OID_SHA1;
   294 	} else if (len < 32) { /* 32 bytes == 256 bits */
   295 	    *hashalg = SEC_OID_SHA224;
   296 	} else if (len < 48) { /* 48 bytes == 384 bits */
   297 	    *hashalg = SEC_OID_SHA256;
   298 	} else if (len < 64) { /* 48 bytes == 512 bits */
   299 	    *hashalg = SEC_OID_SHA384;
   300 	} else {
   301 	    /* use the largest in this case */
   302 	    *hashalg = SEC_OID_SHA512;
   303 	}
   304 	break;
   305       case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST:
   306 	if (param == NULL) {
   307 	    PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
   308 	    return SECFailure;
   309 	}
   310 	arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   311 	if (arena == NULL) {
   312 	    return SECFailure;
   313 	}
   314 	rv = SEC_QuickDERDecodeItem(arena, &oid, hashParameterTemplate, param);
   315 	if (rv == SECSuccess) {
   316             *hashalg = SECOID_FindOIDTag(&oid);
   317         }
   318         PORT_FreeArena(arena, PR_FALSE);
   319         if (rv != SECSuccess) {
   320 	    return rv;
   321 	}
   322 	/* only accept hash algorithms */
   323 	if (HASH_GetHashTypeByOidTag(*hashalg) == HASH_AlgNULL) {
   324 	    /* error set by HASH_GetHashTypeByOidTag */
   325 	    return SECFailure;
   326 	}
   327 	break;
   328       /* we don't implement MD4 hashes */
   329       case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
   330       default:
   331 	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
   332 	return SECFailure;
   333     }
   334     /* get the "encryption" algorithm */ 
   335     switch (sigAlg) {
   336       case SEC_OID_PKCS1_RSA_ENCRYPTION:
   337       case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
   338       case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
   339       case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
   340       case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE:
   341       case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE:
   342       case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION:
   343       case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
   344       case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
   345       case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
   346 	*encalg = SEC_OID_PKCS1_RSA_ENCRYPTION;
   347 	break;
   348       case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
   349 	*encalg = SEC_OID_PKCS1_RSA_PSS_SIGNATURE;
   350 	break;
   352       /* what about normal DSA? */
   353       case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST:
   354       case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST:
   355       case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST:
   356       case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST:
   357 	*encalg = SEC_OID_ANSIX9_DSA_SIGNATURE;
   358 	break;
   359       case SEC_OID_MISSI_DSS:
   360       case SEC_OID_MISSI_KEA_DSS:
   361       case SEC_OID_MISSI_KEA_DSS_OLD:
   362       case SEC_OID_MISSI_DSS_OLD:
   363 	*encalg = SEC_OID_MISSI_DSS;
   364 	break;
   365       case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
   366       case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE:
   367       case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE:
   368       case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE:
   369       case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE:
   370       case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST:
   371       case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST:
   372 	*encalg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
   373 	break;
   374       /* we don't implement MD4 hashes */
   375       case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
   376       default:
   377 	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
   378 	return SECFailure;
   379     }
   380     return SECSuccess;
   381 }
   383 /*
   384  * we can verify signatures that come from 2 different sources:
   385  *  one in with the signature contains a signature oid, and the other
   386  *  in which the signature is managed by a Public key (encAlg) oid
   387  *  and a hash oid. The latter is the more basic, so that's what
   388  *  our base vfyCreate function takes.
   389  *
   390  * There is one noteworthy corner case, if we are using an RSA key, and the
   391  * signature block is provided, then the hashAlg can be specified as 
   392  * SEC_OID_UNKNOWN. In this case, verify will use the hash oid supplied
   393  * in the RSA signature block.
   394  */
   395 static VFYContext *
   396 vfy_CreateContext(const SECKEYPublicKey *key, const SECItem *sig, 
   397 	SECOidTag encAlg, SECOidTag hashAlg, SECOidTag *hash, void *wincx)
   398 {
   399     VFYContext *cx;
   400     SECStatus rv;
   401     unsigned int sigLen;
   402     KeyType type;
   404     /* make sure the encryption algorithm matches the key type */
   405     /* RSA-PSS algorithm can be used with both rsaKey and rsaPssKey */
   406     type = seckey_GetKeyType(encAlg);
   407     if ((key->keyType != type) &&
   408 	((key->keyType != rsaKey) || (type != rsaPssKey))) {
   409 	PORT_SetError(SEC_ERROR_PKCS7_KEYALG_MISMATCH);
   410 	return NULL;
   411     }
   413     cx = (VFYContext*) PORT_ZAlloc(sizeof(VFYContext));
   414     if (cx == NULL) {
   415 	goto loser;
   416     }
   418     cx->wincx = wincx;
   419     cx->hasSignature = (sig != NULL);
   420     cx->encAlg = encAlg;
   421     cx->hashAlg = hashAlg;
   422     cx->key = SECKEY_CopyPublicKey(key);
   423     cx->pkcs1RSADigestInfo = NULL;
   424     rv = SECSuccess;
   425     if (sig) {
   426 	switch (type) {
   427 	case rsaKey:
   428 	    rv = recoverPKCS1DigestInfo(hashAlg, &cx->hashAlg,
   429 					&cx->pkcs1RSADigestInfo,
   430 					&cx->pkcs1RSADigestInfoLen,
   431 					cx->key,
   432 					sig, wincx);
   433 	    break;
   434 	case dsaKey:
   435 	case ecKey:
   436 	    sigLen = SECKEY_SignatureLen(key);
   437 	    if (sigLen == 0) {
   438 		/* error set by SECKEY_SignatureLen */
   439 		rv = SECFailure;	
   440 		break;
   441 	    }
   442 	    rv = decodeECorDSASignature(encAlg, sig, cx->u.buffer, sigLen);
   443  	    break;
   444 	default:
   445 	    rv = SECFailure;
   446 	    PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
   447 	    break;
   448 	}
   449     }
   451     if (rv) goto loser;
   453     /* check hash alg again, RSA may have changed it.*/
   454     if (HASH_GetHashTypeByOidTag(cx->hashAlg) == HASH_AlgNULL) {
   455 	/* error set by HASH_GetHashTypeByOidTag */
   456 	goto loser;
   457     }
   459     if (hash) {
   460 	*hash = cx->hashAlg;
   461     }
   462     return cx;
   464   loser:
   465     if (cx) {
   466 	VFY_DestroyContext(cx, PR_TRUE);
   467     }
   468     return 0;
   469 }
   471 VFYContext *
   472 VFY_CreateContext(SECKEYPublicKey *key, SECItem *sig, SECOidTag sigAlg,
   473 		  void *wincx)
   474 {
   475     SECOidTag encAlg, hashAlg;
   476     SECStatus rv = sec_DecodeSigAlg(key, sigAlg, NULL, &encAlg, &hashAlg);
   477     if (rv != SECSuccess) {
   478 	return NULL;
   479     }
   480     return vfy_CreateContext(key, sig, encAlg, hashAlg, NULL, wincx);
   481 }
   483 VFYContext *
   484 VFY_CreateContextDirect(const SECKEYPublicKey *key, const SECItem *sig, 
   485 			SECOidTag encAlg, SECOidTag hashAlg, 
   486 			SECOidTag *hash, void *wincx)
   487 {
   488   return vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx);
   489 }
   491 VFYContext *
   492 VFY_CreateContextWithAlgorithmID(const SECKEYPublicKey *key, const SECItem *sig,
   493 	      const SECAlgorithmID *sigAlgorithm, SECOidTag *hash, void *wincx)
   494 {
   495     SECOidTag encAlg, hashAlg;
   496     SECStatus rv = sec_DecodeSigAlg(key, 
   497 		    SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm), 
   498 		    &sigAlgorithm->parameters, &encAlg, &hashAlg);
   499     if (rv != SECSuccess) {
   500 	return NULL;
   501     }
   502     return vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx);
   503 }
   505 void
   506 VFY_DestroyContext(VFYContext *cx, PRBool freeit)
   507 {
   508     if (cx) {
   509 	if (cx->hashcx != NULL) {
   510 	    (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
   511 	    cx->hashcx = NULL;
   512 	}
   513 	if (cx->key) {
   514 	    SECKEY_DestroyPublicKey(cx->key);
   515 	}
   516     if (cx->pkcs1RSADigestInfo) {
   517         PORT_Free(cx->pkcs1RSADigestInfo);
   518     }
   519 	if (freeit) {
   520 	    PORT_ZFree(cx, sizeof(VFYContext));
   521 	}
   522     }
   523 }
   525 SECStatus
   526 VFY_Begin(VFYContext *cx)
   527 {
   528     if (cx->hashcx != NULL) {
   529 	(*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
   530 	cx->hashcx = NULL;
   531     }
   533     cx->hashobj = HASH_GetHashObjectByOidTag(cx->hashAlg);
   534     if (!cx->hashobj) 
   535 	return SECFailure;	/* error code is set */
   537     cx->hashcx = (*cx->hashobj->create)();
   538     if (cx->hashcx == NULL)
   539 	return SECFailure;
   541     (*cx->hashobj->begin)(cx->hashcx);
   542     return SECSuccess;
   543 }
   545 SECStatus
   546 VFY_Update(VFYContext *cx, const unsigned char *input, unsigned inputLen)
   547 {
   548     if (cx->hashcx == NULL) {
   549 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
   550 	return SECFailure;
   551     }
   552     (*cx->hashobj->update)(cx->hashcx, input, inputLen);
   553     return SECSuccess;
   554 }
   556 SECStatus
   557 VFY_EndWithSignature(VFYContext *cx, SECItem *sig)
   558 {
   559     unsigned char final[HASH_LENGTH_MAX];
   560     unsigned part;
   561     SECItem hash,dsasig; /* dsasig is also used for ECDSA */
   562     SECStatus rv;
   564     if ((cx->hasSignature == PR_FALSE) && (sig == NULL)) {
   565 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
   566 	return SECFailure;
   567     }
   569     if (cx->hashcx == NULL) {
   570 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
   571 	return SECFailure;
   572     }
   573     (*cx->hashobj->end)(cx->hashcx, final, &part, sizeof(final));
   574     switch (cx->key->keyType) {
   575       case ecKey:
   576       case dsaKey:
   577 	dsasig.data = cx->u.buffer;
   578 	dsasig.len = SECKEY_SignatureLen(cx->key);
   579 	if (dsasig.len == 0) {
   580 	    return SECFailure;
   581 	} 
   582 	if (sig) {
   583 	    rv = decodeECorDSASignature(cx->encAlg, sig, dsasig.data,
   584 					dsasig.len);
   585 	    if (rv != SECSuccess) {
   586 		PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
   587 		return SECFailure;
   588 	    }
   589 	} 
   590 	hash.data = final;
   591 	hash.len = part;
   592 	if (PK11_Verify(cx->key,&dsasig,&hash,cx->wincx) != SECSuccess) {
   593 		PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
   594 		return SECFailure;
   595 	}
   596 	break;
   597       case rsaKey:
   598       {
   599         SECItem digest;
   600         digest.data = final;
   601         digest.len = part;
   602 	if (sig) {
   603 	    SECOidTag hashid;
   604 	    PORT_Assert(cx->hashAlg != SEC_OID_UNKNOWN);
   605 	    rv = recoverPKCS1DigestInfo(cx->hashAlg, &hashid,
   606 					&cx->pkcs1RSADigestInfo,
   607 					&cx->pkcs1RSADigestInfoLen,
   608 					cx->key,
   609 					sig, cx->wincx);
   610 	    PORT_Assert(cx->hashAlg == hashid);
   611 	    if (rv != SECSuccess) {
   612 		return SECFailure;
   613 	    }
   614 	}
   615 	return verifyPKCS1DigestInfo(cx, &digest);
   616       }
   617       default:
   618 	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
   619 	return SECFailure; /* shouldn't happen */
   620     }
   621     return SECSuccess;
   622 }
   624 SECStatus
   625 VFY_End(VFYContext *cx)
   626 {
   627     return VFY_EndWithSignature(cx,NULL);
   628 }
   630 /************************************************************************/
   631 /*
   632  * Verify that a previously-computed digest matches a signature.
   633  */
   634 static SECStatus
   635 vfy_VerifyDigest(const SECItem *digest, const SECKEYPublicKey *key, 
   636 		 const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg,
   637 		 void *wincx)
   638 {
   639     SECStatus rv;
   640     VFYContext *cx;
   641     SECItem dsasig; /* also used for ECDSA */
   643     rv = SECFailure;
   645     cx = vfy_CreateContext(key, sig, encAlg, hashAlg, NULL, wincx);
   646     if (cx != NULL) {
   647 	switch (key->keyType) {
   648 	case rsaKey:
   649 	    rv = verifyPKCS1DigestInfo(cx, digest);
   650 	    break;
   651 	case dsaKey:
   652 	case ecKey:
   653 	    dsasig.data = cx->u.buffer;
   654 	    dsasig.len = SECKEY_SignatureLen(cx->key);
   655 	    if (dsasig.len == 0) {
   656 		break;
   657 	    }
   658 	    if (PK11_Verify(cx->key, &dsasig, (SECItem *)digest, cx->wincx)
   659 		!= SECSuccess) {
   660 		PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
   661 	    } else {
   662 		rv = SECSuccess;
   663 	    }
   664 	    break;
   665 	default:
   666 	    break;
   667 	}
   668 	VFY_DestroyContext(cx, PR_TRUE);
   669     }
   670     return rv;
   671 }
   673 SECStatus
   674 VFY_VerifyDigestDirect(const SECItem *digest, const SECKEYPublicKey *key, 
   675 		       const SECItem *sig, SECOidTag encAlg, 
   676 		       SECOidTag hashAlg, void *wincx)
   677 {
   678     return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx);
   679 }
   681 SECStatus
   682 VFY_VerifyDigest(SECItem *digest, SECKEYPublicKey *key, SECItem *sig,
   683 		 SECOidTag algid, void *wincx)
   684 {
   685     SECOidTag encAlg, hashAlg;
   686     SECStatus rv = sec_DecodeSigAlg(key, algid, NULL, &encAlg, &hashAlg);
   687     if (rv != SECSuccess) {
   688 	return SECFailure;
   689     }
   690     return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx);
   691 }
   693 /*
   694  * this function takes an optional hash oid, which the digest function
   695  * will be compared with our target hash value.
   696  */
   697 SECStatus
   698 VFY_VerifyDigestWithAlgorithmID(const SECItem *digest, 
   699 		const SECKEYPublicKey *key, const SECItem *sig, 
   700 		const SECAlgorithmID *sigAlgorithm, 
   701 		SECOidTag hashCmp, void *wincx)
   702 {
   703     SECOidTag encAlg, hashAlg;
   704     SECStatus rv = sec_DecodeSigAlg(key, 
   705 		    SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm), 
   706 		    &sigAlgorithm->parameters, &encAlg, &hashAlg);
   707     if (rv != SECSuccess) {
   708 	return rv;
   709     }
   710     if ( hashCmp != SEC_OID_UNKNOWN && 
   711 	 hashAlg != SEC_OID_UNKNOWN &&
   712 	 hashCmp != hashAlg) {
   713 	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
   714 	return SECFailure;
   715     }
   716     return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx);
   717 }
   719 static SECStatus
   720 vfy_VerifyData(const unsigned char *buf, int len, const SECKEYPublicKey *key,
   721 	       const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg,
   722 	       SECOidTag *hash, void *wincx)
   723 {
   724     SECStatus rv;
   725     VFYContext *cx;
   727     cx = vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx);
   728     if (cx == NULL)
   729 	return SECFailure;
   731     rv = VFY_Begin(cx);
   732     if (rv == SECSuccess) {
   733 	rv = VFY_Update(cx, (unsigned char *)buf, len);
   734 	if (rv == SECSuccess)
   735 	    rv = VFY_End(cx);
   736     }
   738     VFY_DestroyContext(cx, PR_TRUE);
   739     return rv;
   740 }
   742 SECStatus
   743 VFY_VerifyDataDirect(const unsigned char *buf, int len, 
   744 		     const SECKEYPublicKey *key, const SECItem *sig,
   745 		     SECOidTag encAlg, SECOidTag hashAlg,
   746 		     SECOidTag *hash, void *wincx)
   747 {
   748     return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, hash, wincx);
   749 }
   751 SECStatus
   752 VFY_VerifyData(const unsigned char *buf, int len, const SECKEYPublicKey *key,
   753 	       const SECItem *sig, SECOidTag algid, void *wincx)
   754 {
   755     SECOidTag encAlg, hashAlg;
   756     SECStatus rv = sec_DecodeSigAlg(key, algid, NULL, &encAlg, &hashAlg);
   757     if (rv != SECSuccess) {
   758 	return rv;
   759     }
   760     return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, NULL, wincx);
   761 }
   763 SECStatus
   764 VFY_VerifyDataWithAlgorithmID(const unsigned char *buf, int len, 
   765 			      const SECKEYPublicKey *key,
   766 			      const SECItem *sig, 
   767 			      const SECAlgorithmID *sigAlgorithm, 
   768 			      SECOidTag *hash, void *wincx)
   769 {
   770     SECOidTag encAlg, hashAlg;
   771     SECOidTag sigAlg = SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm);
   772     SECStatus rv     = sec_DecodeSigAlg(key, sigAlg, 
   773 		                &sigAlgorithm->parameters, &encAlg, &hashAlg);
   774     if (rv != SECSuccess) {
   775 	return rv;
   776     }
   777     return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, hash, wincx);
   778 }

mercurial