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