src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11RSACipher.java
changeset 47216 71c04702a3d5
parent 43248 5e15de85a1a0
child 53257 5170dc2bcf64
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 2003, 2015, 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.security.*;
       
    29 import java.security.spec.AlgorithmParameterSpec;
       
    30 import java.security.spec.*;
       
    31 
       
    32 import java.util.Locale;
       
    33 
       
    34 import javax.crypto.*;
       
    35 import javax.crypto.spec.*;
       
    36 
       
    37 import static sun.security.pkcs11.TemplateManager.*;
       
    38 import sun.security.pkcs11.wrapper.*;
       
    39 import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
       
    40 import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec;
       
    41 import sun.security.util.KeyUtil;
       
    42 
       
    43 /**
       
    44  * RSA Cipher implementation class. We currently only support
       
    45  * PKCS#1 v1.5 padding on top of CKM_RSA_PKCS.
       
    46  *
       
    47  * @author  Andreas Sterbenz
       
    48  * @since   1.5
       
    49  */
       
    50 final class P11RSACipher extends CipherSpi {
       
    51 
       
    52     // minimum length of PKCS#1 v1.5 padding
       
    53     private final static int PKCS1_MIN_PADDING_LENGTH = 11;
       
    54 
       
    55     // constant byte[] of length 0
       
    56     private final static byte[] B0 = new byte[0];
       
    57 
       
    58     // mode constant for public key encryption
       
    59     private final static int MODE_ENCRYPT = 1;
       
    60     // mode constant for private key decryption
       
    61     private final static int MODE_DECRYPT = 2;
       
    62     // mode constant for private key encryption (signing)
       
    63     private final static int MODE_SIGN    = 3;
       
    64     // mode constant for public key decryption (verifying)
       
    65     private final static int MODE_VERIFY  = 4;
       
    66 
       
    67     // padding type constant for NoPadding
       
    68     private final static int PAD_NONE = 1;
       
    69     // padding type constant for PKCS1Padding
       
    70     private final static int PAD_PKCS1 = 2;
       
    71 
       
    72     // token instance
       
    73     private final Token token;
       
    74 
       
    75     // algorithm name (always "RSA")
       
    76     private final String algorithm;
       
    77 
       
    78     // mechanism id
       
    79     private final long mechanism;
       
    80 
       
    81     // associated session, if any
       
    82     private Session session;
       
    83 
       
    84     // mode, one of MODE_* above
       
    85     private int mode;
       
    86 
       
    87     // padding, one of PAD_* above
       
    88     private int padType;
       
    89 
       
    90     private byte[] buffer;
       
    91     private int bufOfs;
       
    92 
       
    93     // key, if init() was called
       
    94     private P11Key p11Key;
       
    95 
       
    96     // flag indicating whether an operation is initialized
       
    97     private boolean initialized;
       
    98 
       
    99     // maximum input data size allowed
       
   100     // for decryption, this is the length of the key
       
   101     // for encryption, length of the key minus minimum padding length
       
   102     private int maxInputSize;
       
   103 
       
   104     // maximum output size. this is the length of the key
       
   105     private int outputSize;
       
   106 
       
   107     // cipher parameter for TLS RSA premaster secret
       
   108     private AlgorithmParameterSpec spec = null;
       
   109 
       
   110     // the source of randomness
       
   111     private SecureRandom random;
       
   112 
       
   113     P11RSACipher(Token token, String algorithm, long mechanism)
       
   114             throws PKCS11Exception {
       
   115         super();
       
   116         this.token = token;
       
   117         this.algorithm = "RSA";
       
   118         this.mechanism = mechanism;
       
   119     }
       
   120 
       
   121     // modes do not make sense for RSA, but allow ECB
       
   122     // see JCE spec
       
   123     protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
       
   124         if (mode.equalsIgnoreCase("ECB") == false) {
       
   125             throw new NoSuchAlgorithmException("Unsupported mode " + mode);
       
   126         }
       
   127     }
       
   128 
       
   129     protected void engineSetPadding(String padding)
       
   130             throws NoSuchPaddingException {
       
   131         String lowerPadding = padding.toLowerCase(Locale.ENGLISH);
       
   132         if (lowerPadding.equals("pkcs1padding")) {
       
   133             padType = PAD_PKCS1;
       
   134         } else if (lowerPadding.equals("nopadding")) {
       
   135             padType = PAD_NONE;
       
   136         } else {
       
   137             throw new NoSuchPaddingException("Unsupported padding " + padding);
       
   138         }
       
   139     }
       
   140 
       
   141     // return 0 as block size, we are not a block cipher
       
   142     // see JCE spec
       
   143     protected int engineGetBlockSize() {
       
   144         return 0;
       
   145     }
       
   146 
       
   147     // return the output size
       
   148     // see JCE spec
       
   149     protected int engineGetOutputSize(int inputLen) {
       
   150         return outputSize;
       
   151     }
       
   152 
       
   153     // no IV, return null
       
   154     // see JCE spec
       
   155     protected byte[] engineGetIV() {
       
   156         return null;
       
   157     }
       
   158 
       
   159     // no parameters, return null
       
   160     // see JCE spec
       
   161     protected AlgorithmParameters engineGetParameters() {
       
   162         return null;
       
   163     }
       
   164 
       
   165     // see JCE spec
       
   166     protected void engineInit(int opmode, Key key, SecureRandom random)
       
   167             throws InvalidKeyException {
       
   168         implInit(opmode, key);
       
   169     }
       
   170 
       
   171     // see JCE spec
       
   172     @SuppressWarnings("deprecation")
       
   173     protected void engineInit(int opmode, Key key,
       
   174             AlgorithmParameterSpec params, SecureRandom random)
       
   175             throws InvalidKeyException, InvalidAlgorithmParameterException {
       
   176         if (params != null) {
       
   177             if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) {
       
   178                 throw new InvalidAlgorithmParameterException(
       
   179                         "Parameters not supported");
       
   180             }
       
   181             spec = params;
       
   182             this.random = random;   // for TLS RSA premaster secret
       
   183         }
       
   184         implInit(opmode, key);
       
   185     }
       
   186 
       
   187     // see JCE spec
       
   188     protected void engineInit(int opmode, Key key, AlgorithmParameters params,
       
   189             SecureRandom random)
       
   190             throws InvalidKeyException, InvalidAlgorithmParameterException {
       
   191         if (params != null) {
       
   192             throw new InvalidAlgorithmParameterException(
       
   193                         "Parameters not supported");
       
   194         }
       
   195         implInit(opmode, key);
       
   196     }
       
   197 
       
   198     private void implInit(int opmode, Key key) throws InvalidKeyException {
       
   199         cancelOperation();
       
   200         p11Key = P11KeyFactory.convertKey(token, key, algorithm);
       
   201         boolean encrypt;
       
   202         if (opmode == Cipher.ENCRYPT_MODE) {
       
   203             encrypt = true;
       
   204         } else if (opmode == Cipher.DECRYPT_MODE) {
       
   205             encrypt = false;
       
   206         } else if (opmode == Cipher.WRAP_MODE) {
       
   207             if (p11Key.isPublic() == false) {
       
   208                 throw new InvalidKeyException
       
   209                                 ("Wrap has to be used with public keys");
       
   210             }
       
   211             // No further setup needed for C_Wrap(). We'll initialize later if
       
   212             // we can't use C_Wrap().
       
   213             return;
       
   214         } else if (opmode == Cipher.UNWRAP_MODE) {
       
   215             if (p11Key.isPrivate() == false) {
       
   216                 throw new InvalidKeyException
       
   217                                 ("Unwrap has to be used with private keys");
       
   218             }
       
   219             // No further setup needed for C_Unwrap(). We'll initialize later
       
   220             // if we can't use C_Unwrap().
       
   221             return;
       
   222         } else {
       
   223             throw new InvalidKeyException("Unsupported mode: " + opmode);
       
   224         }
       
   225         if (p11Key.isPublic()) {
       
   226             mode = encrypt ? MODE_ENCRYPT : MODE_VERIFY;
       
   227         } else if (p11Key.isPrivate()) {
       
   228             mode = encrypt ? MODE_SIGN : MODE_DECRYPT;
       
   229         } else {
       
   230             throw new InvalidKeyException("Unknown key type: " + p11Key);
       
   231         }
       
   232         int n = (p11Key.length() + 7) >> 3;
       
   233         outputSize = n;
       
   234         buffer = new byte[n];
       
   235         maxInputSize = ((padType == PAD_PKCS1 && encrypt) ?
       
   236                             (n - PKCS1_MIN_PADDING_LENGTH) : n);
       
   237         try {
       
   238             initialize();
       
   239         } catch (PKCS11Exception e) {
       
   240             throw new InvalidKeyException("init() failed", e);
       
   241         }
       
   242     }
       
   243 
       
   244     private void cancelOperation() {
       
   245         token.ensureValid();
       
   246         if (initialized == false) {
       
   247             return;
       
   248         }
       
   249         initialized = false;
       
   250         if ((session == null) || (token.explicitCancel == false)) {
       
   251             return;
       
   252         }
       
   253         if (session.hasObjects() == false) {
       
   254             session = token.killSession(session);
       
   255             return;
       
   256         }
       
   257         try {
       
   258             PKCS11 p11 = token.p11;
       
   259             int inLen = maxInputSize;
       
   260             int outLen = buffer.length;
       
   261             switch (mode) {
       
   262             case MODE_ENCRYPT:
       
   263                 p11.C_Encrypt
       
   264                         (session.id(), buffer, 0, inLen, buffer, 0, outLen);
       
   265                 break;
       
   266             case MODE_DECRYPT:
       
   267                 p11.C_Decrypt
       
   268                         (session.id(), buffer, 0, inLen, buffer, 0, outLen);
       
   269                 break;
       
   270             case MODE_SIGN:
       
   271                 byte[] tmpBuffer = new byte[maxInputSize];
       
   272                 p11.C_Sign
       
   273                         (session.id(), tmpBuffer);
       
   274                 break;
       
   275             case MODE_VERIFY:
       
   276                 p11.C_VerifyRecover
       
   277                         (session.id(), buffer, 0, inLen, buffer, 0, outLen);
       
   278                 break;
       
   279             default:
       
   280                 throw new ProviderException("internal error");
       
   281             }
       
   282         } catch (PKCS11Exception e) {
       
   283             // XXX ensure this always works, ignore error
       
   284         }
       
   285     }
       
   286 
       
   287     private void ensureInitialized() throws PKCS11Exception {
       
   288         token.ensureValid();
       
   289         if (initialized == false) {
       
   290             initialize();
       
   291         }
       
   292     }
       
   293 
       
   294     private void initialize() throws PKCS11Exception {
       
   295         if (session == null) {
       
   296             session = token.getOpSession();
       
   297         }
       
   298         PKCS11 p11 = token.p11;
       
   299         CK_MECHANISM ckMechanism = new CK_MECHANISM(mechanism);
       
   300         switch (mode) {
       
   301         case MODE_ENCRYPT:
       
   302             p11.C_EncryptInit(session.id(), ckMechanism, p11Key.keyID);
       
   303             break;
       
   304         case MODE_DECRYPT:
       
   305             p11.C_DecryptInit(session.id(), ckMechanism, p11Key.keyID);
       
   306             break;
       
   307         case MODE_SIGN:
       
   308             p11.C_SignInit(session.id(), ckMechanism, p11Key.keyID);
       
   309             break;
       
   310         case MODE_VERIFY:
       
   311             p11.C_VerifyRecoverInit(session.id(), ckMechanism, p11Key.keyID);
       
   312             break;
       
   313         default:
       
   314             throw new AssertionError("internal error");
       
   315         }
       
   316         bufOfs = 0;
       
   317         initialized = true;
       
   318     }
       
   319 
       
   320     private void implUpdate(byte[] in, int inOfs, int inLen) {
       
   321         try {
       
   322             ensureInitialized();
       
   323         } catch (PKCS11Exception e) {
       
   324             throw new ProviderException("update() failed", e);
       
   325         }
       
   326         if ((inLen == 0) || (in == null)) {
       
   327             return;
       
   328         }
       
   329         if (bufOfs + inLen > maxInputSize) {
       
   330             bufOfs = maxInputSize + 1;
       
   331             return;
       
   332         }
       
   333         System.arraycopy(in, inOfs, buffer, bufOfs, inLen);
       
   334         bufOfs += inLen;
       
   335     }
       
   336 
       
   337     private int implDoFinal(byte[] out, int outOfs, int outLen)
       
   338             throws BadPaddingException, IllegalBlockSizeException {
       
   339         if (bufOfs > maxInputSize) {
       
   340             throw new IllegalBlockSizeException("Data must not be longer "
       
   341                 + "than " + maxInputSize + " bytes");
       
   342         }
       
   343         try {
       
   344             ensureInitialized();
       
   345             PKCS11 p11 = token.p11;
       
   346             int n;
       
   347             switch (mode) {
       
   348             case MODE_ENCRYPT:
       
   349                 n = p11.C_Encrypt
       
   350                         (session.id(), buffer, 0, bufOfs, out, outOfs, outLen);
       
   351                 break;
       
   352             case MODE_DECRYPT:
       
   353                 n = p11.C_Decrypt
       
   354                         (session.id(), buffer, 0, bufOfs, out, outOfs, outLen);
       
   355                 break;
       
   356             case MODE_SIGN:
       
   357                 byte[] tmpBuffer = new byte[bufOfs];
       
   358                 System.arraycopy(buffer, 0, tmpBuffer, 0, bufOfs);
       
   359                 tmpBuffer = p11.C_Sign(session.id(), tmpBuffer);
       
   360                 if (tmpBuffer.length > outLen) {
       
   361                     throw new BadPaddingException(
       
   362                         "Output buffer (" + outLen + ") is too small to " +
       
   363                         "hold the produced data (" + tmpBuffer.length + ")");
       
   364                 }
       
   365                 System.arraycopy(tmpBuffer, 0, out, outOfs, tmpBuffer.length);
       
   366                 n = tmpBuffer.length;
       
   367                 break;
       
   368             case MODE_VERIFY:
       
   369                 n = p11.C_VerifyRecover
       
   370                         (session.id(), buffer, 0, bufOfs, out, outOfs, outLen);
       
   371                 break;
       
   372             default:
       
   373                 throw new ProviderException("internal error");
       
   374             }
       
   375             return n;
       
   376         } catch (PKCS11Exception e) {
       
   377             throw (BadPaddingException)new BadPaddingException
       
   378                 ("doFinal() failed").initCause(e);
       
   379         } finally {
       
   380             initialized = false;
       
   381             session = token.releaseSession(session);
       
   382         }
       
   383     }
       
   384 
       
   385     // see JCE spec
       
   386     protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {
       
   387         implUpdate(in, inOfs, inLen);
       
   388         return B0;
       
   389     }
       
   390 
       
   391     // see JCE spec
       
   392     protected int engineUpdate(byte[] in, int inOfs, int inLen,
       
   393             byte[] out, int outOfs) throws ShortBufferException {
       
   394         implUpdate(in, inOfs, inLen);
       
   395         return 0;
       
   396     }
       
   397 
       
   398     // see JCE spec
       
   399     protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)
       
   400             throws IllegalBlockSizeException, BadPaddingException {
       
   401         implUpdate(in, inOfs, inLen);
       
   402         int n = implDoFinal(buffer, 0, buffer.length);
       
   403         byte[] out = new byte[n];
       
   404         System.arraycopy(buffer, 0, out, 0, n);
       
   405         return out;
       
   406     }
       
   407 
       
   408     // see JCE spec
       
   409     protected int engineDoFinal(byte[] in, int inOfs, int inLen,
       
   410             byte[] out, int outOfs) throws ShortBufferException,
       
   411             IllegalBlockSizeException, BadPaddingException {
       
   412         implUpdate(in, inOfs, inLen);
       
   413         return implDoFinal(out, outOfs, out.length - outOfs);
       
   414     }
       
   415 
       
   416     private byte[] doFinal() throws BadPaddingException,
       
   417             IllegalBlockSizeException {
       
   418         byte[] t = new byte[2048];
       
   419         int n = implDoFinal(t, 0, t.length);
       
   420         byte[] out = new byte[n];
       
   421         System.arraycopy(t, 0, out, 0, n);
       
   422         return out;
       
   423     }
       
   424 
       
   425     // see JCE spec
       
   426     protected byte[] engineWrap(Key key) throws InvalidKeyException,
       
   427             IllegalBlockSizeException {
       
   428         String keyAlg = key.getAlgorithm();
       
   429         P11Key sKey = null;
       
   430         try {
       
   431             // The conversion may fail, e.g. trying to wrap an AES key on
       
   432             // a token that does not support AES, or when the key size is
       
   433             // not within the range supported by the token.
       
   434             sKey = P11SecretKeyFactory.convertKey(token, key, keyAlg);
       
   435         } catch (InvalidKeyException ike) {
       
   436             byte[] toBeWrappedKey = key.getEncoded();
       
   437             if (toBeWrappedKey == null) {
       
   438                 throw new InvalidKeyException
       
   439                         ("wrap() failed, no encoding available", ike);
       
   440             }
       
   441             // Directly encrypt the key encoding when key conversion failed
       
   442             implInit(Cipher.ENCRYPT_MODE, p11Key);
       
   443             implUpdate(toBeWrappedKey, 0, toBeWrappedKey.length);
       
   444             try {
       
   445                 return doFinal();
       
   446             } catch (BadPaddingException bpe) {
       
   447                 // should not occur
       
   448                 throw new InvalidKeyException("wrap() failed", bpe);
       
   449             } finally {
       
   450                 // Restore original mode
       
   451                 implInit(Cipher.WRAP_MODE, p11Key);
       
   452             }
       
   453         }
       
   454         Session s = null;
       
   455         try {
       
   456             s = token.getOpSession();
       
   457             return token.p11.C_WrapKey(s.id(), new CK_MECHANISM(mechanism),
       
   458                 p11Key.keyID, sKey.keyID);
       
   459         } catch (PKCS11Exception e) {
       
   460             throw new InvalidKeyException("wrap() failed", e);
       
   461         } finally {
       
   462             token.releaseSession(s);
       
   463         }
       
   464     }
       
   465 
       
   466     // see JCE spec
       
   467     @SuppressWarnings("deprecation")
       
   468     protected Key engineUnwrap(byte[] wrappedKey, String algorithm,
       
   469             int type) throws InvalidKeyException, NoSuchAlgorithmException {
       
   470 
       
   471         boolean isTlsRsaPremasterSecret =
       
   472                 algorithm.equals("TlsRsaPremasterSecret");
       
   473         Exception failover = null;
       
   474 
       
   475         // Should C_Unwrap be preferred for non-TLS RSA premaster secret?
       
   476         if (token.supportsRawSecretKeyImport()) {
       
   477             // XXX implement unwrap using C_Unwrap() for all keys
       
   478             implInit(Cipher.DECRYPT_MODE, p11Key);
       
   479             try {
       
   480                 if (wrappedKey.length > maxInputSize) {
       
   481                     throw new InvalidKeyException("Key is too long for unwrapping");
       
   482                 }
       
   483 
       
   484                 byte[] encoded = null;
       
   485                 implUpdate(wrappedKey, 0, wrappedKey.length);
       
   486                 try {
       
   487                     encoded = doFinal();
       
   488                 } catch (BadPaddingException e) {
       
   489                     if (isTlsRsaPremasterSecret) {
       
   490                         failover = e;
       
   491                     } else {
       
   492                         throw new InvalidKeyException("Unwrapping failed", e);
       
   493                     }
       
   494                 } catch (IllegalBlockSizeException e) {
       
   495                     // should not occur, handled with length check above
       
   496                     throw new InvalidKeyException("Unwrapping failed", e);
       
   497                 }
       
   498 
       
   499                 if (isTlsRsaPremasterSecret) {
       
   500                     if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) {
       
   501                         throw new IllegalStateException(
       
   502                                 "No TlsRsaPremasterSecretParameterSpec specified");
       
   503                     }
       
   504 
       
   505                     // polish the TLS premaster secret
       
   506                     TlsRsaPremasterSecretParameterSpec psps =
       
   507                             (TlsRsaPremasterSecretParameterSpec)spec;
       
   508                     encoded = KeyUtil.checkTlsPreMasterSecretKey(
       
   509                             psps.getClientVersion(), psps.getServerVersion(),
       
   510                             random, encoded, (failover != null));
       
   511                 }
       
   512 
       
   513                 return ConstructKeys.constructKey(encoded, algorithm, type);
       
   514             } finally {
       
   515                 // Restore original mode
       
   516                 implInit(Cipher.UNWRAP_MODE, p11Key);
       
   517             }
       
   518         } else {
       
   519             Session s = null;
       
   520             SecretKey secretKey = null;
       
   521             try {
       
   522                 try {
       
   523                     s = token.getObjSession();
       
   524                     long keyType = CKK_GENERIC_SECRET;
       
   525                     CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
       
   526                             new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),
       
   527                             new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType),
       
   528                         };
       
   529                     attributes = token.getAttributes(
       
   530                             O_IMPORT, CKO_SECRET_KEY, keyType, attributes);
       
   531                     long keyID = token.p11.C_UnwrapKey(s.id(),
       
   532                             new CK_MECHANISM(mechanism), p11Key.keyID,
       
   533                             wrappedKey, attributes);
       
   534                     secretKey = P11Key.secretKey(s, keyID,
       
   535                             algorithm, 48 << 3, attributes);
       
   536                 } catch (PKCS11Exception e) {
       
   537                     if (isTlsRsaPremasterSecret) {
       
   538                         failover = e;
       
   539                     } else {
       
   540                         throw new InvalidKeyException("unwrap() failed", e);
       
   541                     }
       
   542                 }
       
   543 
       
   544                 if (isTlsRsaPremasterSecret) {
       
   545                     TlsRsaPremasterSecretParameterSpec psps =
       
   546                             (TlsRsaPremasterSecretParameterSpec)spec;
       
   547 
       
   548                     // Please use the tricky failover as the parameter so that
       
   549                     // smart compiler won't dispose the unused variable.
       
   550                     secretKey = polishPreMasterSecretKey(token, s,
       
   551                             failover, secretKey,
       
   552                             psps.getClientVersion(), psps.getServerVersion());
       
   553                 }
       
   554 
       
   555                 return secretKey;
       
   556             } finally {
       
   557                 token.releaseSession(s);
       
   558             }
       
   559         }
       
   560     }
       
   561 
       
   562     // see JCE spec
       
   563     protected int engineGetKeySize(Key key) throws InvalidKeyException {
       
   564         int n = P11KeyFactory.convertKey(token, key, algorithm).length();
       
   565         return n;
       
   566     }
       
   567 
       
   568     private static SecretKey polishPreMasterSecretKey(
       
   569             Token token, Session session,
       
   570             Exception failover, SecretKey unwrappedKey,
       
   571             int clientVersion, int serverVersion) {
       
   572 
       
   573         SecretKey newKey;
       
   574         CK_VERSION version = new CK_VERSION(
       
   575                 (clientVersion >>> 8) & 0xFF, clientVersion & 0xFF);
       
   576         try {
       
   577             CK_ATTRIBUTE[] attributes = token.getAttributes(
       
   578                     O_GENERATE, CKO_SECRET_KEY,
       
   579                     CKK_GENERIC_SECRET, new CK_ATTRIBUTE[0]);
       
   580             long keyID = token.p11.C_GenerateKey(session.id(),
       
   581                     new CK_MECHANISM(CKM_SSL3_PRE_MASTER_KEY_GEN, version),
       
   582                     attributes);
       
   583             newKey = P11Key.secretKey(session,
       
   584                     keyID, "TlsRsaPremasterSecret", 48 << 3, attributes);
       
   585         } catch (PKCS11Exception e) {
       
   586             throw new ProviderException(
       
   587                     "Could not generate premaster secret", e);
       
   588         }
       
   589 
       
   590         return (failover == null) ? unwrappedKey : newKey;
       
   591     }
       
   592 
       
   593 }
       
   594 
       
   595 final class ConstructKeys {
       
   596     /**
       
   597      * Construct a public key from its encoding.
       
   598      *
       
   599      * @param encodedKey the encoding of a public key.
       
   600      *
       
   601      * @param encodedKeyAlgorithm the algorithm the encodedKey is for.
       
   602      *
       
   603      * @return a public key constructed from the encodedKey.
       
   604      */
       
   605     private static final PublicKey constructPublicKey(byte[] encodedKey,
       
   606             String encodedKeyAlgorithm)
       
   607             throws InvalidKeyException, NoSuchAlgorithmException {
       
   608         try {
       
   609             KeyFactory keyFactory =
       
   610                 KeyFactory.getInstance(encodedKeyAlgorithm);
       
   611             X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey);
       
   612             return keyFactory.generatePublic(keySpec);
       
   613         } catch (NoSuchAlgorithmException nsae) {
       
   614             throw new NoSuchAlgorithmException("No installed providers " +
       
   615                                                "can create keys for the " +
       
   616                                                encodedKeyAlgorithm +
       
   617                                                "algorithm", nsae);
       
   618         } catch (InvalidKeySpecException ike) {
       
   619             throw new InvalidKeyException("Cannot construct public key", ike);
       
   620         }
       
   621     }
       
   622 
       
   623     /**
       
   624      * Construct a private key from its encoding.
       
   625      *
       
   626      * @param encodedKey the encoding of a private key.
       
   627      *
       
   628      * @param encodedKeyAlgorithm the algorithm the wrapped key is for.
       
   629      *
       
   630      * @return a private key constructed from the encodedKey.
       
   631      */
       
   632     private static final PrivateKey constructPrivateKey(byte[] encodedKey,
       
   633             String encodedKeyAlgorithm) throws InvalidKeyException,
       
   634             NoSuchAlgorithmException {
       
   635         try {
       
   636             KeyFactory keyFactory =
       
   637                 KeyFactory.getInstance(encodedKeyAlgorithm);
       
   638             PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey);
       
   639             return keyFactory.generatePrivate(keySpec);
       
   640         } catch (NoSuchAlgorithmException nsae) {
       
   641             throw new NoSuchAlgorithmException("No installed providers " +
       
   642                                                "can create keys for the " +
       
   643                                                encodedKeyAlgorithm +
       
   644                                                "algorithm", nsae);
       
   645         } catch (InvalidKeySpecException ike) {
       
   646             throw new InvalidKeyException("Cannot construct private key", ike);
       
   647         }
       
   648     }
       
   649 
       
   650     /**
       
   651      * Construct a secret key from its encoding.
       
   652      *
       
   653      * @param encodedKey the encoding of a secret key.
       
   654      *
       
   655      * @param encodedKeyAlgorithm the algorithm the secret key is for.
       
   656      *
       
   657      * @return a secret key constructed from the encodedKey.
       
   658      */
       
   659     private static final SecretKey constructSecretKey(byte[] encodedKey,
       
   660             String encodedKeyAlgorithm) {
       
   661         return new SecretKeySpec(encodedKey, encodedKeyAlgorithm);
       
   662     }
       
   663 
       
   664     static final Key constructKey(byte[] encoding, String keyAlgorithm,
       
   665             int keyType) throws InvalidKeyException, NoSuchAlgorithmException {
       
   666         switch (keyType) {
       
   667         case Cipher.SECRET_KEY:
       
   668             return constructSecretKey(encoding, keyAlgorithm);
       
   669         case Cipher.PRIVATE_KEY:
       
   670             return constructPrivateKey(encoding, keyAlgorithm);
       
   671         case Cipher.PUBLIC_KEY:
       
   672             return constructPublicKey(encoding, keyAlgorithm);
       
   673         default:
       
   674             throw new InvalidKeyException("Unknown keytype " + keyType);
       
   675         }
       
   676     }
       
   677 }