1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.wss4j.common.crypto;
21
22 import java.io.IOException;
23 import java.math.BigInteger;
24 import java.security.InvalidAlgorithmParameterException;
25 import java.security.KeyStore;
26 import java.security.KeyStoreException;
27 import java.security.NoSuchAlgorithmException;
28 import java.security.NoSuchProviderException;
29 import java.security.cert.CertPath;
30 import java.security.cert.CertPathValidator;
31 import java.security.cert.Certificate;
32 import java.security.cert.CertificateEncodingException;
33 import java.security.cert.CertificateException;
34 import java.security.cert.CertificateExpiredException;
35 import java.security.cert.CertificateNotYetValidException;
36 import java.security.cert.PKIXParameters;
37 import java.security.cert.TrustAnchor;
38 import java.security.cert.X509Certificate;
39 import java.util.Arrays;
40 import java.util.Collection;
41 import java.util.Enumeration;
42 import java.util.HashSet;
43 import java.util.List;
44 import java.util.Properties;
45 import java.util.Set;
46 import java.util.regex.Pattern;
47
48 import org.apache.wss4j.common.ext.WSSecurityException;
49
50
51
52
53
54
55
56 public class MerlinAKI extends Merlin {
57
58 private static final org.slf4j.Logger LOG =
59 org.slf4j.LoggerFactory.getLogger(MerlinAKI.class);
60
61 public MerlinAKI() {
62 super();
63 }
64
65 public MerlinAKI(boolean loadCACerts, String cacertsPasswd) {
66 super(loadCACerts, cacertsPasswd);
67 }
68
69 public MerlinAKI(Properties properties, ClassLoader loader, PasswordEncryptor passwordEncryptor)
70 throws WSSecurityException, IOException {
71 super(properties, loader, passwordEncryptor);
72 }
73
74
75
76
77
78
79
80
81
82
83 @Override
84 protected void verifyTrust(
85 X509Certificate[] certs,
86 boolean enableRevocation,
87 Collection<Pattern> subjectCertConstraints
88 ) throws WSSecurityException {
89
90
91
92 if (certs.length == 1 && !enableRevocation) {
93 String issuerString = certs[0].getIssuerX500Principal().getName();
94 BigInteger issuerSerial = certs[0].getSerialNumber();
95
96 CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ISSUER_SERIAL);
97 cryptoType.setIssuerSerial(issuerString, issuerSerial);
98 X509Certificate[] foundCerts = getX509Certificates(cryptoType);
99
100
101
102
103
104 if (foundCerts != null && foundCerts.length > 0 && foundCerts[0] != null && foundCerts[0].equals(certs[0])) {
105 try {
106 certs[0].checkValidity();
107 } catch (CertificateExpiredException | CertificateNotYetValidException e) {
108 throw new WSSecurityException(
109 WSSecurityException.ErrorCode.FAILED_CHECK, e, "invalidCert"
110 );
111 }
112 LOG.debug(
113 "Direct trust for certificate with {}", certs[0].getSubjectX500Principal().getName()
114 );
115 return;
116 }
117 }
118
119
120
121
122
123 X509Certificate[] x509certs = certs;
124 String issuerString = certs[0].getIssuerX500Principal().getName();
125 try {
126 if (certs.length == 1) {
127 byte[] keyIdentifierBytes =
128 BouncyCastleUtils.getAuthorityKeyIdentifierBytes(certs[0]);
129 X509Certificate[] foundCerts = getX509CertificatesFromKeyIdentifier(keyIdentifierBytes);
130
131
132
133 if (foundCerts == null || foundCerts.length < 1) {
134 String subjectString = certs[0].getSubjectX500Principal().getName();
135 LOG.debug(
136 "No certs found in keystore for issuer {} of certificate for {}",
137 issuerString, subjectString
138 );
139 throw new WSSecurityException(
140 WSSecurityException.ErrorCode.FAILURE, "certpath", new Object[] {"No trusted certs found"}
141 );
142 }
143
144
145
146
147
148 x509certs = new X509Certificate[foundCerts.length + 1];
149 x509certs[0] = certs[0];
150 System.arraycopy(foundCerts, 0, x509certs, 1, foundCerts.length);
151 }
152 } catch (NoSuchAlgorithmException | CertificateException ex) {
153 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex, "certpath");
154 }
155
156
157
158
159
160 LOG.debug(
161 "Preparing to validate certificate path for issuer {}", issuerString
162 );
163
164 try {
165
166 List<X509Certificate> certList = Arrays.asList(x509certs);
167 CertPath path = getCertificateFactory().generateCertPath(certList);
168
169 Set<TrustAnchor> set = new HashSet<>();
170 if (truststore != null) {
171 addTrustAnchors(set, truststore);
172 }
173
174
175
176
177
178
179 if (keystore != null && (truststore == null || loadCACerts)) {
180 addTrustAnchors(set, keystore);
181 }
182
183
184 String provider = getCryptoProvider();
185 CertPathValidator validator = null;
186 if (provider == null || provider.length() == 0) {
187 validator = CertPathValidator.getInstance("PKIX");
188 } else {
189 validator = CertPathValidator.getInstance("PKIX", provider);
190 }
191
192 PKIXParameters param = createPKIXParameters(set, enableRevocation);
193 validator.validate(path, param);
194 } catch (NoSuchProviderException | NoSuchAlgorithmException
195 | CertificateException | InvalidAlgorithmParameterException
196 | java.security.cert.CertPathValidatorException
197 | KeyStoreException e) {
198 throw new WSSecurityException(
199 WSSecurityException.ErrorCode.FAILURE, e, "certpath"
200 );
201 }
202
203
204 if (!matchesSubjectDnPattern(certs[0], subjectCertConstraints)) {
205 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
206 }
207 }
208
209 private X509Certificate[] getX509CertificatesFromKeyIdentifier(
210 byte[] keyIdentifierBytes
211 ) throws WSSecurityException, NoSuchAlgorithmException, CertificateEncodingException {
212 if (keyIdentifierBytes == null) {
213 return new X509Certificate[0];
214 }
215
216 Certificate[] certs = null;
217 if (keystore != null) {
218 certs = getCertificates(keyIdentifierBytes, keystore);
219 }
220
221
222 if ((certs == null || certs.length == 0) && truststore != null) {
223 certs = getCertificates(keyIdentifierBytes, truststore);
224 }
225
226 if (certs == null || certs.length == 0) {
227 return new X509Certificate[0];
228 }
229
230 return Arrays.copyOf(certs, certs.length, X509Certificate[].class);
231 }
232
233 private Certificate[] getCertificates(
234 byte[] keyIdentifier,
235 KeyStore store
236 ) throws WSSecurityException, NoSuchAlgorithmException, CertificateEncodingException {
237 try {
238 for (Enumeration<String> e = store.aliases(); e.hasMoreElements();) {
239 String alias = e.nextElement();
240 Certificate[] certs = store.getCertificateChain(alias);
241 if (certs == null || certs.length == 0) {
242
243 Certificate cert = store.getCertificate(alias);
244 if (cert != null) {
245 certs = new Certificate[]{cert};
246 }
247 }
248
249 if (certs != null && certs.length > 0 && certs[0] instanceof X509Certificate) {
250 byte[] subjectKeyIdentifier =
251 BouncyCastleUtils.getSubjectKeyIdentifierBytes((X509Certificate)certs[0]);
252 if (subjectKeyIdentifier != null
253 && Arrays.equals(subjectKeyIdentifier, keyIdentifier)) {
254 return certs;
255 }
256 }
257 }
258 } catch (KeyStoreException e) {
259 throw new WSSecurityException(
260 WSSecurityException.ErrorCode.FAILURE, e, "keystore"
261 );
262 }
263 return new Certificate[]{};
264 }
265
266 }