PKCS12Security | Line # 60 | 38 | 9 | 84% |
0.84
|
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 | package issrg.security; | |
46 | ||
47 | import java.security.cert.X509Certificate; | |
48 | import java.security.PrivateKey; | |
49 | ||
50 | import java.io.File; | |
51 | import java.io.FileNotFoundException; | |
52 | ||
53 | /** | |
54 | * This class implements a security that uses a PKCS#12 file to authenticate | |
55 | * the user and obtain the signing and signature verification keys. The user | |
56 | * interaction is inherited from DefaultSecurity. Only the key methods are | |
57 | * overridden to log the user in using a known PKCS#12 file name, and | |
58 | * a method to construct a FilenameCallback. | |
59 | */ | |
60 | public class PKCS12Security extends DefaultSecurity { | |
61 | private static final byte [] checkbytes=new byte[256]; | |
62 | ||
63 | 2 | static{ |
64 | 514 | for (int i=0; i<checkbytes.length; i++) checkbytes[i]=(byte)i; |
65 | ||
66 | 2 | iaik.security.provider.IAIK.addAsJDK14Provider(); |
67 | } | |
68 | ||
69 | 4 | public PKCS12Security() throws SecurityException { |
70 | 4 | super(); |
71 | } | |
72 | ||
73 | /** | |
74 | * The method for logging the user in without GUI. The method attempts to | |
75 | * decrypt the private key, then signs and verifies a signature on an | |
76 | * arbitrary | |
77 | * byte array to ensure that the private key and the PKC match. Note that for | |
78 | * signing purposes it is necessary to know the DN of the signer, which is | |
79 | * not included | |
80 | * in the private key. | |
81 | * | |
82 | * <p>After logging the user in the Root CAs are set to the collection of PKCs | |
83 | * in the PKCS#12 file, including the user's signature verification PKC. The | |
84 | * first PKC to match the signing key is used as the user's signature | |
85 | * verification key. | |
86 | * | |
87 | * @param pkcFile is the filename of the PKCS#12 construct | |
88 | * @param password is the password for decrypting the PKCS#12 file | |
89 | */ | |
90 | 3 | public void login(String pkcFile, char[] password) throws SecurityException { |
91 | 3 | X509Certificate [] x509=getRootCAs(); |
92 | 3 | X509Certificate [] rootCA; |
93 | 3 | PrivateKey pk=getPrivateKey(); |
94 | 3 | java.security.Signature signature=getSignature(); |
95 | ||
96 | 3 | try{ |
97 | 3 | java.io.FileInputStream fin=new java.io.FileInputStream(pkcFile); |
98 | 3 | iaik.pkcs.pkcs12.PKCS12 epki = new iaik.pkcs.pkcs12.PKCS12(fin); |
99 | 3 | epki.decrypt(password); |
100 | ||
101 | // here the PKCS12 file should have been decrypted ok | |
102 | ||
103 | 3 | secretKey=epki.getKeyBag().getPrivateKey(); |
104 | 3 | rootCA=iaik.pkcs.pkcs12.CertificateBag.getCertificates(epki.getCertificateBags()); |
105 | ||
106 | // here both x509 and pk are fine | |
107 | // lets check if they match each other | |
108 | ||
109 | 3 | String sigAlg = getDigestAlgorithm()+"with"+secretKey.getAlgorithm(); |
110 | 3 | setSignature(java.security.Signature.getInstance(sigAlg)); |
111 | ||
112 | 3 | byte [] sig=sign(checkbytes); |
113 | // the use of rootCA.getSigAlgOID() is not always correct. This value shows what algorithm was used to sign rootCA certificate | |
114 | // we can reuse this algorithm only if rootCA is really a self-signed PKC, which usually it is, but in a simplistic "PKI" | |
115 | // non-selfsigned PKCs may be allowed | |
116 | 3 | boolean verified=false; |
117 | 5 | for (int i=0; i<rootCA.length; i++){ |
118 | 5 | try{ |
119 | 5 | if (verify(checkbytes, sig, sigAlg, new X509Certificate[]{rootCA[i]})){ |
120 | 3 | X509Certificate c=rootCA[0]; // reorder them so that the entity PKC is the first in the array |
121 | 3 | rootCA[0]=rootCA[i]; |
122 | 3 | rootCA[i]=c; |
123 | 3 | verified=true; |
124 | 3 | break; |
125 | } | |
126 | }catch(Exception ex){ | |
127 | // ignore - this is not the key of the holder; try another | |
128 | } | |
129 | } | |
130 | 3 | if (verified){ // the signature verifies |
131 | 3 | x509=rootCA; // note that the finally statement requires such substitution, so the keys will be properly remembered |
132 | 3 | pk=secretKey; |
133 | 3 | signature=getSignature(); |
134 | }else{ | |
135 | 0 | throw new SecurityException ("The PKC does not match the Private Key. Use another key-pair."); |
136 | } | |
137 | ||
138 | }catch (SecurityException se){ | |
139 | 0 | throw se; |
140 | }catch (FileNotFoundException fnfe) { | |
141 | 0 | throw new SecurityException("Could not find the P12 file", fnfe); |
142 | }catch(Exception e){ | |
143 | 0 | throw new SecurityException("Failed to log into the specified PKCS#12", e); |
144 | }finally{ // restore the private key and PKC as they were before executing the method | |
145 | // unless the values of the x509 and pk have been updated due to successful signature verification | |
146 | 3 | setRootCAs(x509); |
147 | 3 | setPrivateKey(pk); |
148 | 3 | setSignature(signature); |
149 | } | |
150 | } | |
151 | ||
152 | final public static String PKC_EXTENSION=".p12"; | |
153 | final public static String PFX_EXTENSION=".pfx"; | |
154 | final public static String exts[] = new String[]{PKC_EXTENSION, PFX_EXTENSION}; | |
155 | ||
156 | /** | |
157 | * This method constructs a FilenameCallback that will filter out all but | |
158 | * PKCS#12 files with the extensions PKC_EXTENSION (".p12") and PFX_EXTENSION | |
159 | * (".pfx"). | |
160 | * | |
161 | * @param defaultFile - the default file to use if the user doesn't make any | |
162 | * selection | |
163 | * | |
164 | * @return FilenameCallback configured to display PKCS#12 files only | |
165 | */ | |
166 | 0 | public FilenameCallback getFilenameCallback(String defaultFile){ |
167 | 0 | return new FilenameCallback("PKCS#12 file", defaultFile, "PKCS#12 Files", exts); |
168 | } | |
169 | } |
|