2018-05-04 16:08:28 +02:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2015-10-21 05:03:22 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
|
|
|
|
/*
|
2018-05-04 16:08:28 +02:00
|
|
|
* J A R _ c a l c u l a t e _ d i g e s t
|
2015-10-21 05:03:22 +02: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.
|
2018-05-04 16:08:28 +02:00
|
|
|
*
|
2015-10-21 05:03:22 +02:00
|
|
|
*/
|
2018-05-04 16:08:28 +02: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;
|
2015-10-21 05:03:22 +02:00
|
|
|
|
2018-05-04 16:08:28 +02:00
|
|
|
if (dig == NULL) {
|
|
|
|
/* out of memory allocating digest */
|
|
|
|
return NULL;
|
2015-10-21 05:03:22 +02:00
|
|
|
}
|
|
|
|
|
2018-05-04 16:08:28 +02:00
|
|
|
md5 = PK11_CreateDigestContext(SEC_OID_MD5);
|
|
|
|
sha1 = PK11_CreateDigestContext(SEC_OID_SHA1);
|
2015-10-21 05:03:22 +02:00
|
|
|
|
2018-05-04 16:08:28 +02:00
|
|
|
if (length >= 0) {
|
|
|
|
PK11_DigestBegin (md5);
|
|
|
|
PK11_DigestBegin (sha1);
|
2015-10-21 05:03:22 +02:00
|
|
|
|
2018-05-04 16:08:28 +02:00
|
|
|
do {
|
|
|
|
chunq = length;
|
2015-10-21 05:03:22 +02:00
|
|
|
|
2018-05-04 16:08:28 +02:00
|
|
|
PK11_DigestOp(md5, (unsigned char*)data, chunq);
|
|
|
|
PK11_DigestOp(sha1, (unsigned char*)data, chunq);
|
|
|
|
length -= chunq;
|
|
|
|
data = ((char *) data + chunq);
|
|
|
|
}
|
|
|
|
while (length > 0);
|
2015-10-21 05:03:22 +02:00
|
|
|
|
2018-05-04 16:08:28 +02:00
|
|
|
PK11_DigestFinal (md5, dig->md5, &md5_length, MD5_LENGTH);
|
|
|
|
PK11_DigestFinal (sha1, dig->sha1, &sha1_length, SHA1_LENGTH);
|
2015-10-21 05:03:22 +02:00
|
|
|
|
2018-05-04 16:08:28 +02:00
|
|
|
PK11_DestroyContext (md5, PR_TRUE);
|
|
|
|
PK11_DestroyContext (sha1, PR_TRUE);
|
2015-10-21 05:03:22 +02:00
|
|
|
}
|
2018-05-04 16:08:28 +02:00
|
|
|
return dig;
|
|
|
|
}
|
2015-10-21 05:03:22 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* J A R _ d i g e s t _ f i l e
|
|
|
|
*
|
2018-05-04 16:08:28 +02:00
|
|
|
* Calculates the MD5 and SHA1 digests for a file
|
2015-10-21 05:03:22 +02:00
|
|
|
* present on disk, and returns these in JAR_Digest struct.
|
|
|
|
*
|
|
|
|
*/
|
2018-05-04 16:08:28 +02:00
|
|
|
int
|
|
|
|
JAR_digest_file (char *filename, JAR_Digest *dig)
|
|
|
|
{
|
2015-10-21 05:03:22 +02:00
|
|
|
JAR_FILE fp;
|
|
|
|
PK11Context *md5 = 0;
|
|
|
|
PK11Context *sha1 = 0;
|
2018-05-04 16:08:28 +02:00
|
|
|
unsigned char *buf = (unsigned char *) PORT_ZAlloc (FILECHUNQ);
|
|
|
|
int num;
|
2015-10-21 05:03:22 +02:00
|
|
|
unsigned int md5_length, sha1_length;
|
|
|
|
|
2018-05-04 16:08:28 +02: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;
|
|
|
|
}
|
2015-10-21 05:03:22 +02:00
|
|
|
|
|
|
|
md5 = PK11_CreateDigestContext (SEC_OID_MD5);
|
|
|
|
sha1 = PK11_CreateDigestContext (SEC_OID_SHA1);
|
|
|
|
|
2018-05-04 16:08:28 +02:00
|
|
|
if (md5 == NULL || sha1 == NULL) {
|
|
|
|
/* can't generate digest contexts */
|
|
|
|
PORT_Free (buf);
|
|
|
|
JAR_FCLOSE (fp);
|
|
|
|
return JAR_ERR_GENERAL;
|
|
|
|
}
|
2015-10-21 05:03:22 +02:00
|
|
|
|
|
|
|
PK11_DigestBegin (md5);
|
|
|
|
PK11_DigestBegin (sha1);
|
|
|
|
|
2018-05-04 16:08:28 +02:00
|
|
|
while (1) {
|
|
|
|
if ((num = JAR_FREAD (fp, buf, FILECHUNQ)) == 0)
|
|
|
|
break;
|
2015-10-21 05:03:22 +02:00
|
|
|
|
2018-05-04 16:08:28 +02:00
|
|
|
PK11_DigestOp (md5, buf, num);
|
|
|
|
PK11_DigestOp (sha1, buf, num);
|
|
|
|
}
|
2015-10-21 05:03:22 +02: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;
|
2018-05-04 16:08:28 +02:00
|
|
|
}
|
2015-10-21 05:03:22 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* J A R _ o p e n _ k e y _ d a t a b a s e
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2018-05-04 16:08:28 +02:00
|
|
|
void*
|
|
|
|
jar_open_key_database(void)
|
|
|
|
{
|
2015-10-21 05:03:22 +02:00
|
|
|
return NULL;
|
2018-05-04 16:08:28 +02:00
|
|
|
}
|
2015-10-21 05:03:22 +02:00
|
|
|
|
2018-05-04 16:08:28 +02:00
|
|
|
int
|
|
|
|
jar_close_key_database(void *keydb)
|
|
|
|
{
|
|
|
|
/* We never do close it */
|
|
|
|
return 0;
|
|
|
|
}
|
2015-10-21 05:03:22 +02: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)
|
2018-05-04 16:08:28 +02: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);
|
2015-10-21 05:03:22 +02:00
|
|
|
}
|
2018-05-04 16:08:28 +02: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;
|
2015-10-21 05:03:22 +02:00
|
|
|
}
|
|
|
|
|
2018-05-04 16:08:28 +02:00
|
|
|
/* Having this here forces signtool to always include signing time. */
|
|
|
|
rv = SEC_PKCS7AddSigningTime(cinfo);
|
2015-10-21 05:03:22 +02:00
|
|
|
/* don't check error */
|
2018-05-04 16:08:28 +02:00
|
|
|
PORT_SetError(0);
|
2015-10-21 05:03:22 +02:00
|
|
|
|
2018-05-04 16:08:28 +02: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);
|
2015-10-21 05:03:22 +02:00
|
|
|
}
|
2018-05-04 16:08:28 +02:00
|
|
|
return 0;
|
|
|
|
}
|