1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.opensaml.xml.security.keyinfo.provider;
18
19 import java.math.BigInteger;
20 import java.security.PublicKey;
21 import java.security.cert.CRLException;
22 import java.security.cert.CertificateException;
23 import java.security.cert.X509CRL;
24 import java.security.cert.X509Certificate;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.List;
28
29 import javax.security.auth.x500.X500Principal;
30
31 import org.opensaml.xml.XMLObject;
32 import org.opensaml.xml.security.CriteriaSet;
33 import org.opensaml.xml.security.SecurityException;
34 import org.opensaml.xml.security.credential.Credential;
35 import org.opensaml.xml.security.credential.CredentialContext;
36 import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver;
37 import org.opensaml.xml.security.keyinfo.KeyInfoHelper;
38 import org.opensaml.xml.security.keyinfo.KeyInfoProvider;
39 import org.opensaml.xml.security.keyinfo.KeyInfoResolutionContext;
40 import org.opensaml.xml.security.x509.BasicX509Credential;
41 import org.opensaml.xml.security.x509.InternalX500DNHandler;
42 import org.opensaml.xml.security.x509.X500DNHandler;
43 import org.opensaml.xml.security.x509.X509Credential;
44 import org.opensaml.xml.security.x509.X509Util;
45 import org.opensaml.xml.signature.KeyValue;
46 import org.opensaml.xml.signature.X509Data;
47 import org.opensaml.xml.signature.X509IssuerSerial;
48 import org.opensaml.xml.signature.X509SKI;
49 import org.opensaml.xml.signature.X509SubjectName;
50 import org.opensaml.xml.util.Base64;
51 import org.opensaml.xml.util.DatatypeHelper;
52 import org.opensaml.xml.util.LazySet;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 public class InlineX509DataProvider extends AbstractKeyInfoProvider {
72
73
74 private final Logger log = LoggerFactory.getLogger(InlineX509DataProvider.class);
75
76
77 private X500DNHandler x500DNHandler;
78
79
80
81
82 public InlineX509DataProvider() {
83 x500DNHandler = new InternalX500DNHandler();
84 }
85
86
87
88
89
90
91 public X500DNHandler getX500DNHandler() {
92 return x500DNHandler;
93 }
94
95
96
97
98
99
100 public void setX500DNHandler(X500DNHandler handler) {
101 if (handler == null) {
102 throw new IllegalArgumentException("X500DNHandler may not be null");
103 }
104 x500DNHandler = handler;
105 }
106
107
108 public boolean handles(XMLObject keyInfoChild) {
109 return keyInfoChild instanceof X509Data;
110 }
111
112
113 public Collection<Credential> process(KeyInfoCredentialResolver resolver, XMLObject keyInfoChild,
114 CriteriaSet criteriaSet, KeyInfoResolutionContext kiContext) throws SecurityException {
115
116 if (! handles(keyInfoChild)) {
117 return null;
118 }
119
120 X509Data x509Data = (X509Data) keyInfoChild;
121
122 log.debug("Attempting to extract credential from an X509Data");
123
124 List<X509Certificate> certs = extractCertificates(x509Data);
125 if (certs.isEmpty()) {
126 log.info("The X509Data contained no X509Certificate elements, skipping credential extraction");
127 return null;
128 }
129 List<X509CRL> crls = extractCRLs(x509Data);
130
131 PublicKey resolvedPublicKey = null;
132 if (kiContext != null && kiContext.getKey() != null && kiContext.getKey() instanceof PublicKey) {
133 resolvedPublicKey = (PublicKey) kiContext.getKey();
134 }
135 X509Certificate entityCert = findEntityCert(certs, x509Data, resolvedPublicKey);
136 if (entityCert == null) {
137 log.warn("The end-entity cert could not be identified, skipping credential extraction");
138 return null;
139 }
140
141 BasicX509Credential cred = new BasicX509Credential();
142 cred.setEntityCertificate(entityCert);
143 cred.setCRLs(crls);
144 cred.setEntityCertificateChain(certs);
145
146 if (kiContext != null) {
147 cred.getKeyNames().addAll(kiContext.getKeyNames());
148 }
149
150 CredentialContext credContext = buildCredentialContext(kiContext);
151 if (credContext != null) {
152 cred.getCredentalContextSet().add(credContext);
153 }
154
155 LazySet<Credential> credentialSet = new LazySet<Credential>();
156 credentialSet.add(cred);
157 return credentialSet;
158 }
159
160
161
162
163
164
165
166
167 private List<X509CRL> extractCRLs(X509Data x509Data) throws SecurityException {
168 List<X509CRL> crls = null;
169 try {
170 crls = KeyInfoHelper.getCRLs(x509Data);
171 } catch (CRLException e) {
172 log.error("Error extracting CRL's from X509Data", e);
173 throw new SecurityException("Error extracting CRL's from X509Data", e);
174 }
175
176 log.debug("Found {} X509CRLs", crls.size());
177 return crls;
178 }
179
180
181
182
183
184
185
186
187 private List<X509Certificate> extractCertificates(X509Data x509Data) throws SecurityException {
188 List<X509Certificate> certs = null;
189 try {
190 certs = KeyInfoHelper.getCertificates(x509Data);
191 } catch (CertificateException e) {
192 log.error("Error extracting certificates from X509Data", e);
193 throw new SecurityException("Error extracting certificates from X509Data", e);
194 }
195 log.debug("Found {} X509Certificates", certs.size());
196 return certs;
197 }
198
199
200
201
202
203
204
205
206
207 protected X509Certificate findEntityCert(List<X509Certificate> certs, X509Data x509Data, PublicKey resolvedKey) {
208 if (certs == null || certs.isEmpty()) {
209 return null;
210 }
211
212
213 if (certs.size() == 1) {
214 log.debug("Single certificate was present, treating as end-entity certificate");
215 return certs.get(0);
216 }
217
218 X509Certificate cert = null;
219
220
221 cert = findCertFromKey(certs, resolvedKey);
222 if (cert != null) {
223 log.debug("End-entity certificate resolved by matching previously resolved public key");
224 return cert;
225 }
226
227
228 cert = findCertFromSubjectNames(certs, x509Data.getX509SubjectNames());
229 if (cert != null) {
230 log.debug("End-entity certificate resolved by matching X509SubjectName");
231 return cert;
232 }
233
234
235 cert = findCertFromIssuerSerials(certs, x509Data.getX509IssuerSerials());
236 if (cert != null) {
237 log.debug("End-entity certificate resolved by matching X509IssuerSerial");
238 return cert;
239 }
240
241
242 cert = findCertFromSubjectKeyIdentifier(certs, x509Data.getX509SKIs());
243 if (cert != null) {
244 log.debug("End-entity certificate resolved by matching X509SKI");
245 return cert;
246 }
247
248
249
250
251
252 log.debug("Treating the first certificate in the X509Data as the end-entity certificate");
253 return certs.get(0);
254 }
255
256
257
258
259
260
261
262
263 protected X509Certificate findCertFromKey(List<X509Certificate> certs, PublicKey key) {
264 if (key != null) {
265 for (X509Certificate cert : certs) {
266 if (cert.getPublicKey().equals(key)) {
267 return cert;
268 }
269 }
270 }
271 return null;
272 }
273
274
275
276
277
278
279
280
281 protected X509Certificate findCertFromSubjectNames(List<X509Certificate> certs, List<X509SubjectName> names) {
282 for (X509SubjectName subjectName : names) {
283 if (! DatatypeHelper.isEmpty(subjectName.getValue())) {
284 X500Principal subjectX500Principal = x500DNHandler.parse(subjectName.getValue());
285 for (X509Certificate cert : certs) {
286 if (cert.getSubjectX500Principal().equals(subjectX500Principal)) {
287 return cert;
288 }
289 }
290 }
291 }
292 return null;
293 }
294
295
296
297
298
299
300
301
302 protected X509Certificate findCertFromIssuerSerials(List<X509Certificate> certs, List<X509IssuerSerial> serials) {
303 for (X509IssuerSerial issuerSerial : serials) {
304 if (issuerSerial.getX509IssuerName() == null || issuerSerial.getX509SerialNumber() == null) {
305 continue;
306 }
307 String issuerNameValue = issuerSerial.getX509IssuerName().getValue();
308 BigInteger serialNumber = issuerSerial.getX509SerialNumber().getValue();
309 if (! DatatypeHelper.isEmpty(issuerNameValue)) {
310 X500Principal issuerX500Principal = x500DNHandler.parse(issuerNameValue);
311 for (X509Certificate cert : certs) {
312 if (cert.getIssuerX500Principal().equals(issuerX500Principal) &&
313 cert.getSerialNumber().equals(serialNumber)) {
314 return cert;
315 }
316 }
317 }
318 }
319 return null;
320 }
321
322
323
324
325
326
327
328
329 protected X509Certificate findCertFromSubjectKeyIdentifier(List<X509Certificate> certs, List<X509SKI> skis) {
330 for (X509SKI ski : skis) {
331 if (! DatatypeHelper.isEmpty(ski.getValue())) {
332 byte[] xmlValue = Base64.decode(ski.getValue());
333 for (X509Certificate cert : certs) {
334 byte[] certValue = X509Util.getSubjectKeyIdentifier(cert);
335 if (certValue != null && Arrays.equals(xmlValue, certValue)) {
336 return cert;
337 }
338 }
339 }
340 }
341 return null;
342 }
343 }