From 67c2c66d6befca1236a92c68ed9a0ba55c3a3eb6 Mon Sep 17 00:00:00 2001
Date: Thu, 5 Nov 2020 22:28:14 +0800
Subject: [PATCH] 8236512: PKCS11 Connection closed after Cipher.doFinal and
 NoPadding

Summary: security-libs : Removed killSession() calls in certain impl classes when cancelling operations
LLT: N/A
Bug url: https://bugs.openjdk.java.net/browse/JDK-8236512
---
 .../classes/sun/security/pkcs11/P11AEADCipher.java | 38 +++++-----
 .../classes/sun/security/pkcs11/P11Cipher.java     | 31 ++++----
 .../share/classes/sun/security/pkcs11/P11Mac.java  | 20 +++---
 .../sun/security/pkcs11/P11PSSSignature.java       | 30 ++++----
 .../classes/sun/security/pkcs11/P11RSACipher.java  | 60 ++++++++--------
 .../classes/sun/security/pkcs11/P11Signature.java  | 82 ++++++++++------------
 6 files changed, 127 insertions(+), 134 deletions(-)

diff --git a/jdk/src/share/classes/sun/security/pkcs11/P11AEADCipher.java b/jdk/src/share/classes/sun/security/pkcs11/P11AEADCipher.java
index bfd00046c..5af9c8aef 100644
--- a/jdk/src/share/classes/sun/security/pkcs11/P11AEADCipher.java
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11AEADCipher.java
@@ -1,4 +1,5 @@
-/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+/*
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -331,25 +332,25 @@ final class P11AEADCipher extends CipherSpi {
     }
 
     private void cancelOperation() {
+        // cancel operation by finishing it; avoid killSession as some
+        // hardware vendors may require re-login
+        int bufLen = doFinalLength(0);
+        byte[] buffer = new byte[bufLen];
+        byte[] in = dataBuffer.toByteArray();
+        int inLen = in.length;
         try {
-            if (session.hasObjects() == false) {
-                session = token.killSession(session);
-                return;
+            if (encrypt) {
+                token.p11.C_Encrypt(session.id(), 0, in, 0, inLen,
+                        0, buffer, 0, bufLen);
             } else {
-                // cancel operation by finishing it
-                int bufLen = doFinalLength(0);
-                byte[] buffer = new byte[bufLen];
-
-                if (encrypt) {
-                    token.p11.C_Encrypt(session.id(), 0, buffer, 0, bufLen,
-                            0, buffer, 0, bufLen);
-                } else {
-                    token.p11.C_Decrypt(session.id(), 0, buffer, 0, bufLen,
-                            0, buffer, 0, bufLen);
-                }
+                token.p11.C_Decrypt(session.id(), 0, in, 0, inLen,
+                        0, buffer, 0, bufLen);
             }
         } catch (PKCS11Exception e) {
-            throw new ProviderException("Cancel failed", e);
+            if (encrypt) {
+                throw new ProviderException("Cancel failed", e);
+            }
+            // ignore failure for decryption
         }
     }
 
@@ -432,18 +433,21 @@ final class P11AEADCipher extends CipherSpi {
         if (!initialized) {
             return;
         }
+        initialized = false;
+
         try {
             if (session == null) {
                 return;
             }
+
             if (doCancel && token.explicitCancel) {
                 cancelOperation();
             }
         } finally {
             p11Key.releaseKeyID();
             session = token.releaseSession(session);
+            dataBuffer.reset();
         }
-        initialized = false;
     }
 
     // see JCE spec
diff --git a/jdk/src/share/classes/sun/security/pkcs11/P11Cipher.java b/jdk/src/share/classes/sun/security/pkcs11/P11Cipher.java
index 9837f12a5..8f2620e13 100644
--- a/jdk/src/share/classes/sun/security/pkcs11/P11Cipher.java
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11Cipher.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -409,10 +409,12 @@ final class P11Cipher extends CipherSpi {
             return;
         }
         initialized = false;
+
         try {
             if (session == null) {
                 return;
             }
+
             if (doCancel && token.explicitCancel) {
                 cancelOperation();
             }
@@ -426,22 +428,21 @@ final class P11Cipher extends CipherSpi {
 
     private void cancelOperation() {
         token.ensureValid();
-        if (session.hasObjects() == false) {
-            session = token.killSession(session);
-            return;
-        } else {
-            try {
-                // cancel operation by finishing it
-                int bufLen = doFinalLength(0);
-                byte[] buffer = new byte[bufLen];
-                if (encrypt) {
-                    token.p11.C_EncryptFinal(session.id(), 0, buffer, 0, bufLen);
-                } else {
-                    token.p11.C_DecryptFinal(session.id(), 0, buffer, 0, bufLen);
-                }
-            } catch (PKCS11Exception e) {
+        // cancel operation by finishing it; avoid killSession as some
+        // hardware vendors may require re-login
+        try {
+            int bufLen = doFinalLength(0);
+            byte[] buffer = new byte[bufLen];
+            if (encrypt) {
+                token.p11.C_EncryptFinal(session.id(), 0, buffer, 0, bufLen);
+            } else {
+                token.p11.C_DecryptFinal(session.id(), 0, buffer, 0, bufLen);
+            }
+        } catch (PKCS11Exception e) {
+            if (encrypt) {
                 throw new ProviderException("Cancel failed", e);
             }
+            // ignore failure for decryption
         }
     }
 
diff --git a/jdk/src/share/classes/sun/security/pkcs11/P11Mac.java b/jdk/src/share/classes/sun/security/pkcs11/P11Mac.java
index 56d0b1c70..7d80bcb90 100644
--- a/jdk/src/share/classes/sun/security/pkcs11/P11Mac.java
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11Mac.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -122,10 +122,12 @@ final class P11Mac extends MacSpi {
             return;
         }
         initialized = false;
+
         try {
             if (session == null) {
                 return;
             }
+
             if (doCancel && token.explicitCancel) {
                 cancelOperation();
             }
@@ -137,15 +139,12 @@ final class P11Mac extends MacSpi {
 
     private void cancelOperation() {
         token.ensureValid();
-        if (session.hasObjects() == false) {
-            session = token.killSession(session);
-            return;
-        } else {
-            try {
-                token.p11.C_SignFinal(session.id(), 0);
-            } catch (PKCS11Exception e) {
-                throw new ProviderException("Cancel failed", e);
-            }
+        // cancel operation by finishing it; avoid killSession as some
+        // hardware vendors may require re-login
+        try {
+            token.p11.C_SignFinal(session.id(), 0);
+        } catch (PKCS11Exception e) {
+            throw new ProviderException("Cancel failed", e);
         }
     }
 
@@ -207,7 +206,6 @@ final class P11Mac extends MacSpi {
             ensureInitialized();
             return token.p11.C_SignFinal(session.id(), 0);
         } catch (PKCS11Exception e) {
-            reset(true);
             throw new ProviderException("doFinal() failed", e);
         } finally {
             reset(false);
diff --git a/jdk/src/share/classes/sun/security/pkcs11/P11PSSSignature.java b/jdk/src/share/classes/sun/security/pkcs11/P11PSSSignature.java
index c0f48715d..d172108fc 100644
--- a/jdk/src/share/classes/sun/security/pkcs11/P11PSSSignature.java
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11PSSSignature.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -223,10 +223,12 @@ final class P11PSSSignature extends SignatureSpi {
             return;
         }
         initialized = false;
+
         try {
             if (session == null) {
                 return;
             }
+
             if (doCancel && token.explicitCancel) {
                 cancelOperation();
             }
@@ -242,14 +244,10 @@ final class P11PSSSignature extends SignatureSpi {
         token.ensureValid();
         if (DEBUG) System.out.print("Cancelling operation");
 
-        if (session.hasObjects() == false) {
-            if (DEBUG) System.out.println(" by killing session");
-            session = token.killSession(session);
-            return;
-        }
-        // "cancel" operation by finishing it
-        if (mode == M_SIGN) {
-            try {
+        // cancel operation by finishing it; avoid killSession as some
+        // hardware vendors may require re-login
+        try {
+            if (mode == M_SIGN) {
                 if (type == T_UPDATE) {
                     if (DEBUG) System.out.println(" by C_SignFinal");
                     token.p11.C_SignFinal(session.id(), 0);
@@ -259,11 +257,7 @@ final class P11PSSSignature extends SignatureSpi {
                     if (DEBUG) System.out.println(" by C_Sign");
                     token.p11.C_Sign(session.id(), digest);
                 }
-            } catch (PKCS11Exception e) {
-                throw new ProviderException("cancel failed", e);
-            }
-        } else { // M_VERIFY
-            try {
+            } else { // M_VERIFY
                 byte[] signature =
                     new byte[(p11Key.length() + 7) >> 3];
                 if (type == T_UPDATE) {
@@ -275,10 +269,12 @@ final class P11PSSSignature extends SignatureSpi {
                     if (DEBUG) System.out.println(" by C_Verify");
                     token.p11.C_Verify(session.id(), digest, signature);
                 }
-            } catch (PKCS11Exception e) {
-                // will fail since the signature is incorrect
-                // XXX check error code
             }
+        } catch (PKCS11Exception e) {
+            if (mode == M_SIGN) {
+                throw new ProviderException("cancel failed", e);
+            }
+            // ignore failure for verification
         }
     }
 
diff --git a/jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java b/jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java
index 421a16285..4bb629dbf 100644
--- a/jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -246,10 +246,12 @@ final class P11RSACipher extends CipherSpi {
             return;
         }
         initialized = false;
+
         try {
             if (session == null) {
                 return;
             }
+
             if (doCancel && token.explicitCancel) {
                 cancelOperation();
             }
@@ -263,36 +265,33 @@ final class P11RSACipher extends CipherSpi {
     // state variables such as "initialized"
     private void cancelOperation() {
         token.ensureValid();
-        if (session.hasObjects() == false) {
-            session = token.killSession(session);
-            return;
-        } else {
-            try {
-                PKCS11 p11 = token.p11;
-                int inLen = maxInputSize;
-                int outLen = buffer.length;
-                long sessId = session.id();
-                switch (mode) {
-                case MODE_ENCRYPT:
-                    p11.C_Encrypt(sessId, 0, buffer, 0, inLen, 0, buffer, 0, outLen);
-                    break;
-                case MODE_DECRYPT:
-                    p11.C_Decrypt(sessId, 0, buffer, 0, inLen, 0, buffer, 0, outLen);
-                    break;
-                case MODE_SIGN:
-                    byte[] tmpBuffer = new byte[maxInputSize];
-                    p11.C_Sign(sessId, tmpBuffer);
-                    break;
-                case MODE_VERIFY:
-                    p11.C_VerifyRecover(sessId, buffer, 0, inLen, buffer,
-                            0, outLen);
-                    break;
-                default:
-                    throw new ProviderException("internal error");
-                }
-            } catch (PKCS11Exception e) {
-                // XXX ensure this always works, ignore error
+        // cancel operation by finishing it; avoid killSession as some
+        // hardware vendors may require re-login
+        try {
+            PKCS11 p11 = token.p11;
+            int inLen = maxInputSize;
+            int outLen = buffer.length;
+            long sessId = session.id();
+            switch (mode) {
+            case MODE_ENCRYPT:
+                p11.C_Encrypt(sessId, 0, buffer, 0, inLen, 0, buffer, 0, outLen);
+                break;
+            case MODE_DECRYPT:
+                p11.C_Decrypt(sessId, 0, buffer, 0, inLen, 0, buffer, 0, outLen);
+                break;
+            case MODE_SIGN:
+                byte[] tmpBuffer = new byte[maxInputSize];
+                p11.C_Sign(sessId, tmpBuffer);
+                break;
+            case MODE_VERIFY:
+                p11.C_VerifyRecover(sessId, buffer, 0, inLen, buffer,
+                        0, outLen);
+                break;
+            default:
+                throw new ProviderException("internal error");
             }
+        } catch (PKCS11Exception e) {
+            // XXX ensure this always works, ignore error
         }
     }
 
@@ -361,6 +360,7 @@ final class P11RSACipher extends CipherSpi {
     private int implDoFinal(byte[] out, int outOfs, int outLen)
             throws BadPaddingException, IllegalBlockSizeException {
         if (bufOfs > maxInputSize) {
+            reset(true);
             throw new IllegalBlockSizeException("Data must not be longer "
                 + "than " + maxInputSize + " bytes");
         }
diff --git a/jdk/src/share/classes/sun/security/pkcs11/P11Signature.java b/jdk/src/share/classes/sun/security/pkcs11/P11Signature.java
index 48a49f66b..844a23d1a 100644
--- a/jdk/src/share/classes/sun/security/pkcs11/P11Signature.java
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11Signature.java
@@ -245,10 +245,12 @@ final class P11Signature extends SignatureSpi {
             return;
         }
         initialized = false;
+
         try {
             if (session == null) {
                 return;
             }
+
             if (doCancel && token.explicitCancel) {
                 cancelOperation();
             }
@@ -259,59 +261,51 @@ final class P11Signature extends SignatureSpi {
     }
 
     private void cancelOperation() {
-
         token.ensureValid();
-        if (session.hasObjects() == false) {
-            session = token.killSession(session);
-            return;
-        } else {
-            // "cancel" operation by finishing it
-            // XXX make sure all this always works correctly
+        // cancel operation by finishing it; avoid killSession as some
+        // hardware vendors may require re-login
+        try {
             if (mode == M_SIGN) {
-                try {
-                    if (type == T_UPDATE) {
-                        token.p11.C_SignFinal(session.id(), 0);
-                    } else {
-                        byte[] digest;
-                        if (type == T_DIGEST) {
-                            digest = md.digest();
-                        } else { // T_RAW
-                            digest = buffer;
-                        }
-                        token.p11.C_Sign(session.id(), digest);
+                if (type == T_UPDATE) {
+                    token.p11.C_SignFinal(session.id(), 0);
+                } else {
+                    byte[] digest;
+                    if (type == T_DIGEST) {
+                        digest = md.digest();
+                    } else { // T_RAW
+                        digest = buffer;
                     }
-                } catch (PKCS11Exception e) {
-                    throw new ProviderException("cancel failed", e);
+                    token.p11.C_Sign(session.id(), digest);
                 }
             } else { // M_VERIFY
                 byte[] signature;
-                try {
-                    if (keyAlgorithm.equals("DSA")) {
-                        signature = new byte[40];
-                    } else {
-                        signature = new byte[(p11Key.length() + 7) >> 3];
-                    }
-                    if (type == T_UPDATE) {
-                        token.p11.C_VerifyFinal(session.id(), signature);
-                    } else {
-                        byte[] digest;
-                        if (type == T_DIGEST) {
-                            digest = md.digest();
-                        } else { // T_RAW
-                            digest = buffer;
-                        }
-                        token.p11.C_Verify(session.id(), digest, signature);
-                    }
-                } catch (PKCS11Exception e) {
-                    long errorCode = e.getErrorCode();
-                    if ((errorCode == CKR_SIGNATURE_INVALID) ||
-                        (errorCode == CKR_SIGNATURE_LEN_RANGE)) {
-                        // expected since signature is incorrect
-                        return;
+                if (keyAlgorithm.equals("DSA")) {
+                    signature = new byte[40];
+                } else {
+                    signature = new byte[(p11Key.length() + 7) >> 3];
+                }
+                if (type == T_UPDATE) {
+                    token.p11.C_VerifyFinal(session.id(), signature);
+                } else {
+                    byte[] digest;
+                    if (type == T_DIGEST) {
+                        digest = md.digest();
+                    } else { // T_RAW
+                        digest = buffer;
                     }
-                    throw new ProviderException("cancel failed", e);
+                    token.p11.C_Verify(session.id(), digest, signature);
+                }
+            }
+        } catch (PKCS11Exception e) {
+            if (mode == M_VERIFY) {
+                long errorCode = e.getErrorCode();
+                if ((errorCode == CKR_SIGNATURE_INVALID) ||
+                     (errorCode == CKR_SIGNATURE_LEN_RANGE)) {
+                     // expected since signature is incorrect
+                     return;
                 }
             }
+            throw new ProviderException("cancel failed", e);
         }
     }
 
-- 
2.12.3

