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.io.ByteArrayInputStream;
20  import java.security.KeyException;
21  import java.security.KeyFactory;
22  import java.security.KeyPair;
23  import java.security.KeyPairGenerator;
24  import java.security.NoSuchAlgorithmException;
25  import java.security.NoSuchProviderException;
26  import java.security.PrivateKey;
27  import java.security.PublicKey;
28  import java.security.cert.CRLException;
29  import java.security.cert.CertificateException;
30  import java.security.cert.CertificateFactory;
31  import java.security.interfaces.DSAPrivateKey;
32  import java.security.interfaces.DSAPublicKey;
33  import java.security.interfaces.RSAPrivateKey;
34  import java.security.interfaces.RSAPublicKey;
35  import java.security.spec.InvalidKeySpecException;
36  import java.security.spec.KeySpec;
37  import java.security.spec.X509EncodedKeySpec;
38  import java.util.ArrayList;
39  import java.util.List;
40  
41  import javax.crypto.KeyGenerator;
42  import javax.crypto.SecretKey;
43  
44  import org.apache.xml.security.Init;
45  import org.apache.xml.security.algorithms.JCEMapper;
46  import org.opensaml.xml.security.credential.BasicCredential;
47  import org.opensaml.xml.security.credential.Credential;
48  import org.opensaml.xml.security.keyinfo.BasicProviderKeyInfoCredentialResolver;
49  import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver;
50  import org.opensaml.xml.security.keyinfo.KeyInfoProvider;
51  import org.opensaml.xml.security.keyinfo.provider.DSAKeyValueProvider;
52  import org.opensaml.xml.security.keyinfo.provider.InlineX509DataProvider;
53  import org.opensaml.xml.security.keyinfo.provider.RSAKeyValueProvider;
54  import org.opensaml.xml.util.Base64;
55  
56  /**
57   * Some utility methods for doing security, credential, key and crypto-related tests.
58   */
59  public final class SecurityTestHelper {
60      
61      /** Constructor. */
62      private SecurityTestHelper() { }
63      
64      /**
65       * Build Java certificate from base64 encoding.
66       * 
67       * @param base64Cert base64-encoded certificate
68       * @return a native Java X509 certificate
69       * @throws CertificateException thrown if there is an error constructing certificate
70       */
71      public static java.security.cert.X509Certificate buildJavaX509Cert(String base64Cert) throws CertificateException {
72          CertificateFactory  cf = CertificateFactory.getInstance("X.509");
73          ByteArrayInputStream input = new ByteArrayInputStream(Base64.decode(base64Cert));
74          return (java.security.cert.X509Certificate) cf.generateCertificate(input);
75      }
76      
77      /**
78       * Build Java CRL from base64 encoding.
79       * 
80       * @param base64CRL base64-encoded CRL
81       * @return a native Java X509 CRL
82       * @throws CertificateException thrown if there is an error constructing certificate
83       * @throws CRLException  thrown if there is an error constructing CRL
84       */
85      public static java.security.cert.X509CRL buildJavaX509CRL(String base64CRL)
86              throws CertificateException, CRLException {
87          CertificateFactory  cf = CertificateFactory.getInstance("X.509");
88          ByteArrayInputStream input = new ByteArrayInputStream(Base64.decode(base64CRL));
89          return (java.security.cert.X509CRL) cf.generateCRL(input);
90      }
91      
92      /**
93       * Build Java DSA public key from base64 encoding.
94       * 
95       * @param base64EncodedKey base64-encoded DSA public key
96       * @return a native Java DSAPublicKey
97       * @throws KeyException thrown if there is an error constructing key
98       */
99      public static DSAPublicKey buildJavaDSAPublicKey(String base64EncodedKey) throws KeyException {
100         X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decode(base64EncodedKey));
101         return (DSAPublicKey) buildKey(keySpec, "DSA");
102     }
103     
104     /**
105      * Build Java RSA public key from base64 encoding.
106      * 
107      * @param base64EncodedKey base64-encoded RSA public key
108      * @return a native Java RSAPublicKey
109      * @throws KeyException thrown if there is an error constructing key
110      */
111     public static RSAPublicKey buildJavaRSAPublicKey(String base64EncodedKey) throws KeyException {
112         X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decode(base64EncodedKey));
113         return (RSAPublicKey) buildKey(keySpec, "RSA");
114     }
115     
116     /**
117      * Build Java RSA private key from base64 encoding.
118      * 
119      * @param base64EncodedKey base64-encoded RSA private key
120      * @return a native Java RSAPrivateKey
121      * @throws KeyException thrown if there is an error constructing key
122      */
123     public static RSAPrivateKey buildJavaRSAPrivateKey(String base64EncodedKey)  throws KeyException {
124         PrivateKey key =  buildJavaPrivateKey(base64EncodedKey);
125         if (! (key instanceof RSAPrivateKey)) {
126             throw new KeyException("Generated key was not an RSAPrivateKey instance");
127         }
128         return (RSAPrivateKey) key;
129     }
130     
131     /**
132      * Build Java DSA private key from base64 encoding.
133      * 
134      * @param base64EncodedKey base64-encoded DSA private key
135      * @return a native Java DSAPrivateKey
136      * @throws KeyException thrown if there is an error constructing key
137      */
138     public static DSAPrivateKey buildJavaDSAPrivateKey(String base64EncodedKey)  throws KeyException {
139         PrivateKey key =  buildJavaPrivateKey(base64EncodedKey);
140         if (! (key instanceof DSAPrivateKey)) {
141             throw new KeyException("Generated key was not a DSAPrivateKey instance");
142         }
143         return (DSAPrivateKey) key;
144     }
145     
146     /**
147      * Build Java private key from base64 encoding. The key should have no password.
148      * 
149      * @param base64EncodedKey base64-encoded private key
150      * @return a native Java PrivateKey
151      * @throws KeyException thrown if there is an error constructing key
152      */
153     public static PrivateKey buildJavaPrivateKey(String base64EncodedKey)  throws KeyException {
154         return SecurityHelper.decodePrivateKey(Base64.decode(base64EncodedKey), null);
155     }
156     
157     /**
158      * Generates a public key from the given key spec.
159      * 
160      * @param keySpec {@link KeySpec} specification for the key
161      * @param keyAlgorithm key generation algorithm, only DSA and RSA supported
162      * 
163      * @return the generated {@link PublicKey}
164      * 
165      * @throws KeyException thrown if the key algorithm is not supported by the JCE or the key spec does not
166      *             contain valid information
167      */
168     public static PublicKey buildKey(KeySpec keySpec, String keyAlgorithm) throws KeyException {
169         try {
170             KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm);
171             return keyFactory.generatePublic(keySpec);
172         } catch (NoSuchAlgorithmException e) {
173             throw new KeyException(keyAlgorithm + "algorithm is not supported by the JCE", e);
174         } catch (InvalidKeySpecException e) {
175             throw new KeyException("Invalid key information", e);
176         }
177     }
178     
179     /**
180      * Randomly generates a Java JCE symmetric Key object from the specified XML Encryption algorithm URI.
181      * 
182      * @param algoURI  The XML Encryption algorithm URI
183      * @return a randomly-generated symmteric key
184      * @throws NoSuchProviderException  provider not found
185      * @throws NoSuchAlgorithmException algorithm not found
186      */
187     public static SecretKey generateKeyFromURI(String algoURI) 
188             throws NoSuchAlgorithmException, NoSuchProviderException {
189         String jceAlgorithmName = JCEMapper.getJCEKeyAlgorithmFromURI(algoURI);
190         int keyLength = JCEMapper.getKeyLengthFromURI(algoURI);
191         return generateKey(jceAlgorithmName, keyLength, null);
192     }
193     
194     /**
195      * Randomly generates a Java JCE KeyPair object from the specified XML Encryption algorithm URI.
196      * 
197      * @param algoURI  The XML Encryption algorithm URI
198      * @param keyLength  the length of key to generate
199      * @return a randomly-generated KeyPair
200      * @throws NoSuchProviderException  provider not found
201      * @throws NoSuchAlgorithmException  algorithm not found
202      */
203     public static KeyPair generateKeyPairFromURI(String algoURI, int keyLength) 
204             throws NoSuchAlgorithmException, NoSuchProviderException {
205         String jceAlgorithmName = JCEMapper.getJCEKeyAlgorithmFromURI(algoURI);
206         return generateKeyPair(jceAlgorithmName, keyLength, null);
207     }
208     
209     /**
210      * Generate a random symmetric key.
211      * 
212      * @param algo key algorithm
213      * @param keyLength key length
214      * @param provider JCA provider
215      * @return randomly generated symmetric key
216      * @throws NoSuchAlgorithmException algorithm not found
217      * @throws NoSuchProviderException provider not found
218      */
219     public static SecretKey generateKey(String algo, int keyLength, String provider) 
220             throws NoSuchAlgorithmException, NoSuchProviderException {
221         SecretKey key = null;
222         KeyGenerator keyGenerator = null;
223         if (provider != null) {
224             keyGenerator = KeyGenerator.getInstance(algo, provider);
225         } else {
226             keyGenerator = KeyGenerator.getInstance(algo);
227         }
228         keyGenerator.init(keyLength);
229         key = keyGenerator.generateKey();
230         return key;
231     }
232     
233     /**
234      * Generate a random asymmetric key pair.
235      * 
236      * @param algo key algorithm
237      * @param keyLength key length
238      * @param provider JCA provider
239      * @return randomly generated key
240      * @throws NoSuchAlgorithmException algorithm not found
241      * @throws NoSuchProviderException provider not found
242      */
243     public static KeyPair generateKeyPair(String algo, int keyLength, String provider) 
244             throws NoSuchAlgorithmException, NoSuchProviderException {
245         KeyPairGenerator keyGenerator = null;
246         if (provider != null) {
247             keyGenerator = KeyPairGenerator.getInstance(algo, provider);
248         } else {
249             keyGenerator = KeyPairGenerator.getInstance(algo);
250         }
251         keyGenerator.initialize(keyLength);
252         return keyGenerator.generateKeyPair();
253     }
254     
255     /**
256      * Generate a random symmetric key and return in a BasicCredential.
257      * 
258      * @param algorithmURI The XML Encryption algorithm URI
259      * @return a basic credential containing a randomly generated symmetric key
260      * @throws NoSuchAlgorithmException algorithm not found
261      * @throws NoSuchProviderException provider not found
262      */
263     public static Credential generateKeyAndCredential(String algorithmURI) 
264             throws NoSuchAlgorithmException, NoSuchProviderException {
265         SecretKey key = SecurityTestHelper.generateKeyFromURI(algorithmURI);
266         BasicCredential credential = new BasicCredential();
267         credential.setSecretKey(key);
268         return credential;
269     }
270     
271     /**
272      * Generate a random asymmetric key pair and return in a BasicCredential.
273      * 
274      * @param algorithmURI The XML Encryption algorithm URI
275      * @param keyLength key length
276      * @param includePrivate if true, the private key will be included as well
277      * @return a basic credential containing a randomly generated asymmetric key pair
278      * @throws NoSuchAlgorithmException algorithm not found
279      * @throws NoSuchProviderException provider not found
280      */
281     public static Credential generateKeyPairAndCredential(String algorithmURI, int keyLength, boolean includePrivate) 
282             throws NoSuchAlgorithmException, NoSuchProviderException {
283         KeyPair keyPair = SecurityTestHelper.generateKeyPairFromURI(algorithmURI, keyLength);
284         BasicCredential credential = new BasicCredential();
285         credential.setPublicKey(keyPair.getPublic());
286         if (includePrivate) {
287             credential.setPrivateKey(keyPair.getPrivate());
288         }
289         return credential;
290     }
291     
292     /**
293      * Get a basic KeyInfo credential resolver which can process standard inline
294      * data - RSAKeyValue, DSAKeyValue, X509Data.
295      * 
296      * @return a new KeyInfoCredentialResolver instance
297      */
298     public static KeyInfoCredentialResolver buildBasicInlineKeyInfoResolver() {
299         List<KeyInfoProvider> providers = new ArrayList<KeyInfoProvider>();
300         providers.add( new RSAKeyValueProvider() );
301         providers.add( new DSAKeyValueProvider() );
302         providers.add( new InlineX509DataProvider() );
303         return new BasicProviderKeyInfoCredentialResolver(providers);
304     }
305     
306     static {
307         // We use some Apache XML Security utility functions, so need to make sure library
308         // is initialized.
309         if (!Init.isInitialized()) {
310             Init.init();
311         }
312     }
313 }