Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/sun/security/pkcs11/Cipher/CancelMultipart.java
38855 views
/*1* Copyright (c) 2021, Red Hat, Inc.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 825883326* @library /lib/security ..27* @run main/othervm CancelMultipart28*/2930import java.lang.reflect.Field;31import java.nio.ByteBuffer;32import java.security.Key;33import java.security.Provider;34import java.security.ProviderException;35import javax.crypto.Cipher;36import javax.crypto.IllegalBlockSizeException;37import javax.crypto.spec.SecretKeySpec;3839public class CancelMultipart extends PKCS11Test {4041private static Provider provider;42private static Key key;4344static {45key = new SecretKeySpec(new byte[16], "AES");46}4748private static class SessionLeaker {49private LeakOperation op;50private LeakInputType type;5152SessionLeaker(LeakOperation op, LeakInputType type) {53this.op = op;54this.type = type;55}5657private void leakAndTry() throws Exception {58Cipher cipher = op.getCipher();59try {60type.doOperation(cipher,61(op instanceof LeakDecrypt ?62LeakInputType.DECRYPT_MODE :63null));64throw new Exception("PKCS11Exception expected, invalid block"65+ "size");66} catch (ProviderException | IllegalBlockSizeException e) {67// Exception expected - session returned to the SessionManager68// should be cancelled. That's what will be tested now.69}7071tryCipherInit();72}73}7475private static interface LeakOperation {76Cipher getCipher() throws Exception;77}7879private static interface LeakInputType {80static int DECRYPT_MODE = 1;81void doOperation(Cipher cipher, int mode) throws Exception;82}8384private static class LeakDecrypt implements LeakOperation {85public Cipher getCipher() throws Exception {86Cipher cipher = Cipher.getInstance(87"AES/ECB/PKCS5Padding", provider);88cipher.init(Cipher.DECRYPT_MODE, key);89return cipher;90}91}9293private static class LeakByteBuffer implements LeakInputType {94public void doOperation(Cipher cipher, int mode) throws Exception {95if (mode == DECRYPT_MODE) {96cipher.update(ByteBuffer.allocate(1), ByteBuffer.allocate(1));97cipher.doFinal(ByteBuffer.allocate(0), ByteBuffer.allocate(1));98}99}100}101102private static class LeakByteArray implements LeakInputType {103public void doOperation(Cipher cipher, int mode) throws Exception {104if (mode == DECRYPT_MODE) {105cipher.update(new byte[1]);106cipher.doFinal(new byte[1], 0, 0);107}108}109}110111public static void main(String[] args) throws Exception {112main(new CancelMultipart(), args);113}114115@Override116public void main(Provider p) throws Exception {117init(p);118119// Try multiple paths:120121executeTest(new SessionLeaker(new LeakDecrypt(), new LeakByteArray()),122"P11Cipher::implDoFinal(byte[], int, int)");123124executeTest(new SessionLeaker(new LeakDecrypt(), new LeakByteBuffer()),125"P11Cipher::implDoFinal(ByteBuffer)");126127System.out.println("TEST PASS - OK");128}129130private static void executeTest(SessionLeaker sl, String testName)131throws Exception {132try {133sl.leakAndTry();134System.out.println(testName + ": OK");135} catch (Exception e) {136System.out.println(testName + ": FAILED");137throw e;138}139}140141private static void init(Provider p) throws Exception {142provider = p;143144// The max number of sessions is 2 because, in addition to the145// operation (i.e. PKCS11::getNativeKeyInfo), a session to hold146// the P11Key object is needed.147setMaxSessions(2);148}149150/*151* This method is intended to generate pression on the number of sessions152* to be used from the NSS Software Token, so sessions with (potentially)153* active operations are reused.154*/155private static void setMaxSessions(int maxSessions) throws Exception {156Field tokenField = Class.forName("sun.security.pkcs11.SunPKCS11")157.getDeclaredField("token");158tokenField.setAccessible(true);159Field sessionManagerField = Class.forName("sun.security.pkcs11.Token")160.getDeclaredField("sessionManager");161sessionManagerField.setAccessible(true);162Field maxSessionsField = Class.forName("sun.security.pkcs11.SessionManager")163.getDeclaredField("maxSessions");164maxSessionsField.setAccessible(true);165Object sessionManagerObj = sessionManagerField.get(166tokenField.get(provider));167maxSessionsField.setInt(sessionManagerObj, maxSessions);168}169170private static void tryCipherInit() throws Exception {171Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding", provider);172173// A CKR_OPERATION_ACTIVE error may be thrown if a session was174// returned to the Session Manager with an active operation, and175// we try to initialize the Cipher using it.176//177// Given that the maximum number of sessions was forced to 2, we know178// that the session to be used here was already used in a previous179// (failed) operation. Thus, the test asserts that the operation was180// properly cancelled.181cipher.init(Cipher.ENCRYPT_MODE, key);182183// If initialization passes, finish gracefully so other paths can184// be tested under the current maximum number of sessions.185cipher.doFinal(new byte[16], 0, 0);186}187}188189190