summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/jar/jarsign.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/jar/jarsign.c')
-rw-r--r--security/nss/lib/jar/jarsign.c250
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;
+}