1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.apache.james.mailet.crypto;
23
24 import java.io.BufferedInputStream;
25 import java.io.File;
26 import java.io.FileInputStream;
27 import java.io.IOException;
28 import java.security.GeneralSecurityException;
29 import java.security.InvalidAlgorithmParameterException;
30 import java.security.KeyStore;
31 import java.security.KeyStoreException;
32 import java.security.NoSuchAlgorithmException;
33 import java.security.NoSuchProviderException;
34 import java.security.cert.CertPath;
35 import java.security.cert.CertPathBuilder;
36 import java.security.cert.CertPathBuilderException;
37 import java.security.cert.CertPathBuilderResult;
38 import java.security.cert.CertStore;
39 import java.security.cert.CertificateException;
40 import java.security.cert.PKIXBuilderParameters;
41 import java.security.cert.X509CertSelector;
42 import java.security.cert.X509Certificate;
43 import java.util.ArrayList;
44 import java.util.Collection;
45 import java.util.Iterator;
46 import java.util.List;
47
48 import javax.mail.MessagingException;
49
50 import org.bouncycastle.cms.SignerInformation;
51 import org.bouncycastle.cms.SignerInformationStore;
52 import org.bouncycastle.mail.smime.SMIMESigned;
53
54
55
56
57
58
59
60
61
62 public class KeyStoreHolder {
63
64 protected KeyStore keyStore;
65
66 public KeyStoreHolder () throws IOException, GeneralSecurityException {
67
68 this("changeit");
69 }
70
71 public KeyStoreHolder (String password) throws IOException, GeneralSecurityException {
72 this(System.getProperty("java.home")+"/lib/security/cacerts".replace('/', File.separatorChar), password, KeyStore.getDefaultType());
73 }
74
75 public KeyStoreHolder(String keyStoreFileName, String keyStorePassword, String keyStoreType)
76 throws KeyStoreException, NoSuchAlgorithmException, CertificateException, NoSuchProviderException, IOException {
77
78 if (keyStorePassword == null) keyStorePassword = "";
79
80 try {
81 InitJCE.init();
82 } catch (InstantiationException e) {
83 NoSuchProviderException ex = new NoSuchProviderException("Error during cryptography provider initialization. Has bcprov-jdkxx-yyy.jar been copied in the lib directory or installed in the system?");
84 ex.initCause(e);
85 throw ex;
86 } catch (IllegalAccessException e) {
87 NoSuchProviderException ex = new NoSuchProviderException("Error during cryptography provider initialization. Has bcprov-jdkxx-yyy.jar been copied in the lib directory or installed in the system?");
88 ex.initCause(e);
89 throw ex;
90 } catch (ClassNotFoundException e) {
91 NoSuchProviderException ex = new NoSuchProviderException("Error during cryptography provider initialization. Has bcprov-jdkxx-yyy.jar been copied in the lib directory or installed in the system?");
92 ex.initCause(e);
93 throw ex;
94 }
95
96 if (keyStoreType == null) {
97 keyStoreType = KeyStore.getDefaultType();
98 }
99
100 keyStore = KeyStore.getInstance(keyStoreType);
101 keyStore.load(new BufferedInputStream(new FileInputStream(keyStoreFileName)), keyStorePassword.toCharArray());
102 if (keyStore.size() == 0) throw new KeyStoreException("The keystore must be not empty");
103 }
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118 public List verifySignatures(SMIMESigned signed) throws Exception, MessagingException {
119 CertStore certs = signed.getCertificatesAndCRLs("Collection", "BC");
120 SignerInformationStore siginfo = signed.getSignerInfos();
121 Collection sigCol = siginfo.getSigners();
122 Iterator sigIterator = sigCol.iterator();
123 List result = new ArrayList(sigCol.size());
124
125
126
127 for (int i=0;sigIterator.hasNext();i++) {
128 SignerInformation info = (SignerInformation) sigIterator.next();
129
130 Collection certCollection = certs.getCertificates(info.getSID());
131 Iterator certIter =certCollection.iterator();
132 if (certIter.hasNext()) {
133 X509Certificate signerCert = (X509Certificate) certIter.next();
134
135 CertPath path = verifyCertificate(signerCert, certs, keyStore);
136
137 try {
138
139
140
141
142
143
144
145
146
147 if (info.verify(signerCert, "BC")) {
148 result.add(new SMIMESignerInfo(signerCert, path, true));
149 }
150 } catch (Exception e) {
151 result.add(new SMIMESignerInfo(signerCert,path, false));
152 }
153 }
154 }
155 return result;
156 }
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173 private static CertPath verifyCertificate(X509Certificate cert, CertStore store, KeyStore trustedStore)
174 throws InvalidAlgorithmParameterException, KeyStoreException, MessagingException, CertPathBuilderException {
175
176 if (cert == null || store == null || trustedStore == null) throw new IllegalArgumentException("cert == "+cert+", store == "+store+", trustedStore == "+trustedStore);
177
178 CertPathBuilder pathBuilder;
179
180
181
182
183 try {
184 pathBuilder = CertPathBuilder.getInstance("PKIX", "BC");
185 } catch (Exception e) {
186 throw new MessagingException("Error during the creation of the certpathbuilder.", e);
187 }
188
189 X509CertSelector xcs = new X509CertSelector();
190 xcs.setCertificate(cert);
191 PKIXBuilderParameters params = new PKIXBuilderParameters(trustedStore, xcs);
192 params.addCertStore(store);
193 params.setRevocationEnabled(false);
194
195 try {
196 CertPathBuilderResult result = pathBuilder.build(params);
197 CertPath path = result.getCertPath();
198 return path;
199 } catch (CertPathBuilderException e) {
200
201 return null;
202 } catch (InvalidAlgorithmParameterException e) {
203
204
205 throw new MessagingException("Error during the certification path search.", e);
206 }
207 }
208 }