RetroZilla/security/nss/lib/jar/jarsign.c

250 lines
5.6 KiB
C
Raw Normal View History

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
}
md5 = PK11_CreateDigestContext(SEC_OID_MD5);
if (md5 == NULL) {
return NULL;
}
2018-05-04 16:08:28 +02:00
sha1 = PK11_CreateDigestContext(SEC_OID_SHA1);
if (sha1 == NULL) {
PK11_DestroyContext(md5, PR_TRUE);
return NULL;
}
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) {
if (md5) {
PK11_DestroyContext(md5, PR_TRUE);
}
if (sha1) {
PK11_DestroyContext(sha1, PR_TRUE);
}
2018-05-04 16:08:28 +02:00
/* 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;
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) {
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;
}