diff options
Diffstat (limited to 'security/nss/lib/jar/jarsign.c')
-rw-r--r-- | security/nss/lib/jar/jarsign.c | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/security/nss/lib/jar/jarsign.c b/security/nss/lib/jar/jarsign.c new file mode 100644 index 0000000000..601a7fd044 --- /dev/null +++ b/security/nss/lib/jar/jarsign.c @@ -0,0 +1,250 @@ +/* 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/. */ + +/* + * 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 + +/* + * J A R _ c a l c u l a t e _ d i g e s t + * + * 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. + * + */ +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; + + if (dig == NULL) { + /* out of memory allocating digest */ + return NULL; + } + + md5 = PK11_CreateDigestContext(SEC_OID_MD5); + if (md5 == NULL) { + PORT_ZFree(dig, sizeof(JAR_Digest)); + return NULL; + } + sha1 = PK11_CreateDigestContext(SEC_OID_SHA1); + if (sha1 == NULL) { + PK11_DestroyContext(md5, PR_TRUE); + /* added due to bug Bug 1250214 - prevent the 2nd memory leak */ + PORT_ZFree(dig, sizeof(JAR_Digest)); + return NULL; + } + + if (length >= 0) { + PK11_DigestBegin(md5); + PK11_DigestBegin(sha1); + + do { + chunq = length; + + PK11_DigestOp(md5, (unsigned char *)data, chunq); + PK11_DigestOp(sha1, (unsigned char *)data, chunq); + length -= chunq; + data = ((char *)data + chunq); + } while (length > 0); + + 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); + } + return dig; +} + +/* + * J A R _ d i g e s t _ f i l e + * + * Calculates the MD5 and SHA1 digests for a file + * present on disk, and returns these in JAR_Digest struct. + * + */ +int +JAR_digest_file(char *filename, JAR_Digest *dig) +{ + JAR_FILE fp; + PK11Context *md5 = 0; + PK11Context *sha1 = 0; + unsigned char *buf = (unsigned char *)PORT_ZAlloc(FILECHUNQ); + int num; + unsigned int md5_length, sha1_length; + + 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; + } + + md5 = PK11_CreateDigestContext(SEC_OID_MD5); + sha1 = PK11_CreateDigestContext(SEC_OID_SHA1); + + if (md5 == NULL || sha1 == NULL) { + if (md5) { + PK11_DestroyContext(md5, PR_TRUE); + } + if (sha1) { + PK11_DestroyContext(sha1, PR_TRUE); + } + /* can't generate digest contexts */ + PORT_Free(buf); + JAR_FCLOSE(fp); + return JAR_ERR_GENERAL; + } + + PK11_DigestBegin(md5); + PK11_DigestBegin(sha1); + + while (1) { + if ((num = JAR_FREAD(fp, buf, FILECHUNQ)) == 0) + break; + + PK11_DigestOp(md5, buf, num); + PK11_DigestOp(sha1, buf, num); + } + + 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; +} + +/* + * J A R _ o p e n _ k e y _ d a t a b a s e + * + */ + +void * +jar_open_key_database(void) +{ + return NULL; +} + +int +jar_close_key_database(void *keydb) +{ + /* We never do close it */ + return 0; +} + +/* + * 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) +{ + 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); + } + (*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; + } + + /* Having this here forces signtool to always include signing time. */ + rv = SEC_PKCS7AddSigningTime(cinfo); + /* don't check error */ + PORT_SetError(0); + + /* 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); + } + return 0; +} |