secvfy.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:10k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /*
  2.  * Verification stuff.
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public
  5.  * License Version 1.1 (the "License"); you may not use this file
  6.  * except in compliance with the License. You may obtain a copy of
  7.  * the License at http://www.mozilla.org/MPL/
  8.  * 
  9.  * Software distributed under the License is distributed on an "AS
  10.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  11.  * implied. See the License for the specific language governing
  12.  * rights and limitations under the License.
  13.  * 
  14.  * The Original Code is the Netscape security libraries.
  15.  * 
  16.  * The Initial Developer of the Original Code is Netscape
  17.  * Communications Corporation.  Portions created by Netscape are 
  18.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  19.  * Rights Reserved.
  20.  * 
  21.  * Contributor(s):
  22.  * 
  23.  * Alternatively, the contents of this file may be used under the
  24.  * terms of the GNU General Public License Version 2 or later (the
  25.  * "GPL"), in which case the provisions of the GPL are applicable 
  26.  * instead of those above.  If you wish to allow use of your 
  27.  * version of this file only under the terms of the GPL and not to
  28.  * allow others to use your version of this file under the MPL,
  29.  * indicate your decision by deleting the provisions above and
  30.  * replace them with the notice and other provisions required by
  31.  * the GPL.  If you do not delete the provisions above, a recipient
  32.  * may use your version of this file under either the MPL or the
  33.  * GPL.
  34.  *
  35.  * $Id: secvfy.c,v 1.3 2000/06/13 21:56:22 chrisk%netscape.com Exp $
  36.  */
  37. #include <stdio.h>
  38. #include "cryptohi.h"
  39. #include "sechash.h"
  40. #include "keyhi.h"
  41. #include "secasn1.h"
  42. #include "secoid.h"
  43. #include "pk11func.h"
  44. #include "secdig.h"
  45. #include "secerr.h"
  46. /*
  47. ** Decrypt signature block using public key (in place)
  48. ** XXX this is assuming that the signature algorithm has WITH_RSA_ENCRYPTION
  49. */
  50. static SECStatus
  51. DecryptSigBlock(int *tagp, unsigned char *digest, SECKEYPublicKey *key,
  52. SECItem *sig, char *wincx)
  53. {
  54.     SGNDigestInfo *di   = NULL;
  55.     unsigned char *dsig = NULL;
  56.     unsigned char *buf  = NULL;
  57.     SECStatus      rv;
  58.     SECOidTag      tag;
  59.     SECItem        it;
  60.     if (key == NULL) goto loser;
  61.     it.len  = SECKEY_PublicKeyStrength(key);
  62.     if (!it.len) goto loser;
  63.     it.data = buf = (unsigned char *)PORT_Alloc(it.len);
  64.     if (!buf) goto loser;
  65.     /* Decrypt signature block */
  66.     dsig = (unsigned char*) PORT_Alloc(sig->len);
  67.     if (dsig == NULL) goto loser;
  68.     /* decrypt the block */
  69.     rv = PK11_VerifyRecover(key, sig, &it, wincx);
  70.     if (rv != SECSuccess) goto loser;
  71.     di = SGN_DecodeDigestInfo(&it);
  72.     if (di == NULL) goto sigloser;
  73.     /*
  74.     ** Finally we have the digest info; now we can extract the algorithm
  75.     ** ID and the signature block
  76.     */
  77.     tag = SECOID_GetAlgorithmTag(&di->digestAlgorithm);
  78.     /* XXX Check that tag is an appropriate algorithm? */
  79.     if (di->digest.len > 32) {
  80. PORT_SetError(SEC_ERROR_OUTPUT_LEN);
  81. goto loser;
  82.     }
  83.     PORT_Memcpy(digest, di->digest.data, di->digest.len);
  84.     *tagp = tag;
  85.     goto done;
  86.   sigloser:
  87.     PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
  88.   loser:
  89.     rv = SECFailure;
  90.   done:
  91.     if (di   != NULL) SGN_DestroyDigestInfo(di);
  92.     if (dsig != NULL) PORT_Free(dsig);
  93.     if (buf  != NULL) PORT_Free(buf);
  94.     
  95.     return rv;
  96. }
  97. typedef enum { VFY_RSA, VFY_DSA} VerifyType;
  98. struct VFYContextStr {
  99.     int alg;
  100.     VerifyType type;
  101.     SECKEYPublicKey *key;
  102.     /* digest holds the full dsa signature... 40 bytes */
  103.     unsigned char digest[DSA_SIGNATURE_LEN];
  104.     void * wincx;
  105.     void *hashcx;
  106.     SECHashObject *hashobj;
  107. };
  108. VFYContext *
  109. VFY_CreateContext(SECKEYPublicKey *key, SECItem *sig, SECOidTag algid,
  110.   void *wincx)
  111. {
  112.     VFYContext *cx;
  113.     SECStatus rv;
  114.     SECItem *dsasig = NULL;
  115.     cx = (VFYContext*) PORT_ZAlloc(sizeof(VFYContext));
  116.     if (cx) {
  117.         cx->wincx = cx;
  118. switch (key->keyType) {
  119.   case rsaKey:
  120.     cx->type = VFY_RSA;
  121.     cx->key = NULL; /* extra safety precautions */
  122.     rv = DecryptSigBlock(&cx->alg, &cx->digest[0], key, sig, (char*)wincx);
  123.     break;
  124.   case fortezzaKey:
  125.   case dsaKey:
  126.     cx->type = VFY_DSA;
  127.     cx->alg = SEC_OID_SHA1;
  128.     cx->key = SECKEY_CopyPublicKey(key);
  129.     /* if this is a DER encoded signature, decode it first */
  130.     if ((algid == SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST) ||
  131. (algid == SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST) ||
  132. (algid == SEC_OID_ANSIX9_DSA_SIGNATURE)) {
  133. dsasig = DSAU_DecodeDerSig(sig);
  134. if ((dsasig == NULL) || (dsasig->len != DSA_SIGNATURE_LEN)) {
  135.     goto loser;
  136. }
  137. PORT_Memcpy(&cx->digest[0], dsasig->data, dsasig->len);
  138.     } else {
  139. if (sig->len != DSA_SIGNATURE_LEN) {
  140.     goto loser;
  141. }
  142. PORT_Memcpy(&cx->digest[0], sig->data, sig->len);
  143.     }
  144.     rv = SECSuccess;
  145.     break;
  146.   default:
  147.     rv = SECFailure;
  148.     break;
  149. }
  150. if (rv) goto loser;
  151. switch (cx->alg) {
  152.   case SEC_OID_MD2:
  153.   case SEC_OID_MD5:
  154.   case SEC_OID_SHA1:
  155.     break;
  156.   default:
  157.     PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
  158.     goto loser;
  159. }
  160.     }
  161.     return cx;
  162.   loser:
  163.     if (dsasig != NULL)
  164. SECITEM_FreeItem(dsasig, PR_TRUE);
  165.     VFY_DestroyContext(cx, PR_TRUE);
  166.     return 0;
  167. }
  168. void
  169. VFY_DestroyContext(VFYContext *cx, PRBool freeit)
  170. {
  171.     if (cx) {
  172. if (cx->hashcx != NULL) {
  173.     (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
  174.     cx->hashcx = NULL;
  175. }
  176. if (cx->key) {
  177.     SECKEY_DestroyPublicKey(cx->key);
  178. }
  179. if (freeit) {
  180.     PORT_ZFree(cx, sizeof(VFYContext));
  181. }
  182.     }
  183. }
  184. SECStatus
  185. VFY_Begin(VFYContext *cx)
  186. {
  187.     if (cx->hashcx != NULL) {
  188. (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
  189. cx->hashcx = NULL;
  190.     }
  191.     switch (cx->alg) {
  192.       case SEC_OID_MD2:
  193. cx->hashobj = &SECHashObjects[HASH_AlgMD2];
  194. break;
  195.       case SEC_OID_MD5:
  196. cx->hashobj = &SECHashObjects[HASH_AlgMD5];
  197. break;
  198.       case SEC_OID_SHA1:
  199. cx->hashobj = &SECHashObjects[HASH_AlgSHA1];
  200. break;
  201.       default:
  202. PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
  203. return SECFailure;
  204.     }
  205.     cx->hashcx = (*cx->hashobj->create)();
  206.     if (cx->hashcx == NULL)
  207. return SECFailure;
  208.     (*cx->hashobj->begin)(cx->hashcx);
  209.     return SECSuccess;
  210. }
  211. SECStatus
  212. VFY_Update(VFYContext *cx, unsigned char *input, unsigned inputLen)
  213. {
  214.     if (cx->hashcx == NULL) {
  215. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  216. return SECFailure;
  217.     }
  218.     (*cx->hashobj->update)(cx->hashcx, input, inputLen);
  219.     return SECSuccess;
  220. }
  221. SECStatus
  222. VFY_End(VFYContext *cx)
  223. {
  224.     unsigned char final[32];
  225.     unsigned part;
  226.     SECItem hash,sig;
  227.     if (cx->hashcx == NULL) {
  228. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  229. return SECFailure;
  230.     }
  231.     (*cx->hashobj->end)(cx->hashcx, final, &part, sizeof(final));
  232.     switch (cx->type) {
  233.       case VFY_DSA:
  234. sig.data = cx->digest;
  235. sig.len = DSA_SIGNATURE_LEN; /* magic size of dsa signature */
  236. hash.data = final;
  237. hash.len = part;
  238. if (PK11_Verify(cx->key,&sig,&hash,cx->wincx) != SECSuccess) {
  239. PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
  240. return SECFailure;
  241. }
  242. break;
  243.       case VFY_RSA:
  244. if (PORT_Memcmp(final, cx->digest, part)) {
  245.     PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
  246.     return SECFailure;
  247. }
  248. break;
  249.       default:
  250. PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
  251. return SECFailure; /* shouldn't happen */
  252.     }
  253.     return SECSuccess;
  254. }
  255. /************************************************************************/
  256. /*
  257.  * Verify that a previously-computed digest matches a signature.
  258.  * XXX This should take a parameter that specifies the digest algorithm,
  259.  * and we should compare that the algorithm found in the DigestInfo
  260.  * matches it!
  261.  */
  262. SECStatus
  263. VFY_VerifyDigest(SECItem *digest, SECKEYPublicKey *key, SECItem *sig,
  264.  SECOidTag algid, void *wincx)
  265. {
  266.     SECStatus rv;
  267.     VFYContext *cx;
  268.     SECItem dsasig;
  269.     rv = SECFailure;
  270.     cx = VFY_CreateContext(key, sig, algid, wincx);
  271.     if (cx != NULL) {
  272. switch (key->keyType) {
  273. case rsaKey:
  274.     if (PORT_Memcmp(digest->data, cx->digest, digest->len)) {
  275. PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
  276.     } else {
  277. rv = SECSuccess;
  278.     }
  279.     break;
  280. case fortezzaKey:
  281. case dsaKey:
  282.     dsasig.data = &cx->digest[0];
  283.     dsasig.len = DSA_SIGNATURE_LEN; /* magic size of dsa signature */
  284.     if (PK11_Verify(cx->key, &dsasig, digest, cx->wincx) != SECSuccess) {
  285. PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
  286.     } else {
  287. rv = SECSuccess;
  288.     }
  289.     break;
  290. default:
  291.     break;
  292. }
  293. VFY_DestroyContext(cx, PR_TRUE);
  294.     }
  295.     return rv;
  296. }
  297. SECStatus
  298. VFY_VerifyData(unsigned char *buf, int len, SECKEYPublicKey *key,
  299.        SECItem *sig, SECOidTag algid, void *wincx)
  300. {
  301.     SECStatus rv;
  302.     VFYContext *cx;
  303.     cx = VFY_CreateContext(key, sig, algid, wincx);
  304.     if (cx == NULL)
  305. return SECFailure;
  306.     rv = VFY_Begin(cx);
  307.     if (rv == SECSuccess) {
  308. rv = VFY_Update(cx, buf, len);
  309. if (rv == SECSuccess)
  310.     rv = VFY_End(cx);
  311.     }
  312.     VFY_DestroyContext(cx, PR_TRUE);
  313.     return rv;
  314. }
  315. SECStatus
  316. SEC_VerifyFile(FILE *input, SECKEYPublicKey *key, SECItem *sig,
  317.        SECOidTag algid, void *wincx)
  318. {
  319.     unsigned char buf[1024];
  320.     SECStatus rv;
  321.     int nb;
  322.     VFYContext *cx;
  323.     cx = VFY_CreateContext(key, sig, algid, wincx);
  324.     if (cx == NULL)
  325. rv = SECFailure;
  326.     rv = VFY_Begin(cx);
  327.     if (rv == SECSuccess) {
  328. /*
  329.  * Now feed the contents of the input file into the digest algorithm,
  330.  * one chunk at a time, until we have exhausted the input.
  331.  */
  332. for (;;) {
  333.     if (feof(input))
  334. break;
  335.     nb = fread(buf, 1, sizeof(buf), input);
  336.     if (nb == 0) {
  337. if (ferror(input)) {
  338.     PORT_SetError(SEC_ERROR_IO);
  339.     VFY_DestroyContext(cx, PR_TRUE);
  340.     return SECFailure;
  341. }
  342. break;
  343.     }
  344.     rv = VFY_Update(cx, buf, nb);
  345.     if (rv != SECSuccess)
  346. goto loser;
  347. }
  348.     }
  349.     /* Verify the digest */
  350.     rv = VFY_End(cx);
  351.     /* FALL THROUGH */
  352.   loser:
  353.     VFY_DestroyContext(cx, PR_TRUE);
  354.     return rv;
  355. }