1 /* 2 * Copyright (c) 1997, 2011, 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.AccessController; 34 import java.security.interfaces.DSAParams; 35 import java.security.spec.DSAPublicKeySpec; 36 import java.security.spec.DSAPrivateKeySpec; 37 import java.security.spec.KeySpec; 38 import java.security.spec.InvalidKeySpecException; 39 import java.security.spec.X509EncodedKeySpec; 40 import java.security.spec.PKCS8EncodedKeySpec; 41 42 import sun.security.action.GetPropertyAction; 43 44 /** 45 * This class implements the DSA key factory of the Sun provider. 46 * 47 * @author Jan Luehe 48 * 49 * 50 * @since 1.2 51 */ 52 53 public class DSAKeyFactory extends KeyFactorySpi { 54 55 // package private for DSAKeyPairGenerator 56 static final boolean SERIAL_INTEROP; 57 private static final String SERIAL_PROP = "sun.security.key.serial.interop"; 58 59 static { 60 61 /** 62 * Check to see if we need to maintain interoperability for serialized 63 * keys between JDK 5.0 -> JDK 1.4. In other words, determine whether 64 * a key object serialized in JDK 5.0 must be deserializable in 65 * JDK 1.4. 66 * 67 * If true, then we generate sun.security.provider.DSAPublicKey. 68 * If false, then we generate sun.security.provider.DSAPublicKeyImpl. 69 * 70 * By default this is false. 71 * This incompatibility was introduced by 4532506. 72 */ 73 String prop = AccessController.doPrivileged 74 (new GetPropertyAction(SERIAL_PROP, null)); 75 SERIAL_INTEROP = "true".equalsIgnoreCase(prop); 76 } 77 78 /** 79 * Generates a public key object from the provided key specification 80 * (key material). 81 * 82 * @param keySpec the specification (key material) of the public key 83 * 84 * @return the public key 85 * 86 * @exception InvalidKeySpecException if the given key specification 87 * is inappropriate for this key factory to produce a public key. 88 */ 89 protected PublicKey engineGeneratePublic(KeySpec keySpec) 90 throws InvalidKeySpecException { 91 try { 92 if (keySpec instanceof DSAPublicKeySpec) { 93 DSAPublicKeySpec dsaPubKeySpec = (DSAPublicKeySpec)keySpec; 94 if (SERIAL_INTEROP) { 95 return new DSAPublicKey(dsaPubKeySpec.getY(), 96 dsaPubKeySpec.getP(), 97 dsaPubKeySpec.getQ(), 98 dsaPubKeySpec.getG()); 99 } else { 100 return new DSAPublicKeyImpl(dsaPubKeySpec.getY(), 101 dsaPubKeySpec.getP(), 102 dsaPubKeySpec.getQ(), 103 dsaPubKeySpec.getG()); 104 } 105 } else if (keySpec instanceof X509EncodedKeySpec) { 106 if (SERIAL_INTEROP) { 107 return new DSAPublicKey 108 (((X509EncodedKeySpec)keySpec).getEncoded()); 109 } else { 110 return new DSAPublicKeyImpl 111 (((X509EncodedKeySpec)keySpec).getEncoded()); 112 } 113 } else { 114 throw new InvalidKeySpecException 115 ("Inappropriate key specification"); 116 } 117 } catch (InvalidKeyException e) { 118 throw new InvalidKeySpecException 119 ("Inappropriate key specification: " + e.getMessage()); 120 } 121 } 122 123 /** 124 * Generates a private key object from the provided key specification 125 * (key material). 126 * 127 * @param keySpec the specification (key material) of the private key 128 * 129 * @return the private key 130 * 131 * @exception InvalidKeySpecException if the given key specification 132 * is inappropriate for this key factory to produce a private key. 133 */ 134 protected PrivateKey engineGeneratePrivate(KeySpec keySpec) 135 throws InvalidKeySpecException { 136 try { 137 if (keySpec instanceof DSAPrivateKeySpec) { 138 DSAPrivateKeySpec dsaPrivKeySpec = (DSAPrivateKeySpec)keySpec; 139 return new DSAPrivateKey(dsaPrivKeySpec.getX(), 140 dsaPrivKeySpec.getP(), 141 dsaPrivKeySpec.getQ(), 142 dsaPrivKeySpec.getG()); 143 144 } else if (keySpec instanceof PKCS8EncodedKeySpec) { 145 return new DSAPrivateKey 146 (((PKCS8EncodedKeySpec)keySpec).getEncoded()); 147 148 } else { 149 throw new InvalidKeySpecException 150 ("Inappropriate key specification"); 151 } 152 } catch (InvalidKeyException e) { 153 throw new InvalidKeySpecException 154 ("Inappropriate key specification: " + e.getMessage()); 155 } 156 } 157 158 /** 159 * Returns a specification (key material) of the given key object 160 * in the requested format. 161 * 162 * @param key the key 163 * 164 * @param keySpec the requested format in which the key material shall be 165 * returned 166 * 167 * @return the underlying key specification (key material) in the 168 * requested format 169 * 170 * @exception InvalidKeySpecException if the requested key specification is 171 * inappropriate for the given key, or the given key cannot be processed 172 * (e.g., the given key has an unrecognized algorithm or format). 173 */ 174 protected <T extends KeySpec> 175 T engineGetKeySpec(Key key, Class<T> keySpec) 176 throws InvalidKeySpecException { 177 178 DSAParams params; 179 180 try { 181 182 if (key instanceof java.security.interfaces.DSAPublicKey) { 183 184 // Determine valid key specs 185 Class<?> dsaPubKeySpec = Class.forName 186 ("java.security.spec.DSAPublicKeySpec"); 187 Class<?> x509KeySpec = Class.forName 188 ("java.security.spec.X509EncodedKeySpec"); 189 190 if (dsaPubKeySpec.isAssignableFrom(keySpec)) { 191 java.security.interfaces.DSAPublicKey dsaPubKey 192 = (java.security.interfaces.DSAPublicKey)key; 193 params = dsaPubKey.getParams(); 194 return keySpec.cast(new DSAPublicKeySpec(dsaPubKey.getY(), 195 params.getP(), 196 params.getQ(), 197 params.getG())); 198 199 } else if (x509KeySpec.isAssignableFrom(keySpec)) { 200 return keySpec.cast(new X509EncodedKeySpec(key.getEncoded())); 201 202 } else { 203 throw new InvalidKeySpecException 204 ("Inappropriate key specification"); 205 } 206 207 } else if (key instanceof java.security.interfaces.DSAPrivateKey) { 208 209 // Determine valid key specs 210 Class<?> dsaPrivKeySpec = Class.forName 211 ("java.security.spec.DSAPrivateKeySpec"); 212 Class<?> pkcs8KeySpec = Class.forName 213 ("java.security.spec.PKCS8EncodedKeySpec"); 214 215 if (dsaPrivKeySpec.isAssignableFrom(keySpec)) { 216 java.security.interfaces.DSAPrivateKey dsaPrivKey 217 = (java.security.interfaces.DSAPrivateKey)key; 218 params = dsaPrivKey.getParams(); 219 return keySpec.cast(new DSAPrivateKeySpec(dsaPrivKey.getX(), 220 params.getP(), 221 params.getQ(), 222 params.getG())); 223 224 } else if (pkcs8KeySpec.isAssignableFrom(keySpec)) { 225 return keySpec.cast(new PKCS8EncodedKeySpec(key.getEncoded())); 226 227 } else { 228 throw new InvalidKeySpecException 229 ("Inappropriate key specification"); 230 } 231 232 } else { 233 throw new InvalidKeySpecException("Inappropriate key type"); 234 } 235 236 } catch (ClassNotFoundException e) { 237 throw new InvalidKeySpecException 238 ("Unsupported key specification: " + e.getMessage()); 239 } 240 } 241 242 /** 243 * Translates a key object, whose provider may be unknown or potentially 244 * untrusted, into a corresponding key object of this key factory. 245 * 246 * @param key the key whose provider is unknown or untrusted 247 * 248 * @return the translated key 249 * 250 * @exception InvalidKeyException if the given key cannot be processed by 251 * this key factory. 252 */ 253 protected Key engineTranslateKey(Key key) throws InvalidKeyException { 254 255 try { 256 257 if (key instanceof java.security.interfaces.DSAPublicKey) { 258 // Check if key originates from this factory 259 if (key instanceof sun.security.provider.DSAPublicKey) { 260 return key; 261 } 262 // Convert key to spec 263 DSAPublicKeySpec dsaPubKeySpec 264 = engineGetKeySpec(key, DSAPublicKeySpec.class); 265 // Create key from spec, and return it 266 return engineGeneratePublic(dsaPubKeySpec); 267 268 } else if (key instanceof java.security.interfaces.DSAPrivateKey) { 269 // Check if key originates from this factory 270 if (key instanceof sun.security.provider.DSAPrivateKey) { 271 return key; 272 } 273 // Convert key to spec 274 DSAPrivateKeySpec dsaPrivKeySpec 275 = engineGetKeySpec(key, DSAPrivateKeySpec.class); 276 // Create key from spec, and return it 277 return engineGeneratePrivate(dsaPrivKeySpec); 278 279 } else { 280 throw new InvalidKeyException("Wrong algorithm type"); 281 } 282 283 } catch (InvalidKeySpecException e) { 284 throw new InvalidKeyException("Cannot translate key: " 285 + e.getMessage()); 286 } 287 } 288 }