1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.opensaml.xml.signature.impl;
18
19 import java.util.Set;
20
21 import org.opensaml.xml.security.CriteriaSet;
22 import org.opensaml.xml.security.SecurityException;
23 import org.opensaml.xml.security.SecurityHelper;
24 import org.opensaml.xml.security.SigningUtil;
25 import org.opensaml.xml.security.credential.Credential;
26 import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver;
27 import org.opensaml.xml.security.x509.BasicX509CredentialNameEvaluator;
28 import org.opensaml.xml.security.x509.PKIXTrustEngine;
29 import org.opensaml.xml.security.x509.CertPathPKIXTrustEvaluator;
30 import org.opensaml.xml.security.x509.PKIXTrustEvaluator;
31 import org.opensaml.xml.security.x509.PKIXValidationInformation;
32 import org.opensaml.xml.security.x509.PKIXValidationInformationResolver;
33 import org.opensaml.xml.security.x509.X509Credential;
34 import org.opensaml.xml.security.x509.X509CredentialNameEvaluator;
35 import org.opensaml.xml.signature.Signature;
36 import org.opensaml.xml.signature.SignatureTrustEngine;
37 import org.opensaml.xml.util.Pair;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41
42
43
44
45
46
47
48
49
50
51
52
53 public class PKIXSignatureTrustEngine extends
54 BaseSignatureTrustEngine<Pair<Set<String>, Iterable<PKIXValidationInformation>>> implements
55 PKIXTrustEngine<Signature> {
56
57
58 private final Logger log = LoggerFactory.getLogger(PKIXSignatureTrustEngine.class);
59
60
61 private PKIXValidationInformationResolver pkixResolver;
62
63
64 private PKIXTrustEvaluator pkixTrustEvaluator;
65
66
67 private X509CredentialNameEvaluator credNameEvaluator;
68
69
70
71
72
73
74
75
76
77
78
79
80 public PKIXSignatureTrustEngine(PKIXValidationInformationResolver resolver,
81 KeyInfoCredentialResolver keyInfoResolver) {
82
83 super(keyInfoResolver);
84 if (resolver == null) {
85 throw new IllegalArgumentException("PKIX trust information resolver may not be null");
86 }
87 pkixResolver = resolver;
88
89 pkixTrustEvaluator = new CertPathPKIXTrustEvaluator();
90 credNameEvaluator = new BasicX509CredentialNameEvaluator();
91 }
92
93
94
95
96
97
98
99
100
101
102 public PKIXSignatureTrustEngine(PKIXValidationInformationResolver resolver,
103 KeyInfoCredentialResolver keyInfoResolver, PKIXTrustEvaluator pkixEvaluator,
104 X509CredentialNameEvaluator nameEvaluator) {
105
106 super(keyInfoResolver);
107 if (resolver == null) {
108 throw new IllegalArgumentException("PKIX trust information resolver may not be null");
109 }
110 pkixResolver = resolver;
111
112 if (pkixEvaluator == null) {
113 throw new IllegalArgumentException("PKIX trust evaluator may not be null");
114 }
115 pkixTrustEvaluator = pkixEvaluator;
116 credNameEvaluator = nameEvaluator;
117 }
118
119
120
121
122
123
124
125
126
127 public PKIXTrustEvaluator getPKIXTrustEvaluator() {
128 return pkixTrustEvaluator;
129 }
130
131
132
133
134
135
136
137
138
139
140 public X509CredentialNameEvaluator getX509CredentialNameEvaluator() {
141 return credNameEvaluator;
142 }
143
144
145 public PKIXValidationInformationResolver getPKIXResolver() {
146 return pkixResolver;
147 }
148
149
150 public boolean validate(Signature signature, CriteriaSet trustBasisCriteria) throws SecurityException {
151
152 checkParams(signature, trustBasisCriteria);
153
154 Pair<Set<String>, Iterable<PKIXValidationInformation>> validationPair =
155 resolveValidationInfo(trustBasisCriteria);
156
157 if (validate(signature, validationPair)) {
158 return true;
159 }
160
161 log.error("PKIX validation of signature failed, unable to resolve valid and trusted signing key");
162 return false;
163 }
164
165
166 public boolean validate(byte[] signature, byte[] content, String algorithmURI, CriteriaSet trustBasisCriteria,
167 Credential candidateCredential) throws SecurityException {
168
169 if (candidateCredential == null || SecurityHelper.extractVerificationKey(candidateCredential) == null) {
170 log.debug("Candidate credential was either not supplied or did not contain verification key");
171 log.debug("PKIX trust engine requires supplied key, skipping PKIX trust evaluation");
172 return false;
173 }
174
175 checkParamsRaw(signature, content, algorithmURI, trustBasisCriteria);
176
177 Pair<Set<String>, Iterable<PKIXValidationInformation>> validationPair =
178 resolveValidationInfo(trustBasisCriteria);
179
180 if (SigningUtil.verifyWithURI(candidateCredential, algorithmURI, signature, content)) {
181 log.debug("Successfully verified raw signature using supplied candidate credential");
182 log.debug("Attempting to establish trust of supplied candidate credential");
183 if (evaluateTrust(candidateCredential, validationPair)) {
184 log.debug("Successfully established trust of supplied candidate credential");
185 return true;
186 } else {
187 log.debug("Failed to establish trust of supplied candidate credential");
188 }
189 } else {
190 log.error("Cryptographic verification of raw signature failed with candidate credential");
191 }
192
193 log.error("PKIX validation of raw signature failed, "
194 + "unable to establish trust of supplied verification credential");
195 return false;
196 }
197
198
199 protected boolean evaluateTrust(Credential untrustedCredential,
200 Pair<Set<String>, Iterable<PKIXValidationInformation>> validationPair) throws SecurityException {
201
202 if (!(untrustedCredential instanceof X509Credential)) {
203 log.info("Can not evaluate trust of non-X509Credential");
204 return false;
205 }
206 X509Credential untrustedX509Credential = (X509Credential) untrustedCredential;
207
208 Set<String> trustedNames = validationPair.getFirst();
209 Iterable<PKIXValidationInformation> validationInfoSet = validationPair.getSecond();
210
211 if (!checkNames(trustedNames, untrustedX509Credential)) {
212 log.error("Evaluation of credential against trusted names failed. Aborting PKIX validation");
213 return false;
214 }
215
216 for (PKIXValidationInformation validationInfo : validationInfoSet) {
217 try {
218 if (pkixTrustEvaluator.validate(validationInfo, untrustedX509Credential)) {
219 log.debug("Signature trust established via PKIX validation of signing credential");
220 return true;
221 }
222 } catch (SecurityException e) {
223
224 log.error("Error performing PKIX validation on untrusted credential", e);
225 }
226 }
227
228 log.debug("Signature trust could not be established via PKIX validation of signing credential");
229 return false;
230 }
231
232
233
234
235
236
237
238
239
240
241 protected Pair<Set<String>, Iterable<PKIXValidationInformation>> resolveValidationInfo(
242 CriteriaSet trustBasisCriteria) throws SecurityException {
243
244 Set<String> trustedNames = null;
245 if (pkixResolver.supportsTrustedNameResolution()) {
246 trustedNames = pkixResolver.resolveTrustedNames(trustBasisCriteria);
247 } else {
248 log.debug("PKIX resolver does not support resolution of trusted names, skipping name checking");
249 }
250 Iterable<PKIXValidationInformation> validationInfoSet = pkixResolver.resolve(trustBasisCriteria);
251
252 Pair<Set<String>, Iterable<PKIXValidationInformation>> validationPair =
253 new Pair<Set<String>, Iterable<PKIXValidationInformation>>(trustedNames, validationInfoSet);
254
255 return validationPair;
256 }
257
258
259
260
261
262
263
264
265
266
267
268 protected boolean checkNames(Set<String> trustedNames, X509Credential untrustedCredential)
269 throws SecurityException {
270
271 if (credNameEvaluator == null) {
272 log.debug("No credential name evaluator was available, skipping trusted name evaluation");
273 return true;
274 } else {
275 return credNameEvaluator.evaluate(untrustedCredential, trustedNames);
276 }
277
278 }
279
280 }