Blame SOURCES/jdk8236512-pkcs11_incorrrect_session_closure.patch

0f3be5
# HG changeset patch
0f3be5
# User valeriep
0f3be5
# Date 1581468987 0
0f3be5
#      Wed Feb 12 00:56:27 2020 +0000
0f3be5
# Node ID e47d22d82b0464720ccb7641e290080972b6ce88
0f3be5
# Parent  5c41dc4c48f85e5a1e1ce6e3836b54674f273367
0f3be5
8236512: PKCS11 Connection closed after Cipher.doFinal and NoPadding
0f3be5
Summary: Removed killSession() calls in certain impl classes when cancelling operations
0f3be5
Reviewed-by: xuelei
0f3be5
0f3be5
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11AEADCipher.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11AEADCipher.java
0f3be5
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11AEADCipher.java
0f3be5
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11AEADCipher.java
0f3be5
@@ -1,4 +1,5 @@
0f3be5
-/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
0f3be5
+/*
0f3be5
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
0f3be5
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0f3be5
  *
0f3be5
  * This code is free software; you can redistribute it and/or modify it
0f3be5
@@ -334,25 +335,25 @@
0f3be5
     }
0f3be5
 
0f3be5
     private void cancelOperation() {
0f3be5
+        // cancel operation by finishing it; avoid killSession as some
0f3be5
+        // hardware vendors may require re-login
0f3be5
+        int bufLen = doFinalLength(0);
0f3be5
+        byte[] buffer = new byte[bufLen];
0f3be5
+        byte[] in = dataBuffer.toByteArray();
0f3be5
+        int inLen = in.length;
0f3be5
         try {
0f3be5
-            if (session.hasObjects() == false) {
0f3be5
-                session = token.killSession(session);
0f3be5
-                return;
0f3be5
+            if (encrypt) {
0f3be5
+                token.p11.C_Encrypt(session.id(), 0, in, 0, inLen,
0f3be5
+                        0, buffer, 0, bufLen);
0f3be5
             } else {
0f3be5
-                // cancel operation by finishing it
0f3be5
-                int bufLen = doFinalLength(0);
0f3be5
-                byte[] buffer = new byte[bufLen];
0f3be5
-
0f3be5
-                if (encrypt) {
0f3be5
-                    token.p11.C_Encrypt(session.id(), 0, buffer, 0, bufLen,
0f3be5
-                            0, buffer, 0, bufLen);
0f3be5
-                } else {
0f3be5
-                    token.p11.C_Decrypt(session.id(), 0, buffer, 0, bufLen,
0f3be5
-                            0, buffer, 0, bufLen);
0f3be5
-                }
0f3be5
+                token.p11.C_Decrypt(session.id(), 0, in, 0, inLen,
0f3be5
+                        0, buffer, 0, bufLen);
0f3be5
             }
0f3be5
         } catch (PKCS11Exception e) {
0f3be5
-            throw new ProviderException("Cancel failed", e);
0f3be5
+            if (encrypt) {
0f3be5
+                throw new ProviderException("Cancel failed", e);
0f3be5
+            }
0f3be5
+            // ignore failure for decryption
0f3be5
         }
0f3be5
     }
0f3be5
 
0f3be5
@@ -434,18 +435,21 @@
0f3be5
         if (!initialized) {
0f3be5
             return;
0f3be5
         }
0f3be5
+        initialized = false;
0f3be5
+
0f3be5
         try {
0f3be5
             if (session == null) {
0f3be5
                 return;
0f3be5
             }
0f3be5
+
0f3be5
             if (doCancel && token.explicitCancel) {
0f3be5
                 cancelOperation();
0f3be5
             }
0f3be5
         } finally {
0f3be5
             p11Key.releaseKeyID();
0f3be5
             session = token.releaseSession(session);
0f3be5
+            dataBuffer.reset();
0f3be5
         }
0f3be5
-        initialized = false;
0f3be5
     }
0f3be5
 
0f3be5
     // see JCE spec
0f3be5
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java
0f3be5
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java
0f3be5
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java
0f3be5
@@ -1,5 +1,5 @@
0f3be5
 /*
0f3be5
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
0f3be5
+ * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
0f3be5
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0f3be5
  *
0f3be5
  * This code is free software; you can redistribute it and/or modify it
0f3be5
@@ -409,10 +409,12 @@
0f3be5
             return;
0f3be5
         }
0f3be5
         initialized = false;
0f3be5
+
0f3be5
         try {
0f3be5
             if (session == null) {
0f3be5
                 return;
0f3be5
             }
0f3be5
+
0f3be5
             if (doCancel && token.explicitCancel) {
0f3be5
                 cancelOperation();
0f3be5
             }
0f3be5
@@ -426,22 +428,21 @@
0f3be5
 
0f3be5
     private void cancelOperation() {
0f3be5
         token.ensureValid();
0f3be5
-        if (session.hasObjects() == false) {
0f3be5
-            session = token.killSession(session);
0f3be5
-            return;
0f3be5
-        } else {
0f3be5
-            try {
0f3be5
-                // cancel operation by finishing it
0f3be5
-                int bufLen = doFinalLength(0);
0f3be5
-                byte[] buffer = new byte[bufLen];
0f3be5
-                if (encrypt) {
0f3be5
-                    token.p11.C_EncryptFinal(session.id(), 0, buffer, 0, bufLen);
0f3be5
-                } else {
0f3be5
-                    token.p11.C_DecryptFinal(session.id(), 0, buffer, 0, bufLen);
0f3be5
-                }
0f3be5
-            } catch (PKCS11Exception e) {
0f3be5
+        // cancel operation by finishing it; avoid killSession as some
0f3be5
+        // hardware vendors may require re-login
0f3be5
+        try {
0f3be5
+            int bufLen = doFinalLength(0);
0f3be5
+            byte[] buffer = new byte[bufLen];
0f3be5
+            if (encrypt) {
0f3be5
+                token.p11.C_EncryptFinal(session.id(), 0, buffer, 0, bufLen);
0f3be5
+            } else {
0f3be5
+                token.p11.C_DecryptFinal(session.id(), 0, buffer, 0, bufLen);
0f3be5
+            }
0f3be5
+        } catch (PKCS11Exception e) {
0f3be5
+            if (encrypt) {
0f3be5
                 throw new ProviderException("Cancel failed", e);
0f3be5
             }
0f3be5
+            // ignore failure for decryption
0f3be5
         }
0f3be5
     }
0f3be5
 
0f3be5
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Mac.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Mac.java
0f3be5
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Mac.java
0f3be5
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Mac.java
0f3be5
@@ -1,5 +1,5 @@
0f3be5
 /*
0f3be5
- * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
0f3be5
+ * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
0f3be5
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0f3be5
  *
0f3be5
  * This code is free software; you can redistribute it and/or modify it
0f3be5
@@ -124,10 +124,12 @@
0f3be5
             return;
0f3be5
         }
0f3be5
         initialized = false;
0f3be5
+
0f3be5
         try {
0f3be5
             if (session == null) {
0f3be5
                 return;
0f3be5
             }
0f3be5
+
0f3be5
             if (doCancel && token.explicitCancel) {
0f3be5
                 cancelOperation();
0f3be5
             }
0f3be5
@@ -139,15 +141,12 @@
0f3be5
 
0f3be5
     private void cancelOperation() {
0f3be5
         token.ensureValid();
0f3be5
-        if (session.hasObjects() == false) {
0f3be5
-            session = token.killSession(session);
0f3be5
-            return;
0f3be5
-        } else {
0f3be5
-            try {
0f3be5
-                token.p11.C_SignFinal(session.id(), 0);
0f3be5
-            } catch (PKCS11Exception e) {
0f3be5
-                throw new ProviderException("Cancel failed", e);
0f3be5
-            }
0f3be5
+        // cancel operation by finishing it; avoid killSession as some
0f3be5
+        // hardware vendors may require re-login
0f3be5
+        try {
0f3be5
+            token.p11.C_SignFinal(session.id(), 0);
0f3be5
+        } catch (PKCS11Exception e) {
0f3be5
+            throw new ProviderException("Cancel failed", e);
0f3be5
         }
0f3be5
     }
0f3be5
 
0f3be5
@@ -209,7 +208,6 @@
0f3be5
             ensureInitialized();
0f3be5
             return token.p11.C_SignFinal(session.id(), 0);
0f3be5
         } catch (PKCS11Exception e) {
0f3be5
-            reset(true);
0f3be5
             throw new ProviderException("doFinal() failed", e);
0f3be5
         } finally {
0f3be5
             reset(false);
0f3be5
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11PSSSignature.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11PSSSignature.java
0f3be5
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11PSSSignature.java
0f3be5
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11PSSSignature.java
0f3be5
@@ -1,5 +1,5 @@
0f3be5
 /*
0f3be5
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
0f3be5
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
0f3be5
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0f3be5
  *
0f3be5
  * This code is free software; you can redistribute it and/or modify it
0f3be5
@@ -223,10 +223,12 @@
0f3be5
             return;
0f3be5
         }
0f3be5
         initialized = false;
0f3be5
+
0f3be5
         try {
0f3be5
             if (session == null) {
0f3be5
                 return;
0f3be5
             }
0f3be5
+
0f3be5
             if (doCancel && token.explicitCancel) {
0f3be5
                 cancelOperation();
0f3be5
             }
0f3be5
@@ -242,14 +244,10 @@
0f3be5
         token.ensureValid();
0f3be5
         if (DEBUG) System.out.print("Cancelling operation");
0f3be5
 
0f3be5
-        if (session.hasObjects() == false) {
0f3be5
-            if (DEBUG) System.out.println(" by killing session");
0f3be5
-            session = token.killSession(session);
0f3be5
-            return;
0f3be5
-        }
0f3be5
-        // "cancel" operation by finishing it
0f3be5
-        if (mode == M_SIGN) {
0f3be5
-            try {
0f3be5
+        // cancel operation by finishing it; avoid killSession as some
0f3be5
+        // hardware vendors may require re-login
0f3be5
+        try {
0f3be5
+            if (mode == M_SIGN) {
0f3be5
                 if (type == T_UPDATE) {
0f3be5
                     if (DEBUG) System.out.println(" by C_SignFinal");
0f3be5
                     token.p11.C_SignFinal(session.id(), 0);
0f3be5
@@ -259,11 +257,7 @@
0f3be5
                     if (DEBUG) System.out.println(" by C_Sign");
0f3be5
                     token.p11.C_Sign(session.id(), digest);
0f3be5
                 }
0f3be5
-            } catch (PKCS11Exception e) {
0f3be5
-                throw new ProviderException("cancel failed", e);
0f3be5
-            }
0f3be5
-        } else { // M_VERIFY
0f3be5
-            try {
0f3be5
+            } else { // M_VERIFY
0f3be5
                 byte[] signature =
0f3be5
                     new byte[(p11Key.length() + 7) >> 3];
0f3be5
                 if (type == T_UPDATE) {
0f3be5
@@ -275,10 +269,12 @@
0f3be5
                     if (DEBUG) System.out.println(" by C_Verify");
0f3be5
                     token.p11.C_Verify(session.id(), digest, signature);
0f3be5
                 }
0f3be5
-            } catch (PKCS11Exception e) {
0f3be5
-                // will fail since the signature is incorrect
0f3be5
-                // XXX check error code
0f3be5
             }
0f3be5
+        } catch (PKCS11Exception e) {
0f3be5
+            if (mode == M_SIGN) {
0f3be5
+                throw new ProviderException("cancel failed", e);
0f3be5
+            }
0f3be5
+            // ignore failure for verification
0f3be5
         }
0f3be5
     }
0f3be5
 
0f3be5
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11RSACipher.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11RSACipher.java
0f3be5
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11RSACipher.java
0f3be5
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11RSACipher.java
0f3be5
@@ -1,5 +1,5 @@
0f3be5
 /*
0f3be5
- * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
0f3be5
+ * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
0f3be5
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0f3be5
  *
0f3be5
  * This code is free software; you can redistribute it and/or modify it
0f3be5
@@ -247,10 +247,12 @@
0f3be5
             return;
0f3be5
         }
0f3be5
         initialized = false;
0f3be5
+
0f3be5
         try {
0f3be5
             if (session == null) {
0f3be5
                 return;
0f3be5
             }
0f3be5
+
0f3be5
             if (doCancel && token.explicitCancel) {
0f3be5
                 cancelOperation();
0f3be5
             }
0f3be5
@@ -264,36 +266,33 @@
0f3be5
     // state variables such as "initialized"
0f3be5
     private void cancelOperation() {
0f3be5
         token.ensureValid();
0f3be5
-        if (session.hasObjects() == false) {
0f3be5
-            session = token.killSession(session);
0f3be5
-            return;
0f3be5
-        } else {
0f3be5
-            try {
0f3be5
-                PKCS11 p11 = token.p11;
0f3be5
-                int inLen = maxInputSize;
0f3be5
-                int outLen = buffer.length;
0f3be5
-                long sessId = session.id();
0f3be5
-                switch (mode) {
0f3be5
-                case MODE_ENCRYPT:
0f3be5
-                    p11.C_Encrypt(sessId, 0, buffer, 0, inLen, 0, buffer, 0, outLen);
0f3be5
-                    break;
0f3be5
-                case MODE_DECRYPT:
0f3be5
-                    p11.C_Decrypt(sessId, 0, buffer, 0, inLen, 0, buffer, 0, outLen);
0f3be5
-                    break;
0f3be5
-                case MODE_SIGN:
0f3be5
-                    byte[] tmpBuffer = new byte[maxInputSize];
0f3be5
-                    p11.C_Sign(sessId, tmpBuffer);
0f3be5
-                    break;
0f3be5
-                case MODE_VERIFY:
0f3be5
-                    p11.C_VerifyRecover(sessId, buffer, 0, inLen, buffer,
0f3be5
-                            0, outLen);
0f3be5
-                    break;
0f3be5
-                default:
0f3be5
-                    throw new ProviderException("internal error");
0f3be5
-                }
0f3be5
-            } catch (PKCS11Exception e) {
0f3be5
-                // XXX ensure this always works, ignore error
0f3be5
+        // cancel operation by finishing it; avoid killSession as some
0f3be5
+        // hardware vendors may require re-login
0f3be5
+        try {
0f3be5
+            PKCS11 p11 = token.p11;
0f3be5
+            int inLen = maxInputSize;
0f3be5
+            int outLen = buffer.length;
0f3be5
+            long sessId = session.id();
0f3be5
+            switch (mode) {
0f3be5
+            case MODE_ENCRYPT:
0f3be5
+                p11.C_Encrypt(sessId, 0, buffer, 0, inLen, 0, buffer, 0, outLen);
0f3be5
+                break;
0f3be5
+            case MODE_DECRYPT:
0f3be5
+                p11.C_Decrypt(sessId, 0, buffer, 0, inLen, 0, buffer, 0, outLen);
0f3be5
+                break;
0f3be5
+            case MODE_SIGN:
0f3be5
+                byte[] tmpBuffer = new byte[maxInputSize];
0f3be5
+                p11.C_Sign(sessId, tmpBuffer);
0f3be5
+                break;
0f3be5
+            case MODE_VERIFY:
0f3be5
+                p11.C_VerifyRecover(sessId, buffer, 0, inLen, buffer,
0f3be5
+                        0, outLen);
0f3be5
+                break;
0f3be5
+            default:
0f3be5
+                throw new ProviderException("internal error");
0f3be5
             }
0f3be5
+        } catch (PKCS11Exception e) {
0f3be5
+            // XXX ensure this always works, ignore error
0f3be5
         }
0f3be5
     }
0f3be5
 
0f3be5
@@ -362,6 +361,7 @@
0f3be5
     private int implDoFinal(byte[] out, int outOfs, int outLen)
0f3be5
             throws BadPaddingException, IllegalBlockSizeException {
0f3be5
         if (bufOfs > maxInputSize) {
0f3be5
+            reset(true);
0f3be5
             throw new IllegalBlockSizeException("Data must not be longer "
0f3be5
                 + "than " + maxInputSize + " bytes");
0f3be5
         }
0f3be5
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Signature.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Signature.java
0f3be5
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Signature.java
0f3be5
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Signature.java
0f3be5
@@ -1,5 +1,5 @@
0f3be5
 /*
0f3be5
- * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
0f3be5
+ * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
0f3be5
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0f3be5
  *
0f3be5
  * This code is free software; you can redistribute it and/or modify it
0f3be5
@@ -270,10 +270,12 @@
0f3be5
             return;
0f3be5
         }
0f3be5
         initialized = false;
0f3be5
+
0f3be5
         try {
0f3be5
             if (session == null) {
0f3be5
                 return;
0f3be5
             }
0f3be5
+
0f3be5
             if (doCancel && token.explicitCancel) {
0f3be5
                 cancelOperation();
0f3be5
             }
0f3be5
@@ -284,59 +286,51 @@
0f3be5
     }
0f3be5
 
0f3be5
     private void cancelOperation() {
0f3be5
-
0f3be5
         token.ensureValid();
0f3be5
-        if (session.hasObjects() == false) {
0f3be5
-            session = token.killSession(session);
0f3be5
-            return;
0f3be5
-        } else {
0f3be5
-            // "cancel" operation by finishing it
0f3be5
-            // XXX make sure all this always works correctly
0f3be5
+        // cancel operation by finishing it; avoid killSession as some
0f3be5
+        // hardware vendors may require re-login
0f3be5
+        try {
0f3be5
             if (mode == M_SIGN) {
0f3be5
-                try {
0f3be5
-                    if (type == T_UPDATE) {
0f3be5
-                        token.p11.C_SignFinal(session.id(), 0);
0f3be5
-                    } else {
0f3be5
-                        byte[] digest;
0f3be5
-                        if (type == T_DIGEST) {
0f3be5
-                            digest = md.digest();
0f3be5
-                        } else { // T_RAW
0f3be5
-                            digest = buffer;
0f3be5
-                        }
0f3be5
-                        token.p11.C_Sign(session.id(), digest);
0f3be5
+                if (type == T_UPDATE) {
0f3be5
+                    token.p11.C_SignFinal(session.id(), 0);
0f3be5
+                } else {
0f3be5
+                    byte[] digest;
0f3be5
+                    if (type == T_DIGEST) {
0f3be5
+                        digest = md.digest();
0f3be5
+                    } else { // T_RAW
0f3be5
+                        digest = buffer;
0f3be5
                     }
0f3be5
-                } catch (PKCS11Exception e) {
0f3be5
-                    throw new ProviderException("cancel failed", e);
0f3be5
+                    token.p11.C_Sign(session.id(), digest);
0f3be5
                 }
0f3be5
             } else { // M_VERIFY
0f3be5
                 byte[] signature;
0f3be5
-                try {
0f3be5
-                    if (keyAlgorithm.equals("DSA")) {
0f3be5
-                        signature = new byte[40];
0f3be5
-                    } else {
0f3be5
-                        signature = new byte[(p11Key.length() + 7) >> 3];
0f3be5
+                if (keyAlgorithm.equals("DSA")) {
0f3be5
+                    signature = new byte[40];
0f3be5
+                } else {
0f3be5
+                    signature = new byte[(p11Key.length() + 7) >> 3];
0f3be5
+                }
0f3be5
+                if (type == T_UPDATE) {
0f3be5
+                    token.p11.C_VerifyFinal(session.id(), signature);
0f3be5
+                } else {
0f3be5
+                    byte[] digest;
0f3be5
+                    if (type == T_DIGEST) {
0f3be5
+                        digest = md.digest();
0f3be5
+                    } else { // T_RAW
0f3be5
+                        digest = buffer;
0f3be5
                     }
0f3be5
-                    if (type == T_UPDATE) {
0f3be5
-                        token.p11.C_VerifyFinal(session.id(), signature);
0f3be5
-                    } else {
0f3be5
-                        byte[] digest;
0f3be5
-                        if (type == T_DIGEST) {
0f3be5
-                            digest = md.digest();
0f3be5
-                        } else { // T_RAW
0f3be5
-                            digest = buffer;
0f3be5
-                        }
0f3be5
-                        token.p11.C_Verify(session.id(), digest, signature);
0f3be5
-                    }
0f3be5
-                } catch (PKCS11Exception e) {
0f3be5
-                    long errorCode = e.getErrorCode();
0f3be5
-                    if ((errorCode == CKR_SIGNATURE_INVALID) ||
0f3be5
-                        (errorCode == CKR_SIGNATURE_LEN_RANGE)) {
0f3be5
-                        // expected since signature is incorrect
0f3be5
-                        return;
0f3be5
-                    }
0f3be5
-                    throw new ProviderException("cancel failed", e);
0f3be5
+                    token.p11.C_Verify(session.id(), digest, signature);
0f3be5
                 }
0f3be5
             }
0f3be5
+        } catch (PKCS11Exception e) {
0f3be5
+            if (mode == M_VERIFY) {
0f3be5
+                long errorCode = e.getErrorCode();
0f3be5
+                if ((errorCode == CKR_SIGNATURE_INVALID) ||
0f3be5
+                     (errorCode == CKR_SIGNATURE_LEN_RANGE)) {
0f3be5
+                     // expected since signature is incorrect
0f3be5
+                     return;
0f3be5
+                }
0f3be5
+            }
0f3be5
+            throw new ProviderException("cancel failed", e);
0f3be5
         }
0f3be5
     }
0f3be5