1 /* 2 * Copyright (c) 2003, 2013, 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.pkcs11; 27 28 import java.math.BigInteger; 29 30 import java.security.*; 31 import java.security.spec.*; 32 33 import javax.crypto.interfaces.*; 34 import javax.crypto.spec.*; 35 36 import static sun.security.pkcs11.TemplateManager.*; 37 import sun.security.pkcs11.wrapper.*; 38 import static sun.security.pkcs11.wrapper.PKCS11Constants.*; 39 40 /** 41 * DH KeyFactory implementation. 42 * 43 * @author Andreas Sterbenz 44 * @since 1.5 45 */ 46 final class P11DHKeyFactory extends P11KeyFactory { 47 48 P11DHKeyFactory(Token token, String algorithm) { 49 super(token, algorithm); 50 } 51 52 PublicKey implTranslatePublicKey(PublicKey key) throws InvalidKeyException { 53 try { 54 if (key instanceof DHPublicKey) { 55 DHPublicKey dhKey = (DHPublicKey)key; 56 DHParameterSpec params = dhKey.getParams(); 57 return generatePublic( 58 dhKey.getY(), 59 params.getP(), 60 params.getG() 61 ); 62 } else if ("X.509".equals(key.getFormat())) { 63 // let SunJCE provider parse for us, then recurse 64 try { 65 KeyFactory factory = implGetSoftwareFactory(); 66 key = (PublicKey)factory.translateKey(key); 67 return implTranslatePublicKey(key); 68 } catch (GeneralSecurityException e) { 69 throw new InvalidKeyException("Could not translate key", e); 70 } 71 } else { 72 throw new InvalidKeyException("PublicKey must be instance " 73 + "of DHPublicKey or have X.509 encoding"); 74 } 75 } catch (PKCS11Exception e) { 76 throw new InvalidKeyException("Could not create DH public key", e); 77 } 78 } 79 80 PrivateKey implTranslatePrivateKey(PrivateKey key) 81 throws InvalidKeyException { 82 try { 83 if (key instanceof DHPrivateKey) { 84 DHPrivateKey dhKey = (DHPrivateKey)key; 85 DHParameterSpec params = dhKey.getParams(); 86 return generatePrivate( 87 dhKey.getX(), 88 params.getP(), 89 params.getG() 90 ); 91 } else if ("PKCS#8".equals(key.getFormat())) { 92 // let SunJCE provider parse for us, then recurse 93 try { 94 KeyFactory factory = implGetSoftwareFactory(); 95 key = (PrivateKey)factory.translateKey(key); 96 return implTranslatePrivateKey(key); 97 } catch (GeneralSecurityException e) { 98 throw new InvalidKeyException("Could not translate key", e); 99 } 100 } else { 101 throw new InvalidKeyException("PrivateKey must be instance " 102 + "of DHPrivateKey or have PKCS#8 encoding"); 103 } 104 } catch (PKCS11Exception e) { 105 throw new InvalidKeyException("Could not create DH private key", e); 106 } 107 } 108 109 // see JCA spec 110 protected PublicKey engineGeneratePublic(KeySpec keySpec) 111 throws InvalidKeySpecException { 112 token.ensureValid(); 113 if (keySpec instanceof X509EncodedKeySpec) { 114 try { 115 KeyFactory factory = implGetSoftwareFactory(); 116 PublicKey key = factory.generatePublic(keySpec); 117 return implTranslatePublicKey(key); 118 } catch (GeneralSecurityException e) { 119 throw new InvalidKeySpecException 120 ("Could not create DH public key", e); 121 } 122 } 123 if (keySpec instanceof DHPublicKeySpec == false) { 124 throw new InvalidKeySpecException("Only DHPublicKeySpec and " 125 + "X509EncodedKeySpec supported for DH public keys"); 126 } 127 try { 128 DHPublicKeySpec ds = (DHPublicKeySpec)keySpec; 129 return generatePublic( 130 ds.getY(), 131 ds.getP(), 132 ds.getG() 133 ); 134 } catch (PKCS11Exception e) { 135 throw new InvalidKeySpecException 136 ("Could not create DH public key", e); 137 } 138 } 139 140 // see JCA spec 141 protected PrivateKey engineGeneratePrivate(KeySpec keySpec) 142 throws InvalidKeySpecException { 143 token.ensureValid(); 144 if (keySpec instanceof PKCS8EncodedKeySpec) { 145 try { 146 KeyFactory factory = implGetSoftwareFactory(); 147 PrivateKey key = factory.generatePrivate(keySpec); 148 return implTranslatePrivateKey(key); 149 } catch (GeneralSecurityException e) { 150 throw new InvalidKeySpecException 151 ("Could not create DH private key", e); 152 } 153 } 154 if (keySpec instanceof DHPrivateKeySpec == false) { 155 throw new InvalidKeySpecException("Only DHPrivateKeySpec and " 156 + "PKCS8EncodedKeySpec supported for DH private keys"); 157 } 158 try { 159 DHPrivateKeySpec ds = (DHPrivateKeySpec)keySpec; 160 return generatePrivate( 161 ds.getX(), 162 ds.getP(), 163 ds.getG() 164 ); 165 } catch (PKCS11Exception e) { 166 throw new InvalidKeySpecException 167 ("Could not create DH private key", e); 168 } 169 } 170 171 private PublicKey generatePublic(BigInteger y, BigInteger p, BigInteger g) 172 throws PKCS11Exception { 173 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 174 new CK_ATTRIBUTE(CKA_CLASS, CKO_PUBLIC_KEY), 175 new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_DH), 176 new CK_ATTRIBUTE(CKA_VALUE, y), 177 new CK_ATTRIBUTE(CKA_PRIME, p), 178 new CK_ATTRIBUTE(CKA_BASE, g), 179 }; 180 attributes = token.getAttributes 181 (O_IMPORT, CKO_PUBLIC_KEY, CKK_DH, attributes); 182 Session session = null; 183 try { 184 session = token.getObjSession(); 185 long keyID = token.p11.C_CreateObject(session.id(), attributes); 186 return P11Key.publicKey 187 (session, keyID, "DH", p.bitLength(), attributes); 188 } finally { 189 token.releaseSession(session); 190 } 191 } 192 193 private PrivateKey generatePrivate(BigInteger x, BigInteger p, 194 BigInteger g) throws PKCS11Exception { 195 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 196 new CK_ATTRIBUTE(CKA_CLASS, CKO_PRIVATE_KEY), 197 new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_DH), 198 new CK_ATTRIBUTE(CKA_VALUE, x), 199 new CK_ATTRIBUTE(CKA_PRIME, p), 200 new CK_ATTRIBUTE(CKA_BASE, g), 201 }; 202 attributes = token.getAttributes 203 (O_IMPORT, CKO_PRIVATE_KEY, CKK_DH, attributes); 204 Session session = null; 205 try { 206 session = token.getObjSession(); 207 long keyID = token.p11.C_CreateObject(session.id(), attributes); 208 return P11Key.privateKey 209 (session, keyID, "DH", p.bitLength(), attributes); 210 } finally { 211 token.releaseSession(session); 212 } 213 } 214 215 <T extends KeySpec> T implGetPublicKeySpec(P11Key key, Class<T> keySpec, 216 Session[] session) throws PKCS11Exception, InvalidKeySpecException { 217 if (DHPublicKeySpec.class.isAssignableFrom(keySpec)) { 218 session[0] = token.getObjSession(); 219 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 220 new CK_ATTRIBUTE(CKA_VALUE), 221 new CK_ATTRIBUTE(CKA_PRIME), 222 new CK_ATTRIBUTE(CKA_BASE), 223 }; 224 token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); 225 KeySpec spec = new DHPublicKeySpec( 226 attributes[0].getBigInteger(), 227 attributes[1].getBigInteger(), 228 attributes[2].getBigInteger() 229 ); 230 return keySpec.cast(spec); 231 } else { // X.509 handled in superclass 232 throw new InvalidKeySpecException("Only DHPublicKeySpec and " 233 + "X509EncodedKeySpec supported for DH public keys"); 234 } 235 } 236 237 <T extends KeySpec> T implGetPrivateKeySpec(P11Key key, Class<T> keySpec, 238 Session[] session) throws PKCS11Exception, InvalidKeySpecException { 239 if (DHPrivateKeySpec.class.isAssignableFrom(keySpec)) { 240 session[0] = token.getObjSession(); 241 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 242 new CK_ATTRIBUTE(CKA_VALUE), 243 new CK_ATTRIBUTE(CKA_PRIME), 244 new CK_ATTRIBUTE(CKA_BASE), 245 }; 246 token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes); 247 KeySpec spec = new DHPrivateKeySpec( 248 attributes[0].getBigInteger(), 249 attributes[1].getBigInteger(), 250 attributes[2].getBigInteger() 251 ); 252 return keySpec.cast(spec); 253 } else { // PKCS#8 handled in superclass 254 throw new InvalidKeySpecException("Only DHPrivateKeySpec " 255 + "and PKCS8EncodedKeySpec supported for DH private keys"); 256 } 257 } 258 259 KeyFactory implGetSoftwareFactory() throws GeneralSecurityException { 260 return KeyFactory.getInstance("DH", P11Util.getSunJceProvider()); 261 } 262 263 }