1 /*
2  * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.security.provider;
27 
28 import java.security.Key;
29 import java.security.PublicKey;
30 import java.security.PrivateKey;
31 import java.security.KeyFactorySpi;
32 import java.security.InvalidKeyException;
33 import java.security.interfaces.DSAParams;
34 import java.security.spec.DSAPublicKeySpec;
35 import java.security.spec.DSAPrivateKeySpec;
36 import java.security.spec.KeySpec;
37 import java.security.spec.InvalidKeySpecException;
38 import java.security.spec.X509EncodedKeySpec;
39 import java.security.spec.PKCS8EncodedKeySpec;
40 
41 /**
42  * This class implements the DSA key factory of the Sun provider.
43  *
44  * @author Jan Luehe
45  *
46  *
47  * @since 1.2
48  */
49 
50 public class DSAKeyFactory extends KeyFactorySpi {
51     /**
52      * Generates a public key object from the provided key specification
53      * (key material).
54      *
55      * @param keySpec the specification (key material) of the public key
56      *
57      * @return the public key
58      *
59      * @exception InvalidKeySpecException if the given key specification
60      * is inappropriate for this key factory to produce a public key.
61      */
engineGeneratePublic(KeySpec keySpec)62     protected PublicKey engineGeneratePublic(KeySpec keySpec)
63     throws InvalidKeySpecException {
64         try {
65             if (keySpec instanceof DSAPublicKeySpec) {
66                 DSAPublicKeySpec dsaPubKeySpec = (DSAPublicKeySpec)keySpec;
67                 return new DSAPublicKeyImpl(dsaPubKeySpec.getY(),
68                                     dsaPubKeySpec.getP(),
69                                     dsaPubKeySpec.getQ(),
70                                     dsaPubKeySpec.getG());
71             } else if (keySpec instanceof X509EncodedKeySpec) {
72                 return new DSAPublicKeyImpl
73                     (((X509EncodedKeySpec)keySpec).getEncoded());
74             } else {
75                 throw new InvalidKeySpecException
76                     ("Inappropriate key specification");
77             }
78         } catch (InvalidKeyException e) {
79             throw new InvalidKeySpecException
80                 ("Inappropriate key specification: " + e.getMessage());
81         }
82     }
83 
84     /**
85      * Generates a private key object from the provided key specification
86      * (key material).
87      *
88      * @param keySpec the specification (key material) of the private key
89      *
90      * @return the private key
91      *
92      * @exception InvalidKeySpecException if the given key specification
93      * is inappropriate for this key factory to produce a private key.
94      */
engineGeneratePrivate(KeySpec keySpec)95     protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
96     throws InvalidKeySpecException {
97         try {
98             if (keySpec instanceof DSAPrivateKeySpec) {
99                 DSAPrivateKeySpec dsaPrivKeySpec = (DSAPrivateKeySpec)keySpec;
100                 return new DSAPrivateKey(dsaPrivKeySpec.getX(),
101                                          dsaPrivKeySpec.getP(),
102                                          dsaPrivKeySpec.getQ(),
103                                          dsaPrivKeySpec.getG());
104 
105             } else if (keySpec instanceof PKCS8EncodedKeySpec) {
106                 return new DSAPrivateKey
107                     (((PKCS8EncodedKeySpec)keySpec).getEncoded());
108 
109             } else {
110                 throw new InvalidKeySpecException
111                     ("Inappropriate key specification");
112             }
113         } catch (InvalidKeyException e) {
114             throw new InvalidKeySpecException
115                 ("Inappropriate key specification: " + e.getMessage());
116         }
117     }
118 
119     /**
120      * Returns a specification (key material) of the given key object
121      * in the requested format.
122      *
123      * @param key the key
124      *
125      * @param keySpec the requested format in which the key material shall be
126      * returned
127      *
128      * @return the underlying key specification (key material) in the
129      * requested format
130      *
131      * @exception InvalidKeySpecException if the requested key specification is
132      * inappropriate for the given key, or the given key cannot be processed
133      * (e.g., the given key has an unrecognized algorithm or format).
134      */
135     protected <T extends KeySpec>
engineGetKeySpec(Key key, Class<T> keySpec)136         T engineGetKeySpec(Key key, Class<T> keySpec)
137     throws InvalidKeySpecException {
138 
139         DSAParams params;
140 
141         try {
142 
143             if (key instanceof java.security.interfaces.DSAPublicKey) {
144 
145                 // Determine valid key specs
146                 Class<?> dsaPubKeySpec = Class.forName
147                     ("java.security.spec.DSAPublicKeySpec");
148                 Class<?> x509KeySpec = Class.forName
149                     ("java.security.spec.X509EncodedKeySpec");
150 
151                 if (dsaPubKeySpec.isAssignableFrom(keySpec)) {
152                     java.security.interfaces.DSAPublicKey dsaPubKey
153                         = (java.security.interfaces.DSAPublicKey)key;
154                     params = dsaPubKey.getParams();
155                     return keySpec.cast(new DSAPublicKeySpec(dsaPubKey.getY(),
156                                                              params.getP(),
157                                                              params.getQ(),
158                                                              params.getG()));
159 
160                 } else if (x509KeySpec.isAssignableFrom(keySpec)) {
161                     return keySpec.cast(new X509EncodedKeySpec(key.getEncoded()));
162 
163                 } else {
164                     throw new InvalidKeySpecException
165                         ("Inappropriate key specification");
166                 }
167 
168             } else if (key instanceof java.security.interfaces.DSAPrivateKey) {
169 
170                 // Determine valid key specs
171                 Class<?> dsaPrivKeySpec = Class.forName
172                     ("java.security.spec.DSAPrivateKeySpec");
173                 Class<?> pkcs8KeySpec = Class.forName
174                     ("java.security.spec.PKCS8EncodedKeySpec");
175 
176                 if (dsaPrivKeySpec.isAssignableFrom(keySpec)) {
177                     java.security.interfaces.DSAPrivateKey dsaPrivKey
178                         = (java.security.interfaces.DSAPrivateKey)key;
179                     params = dsaPrivKey.getParams();
180                     return keySpec.cast(new DSAPrivateKeySpec(dsaPrivKey.getX(),
181                                                               params.getP(),
182                                                               params.getQ(),
183                                                               params.getG()));
184 
185                 } else if (pkcs8KeySpec.isAssignableFrom(keySpec)) {
186                     return keySpec.cast(new PKCS8EncodedKeySpec(key.getEncoded()));
187 
188                 } else {
189                     throw new InvalidKeySpecException
190                         ("Inappropriate key specification");
191                 }
192 
193             } else {
194                 throw new InvalidKeySpecException("Inappropriate key type");
195             }
196 
197         } catch (ClassNotFoundException e) {
198             throw new InvalidKeySpecException
199                 ("Unsupported key specification: " + e.getMessage());
200         }
201     }
202 
203     /**
204      * Translates a key object, whose provider may be unknown or potentially
205      * untrusted, into a corresponding key object of this key factory.
206      *
207      * @param key the key whose provider is unknown or untrusted
208      *
209      * @return the translated key
210      *
211      * @exception InvalidKeyException if the given key cannot be processed by
212      * this key factory.
213      */
engineTranslateKey(Key key)214     protected Key engineTranslateKey(Key key) throws InvalidKeyException {
215 
216         try {
217 
218             if (key instanceof java.security.interfaces.DSAPublicKey) {
219                 // Check if key originates from this factory
220                 if (key instanceof sun.security.provider.DSAPublicKey) {
221                     return key;
222                 }
223                 // Convert key to spec
224                 DSAPublicKeySpec dsaPubKeySpec
225                     = engineGetKeySpec(key, DSAPublicKeySpec.class);
226                 // Create key from spec, and return it
227                 return engineGeneratePublic(dsaPubKeySpec);
228 
229             } else if (key instanceof java.security.interfaces.DSAPrivateKey) {
230                 // Check if key originates from this factory
231                 if (key instanceof sun.security.provider.DSAPrivateKey) {
232                     return key;
233                 }
234                 // Convert key to spec
235                 DSAPrivateKeySpec dsaPrivKeySpec
236                     = engineGetKeySpec(key, DSAPrivateKeySpec.class);
237                 // Create key from spec, and return it
238                 return engineGeneratePrivate(dsaPrivKeySpec);
239 
240             } else {
241                 throw new InvalidKeyException("Wrong algorithm type");
242             }
243 
244         } catch (InvalidKeySpecException e) {
245             throw new InvalidKeyException("Cannot translate key: "
246                                           + e.getMessage());
247         }
248     }
249 }
250