Clover Coverage Report
Coverage timestamp: Sun Mar 23 2008 08:24:39 GMT
152   367   47   19
56   243   0.36   8
8     6.75  
1    
 
 
  SAWSFileCallbackHandler       Line # 74 152 47 66.7% 0.6666667
 
No Tests
 
1    /*
2    * Copyright (c) 2006, University of Kent
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    * 1. Neither the name of the University of Kent 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    * 2. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20    * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21    * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22    * PURPOSE ARE DISCLAIMED.
23    *
24    * 3. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25    * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26    * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27    * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28    * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29    * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30    * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31    * POSSIBILITY OF SUCH DAMAGE.
32    *
33    * 4. YOU AGREE THAT THE EXCLUSIONS IN PARAGRAPHS 2 AND 3 ABOVE ARE REASONABLE
34    * IN THE CIRCUMSTANCES. IN PARTICULAR, YOU ACKNOWLEDGE (1) THAT THIS
35    * SOFTWARE HAS BEEN MADE AVAILABLE TO YOU FREE OF CHARGE, (2) THAT THIS
36    * SOFTWARE IS NOT "PRODUCT" QUALITY, BUT HAS BEEN PRODUCED BY A RESEARCH
37    * GROUP WHO DESIRE TO MAKE THIS SOFTWARE FREELY AVAILABLE TO PEOPLE WHO WISH
38    * TO USE IT, AND (3) THAT BECAUSE THIS SOFTWARE IS NOT OF "PRODUCT" QUALITY
39    * IT IS INEVITABLE THAT THERE WILL BE BUGS AND ERRORS, AND POSSIBLY MORE
40    * SERIOUS FAULTS, IN THIS SOFTWARE.
41    *
42    * 5. This license is governed, except to the extent that local laws
43    * necessarily apply, by the laws of England and Wales.
44    */
45   
46    package issrg.SAWS.callback;
47   
48    import issrg.SAWS.util.CertificateData;
49   
50    import issrg.SAWS.util.SAWSLogWriter;
51    import java.io.File;
52    import java.io.FileInputStream;
53   
54    import java.io.FileNotFoundException;
55   
56    import java.io.PrintStream;
57    import java.io.IOException;
58   
59    import java.util.Calendar;
60    import java.util.PropertyResourceBundle;
61   
62    import javax.security.auth.callback.Callback;
63    import javax.security.auth.callback.CallbackHandler;
64    import javax.security.auth.callback.UnsupportedCallbackException;
65   
66    /**
67    * This class represents the callback handler that uses graphical components
68    * to interact with the user.
69    *
70    * @author E. Silva
71    * @version 1.0, Feb. 2007
72    */
73   
 
