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.security;
18  
19  import java.security.Key;
20  import java.security.interfaces.DSAParams;
21  import java.util.HashMap;
22  import java.util.Map;
23  
24  import org.opensaml.xml.security.credential.Credential;
25  import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver;
26  import org.opensaml.xml.security.keyinfo.NamedKeyInfoGeneratorManager;
27  import org.opensaml.xml.util.DatatypeHelper;
28  import org.slf4j.Logger;
29  import org.slf4j.LoggerFactory;
30  
31  /**
32   * Basic in-memory implementation of {@link SecurityConfiguration}.
33   */
34  public class BasicSecurityConfiguration implements SecurityConfiguration {
35      
36      /** The name of the KeyInfoCredentialResolver default config. */
37      public static final String KEYINFO_RESOLVER_DEFAULT_CONFIG = "_KEYINFO_RESOLVER_DEFAULT_";
38      
39      /** Class logger. */
40      private final Logger log = LoggerFactory.getLogger(BasicSecurityConfiguration.class);
41      
42      /** JCA algorithm to signature URI mappings. */
43      private Map<String, String> signatureAlgorithms;
44      
45      /** Signature canonicalization algorithm URI. */
46      private String signatureCanonicalization;
47      
48      /** Signature Reference digest method algorithm URI. */
49      private String signatureReferenceDigestMethod;
50      
51      /** Signature HMAC output length. */
52      private Integer signatureHMACOutputLength;
53      
54      /** JCA algorithm to data encryption URI mappings. */
55      private Map<DataEncryptionIndex, String> dataEncryptionAlgorithms;
56      
57      /** JCA algorithm to key transport encryption URI mappings. */
58      private Map<KeyTransportEncryptionIndex, String> keyTransportEncryptionAlgorithms;
59      
60      /** Encryption algorithm URI for auto-generated data encryption keys. */
61      private String autoGenEncryptionURI;
62      
63      /** Manager for named KeyInfoGenerator instances. */
64      private NamedKeyInfoGeneratorManager keyInfoGeneratorManager;
65      
66      /** Set of named KeyInfoCredentialResolvers. */
67      private Map<String, KeyInfoCredentialResolver> keyInfoCredentialResolvers;
68      
69      /** Default DSA key family parameters. */
70      private Map<Integer, DSAParams> dsaParams;
71      
72      /** Constructor. */
73      public BasicSecurityConfiguration() {
74          signatureAlgorithms = new HashMap<String, String>();
75          dataEncryptionAlgorithms = new HashMap<DataEncryptionIndex, String>();
76          keyTransportEncryptionAlgorithms = new HashMap<KeyTransportEncryptionIndex, String>();
77          keyInfoCredentialResolvers = new HashMap<String, KeyInfoCredentialResolver>();
78          dsaParams = new HashMap<Integer, DSAParams>();
79      }
80      
81      // Signature-related config
82      
83      /** {@inheritDoc} */
84      public String getSignatureAlgorithmURI(String jcaAlgorithmName) {
85          return signatureAlgorithms.get(jcaAlgorithmName);
86      }
87      
88      /** {@inheritDoc} */
89      public String getSignatureAlgorithmURI(Credential credential) {
90          Key key = SecurityHelper.extractSigningKey(credential);
91          if (key == null) {
92              log.debug("Could not extract signing key from credential, unable to map to algorithm URI");
93              return null;
94          } else if (key.getAlgorithm() == null) {
95              log.debug("Signing key algorithm value was not available, unable to map to algorithm URI");
96              return null;
97          }
98          return getSignatureAlgorithmURI(key.getAlgorithm());
99      }
100     
101     /**
102      * Register a mapping from the specified JCA algorithm name to a signature algorithm URI.
103      * 
104      * @param jcaAlgorithmName the JCA algorithm name to register
105      * @param algorithmURI the algorithm URI to register
106      */
107     public void registerSignatureAlgorithmURI(String jcaAlgorithmName, String algorithmURI) {
108         signatureAlgorithms.put(jcaAlgorithmName, algorithmURI);
109     }
110     
111     /**
112      * Deregister a mapping for the specified JCA algorithm name.
113      * 
114      * @param jcaAlgorithmName the JCA algorithm name to deregister
115      */
116     public void deregisterSignatureAlgorithmURI(String jcaAlgorithmName) {
117         signatureAlgorithms.remove(jcaAlgorithmName);
118     }
119 
120     /** {@inheritDoc} */
121     public String getSignatureCanonicalizationAlgorithm() {
122         return signatureCanonicalization;
123     }
124     
125     /**
126      * Set a canonicalization algorithm URI suitable for use as a Signature CanonicalizationMethod value.
127      * 
128      * @param algorithmURI a canonicalization algorithm URI
129      */
130     public void setSignatureCanonicalizationAlgorithm(String algorithmURI) {
131         signatureCanonicalization = algorithmURI;
132     }
133 
134     /** {@inheritDoc} */
135     public String getSignatureReferenceDigestMethod() {
136         return signatureReferenceDigestMethod;
137     }
138     
139     /**
140      * Set a digest method algorithm URI suitable for use as a Signature Reference DigestMethod value.
141      * 
142      * @param algorithmURI a digest method algorithm URI
143      */
144     public void setSignatureReferenceDigestMethod(String algorithmURI) {
145         signatureReferenceDigestMethod = algorithmURI;
146     }
147  
148     /** {@inheritDoc} */
149     public Integer getSignatureHMACOutputLength() {
150         return signatureHMACOutputLength;
151     }
152     
153     /**
154      * Set the value to be used as the Signature SignatureMethod HMACOutputLength value, used
155      * only when signing with an HMAC algorithm.  This value is optional when using HMAC.
156      * 
157      * @param length the HMAC output length value to use when performing HMAC signing (may be null)
158      */
159     public void setSignatureHMACOutputLength(Integer length) {
160         signatureHMACOutputLength = length;
161     }
162     
163     //  Encryption-related config
164     
165     /** {@inheritDoc} */
166     public String getDataEncryptionAlgorithmURI(String jcaAlgorithmName, Integer keyLength) {
167         DataEncryptionIndex index = new DataEncryptionIndex(jcaAlgorithmName, keyLength);
168         String algorithmURI = dataEncryptionAlgorithms.get(index);
169         if (algorithmURI != null) {
170             return algorithmURI;
171         }
172         if (keyLength != null) {
173             // Fall through to default, i.e. with no specific key length registered
174             log.debug("No data encryption algorithm mapping available for JCA name + key length, " 
175                     + "trying JCA name alone");
176             index = new DataEncryptionIndex(jcaAlgorithmName, null);
177             return dataEncryptionAlgorithms.get(index);
178         }
179         return null;
180     }
181     
182     /** {@inheritDoc} */
183     public String getDataEncryptionAlgorithmURI(Credential credential) {
184         Key key = SecurityHelper.extractEncryptionKey(credential);
185         if (key == null) {
186             log.debug("Could not extract data encryption key from credential, unable to map to algorithm URI");
187             return null;
188         } else if (key.getAlgorithm() == null){
189             log.debug("Data encryption key algorithm value was not available, unable to map to algorithm URI");
190             return null;
191         }
192         Integer length = SecurityHelper.getKeyLength(key);
193         return getDataEncryptionAlgorithmURI(key.getAlgorithm(), length);
194     }
195     
196     /**
197      * Register a mapping from the specified JCA algorithm name to an encryption algorithm URI.
198      * 
199      * @param jcaAlgorithmName the JCA algorithm name to register
200      * @param keyLength the key length to register (may be null)
201      * @param algorithmURI the algorithm URI to register
202      */
203     public void registerDataEncryptionAlgorithmURI(String jcaAlgorithmName, Integer keyLength, String algorithmURI) {
204         DataEncryptionIndex index = new DataEncryptionIndex(jcaAlgorithmName, keyLength);
205         dataEncryptionAlgorithms.put(index, algorithmURI);
206     }
207     
208     /**
209      * Deregister a mapping for the specified JCA algorithm name.
210      * 
211      * @param jcaAlgorithmName the JCA algorithm name to deregister
212      * @param keyLength the key length to deregister (may be null)
213      */
214     public void deregisterDataEncryptionAlgorithmURI(String jcaAlgorithmName, Integer keyLength) {
215         DataEncryptionIndex index = new DataEncryptionIndex(jcaAlgorithmName, keyLength);
216         dataEncryptionAlgorithms.remove(index);
217     }
218     
219     /** {@inheritDoc} */
220     public String getKeyTransportEncryptionAlgorithmURI(String jcaAlgorithmName, Integer keyLength,
221             String wrappedKeyAlgorithm) {
222         
223         KeyTransportEncryptionIndex index = 
224             new KeyTransportEncryptionIndex(jcaAlgorithmName, keyLength, wrappedKeyAlgorithm);
225         String algorithmURI = keyTransportEncryptionAlgorithms.get(index);
226         if (algorithmURI != null) {
227             return algorithmURI;
228         }
229         
230         if (wrappedKeyAlgorithm != null) {
231             // Fall through to case of no specific wrapped key algorithm registered
232             log.debug("No data encryption algorithm mapping available for JCA name + key length + wrapped algorithm, " 
233                     + "trying JCA name + key length");
234             index = new KeyTransportEncryptionIndex(jcaAlgorithmName, keyLength, null);
235             algorithmURI = keyTransportEncryptionAlgorithms.get(index);
236             if (algorithmURI != null) {
237                 return algorithmURI;
238             }
239         }
240         if (keyLength != null) {
241             // Fall through to case of no specific key length registered
242             log.debug("No data encryption algorithm mapping available for JCA name + key length + wrapped algorithm, " 
243                     + "trying JCA name + wrapped algorithm");
244             index = new KeyTransportEncryptionIndex(jcaAlgorithmName, null, wrappedKeyAlgorithm);
245             algorithmURI = keyTransportEncryptionAlgorithms.get(index);
246             if (algorithmURI != null) {
247                 return algorithmURI;
248             }
249         }
250         // Fall through to case of no specific key length or wrapped key algorithm registered
251         log.debug("No data encryption algorithm mapping available for JCA name + key length + wrapped algorithm, " 
252                 + "trying JCA name alone");
253         index = new KeyTransportEncryptionIndex(jcaAlgorithmName, null, null);
254         return keyTransportEncryptionAlgorithms.get(index);
255     }
256     
257     /** {@inheritDoc} */
258     public String getKeyTransportEncryptionAlgorithmURI(Credential credential, String wrappedKeyAlgorithm) {
259         Key key = SecurityHelper.extractEncryptionKey(credential);
260         if (key == null) {
261             log.debug("Could not extract key transport encryption key from credential, unable to map to algorithm URI");
262             return null;
263         } else if (key.getAlgorithm() == null){
264             log.debug("Key transport encryption key algorithm value was not available, unable to map to algorithm URI");
265             return null;
266         }
267         Integer length = SecurityHelper.getKeyLength(key);
268         return getKeyTransportEncryptionAlgorithmURI(key.getAlgorithm(), length, wrappedKeyAlgorithm);
269     }
270 
271     /**
272      * Register a mapping from the specified JCA algorithm name to an encryption algorithm URI.
273      * 
274      * @param jcaAlgorithmName the JCA algorithm name to register
275      * @param keyLength the key length to register (may be null)
276      * @param wrappedKeyAlgorithm the JCA algorithm name of the key to be encrypted (may be null)
277      * @param algorithmURI the algorithm URI to register
278      */
279     public void registerKeyTransportEncryptionAlgorithmURI(String jcaAlgorithmName, Integer keyLength,
280             String wrappedKeyAlgorithm, String algorithmURI) {
281         
282         KeyTransportEncryptionIndex index = 
283             new KeyTransportEncryptionIndex(jcaAlgorithmName, keyLength, wrappedKeyAlgorithm);
284         keyTransportEncryptionAlgorithms.put(index, algorithmURI);
285     }
286 
287     /**
288      * Deregister a mapping for the specified JCA algorithm name.
289      * 
290      * @param jcaAlgorithmName the JCA algorithm name to deregister
291      * @param keyLength the key length to deregister (may be null)
292      * @param wrappedKeyAlgorithm the JCA algorithm name of the key to be encrypted (may be null)
293      */
294     public void deregisterKeyTransportEncryptionAlgorithmURI(String jcaAlgorithmName, Integer keyLength,
295             String wrappedKeyAlgorithm) {
296         
297         KeyTransportEncryptionIndex index = 
298             new KeyTransportEncryptionIndex(jcaAlgorithmName, keyLength, wrappedKeyAlgorithm);
299         keyTransportEncryptionAlgorithms.remove(index);
300 
301     }
302     
303     /** {@inheritDoc} */
304     public String getAutoGeneratedDataEncryptionKeyAlgorithmURI() {
305         return autoGenEncryptionURI;
306     }
307     
308     /**
309      * Set the encryption algorithm URI to be used when auto-generating random data encryption keys.
310      * 
311      * @param algorithmURI the encryption algorithm URI to use
312      */
313     public void setAutoGeneratedDataEncryptionKeyAlgorithmURI(String algorithmURI) {
314         autoGenEncryptionURI = algorithmURI;
315     }
316     
317     
318     // KeyInfo-related config
319     
320     /** {@inheritDoc} */
321     public NamedKeyInfoGeneratorManager getKeyInfoGeneratorManager() {
322         return keyInfoGeneratorManager;
323     }
324     /**
325      * Set the manager for named KeyInfoGenerator instances.
326      * 
327      * @param keyInfoManager the KeyInfoGenerator manager to use
328      */
329     public void setKeyInfoGeneratorManager(NamedKeyInfoGeneratorManager keyInfoManager) {
330         keyInfoGeneratorManager = keyInfoManager;
331     }
332     
333     /** {@inheritDoc} */
334     public KeyInfoCredentialResolver getDefaultKeyInfoCredentialResolver() {
335         return keyInfoCredentialResolvers.get(KEYINFO_RESOLVER_DEFAULT_CONFIG);
336     }
337     
338     /**
339      * Set the default KeyInfoCredentialResolver config.
340      * 
341      * @param resolver the default KeyInfoCredentialResolver
342      */
343     public void setDefaultKeyInfoCredentialResolver(KeyInfoCredentialResolver resolver) {
344         keyInfoCredentialResolvers.put(KEYINFO_RESOLVER_DEFAULT_CONFIG, resolver);
345     }
346 
347     /** {@inheritDoc} */
348     public KeyInfoCredentialResolver getKeyInfoCredentialResolver(String name) {
349         return keyInfoCredentialResolvers.get(name);
350     }
351     
352     /**
353      * Register a named KeyInfoCredentialResolver configuration.
354      * 
355      * @param name the name of the configuration
356      * @param resolver the KeyInfoCredentialResolver to register
357      */
358     public void registerKeyInfoCredentialResolver(String name, KeyInfoCredentialResolver resolver) {
359         keyInfoCredentialResolvers.put(name, resolver);
360     }
361     
362     /**
363      * Deregister a named KeyInfoCredentialResolver configuration.
364      * 
365      * @param name the name of the configuration
366      */
367     public void deregisterKeyInfoCredentialResolver(String name) {
368         keyInfoCredentialResolvers.remove(name);
369     }
370  
371     // Miscellaneous config
372 
373     /** {@inheritDoc} */
374     public DSAParams getDSAParams(int keyLength) {
375         return dsaParams.get(keyLength);
376     }
377     
378     /**
379      * Set a DSA parameters instance which defines the default DSA key information to be used 
380      * within a DSA "key family".
381      * 
382      * @param keyLength the key length of the DSA parameters 
383      * @param params the default DSA parameters instance
384      */
385     public void setDSAParams(int keyLength, DSAParams params) {
386         dsaParams.put(keyLength, params);
387     }
388     
389     
390     /**
391      * Class used as an index to the data encryption algorithm URI map.
392      */
393     protected class DataEncryptionIndex {
394         
395         /** The JCA key algorithm name. */
396         private String keyAlgorithm;
397         
398         /** The key length.  Optional, may be null. */
399         private Integer keyLength;
400         
401         /**
402          * Constructor.
403          *
404          * @param jcaAlgorithmName the JCA algorithm name
405          * @param length the key length (optional, may be null)
406          */
407         protected DataEncryptionIndex(String jcaAlgorithmName, Integer length) {
408             if (DatatypeHelper.isEmpty(jcaAlgorithmName)) {
409                 throw new IllegalArgumentException("JCA Algorithm name may not be null or empty");
410             }
411             keyAlgorithm = DatatypeHelper.safeTrimOrNullString(jcaAlgorithmName);
412             keyLength = length;
413         }
414         
415         /** {@inheritDoc} */
416         public boolean equals(Object obj) {
417             if(obj == this){
418                 return true;
419             }
420             
421             if (! (obj instanceof DataEncryptionIndex)) {
422                 return false;
423             }
424             DataEncryptionIndex other = (DataEncryptionIndex) obj;
425             
426             if (! this.keyAlgorithm.equals(other.keyAlgorithm)) {
427                 return false;
428             }
429             if (this.keyLength == null) {
430                 return other.keyLength == null;
431             } else {
432                 return this.keyLength.equals(other.keyLength);
433             }
434             
435         }
436 
437         /** {@inheritDoc} */
438         public int hashCode() {
439             int result = 17;
440             result = 37*result + keyAlgorithm.hashCode();
441             if (keyLength != null) {
442                 result = 37*result + keyLength.hashCode();
443             }
444             return result;
445         }
446 
447         /** {@inheritDoc} */
448         public String toString() {
449             return String.format("[%s,%s]", keyAlgorithm, keyLength);
450         }
451 
452     }
453     
454     /**
455      * Class used as an index to the key transport encryption algorithm URI map.
456      */
457     protected class KeyTransportEncryptionIndex {
458         
459         /** The JCA key algorithm name. */
460         private String keyAlgorithm;
461         
462         /** The key length.  Optional, may be null. */
463         private Integer keyLength;
464         
465         /** The JCA key algorithm name of the key to be encrypted. */
466         private String wrappedAlgorithm;
467         
468         /**
469          * Constructor.
470          *
471          * @param jcaAlgorithmName the JCA algorithm name
472          * @param length the key length (optional, may be null)
473          * @param wrappedKeyAlgorithm the JCA algorithm name of the key to be encrypted (optional, may be null)
474          */
475         protected KeyTransportEncryptionIndex(String jcaAlgorithmName, Integer length, String wrappedKeyAlgorithm) {
476             if (DatatypeHelper.isEmpty(jcaAlgorithmName)) {
477                 throw new IllegalArgumentException("JCA Algorithm name may not be null or empty");
478             }
479             keyAlgorithm = DatatypeHelper.safeTrimOrNullString(jcaAlgorithmName);
480             keyLength = length;
481             wrappedAlgorithm = DatatypeHelper.safeTrimOrNullString(wrappedKeyAlgorithm);
482         }
483         
484         /** {@inheritDoc} */
485         public boolean equals(Object obj) {
486             if(obj == this){
487                 return true;
488             }
489             
490             if (! (obj instanceof KeyTransportEncryptionIndex)) {
491                 return false;
492             }
493             KeyTransportEncryptionIndex other = (KeyTransportEncryptionIndex) obj;
494             
495             if (! this.keyAlgorithm.equals(other.keyAlgorithm)) {
496                 return false;
497             }
498             if (this.keyLength == null) {
499                 if (other.keyLength != null) {
500                     return false;
501                 }
502             } else {
503                 if (! this.keyLength.equals(other.keyLength)) {
504                     return false;
505                 }
506             }
507             if (this.wrappedAlgorithm == null) {
508                 return other.wrappedAlgorithm == null;
509             } else {
510                 return this.wrappedAlgorithm.equals(other.wrappedAlgorithm);
511             }
512         }
513 
514         /** {@inheritDoc} */
515         public int hashCode() {
516             int result = 17;
517             result = 37*result + keyAlgorithm.hashCode();
518             if (keyLength != null) {
519                 result = 37*result + keyLength.hashCode();
520             }
521             if (wrappedAlgorithm != null) {
522                 result = 37*result + wrappedAlgorithm.hashCode();
523             }
524             return result;
525         }
526 
527         /** {@inheritDoc} */
528         public String toString() {
529             return String.format("[%s,%s,%s]", keyAlgorithm, keyLength, wrappedAlgorithm);
530         }
531 
532     }
533 }