View Javadoc

1   /*
2    * Copyright [2007] [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.signature.impl;
18  
19  import org.opensaml.xml.security.CriteriaSet;
20  import org.opensaml.xml.security.SecurityException;
21  import org.opensaml.xml.security.SecurityHelper;
22  import org.opensaml.xml.security.SigningUtil;
23  import org.opensaml.xml.security.credential.Credential;
24  import org.opensaml.xml.security.credential.CredentialResolver;
25  import org.opensaml.xml.security.credential.UsageType;
26  import org.opensaml.xml.security.criteria.KeyAlgorithmCriteria;
27  import org.opensaml.xml.security.criteria.UsageCriteria;
28  import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver;
29  import org.opensaml.xml.security.trust.ExplicitKeyTrustEvaluator;
30  import org.opensaml.xml.security.trust.TrustedCredentialTrustEngine;
31  import org.opensaml.xml.signature.Signature;
32  import org.opensaml.xml.signature.SignatureTrustEngine;
33  import org.opensaml.xml.util.DatatypeHelper;
34  import org.slf4j.Logger;
35  import org.slf4j.LoggerFactory;
36  
37  /**
38   * An implementation of {@link SignatureTrustEngine} which evaluates the validity and trustworthiness of XML and raw
39   * signatures.
40   * 
41   * <p>
42   * Processing is first performed as described in {@link BaseSignatureTrustEngine}. If based on this processing, it is
43   * determined that the Signature's KeyInfo is not present or does not contain a resolveable valid (and trusted) signing
44   * key, then all trusted credentials obtained by the trusted credential resolver will be used to attempt to validate the
45   * signature.
46   * </p>
47   */
48  public class ExplicitKeySignatureTrustEngine extends BaseSignatureTrustEngine<Iterable<Credential>> implements
49          TrustedCredentialTrustEngine<Signature> {
50  
51      /** Class logger. */
52      private final Logger log = LoggerFactory.getLogger(ExplicitKeySignatureTrustEngine.class);
53  
54      /** Resolver used for resolving trusted credentials. */
55      private CredentialResolver credentialResolver;
56  
57      /** The external explicit key trust engine to use as a basis for trust in this implementation. */
58      private ExplicitKeyTrustEvaluator keyTrust;
59  
60      /**
61       * Constructor.
62       * 
63       * @param resolver credential resolver used to resolve trusted credentials.
64       * @param keyInfoResolver KeyInfo credential resolver used to obtain the (advisory) signing credential from a
65       *            Signature's KeyInfo element.
66       */
67      public ExplicitKeySignatureTrustEngine(CredentialResolver resolver, KeyInfoCredentialResolver keyInfoResolver) {
68          super(keyInfoResolver);
69          if (resolver == null) {
70              throw new IllegalArgumentException("Credential resolver may not be null");
71          }
72          credentialResolver = resolver;
73  
74          keyTrust = new ExplicitKeyTrustEvaluator();
75      }
76  
77      /** {@inheritDoc} */
78      public CredentialResolver getCredentialResolver() {
79          return credentialResolver;
80      }
81  
82      /** {@inheritDoc} */
83      public boolean validate(Signature signature, CriteriaSet trustBasisCriteria) throws SecurityException {
84  
85          checkParams(signature, trustBasisCriteria);
86  
87          CriteriaSet criteriaSet = new CriteriaSet();
88          criteriaSet.addAll(trustBasisCriteria);
89          if (!criteriaSet.contains(UsageCriteria.class)) {
90              criteriaSet.add(new UsageCriteria(UsageType.SIGNING));
91          }
92          String jcaAlgorithm = SecurityHelper.getKeyAlgorithmFromURI(signature.getSignatureAlgorithm());
93          if (!DatatypeHelper.isEmpty(jcaAlgorithm)) {
94              criteriaSet.add(new KeyAlgorithmCriteria(jcaAlgorithm), true);
95          }
96  
97          Iterable<Credential> trustedCredentials = getCredentialResolver().resolve(criteriaSet);
98  
99          if (validate(signature, trustedCredentials)) {
100             return true;
101         }
102 
103         // If the credentials extracted from Signature's KeyInfo (if any) did not verify the
104         // signature and/or establish trust, as a fall back attempt to verify the signature with
105         // the trusted credentials directly.
106         log.debug("Attempting to verify signature using trusted credentials");
107 
108         for (Credential trustedCredential : trustedCredentials) {
109             if (verifySignature(signature, trustedCredential)) {
110                 log.debug("Successfully verified signature using resolved trusted credential");
111                 return true;
112             }
113         }
114         log.error("Failed to verify signature using either KeyInfo-derived or directly trusted credentials");
115         return false;
116     }
117 
118     /** {@inheritDoc} */
119     public boolean validate(byte[] signature, byte[] content, String algorithmURI, CriteriaSet trustBasisCriteria,
120             Credential candidateCredential) throws SecurityException {
121 
122         checkParamsRaw(signature, content, algorithmURI, trustBasisCriteria);
123 
124         CriteriaSet criteriaSet = new CriteriaSet();
125         criteriaSet.addAll(trustBasisCriteria);
126         if (!criteriaSet.contains(UsageCriteria.class)) {
127             criteriaSet.add(new UsageCriteria(UsageType.SIGNING));
128         }
129         String jcaAlgorithm = SecurityHelper.getKeyAlgorithmFromURI(algorithmURI);
130         if (!DatatypeHelper.isEmpty(jcaAlgorithm)) {
131             criteriaSet.add(new KeyAlgorithmCriteria(jcaAlgorithm), true);
132         }
133 
134         Iterable<Credential> trustedCredentials = getCredentialResolver().resolve(criteriaSet);
135 
136         // First try the optional supplied candidate credential
137         if (candidateCredential != null) {
138             if (SigningUtil.verifyWithURI(candidateCredential, algorithmURI, signature, content)) {
139                 log.debug("Successfully verified signature using supplied candidate credential");
140                 log.debug("Attempting to establish trust of supplied candidate credential");
141                 if (evaluateTrust(candidateCredential, trustedCredentials)) {
142                     log.debug("Successfully established trust of supplied candidate credential");
143                     return true;
144                 } else {
145                     log.debug("Failed to establish trust of supplied candidate credential");
146                 }
147             }
148         }
149 
150         // If the candidate verification credential did not verify the
151         // signature and/or establish trust, or if no candidate was supplied,
152         // as a fall back attempt to verify the signature with the trusted credentials directly.
153         log.debug("Attempting to verify signature using trusted credentials");
154 
155         for (Credential trustedCredential : trustedCredentials) {
156             if (SigningUtil.verifyWithURI(trustedCredential, algorithmURI, signature, content)) {
157                 log.debug("Successfully verified signature using resolved trusted credential");
158                 return true;
159             }
160         }
161         log.error("Failed to verify signature using either supplied candidate credential"
162                 + " or directly trusted credentials");
163         return false;
164     }
165 
166     /** {@inheritDoc} */
167     protected boolean evaluateTrust(Credential untrustedCredential, Iterable<Credential> trustedCredentials)
168             throws SecurityException {
169 
170         return keyTrust.validate(untrustedCredential, trustedCredentials);
171     }
172 }