1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.util.jar; 19 20import java.io.IOException; 21import java.security.CodeSigner; 22import java.security.cert.CertPath; 23import java.security.cert.Certificate; 24import java.security.cert.CertificateException; 25import java.security.cert.CertificateFactory; 26import java.security.cert.X509Certificate; 27import java.util.ArrayList; 28import java.util.List; 29import java.util.zip.ZipEntry; 30import javax.security.auth.x500.X500Principal; 31 32/** 33 * Represents a single file in a JAR archive together with the manifest 34 * attributes and digital signatures associated with it. 35 * 36 * @see JarFile 37 * @see JarInputStream 38 */ 39public class JarEntry extends ZipEntry { 40 private Attributes attributes; 41 42 JarFile parentJar; 43 44 CodeSigner signers[]; 45 46 // Cached factory used to build CertPath-s in <code>getCodeSigners()</code>. 47 private CertificateFactory factory; 48 49 private boolean isFactoryChecked = false; 50 51 /** 52 * Creates a new {@code JarEntry} named name. 53 * 54 * @param name 55 * The name of the new {@code JarEntry}. 56 */ 57 public JarEntry(String name) { 58 super(name); 59 } 60 61 /** 62 * Creates a new {@code JarEntry} using the values obtained from entry. 63 * 64 * @param entry 65 * The ZipEntry to obtain values from. 66 */ 67 public JarEntry(ZipEntry entry) { 68 super(entry); 69 } 70 71 /** 72 * Returns the {@code Attributes} object associated with this entry or 73 * {@code null} if none exists. 74 * 75 * @return the {@code Attributes} for this entry. 76 * @exception IOException 77 * If an error occurs obtaining the {@code Attributes}. 78 * @see Attributes 79 */ 80 public Attributes getAttributes() throws IOException { 81 if (attributes != null || parentJar == null) { 82 return attributes; 83 } 84 Manifest manifest = parentJar.getManifest(); 85 if (manifest == null) { 86 return null; 87 } 88 return attributes = manifest.getAttributes(getName()); 89 } 90 91 /** 92 * Returns an array of {@code Certificate} Objects associated with this 93 * entry or {@code null} if none exists. Make sure that the everything is 94 * read from the input stream before calling this method, or else the method 95 * returns {@code null}. 96 * 97 * @return the certificate for this entry. 98 * @see java.security.cert.Certificate 99 */ 100 public Certificate[] getCertificates() { 101 if (parentJar == null) { 102 return null; 103 } 104 JarVerifier jarVerifier = parentJar.verifier; 105 if (jarVerifier == null) { 106 return null; 107 } 108 return jarVerifier.getCertificates(getName()); 109 } 110 111 void setAttributes(Attributes attrib) { 112 attributes = attrib; 113 } 114 115 /** 116 * Create a new {@code JarEntry} using the values obtained from the 117 * argument. 118 * 119 * @param je 120 * The {@code JarEntry} to obtain values from. 121 */ 122 public JarEntry(JarEntry je) { 123 super(je); 124 parentJar = je.parentJar; 125 attributes = je.attributes; 126 signers = je.signers; 127 } 128 129 /** 130 * Returns the code signers for the digital signatures associated with the 131 * JAR file. If there is no such code signer, it returns {@code null}. Make 132 * sure that the everything is read from the input stream before calling 133 * this method, or else the method returns {@code null}. 134 * 135 * @return the code signers for the JAR entry. 136 * @see CodeSigner 137 */ 138 public CodeSigner[] getCodeSigners() { 139 if (signers == null) { 140 signers = getCodeSigners(getCertificates()); 141 } 142 if (signers == null) { 143 return null; 144 } 145 146 CodeSigner[] tmp = new CodeSigner[signers.length]; 147 System.arraycopy(signers, 0, tmp, 0, tmp.length); 148 return tmp; 149 } 150 151 private CodeSigner[] getCodeSigners(Certificate[] certs) { 152 if (certs == null) { 153 return null; 154 } 155 156 X500Principal prevIssuer = null; 157 ArrayList<Certificate> list = new ArrayList<Certificate>(certs.length); 158 ArrayList<CodeSigner> asigners = new ArrayList<CodeSigner>(); 159 160 for (Certificate element : certs) { 161 if (!(element instanceof X509Certificate)) { 162 // Only X509Certificate-s are taken into account - see API spec. 163 continue; 164 } 165 X509Certificate x509 = (X509Certificate) element; 166 if (prevIssuer != null) { 167 X500Principal subj = x509.getSubjectX500Principal(); 168 if (!prevIssuer.equals(subj)) { 169 // Ok, this ends the previous chain, 170 // so transform this one into CertPath ... 171 addCodeSigner(asigners, list); 172 // ... and start a new one 173 list.clear(); 174 }// else { it's still the same chain } 175 176 } 177 prevIssuer = x509.getIssuerX500Principal(); 178 list.add(x509); 179 } 180 if (!list.isEmpty()) { 181 addCodeSigner(asigners, list); 182 } 183 if (asigners.isEmpty()) { 184 // 'signers' is 'null' already 185 return null; 186 } 187 188 CodeSigner[] tmp = new CodeSigner[asigners.size()]; 189 asigners.toArray(tmp); 190 return tmp; 191 192 } 193 194 private void addCodeSigner(ArrayList<CodeSigner> asigners, 195 List<Certificate> list) { 196 CertPath certPath = null; 197 if (!isFactoryChecked) { 198 try { 199 factory = CertificateFactory.getInstance("X.509"); 200 } catch (CertificateException ex) { 201 // do nothing 202 } finally { 203 isFactoryChecked = true; 204 } 205 } 206 if (factory == null) { 207 return; 208 } 209 try { 210 certPath = factory.generateCertPath(list); 211 } catch (CertificateException ex) { 212 // do nothing 213 } 214 if (certPath != null) { 215 asigners.add(new CodeSigner(certPath, null)); 216 } 217 } 218} 219