1 7 8 package java.util.jar; 9 10 import java.io.*; 11 import java.util.*; 12 import java.util.zip.*; 13 import java.security.*; 14 import java.security.cert.CertificateException ; 15 16 import sun.security.util.ManifestDigester; 17 import sun.security.util.ManifestEntryVerifier; 18 import sun.security.util.SignatureFileVerifier; 19 import sun.security.util.Debug; 20 21 26 class JarVerifier { 27 28 29 static final Debug debug = Debug.getInstance("jar"); 30 31 33 private Hashtable verifiedSigners; 34 35 37 private Hashtable sigFileSigners; 38 39 40 private Hashtable sigFileData; 41 42 44 private ArrayList pendingBlocks; 45 46 47 private ArrayList signerCache; 48 49 50 private boolean parsingBlockOrSF = false; 51 52 53 private boolean parsingMeta = true; 54 55 56 private boolean anyToVerify = true; 57 58 60 private ByteArrayOutputStream baos; 61 62 63 private ManifestDigester manDig; 64 65 66 byte manifestRawBytes[] = null; 67 68 public JarVerifier(byte rawBytes[]) { 69 manifestRawBytes = rawBytes; 70 sigFileSigners = new Hashtable(); 71 verifiedSigners = new Hashtable(); 72 sigFileData = new Hashtable(11); 73 pendingBlocks = new ArrayList(); 74 baos = new ByteArrayOutputStream(); 75 } 76 77 82 public void beginEntry(JarEntry je, ManifestEntryVerifier mev) 83 throws IOException 84 { 85 if (je == null) 86 return; 87 88 if (debug != null) { 89 debug.println("beginEntry "+je.getName()); 90 } 91 92 String name = je.getName(); 93 94 103 104 if (parsingMeta) { 105 String uname = name.toUpperCase(Locale.ENGLISH); 106 if ((uname.startsWith("META-INF/") || 107 uname.startsWith("/META-INF/"))) { 108 109 if (je.isDirectory()) { 110 mev.setEntry(null, je); 111 return; 112 } 113 114 if (SignatureFileVerifier.isBlockOrSF(uname)) { 115 116 parsingBlockOrSF = true; 117 baos.reset(); 118 mev.setEntry(null, je); 119 } 120 return; 121 } 122 } 123 124 if (parsingMeta) { 125 doneWithMeta(); 126 } 127 128 if (je.isDirectory()) { 129 mev.setEntry(null, je); 130 return; 131 } 132 133 if (name.startsWith("./")) 136 name = name.substring(2); 137 138 if (name.startsWith("/")) 141 name = name.substring(1); 142 143 if (sigFileSigners.get(name) != null) { 145 mev.setEntry(name, je); 146 return; 147 } 148 149 mev.setEntry(null, je); 151 152 return; 153 } 154 155 158 159 public void update(int b, ManifestEntryVerifier mev) 160 throws IOException 161 { 162 if (b != -1) { 163 if (parsingBlockOrSF) { 164 baos.write(b); 165 } else { 166 mev.update((byte)b); 167 } 168 } else { 169 processEntry(mev); 170 } 171 } 172 173 176 177 public void update(int n, byte[] b, int off, int len, 178 ManifestEntryVerifier mev) 179 throws IOException 180 { 181 if (n != -1) { 182 if (parsingBlockOrSF) { 183 baos.write(b, off, n); 184 } else { 185 mev.update(b, off, n); 186 } 187 } else { 188 processEntry(mev); 189 } 190 } 191 192 195 private void processEntry(ManifestEntryVerifier mev) 196 throws IOException 197 { 198 if (!parsingBlockOrSF) { 199 JarEntry je = mev.getEntry(); 200 if ((je != null) && (je.signers == null)) { 201 je.signers = mev.verify(verifiedSigners, sigFileSigners); 202 } 203 } else { 204 205 try { 206 parsingBlockOrSF = false; 207 208 if (debug != null) { 209 debug.println("processEntry: processing block"); 210 } 211 212 String uname = mev.getEntry().getName() 213 .toUpperCase(Locale.ENGLISH); 214 215 if (uname.endsWith(".SF")) { 216 String key = uname.substring(0, uname.length()-3); 217 byte bytes[] = baos.toByteArray(); 218 sigFileData.put(key, bytes); 220 Iterator it = pendingBlocks.iterator(); 223 while (it.hasNext()) { 224 SignatureFileVerifier sfv = 225 (SignatureFileVerifier) it.next(); 226 if (sfv.needSignatureFile(key)) { 227 if (debug != null) { 228 debug.println( 229 "processEntry: processing pending block"); 230 } 231 232 sfv.setSignatureFile(bytes); 233 sfv.process(sigFileSigners); 234 } 235 } 236 return; 237 } 238 239 241 String key = uname.substring(0, uname.lastIndexOf(".")); 242 243 if (signerCache == null) 244 signerCache = new ArrayList(); 245 246 if (manDig == null) { 247 synchronized(manifestRawBytes) { 248 if (manDig == null) { 249 manDig = new ManifestDigester(manifestRawBytes); 250 manifestRawBytes = null; 251 } 252 } 253 } 254 255 SignatureFileVerifier sfv = 256 new SignatureFileVerifier(signerCache, 257 manDig, uname, baos.toByteArray()); 258 259 if (sfv.needSignatureFileBytes()) { 260 byte[] bytes = (byte[]) sigFileData.get(key); 262 263 if (bytes == null) { 264 if (debug != null) { 268 debug.println("adding pending block"); 269 } 270 pendingBlocks.add(sfv); 271 return; 272 } else { 273 sfv.setSignatureFile(bytes); 274 } 275 } 276 sfv.process(sigFileSigners); 277 278 } catch (sun.security.pkcs.ParsingException pe) { 279 if (debug != null) debug.println("processEntry caught: "+pe); 280 } catch (IOException ioe) { 282 if (debug != null) debug.println("processEntry caught: "+ioe); 283 } catch (SignatureException se) { 285 if (debug != null) debug.println("processEntry caught: "+se); 286 } catch (NoSuchAlgorithmException nsae) { 288 if (debug != null) debug.println("processEntry caught: "+nsae); 289 } catch (CertificateException ce) { 291 if (debug != null) debug.println("processEntry caught: "+ce); 292 } 294 } 295 } 296 297 301 public java.security.cert.Certificate [] getCerts(String name) 302 { 303 CodeSigner[] signers = getCodeSigners(name); 304 if (signers != null) { 306 ArrayList certChains = new ArrayList(); 307 for (int i = 0; i < signers.length; i++) { 308 certChains.addAll( 309 signers[i].getSignerCertPath().getCertificates()); 310 } 311 312 return (java.security.cert.Certificate []) 314 certChains.toArray( 315 new java.security.cert.Certificate [certChains.size()]); 316 } 317 return null; 318 } 319 320 325 public CodeSigner[] getCodeSigners(String name) 326 { 327 return (CodeSigner[])verifiedSigners.get(name); 328 } 329 330 331 336 boolean nothingToVerify() 337 { 338 return (anyToVerify == false); 339 } 340 341 347 void doneWithMeta() 348 { 349 parsingMeta = false; 350 anyToVerify = !sigFileSigners.isEmpty(); 351 baos = null; 352 sigFileData = null; 353 pendingBlocks = null; 354 signerCache = null; 355 manDig = null; 356 } 357 358 static class VerifierStream extends java.io.InputStream { 359 360 private InputStream is; 361 private JarVerifier jv; 362 private ManifestEntryVerifier mev; 363 private long numLeft; 364 365 VerifierStream(Manifest man, 366 JarEntry je, 367 InputStream is, 368 JarVerifier jv) throws IOException 369 { 370 this.is = is; 371 this.jv = jv; 372 this.mev = new ManifestEntryVerifier(man); 373 this.jv.beginEntry(je, mev); 374 this.numLeft = je.getSize(); 375 if (this.numLeft == 0) 376 this.jv.update(-1, this.mev); 377 } 378 379 public int read() throws IOException 380 { 381 if (numLeft > 0) { 382 int b = is.read(); 383 jv.update(b, mev); 384 numLeft--; 385 if (numLeft == 0) 386 jv.update(-1, mev); 387 return b; 388 } else { 389 return -1; 390 } 391 } 392 393 public int read(byte b[], int off, int len) throws IOException { 394 if ((numLeft > 0) && (numLeft < len)) { 395 len = (int)numLeft; 396 } 397 398 if (numLeft > 0) { 399 int n = is.read(b, off, len); 400 jv.update(n, b, off, len, mev); 401 numLeft -= n; 402 if (numLeft == 0) 403 jv.update(-1, b, off, len, mev); 404 return n; 405 } else { 406 return -1; 407 } 408 } 409 410 public void close() 411 throws IOException 412 { 413 if (is != null) 414 is.close(); 415 is = null; 416 mev = null; 417 jv = null; 418 } 419 420 public int available() throws IOException { 421 return is.available(); 422 } 423 424 } 425 } 426 | Popular Tags |