Clover Coverage Report
Coverage timestamp: Sun Mar 23 2008 08:24:39 GMT
77   333   31   7.7
48   115   0.52   10
10     4  
1    
 
 
  DefaultVerifier       Line # 104 77 31 61.5% 0.6148148
 
  (1)
 
1    /*
2    * Copyright (c) 2000-2005, University of Salford
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions are met:
7    *
8    * Redistributions of source code must retain the above copyright notice, this
9    * list of conditions and the following disclaimer.
10    *
11    * Redistributions in binary form must reproduce the above copyright notice,
12    * this list of conditions and the following disclaimer in the documentation
13    * and/or other materials provided with the distribution.
14    *
15    * Neither the name of the University of Salford nor the names of its
16    * contributors may be used to endorse or promote products derived from this
17    * software without specific prior written permission.
18    *
19    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20    * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22    * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23    * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24    * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25    * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26    * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27    * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28    * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29    * POSSIBILITY OF SUCH DAMAGE.
30    */
31    /*
32    * Copyright (c) 2006, University of Kent
33    * All rights reserved.
34    *
35    * Redistribution and use in source and binary forms, with or without
36    * modification, are permitted provided that the following conditions are met:
37    *
38    * Redistributions of source code must retain the above copyright notice, this
39    * list of conditions and the following disclaimer.
40    *
41    * Redistributions in binary form must reproduce the above copyright notice,
42    * this list of conditions and the following disclaimer in the documentation
43    * and/or other materials provided with the distribution.
44    *
45    * 1. Neither the name of the University of Kent nor the names of its
46    * contributors may be used to endorse or promote products derived from this
47    * software without specific prior written permission.
48    *
49    * 2. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
50    * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
51    * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
52    * PURPOSE ARE DISCLAIMED.
53    *
54    * 3. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
55    * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
56    * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
57    * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
58    * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
59    * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
60    * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
61    * POSSIBILITY OF SUCH DAMAGE.
62    *
63    * 4. YOU AGREE THAT THE EXCLUSIONS IN PARAGRAPHS 2 AND 3 ABOVE ARE REASONABLE
64    * IN THE CIRCUMSTANCES. IN PARTICULAR, YOU ACKNOWLEDGE (1) THAT THIS
65    * SOFTWARE HAS BEEN MADE AVAILABLE TO YOU FREE OF CHARGE, (2) THAT THIS
66    * SOFTWARE IS NOT "PRODUCT" QUALITY, BUT HAS BEEN PRODUCED BY A RESEARCH
67    * GROUP WHO DESIRE TO MAKE THIS SOFTWARE FREELY AVAILABLE TO PEOPLE WHO WISH
68    * TO USE IT, AND (3) THAT BECAUSE THIS SOFTWARE IS NOT OF "PRODUCT" QUALITY
69    * IT IS INEVITABLE THAT THERE WILL BE BUGS AND ERRORS, AND POSSIBLY MORE
70    * SERIOUS FAULTS, IN THIS SOFTWARE.
71    *
72    * 5. This license is governed, except to the extent that local laws
73    * necessarily apply, by the laws of England and Wales.
74    */
75   
76    package issrg.security;
77   
78    import issrg.pba.rbac.CustomisePERMIS;
79   
80    import java.security.cert.CertificateFactory;
81    import java.security.cert.CertificateException;
82    import java.security.cert.X509Certificate;
83    import java.security.Signature;
84   
85    import java.io.ByteArrayInputStream;
86   
87    import org.apache.log4j.*;
88    /**
89    * This is the default implementation of a Verifier. It can validate signatures
90    * on the given objects. This component doesn't require any user interaction
91    * and can be used in interface-less applications (e.g. servers).
92    *
93    * <p>This default security supports:
94    * <ul>
95    * <br><li>signature verification, given the PKC</li>
96    * <br><li>validation of the PKCs, given the root CA PKC, and given
97    * certification path is not
98    * deeper than 1 hop (i.e. root CA->end-user)</li> In this case the PKCs of
99    * end-users are retrieved from a given PKCRepository
100    * </ul>
101    * @author A.Otenko
102    */
103   
 
