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

CA认证

开发平台:

WINDOWS

  1. /*
  2.  * Signature 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: secsign.c,v 1.1 2000/03/31 19:46:09 relyea%netscape.com Exp $
  36.  */
  37. #include <stdio.h>
  38. #include "cryptohi.h"
  39. #include "sechash.h"
  40. #include "secder.h"
  41. #include "keyhi.h"
  42. #include "secoid.h"
  43. #include "secdig.h"
  44. #include "pk11func.h"
  45. #include "secerr.h"
  46. struct SGNContextStr {
  47.     SECOidTag signalg;
  48.     SECOidTag hashalg;
  49.     void *hashcx;
  50.     SECHashObject *hashobj;
  51.     SECKEYPrivateKey *key;
  52. };
  53. SGNContext *
  54. SGN_NewContext(SECOidTag alg, SECKEYPrivateKey *key)
  55. {
  56.     SGNContext *cx;
  57.     SECOidTag hashalg, signalg;
  58.     KeyType keyType;
  59.     /* OK, map a PKCS #7 hash and encrypt algorithm into
  60.      * a standard hashing algorithm. Why did we pass in the whole
  61.      * PKCS #7 algTag if we were just going to change here you might
  62.      * ask. Well the answer is for some cards we may have to do the
  63.      * hashing on card. It may not support CKM_RSA_PKCS sign algorithm,
  64.      * it may just support CKM_RSA_PKCS_WITH_SHA1 and/or CKM_RSA_PKCS_WITH_MD5.
  65.      */
  66.     switch (alg) {
  67.       /* We probably shouldn't be generating MD2 signatures either */
  68.       case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
  69. hashalg = SEC_OID_MD2;
  70. signalg = SEC_OID_PKCS1_RSA_ENCRYPTION;
  71. keyType = rsaKey;
  72. break;
  73.       case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
  74.         hashalg = SEC_OID_MD5;
  75. signalg = SEC_OID_PKCS1_RSA_ENCRYPTION;
  76. keyType = rsaKey;
  77. break;
  78.       case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
  79.       case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE:
  80. hashalg = SEC_OID_SHA1;
  81. signalg = SEC_OID_PKCS1_RSA_ENCRYPTION;
  82. keyType = rsaKey;
  83. break;
  84.       /* what about normal DSA? */
  85.       case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST:
  86.       case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST:
  87. hashalg = SEC_OID_SHA1;
  88. signalg = SEC_OID_ANSIX9_DSA_SIGNATURE;
  89. keyType = dsaKey;
  90. break;
  91.       case SEC_OID_MISSI_DSS:
  92.       case SEC_OID_MISSI_KEA_DSS:
  93.       case SEC_OID_MISSI_KEA_DSS_OLD:
  94.       case SEC_OID_MISSI_DSS_OLD:
  95. hashalg = SEC_OID_SHA1;
  96. signalg = SEC_OID_MISSI_DSS; /* XXX Is there a better algid? */
  97. keyType = fortezzaKey;
  98. break;
  99.       /* we don't implement MD4 hashes. 
  100.        * we *CERTAINLY* don't want to sign one! */
  101.       case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
  102.       default:
  103. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  104. return 0;
  105.     }
  106.     /* verify our key type */
  107.     if (key->keyType != keyType &&
  108. !((key->keyType == dsaKey) && (keyType == fortezzaKey)) &&
  109. !((key->keyType == fortezzaKey) && (keyType == dsaKey)) ) {
  110. PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
  111. return 0;
  112.     }
  113.     cx = (SGNContext*) PORT_ZAlloc(sizeof(SGNContext));
  114.     if (cx) {
  115. cx->hashalg = hashalg;
  116. cx->signalg = signalg;
  117. cx->key = key;
  118.     }
  119.     return cx;
  120. }
  121. void
  122. SGN_DestroyContext(SGNContext *cx, PRBool freeit)
  123. {
  124.     if (cx) {
  125. if (cx->hashcx != NULL) {
  126.     (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
  127.     cx->hashcx = NULL;
  128. }
  129. if (freeit) {
  130.     PORT_ZFree(cx, sizeof(SGNContext));
  131. }
  132.     }
  133. }
  134. SECStatus
  135. SGN_Begin(SGNContext *cx)
  136. {
  137.     if (cx->hashcx != NULL) {
  138. (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE);
  139. cx->hashcx = NULL;
  140.     }
  141.     switch (cx->hashalg) {
  142.       case SEC_OID_MD2:
  143. cx->hashobj = &SECHashObjects[HASH_AlgMD2];
  144. break;
  145.       case SEC_OID_MD5:
  146. cx->hashobj = &SECHashObjects[HASH_AlgMD5];
  147. break;
  148.       case SEC_OID_SHA1:
  149. cx->hashobj = &SECHashObjects[HASH_AlgSHA1];
  150. break;
  151.       default:
  152. PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
  153. return SECFailure;
  154.     }
  155.     cx->hashcx = (*cx->hashobj->create)();
  156.     if (cx->hashcx == NULL)
  157. return SECFailure;
  158.     (*cx->hashobj->begin)(cx->hashcx);
  159.     return SECSuccess;
  160. }
  161. SECStatus
  162. SGN_Update(SGNContext *cx, unsigned char *input, unsigned inputLen)
  163. {
  164.     if (cx->hashcx == NULL) {
  165. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  166. return SECFailure;
  167.     }
  168.     (*cx->hashobj->update)(cx->hashcx, input, inputLen);
  169.     return SECSuccess;
  170. }
  171. SECStatus
  172. SGN_End(SGNContext *cx, SECItem *result)
  173. {
  174.     unsigned char digest[32];
  175.     unsigned part1, signatureLen;
  176.     SECStatus rv;
  177.     SECItem digder, sigitem;
  178.     PRArenaPool *arena = 0;
  179.     SECKEYPrivateKey *privKey = cx->key;
  180.     SGNDigestInfo *di = 0;
  181.     result->data = 0;
  182.     digder.data = 0;
  183.     /* Finish up digest function */
  184.     if (cx->hashcx == NULL) {
  185. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  186. return SECFailure;
  187.     }
  188.     (*cx->hashobj->end)(cx->hashcx, digest, &part1, sizeof(digest));
  189.     if (privKey->keyType == rsaKey) {
  190. arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  191. if ( !arena ) {
  192.     rv = SECFailure;
  193.     goto loser;
  194. }
  195.     
  196. /* Construct digest info */
  197. di = SGN_CreateDigestInfo(cx->hashalg, digest, part1);
  198. if (!di) {
  199.     rv = SECFailure;
  200.     goto loser;
  201. }
  202. /* Der encode the digest as a DigestInfo */
  203. rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, di);
  204. if (rv != SECSuccess) {
  205.     goto loser;
  206. }
  207.     } else {
  208. digder.data = digest;
  209. digder.len = part1;
  210.     }
  211.     /*
  212.     ** Encrypt signature after constructing appropriate PKCS#1 signature
  213.     ** block
  214.     */
  215.     signatureLen = PK11_SignatureLen(privKey);
  216.     sigitem.len = signatureLen;
  217.     sigitem.data = (unsigned char*) PORT_Alloc(signatureLen);
  218.     if (sigitem.data == NULL) {
  219. rv = SECFailure;
  220. goto loser;
  221.     }
  222.     rv = PK11_Sign(privKey, &sigitem, &digder);
  223.     if (rv != SECSuccess) {
  224. PORT_Free(sigitem.data);
  225. sigitem.data = NULL;
  226.     }
  227.     if (cx->signalg == SEC_OID_ANSIX9_DSA_SIGNATURE) {
  228. rv = DSAU_EncodeDerSig(result, &sigitem);
  229. PORT_Free(sigitem.data);
  230. if (rv != SECSuccess)
  231.     goto loser;
  232.     } else {
  233. result->len = sigitem.len;
  234. result->data = sigitem.data;
  235.     }
  236.   loser:
  237.     SGN_DestroyDigestInfo(di);
  238.     if (arena != NULL) {
  239. PORT_FreeArena(arena, PR_FALSE);
  240.     }
  241.     return rv;
  242. }
  243. /************************************************************************/
  244. /*
  245. ** Sign a block of data returning in result a bunch of bytes that are the
  246. ** signature. Returns zero on success, an error code on failure.
  247. */
  248. SECStatus
  249. SEC_SignData(SECItem *res, unsigned char *buf, int len,
  250.      SECKEYPrivateKey *pk, SECOidTag algid)
  251. {
  252.     SECStatus rv;
  253.     SGNContext *sgn;
  254.     sgn = SGN_NewContext(algid, pk);
  255.     if (sgn == NULL)
  256. return SECFailure;
  257.     rv = SGN_Begin(sgn);
  258.     if (rv != SECSuccess)
  259. goto loser;
  260.     rv = SGN_Update(sgn, buf, len);
  261.     if (rv != SECSuccess)
  262. goto loser;
  263.     rv = SGN_End(sgn, res);
  264.   loser:
  265.     SGN_DestroyContext(sgn, PR_TRUE);
  266.     return rv;
  267. }
  268. /*
  269. ** Sign the input file's contents returning in result a bunch of bytes
  270. ** that are the signature. Returns zero on success, an error code on
  271. ** failure.
  272. */
  273. SECStatus
  274. SEC_SignFile(SECItem *result, FILE *input, 
  275.      SECKEYPrivateKey *pk, SECOidTag algid)
  276. {
  277.     unsigned char buf[1024];
  278.     SECStatus rv;
  279.     int nb;
  280.     SGNContext *sgn;
  281.     sgn = SGN_NewContext(algid, pk);
  282.     if (sgn == NULL)
  283. return SECFailure;
  284.     rv = SGN_Begin(sgn);
  285.     if (rv != SECSuccess)
  286. goto loser;
  287.     /*
  288.     ** Now feed the contents of the input file into the digest
  289.     ** algorithm, one chunk at a time, until we have exhausted the
  290.     ** input
  291.     */
  292.     for (;;) {
  293. if (feof(input)) break;
  294. nb = fread(buf, 1, sizeof(buf), input);
  295. if (nb == 0) {
  296.     if (ferror(input)) {
  297. PORT_SetError(SEC_ERROR_IO);
  298. rv = SECFailure;
  299. goto loser;
  300.     }
  301.     break;
  302. }
  303. rv = SGN_Update(sgn, buf, nb);
  304. if (rv != SECSuccess)
  305.     goto loser;
  306.     }
  307.     /* Sign the digest */
  308.     rv = SGN_End(sgn, result);
  309.     /* FALL THROUGH */
  310.   loser:
  311.     SGN_DestroyContext(sgn, PR_TRUE);
  312.     return rv;
  313. }
  314. /************************************************************************/
  315.     
  316. DERTemplate CERTSignedDataTemplate[] =
  317. {
  318.     { DER_SEQUENCE,
  319.   0, NULL, sizeof(CERTSignedData) },
  320.     { DER_ANY,
  321.   offsetof(CERTSignedData,data), },
  322.     { DER_INLINE,
  323.   offsetof(CERTSignedData,signatureAlgorithm),
  324.   SECAlgorithmIDTemplate, },
  325.     { DER_BIT_STRING,
  326.   offsetof(CERTSignedData,signature), },
  327.     { 0, }
  328. };
  329. const SEC_ASN1Template CERT_SignedDataTemplate[] =
  330. {
  331.     { SEC_ASN1_SEQUENCE,
  332.   0, NULL, sizeof(CERTSignedData) },
  333.     { SEC_ASN1_ANY,
  334.   offsetof(CERTSignedData,data), },
  335.     { SEC_ASN1_INLINE,
  336.   offsetof(CERTSignedData,signatureAlgorithm),
  337.   SECOID_AlgorithmIDTemplate, },
  338.     { SEC_ASN1_BIT_STRING,
  339.   offsetof(CERTSignedData,signature), },
  340.     { 0, }
  341. };
  342. SECStatus
  343. SEC_DerSignData(PRArenaPool *arena, SECItem *result, 
  344. unsigned char *buf, int len, SECKEYPrivateKey *pk, SECOidTag algID)
  345. {
  346.     SECItem it;
  347.     CERTSignedData sd;
  348.     SECStatus rv;
  349.     it.data = 0;
  350.     /* XXX We should probably have some asserts here to make sure the key type
  351.      * and algID match
  352.      */
  353.     if (algID == SEC_OID_UNKNOWN) {
  354. switch(pk->keyType) {
  355.   case rsaKey:
  356.     algID = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
  357.     break;
  358.   case dsaKey:
  359.     algID = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
  360.     break;
  361.   default:
  362.     return SECFailure;
  363.     break;
  364. }
  365.     }
  366.     /* Sign input buffer */
  367.     rv = SEC_SignData(&it, buf, len, pk, algID);
  368.     if (rv) goto loser;
  369.     /* Fill out SignedData object */
  370.     PORT_Memset(&sd, 0, sizeof(sd));
  371.     sd.data.data = buf;
  372.     sd.data.len = len;
  373.     sd.signature.data = it.data;
  374.     sd.signature.len = it.len << 3; /* convert to bit string */
  375.     rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algID, 0);
  376.     if (rv) goto loser;
  377.     /* DER encode the signed data object */
  378.     rv = DER_Encode(arena, result, CERTSignedDataTemplate, &sd);
  379.     /* FALL THROUGH */
  380.   loser:
  381.     PORT_Free(it.data);
  382.     return rv;
  383. }
  384. SECStatus
  385. SGN_Digest(SECKEYPrivateKey *privKey,
  386. SECOidTag algtag, SECItem *result, SECItem *digest)
  387. {
  388.     unsigned modulusLen;
  389.     SECStatus rv;
  390.     SECItem digder;
  391.     PRArenaPool *arena = 0;
  392.     SGNDigestInfo *di = 0;
  393.     result->data = 0;
  394.     if (privKey->keyType == rsaKey) {
  395. arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  396. if ( !arena ) {
  397.     rv = SECFailure;
  398.     goto loser;
  399. }
  400.     
  401. /* Construct digest info */
  402. di = SGN_CreateDigestInfo(algtag, digest->data, digest->len);
  403. if (!di) {
  404.     rv = SECFailure;
  405.     goto loser;
  406. }
  407. /* Der encode the digest as a DigestInfo */
  408. rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, di);
  409. if (rv != SECSuccess) {
  410.     goto loser;
  411. }
  412.     } else {
  413. digder.data = digest->data;
  414. digder.len = digest->len;
  415.     }
  416.     /*
  417.     ** Encrypt signature after constructing appropriate PKCS#1 signature
  418.     ** block
  419.     */
  420.     modulusLen = PK11_SignatureLen(privKey);
  421.     result->len = modulusLen;
  422.     result->data = (unsigned char*) PORT_Alloc(modulusLen);
  423.     if (result->data == NULL) {
  424. rv = SECFailure;
  425. goto loser;
  426.     }
  427.     rv = PK11_Sign(privKey, result, &digder);
  428.     if (rv != SECSuccess) {
  429. PORT_Free(result->data);
  430. result->data = NULL;
  431.     }
  432.   loser:
  433.     SGN_DestroyDigestInfo(di);
  434.     if (arena != NULL) {
  435. PORT_FreeArena(arena, PR_FALSE);
  436.     }
  437.     return rv;
  438. }