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 }