104    public class DefaultVerifier implements Verifier {
105    Logger logger = Logger.getLogger("issrg.security.DefaultVerifier");
106    CertificateFactory cf;
107   
108    X509Certificate [] roots=null;
109    PKCRepository rep=null;
110   
111    /**
112    * This constructor initialises the DefaultVerifier.
113    *
114    * @throws SecurityException, if there were no CertificateFactories found for
115    * "X.509" certificates in this instance of JVM
116    */
 
117  7 toggle public DefaultVerifier() throws SecurityException {
118  7 try{
119  7 cf = CertificateFactory.getInstance("X.509");
120    }catch (CertificateException ce){
121  0 if(logger.isDebugEnabled()) logger.debug("Could not instantiate a X.509 Certificate factory", ce);
122  0 throw new SecurityException("Could not instantiate a X.509 Certificate factory", ce);
123    }
124    }
125   
126    /**
127    * Sets the root CA by specifying its PKC.
128    *
129    * @param pkc is the BER encoded X.509 PKC of the root CA
130    */
 
131  3 toggle public void setRootCA(byte [] pkc) throws SecurityException {
132  3 setRootCAs(new byte[][]{pkc});
133    }
134   
135    /**
136    * Sets the root CA by specifying its PKC.
137    *
138    * @param pkc is the X.509 PKC of the root CA
139    */
 
140  1 toggle public void setRootCA(X509Certificate pkc) {
141  1 setRootCAs(new X509Certificate[]{pkc});
142    }
143   
144    /**
145    * This method sets multiple roots of trust by providing their X.509 PKCs.
146    *
147    * @param pkcs - the Public Key Certificates of the CAs
148    */
 
149  4 toggle public void setRootCAs(X509Certificate [] pkcs) {
150  4 roots=pkcs;
151    }
152   
153    /**
154    * This method returns the array of PKCs of multiple roots of trust.
155    *
156    * @return array of X509Certificate, which can be empty or null, if no roots
157    * of trust have been specified
158    */
 
159  4 toggle public X509Certificate[] getRootCAs(){
160  4 return roots;
161    }
162   
163    /**
164    * This method lets you specify multiple Root CAs. If any of them is
165    * a malformed PKC, there will be a SecurityException.
166    *
167    * @param pkcs - an array of BER-encoded X.509 PKCs
168    */
 
169  3 toggle public void setRootCAs(byte[][] pkcs) throws SecurityException {
170  3 try{
171  3 roots=new X509Certificate[pkcs.length];
172  6 for (int i=0; i<roots.length; i++){
173  3 roots[i]=(X509Certificate)cf.generateCertificate(new ByteArrayInputStream(pkcs[i]));
174  0 if(logger.isDebugEnabled()) logger.debug(roots[i].toString());
175    }
176    }catch (java.security.cert.CertificateException ce){
177  0 if(logger.isDebugEnabled()) logger.debug("Certificate decoding error", ce);
178  0 throw new SecurityException("Certificate decoding error", ce);
179    }
180    }
181   
182    /**
183    * Sets the repository that will be used to retrieve user's signature
184    * verification Public Key Certificates.
185    *
186    * @param repository - the PKCRepository that can return the PKCs for a
187    * given principal
188    */
 
189  4 toggle public void setPKCRepository(PKCRepository repository) {
190  4 rep=repository;
191    }
192   
193    /*
194    * VERIFIER METHODS
195    */
196   
197    /**
198    * Retrieves the valid certificates of the signer. For this purpose it
199    * contacts the PKCRepository and retrieves
200    * all user certificates from the specified entry. Then the signatures are
201    * verified on them. They should be signed
202    * by one of the Root CAs directly. Malformed user certificates are discarded.
203    *
204    * <p>Certification path validation will be added later.
205    *
206    * @param signerName is the name of the signer's LDAP entry
207    *
208    * @return all valid certificates located in that LDAP entry; never null, but
209    * can be an empty array
210    *
211    * @throws SecurityException if there were errors during processing the
212    * request
213    */
 
214  1009 toggle public java.security.cert.X509Certificate [] getVerificationCertificates(issrg.utils.repository.TokenLocator signerName) throws SecurityException {
215  1009 if (roots==null){
216  0 throw new SecurityException("Cannot validate the certificates; Root CAs are not specified");
217    }
218   
219  1009 try{
220  0 if(logger.isDebugEnabled()) logger.debug("getting verification certificates for: "+signerName.getEntry().getEntryName().getName());
221    //System.out.println("getting verification certificates for: "+signerName.getName()); //**********
222   
223  1009 javax.naming.directory.Attribute pkcs=null;
224  1009 if (rep!=null) pkcs=rep.getUserCertificate(signerName); // note, that this code will also retrieve other self-signed certificates of the rootCA. useful for getting userCertificates of the CA
225   
226  1009 if (pkcs==null){ // the repository can be unspecified. in this case only the rootCA can be a signer
227  0 pkcs=new javax.naming.directory.BasicAttribute(PKCRepository.USER_PKC_ATTRIBUTE);
228    }
229   
230    // now lets verify the signatures on those PKCs
231    //java.security.cert.X509Certificate [] root=new java.security.cert.X509Certificate[]{rootCA};
232  1009 java.util.Vector v=new java.util.Vector(); // vector of valid PKCs
233  0 if(logger.isDebugEnabled()) logger.debug("got "+pkcs);
234    //System.out.println("got "+pkcs); //**********
235   
236  2018 for (int i=pkcs.size(); i-->0;){
237  1009 boolean valid=false;
238  1009 try{
239  0 if(logger.isDebugEnabled()) logger.debug("PKC["+i+"] : "+pkcs.get(i));
240    //System.out.println("PKC["+i+"] : "+pkcs.get(i)); //**********
241  1009 byte[] pkc = null;
242  0 if (CustomisePERMIS.isMultiParserUsed()) pkc = (byte[])((issrg.pba.RawCredential)pkcs.get(i)).getCredential();
243  1009 else pkc = (byte[])pkcs.get(i);
244  1009 X509Certificate c=(X509Certificate)cf.generateCertificate(new ByteArrayInputStream(pkc));
245   
246    // usually I would need to verify that the DN is the same, too...
247    // lets omit it for brewity. can the DN be different, if the signature matches?
248    // c.getIssuerDN().equals(rootCA.getSubjectDN())
249  1009 valid=verifyByRoot(c.getTBSCertificate(), c.getSignature(), c.getSigAlgOID());
250  1009 if (valid){
251  0 if(logger.isDebugEnabled()) logger.debug("PKC["+i+"] is valid");
252    //System.out.println("PKC["+i+"] is valid"); //**********
253  1009 v.add(c);
254    }
255    }catch(Exception ce){ //ignore invalid PKCs
256  0 if(logger.isDebugEnabled()) logger.debug("Invalid PKC : " + ce.getMessage());
257    }
258    }
259   
260  2018 for (int i=0; i<roots.length; i++){
261  1009 if (signerName.getEntry().getEntryName().equals(roots[i].getSubjectDN())){
262  1 v.add(roots[i]);
263    }
264    }
265   
266  1009 java.security.cert.X509Certificate [] certs=(java.security.cert.X509Certificate[])v.toArray(new java.security.cert.X509Certificate[0]);
267   
268  1009 return certs;
269    }catch(Exception e){
270  0 if(logger.isDebugEnabled()) logger.debug("Error while getting certificates", e);
271  0 throw new SecurityException("Error while getting certificates", e);
272    }
273    }
274   
275    /**
276    * This method verifies a signature on the data. It assumes that all X.509
277    * certificates are still valid and non-revoked in the array.
278    * It is so if they have been retrieved using getVerificationCertificates
279    * method.
280    * In fact, for this reason it uses only the first certificate in the array,
281    * which should be the signature verification certificate
282    * of the signer.
283    *
284    * @param data is the to-be-signed array
285    * @param signature is the signature of that array
286    * @param certs is the array of X.509 PKCs, but only the first one is used in
287    * this implementation
288    *
289    * @return true, if the signature validates; false otherwise
290    *
291    * @throws SecurityException, if there were errors during processing the
292    * request
293    */
 
294  2023 toggle public boolean verify(byte [] data, byte[] signature, String algorithmID, X509Certificate[] certs) throws SecurityException {
295  2023 try{
296  0 if(logger.isDebugEnabled()) logger.debug(certs[0].getSubjectDN().getName()+" is the holder of the PKC");
297    //System.out.println(certs[0].getSubjectDN().getName()+" is the holder of the PKC"); //************
298  2023 Signature sig = Signature.getInstance(algorithmID);
299   
300  2023 sig.initVerify(certs[0].getPublicKey());
301  2023 sig.update(data);
302  2023 boolean v = sig.verify(signature);
303  2023 logger.debug("signature verification = "+v);
304  2023 return v;
305    }catch (Exception e){
306  0 if(logger.isDebugEnabled()) logger.debug("Error while verifying the signature", e);
307  0 throw new SecurityException("Error while verifying the signature", e);
308    }
309    }
310   
311    /**
312    * This method checks if the given data was signed by any of the Root CAs.
313    *
314    * @param data - the to-be-signed byte array
315    * @param signature - the matching signature
316    * @param algorithmID - the signature algorithm identifier
317    *
318    * @return true, if the signature can be verified using one of the PKCs of
319    * the roots of trust; false otherwise (e.g. no Root CAs have been
320    * configured, or there was a problem during signature verification)
321    */
 
322  1009 toggle public boolean verifyByRoot(byte [] data, byte[] signature, String algorithmID) {
323  1009 if (roots!=null) for (int i=0; i<roots.length; i++){
324  1009 try{
325  1009 if (verify(data, signature, algorithmID, new X509Certificate[]{roots[i]})) return true;
326    }catch (Exception e){
327  0 if(logger.isDebugEnabled()) logger.debug("Error while verifying the signature", e);
328    //throw new SecurityException("Error while verifying the signature", e);
329    }
330    }
331  0 return false; // returns false, if none fsof the certificates validates the signature
332    }
333    }