1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.xnap.plugin;
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.security.KeyFactory;
26 import java.security.NoSuchAlgorithmException;
27 import java.security.Principal;
28 import java.security.PublicKey;
29 import java.security.cert.Certificate;
30 import java.security.cert.X509Certificate;
31 import java.security.interfaces.DSAPublicKey;
32 import java.security.spec.InvalidKeySpecException;
33 import java.security.spec.KeySpec;
34 import java.security.spec.X509EncodedKeySpec;
35 import java.util.ArrayList;
36 import java.util.Enumeration;
37 import java.util.List;
38 import java.util.jar.JarEntry;
39 import java.util.jar.JarFile;
40
41 import org.apache.log4j.Logger;
42 import org.apache.xerces.utils.Base64;
43 import org.xnap.XNap;
44 import org.xnap.loader.XNapClassLoader;
45
46 /***
47 * This class verifies the signature of the given Jar and provides
48 * informations about its signers
49 *
50 * @version $Id: PluginVerifier.java,v 1.7 2003/11/04 13:51:06 vanto Exp $
51 */
52 public class PluginVerifier {
53
54 private static Logger logger = Logger.getLogger(PluginVerifier.class);
55
56 private PluginInfo info;
57 private List certs = new ArrayList();
58 private boolean valid;
59 private boolean signed;
60 private List unsignedJars = new ArrayList();
61 private List signedJars = new ArrayList();
62
63 /***
64 * Initialized a new PluginVerifier
65 * It verfies all jars used by the plugin and provides information
66 * about its signers.
67 */
68 public PluginVerifier(PluginInfo info) throws IOException {
69 this.info = info;
70 this.valid = true;
71 this.signed = true;
72 try {
73 String[] classpath = info.getClassPath();
74 for (int i = 0; i < classpath.length; i++) {
75 if (XNapClassLoader.isLoaded(new File(classpath[i]).toURL())) break;
76 boolean s = validateJar(classpath[i]);
77 if (!s) {
78 unsignedJars.add(classpath[i]);
79 } else {
80 signedJars.add(classpath[i]);
81 }
82 signed = signed && s;
83 }
84 } catch (SecurityException e) {
85 this.valid = false;
86 }
87 }
88
89 /***
90 * Returns true if all jars are consistent and if signed, the signature
91 * must be valid. */
92 public boolean isValid() {
93 return valid;
94 }
95
96 /***
97 * Return true, (only) if all jars of the plugin are signed. */
98 public boolean isSigned() {
99 return valid && signed;
100 }
101
102 /***
103 * Returns true, if all jars are signed and trusted by XNap */
104 public boolean isTrustedByXNap() {
105 return isTrustedBy(XNap.TRUSTED_KEYS);
106 }
107
108 /***
109 * Returns true, if all jars are signed and trusted by the given keyset
110 * @param encodedPKs StringArray of Base64-encoded X509-PublicKeys */
111 public boolean isTrustedBy(String[] encodedPKs) {
112 boolean trusted = false;
113 if (isSigned()) {
114 trusted = true;
115 try {
116 KeyFactory kf = KeyFactory.getInstance("DSA");
117 for (int i = 0; i < getCertificates().length; i++) {
118 if (getCertificates()[i] instanceof X509Certificate) {
119 X509Certificate cert = (X509Certificate)getCertificates()[i];
120 DSAPublicKey pk = (DSAPublicKey)cert.getPublicKey();
121 for (int j = 0; j < encodedPKs.length; j++) {
122 KeySpec ks = new X509EncodedKeySpec(Base64.decode(encodedPKs[j].getBytes()));
123 PublicKey trustedKey = kf.generatePublic(ks);
124 trusted = trusted && trustedKey.equals(pk);
125 }
126 }
127 }
128 } catch (NoSuchAlgorithmException e) {
129 logger.debug(e);
130 } catch (InvalidKeySpecException e) {
131 logger.debug(e);
132 }
133 }
134 return trusted;
135 }
136
137 /***
138 * Returns a list of unsigned jars */
139 public String[] getUnsignedJars() {
140 return (String[])unsignedJars.toArray(new String[0]);
141 }
142
143 /***
144 * Returns a list of signed jars */
145 public String[] getSignedJars() {
146 return (String[])signedJars.toArray(new String[0]);
147 }
148
149 /***
150 * Returns the list of certificates (mostly X509) */
151 public Certificate[] getCertificates() {
152 return (Certificate[])certs.toArray(new Certificate[0]);
153 }
154
155 /***
156 * Validates the given jar and updates this' fields */
157 private boolean validateJar(String filename) throws IOException
158 {
159 logger.debug(new File(filename.trim()).getAbsolutePath().toString());
160 JarFile jar = new JarFile(new File(filename.trim()).getAbsolutePath(), true);
161 Enumeration entries = jar.entries();
162 boolean signed = false;
163 while (entries.hasMoreElements()) {
164 JarEntry entry = (JarEntry) entries.nextElement();
165 InputStream in = jar.getInputStream(entry);
166
167 while (in.read() != -1) {}
168
169 if (entry.getCertificates() != null) {
170 for (int i = 0; i < entry.getCertificates().length; i++) {
171 signed = true;
172 if (!certs.contains(entry.getCertificates()[i])) {
173 certs.add(entry.getCertificates()[i]);
174 }
175 }
176 }
177 }
178 return signed;
179 }
180
181 /***
182 * Formats the Principal to make it more human readable */
183 public static String readablePrincipal(Principal prin)
184 {
185
186
187
188
189
190
191 return prin.getName();
192 }
193
194 /***
195 * Returns a String with all signers. */
196 public String getSigners()
197 {
198 StringBuffer sig = new StringBuffer();
199 for (int i = 0; i < getCertificates().length; i++) {
200 if (getCertificates()[i] instanceof X509Certificate) {
201 X509Certificate cert = (X509Certificate)getCertificates()[i];
202 sig.append(cert.getIssuerDN());
203 if (i < getCertificates().length) {
204 sig.append(", ");
205 }
206 }
207 }
208 return sig.toString();
209 }
210
211 }