1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/cmd/signtool/verify.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,339 @@ 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 +#include "signtool.h" 1.9 + 1.10 + 1.11 +static int jar_cb(int status, JAR *jar, const char *metafile, 1.12 +char *pathname, char *errortext); 1.13 +static int verify_global (JAR *jar); 1.14 + 1.15 +/************************************************************************* 1.16 + * 1.17 + * V e r i f y J a r 1.18 + */ 1.19 +int 1.20 +VerifyJar(char *filename) 1.21 +{ 1.22 + FILE * fp; 1.23 + 1.24 + int ret; 1.25 + int status; 1.26 + int failed = 0; 1.27 + char *err; 1.28 + 1.29 + JAR * jar; 1.30 + JAR_Context * ctx; 1.31 + 1.32 + JAR_Item * it; 1.33 + 1.34 + jar = JAR_new(); 1.35 + 1.36 + if ((fp = fopen (filename, "r")) == NULL) { 1.37 + perror (filename); 1.38 + exit (ERRX); 1.39 + } else 1.40 + fclose (fp); 1.41 + 1.42 + JAR_set_callback (JAR_CB_SIGNAL, jar, jar_cb); 1.43 + 1.44 + 1.45 + status = JAR_pass_archive (jar, jarArchGuess, filename, "some-url"); 1.46 + 1.47 + if (status < 0 || jar->valid < 0) { 1.48 + failed = 1; 1.49 + PR_fprintf(outputFD, 1.50 + "\nNOTE -- \"%s\" archive DID NOT PASS crypto verification.\n", 1.51 + filename); 1.52 + if (status < 0) { 1.53 + const char *errtext; 1.54 + 1.55 + if (status >= JAR_BASE && status <= JAR_BASE_END) { 1.56 + errtext = JAR_get_error (status); 1.57 + } else { 1.58 + errtext = SECU_Strerror(PORT_GetError()); 1.59 + } 1.60 + 1.61 + PR_fprintf(outputFD, " (reported reason: %s)\n\n", 1.62 + errtext); 1.63 + 1.64 + /* corrupt files should not have their contents listed */ 1.65 + 1.66 + if (status == JAR_ERR_CORRUPT) 1.67 + return - 1; 1.68 + } 1.69 + PR_fprintf(outputFD, 1.70 + "entries shown below will have their digests checked only.\n"); 1.71 + jar->valid = 0; 1.72 + } else 1.73 + PR_fprintf(outputFD, 1.74 + "archive \"%s\" has passed crypto verification.\n", filename); 1.75 + 1.76 + if (verify_global (jar)) 1.77 + failed = 1; 1.78 + 1.79 + PR_fprintf(outputFD, "\n"); 1.80 + PR_fprintf(outputFD, "%16s %s\n", "status", "path"); 1.81 + PR_fprintf(outputFD, "%16s %s\n", "------------", "-------------------"); 1.82 + 1.83 + ctx = JAR_find (jar, NULL, jarTypeMF); 1.84 + 1.85 + while (JAR_find_next (ctx, &it) >= 0) { 1.86 + if (it && it->pathname) { 1.87 + rm_dash_r(TMP_OUTPUT); 1.88 + ret = JAR_verified_extract (jar, it->pathname, TMP_OUTPUT); 1.89 + /* if (ret < 0) printf ("error %d on %s\n", ret, it->pathname); */ 1.90 + if (ret < 0) 1.91 + failed = 1; 1.92 + 1.93 + if (ret == JAR_ERR_PNF) 1.94 + err = "NOT PRESENT"; 1.95 + else if (ret == JAR_ERR_HASH) 1.96 + err = "HASH FAILED"; 1.97 + else 1.98 + err = "NOT VERIFIED"; 1.99 + 1.100 + PR_fprintf(outputFD, "%16s %s\n", 1.101 + ret >= 0 ? "verified" : err, it->pathname); 1.102 + 1.103 + if (ret != 0 && ret != JAR_ERR_PNF && ret != JAR_ERR_HASH) 1.104 + PR_fprintf(outputFD, " (reason: %s)\n", 1.105 + JAR_get_error (ret)); 1.106 + } 1.107 + } 1.108 + 1.109 + JAR_find_end (ctx); 1.110 + 1.111 + if (status < 0 || jar->valid < 0) { 1.112 + failed = 1; 1.113 + PR_fprintf(outputFD, 1.114 + "\nNOTE -- \"%s\" archive DID NOT PASS crypto verification.\n", 1.115 + filename); 1.116 + give_help (status); 1.117 + } 1.118 + 1.119 + JAR_destroy (jar); 1.120 + 1.121 + if (failed) 1.122 + return - 1; 1.123 + return 0; 1.124 +} 1.125 + 1.126 + 1.127 +/*************************************************************************** 1.128 + * 1.129 + * v e r i f y _ g l o b a l 1.130 + */ 1.131 +static int 1.132 +verify_global (JAR *jar) 1.133 +{ 1.134 + FILE * fp; 1.135 + JAR_Context * ctx; 1.136 + JAR_Item * it; 1.137 + JAR_Digest * globaldig; 1.138 + char * ext; 1.139 + unsigned char *md5_digest, *sha1_digest; 1.140 + unsigned int sha1_length, md5_length; 1.141 + int retval = 0; 1.142 + char buf [BUFSIZ]; 1.143 + 1.144 + ctx = JAR_find (jar, "*", jarTypePhy); 1.145 + 1.146 + while (JAR_find_next (ctx, &it) >= 0) { 1.147 + if (!PORT_Strncmp (it->pathname, "META-INF", 8)) { 1.148 + for (ext = it->pathname; *ext; ext++) 1.149 + ; 1.150 + while (ext > it->pathname && *ext != '.') 1.151 + ext--; 1.152 + 1.153 + if (verbosity >= 0) { 1.154 + if (!PORT_Strcasecmp (ext, ".rsa")) { 1.155 + PR_fprintf(outputFD, "found a RSA signature file: %s\n", 1.156 + it->pathname); 1.157 + } 1.158 + 1.159 + if (!PORT_Strcasecmp (ext, ".dsa")) { 1.160 + PR_fprintf(outputFD, "found a DSA signature file: %s\n", 1.161 + it->pathname); 1.162 + } 1.163 + 1.164 + if (!PORT_Strcasecmp (ext, ".mf")) { 1.165 + PR_fprintf(outputFD, 1.166 + "found a MF master manifest file: %s\n", 1.167 + it->pathname); 1.168 + } 1.169 + } 1.170 + 1.171 + if (!PORT_Strcasecmp (ext, ".sf")) { 1.172 + if (verbosity >= 0) { 1.173 + PR_fprintf(outputFD, 1.174 + "found a SF signature manifest file: %s\n", 1.175 + it->pathname); 1.176 + } 1.177 + 1.178 + rm_dash_r(TMP_OUTPUT); 1.179 + if (JAR_extract (jar, it->pathname, TMP_OUTPUT) < 0) { 1.180 + PR_fprintf(errorFD, "%s: error extracting %s\n", 1.181 + PROGRAM_NAME, it->pathname); 1.182 + errorCount++; 1.183 + retval = -1; 1.184 + continue; 1.185 + } 1.186 + 1.187 + md5_digest = NULL; 1.188 + sha1_digest = NULL; 1.189 + 1.190 + if ((fp = fopen (TMP_OUTPUT, "rb")) != NULL) { 1.191 + while (fgets (buf, BUFSIZ, fp)) { 1.192 + char *s; 1.193 + 1.194 + if (*buf == 0 || *buf == '\n' || *buf == '\r') 1.195 + break; 1.196 + 1.197 + for (s = buf; *s && *s != '\n' && *s != '\r'; s++) 1.198 + ; 1.199 + *s = 0; 1.200 + 1.201 + if (!PORT_Strncmp (buf, "MD5-Digest: ", 12)) { 1.202 + md5_digest = 1.203 + ATOB_AsciiToData (buf + 12, &md5_length); 1.204 + } 1.205 + if (!PORT_Strncmp (buf, "SHA1-Digest: ", 13)) { 1.206 + sha1_digest = 1.207 + ATOB_AsciiToData (buf + 13, &sha1_length); 1.208 + } 1.209 + if (!PORT_Strncmp (buf, "SHA-Digest: ", 12)) { 1.210 + sha1_digest = 1.211 + ATOB_AsciiToData (buf + 12, &sha1_length); 1.212 + } 1.213 + } 1.214 + 1.215 + globaldig = jar->globalmeta; 1.216 + 1.217 + if (globaldig && md5_digest && verbosity >= 0) { 1.218 + PR_fprintf(outputFD, 1.219 + " md5 digest on global metainfo: %s\n", 1.220 + PORT_Memcmp(md5_digest, globaldig->md5, MD5_LENGTH) 1.221 + ? "no match" : "match"); 1.222 + } 1.223 + 1.224 + if (globaldig && sha1_digest && verbosity >= 0) { 1.225 + PR_fprintf(outputFD, 1.226 + " sha digest on global metainfo: %s\n", 1.227 + PORT_Memcmp(sha1_digest, globaldig->sha1, SHA1_LENGTH) 1.228 + ? "no match" : "match"); 1.229 + } 1.230 + 1.231 + if (globaldig == NULL && verbosity >= 0) { 1.232 + PR_fprintf(outputFD, 1.233 + "global metadigest is not available, strange.\n"); 1.234 + } 1.235 + 1.236 + fclose (fp); 1.237 + } 1.238 + } 1.239 + } 1.240 + } 1.241 + 1.242 + JAR_find_end (ctx); 1.243 + 1.244 + return retval; 1.245 +} 1.246 + 1.247 + 1.248 +/************************************************************************ 1.249 + * 1.250 + * J a r W h o 1.251 + */ 1.252 +int 1.253 +JarWho(char *filename) 1.254 +{ 1.255 + FILE * fp; 1.256 + 1.257 + JAR * jar; 1.258 + JAR_Context * ctx; 1.259 + 1.260 + int status; 1.261 + int retval = 0; 1.262 + 1.263 + JAR_Item * it; 1.264 + JAR_Cert * fing; 1.265 + 1.266 + CERTCertificate * cert, *prev = NULL; 1.267 + 1.268 + jar = JAR_new(); 1.269 + 1.270 + if ((fp = fopen (filename, "r")) == NULL) { 1.271 + perror (filename); 1.272 + exit (ERRX); 1.273 + } 1.274 + fclose (fp); 1.275 + 1.276 + status = JAR_pass_archive (jar, jarArchGuess, filename, "some-url"); 1.277 + 1.278 + if (status < 0 || jar->valid < 0) { 1.279 + PR_fprintf(outputFD, 1.280 + "NOTE -- \"%s\" archive DID NOT PASS crypto verification.\n", 1.281 + filename); 1.282 + retval = -1; 1.283 + if (jar->valid < 0 || status != -1) { 1.284 + const char *errtext; 1.285 + 1.286 + if (status >= JAR_BASE && status <= JAR_BASE_END) { 1.287 + errtext = JAR_get_error (status); 1.288 + } else { 1.289 + errtext = SECU_Strerror(PORT_GetError()); 1.290 + } 1.291 + 1.292 + PR_fprintf(outputFD, " (reported reason: %s)\n\n", errtext); 1.293 + } 1.294 + } 1.295 + 1.296 + PR_fprintf(outputFD, "\nSigner information:\n\n"); 1.297 + 1.298 + ctx = JAR_find (jar, NULL, jarTypeSign); 1.299 + 1.300 + while (JAR_find_next (ctx, &it) >= 0) { 1.301 + fing = (JAR_Cert * ) it->data; 1.302 + cert = fing->cert; 1.303 + 1.304 + if (cert) { 1.305 + if (prev == cert) 1.306 + break; 1.307 + 1.308 + if (cert->nickname) 1.309 + PR_fprintf(outputFD, "nickname: %s\n", cert->nickname); 1.310 + if (cert->subjectName) 1.311 + PR_fprintf(outputFD, "subject name: %s\n", 1.312 + cert->subjectName); 1.313 + if (cert->issuerName) 1.314 + PR_fprintf(outputFD, "issuer name: %s\n", cert->issuerName); 1.315 + } else { 1.316 + PR_fprintf(outputFD, "no certificate could be found\n"); 1.317 + retval = -1; 1.318 + } 1.319 + 1.320 + prev = cert; 1.321 + } 1.322 + 1.323 + JAR_find_end (ctx); 1.324 + 1.325 + JAR_destroy (jar); 1.326 + return retval; 1.327 +} 1.328 + 1.329 + 1.330 +/************************************************************************ 1.331 + * j a r _ c b 1.332 + */ 1.333 +static int jar_cb(int status, JAR *jar, const char *metafile, 1.334 +char *pathname, char *errortext) 1.335 +{ 1.336 + PR_fprintf(errorFD, "error %d: %s IN FILE %s\n", status, errortext, 1.337 + pathname); 1.338 + errorCount++; 1.339 + return 0; 1.340 +} 1.341 + 1.342 +