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.credential.Credential;
22  import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver;
23  import org.opensaml.xml.security.keyinfo.KeyInfoCriteria;
24  import org.opensaml.xml.signature.Signature;
25  import org.opensaml.xml.signature.SignatureTrustEngine;
26  import org.opensaml.xml.signature.SignatureValidator;
27  import org.opensaml.xml.util.DatatypeHelper;
28  import org.opensaml.xml.validation.ValidationException;
29  import org.slf4j.Logger;
30  import org.slf4j.LoggerFactory;
31  
32  /**
33   * A base implementation of {@link SignatureTrustEngine} which evaluates the validity and trustworthiness of XML and raw
34   * signatures.
35   * 
36   * <p>
37   * When processing XML signatures, the supplied KeyInfoCredentialResolver will be used to resolve credential(s)
38   * containing the (advisory) signing key from the KeyInfo element of the Signature, if present. If any of these
39   * credentials do contain the valid signing key, they will be evaluated for trustworthiness against trusted information,
40   * which will be resolved in an implementation-specific manner.
41   * 
42   * <p>
43   * Subclasses are required to implement {@link #evaluateTrust(Credential, Object)} using an implementation-specific
44   * trust model.
45   * </p>
46   * 
47   * @param <TrustBasisType> the type of trusted information which has been resolved and which will serve as the basis for
48   *            trust evaluation
49   * 
50   */
51  public abstract class BaseSignatureTrustEngine<TrustBasisType> implements SignatureTrustEngine {
52  
53      /** Class logger. */
54      private final Logger log = LoggerFactory.getLogger(BaseSignatureTrustEngine.class);
55  
56      /** KeyInfo credential resolver used to obtain the signing credential from a Signature's KeyInfo. */
57      private KeyInfoCredentialResolver keyInfoCredentialResolver;
58  
59      /**
60       * Constructor.
61       * 
62       * @param keyInfoResolver KeyInfo credential resolver used to obtain the (advisory) signing credential from a
63       *            Signature's KeyInfo element.
64       */
65      public BaseSignatureTrustEngine(KeyInfoCredentialResolver keyInfoResolver) {
66          if (keyInfoResolver == null) {
67              throw new IllegalArgumentException("KeyInfo credential resolver may not be null");
68          }
69  
70          keyInfoCredentialResolver = keyInfoResolver;
71      }
72  
73      /** {@inheritDoc} */
74      public KeyInfoCredentialResolver getKeyInfoResolver() {
75          return keyInfoCredentialResolver;
76      }
77  
78      /**
79       * Attempt to establish trust by resolving signature verification credentials from the Signature's KeyInfo. If any
80       * credentials so resolved correctly verify the signature, attempt to establish trust using subclass-specific trust
81       * logic against trusted information as implemented in {@link #evaluateTrust(Credential, Object)}.
82       * 
83       * @param signature the Signature to evaluate
84       * @param trustBasis the information which serves as the basis for trust evaluation
85       * @return true if the signature is verified by any KeyInfo-derived credential which can be established as trusted,
86       *         otherwise false
87       * @throws SecurityException if an error occurs during signature verification or trust processing
88       */
89      protected boolean validate(Signature signature, TrustBasisType trustBasis) throws SecurityException {
90  
91          log.debug("Attempting to verify signature and establish trust using KeyInfo-derived credentials");
92  
93          if (signature.getKeyInfo() != null) {
94  
95              KeyInfoCriteria keyInfoCriteria = new KeyInfoCriteria(signature.getKeyInfo());
96              CriteriaSet keyInfoCriteriaSet = new CriteriaSet(keyInfoCriteria);
97  
98              for (Credential kiCred : getKeyInfoResolver().resolve(keyInfoCriteriaSet)) {
99                  if (verifySignature(signature, kiCred)) {
100                     log.debug("Successfully verified signature using KeyInfo-derived credential");
101                     log.debug("Attempting to establish trust of KeyInfo-derived credential");
102                     if (evaluateTrust(kiCred, trustBasis)) {
103                         log.debug("Successfully established trust of KeyInfo-derived credential");
104                         return true;
105                     } else {
106                         log.debug("Failed to establish trust of KeyInfo-derived credential");
107                     }
108                 }
109             }
110         } else {
111             log.info("Signature contained no KeyInfo element, could not resolve verification credentials");
112         }
113 
114         log.debug("Failed to verify signature and/or establish trust using any KeyInfo-derived credentials");
115         return false;
116     }
117 
118     /**
119      * Evaluate the untrusted KeyInfo-derived credential with respect to the specified trusted information.
120      * 
121      * @param untrustedCredential the untrusted credential being evaluated
122      * @param trustBasis the information which serves as the basis for trust evaluation
123      * 
124      * @return true if the trust can be established for the untrusted credential, otherwise false
125      * 
126      * @throws SecurityException if an error occurs during trust processing
127      */
128     protected abstract boolean evaluateTrust(Credential untrustedCredential, TrustBasisType trustBasis)
129             throws SecurityException;
130 
131     /**
132      * Attempt to verify a signature using the key from the supplied credential.
133      * 
134      * @param signature the signature on which to attempt verification
135      * @param credential the credential containing the candidate validation key
136      * @return true if the signature can be verified using the key from the credential, otherwise false
137      */
138     protected boolean verifySignature(Signature signature, Credential credential) {
139         SignatureValidator validator = new SignatureValidator(credential);
140         try {
141             validator.validate(signature);
142         } catch (ValidationException e) {
143             log.debug("Signature validation using candidate validation credential failed", e);
144             return false;
145         }
146         
147         log.debug("Signature validation using candidate credential was successful");
148         return true;
149     }
150 
151     /**
152      * Check the signature and credential criteria for required values.
153      * 
154      * @param signature the signature to be evaluated
155      * @param trustBasisCriteria the set of trusted credential criteria
156      * @throws SecurityException thrown if required values are absent or otherwise invalid
157      */
158     protected void checkParams(Signature signature, CriteriaSet trustBasisCriteria) throws SecurityException {
159 
160         if (signature == null) {
161             throw new SecurityException("Signature was null");
162         }
163         if (trustBasisCriteria == null) {
164             throw new SecurityException("Trust basis criteria set was null");
165         }
166         if (trustBasisCriteria.isEmpty()) {
167             throw new SecurityException("Trust basis criteria set was empty");
168         }
169     }
170 
171     /**
172      * Check the signature and credential criteria for required values.
173      * 
174      * @param signature the signature to be evaluated
175      * @param content the data over which the signature was computed
176      * @param algorithmURI the signing algorithm URI which was used
177      * @param trustBasisCriteria the set of trusted credential criteria
178      * @throws SecurityException thrown if required values are absent or otherwise invalid
179      */
180     protected void checkParamsRaw(byte[] signature, byte[] content, String algorithmURI, CriteriaSet trustBasisCriteria)
181             throws SecurityException {
182 
183         if (signature == null || signature.length == 0) {
184             throw new SecurityException("Signature byte array was null or empty");
185         }
186         if (content == null || content.length == 0) {
187             throw new SecurityException("Content byte array was null or empty");
188         }
189         if (DatatypeHelper.isEmpty(algorithmURI)) {
190             throw new SecurityException("Signature algorithm was null or empty");
191         }
192         if (trustBasisCriteria == null) {
193             throw new SecurityException("Trust basis criteria set was null");
194         }
195         if (trustBasisCriteria.isEmpty()) {
196             throw new SecurityException("Trust basis criteria set was empty");
197         }
198     }
199 
200 }