74    public class SAWSFileCallbackHandler implements CallbackHandler {
75   
76    private static SAWSLogWriter sawsDebugLog = new SAWSLogWriter(SAWSFileCallbackHandler.class.getName());
77    private String inputFile, outputFile;
78    private PropertyResourceBundle replies;
79    private PrintStream output;
80   
81    /**
82    * Constructor of the class.
83    */
 
84  0 toggle private SAWSFileCallbackHandler() {
85    }
86   
 
87  8 toggle public SAWSFileCallbackHandler(String inputFile, String outputFile) {
88  8 this.setInputFile(inputFile);
89  8 this.setOutputFile(outputFile);
90  8 FileInputStream is = null;
91  8 try {
92  8 is = new FileInputStream(new File(inputFile));
93  8 if (this.outputFile != null) {
94  8 this.output = new PrintStream(new File(outputFile));
95    } else {
96  0 this.output = System.out;
97    }
98    } catch (FileNotFoundException e) {
99  0 throw new IllegalArgumentException("The input file '" + inputFile
100    + "' could not be found.");
101    }
102  8 try {
103  8 this.replies = new PropertyResourceBundle(is);
104    } catch (IOException e) {
105  0 throw new IllegalArgumentException("Fail accessing the input file.");
106    }
107    }
108   
109   
110    /**
111    * Method that handles the callbacks sent as parameter.
112    * @param callbacks The list of callbacks to be handled.
113    * @throws UnsupportedCallbackException If one of the callbacks are not known (supported).
114    */
 
115  33 toggle public void handle(Callback[] callbacks) throws UnsupportedCallbackException {
116  33 if (callbacks == null) {
117  0 throw new UnsupportedCallbackException(null, "ERROR: Callbacks can not be null.");
118    }
119   
120  68 for (int i = 0; i < callbacks.length; i++) {
121  35 if (callbacks[i] instanceof SAWSTextOutputCallback) {
122  6 switch (((SAWSTextOutputCallback)callbacks[i]).getMessageType()) {
123  0 case SAWSTextOutputCallback.ERROR:
124  0 this.output.println("\nERROR: " + ((SAWSTextOutputCallback)callbacks[i]).getMessage());
125  0 break;
126  6 case SAWSTextOutputCallback.INFORMATION:
127  6 this.output.println("\nINFO: " + ((SAWSTextOutputCallback)callbacks[i]).getMessage());
128  6 break;
129  0 case SAWSTextOutputCallback.WARNING:
130  0 this.output.println("\nWARNING: " + ((SAWSTextOutputCallback)callbacks[i]).getMessage());
131  0 break;
132  0 case SAWSTextOutputCallback.LONG_MESSAGE:
133  0 this.output.println("\n" + ((SAWSTextOutputCallback)callbacks[i]).getMessage());
134  0 break;
135    }
136   
137  6 this.output.flush();
138  6 if (this.output.checkError()) {
139  0 sawsDebugLog.write("Error:Fail writing in the output file.");
140  0 System.exit(-1);
141    }
142  29 } else if (callbacks[i] instanceof SAWSPasswordCallback) {
143  16 SAWSPasswordCallback pc = (SAWSPasswordCallback)callbacks[i];
144   
145  16 this.output.println("Reading password " + pc.getCurrentPasswordShare()
146    + " of " + pc.getPasswordShares() + " for the " + pc.getType() + " keystore...");
147   
148  16 pc.setPassword(this.replies.getString(pc.getType() + "Password" + pc.getCurrentPasswordShare()
149    + "of" + pc.getPasswordShares()).toCharArray());
150   
151  13 } else if (callbacks[i] instanceof CertificateDataCallback) {
152  2 CertificateDataCallback cdc = (CertificateDataCallback) callbacks[i];
153  2 CertificateData cd = null;
154  2 this.output.println("Reading Certificate Data from the input file..." + "\n");
155   
156  2 try {
157  2 cd = this.readCertificateData(cdc);
158    } catch (IllegalArgumentException iae) {
159  0 this.output.println(iae.getMessage());
160  0 this.output.flush();
161  0 if (this.output.checkError()) {
162  0 sawsDebugLog.write("Error: Fail writing in the output file.");
163    }
164  0 System.exit(-1);
165    }
166   
167  2 this.output.println("Subject Name: " + cd.toSubjectName() + "\n");
168  2 cdc.setCertData(cd);
169  11 } else if (callbacks[i] instanceof SAWSChoiceCallback) {
170  11 SAWSChoiceCallback cc = (SAWSChoiceCallback) callbacks[i];
171  11 this.output.println(cc.getPrompt());
172  11 int choice = cc.getDefaultOption();
173  11 try {
174  11 choice = Integer.parseInt(this.replies.getString(cc.getKey()));
175    } catch (NumberFormatException nfe) {
176  0 this.output.println("Warning: The value for the key " + cc.getKey()
177    + " must be a number. Please check the input file and try again.");
178  0 this.output.flush();
179  0 if (this.output.checkError()) {
180  0 this.sawsDebugLog.write("Fail wrinting the output file.");
181    }
182    }
183  11 this.output.println("Selected index: " + (choice));
184  11 this.output.flush();
185  11 cc.setSelectedIndex(choice - 1);
186  0 } else if (callbacks[i] instanceof SAWSTextInputCallback) {
187  0 SAWSTextInputCallback stic = (SAWSTextInputCallback) callbacks[i];
188  0 this.output.println(stic.getPrompt() + "\n");
189  0 String value = this.replies.getString(stic.getKey());
190  0 this.output.println("Input value: " + value + "\n");
191  0 this.output.flush();
192  0 stic.setText(value);
193    } else {
194  0 throw new UnsupportedCallbackException
195    (callbacks[i], "ERROR: Unrecognized Callback.");
196    }
197    }
198    }
199   
 
200  0 toggle public String getInputFile() {
201  0 return inputFile;
202    }
203   
 
204  8 toggle public void setInputFile(String inputFile) {
205  8 if (inputFile != null && inputFile.length() > 0) {
206  8 this.inputFile = inputFile;
207    } else {
208  0 throw new IllegalArgumentException("Invalid name for the input file.");
209    }
210    }
211   
 
212  0 toggle public String getOutputFile() {
213  0 return outputFile;
214    }
215   
 
216  8 toggle public void setOutputFile(String outputFile) {
217  8 if (outputFile != null && outputFile.length() > 0) {
218  8 this.outputFile = outputFile;
219    }
220    }
221   
222    /**
223    * Method responsible for asking the user the data about the certificate
224    * being created.
225    *
226    * @param cdc The callback generated to ask data about the certificate.
227    * @return The data about the certificate
228    */
 
229  2 toggle private CertificateData readCertificateData(CertificateDataCallback cdc) {
230  2 CertificateData cd = new CertificateData();
231  2 byte type = cdc.getType();
232   
233  2 String prefix = "";
234  2 if (type == CertificateDataCallback.ENCRYPTION) {
235  1 prefix = "EncCert";
236  1 } else if (type == CertificateDataCallback.SIGNING) {
237  1 prefix = "SigCert";
238    }
239   
240    // read Validity
241  2 String validity = this.replies.getString(prefix + "Validity");
242  2 if (validity.length() != 8) {
243  0 throw new IllegalArgumentException("WARNING: Please input a date in the format DDMMYYYY.");
244    }
245   
246  2 Calendar c = Calendar.getInstance();
247  2 c.setLenient(false);
248  2 try {
249  2 c.set(Calendar.YEAR, Integer.parseInt(validity.substring(4, 8)));
250  2 c.set(Calendar.MONTH, Integer.parseInt(validity.substring(2, 4)) - 1);
251  2 c.set(Calendar.DATE, Integer.parseInt(validity.substring(0, 2)));
252   
253  2 Calendar today = Calendar.getInstance();
254  2 today.set(Calendar.HOUR, 0);
255  2 today.set(Calendar.MINUTE, 0);
256  2 today.set(Calendar.SECOND, 0);
257   
258  2 Calendar temp = Calendar.getInstance();
259  2 temp.set(c.get(Calendar.YEAR), c.get(Calendar.MONTH),
260    c.get(Calendar.DATE), 0, 0, 0);
261   
262  2 long todayMili = today.getTimeInMillis();
263  2 long dateMili = temp.getTimeInMillis();
264   
265  2 if (todayMili > dateMili) {
266  0 throw new IllegalArgumentException("WARNING: The selected date must be after to "
267    + today.get(Calendar.DATE) + "/" + (today.get(Calendar.MONTH) + 1) + "/"
268    + today.get(Calendar.YEAR) + ".");
269    }
270   
271    /*calculate the number of days from today to the specified date
272    * and set teh field validity of the class CertificateData */
273  2 int days = (int)((dateMili - todayMili) / 1000 / 60 / 60 / 24);
274  2 today.add(Calendar.DATE, days);
275   
276  2 if (today.compareTo(temp) > 0) {
277  0 days = days - 1;
278  2 } else if (today.compareTo(temp) < 0) {
279  2 days = days + 1;
280    }
281   
282  2 cd.setValidity(days);
283   
284    } catch (NumberFormatException nfe) {
285  0 throw new IllegalArgumentException("WARNING: The date can not contain letters, only numbers. Please type again.");
286    } catch (IllegalArgumentException iae) {
287  0 throw new IllegalArgumentException("WARNING: " + iae.getMessage() + " is not valid. Please type the validity date again.");
288    }
289   
290    //read Subject Name
291  2 cd.setCommonName(this.replies.getString(prefix + "CN"));
292  2 cd.setOrganizationUnitName(this.replies.getString(prefix + "OU"));
293  2 cd.setOrganizationName(this.replies.getString(prefix + "O"));
294  2 cd.setLocalityName(this.replies.getString(prefix + "L"));
295  2 cd.setStateName(this.replies.getString(prefix + "S"));
296   
297  2 String country = this.replies.getString(prefix + "C");
298  2 if (country != null && !country.equals("") && country.length() != 2) {
299  0 throw new IllegalArgumentException("WARNING: The country code, if specified, "
300    + "must contain two letters. Please try again.");
301    } else {
302  2 cd.setCountryName(country);
303    }
304   
305  2 String sn = cd.toSubjectName();
306  2 if (sn == null || sn.equals("")) {
307  0 throw new IllegalArgumentException("WARNING: Subject name can not be null or empty. Please try again.");
308    }
309   
310    //read Algorithm Name
311   
312  2 String alg = this.replies.getString(prefix + "Algorithm");
313   
314  2 if (type == CertificateDataCallback.ENCRYPTION) {
315  1 if (alg.equalsIgnoreCase("RSA")) {
316  1 cd.setAlgorithm("RSA");
317    } else {
318  0 throw new IllegalArgumentException("WARNING: The supported algorithm for the "
319    + "encryption keystore is RSA. Please check the input file and try again.");
320    }
321    } else {
322  1 if (alg.equalsIgnoreCase("RSA") || alg.equalsIgnoreCase("DSA")) {
323  1 cd.setAlgorithm(alg);
324    } else {
325  0 throw new IllegalArgumentException("WARNING: The supported algorithm for the "
326    + "signing keystore are RSA and DSA. Please check the input file and try again.");
327    }
328    }
329   
330  2 int[] keySizes = null;
331  2 alg = cd.getAlgorithm();
332   
333  2 if (alg.equalsIgnoreCase("RSA")) { // Algorithm = RSA
334  1 keySizes = new int[]{1024, 2048, 3072, 4096};
335    } else { // Algorithm = DSA
336  1 keySizes = new int[]{512, 640, 768, 896, 1024};
337    }
338   
339  2 int keySize = 1024;
340  2 try {
341  2 keySize = Integer.parseInt(this.replies.getString(prefix + "KeySize"));
342    } catch (Exception ex) {
343  0 throw new IllegalArgumentException("WARNING: Invalid option. Please input a valid number for the key size.");
344    }
345   
346  2 boolean found = false;
347   
348   
349  2 String sizes = "";
350   
351  4 for (int i = 0;!found && i < keySizes.length; i = i + 1) {
352  2 if (keySizes[i] == keySize) {
353  2 found = true;
354    }
355   
356  2 sizes = sizes + ", " + keySizes[i];
357    }
358   
359  2 if (!found) {
360  0 throw new IllegalArgumentException("WARNING: Invalid key size. Please input one of the following: " + sizes);
361    } else {
362  2 cd.setKeySize(keySize);
363    }
364   
365  2 return cd;
366    }
367    }