OLD | NEW |
1 /* This Source Code Form is subject to the terms of the Mozilla Public | 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 | 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/. */ | 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | 4 |
5 #include "signtool.h" | 5 #include "signtool.h" |
6 | 6 |
7 | 7 static int jar_cb(int status, JAR *jar, const char *metafile, char *pathname, |
8 static int» jar_cb(int status, JAR *jar, const char *metafile, | 8 char *errortext); |
9 char *pathname, char *errortext); | 9 static int verify_global(JAR *jar); |
10 static int» verify_global (JAR *jar); | |
11 | 10 |
12 /************************************************************************* | 11 /************************************************************************* |
13 * | 12 * |
14 * V e r i f y J a r | 13 * V e r i f y J a r |
15 */ | 14 */ |
16 int | 15 int VerifyJar(char *filename) { |
17 VerifyJar(char *filename) | 16 FILE *fp; |
18 { | 17 |
19 FILE * fp; | 18 int ret; |
20 | 19 int status; |
21 int»ret; | 20 int failed = 0; |
22 int»status; | 21 char *err; |
23 int»failed = 0; | 22 |
24 char» *err; | 23 JAR *jar; |
25 | 24 JAR_Context *ctx; |
26 JAR * jar; | 25 |
27 JAR_Context * ctx; | 26 JAR_Item *it; |
28 | 27 |
29 JAR_Item * it; | 28 jar = JAR_new(); |
30 | 29 |
31 jar = JAR_new(); | 30 if ((fp = fopen(filename, "r")) == NULL) { |
32 | 31 perror(filename); |
33 if ((fp = fopen (filename, "r")) == NULL) { | 32 exit(ERRX); |
34 » perror (filename); | 33 } else |
35 » exit (ERRX); | 34 fclose(fp); |
36 } else | 35 |
37 » fclose (fp); | 36 JAR_set_callback(JAR_CB_SIGNAL, jar, jar_cb); |
38 | 37 |
39 JAR_set_callback (JAR_CB_SIGNAL, jar, jar_cb); | 38 status = JAR_pass_archive(jar, jarArchGuess, filename, "some-url"); |
40 | 39 |
41 | 40 if (status < 0 || jar->valid < 0) { |
42 status = JAR_pass_archive (jar, jarArchGuess, filename, "some-url"); | 41 failed = 1; |
43 | 42 PR_fprintf(outputFD, |
44 if (status < 0 || jar->valid < 0) { | 43 "\nNOTE -- \"%s\" archive DID NOT PASS crypto verification.\n", |
45 » failed = 1; | 44 filename); |
46 » PR_fprintf(outputFD,· | 45 if (status < 0) { |
47 » "\nNOTE -- \"%s\" archive DID NOT PASS crypto verification.\n", | 46 const char *errtext; |
48 » filename); | 47 |
49 » if (status < 0) { | 48 if (status >= JAR_BASE && status <= JAR_BASE_END) { |
50 » const char» *errtext; | 49 errtext = JAR_get_error(status); |
51 | 50 } else { |
52 » if (status >= JAR_BASE && status <= JAR_BASE_END) { | 51 errtext = SECU_Strerror(PORT_GetError()); |
53 » » errtext = JAR_get_error (status); | 52 } |
54 » } else { | 53 |
55 » » errtext = SECU_Strerror(PORT_GetError()); | 54 PR_fprintf(outputFD, " (reported reason: %s)\n\n", errtext); |
56 » } | 55 |
57 | 56 /* corrupt files should not have their contents listed */ |
58 » PR_fprintf(outputFD, " (reported reason: %s)\n\n", | 57 |
59 » errtext); | 58 if (status == JAR_ERR_CORRUPT) return -1; |
60 | 59 } |
61 » /* corrupt files should not have their contents listed */ | 60 PR_fprintf(outputFD, |
62 | 61 "entries shown below will have their digests checked only.\n"); |
63 » if (status == JAR_ERR_CORRUPT) | 62 jar->valid = 0; |
64 » » return - 1; | 63 } else |
65 » } | 64 PR_fprintf(outputFD, "archive \"%s\" has passed crypto verification.\n", |
66 » PR_fprintf(outputFD, | 65 filename); |
67 » "entries shown below will have their digests checked only.\n"); | 66 |
68 » jar->valid = 0; | 67 if (verify_global(jar)) failed = 1; |
69 } else | 68 |
70 » PR_fprintf(outputFD, | 69 PR_fprintf(outputFD, "\n"); |
71 » "archive \"%s\" has passed crypto verification.\n", filename); | 70 PR_fprintf(outputFD, "%16s %s\n", "status", "path"); |
72 | 71 PR_fprintf(outputFD, "%16s %s\n", "------------", "-------------------"); |
73 if (verify_global (jar)) | 72 |
74 » failed = 1; | 73 ctx = JAR_find(jar, NULL, jarTypeMF); |
75 | 74 |
76 PR_fprintf(outputFD, "\n"); | 75 while (JAR_find_next(ctx, &it) >= 0) { |
77 PR_fprintf(outputFD, "%16s %s\n", "status", "path"); | 76 if (it && it->pathname) { |
78 PR_fprintf(outputFD, "%16s %s\n", "------------", "-------------------"); | 77 rm_dash_r(TMP_OUTPUT); |
79 | 78 ret = JAR_verified_extract(jar, it->pathname, TMP_OUTPUT); |
80 ctx = JAR_find (jar, NULL, jarTypeMF); | 79 /* if (ret < 0) printf ("error %d on %s\n", ret, it->pathname); */ |
81 | 80 if (ret < 0) failed = 1; |
82 while (JAR_find_next (ctx, &it) >= 0) { | 81 |
83 » if (it && it->pathname) { | 82 if (ret == JAR_ERR_PNF) |
84 » rm_dash_r(TMP_OUTPUT); | 83 err = "NOT PRESENT"; |
85 » ret = JAR_verified_extract (jar, it->pathname, TMP_OUTPUT); | 84 else if (ret == JAR_ERR_HASH) |
86 » /* if (ret < 0) printf ("error %d on %s\n", ret, it->pathname); */ | 85 err = "HASH FAILED"; |
87 » if (ret < 0) | 86 else |
88 » » failed = 1; | 87 err = "NOT VERIFIED"; |
89 | 88 |
90 » if (ret == JAR_ERR_PNF) | 89 PR_fprintf(outputFD, "%16s %s\n", ret >= 0 ? "verified" : err, |
91 » » err = "NOT PRESENT"; | 90 it->pathname); |
92 » else if (ret == JAR_ERR_HASH) | 91 |
93 » » err = "HASH FAILED"; | 92 if (ret != 0 && ret != JAR_ERR_PNF && ret != JAR_ERR_HASH) |
94 » else | 93 PR_fprintf(outputFD, " (reason: %s)\n", JAR_get_error(ret)); |
95 » » err = "NOT VERIFIED"; | 94 } |
96 | 95 } |
97 » PR_fprintf(outputFD, "%16s %s\n", | 96 |
98 » ret >= 0 ? "verified" : err, it->pathname); | 97 JAR_find_end(ctx); |
99 | 98 |
100 » if (ret != 0 && ret != JAR_ERR_PNF && ret != JAR_ERR_HASH) | 99 if (status < 0 || jar->valid < 0) { |
101 » » PR_fprintf(outputFD, " (reason: %s)\n", | 100 failed = 1; |
102 » » JAR_get_error (ret)); | 101 PR_fprintf(outputFD, |
103 » } | 102 "\nNOTE -- \"%s\" archive DID NOT PASS crypto verification.\n", |
104 } | 103 filename); |
105 | 104 give_help(status); |
106 JAR_find_end (ctx); | 105 } |
107 | 106 |
108 if (status < 0 || jar->valid < 0) { | 107 JAR_destroy(jar); |
109 » failed = 1; | 108 |
110 » PR_fprintf(outputFD, | 109 if (failed) return -1; |
111 » "\nNOTE -- \"%s\" archive DID NOT PASS crypto verification.\n", | 110 return 0; |
112 » filename); | |
113 » give_help (status); | |
114 } | |
115 | |
116 JAR_destroy (jar); | |
117 | |
118 if (failed) | |
119 » return - 1; | |
120 return 0; | |
121 } | 111 } |
122 | 112 |
123 | |
124 /*************************************************************************** | 113 /*************************************************************************** |
125 * | 114 * |
126 * v e r i f y _ g l o b a l | 115 * v e r i f y _ g l o b a l |
127 */ | 116 */ |
128 static int»····· | 117 static int verify_global(JAR *jar) { |
129 verify_global (JAR *jar) | 118 FILE *fp; |
130 { | 119 JAR_Context *ctx; |
131 FILE * fp; | 120 JAR_Item *it; |
132 JAR_Context * ctx; | 121 JAR_Digest *globaldig; |
133 JAR_Item * it; | 122 char *ext; |
134 JAR_Digest * globaldig; | 123 unsigned char *md5_digest, *sha1_digest; |
135 char» * ext; | 124 unsigned int sha1_length, md5_length; |
136 unsigned char *md5_digest, *sha1_digest; | 125 int retval = 0; |
137 unsigned int sha1_length, md5_length; | 126 char buf[BUFSIZ]; |
138 int» retval = 0; | 127 |
139 char» buf [BUFSIZ]; | 128 ctx = JAR_find(jar, "*", jarTypePhy); |
140 | 129 |
141 ctx = JAR_find (jar, "*", jarTypePhy); | 130 while (JAR_find_next(ctx, &it) >= 0) { |
142 | 131 if (!PORT_Strncmp(it->pathname, "META-INF", 8)) { |
143 while (JAR_find_next (ctx, &it) >= 0) { | 132 for (ext = it->pathname; *ext; ext++) |
144 » if (!PORT_Strncmp (it->pathname, "META-INF", 8)) { | 133 ; |
145 » for (ext = it->pathname; *ext; ext++) | 134 while (ext > it->pathname && *ext != '.') ext--; |
146 » » ; | 135 |
147 » while (ext > it->pathname && *ext != '.') | 136 if (verbosity >= 0) { |
148 » » ext--; | 137 if (!PORT_Strcasecmp(ext, ".rsa")) { |
149 | 138 PR_fprintf(outputFD, "found a RSA signature file: %s\n", |
150 » if (verbosity >= 0) { | 139 it->pathname); |
151 » » if (!PORT_Strcasecmp (ext, ".rsa")) { | 140 } |
152 » » PR_fprintf(outputFD, "found a RSA signature file: %s\n", | 141 |
153 » » » » » » it->pathname); | 142 if (!PORT_Strcasecmp(ext, ".dsa")) { |
154 » » } | 143 PR_fprintf(outputFD, "found a DSA signature file: %s\n", |
155 | 144 it->pathname); |
156 » » if (!PORT_Strcasecmp (ext, ".dsa")) { | 145 } |
157 » » PR_fprintf(outputFD, "found a DSA signature file: %s\n", | 146 |
158 » » » » » » it->pathname); | 147 if (!PORT_Strcasecmp(ext, ".mf")) { |
159 » » } | 148 PR_fprintf(outputFD, "found a MF master manifest file: %s\n", |
160 | 149 it->pathname); |
161 » » if (!PORT_Strcasecmp (ext, ".mf")) { | 150 } |
162 » » PR_fprintf(outputFD, | 151 } |
163 » » "found a MF master manifest file: %s\n", | 152 |
164 » » it->pathname); | 153 if (!PORT_Strcasecmp(ext, ".sf")) { |
165 » » } | 154 if (verbosity >= 0) { |
166 » } | 155 PR_fprintf(outputFD, "found a SF signature manifest file: %s\n", |
167 | 156 it->pathname); |
168 » if (!PORT_Strcasecmp (ext, ".sf")) { | 157 } |
169 » » if (verbosity >= 0) { | 158 |
170 » » PR_fprintf(outputFD, | 159 rm_dash_r(TMP_OUTPUT); |
171 » » "found a SF signature manifest file: %s\n", | 160 if (JAR_extract(jar, it->pathname, TMP_OUTPUT) < 0) { |
172 » » it->pathname); | 161 PR_fprintf(errorFD, "%s: error extracting %s\n", PROGRAM_NAME, |
173 » » } | 162 it->pathname); |
174 | 163 errorCount++; |
175 » » rm_dash_r(TMP_OUTPUT); | 164 retval = -1; |
176 » » if (JAR_extract (jar, it->pathname, TMP_OUTPUT) < 0) { | 165 continue; |
177 » » PR_fprintf(errorFD, "%s: error extracting %s\n", | 166 } |
178 » » PROGRAM_NAME, it->pathname); | 167 |
179 » » errorCount++; | 168 md5_digest = NULL; |
180 » » retval = -1; | 169 sha1_digest = NULL; |
181 » » continue; | 170 |
182 » » } | 171 if ((fp = fopen(TMP_OUTPUT, "rb")) != NULL) { |
183 | 172 while (fgets(buf, BUFSIZ, fp)) { |
184 » » md5_digest = NULL; | 173 char *s; |
185 » » sha1_digest = NULL; | 174 |
186 | 175 if (*buf == 0 || *buf == '\n' || *buf == '\r') break; |
187 » » if ((fp = fopen (TMP_OUTPUT, "rb")) != NULL) { | 176 |
188 » » while (fgets (buf, BUFSIZ, fp)) { | 177 for (s = buf; *s && *s != '\n' && *s != '\r'; s++) |
189 » » » char» *s; | 178 ; |
190 | 179 *s = 0; |
191 » » » if (*buf == 0 || *buf == '\n' || *buf == '\r') | 180 |
192 » » » break; | 181 if (!PORT_Strncmp(buf, "MD5-Digest: ", 12)) { |
193 | 182 md5_digest = ATOB_AsciiToData(buf + 12, &md5_length); |
194 » » » for (s = buf; *s && *s != '\n' && *s != '\r'; s++) | 183 } |
195 » » » ; | 184 if (!PORT_Strncmp(buf, "SHA1-Digest: ", 13)) { |
196 » » » *s = 0; | 185 sha1_digest = ATOB_AsciiToData(buf + 13, &sha1_length); |
197 | 186 } |
198 » » » if (!PORT_Strncmp (buf, "MD5-Digest: ", 12)) { | 187 if (!PORT_Strncmp(buf, "SHA-Digest: ", 12)) { |
199 » » » md5_digest = | 188 sha1_digest = ATOB_AsciiToData(buf + 12, &sha1_length); |
200 » » » » ATOB_AsciiToData (buf + 12, &md5_length); | 189 } |
201 » » » } | 190 } |
202 » » » if (!PORT_Strncmp (buf, "SHA1-Digest: ", 13)) { | 191 |
203 » » » sha1_digest = | 192 globaldig = jar->globalmeta; |
204 » » » » ATOB_AsciiToData (buf + 13, &sha1_length); | 193 |
205 » » » } | 194 if (globaldig && md5_digest && verbosity >= 0) { |
206 » » » if (!PORT_Strncmp (buf, "SHA-Digest: ", 12)) { | 195 PR_fprintf(outputFD, " md5 digest on global metainfo: %s\n", |
207 » » » sha1_digest = | 196 PORT_Memcmp(md5_digest, globaldig->md5, MD5_LENGTH) |
208 » » » » ATOB_AsciiToData (buf + 12, &sha1_length); | 197 ? "no match" |
209 » » » } | 198 : "match"); |
210 » » } | 199 } |
211 | 200 |
212 » » globaldig = jar->globalmeta; | 201 if (globaldig && sha1_digest && verbosity >= 0) { |
213 | 202 PR_fprintf(outputFD, " sha digest on global metainfo: %s\n", |
214 » » if (globaldig && md5_digest && verbosity >= 0) { | 203 PORT_Memcmp(sha1_digest, globaldig->sha1, SHA1_LENGTH) |
215 » » » PR_fprintf(outputFD, | 204 ? "no match" |
216 » » » " md5 digest on global metainfo: %s\n", | 205 : "match"); |
217 » » » PORT_Memcmp(md5_digest, globaldig->md5, MD5_LENGTH) | 206 } |
218 » » » ? "no match" : "match"); | 207 |
219 » » } | 208 if (globaldig == NULL && verbosity >= 0) { |
220 | 209 PR_fprintf(outputFD, |
221 » » if (globaldig && sha1_digest && verbosity >= 0) { | 210 "global metadigest is not available, strange.\n"); |
222 » » » PR_fprintf(outputFD, | 211 } |
223 » » » " sha digest on global metainfo: %s\n", | 212 |
224 » » » PORT_Memcmp(sha1_digest, globaldig->sha1, SHA1_LENGT
H)· | 213 fclose(fp); |
225 » » » ? "no match" : "match"); | 214 } |
226 » » } | 215 } |
227 | 216 } |
228 » » if (globaldig == NULL && verbosity >= 0) { | 217 } |
229 » » » PR_fprintf(outputFD, | 218 |
230 » » » "global metadigest is not available, strange.\n"); | 219 JAR_find_end(ctx); |
231 » » } | 220 |
232 | 221 return retval; |
233 » » fclose (fp); | |
234 » » } | |
235 » } | |
236 » } | |
237 } | |
238 | |
239 JAR_find_end (ctx); | |
240 | |
241 return retval; | |
242 } | 222 } |
243 | 223 |
244 | |
245 /************************************************************************ | 224 /************************************************************************ |
246 * | 225 * |
247 * J a r W h o | 226 * J a r W h o |
248 */ | 227 */ |
249 int | 228 int JarWho(char *filename) { |
250 JarWho(char *filename) | 229 FILE *fp; |
251 { | 230 |
252 FILE * fp; | 231 JAR *jar; |
253 | 232 JAR_Context *ctx; |
254 JAR * jar; | 233 |
255 JAR_Context * ctx; | 234 int status; |
256 | 235 int retval = 0; |
257 int»status; | 236 |
258 int»retval = 0; | 237 JAR_Item *it; |
259 | 238 JAR_Cert *fing; |
260 JAR_Item * it; | 239 |
261 JAR_Cert * fing; | 240 CERTCertificate *cert, *prev = NULL; |
262 | 241 |
263 CERTCertificate * cert, *prev = NULL; | 242 jar = JAR_new(); |
264 | 243 |
265 jar = JAR_new(); | 244 if ((fp = fopen(filename, "r")) == NULL) { |
266 | 245 perror(filename); |
267 if ((fp = fopen (filename, "r")) == NULL) { | 246 exit(ERRX); |
268 » perror (filename); | 247 } |
269 » exit (ERRX); | 248 fclose(fp); |
270 }· | 249 |
271 fclose (fp); | 250 status = JAR_pass_archive(jar, jarArchGuess, filename, "some-url"); |
272 | 251 |
273 status = JAR_pass_archive (jar, jarArchGuess, filename, "some-url"); | 252 if (status < 0 || jar->valid < 0) { |
274 | 253 PR_fprintf(outputFD, |
275 if (status < 0 || jar->valid < 0) { | 254 "NOTE -- \"%s\" archive DID NOT PASS crypto verification.\n", |
276 » PR_fprintf(outputFD, | 255 filename); |
277 » "NOTE -- \"%s\" archive DID NOT PASS crypto verification.\n", | 256 retval = -1; |
278 » filename); | 257 if (jar->valid < 0 || status != -1) { |
279 » retval = -1; | 258 const char *errtext; |
280 » if (jar->valid < 0 || status != -1) { | 259 |
281 » const char» *errtext; | 260 if (status >= JAR_BASE && status <= JAR_BASE_END) { |
282 | 261 errtext = JAR_get_error(status); |
283 » if (status >= JAR_BASE && status <= JAR_BASE_END) { | 262 } else { |
284 » » errtext = JAR_get_error (status); | 263 errtext = SECU_Strerror(PORT_GetError()); |
285 » } else { | 264 } |
286 » » errtext = SECU_Strerror(PORT_GetError()); | 265 |
287 » } | 266 PR_fprintf(outputFD, " (reported reason: %s)\n\n", errtext); |
288 | 267 } |
289 » PR_fprintf(outputFD, " (reported reason: %s)\n\n", errtext); | 268 } |
290 » } | 269 |
291 } | 270 PR_fprintf(outputFD, "\nSigner information:\n\n"); |
292 | 271 |
293 PR_fprintf(outputFD, "\nSigner information:\n\n"); | 272 ctx = JAR_find(jar, NULL, jarTypeSign); |
294 | 273 |
295 ctx = JAR_find (jar, NULL, jarTypeSign); | 274 while (JAR_find_next(ctx, &it) >= 0) { |
296 | 275 fing = (JAR_Cert *)it->data; |
297 while (JAR_find_next (ctx, &it) >= 0) { | 276 cert = fing->cert; |
298 » fing = (JAR_Cert * ) it->data; | 277 |
299 » cert = fing->cert; | 278 if (cert) { |
300 | 279 if (prev == cert) break; |
301 » if (cert) { | 280 |
302 » if (prev == cert) | 281 if (cert->nickname) |
303 » » break; | 282 PR_fprintf(outputFD, "nickname: %s\n", cert->nickname); |
304 | 283 if (cert->subjectName) |
305 » if (cert->nickname) | 284 PR_fprintf(outputFD, "subject name: %s\n", cert->subjectName); |
306 » » PR_fprintf(outputFD, "nickname: %s\n", cert->nickname); | 285 if (cert->issuerName) |
307 » if (cert->subjectName) | 286 PR_fprintf(outputFD, "issuer name: %s\n", cert->issuerName); |
308 » » PR_fprintf(outputFD, "subject name: %s\n", | 287 } else { |
309 » » cert->subjectName); | 288 PR_fprintf(outputFD, "no certificate could be found\n"); |
310 » if (cert->issuerName) | 289 retval = -1; |
311 » » PR_fprintf(outputFD, "issuer name: %s\n", cert->issuerName); | 290 } |
312 » } else { | 291 |
313 » PR_fprintf(outputFD, "no certificate could be found\n"); | 292 prev = cert; |
314 » retval = -1; | 293 } |
315 » } | 294 |
316 | 295 JAR_find_end(ctx); |
317 » prev = cert; | 296 |
318 } | 297 JAR_destroy(jar); |
319 | 298 return retval; |
320 JAR_find_end (ctx); | |
321 | |
322 JAR_destroy (jar); | |
323 return retval; | |
324 } | 299 } |
325 | 300 |
326 | |
327 /************************************************************************ | 301 /************************************************************************ |
328 * j a r _ c b | 302 * j a r _ c b |
329 */ | 303 */ |
330 static int» jar_cb(int status, JAR *jar, const char *metafile, | 304 static int jar_cb(int status, JAR *jar, const char *metafile, char *pathname, |
331 char *pathname, char *errortext) | 305 char *errortext) { |
332 { | 306 PR_fprintf(errorFD, "error %d: %s IN FILE %s\n", status, errortext, pathname); |
333 PR_fprintf(errorFD, "error %d: %s IN FILE %s\n", status, errortext, | 307 errorCount++; |
334 pathname); | 308 return 0; |
335 errorCount++; | |
336 return 0; | |
337 } | 309 } |
338 | |
339 | |
OLD | NEW |