src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11PSSSignature.java
branchdatagramsocketimpl-branch
changeset 58678 9cf78a70fa4f
child 58679 9c3209ff7550
equal deleted inserted replaced
58677:13588c901957 58678:9cf78a70fa4f
       
     1 /*
       
     2  * Copyright (c) 2019, 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.io.ByteArrayOutputStream;
       
    29 import java.io.IOException;
       
    30 import java.nio.ByteBuffer;
       
    31 import sun.nio.ch.DirectBuffer;
       
    32 
       
    33 import java.util.Hashtable;
       
    34 import java.util.Arrays;
       
    35 import java.security.*;
       
    36 import java.security.spec.AlgorithmParameterSpec;
       
    37 import java.security.spec.MGF1ParameterSpec;
       
    38 import java.security.spec.PSSParameterSpec;
       
    39 import java.security.interfaces.*;
       
    40 import sun.security.pkcs11.wrapper.*;
       
    41 import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
       
    42 
       
    43 
       
    44 /**
       
    45  * RSASSA-PSS Signature implementation class. This class currently supports the
       
    46  * following algorithms:
       
    47  *
       
    48  * . RSA-PSS:
       
    49  *   . RSASSA-PSS
       
    50  *   . SHA1withRSASSA-PSS
       
    51  *   . SHA224withRSASSA-PSS
       
    52  *   . SHA256withRSASSA-PSS
       
    53  *   . SHA384withRSASSA-PSS
       
    54  *   . SHA512withRSASSA-PSS
       
    55  *
       
    56  * Note that the underlying PKCS#11 token may support complete signature
       
    57  * algorithm (e.g. CKM_<md>_RSA_PKCS_PSS), or it may just
       
    58  * implement the signature algorithm without hashing (i.e. CKM_RSA_PKCS_PSS).
       
    59  * This class uses what is available and adds whatever extra processing
       
    60  * is needed.
       
    61  *
       
    62  * @since   13
       
    63  */
       
    64 final class P11PSSSignature extends SignatureSpi {
       
    65 
       
    66     private final static boolean DEBUG = false;
       
    67 
       
    68     // mappings of digest algorithms and their output length in bytes
       
    69     private static final Hashtable<String, Integer> DIGEST_LENGTHS =
       
    70         new Hashtable<String, Integer>();
       
    71 
       
    72     static {
       
    73         DIGEST_LENGTHS.put("SHA-1", 20);
       
    74         DIGEST_LENGTHS.put("SHA", 20);
       
    75         DIGEST_LENGTHS.put("SHA1", 20);
       
    76         DIGEST_LENGTHS.put("SHA-224", 28);
       
    77         DIGEST_LENGTHS.put("SHA224", 28);
       
    78         DIGEST_LENGTHS.put("SHA-256", 32);
       
    79         DIGEST_LENGTHS.put("SHA256", 32);
       
    80         DIGEST_LENGTHS.put("SHA-384", 48);
       
    81         DIGEST_LENGTHS.put("SHA384", 48);
       
    82         DIGEST_LENGTHS.put("SHA-512", 64);
       
    83         DIGEST_LENGTHS.put("SHA512", 64);
       
    84         DIGEST_LENGTHS.put("SHA-512/224", 28);
       
    85         DIGEST_LENGTHS.put("SHA512/224", 28);
       
    86         DIGEST_LENGTHS.put("SHA-512/256", 32);
       
    87         DIGEST_LENGTHS.put("SHA512/256", 32);
       
    88     }
       
    89 
       
    90     // utility method for comparing digest algorithms
       
    91     // NOTE that first argument is assumed to be standard digest name
       
    92     private static boolean isDigestEqual(String stdAlg, String givenAlg) {
       
    93         if (stdAlg == null || givenAlg == null) return false;
       
    94 
       
    95         if (givenAlg.indexOf("-") != -1) {
       
    96             return stdAlg.equalsIgnoreCase(givenAlg);
       
    97         } else {
       
    98             if (stdAlg.equals("SHA-1")) {
       
    99                 return (givenAlg.equalsIgnoreCase("SHA")
       
   100                         || givenAlg.equalsIgnoreCase("SHA1"));
       
   101             } else {
       
   102                 StringBuilder sb = new StringBuilder(givenAlg);
       
   103                 // case-insensitive check
       
   104                 if (givenAlg.regionMatches(true, 0, "SHA", 0, 3)) {
       
   105                     givenAlg = sb.insert(3, "-").toString();
       
   106                     return stdAlg.equalsIgnoreCase(givenAlg);
       
   107                 } else {
       
   108                     throw new ProviderException("Unsupported digest algorithm "
       
   109                             + givenAlg);
       
   110                 }
       
   111             }
       
   112         }
       
   113     }
       
   114 
       
   115     // token instance
       
   116     private final Token token;
       
   117 
       
   118     // algorithm name
       
   119     private final String algorithm;
       
   120 
       
   121     // name of the key algorithm, currently just RSA
       
   122     private static final String KEY_ALGO = "RSA";
       
   123 
       
   124     // mechanism id
       
   125     private final CK_MECHANISM mechanism;
       
   126 
       
   127     // type, one of T_* below
       
   128     private final int type;
       
   129 
       
   130     // key instance used, if init*() was called
       
   131     private P11Key p11Key = null;
       
   132 
       
   133     // PSS parameters and the flag controlling its access
       
   134     private PSSParameterSpec sigParams = null;
       
   135     private boolean isActive = false;
       
   136 
       
   137     // message digest alg, if implied by the algorithm name
       
   138     private final String mdAlg;
       
   139 
       
   140     // message digest, if we do the digesting ourselves
       
   141     private MessageDigest md = null;
       
   142 
       
   143     // associated session, if any
       
   144     private Session session;
       
   145 
       
   146     // mode, one of M_* below
       
   147     private int mode;
       
   148 
       
   149     // flag indicating whether an operation is initialized
       
   150     private boolean initialized = false;
       
   151 
       
   152     // buffer, for update(byte)
       
   153     private final byte[] buffer = new byte[1];
       
   154 
       
   155     // total number of bytes processed in current operation
       
   156     private int bytesProcessed = 0;
       
   157 
       
   158     // constant for signing mode
       
   159     private final static int M_SIGN   = 1;
       
   160     // constant for verification mode
       
   161     private final static int M_VERIFY = 2;
       
   162 
       
   163     // constant for type digesting, we do the hashing ourselves
       
   164     private final static int T_DIGEST = 1;
       
   165     // constant for type update, token does everything
       
   166     private final static int T_UPDATE = 2;
       
   167 
       
   168     P11PSSSignature(Token token, String algorithm, long mechId)
       
   169             throws NoSuchAlgorithmException, PKCS11Exception {
       
   170         super();
       
   171         this.token = token;
       
   172         this.algorithm = algorithm;
       
   173         this.mechanism = new CK_MECHANISM(mechId);
       
   174         int idx = algorithm.indexOf("with");
       
   175         this.mdAlg = (idx == -1? null : algorithm.substring(0, idx));
       
   176         switch ((int)mechId) {
       
   177         case (int)CKM_SHA1_RSA_PKCS_PSS:
       
   178         case (int)CKM_SHA224_RSA_PKCS_PSS:
       
   179         case (int)CKM_SHA256_RSA_PKCS_PSS:
       
   180         case (int)CKM_SHA384_RSA_PKCS_PSS:
       
   181         case (int)CKM_SHA512_RSA_PKCS_PSS:
       
   182             type = T_UPDATE;
       
   183             break;
       
   184         case (int)CKM_RSA_PKCS_PSS:
       
   185             type = T_DIGEST;
       
   186             break;
       
   187         default:
       
   188             throw new ProviderException("Unsupported mechanism: " + mechId);
       
   189         }
       
   190         this.md = null;
       
   191     }
       
   192 
       
   193     private void ensureInitialized() throws SignatureException {
       
   194         token.ensureValid();
       
   195         if (this.p11Key == null) {
       
   196             throw new SignatureException("Missing key");
       
   197         }
       
   198         if (this.sigParams == null) {
       
   199             if (this.mdAlg == null) {
       
   200                 // PSS Parameters are required for signature verification
       
   201                 throw new SignatureException
       
   202                     ("Parameters required for RSASSA-PSS signature");
       
   203             } else {
       
   204                 int saltLen = DIGEST_LENGTHS.get(this.mdAlg).intValue();
       
   205                 // generate default params for both sign and verify?
       
   206                 this.sigParams = new PSSParameterSpec(this.mdAlg,
       
   207                         "MGF1", new MGF1ParameterSpec(this.mdAlg),
       
   208                         saltLen, PSSParameterSpec.TRAILER_FIELD_BC);
       
   209                 this.mechanism.setParameter(new CK_RSA_PKCS_PSS_PARAMS(
       
   210                         this.mdAlg, "MGF1", this.mdAlg,
       
   211                         DIGEST_LENGTHS.get(this.mdAlg).intValue()));
       
   212             }
       
   213         }
       
   214 
       
   215         if (initialized == false) {
       
   216             initialize();
       
   217         }
       
   218     }
       
   219 
       
   220     // reset the states to the pre-initialized values
       
   221     private void reset(boolean doCancel) {
       
   222         if (!initialized) {
       
   223             return;
       
   224         }
       
   225         initialized = false;
       
   226         try {
       
   227             if (session == null) {
       
   228                 return;
       
   229             }
       
   230             if (doCancel && token.explicitCancel) {
       
   231                 cancelOperation();
       
   232             }
       
   233         } finally {
       
   234             p11Key.releaseKeyID();
       
   235             mechanism.freeHandle();
       
   236             session = token.releaseSession(session);
       
   237             isActive = false;
       
   238         }
       
   239     }
       
   240 
       
   241     private void cancelOperation() {
       
   242         token.ensureValid();
       
   243         if (DEBUG) System.out.print("Cancelling operation");
       
   244 
       
   245         if (session.hasObjects() == false) {
       
   246             if (DEBUG) System.out.println(" by killing session");
       
   247             session = token.killSession(session);
       
   248             return;
       
   249         }
       
   250         // "cancel" operation by finishing it
       
   251         if (mode == M_SIGN) {
       
   252             try {
       
   253                 if (type == T_UPDATE) {
       
   254                     if (DEBUG) System.out.println(" by C_SignFinal");
       
   255                     token.p11.C_SignFinal(session.id(), 0);
       
   256                 } else {
       
   257                     byte[] digest =
       
   258                         (md == null? new byte[0] : md.digest());
       
   259                     if (DEBUG) System.out.println(" by C_Sign");
       
   260                     token.p11.C_Sign(session.id(), digest);
       
   261                 }
       
   262             } catch (PKCS11Exception e) {
       
   263                 throw new ProviderException("cancel failed", e);
       
   264             }
       
   265         } else { // M_VERIFY
       
   266             try {
       
   267                 byte[] signature =
       
   268                     new byte[(p11Key.length() + 7) >> 3];
       
   269                 if (type == T_UPDATE) {
       
   270                     if (DEBUG) System.out.println(" by C_VerifyFinal");
       
   271                     token.p11.C_VerifyFinal(session.id(), signature);
       
   272                 } else {
       
   273                     byte[] digest =
       
   274                         (md == null? new byte[0] : md.digest());
       
   275                     if (DEBUG) System.out.println(" by C_Verify");
       
   276                     token.p11.C_Verify(session.id(), digest, signature);
       
   277                 }
       
   278             } catch (PKCS11Exception e) {
       
   279                 // will fail since the signature is incorrect
       
   280                 // XXX check error code
       
   281             }
       
   282         }
       
   283     }
       
   284 
       
   285     // assumes current state is initialized == false
       
   286     private void initialize() {
       
   287         if (DEBUG) System.out.println("Initializing");
       
   288 
       
   289         if (p11Key == null) {
       
   290             throw new ProviderException(
       
   291                     "No Key found, call initSign/initVerify first");
       
   292         }
       
   293 
       
   294         long keyID = p11Key.getKeyID();
       
   295         try {
       
   296             if (session == null) {
       
   297                 session = token.getOpSession();
       
   298             }
       
   299             if (mode == M_SIGN) {
       
   300                 token.p11.C_SignInit(session.id(), mechanism, keyID);
       
   301             } else {
       
   302                 token.p11.C_VerifyInit(session.id(), mechanism, keyID);
       
   303             }
       
   304         } catch (PKCS11Exception e) {
       
   305             p11Key.releaseKeyID();
       
   306             session = token.releaseSession(session);
       
   307             throw new ProviderException("Initialization failed", e);
       
   308         }
       
   309         if (bytesProcessed != 0) {
       
   310             bytesProcessed = 0;
       
   311             if (md != null) {
       
   312                 md.reset();
       
   313             }
       
   314         }
       
   315         initialized = true;
       
   316         isActive = false;
       
   317         if (DEBUG) System.out.println("Initialized");
       
   318     }
       
   319 
       
   320     private void checkKeySize(Key key) throws InvalidKeyException {
       
   321         if (DEBUG) System.out.print("Checking Key");
       
   322 
       
   323         if (!key.getAlgorithm().equals(KEY_ALGO)) {
       
   324             throw new InvalidKeyException("Only " + KEY_ALGO +
       
   325                 " keys are supported");
       
   326         }
       
   327 
       
   328         CK_MECHANISM_INFO mechInfo = null;
       
   329         try {
       
   330             mechInfo = token.getMechanismInfo(mechanism.mechanism);
       
   331         } catch (PKCS11Exception e) {
       
   332             // should not happen, ignore for now
       
   333             if (DEBUG) {
       
   334                 System.out.println("Unexpected exception");
       
   335                 e.printStackTrace();
       
   336             }
       
   337         }
       
   338 
       
   339         int keySize = 0; // in bytes
       
   340         if (mechInfo != null) {
       
   341             // check against available native info
       
   342             int minKeySize = (int) mechInfo.ulMinKeySize;
       
   343             int maxKeySize = (int) mechInfo.ulMaxKeySize;
       
   344             if (key instanceof P11Key) {
       
   345                 keySize = (((P11Key) key).length() + 7) >> 3;
       
   346             } else if (key instanceof RSAKey) {
       
   347                 keySize = ((RSAKey) key).getModulus().bitLength() >> 3;
       
   348             } else {
       
   349                 throw new InvalidKeyException("Unrecognized key type " + key);
       
   350             }
       
   351             if ((minKeySize != -1) && (keySize < minKeySize)) {
       
   352                 throw new InvalidKeyException(KEY_ALGO +
       
   353                     " key must be at least " + minKeySize + " bytes");
       
   354             }
       
   355             if ((maxKeySize != -1) && (keySize > maxKeySize)) {
       
   356                 throw new InvalidKeyException(KEY_ALGO +
       
   357                     " key must be at most " + maxKeySize + " bytes");
       
   358             }
       
   359         }
       
   360         if (this.sigParams != null) {
       
   361             String digestAlg = this.sigParams.getDigestAlgorithm();
       
   362             int sLen = this.sigParams.getSaltLength();
       
   363             int hLen = DIGEST_LENGTHS.get(digestAlg).intValue();
       
   364             int minKeyLen = Math.addExact(Math.addExact(sLen, hLen), 2);
       
   365 
       
   366             if (keySize < minKeyLen) {
       
   367                 throw new InvalidKeyException
       
   368                     ("Key is too short for current params, need min " + minKeyLen);
       
   369             }
       
   370         }
       
   371     }
       
   372 
       
   373     private void setSigParams(AlgorithmParameterSpec p)
       
   374             throws InvalidAlgorithmParameterException {
       
   375         if (p == null) {
       
   376             throw new InvalidAlgorithmParameterException("PSS Parameter required");
       
   377         }
       
   378         if (!(p instanceof PSSParameterSpec)) {
       
   379             throw new InvalidAlgorithmParameterException
       
   380                 ("Only PSSParameterSpec is supported");
       
   381         }
       
   382         // no need to validate again if same as current signature parameters
       
   383         PSSParameterSpec params = (PSSParameterSpec) p;
       
   384         if (params == this.sigParams) return;
       
   385 
       
   386         String digestAlgorithm = params.getDigestAlgorithm();
       
   387         if (this.mdAlg != null && !isDigestEqual(digestAlgorithm, this.mdAlg)) {
       
   388             throw new InvalidAlgorithmParameterException
       
   389                     ("Digest algorithm in Signature parameters must be " +
       
   390                      this.mdAlg);
       
   391         }
       
   392         Integer digestLen = DIGEST_LENGTHS.get(digestAlgorithm);
       
   393         if (digestLen == null) {
       
   394             throw new InvalidAlgorithmParameterException
       
   395                 ("Unsupported digest algorithm in Signature parameters: " +
       
   396                  digestAlgorithm);
       
   397         }
       
   398 
       
   399         if (!(params.getMGFAlgorithm().equalsIgnoreCase("MGF1"))) {
       
   400             throw new InvalidAlgorithmParameterException("Only supports MGF1");
       
   401         }
       
   402 
       
   403         // defaults to the digest algorithm unless overridden
       
   404         String mgfDigestAlgo = digestAlgorithm;
       
   405         AlgorithmParameterSpec mgfParams = params.getMGFParameters();
       
   406         if (mgfParams != null) {
       
   407             if (!(mgfParams instanceof MGF1ParameterSpec)) {
       
   408                 throw new InvalidAlgorithmParameterException
       
   409                         ("Only MGF1ParameterSpec is supported");
       
   410             }
       
   411             mgfDigestAlgo = ((MGF1ParameterSpec)mgfParams).getDigestAlgorithm();
       
   412         }
       
   413 
       
   414         if (params.getTrailerField() != PSSParameterSpec.TRAILER_FIELD_BC) {
       
   415             throw new InvalidAlgorithmParameterException
       
   416                 ("Only supports TrailerFieldBC(1)");
       
   417         }
       
   418 
       
   419         int saltLen = params.getSaltLength();
       
   420         if (this.p11Key != null) {
       
   421             int maxSaltLen = ((this.p11Key.length() + 7) >> 3) -
       
   422                     digestLen.intValue() - 2;
       
   423 
       
   424             if (DEBUG) {
       
   425                 System.out.println("Max saltLen = " + maxSaltLen);
       
   426                 System.out.println("Curr saltLen = " + saltLen);
       
   427             }
       
   428             if (maxSaltLen < 0 || saltLen > maxSaltLen) {
       
   429                 throw new InvalidAlgorithmParameterException
       
   430                         ("Invalid with current key size");
       
   431             }
       
   432         } else if (DEBUG) {
       
   433             System.out.println("No key available for validating saltLen");
       
   434         }
       
   435 
       
   436         // validated, now try to store the parameter internally
       
   437         try {
       
   438             this.mechanism.setParameter(
       
   439                     new CK_RSA_PKCS_PSS_PARAMS(digestAlgorithm, "MGF1",
       
   440                             mgfDigestAlgo, saltLen));
       
   441             this.sigParams = params;
       
   442         } catch (IllegalArgumentException iae) {
       
   443             throw new InvalidAlgorithmParameterException(iae);
       
   444         }
       
   445     }
       
   446 
       
   447     // see JCA spec
       
   448     @Override
       
   449     protected void engineInitVerify(PublicKey publicKey)
       
   450             throws InvalidKeyException {
       
   451 
       
   452         if (publicKey == null) {
       
   453             throw new InvalidKeyException("Key must not be null");
       
   454         }
       
   455 
       
   456         // Need to check key length whenever a new key is set
       
   457         if (publicKey != p11Key) {
       
   458             checkKeySize(publicKey);
       
   459         }
       
   460 
       
   461         reset(true);
       
   462         mode = M_VERIFY;
       
   463         p11Key = P11KeyFactory.convertKey(token, publicKey, KEY_ALGO);
       
   464 
       
   465         // For PSS, defer PKCS11 initialization calls to update/doFinal as it
       
   466         // needs both key and params
       
   467     }
       
   468 
       
   469     // see JCA spec
       
   470     @Override
       
   471     protected void engineInitSign(PrivateKey privateKey)
       
   472             throws InvalidKeyException {
       
   473 
       
   474         if (privateKey == null) {
       
   475             throw new InvalidKeyException("Key must not be null");
       
   476         }
       
   477 
       
   478         // Need to check RSA key length whenever a new key is set
       
   479         if (privateKey != p11Key) {
       
   480             checkKeySize(privateKey);
       
   481         }
       
   482 
       
   483         reset(true);
       
   484         mode = M_SIGN;
       
   485         p11Key = P11KeyFactory.convertKey(token, privateKey, KEY_ALGO);
       
   486 
       
   487         // For PSS, defer PKCS11 initialization calls to update/doFinal as it
       
   488         // needs both key and params
       
   489     }
       
   490 
       
   491     // see JCA spec
       
   492     @Override
       
   493     protected void engineUpdate(byte b) throws SignatureException {
       
   494         ensureInitialized();
       
   495         isActive = true;
       
   496         buffer[0] = b;
       
   497         engineUpdate(buffer, 0, 1);
       
   498     }
       
   499 
       
   500     // see JCA spec
       
   501     @Override
       
   502     protected void engineUpdate(byte[] b, int ofs, int len)
       
   503             throws SignatureException {
       
   504         ensureInitialized();
       
   505         if (len == 0) {
       
   506             return;
       
   507         }
       
   508         // check for overflow
       
   509         if (len + bytesProcessed < 0) {
       
   510             throw new ProviderException("Processed bytes limits exceeded.");
       
   511         }
       
   512         isActive = true;
       
   513         switch (type) {
       
   514         case T_UPDATE:
       
   515             try {
       
   516                 if (mode == M_SIGN) {
       
   517                     System.out.println(this + ": Calling C_SignUpdate");
       
   518                     token.p11.C_SignUpdate(session.id(), 0, b, ofs, len);
       
   519                 } else {
       
   520                     System.out.println(this + ": Calling C_VerfifyUpdate");
       
   521                     token.p11.C_VerifyUpdate(session.id(), 0, b, ofs, len);
       
   522                 }
       
   523                 bytesProcessed += len;
       
   524             } catch (PKCS11Exception e) {
       
   525                 reset(false);
       
   526                 throw new ProviderException(e);
       
   527             }
       
   528             break;
       
   529         case T_DIGEST:
       
   530             // should not happen as this should be covered by earlier checks
       
   531             if (md == null) {
       
   532                 throw new ProviderException("PSS Parameters required");
       
   533             }
       
   534             md.update(b, ofs, len);
       
   535             bytesProcessed += len;
       
   536             break;
       
   537         default:
       
   538             throw new ProviderException("Internal error");
       
   539         }
       
   540     }
       
   541 
       
   542     // see JCA spec
       
   543     @Override
       
   544     protected void engineUpdate(ByteBuffer byteBuffer) {
       
   545         try {
       
   546             ensureInitialized();
       
   547         } catch (SignatureException se) {
       
   548             throw new ProviderException(se);
       
   549         }
       
   550         int len = byteBuffer.remaining();
       
   551         if (len <= 0) {
       
   552             return;
       
   553         }
       
   554         isActive = true;
       
   555         switch (type) {
       
   556         case T_UPDATE:
       
   557             if (byteBuffer instanceof DirectBuffer == false) {
       
   558                 // cannot do better than default impl
       
   559                 super.engineUpdate(byteBuffer);
       
   560                 return;
       
   561             }
       
   562             long addr = ((DirectBuffer)byteBuffer).address();
       
   563             int ofs = byteBuffer.position();
       
   564             try {
       
   565                 if (mode == M_SIGN) {
       
   566                     System.out.println(this + ": Calling C_SignUpdate");
       
   567                     token.p11.C_SignUpdate
       
   568                         (session.id(), addr + ofs, null, 0, len);
       
   569                 } else {
       
   570                     System.out.println(this + ": Calling C_VerifyUpdate");
       
   571                     token.p11.C_VerifyUpdate
       
   572                         (session.id(), addr + ofs, null, 0, len);
       
   573                 }
       
   574                 bytesProcessed += len;
       
   575                 byteBuffer.position(ofs + len);
       
   576             } catch (PKCS11Exception e) {
       
   577                 reset(false);
       
   578                 throw new ProviderException("Update failed", e);
       
   579             }
       
   580             break;
       
   581         case T_DIGEST:
       
   582             // should not happen as this should be covered by earlier checks
       
   583             if (md == null) {
       
   584                 throw new ProviderException("PSS Parameters required");
       
   585             }
       
   586             md.update(byteBuffer);
       
   587             bytesProcessed += len;
       
   588             break;
       
   589         default:
       
   590             reset(false);
       
   591             throw new ProviderException("Internal error");
       
   592         }
       
   593     }
       
   594 
       
   595     // see JCA spec
       
   596     @Override
       
   597     protected byte[] engineSign() throws SignatureException {
       
   598         ensureInitialized();
       
   599         boolean doCancel = true;
       
   600         if (DEBUG) System.out.print("Generating signature");
       
   601         try {
       
   602             byte[] signature;
       
   603             if (type == T_UPDATE) {
       
   604                 if (DEBUG) System.out.println(" by C_SignFinal");
       
   605                 signature = token.p11.C_SignFinal(session.id(), 0);
       
   606             } else {
       
   607                 if (md == null) {
       
   608                     throw new ProviderException("PSS Parameters required");
       
   609                 }
       
   610                 byte[] digest = md.digest();
       
   611                 if (DEBUG) System.out.println(" by C_Sign");
       
   612                 signature = token.p11.C_Sign(session.id(), digest);
       
   613             }
       
   614             doCancel = false;
       
   615             return signature;
       
   616         } catch (PKCS11Exception pe) {
       
   617             doCancel = false;
       
   618             throw new ProviderException(pe);
       
   619         } catch (ProviderException e) {
       
   620             throw e;
       
   621         } finally {
       
   622             reset(doCancel);
       
   623         }
       
   624     }
       
   625 
       
   626     // see JCA spec
       
   627     @Override
       
   628     protected boolean engineVerify(byte[] signature) throws SignatureException {
       
   629         ensureInitialized();
       
   630         boolean doCancel = true;
       
   631         if (DEBUG) System.out.print("Verifying signature");
       
   632         try {
       
   633             if (type == T_UPDATE) {
       
   634                 if (DEBUG) System.out.println(" by C_VerifyFinal");
       
   635                 token.p11.C_VerifyFinal(session.id(), signature);
       
   636             } else {
       
   637                 if (md == null) {
       
   638                     throw new ProviderException("PSS Parameters required");
       
   639                 }
       
   640                 byte[] digest = md.digest();
       
   641                 if (DEBUG) System.out.println(" by C_Verify");
       
   642                 token.p11.C_Verify(session.id(), digest, signature);
       
   643             }
       
   644             doCancel = false;
       
   645             return true;
       
   646         } catch (PKCS11Exception pe) {
       
   647             doCancel = false;
       
   648             long errorCode = pe.getErrorCode();
       
   649             if (errorCode == CKR_SIGNATURE_INVALID) {
       
   650                 return false;
       
   651             }
       
   652             if (errorCode == CKR_SIGNATURE_LEN_RANGE) {
       
   653                 // return false rather than throwing an exception
       
   654                 return false;
       
   655             }
       
   656             // ECF bug?
       
   657             if (errorCode == CKR_DATA_LEN_RANGE) {
       
   658                 return false;
       
   659             }
       
   660             throw new ProviderException(pe);
       
   661         }  catch (ProviderException e) {
       
   662             throw e;
       
   663         } finally {
       
   664             reset(doCancel);
       
   665         }
       
   666     }
       
   667 
       
   668     // see JCA spec
       
   669     @SuppressWarnings("deprecation")
       
   670     @Override
       
   671     protected void engineSetParameter(String param, Object value)
       
   672             throws InvalidParameterException {
       
   673         throw new UnsupportedOperationException("setParameter() not supported");
       
   674     }
       
   675 
       
   676     // see JCA spec
       
   677     @Override
       
   678     protected void engineSetParameter(AlgorithmParameterSpec params)
       
   679             throws InvalidAlgorithmParameterException {
       
   680         // disallow changing parameters when update has been called
       
   681         if (isActive) {
       
   682             throw new ProviderException
       
   683                 ("Cannot set parameters during operations");
       
   684         }
       
   685         setSigParams(params);
       
   686         if (type == T_DIGEST) {
       
   687             try {
       
   688                 this.md = MessageDigest.getInstance(sigParams.getDigestAlgorithm());
       
   689             } catch (NoSuchAlgorithmException nsae) {
       
   690                 throw new InvalidAlgorithmParameterException(nsae);
       
   691             }
       
   692         }
       
   693     }
       
   694 
       
   695     // see JCA spec
       
   696     @SuppressWarnings("deprecation")
       
   697     @Override
       
   698     protected Object engineGetParameter(String param)
       
   699             throws InvalidParameterException {
       
   700         throw new UnsupportedOperationException("getParameter() not supported");
       
   701     }
       
   702 
       
   703     // see JCA spec
       
   704     @Override
       
   705     protected AlgorithmParameters engineGetParameters() {
       
   706         if (this.sigParams != null) {
       
   707             try {
       
   708                 AlgorithmParameters ap = AlgorithmParameters.getInstance("RSASSA-PSS");
       
   709                 ap.init(this.sigParams);
       
   710                 return ap;
       
   711             } catch (GeneralSecurityException e) {
       
   712                 throw new RuntimeException(e);
       
   713             }
       
   714         }
       
   715         return null;
       
   716     }
       
   717 }