1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/jar/jarsign.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,238 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/* 1.9 + * JARSIGN 1.10 + * 1.11 + * Routines used in signing archives. 1.12 + */ 1.13 + 1.14 + 1.15 +#include "jar.h" 1.16 +#include "jarint.h" 1.17 +#include "secpkcs7.h" 1.18 +#include "pk11func.h" 1.19 +#include "sechash.h" 1.20 + 1.21 +/* from libevent.h */ 1.22 +typedef void (*ETVoidPtrFunc) (void * data); 1.23 + 1.24 +/* key database wrapper */ 1.25 +/* static SECKEYKeyDBHandle *jar_open_key_database (void); */ 1.26 +/* CHUNQ is our bite size */ 1.27 + 1.28 +#define CHUNQ 64000 1.29 +#define FILECHUNQ 32768 1.30 + 1.31 +/* 1.32 + * J A R _ c a l c u l a t e _ d i g e s t 1.33 + * 1.34 + * Quick calculation of a digest for 1.35 + * the specified block of memory. Will calculate 1.36 + * for all supported algorithms, now MD5. 1.37 + * 1.38 + * This version supports huge pointers for WIN16. 1.39 + * 1.40 + */ 1.41 +JAR_Digest * PR_CALLBACK 1.42 +JAR_calculate_digest(void *data, long length) 1.43 +{ 1.44 + PK11Context *md5 = 0; 1.45 + PK11Context *sha1 = 0; 1.46 + JAR_Digest *dig = PORT_ZNew(JAR_Digest); 1.47 + long chunq; 1.48 + unsigned int md5_length, sha1_length; 1.49 + 1.50 + if (dig == NULL) { 1.51 + /* out of memory allocating digest */ 1.52 + return NULL; 1.53 + } 1.54 + 1.55 + md5 = PK11_CreateDigestContext(SEC_OID_MD5); 1.56 + sha1 = PK11_CreateDigestContext(SEC_OID_SHA1); 1.57 + 1.58 + if (length >= 0) { 1.59 + PK11_DigestBegin (md5); 1.60 + PK11_DigestBegin (sha1); 1.61 + 1.62 + do { 1.63 + chunq = length; 1.64 + 1.65 + PK11_DigestOp(md5, (unsigned char*)data, chunq); 1.66 + PK11_DigestOp(sha1, (unsigned char*)data, chunq); 1.67 + length -= chunq; 1.68 + data = ((char *) data + chunq); 1.69 + } 1.70 + while (length > 0); 1.71 + 1.72 + PK11_DigestFinal (md5, dig->md5, &md5_length, MD5_LENGTH); 1.73 + PK11_DigestFinal (sha1, dig->sha1, &sha1_length, SHA1_LENGTH); 1.74 + 1.75 + PK11_DestroyContext (md5, PR_TRUE); 1.76 + PK11_DestroyContext (sha1, PR_TRUE); 1.77 + } 1.78 + return dig; 1.79 +} 1.80 + 1.81 +/* 1.82 + * J A R _ d i g e s t _ f i l e 1.83 + * 1.84 + * Calculates the MD5 and SHA1 digests for a file 1.85 + * present on disk, and returns these in JAR_Digest struct. 1.86 + * 1.87 + */ 1.88 +int 1.89 +JAR_digest_file (char *filename, JAR_Digest *dig) 1.90 +{ 1.91 + JAR_FILE fp; 1.92 + PK11Context *md5 = 0; 1.93 + PK11Context *sha1 = 0; 1.94 + unsigned char *buf = (unsigned char *) PORT_ZAlloc (FILECHUNQ); 1.95 + int num; 1.96 + unsigned int md5_length, sha1_length; 1.97 + 1.98 + if (buf == NULL) { 1.99 + /* out of memory */ 1.100 + return JAR_ERR_MEMORY; 1.101 + } 1.102 + 1.103 + if ((fp = JAR_FOPEN (filename, "rb")) == 0) { 1.104 + /* perror (filename); FIX XXX XXX XXX XXX XXX XXX */ 1.105 + PORT_Free (buf); 1.106 + return JAR_ERR_FNF; 1.107 + } 1.108 + 1.109 + md5 = PK11_CreateDigestContext (SEC_OID_MD5); 1.110 + sha1 = PK11_CreateDigestContext (SEC_OID_SHA1); 1.111 + 1.112 + if (md5 == NULL || sha1 == NULL) { 1.113 + /* can't generate digest contexts */ 1.114 + PORT_Free (buf); 1.115 + JAR_FCLOSE (fp); 1.116 + return JAR_ERR_GENERAL; 1.117 + } 1.118 + 1.119 + PK11_DigestBegin (md5); 1.120 + PK11_DigestBegin (sha1); 1.121 + 1.122 + while (1) { 1.123 + if ((num = JAR_FREAD (fp, buf, FILECHUNQ)) == 0) 1.124 + break; 1.125 + 1.126 + PK11_DigestOp (md5, buf, num); 1.127 + PK11_DigestOp (sha1, buf, num); 1.128 + } 1.129 + 1.130 + PK11_DigestFinal (md5, dig->md5, &md5_length, MD5_LENGTH); 1.131 + PK11_DigestFinal (sha1, dig->sha1, &sha1_length, SHA1_LENGTH); 1.132 + 1.133 + PK11_DestroyContext (md5, PR_TRUE); 1.134 + PK11_DestroyContext (sha1, PR_TRUE); 1.135 + 1.136 + PORT_Free (buf); 1.137 + JAR_FCLOSE (fp); 1.138 + 1.139 + return 0; 1.140 +} 1.141 + 1.142 +/* 1.143 + * J A R _ o p e n _ k e y _ d a t a b a s e 1.144 + * 1.145 + */ 1.146 + 1.147 +void* 1.148 +jar_open_key_database(void) 1.149 +{ 1.150 + return NULL; 1.151 +} 1.152 + 1.153 +int 1.154 +jar_close_key_database(void *keydb) 1.155 +{ 1.156 + /* We never do close it */ 1.157 + return 0; 1.158 +} 1.159 + 1.160 + 1.161 +/* 1.162 + * j a r _ c r e a t e _ p k 7 1.163 + * 1.164 + */ 1.165 + 1.166 +static void jar_pk7_out (void *arg, const char *buf, unsigned long len) 1.167 +{ 1.168 + JAR_FWRITE ((JAR_FILE) arg, buf, len); 1.169 +} 1.170 + 1.171 +int 1.172 +jar_create_pk7(CERTCertDBHandle *certdb, void *keydb, CERTCertificate *cert, 1.173 + char *password, JAR_FILE infp, JAR_FILE outfp) 1.174 +{ 1.175 + SEC_PKCS7ContentInfo *cinfo; 1.176 + const SECHashObject *hashObj; 1.177 + char *errstring; 1.178 + void *mw = NULL; 1.179 + void *hashcx; 1.180 + unsigned int len; 1.181 + int status = 0; 1.182 + SECStatus rv; 1.183 + SECItem digest; 1.184 + unsigned char digestdata[32]; 1.185 + unsigned char buffer[4096]; 1.186 + 1.187 + if (outfp == NULL || infp == NULL || cert == NULL) 1.188 + return JAR_ERR_GENERAL; 1.189 + 1.190 + /* we sign with SHA */ 1.191 + hashObj = HASH_GetHashObject(HASH_AlgSHA1); 1.192 + 1.193 + hashcx = (* hashObj->create)(); 1.194 + if (hashcx == NULL) 1.195 + return JAR_ERR_GENERAL; 1.196 + 1.197 + (* hashObj->begin)(hashcx); 1.198 + while (1) { 1.199 + int nb = JAR_FREAD(infp, buffer, sizeof buffer); 1.200 + if (nb == 0) { /* eof */ 1.201 + break; 1.202 + } 1.203 + (* hashObj->update) (hashcx, buffer, nb); 1.204 + } 1.205 + (* hashObj->end)(hashcx, digestdata, &len, 32); 1.206 + (* hashObj->destroy)(hashcx, PR_TRUE); 1.207 + 1.208 + digest.data = digestdata; 1.209 + digest.len = len; 1.210 + 1.211 + /* signtool must use any old context it can find since it's 1.212 + calling from inside javaland. */ 1.213 + PORT_SetError (0); 1.214 + cinfo = SEC_PKCS7CreateSignedData(cert, certUsageObjectSigner, NULL, 1.215 + SEC_OID_SHA1, &digest, NULL, mw); 1.216 + if (cinfo == NULL) 1.217 + return JAR_ERR_PK7; 1.218 + 1.219 + rv = SEC_PKCS7IncludeCertChain(cinfo, NULL); 1.220 + if (rv != SECSuccess) { 1.221 + status = PORT_GetError(); 1.222 + SEC_PKCS7DestroyContentInfo(cinfo); 1.223 + return status; 1.224 + } 1.225 + 1.226 + /* Having this here forces signtool to always include signing time. */ 1.227 + rv = SEC_PKCS7AddSigningTime(cinfo); 1.228 + /* don't check error */ 1.229 + PORT_SetError(0); 1.230 + 1.231 + /* if calling from mozilla thread*/ 1.232 + rv = SEC_PKCS7Encode(cinfo, jar_pk7_out, outfp, NULL, NULL, mw); 1.233 + if (rv != SECSuccess) 1.234 + status = PORT_GetError(); 1.235 + SEC_PKCS7DestroyContentInfo (cinfo); 1.236 + if (rv != SECSuccess) { 1.237 + errstring = JAR_get_error (status); 1.238 + return ((status < 0) ? status : JAR_ERR_GENERAL); 1.239 + } 1.240 + return 0; 1.241 +}