96 // need to use local providers here, see Providers class |
92 // need to use local providers here, see Providers class |
97 Object obj = null; |
93 Object obj = null; |
98 try { |
94 try { |
99 obj = Providers.startJarVerification(); |
95 obj = Providers.startJarVerification(); |
100 block = new PKCS7(rawBytes); |
96 block = new PKCS7(rawBytes); |
101 byte[] contentData = block.getContentInfo().getData(); |
97 sfBytes = block.getContentInfo().getData(); |
102 if (contentData != null) { |
|
103 sfStream = new ByteArrayInputStream(contentData); |
|
104 } |
|
105 certificateFactory = CertificateFactory.getInstance("X509"); |
98 certificateFactory = CertificateFactory.getInstance("X509"); |
106 } finally { |
99 } finally { |
107 Providers.stopJarVerification(obj); |
100 Providers.stopJarVerification(obj); |
108 } |
101 } |
109 this.name = name.substring(0, name.lastIndexOf(".")) |
102 this.name = name.substring(0, name.lastIndexOf(".")) |
110 .toUpperCase(Locale.ENGLISH); |
103 .toUpperCase(Locale.ENGLISH); |
111 |
|
112 this.man = man; |
|
113 this.md = md; |
104 this.md = md; |
114 this.signerCache = signerCache; |
105 this.signerCache = signerCache; |
115 } |
106 } |
116 |
107 |
117 /** |
108 /** |
118 * returns true if we need the .SF file |
109 * returns true if we need the .SF file |
119 */ |
110 */ |
120 public boolean needSignatureFile() |
111 public boolean needSignatureFileBytes() |
121 { |
112 { |
122 return sfStream == null; |
113 |
123 } |
114 return sfBytes == null; |
124 |
115 } |
125 public void setSignatureFile(InputStream ins) { |
116 |
126 this.sfStream = ins; |
117 |
|
118 /** |
|
119 * returns true if we need this .SF file. |
|
120 * |
|
121 * @param name the name of the .SF file without the extension |
|
122 * |
|
123 */ |
|
124 public boolean needSignatureFile(String name) |
|
125 { |
|
126 return this.name.equalsIgnoreCase(name); |
|
127 } |
|
128 |
|
129 /** |
|
130 * used to set the raw bytes of the .SF file when it |
|
131 * is external to the signature block file. |
|
132 */ |
|
133 public void setSignatureFile(byte sfBytes[]) |
|
134 { |
|
135 this.sfBytes = sfBytes; |
127 } |
136 } |
128 |
137 |
129 /** |
138 /** |
130 * Utility method used by JarVerifier and JarSigner |
139 * Utility method used by JarVerifier and JarSigner |
131 * to determine the signature file names and PKCS7 block |
140 * to determine the signature file names and PKCS7 block |
192 Providers.stopJarVerification(obj); |
195 Providers.stopJarVerification(obj); |
193 } |
196 } |
194 |
197 |
195 } |
198 } |
196 |
199 |
197 private void processImpl(Map<String, CodeSigner[]> signers, |
200 private void processImpl(Hashtable<String, CodeSigner[]> signers, |
198 List manifestDigests) |
201 List manifestDigests) |
199 throws IOException, SignatureException, NoSuchAlgorithmException, |
202 throws IOException, SignatureException, NoSuchAlgorithmException, |
200 JarException, CertificateException |
203 JarException, CertificateException |
201 { |
204 { |
202 SignatureFileManifest sf = new SignatureFileManifest(); |
205 Manifest sf = new Manifest(); |
203 InputStream ins = sfStream; |
206 sf.read(new ByteArrayInputStream(sfBytes)); |
204 |
207 |
205 byte[] buffer = new byte[4096]; |
208 String version = |
206 int sLen = block.getSignerInfos().length; |
209 sf.getMainAttributes().getValue(Attributes.Name.SIGNATURE_VERSION); |
207 boolean mainOK = false; // main attributes of SF is available... |
210 |
208 boolean manifestSigned = false; // and it matches MANIFEST.MF |
211 if ((version == null) || !(version.equalsIgnoreCase("1.0"))) { |
209 BASE64Decoder decoder = new BASE64Decoder(); |
212 // XXX: should this be an exception? |
210 |
213 // for now we just ignore this signature file |
211 PKCS7.PKCS7Verifier[] pvs = new PKCS7.PKCS7Verifier[sLen]; |
214 return; |
212 for (int i=0; i<sLen; i++) { |
215 } |
213 pvs[i] = PKCS7.PKCS7Verifier.from(block, block.getSignerInfos()[i]); |
216 |
214 } |
217 SignerInfo[] infos = block.verify(sfBytes); |
215 |
218 |
216 /* |
219 if (infos == null) { |
217 * Verify SF in streaming mode. The chunks of the file are fed into |
|
218 * the Manifest object sf and all PKCS7Verifiers. As soon as the main |
|
219 * attributes is available, we'll check if manifestSigned is true. If |
|
220 * yes, there is no need to fill in sf's entries field, since it should |
|
221 * be identical to entries in man. |
|
222 */ |
|
223 while (true) { |
|
224 int len = ins.read(buffer); |
|
225 if (len < 0) { |
|
226 if (!manifestSigned) { |
|
227 sf.update(null, 0, 0); |
|
228 } |
|
229 break; |
|
230 } else { |
|
231 for (int i=0; i<sLen; i++) { |
|
232 if (pvs[i] != null) pvs[i].update(buffer, 0, len); |
|
233 } |
|
234 // Continue reading if verifyManifestHash fails (or, the |
|
235 // main attributes is not available yet) |
|
236 if (!manifestSigned) { |
|
237 sf.update(buffer, 0, len); |
|
238 if (!mainOK) { |
|
239 try { |
|
240 Attributes attr = sf.getMainAttributes(); |
|
241 String version = attr.getValue( |
|
242 Attributes.Name.SIGNATURE_VERSION); |
|
243 |
|
244 if ((version == null) || |
|
245 !(version.equalsIgnoreCase("1.0"))) { |
|
246 // XXX: should this be an exception? |
|
247 // for now we just ignore this signature file |
|
248 return; |
|
249 } |
|
250 |
|
251 mainOK = true; |
|
252 manifestSigned = verifyManifestHash( |
|
253 sf, md, decoder, manifestDigests); |
|
254 } catch (IllegalStateException ise) { |
|
255 // main attributes not available yet |
|
256 } |
|
257 } |
|
258 } |
|
259 } |
|
260 } |
|
261 List<SignerInfo> intResult = new ArrayList<>(sLen); |
|
262 for (int i = 0; i < sLen; i++) { |
|
263 if (pvs[i] != null) { |
|
264 SignerInfo signerInfo = pvs[i].verify(); |
|
265 if (signerInfo != null) { |
|
266 intResult.add(signerInfo); |
|
267 } |
|
268 } |
|
269 } |
|
270 if (intResult.isEmpty()) { |
|
271 throw new SecurityException("cannot verify signature block file " + |
220 throw new SecurityException("cannot verify signature block file " + |
272 name); |
221 name); |
273 } |
222 } |
274 |
223 |
275 SignerInfo[] infos = |
224 BASE64Decoder decoder = new BASE64Decoder(); |
276 intResult.toArray(new SignerInfo[intResult.size()]); |
|
277 |
225 |
278 CodeSigner[] newSigners = getSigners(infos, block); |
226 CodeSigner[] newSigners = getSigners(infos, block); |
279 |
227 |
280 // make sure we have something to do all this work for... |
228 // make sure we have something to do all this work for... |
281 if (newSigners == null) |
229 if (newSigners == null) |
282 return; |
230 return; |
|
231 |
|
232 Iterator<Map.Entry<String,Attributes>> entries = |
|
233 sf.getEntries().entrySet().iterator(); |
|
234 |
|
235 // see if we can verify the whole manifest first |
|
236 boolean manifestSigned = verifyManifestHash(sf, md, decoder, manifestDigests); |
283 |
237 |
284 // verify manifest main attributes |
238 // verify manifest main attributes |
285 if (!manifestSigned && !verifyManifestMainAttrs(sf, md, decoder)) { |
239 if (!manifestSigned && !verifyManifestMainAttrs(sf, md, decoder)) { |
286 throw new SecurityException |
240 throw new SecurityException |
287 ("Invalid signature file digest for Manifest main attributes"); |
241 ("Invalid signature file digest for Manifest main attributes"); |
288 } |
242 } |
289 |
243 |
290 Iterator<Map.Entry<String,Attributes>> entries; |
244 // go through each section in the signature file |
291 |
|
292 if (manifestSigned) { |
|
293 if (debug != null) { |
|
294 debug.println("full manifest signature match, " |
|
295 + "update signer info from MANIFEST.MF"); |
|
296 } |
|
297 entries = man.getEntries().entrySet().iterator(); |
|
298 } else { |
|
299 if (debug != null) { |
|
300 debug.println("full manifest signature unmatch, " |
|
301 + "update signer info from SF file"); |
|
302 } |
|
303 entries = sf.getEntries().entrySet().iterator(); |
|
304 } |
|
305 |
|
306 // go through each section |
|
307 |
|
308 while(entries.hasNext()) { |
245 while(entries.hasNext()) { |
309 |
246 |
310 Map.Entry<String,Attributes> e = entries.next(); |
247 Map.Entry<String,Attributes> e = entries.next(); |
311 String name = e.getKey(); |
248 String name = e.getKey(); |
312 |
249 |
313 if (manifestSigned || |
250 if (manifestSigned || |
314 (verifySection(e.getValue(), name, md, decoder))) { |
251 (verifySection(e.getValue(), name, md, decoder))) { |
315 |
252 |
316 if (name.startsWith("./")) |
253 if (name.startsWith("./")) |
317 name = name.substring(2); |
254 name = name.substring(2); |
318 |
255 |
319 if (name.startsWith("/")) |
256 if (name.startsWith("/")) |