1 /*
2 * Copyright [2006] [University Corporation for Advanced Internet Development, Inc.]
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.opensaml.xml.security.x509;
18
19 import java.util.Set;
20
21 import org.opensaml.xml.security.CriteriaSet;
22 import org.opensaml.xml.security.SecurityException;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26 /**
27 * Trust engine implementation which evaluates an X509Credential token based on PKIX validation processing using
28 * validation information from a trusted source.
29 *
30 */
31 public class PKIXX509CredentialTrustEngine implements PKIXTrustEngine<X509Credential> {
32
33 /** Class logger. */
34 private final Logger log = LoggerFactory.getLogger(PKIXX509CredentialTrustEngine.class);
35
36 /** Resolver used for resolving trusted credentials. */
37 private PKIXValidationInformationResolver pkixResolver;
38
39 /** The external PKIX trust evaluator used to establish trust. */
40 private PKIXTrustEvaluator pkixTrustEvaluator;
41
42 /** The external credential name evaluator used to establish trusted name compliance. */
43 private X509CredentialNameEvaluator credNameEvaluator;
44
45 /**
46 * Constructor.
47 *
48 * <p>The PKIX trust evaluator used defaults to {@link CertPathPKIXTrustEvaluator}.</p>
49 *
50 * <p>The X.509 credential name evaluator used defaults to {@link BasicX509CredentialNameEvaluator}.</p>
51 *
52 * @param resolver credential resolver used to resolve trusted credentials
53 */
54 public PKIXX509CredentialTrustEngine(PKIXValidationInformationResolver resolver) {
55 if (resolver == null) {
56 throw new IllegalArgumentException("PKIX trust information resolver may not be null");
57 }
58 pkixResolver = resolver;
59
60 pkixTrustEvaluator = new CertPathPKIXTrustEvaluator();
61 credNameEvaluator = new BasicX509CredentialNameEvaluator();
62 }
63
64 /**
65 * Constructor.
66 *
67 * @param resolver credential resolver used to resolve trusted credentials
68 * @param pkixEvaluator the PKIX trust evaluator to use
69 * @param nameEvaluator the X.509 credential name evaluator to use (may be null)
70 */
71 public PKIXX509CredentialTrustEngine(PKIXValidationInformationResolver resolver, PKIXTrustEvaluator pkixEvaluator,
72 X509CredentialNameEvaluator nameEvaluator) {
73 if (resolver == null) {
74 throw new IllegalArgumentException("PKIX trust information resolver may not be null");
75 }
76 pkixResolver = resolver;
77
78 if (pkixEvaluator == null) {
79 throw new IllegalArgumentException("PKIX trust evaluator may not be null");
80 }
81 pkixTrustEvaluator = pkixEvaluator;
82 credNameEvaluator = nameEvaluator;
83 }
84
85 /** {@inheritDoc} */
86 public PKIXValidationInformationResolver getPKIXResolver() {
87 return pkixResolver;
88 }
89
90 /**
91 * Get the PKIXTrustEvaluator instance used to evalute trust.
92 *
93 * <p>The parameters of this evaluator may be modified to
94 * adjust trust evaluation processing.</p>
95 *
96 * @return the PKIX trust evaluator instance that will be used
97 */
98 public PKIXTrustEvaluator getPKIXTrustEvaluator() {
99 return pkixTrustEvaluator;
100 }
101
102 /**
103 * Get the X509CredentialNameEvaluator instance used to evalute a credential
104 * against trusted names.
105 *
106 * <p>The parameters of this evaluator may be modified to
107 * adjust trust evaluation processing.</p>
108 *
109 * @return the PKIX trust evaluator instance that will be used
110 */
111 public X509CredentialNameEvaluator getX509CredentialNameEvaluator() {
112 return credNameEvaluator;
113 }
114
115 /** {@inheritDoc} */
116 public boolean validate(X509Credential untrustedCredential, CriteriaSet trustBasisCriteria)
117 throws SecurityException {
118
119 log.debug("Attempting PKIX validation of untrusted credential");
120
121 if (untrustedCredential == null) {
122 log.error("X.509 credential was null, unable to perform validation");
123 return false;
124 }
125
126 if (untrustedCredential.getEntityCertificate() == null) {
127 log.error("Untrusted X.509 credential's entity certificate was null, unable to perform validation");
128 return false;
129 }
130
131 Set<String> trustedNames = null;
132 if (pkixResolver.supportsTrustedNameResolution()) {
133 trustedNames = pkixResolver.resolveTrustedNames(trustBasisCriteria);
134 } else {
135 log.debug("PKIX resolver does not support resolution of trusted names, skipping name checking");
136 }
137
138 return validate(untrustedCredential, trustedNames, pkixResolver.resolve(trustBasisCriteria));
139 }
140
141 /**
142 * Perform PKIX validation on the untrusted credential, using PKIX validation information based on the supplied set
143 * of trusted credentials.
144 *
145 * @param untrustedX509Credential the credential to evaluate
146 * @param validationInfoSet the set of validation information which serves as ths basis for trust evaluation
147 * @param trustedNames the set of trusted names for name checking purposes
148 *
149 * @return true if PKIX validation of the untrusted credential is successful, otherwise false
150 * @throws SecurityException thrown if there is an error validating the untrusted credential
151 * against trusted names or validation information
152 */
153 protected boolean validate(X509Credential untrustedX509Credential, Set<String> trustedNames,
154 Iterable<PKIXValidationInformation> validationInfoSet) throws SecurityException {
155
156 log.debug("Beginning PKIX validation using trusted validation information");
157
158 if (!checkNames(trustedNames, untrustedX509Credential)) {
159 log.debug("Evaluation of credential against trusted names failed. Aborting PKIX validation");
160 return false;
161 }
162
163 for (PKIXValidationInformation validationInfo : validationInfoSet) {
164 try {
165 if (pkixTrustEvaluator.validate(validationInfo, untrustedX509Credential)) {
166 log.debug("Credential trust established via PKIX validation");
167 return true;
168 }
169 } catch (SecurityException e) {
170 // log the operational error, but allow other validation info sets to be tried
171 log.debug("Error performing PKIX validation on untrusted credential", e);
172 }
173 }
174 log.debug("Trust of untrusted credential could not be established via PKIX validation");
175 return false;
176 }
177
178 /**
179 * Evaluate the credential against the set of trusted names.
180 *
181 * <p>Evaluates to true if no intsance of {@link X509CredentialNameEvaluator} is configured.</p>
182 *
183 * @param trustedNames set of trusted names
184 * @param untrustedCredential the credential being evaluated
185 * @return true if evaluation is successful, false otherwise
186 * @throws SecurityException thrown if there is an error evaluation the credential
187 */
188 protected boolean checkNames(Set<String> trustedNames, X509Credential untrustedCredential)
189 throws SecurityException {
190
191 if (credNameEvaluator == null) {
192 log.debug("No credential name evaluator was available, skipping trusted name evaluation");
193 return true;
194 } else {
195 return credNameEvaluator.evaluate(untrustedCredential, trustedNames);
196 }
197
198 }
199
200 }