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