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