jarsign.c (6095B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 /* 6 * JARSIGN 7 * 8 * Routines used in signing archives. 9 */ 10 11 #include "jar.h" 12 #include "jarint.h" 13 #include "secpkcs7.h" 14 #include "pk11func.h" 15 #include "sechash.h" 16 17 /* from libevent.h */ 18 typedef void (*ETVoidPtrFunc)(void *data); 19 20 /* key database wrapper */ 21 /* static SECKEYKeyDBHandle *jar_open_key_database (void); */ 22 /* CHUNQ is our bite size */ 23 24 #define CHUNQ 64000 25 #define FILECHUNQ 32768 26 27 /* 28 * J A R _ c a l c u l a t e _ d i g e s t 29 * 30 * Quick calculation of a digest for 31 * the specified block of memory. Will calculate 32 * for all supported algorithms, now MD5. 33 * 34 */ 35 JAR_Digest *PR_CALLBACK 36 JAR_calculate_digest(void *data, long length) 37 { 38 PK11Context *md5 = 0; 39 PK11Context *sha1 = 0; 40 JAR_Digest *dig = PORT_ZNew(JAR_Digest); 41 long chunq; 42 unsigned int md5_length, sha1_length; 43 44 if (dig == NULL) { 45 /* out of memory allocating digest */ 46 return NULL; 47 } 48 49 md5 = PK11_CreateDigestContext(SEC_OID_MD5); 50 if (md5 == NULL) { 51 PORT_ZFree(dig, sizeof(JAR_Digest)); 52 return NULL; 53 } 54 sha1 = PK11_CreateDigestContext(SEC_OID_SHA1); 55 if (sha1 == NULL) { 56 PK11_DestroyContext(md5, PR_TRUE); 57 /* added due to bug Bug 1250214 - prevent the 2nd memory leak */ 58 PORT_ZFree(dig, sizeof(JAR_Digest)); 59 return NULL; 60 } 61 62 if (length >= 0) { 63 PK11_DigestBegin(md5); 64 PK11_DigestBegin(sha1); 65 66 do { 67 chunq = length; 68 69 PK11_DigestOp(md5, (unsigned char *)data, chunq); 70 PK11_DigestOp(sha1, (unsigned char *)data, chunq); 71 length -= chunq; 72 data = ((char *)data + chunq); 73 } while (length > 0); 74 75 PK11_DigestFinal(md5, dig->md5, &md5_length, MD5_LENGTH); 76 PK11_DigestFinal(sha1, dig->sha1, &sha1_length, SHA1_LENGTH); 77 78 PK11_DestroyContext(md5, PR_TRUE); 79 PK11_DestroyContext(sha1, PR_TRUE); 80 } 81 return dig; 82 } 83 84 /* 85 * J A R _ d i g e s t _ f i l e 86 * 87 * Calculates the MD5 and SHA1 digests for a file 88 * present on disk, and returns these in JAR_Digest struct. 89 * 90 */ 91 int 92 JAR_digest_file(char *filename, JAR_Digest *dig) 93 { 94 JAR_FILE fp; 95 PK11Context *md5 = 0; 96 PK11Context *sha1 = 0; 97 unsigned char *buf = (unsigned char *)PORT_ZAlloc(FILECHUNQ); 98 int num; 99 unsigned int md5_length, sha1_length; 100 101 if (buf == NULL) { 102 /* out of memory */ 103 return JAR_ERR_MEMORY; 104 } 105 106 if ((fp = JAR_FOPEN(filename, "rb")) == 0) { 107 /* perror (filename); FIX XXX XXX XXX XXX XXX XXX */ 108 PORT_Free(buf); 109 return JAR_ERR_FNF; 110 } 111 112 md5 = PK11_CreateDigestContext(SEC_OID_MD5); 113 sha1 = PK11_CreateDigestContext(SEC_OID_SHA1); 114 115 if (md5 == NULL || sha1 == NULL) { 116 if (md5) { 117 PK11_DestroyContext(md5, PR_TRUE); 118 } 119 if (sha1) { 120 PK11_DestroyContext(sha1, PR_TRUE); 121 } 122 /* can't generate digest contexts */ 123 PORT_Free(buf); 124 JAR_FCLOSE(fp); 125 return JAR_ERR_GENERAL; 126 } 127 128 PK11_DigestBegin(md5); 129 PK11_DigestBegin(sha1); 130 131 while (1) { 132 if ((num = JAR_FREAD(fp, buf, FILECHUNQ)) == 0) 133 break; 134 135 PK11_DigestOp(md5, buf, num); 136 PK11_DigestOp(sha1, buf, num); 137 } 138 139 PK11_DigestFinal(md5, dig->md5, &md5_length, MD5_LENGTH); 140 PK11_DigestFinal(sha1, dig->sha1, &sha1_length, SHA1_LENGTH); 141 142 PK11_DestroyContext(md5, PR_TRUE); 143 PK11_DestroyContext(sha1, PR_TRUE); 144 145 PORT_Free(buf); 146 JAR_FCLOSE(fp); 147 148 return 0; 149 } 150 151 /* 152 * J A R _ o p e n _ k e y _ d a t a b a s e 153 * 154 */ 155 156 void * 157 jar_open_key_database(void) 158 { 159 return NULL; 160 } 161 162 int 163 jar_close_key_database(void *keydb) 164 { 165 /* We never do close it */ 166 return 0; 167 } 168 169 /* 170 * j a r _ c r e a t e _ p k 7 171 * 172 */ 173 174 static void 175 jar_pk7_out(void *arg, const char *buf, unsigned long len) 176 { 177 JAR_FWRITE((JAR_FILE)arg, buf, len); 178 } 179 180 int 181 jar_create_pk7(CERTCertDBHandle *certdb, void *keydb, CERTCertificate *cert, 182 char *password, JAR_FILE infp, JAR_FILE outfp) 183 { 184 SEC_PKCS7ContentInfo *cinfo; 185 const SECHashObject *hashObj; 186 void *mw = NULL; 187 void *hashcx; 188 unsigned int len; 189 int status = 0; 190 SECStatus rv; 191 SECItem digest; 192 unsigned char digestdata[32]; 193 unsigned char buffer[4096]; 194 195 if (outfp == NULL || infp == NULL || cert == NULL) 196 return JAR_ERR_GENERAL; 197 198 /* we sign with SHA */ 199 hashObj = HASH_GetHashObject(HASH_AlgSHA1); 200 201 hashcx = (*hashObj->create)(); 202 if (hashcx == NULL) 203 return JAR_ERR_GENERAL; 204 205 (*hashObj->begin)(hashcx); 206 while (1) { 207 int nb = JAR_FREAD(infp, buffer, sizeof buffer); 208 if (nb == 0) { /* eof */ 209 break; 210 } 211 (*hashObj->update)(hashcx, buffer, nb); 212 } 213 (*hashObj->end)(hashcx, digestdata, &len, 32); 214 (*hashObj->destroy)(hashcx, PR_TRUE); 215 216 digest.data = digestdata; 217 digest.len = len; 218 219 /* signtool must use any old context it can find since it's 220 calling from inside javaland. */ 221 PORT_SetError(0); 222 cinfo = SEC_PKCS7CreateSignedData(cert, certUsageObjectSigner, NULL, 223 SEC_OID_SHA1, &digest, NULL, mw); 224 if (cinfo == NULL) 225 return JAR_ERR_PK7; 226 227 rv = SEC_PKCS7IncludeCertChain(cinfo, NULL); 228 if (rv != SECSuccess) { 229 status = PORT_GetError(); 230 SEC_PKCS7DestroyContentInfo(cinfo); 231 return status; 232 } 233 234 /* Having this here forces signtool to always include signing time. */ 235 rv = SEC_PKCS7AddSigningTime(cinfo); 236 /* don't check error */ 237 PORT_SetError(0); 238 239 /* if calling from mozilla thread*/ 240 rv = SEC_PKCS7Encode(cinfo, jar_pk7_out, outfp, NULL, NULL, mw); 241 if (rv != SECSuccess) 242 status = PORT_GetError(); 243 SEC_PKCS7DestroyContentInfo(cinfo); 244 if (rv != SECSuccess) { 245 return ((status < 0) ? status : JAR_ERR_GENERAL); 246 } 247 return 0; 248 }