| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package sun.security.pkcs11;  | 
 | 
 | 
 | 
import java.io.ByteArrayOutputStream;  | 
 | 
import java.io.IOException;  | 
 | 
import java.nio.ByteBuffer;  | 
 | 
import sun.nio.ch.DirectBuffer;  | 
 | 
 | 
 | 
import java.util.Hashtable;  | 
 | 
import java.util.Arrays;  | 
 | 
import java.security.*;  | 
 | 
import java.security.spec.AlgorithmParameterSpec;  | 
 | 
import java.security.spec.MGF1ParameterSpec;  | 
 | 
import java.security.spec.PSSParameterSpec;  | 
 | 
import java.security.interfaces.*;  | 
 | 
import sun.security.pkcs11.wrapper.*;  | 
 | 
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
final class P11PSSSignature extends SignatureSpi { | 
 | 
 | 
 | 
    private final static boolean DEBUG = false;  | 
 | 
 | 
 | 
      | 
 | 
    private static final Hashtable<String, Integer> DIGEST_LENGTHS =  | 
 | 
        new Hashtable<String, Integer>();  | 
 | 
 | 
 | 
    static { | 
 | 
        DIGEST_LENGTHS.put("SHA-1", 20); | 
 | 
        DIGEST_LENGTHS.put("SHA", 20); | 
 | 
        DIGEST_LENGTHS.put("SHA1", 20); | 
 | 
        DIGEST_LENGTHS.put("SHA-224", 28); | 
 | 
        DIGEST_LENGTHS.put("SHA224", 28); | 
 | 
        DIGEST_LENGTHS.put("SHA-256", 32); | 
 | 
        DIGEST_LENGTHS.put("SHA256", 32); | 
 | 
        DIGEST_LENGTHS.put("SHA-384", 48); | 
 | 
        DIGEST_LENGTHS.put("SHA384", 48); | 
 | 
        DIGEST_LENGTHS.put("SHA-512", 64); | 
 | 
        DIGEST_LENGTHS.put("SHA512", 64); | 
 | 
        DIGEST_LENGTHS.put("SHA-512/224", 28); | 
 | 
        DIGEST_LENGTHS.put("SHA512/224", 28); | 
 | 
        DIGEST_LENGTHS.put("SHA-512/256", 32); | 
 | 
        DIGEST_LENGTHS.put("SHA512/256", 32); | 
 | 
    }  | 
 | 
 | 
 | 
    // utility method for comparing digest algorithms  | 
 | 
      | 
 | 
    private static boolean isDigestEqual(String stdAlg, String givenAlg) { | 
 | 
        if (stdAlg == null || givenAlg == null) return false;  | 
 | 
 | 
 | 
        if (givenAlg.indexOf("-") != -1) { | 
 | 
            return stdAlg.equalsIgnoreCase(givenAlg);  | 
 | 
        } else { | 
 | 
            if (stdAlg.equals("SHA-1")) { | 
 | 
                return (givenAlg.equalsIgnoreCase("SHA") | 
 | 
                        || givenAlg.equalsIgnoreCase("SHA1")); | 
 | 
            } else { | 
 | 
                StringBuilder sb = new StringBuilder(givenAlg);  | 
 | 
                  | 
 | 
                if (givenAlg.regionMatches(true, 0, "SHA", 0, 3)) { | 
 | 
                    givenAlg = sb.insert(3, "-").toString();  | 
 | 
                    return stdAlg.equalsIgnoreCase(givenAlg);  | 
 | 
                } else { | 
 | 
                    throw new ProviderException("Unsupported digest algorithm " | 
 | 
                            + givenAlg);  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    private final Token token;  | 
 | 
 | 
 | 
      | 
 | 
    private final String algorithm;  | 
 | 
 | 
 | 
      | 
 | 
    private static final String KEY_ALGO = "RSA";  | 
 | 
 | 
 | 
      | 
 | 
    private final CK_MECHANISM mechanism;  | 
 | 
 | 
 | 
      | 
 | 
    private final int type;  | 
 | 
 | 
 | 
      | 
 | 
    private P11Key p11Key = null;  | 
 | 
 | 
 | 
      | 
 | 
    private PSSParameterSpec sigParams = null;  | 
 | 
    private boolean isActive = false;  | 
 | 
 | 
 | 
      | 
 | 
    private final String mdAlg;  | 
 | 
 | 
 | 
      | 
 | 
    private MessageDigest md = null;  | 
 | 
 | 
 | 
      | 
 | 
    private Session session;  | 
 | 
 | 
 | 
      | 
 | 
    private int mode;  | 
 | 
 | 
 | 
      | 
 | 
    private boolean initialized = false;  | 
 | 
 | 
 | 
      | 
 | 
    private final byte[] buffer = new byte[1];  | 
 | 
 | 
 | 
      | 
 | 
    private int bytesProcessed = 0;  | 
 | 
 | 
 | 
      | 
 | 
    private final static int M_SIGN   = 1;  | 
 | 
      | 
 | 
    private final static int M_VERIFY = 2;  | 
 | 
 | 
 | 
      | 
 | 
    private final static int T_DIGEST = 1;  | 
 | 
      | 
 | 
    private final static int T_UPDATE = 2;  | 
 | 
 | 
 | 
    P11PSSSignature(Token token, String algorithm, long mechId)  | 
 | 
            throws NoSuchAlgorithmException, PKCS11Exception { | 
 | 
        super();  | 
 | 
        this.token = token;  | 
 | 
        this.algorithm = algorithm;  | 
 | 
        this.mechanism = new CK_MECHANISM(mechId);  | 
 | 
        int idx = algorithm.indexOf("with"); | 
 | 
        this.mdAlg = (idx == -1? null : algorithm.substring(0, idx));  | 
 | 
        switch ((int)mechId) { | 
 | 
        case (int)CKM_SHA1_RSA_PKCS_PSS:  | 
 | 
        case (int)CKM_SHA224_RSA_PKCS_PSS:  | 
 | 
        case (int)CKM_SHA256_RSA_PKCS_PSS:  | 
 | 
        case (int)CKM_SHA384_RSA_PKCS_PSS:  | 
 | 
        case (int)CKM_SHA512_RSA_PKCS_PSS:  | 
 | 
            type = T_UPDATE;  | 
 | 
            break;  | 
 | 
        case (int)CKM_RSA_PKCS_PSS:  | 
 | 
            type = T_DIGEST;  | 
 | 
            break;  | 
 | 
        default:  | 
 | 
            throw new ProviderException("Unsupported mechanism: " + mechId); | 
 | 
        }  | 
 | 
        this.md = null;  | 
 | 
    }  | 
 | 
 | 
 | 
    private void ensureInitialized() throws SignatureException { | 
 | 
        token.ensureValid();  | 
 | 
        if (this.p11Key == null) { | 
 | 
            throw new SignatureException("Missing key"); | 
 | 
        }  | 
 | 
        if (this.sigParams == null) { | 
 | 
            if (this.mdAlg == null) { | 
 | 
                  | 
 | 
                throw new SignatureException  | 
 | 
                    ("Parameters required for RSASSA-PSS signature"); | 
 | 
            } else { | 
 | 
                int saltLen = DIGEST_LENGTHS.get(this.mdAlg).intValue();  | 
 | 
                  | 
 | 
                this.sigParams = new PSSParameterSpec(this.mdAlg,  | 
 | 
                        "MGF1", new MGF1ParameterSpec(this.mdAlg),  | 
 | 
                        saltLen, PSSParameterSpec.TRAILER_FIELD_BC);  | 
 | 
                this.mechanism.setParameter(new CK_RSA_PKCS_PSS_PARAMS(  | 
 | 
                        this.mdAlg, "MGF1", this.mdAlg,  | 
 | 
                        DIGEST_LENGTHS.get(this.mdAlg).intValue()));  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        if (initialized == false) { | 
 | 
            initialize();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    private void reset(boolean doCancel) { | 
 | 
        if (!initialized) { | 
 | 
            return;  | 
 | 
        }  | 
 | 
        initialized = false;  | 
 | 
 | 
 | 
        try { | 
 | 
            if (session == null) { | 
 | 
                return;  | 
 | 
            }  | 
 | 
 | 
 | 
            if (doCancel && token.explicitCancel) { | 
 | 
                cancelOperation();  | 
 | 
            }  | 
 | 
        } finally { | 
 | 
            p11Key.releaseKeyID();  | 
 | 
            mechanism.freeHandle();  | 
 | 
            session = token.releaseSession(session);  | 
 | 
            isActive = false;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private void cancelOperation() { | 
 | 
        token.ensureValid();  | 
 | 
        if (DEBUG) System.out.print("Cancelling operation"); | 
 | 
 | 
 | 
        // cancel operation by finishing it; avoid killSession as some  | 
 | 
          | 
 | 
        try { | 
 | 
            if (mode == M_SIGN) { | 
 | 
                if (type == T_UPDATE) { | 
 | 
                    if (DEBUG) System.out.println(" by C_SignFinal"); | 
 | 
                    token.p11.C_SignFinal(session.id(), 0);  | 
 | 
                } else { | 
 | 
                    byte[] digest =  | 
 | 
                        (md == null? new byte[0] : md.digest());  | 
 | 
                    if (DEBUG) System.out.println(" by C_Sign"); | 
 | 
                    token.p11.C_Sign(session.id(), digest);  | 
 | 
                }  | 
 | 
            } else {  | 
 | 
                byte[] signature =  | 
 | 
                    new byte[(p11Key.length() + 7) >> 3];  | 
 | 
                if (type == T_UPDATE) { | 
 | 
                    if (DEBUG) System.out.println(" by C_VerifyFinal"); | 
 | 
                    token.p11.C_VerifyFinal(session.id(), signature);  | 
 | 
                } else { | 
 | 
                    byte[] digest =  | 
 | 
                        (md == null? new byte[0] : md.digest());  | 
 | 
                    if (DEBUG) System.out.println(" by C_Verify"); | 
 | 
                    token.p11.C_Verify(session.id(), digest, signature);  | 
 | 
                }  | 
 | 
            }  | 
 | 
        } catch (PKCS11Exception e) { | 
 | 
            if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) { | 
 | 
                // Cancel Operation may be invoked after an error on a PKCS#11  | 
 | 
                // call. If the operation inside the token was already cancelled,  | 
 | 
                // do not fail here. This is part of a defensive mechanism for  | 
 | 
                  | 
 | 
                return;  | 
 | 
            }  | 
 | 
            if (mode == M_SIGN) { | 
 | 
                throw new ProviderException("cancel failed", e); | 
 | 
            }  | 
 | 
            // ignore failure for verification  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    private void initialize() { | 
 | 
        if (DEBUG) System.out.println("Initializing"); | 
 | 
 | 
 | 
        if (p11Key == null) { | 
 | 
            throw new ProviderException(  | 
 | 
                    "No Key found, call initSign/initVerify first");  | 
 | 
        }  | 
 | 
 | 
 | 
        long keyID = p11Key.getKeyID();  | 
 | 
        try { | 
 | 
            if (session == null) { | 
 | 
                session = token.getOpSession();  | 
 | 
            }  | 
 | 
            if (mode == M_SIGN) { | 
 | 
                token.p11.C_SignInit(session.id(), mechanism, keyID);  | 
 | 
            } else { | 
 | 
                token.p11.C_VerifyInit(session.id(), mechanism, keyID);  | 
 | 
            }  | 
 | 
        } catch (PKCS11Exception e) { | 
 | 
            p11Key.releaseKeyID();  | 
 | 
            session = token.releaseSession(session);  | 
 | 
            throw new ProviderException("Initialization failed", e); | 
 | 
        }  | 
 | 
        if (bytesProcessed != 0) { | 
 | 
            bytesProcessed = 0;  | 
 | 
            if (md != null) { | 
 | 
                md.reset();  | 
 | 
            }  | 
 | 
        }  | 
 | 
        initialized = true;  | 
 | 
        isActive = false;  | 
 | 
        if (DEBUG) System.out.println("Initialized"); | 
 | 
    }  | 
 | 
 | 
 | 
    private void checkKeySize(Key key) throws InvalidKeyException { | 
 | 
        if (DEBUG) System.out.print("Checking Key"); | 
 | 
 | 
 | 
        if (!key.getAlgorithm().equals(KEY_ALGO)) { | 
 | 
            throw new InvalidKeyException("Only " + KEY_ALGO + | 
 | 
                " keys are supported");  | 
 | 
        }  | 
 | 
 | 
 | 
        CK_MECHANISM_INFO mechInfo = null;  | 
 | 
        try { | 
 | 
            mechInfo = token.getMechanismInfo(mechanism.mechanism);  | 
 | 
        } catch (PKCS11Exception e) { | 
 | 
              | 
 | 
            if (DEBUG) { | 
 | 
                System.out.println("Unexpected exception"); | 
 | 
                e.printStackTrace();  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        int keySize = 0;   | 
 | 
        if (mechInfo != null) { | 
 | 
              | 
 | 
            int minKeySize = (int) mechInfo.ulMinKeySize;  | 
 | 
            int maxKeySize = (int) mechInfo.ulMaxKeySize;  | 
 | 
            if (key instanceof P11Key) { | 
 | 
                keySize = (((P11Key) key).length() + 7) >> 3;  | 
 | 
            } else if (key instanceof RSAKey) { | 
 | 
                keySize = ((RSAKey) key).getModulus().bitLength() >> 3;  | 
 | 
            } else { | 
 | 
                throw new InvalidKeyException("Unrecognized key type " + key); | 
 | 
            }  | 
 | 
            if ((minKeySize != -1) && (keySize < minKeySize)) { | 
 | 
                throw new InvalidKeyException(KEY_ALGO +  | 
 | 
                    " key must be at least " + minKeySize + " bytes");  | 
 | 
            }  | 
 | 
            if ((maxKeySize != -1) && (keySize > maxKeySize)) { | 
 | 
                throw new InvalidKeyException(KEY_ALGO +  | 
 | 
                    " key must be at most " + maxKeySize + " bytes");  | 
 | 
            }  | 
 | 
        }  | 
 | 
        if (this.sigParams != null) { | 
 | 
            String digestAlg = this.sigParams.getDigestAlgorithm();  | 
 | 
            int sLen = this.sigParams.getSaltLength();  | 
 | 
            int hLen = DIGEST_LENGTHS.get(digestAlg).intValue();  | 
 | 
            int minKeyLen = Math.addExact(Math.addExact(sLen, hLen), 2);  | 
 | 
 | 
 | 
            if (keySize < minKeyLen) { | 
 | 
                throw new InvalidKeyException  | 
 | 
                    ("Key is too short for current params, need min " + minKeyLen); | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private void setSigParams(AlgorithmParameterSpec p)  | 
 | 
            throws InvalidAlgorithmParameterException { | 
 | 
        if (p == null) { | 
 | 
            throw new InvalidAlgorithmParameterException("PSS Parameter required"); | 
 | 
        }  | 
 | 
        if (!(p instanceof PSSParameterSpec)) { | 
 | 
            throw new InvalidAlgorithmParameterException  | 
 | 
                ("Only PSSParameterSpec is supported"); | 
 | 
        }  | 
 | 
          | 
 | 
        PSSParameterSpec params = (PSSParameterSpec) p;  | 
 | 
        if (params == this.sigParams) return;  | 
 | 
 | 
 | 
        String digestAlgorithm = params.getDigestAlgorithm();  | 
 | 
        if (this.mdAlg != null && !isDigestEqual(digestAlgorithm, this.mdAlg)) { | 
 | 
            throw new InvalidAlgorithmParameterException  | 
 | 
                    ("Digest algorithm in Signature parameters must be " + | 
 | 
                     this.mdAlg);  | 
 | 
        }  | 
 | 
        Integer digestLen = DIGEST_LENGTHS.get(digestAlgorithm);  | 
 | 
        if (digestLen == null) { | 
 | 
            throw new InvalidAlgorithmParameterException  | 
 | 
                ("Unsupported digest algorithm in Signature parameters: " + | 
 | 
                 digestAlgorithm);  | 
 | 
        }  | 
 | 
        if (!(params.getMGFAlgorithm().equalsIgnoreCase("MGF1"))) { | 
 | 
            throw new InvalidAlgorithmParameterException("Only supports MGF1"); | 
 | 
        }  | 
 | 
        if (params.getTrailerField() != PSSParameterSpec.TRAILER_FIELD_BC) { | 
 | 
            throw new InvalidAlgorithmParameterException  | 
 | 
                ("Only supports TrailerFieldBC(1)"); | 
 | 
        }  | 
 | 
        int saltLen = params.getSaltLength();  | 
 | 
        if (this.p11Key != null) { | 
 | 
            int maxSaltLen = ((this.p11Key.length() + 7) >> 3) - digestLen.intValue() - 2;  | 
 | 
 | 
 | 
            if (DEBUG) { | 
 | 
                System.out.println("Max saltLen = " + maxSaltLen); | 
 | 
                System.out.println("Curr saltLen = " + saltLen); | 
 | 
            }  | 
 | 
            if (maxSaltLen < 0 || saltLen > maxSaltLen) { | 
 | 
                throw new InvalidAlgorithmParameterException("Invalid with current key size"); | 
 | 
            }  | 
 | 
        } else { | 
 | 
            if (DEBUG) System.out.println("No key available for validating saltLen"); | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        try { | 
 | 
            this.mechanism.setParameter(  | 
 | 
                    new CK_RSA_PKCS_PSS_PARAMS(digestAlgorithm, "MGF1",  | 
 | 
                        digestAlgorithm, saltLen));  | 
 | 
            this.sigParams = params;  | 
 | 
        } catch (IllegalArgumentException iae) { | 
 | 
            throw new InvalidAlgorithmParameterException(iae);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    @Override  | 
 | 
    protected void engineInitVerify(PublicKey publicKey)  | 
 | 
            throws InvalidKeyException { | 
 | 
 | 
 | 
        if (publicKey == null) { | 
 | 
            throw new InvalidKeyException("Key must not be null"); | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        if (publicKey != p11Key) { | 
 | 
            checkKeySize(publicKey);  | 
 | 
        }  | 
 | 
 | 
 | 
        reset(true);  | 
 | 
        mode = M_VERIFY;  | 
 | 
        p11Key = P11KeyFactory.convertKey(token, publicKey, KEY_ALGO);  | 
 | 
 | 
 | 
        // For PSS, defer PKCS11 initialization calls to update/doFinal as it  | 
 | 
        // needs both key and params  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    @Override  | 
 | 
    protected void engineInitSign(PrivateKey privateKey)  | 
 | 
            throws InvalidKeyException { | 
 | 
 | 
 | 
        if (privateKey == null) { | 
 | 
            throw new InvalidKeyException("Key must not be null"); | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        if (privateKey != p11Key) { | 
 | 
            checkKeySize(privateKey);  | 
 | 
        }  | 
 | 
 | 
 | 
        reset(true);  | 
 | 
        mode = M_SIGN;  | 
 | 
        p11Key = P11KeyFactory.convertKey(token, privateKey, KEY_ALGO);  | 
 | 
 | 
 | 
        // For PSS, defer PKCS11 initialization calls to update/doFinal as it  | 
 | 
        // needs both key and params  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    @Override  | 
 | 
    protected void engineUpdate(byte b) throws SignatureException { | 
 | 
        ensureInitialized();  | 
 | 
        isActive = true;  | 
 | 
        buffer[0] = b;  | 
 | 
        engineUpdate(buffer, 0, 1);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    @Override  | 
 | 
    protected void engineUpdate(byte[] b, int ofs, int len)  | 
 | 
            throws SignatureException { | 
 | 
        ensureInitialized();  | 
 | 
        if (len == 0) { | 
 | 
            return;  | 
 | 
        }  | 
 | 
          | 
 | 
        if (len + bytesProcessed < 0) { | 
 | 
            throw new ProviderException("Processed bytes limits exceeded."); | 
 | 
        }  | 
 | 
        isActive = true;  | 
 | 
        switch (type) { | 
 | 
        case T_UPDATE:  | 
 | 
            try { | 
 | 
                if (mode == M_SIGN) { | 
 | 
                    System.out.println(this + ": Calling C_SignUpdate");  | 
 | 
                    token.p11.C_SignUpdate(session.id(), 0, b, ofs, len);  | 
 | 
                } else { | 
 | 
                    System.out.println(this + ": Calling C_VerfifyUpdate");  | 
 | 
                    token.p11.C_VerifyUpdate(session.id(), 0, b, ofs, len);  | 
 | 
                }  | 
 | 
                bytesProcessed += len;  | 
 | 
            } catch (PKCS11Exception e) { | 
 | 
                reset(false);  | 
 | 
                throw new ProviderException(e);  | 
 | 
            }  | 
 | 
            break;  | 
 | 
        case T_DIGEST:  | 
 | 
              | 
 | 
            if (md == null) { | 
 | 
                throw new ProviderException("PSS Parameters required"); | 
 | 
            }  | 
 | 
            md.update(b, ofs, len);  | 
 | 
            bytesProcessed += len;  | 
 | 
            break;  | 
 | 
        default:  | 
 | 
            throw new ProviderException("Internal error"); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    @Override  | 
 | 
    protected void engineUpdate(ByteBuffer byteBuffer) { | 
 | 
        try { | 
 | 
            ensureInitialized();  | 
 | 
        } catch (SignatureException se) { | 
 | 
            throw new ProviderException(se);  | 
 | 
        }  | 
 | 
        int len = byteBuffer.remaining();  | 
 | 
        if (len <= 0) { | 
 | 
            return;  | 
 | 
        }  | 
 | 
        isActive = true;  | 
 | 
        switch (type) { | 
 | 
        case T_UPDATE:  | 
 | 
            if (byteBuffer instanceof DirectBuffer == false) { | 
 | 
                  | 
 | 
                super.engineUpdate(byteBuffer);  | 
 | 
                return;  | 
 | 
            }  | 
 | 
            long addr = ((DirectBuffer)byteBuffer).address();  | 
 | 
            int ofs = byteBuffer.position();  | 
 | 
            try { | 
 | 
                if (mode == M_SIGN) { | 
 | 
                    System.out.println(this + ": Calling C_SignUpdate");  | 
 | 
                    token.p11.C_SignUpdate  | 
 | 
                        (session.id(), addr + ofs, null, 0, len);  | 
 | 
                } else { | 
 | 
                    System.out.println(this + ": Calling C_VerifyUpdate");  | 
 | 
                    token.p11.C_VerifyUpdate  | 
 | 
                        (session.id(), addr + ofs, null, 0, len);  | 
 | 
                }  | 
 | 
                bytesProcessed += len;  | 
 | 
                byteBuffer.position(ofs + len);  | 
 | 
            } catch (PKCS11Exception e) { | 
 | 
                reset(false);  | 
 | 
                throw new ProviderException("Update failed", e); | 
 | 
            }  | 
 | 
            break;  | 
 | 
        case T_DIGEST:  | 
 | 
              | 
 | 
            if (md == null) { | 
 | 
                throw new ProviderException("PSS Parameters required"); | 
 | 
            }  | 
 | 
            md.update(byteBuffer);  | 
 | 
            bytesProcessed += len;  | 
 | 
            break;  | 
 | 
        default:  | 
 | 
            reset(false);  | 
 | 
            throw new ProviderException("Internal error"); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    @Override  | 
 | 
    protected byte[] engineSign() throws SignatureException { | 
 | 
        ensureInitialized();  | 
 | 
        boolean doCancel = true;  | 
 | 
        if (DEBUG) System.out.print("Generating signature"); | 
 | 
        try { | 
 | 
            byte[] signature;  | 
 | 
            if (type == T_UPDATE) { | 
 | 
                if (DEBUG) System.out.println(" by C_SignFinal"); | 
 | 
                signature = token.p11.C_SignFinal(session.id(), 0);  | 
 | 
            } else { | 
 | 
                if (md == null) { | 
 | 
                    throw new ProviderException("PSS Parameters required"); | 
 | 
                }  | 
 | 
                byte[] digest = md.digest();  | 
 | 
                if (DEBUG) System.out.println(" by C_Sign"); | 
 | 
                signature = token.p11.C_Sign(session.id(), digest);  | 
 | 
            }  | 
 | 
            doCancel = false;  | 
 | 
            return signature;  | 
 | 
        } catch (PKCS11Exception pe) { | 
 | 
            // As per the PKCS#11 standard, C_Sign and C_SignFinal may only  | 
 | 
            // keep the operation active on CKR_BUFFER_TOO_SMALL errors or  | 
 | 
            // successful calls to determine the output length. However,  | 
 | 
            // these cases are handled at OpenJDK's libj2pkcs11 native  | 
 | 
              | 
 | 
            doCancel = false;  | 
 | 
            throw new ProviderException(pe);  | 
 | 
        } catch (ProviderException e) { | 
 | 
            throw e;  | 
 | 
        } finally { | 
 | 
            reset(doCancel);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    @Override  | 
 | 
    protected boolean engineVerify(byte[] signature) throws SignatureException { | 
 | 
        ensureInitialized();  | 
 | 
        boolean doCancel = true;  | 
 | 
        if (DEBUG) System.out.print("Verifying signature"); | 
 | 
        try { | 
 | 
            if (type == T_UPDATE) { | 
 | 
                if (DEBUG) System.out.println(" by C_VerifyFinal"); | 
 | 
                token.p11.C_VerifyFinal(session.id(), signature);  | 
 | 
            } else { | 
 | 
                if (md == null) { | 
 | 
                    throw new ProviderException("PSS Parameters required"); | 
 | 
                }  | 
 | 
                byte[] digest = md.digest();  | 
 | 
                if (DEBUG) System.out.println(" by C_Verify"); | 
 | 
                token.p11.C_Verify(session.id(), digest, signature);  | 
 | 
            }  | 
 | 
            doCancel = false;  | 
 | 
            return true;  | 
 | 
        } catch (PKCS11Exception pe) { | 
 | 
            doCancel = false;  | 
 | 
            long errorCode = pe.getErrorCode();  | 
 | 
            if (errorCode == CKR_SIGNATURE_INVALID) { | 
 | 
                return false;  | 
 | 
            }  | 
 | 
            if (errorCode == CKR_SIGNATURE_LEN_RANGE) { | 
 | 
                  | 
 | 
                return false;  | 
 | 
            }  | 
 | 
              | 
 | 
            if (errorCode == CKR_DATA_LEN_RANGE) { | 
 | 
                return false;  | 
 | 
            }  | 
 | 
            throw new ProviderException(pe);  | 
 | 
        }  catch (ProviderException e) { | 
 | 
            throw e;  | 
 | 
        } finally { | 
 | 
            reset(doCancel);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    @SuppressWarnings("deprecation") | 
 | 
    @Override  | 
 | 
    protected void engineSetParameter(String param, Object value)  | 
 | 
            throws InvalidParameterException { | 
 | 
        throw new UnsupportedOperationException("setParameter() not supported"); | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    @Override  | 
 | 
    protected void engineSetParameter(AlgorithmParameterSpec params)  | 
 | 
            throws InvalidAlgorithmParameterException { | 
 | 
          | 
 | 
        if (isActive) { | 
 | 
            throw new ProviderException  | 
 | 
                ("Cannot set parameters during operations"); | 
 | 
        }  | 
 | 
        setSigParams(params);  | 
 | 
        if (type == T_DIGEST) { | 
 | 
            try { | 
 | 
                this.md = MessageDigest.getInstance(sigParams.getDigestAlgorithm());  | 
 | 
            } catch (NoSuchAlgorithmException nsae) { | 
 | 
                throw new InvalidAlgorithmParameterException(nsae);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    @SuppressWarnings("deprecation") | 
 | 
    @Override  | 
 | 
    protected Object engineGetParameter(String param)  | 
 | 
            throws InvalidParameterException { | 
 | 
        throw new UnsupportedOperationException("getParameter() not supported"); | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    @Override  | 
 | 
    protected AlgorithmParameters engineGetParameters() { | 
 | 
        if (this.sigParams != null) { | 
 | 
            try { | 
 | 
                AlgorithmParameters ap = AlgorithmParameters.getInstance("RSASSA-PSS"); | 
 | 
                ap.init(this.sigParams);  | 
 | 
                return ap;  | 
 | 
            } catch (GeneralSecurityException e) { | 
 | 
                throw new RuntimeException(e);  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return null;  | 
 | 
    }  | 
 | 
}  |