2008-06-06 05:40:11 -07:00
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is the Netscape security libraries.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1994-2000
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* JARSIGN
|
|
|
|
*
|
|
|
|
* Routines used in signing archives.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "jar.h"
|
|
|
|
#include "jarint.h"
|
|
|
|
#include "secpkcs7.h"
|
|
|
|
#include "pk11func.h"
|
|
|
|
#include "sechash.h"
|
|
|
|
|
|
|
|
/* from libevent.h */
|
|
|
|
typedef void (*ETVoidPtrFunc) (void * data);
|
|
|
|
|
|
|
|
/* key database wrapper */
|
|
|
|
/* static SECKEYKeyDBHandle *jar_open_key_database (void); */
|
|
|
|
/* CHUNQ is our bite size */
|
|
|
|
|
|
|
|
#define CHUNQ 64000
|
|
|
|
#define FILECHUNQ 32768
|
|
|
|
|
|
|
|
/*
|
2009-05-05 08:22:50 -07:00
|
|
|
* J A R _ c a l c u l a t e _ d i g e s t
|
2008-06-06 05:40:11 -07:00
|
|
|
*
|
|
|
|
* Quick calculation of a digest for
|
|
|
|
* the specified block of memory. Will calculate
|
|
|
|
* for all supported algorithms, now MD5.
|
|
|
|
*
|
|
|
|
* This version supports huge pointers for WIN16.
|
2009-05-05 08:22:50 -07:00
|
|
|
*
|
2008-06-06 05:40:11 -07:00
|
|
|
*/
|
2009-05-05 08:22:50 -07:00
|
|
|
JAR_Digest * PR_CALLBACK
|
|
|
|
JAR_calculate_digest(void *data, long length)
|
|
|
|
{
|
|
|
|
PK11Context *md5 = 0;
|
|
|
|
PK11Context *sha1 = 0;
|
|
|
|
JAR_Digest *dig = PORT_ZNew(JAR_Digest);
|
|
|
|
long chunq;
|
|
|
|
unsigned int md5_length, sha1_length;
|
2008-06-06 05:40:11 -07:00
|
|
|
|
2009-05-05 08:22:50 -07:00
|
|
|
if (dig == NULL) {
|
|
|
|
/* out of memory allocating digest */
|
|
|
|
return NULL;
|
2008-06-06 05:40:11 -07:00
|
|
|
}
|
|
|
|
|
2009-05-05 08:22:50 -07:00
|
|
|
md5 = PK11_CreateDigestContext(SEC_OID_MD5);
|
|
|
|
sha1 = PK11_CreateDigestContext(SEC_OID_SHA1);
|
2008-06-06 05:40:11 -07:00
|
|
|
|
2009-05-05 08:22:50 -07:00
|
|
|
if (length >= 0) {
|
|
|
|
PK11_DigestBegin (md5);
|
|
|
|
PK11_DigestBegin (sha1);
|
2008-06-06 05:40:11 -07:00
|
|
|
|
2009-05-05 08:22:50 -07:00
|
|
|
do {
|
|
|
|
chunq = length;
|
2008-06-06 05:40:11 -07:00
|
|
|
|
2009-05-05 08:22:50 -07:00
|
|
|
PK11_DigestOp(md5, (unsigned char*)data, chunq);
|
|
|
|
PK11_DigestOp(sha1, (unsigned char*)data, chunq);
|
|
|
|
length -= chunq;
|
|
|
|
data = ((char *) data + chunq);
|
|
|
|
}
|
|
|
|
while (length > 0);
|
2008-06-06 05:40:11 -07:00
|
|
|
|
2009-05-05 08:22:50 -07:00
|
|
|
PK11_DigestFinal (md5, dig->md5, &md5_length, MD5_LENGTH);
|
|
|
|
PK11_DigestFinal (sha1, dig->sha1, &sha1_length, SHA1_LENGTH);
|
2008-06-06 05:40:11 -07:00
|
|
|
|
2009-05-05 08:22:50 -07:00
|
|
|
PK11_DestroyContext (md5, PR_TRUE);
|
|
|
|
PK11_DestroyContext (sha1, PR_TRUE);
|
2008-06-06 05:40:11 -07:00
|
|
|
}
|
2009-05-05 08:22:50 -07:00
|
|
|
return dig;
|
|
|
|
}
|
2008-06-06 05:40:11 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* J A R _ d i g e s t _ f i l e
|
|
|
|
*
|
2009-05-05 08:22:50 -07:00
|
|
|
* Calculates the MD5 and SHA1 digests for a file
|
2008-06-06 05:40:11 -07:00
|
|
|
* present on disk, and returns these in JAR_Digest struct.
|
|
|
|
*
|
|
|
|
*/
|
2009-05-05 08:22:50 -07:00
|
|
|
int
|
|
|
|
JAR_digest_file (char *filename, JAR_Digest *dig)
|
|
|
|
{
|
2008-06-06 05:40:11 -07:00
|
|
|
JAR_FILE fp;
|
|
|
|
PK11Context *md5 = 0;
|
|
|
|
PK11Context *sha1 = 0;
|
2009-05-05 08:22:50 -07:00
|
|
|
unsigned char *buf = (unsigned char *) PORT_ZAlloc (FILECHUNQ);
|
|
|
|
int num;
|
2008-06-06 05:40:11 -07:00
|
|
|
unsigned int md5_length, sha1_length;
|
|
|
|
|
2009-05-05 08:22:50 -07:00
|
|
|
if (buf == NULL) {
|
|
|
|
/* out of memory */
|
|
|
|
return JAR_ERR_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fp = JAR_FOPEN (filename, "rb")) == 0) {
|
|
|
|
/* perror (filename); FIX XXX XXX XXX XXX XXX XXX */
|
|
|
|
PORT_Free (buf);
|
|
|
|
return JAR_ERR_FNF;
|
|
|
|
}
|
2008-06-06 05:40:11 -07:00
|
|
|
|
|
|
|
md5 = PK11_CreateDigestContext (SEC_OID_MD5);
|
|
|
|
sha1 = PK11_CreateDigestContext (SEC_OID_SHA1);
|
|
|
|
|
2009-05-05 08:22:50 -07:00
|
|
|
if (md5 == NULL || sha1 == NULL) {
|
|
|
|
/* can't generate digest contexts */
|
|
|
|
PORT_Free (buf);
|
|
|
|
JAR_FCLOSE (fp);
|
|
|
|
return JAR_ERR_GENERAL;
|
|
|
|
}
|
2008-06-06 05:40:11 -07:00
|
|
|
|
|
|
|
PK11_DigestBegin (md5);
|
|
|
|
PK11_DigestBegin (sha1);
|
|
|
|
|
2009-05-05 08:22:50 -07:00
|
|
|
while (1) {
|
|
|
|
if ((num = JAR_FREAD (fp, buf, FILECHUNQ)) == 0)
|
|
|
|
break;
|
2008-06-06 05:40:11 -07:00
|
|
|
|
2009-05-05 08:22:50 -07:00
|
|
|
PK11_DigestOp (md5, buf, num);
|
|
|
|
PK11_DigestOp (sha1, buf, num);
|
|
|
|
}
|
2008-06-06 05:40:11 -07:00
|
|
|
|
|
|
|
PK11_DigestFinal (md5, dig->md5, &md5_length, MD5_LENGTH);
|
|
|
|
PK11_DigestFinal (sha1, dig->sha1, &sha1_length, SHA1_LENGTH);
|
|
|
|
|
|
|
|
PK11_DestroyContext (md5, PR_TRUE);
|
|
|
|
PK11_DestroyContext (sha1, PR_TRUE);
|
|
|
|
|
|
|
|
PORT_Free (buf);
|
|
|
|
JAR_FCLOSE (fp);
|
|
|
|
|
|
|
|
return 0;
|
2009-05-05 08:22:50 -07:00
|
|
|
}
|
2008-06-06 05:40:11 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* J A R _ o p e n _ k e y _ d a t a b a s e
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2009-05-05 08:22:50 -07:00
|
|
|
void*
|
|
|
|
jar_open_key_database(void)
|
|
|
|
{
|
2008-06-06 05:40:11 -07:00
|
|
|
return NULL;
|
2009-05-05 08:22:50 -07:00
|
|
|
}
|
2008-06-06 05:40:11 -07:00
|
|
|
|
2009-05-05 08:22:50 -07:00
|
|
|
int
|
|
|
|
jar_close_key_database(void *keydb)
|
|
|
|
{
|
|
|
|
/* We never do close it */
|
|
|
|
return 0;
|
|
|
|
}
|
2008-06-06 05:40:11 -07:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* j a r _ c r e a t e _ p k 7
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void jar_pk7_out (void *arg, const char *buf, unsigned long len)
|
2009-05-05 08:22:50 -07:00
|
|
|
{
|
|
|
|
JAR_FWRITE ((JAR_FILE) arg, buf, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
jar_create_pk7(CERTCertDBHandle *certdb, void *keydb, CERTCertificate *cert,
|
|
|
|
char *password, JAR_FILE infp, JAR_FILE outfp)
|
|
|
|
{
|
|
|
|
SEC_PKCS7ContentInfo *cinfo;
|
|
|
|
const SECHashObject *hashObj;
|
|
|
|
char *errstring;
|
|
|
|
void *mw = NULL;
|
|
|
|
void *hashcx;
|
|
|
|
unsigned int len;
|
|
|
|
int status = 0;
|
|
|
|
SECStatus rv;
|
|
|
|
SECItem digest;
|
|
|
|
unsigned char digestdata[32];
|
|
|
|
unsigned char buffer[4096];
|
|
|
|
|
|
|
|
if (outfp == NULL || infp == NULL || cert == NULL)
|
|
|
|
return JAR_ERR_GENERAL;
|
|
|
|
|
|
|
|
/* we sign with SHA */
|
|
|
|
hashObj = HASH_GetHashObject(HASH_AlgSHA1);
|
|
|
|
|
|
|
|
hashcx = (* hashObj->create)();
|
|
|
|
if (hashcx == NULL)
|
|
|
|
return JAR_ERR_GENERAL;
|
|
|
|
|
|
|
|
(* hashObj->begin)(hashcx);
|
|
|
|
while (1) {
|
|
|
|
int nb = JAR_FREAD(infp, buffer, sizeof buffer);
|
|
|
|
if (nb == 0) { /* eof */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
(* hashObj->update) (hashcx, buffer, nb);
|
2008-06-06 05:40:11 -07:00
|
|
|
}
|
2009-05-05 08:22:50 -07:00
|
|
|
(* hashObj->end)(hashcx, digestdata, &len, 32);
|
|
|
|
(* hashObj->destroy)(hashcx, PR_TRUE);
|
|
|
|
|
|
|
|
digest.data = digestdata;
|
|
|
|
digest.len = len;
|
|
|
|
|
|
|
|
/* signtool must use any old context it can find since it's
|
|
|
|
calling from inside javaland. */
|
|
|
|
PORT_SetError (0);
|
|
|
|
cinfo = SEC_PKCS7CreateSignedData(cert, certUsageObjectSigner, NULL,
|
|
|
|
SEC_OID_SHA1, &digest, NULL, mw);
|
|
|
|
if (cinfo == NULL)
|
|
|
|
return JAR_ERR_PK7;
|
|
|
|
|
|
|
|
rv = SEC_PKCS7IncludeCertChain(cinfo, NULL);
|
|
|
|
if (rv != SECSuccess) {
|
|
|
|
status = PORT_GetError();
|
|
|
|
SEC_PKCS7DestroyContentInfo(cinfo);
|
|
|
|
return status;
|
2008-06-06 05:40:11 -07:00
|
|
|
}
|
|
|
|
|
2009-05-05 08:22:50 -07:00
|
|
|
/* Having this here forces signtool to always include signing time. */
|
|
|
|
rv = SEC_PKCS7AddSigningTime(cinfo);
|
2008-06-06 05:40:11 -07:00
|
|
|
/* don't check error */
|
2009-05-05 08:22:50 -07:00
|
|
|
PORT_SetError(0);
|
2008-06-06 05:40:11 -07:00
|
|
|
|
2009-05-05 08:22:50 -07:00
|
|
|
/* if calling from mozilla thread*/
|
|
|
|
rv = SEC_PKCS7Encode(cinfo, jar_pk7_out, outfp, NULL, NULL, mw);
|
|
|
|
if (rv != SECSuccess)
|
|
|
|
status = PORT_GetError();
|
|
|
|
SEC_PKCS7DestroyContentInfo (cinfo);
|
|
|
|
if (rv != SECSuccess) {
|
|
|
|
errstring = JAR_get_error (status);
|
|
|
|
return ((status < 0) ? status : JAR_ERR_GENERAL);
|
2008-06-06 05:40:11 -07:00
|
|
|
}
|
2009-05-05 08:22:50 -07:00
|
|
|
return 0;
|
|
|
|
}
|