changeset 290:519d4185fbe2

6572331: regression: cipher.wrap operation fails with CKR_ATTRIBUTE_VALUE_INVALID Summary: Check supported key size range and use encryption if needed Reviewed-by: andreas
author valeriep
date Thu, 20 Mar 2008 17:17:10 -0700
parents b1c8ad73578f
children be2e0a87d658
files jdk/src/share/classes/sun/security/pkcs11/P11KeyGenerator.java jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java jdk/src/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java jdk/test/sun/security/pkcs11/Cipher/TestRSACipherWrap.java
diffstat 4 files changed, 322 insertions(+), 177 deletions(-) [+]
line wrap: on
line diff
--- a/jdk/src/share/classes/sun/security/pkcs11/P11KeyGenerator.java	Thu Mar 20 16:02:23 2008 -0700
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11KeyGenerator.java	Thu Mar 20 17:17:10 2008 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2003-2008 Sun Microsystems, Inc.  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
@@ -65,10 +65,86 @@
     // are supported.
     private boolean supportBothKeySizes;
 
-    // min and max key sizes (in bits) for variable-key-length
-    // algorithms, e.g. RC4 and Blowfish
-    private int minKeySize;
-    private int maxKeySize;
+    /**
+     * Utility method for checking if the specified key size is valid
+     * and within the supported range. Return the significant key size
+     * upon successful validation.
+     * @param keyGenMech the PKCS#11 key generation mechanism.
+     * @param keySize the to-be-checked key size for this mechanism.
+     * @param token token which provides this mechanism.
+     * @return the significant key size (in bits) corresponding to the
+     * specified key size.
+     * @throws InvalidParameterException if the specified key size is invalid.
+     * @throws ProviderException if this mechanism isn't supported by SunPKCS11
+     * or underlying native impl.
+     */
+    static int checkKeySize(long keyGenMech, int keySize, Token token)
+        throws InvalidAlgorithmParameterException, ProviderException {
+        int sigKeySize;
+        switch ((int)keyGenMech) {
+            case (int)CKM_DES_KEY_GEN:
+                if ((keySize != 64) && (keySize != 56)) {
+                    throw new InvalidAlgorithmParameterException
+                            ("DES key length must be 56 bits");
+                }
+                sigKeySize = 56;
+                break;
+            case (int)CKM_DES2_KEY_GEN:
+            case (int)CKM_DES3_KEY_GEN:
+                if ((keySize == 112) || (keySize == 128)) {
+                    sigKeySize = 112;
+                } else if ((keySize == 168) || (keySize == 192)) {
+                    sigKeySize = 168;
+                } else {
+                    throw new InvalidAlgorithmParameterException
+                            ("DESede key length must be 112, or 168 bits");
+                }
+                break;
+            default:
+                // Handle all variable-key-length algorithms here
+                CK_MECHANISM_INFO info = null;
+                try {
+                    info = token.getMechanismInfo(keyGenMech);
+                } catch (PKCS11Exception p11e) {
+                    // Should never happen
+                    throw new ProviderException
+                            ("Cannot retrieve mechanism info", p11e);
+                }
+                if (info == null) {
+                    // XXX Unable to retrieve the supported key length from
+                    // the underlying native impl. Skip the checking for now.
+                    return keySize;
+                }
+                // PKCS#11 defines these to be in number of bytes except for
+                // RC4 which is in bits. However, some PKCS#11 impls still use
+                // bytes for all mechs, e.g. NSS. We try to detect this
+                // inconsistency if the minKeySize seems unreasonably small.
+                int minKeySize = (int)info.ulMinKeySize;
+                int maxKeySize = (int)info.ulMaxKeySize;
+                if (keyGenMech != CKM_RC4_KEY_GEN || minKeySize < 8) {
+                    minKeySize = (int)info.ulMinKeySize << 3;
+                    maxKeySize = (int)info.ulMaxKeySize << 3;
+                }
+                // Explicitly disallow keys shorter than 40-bits for security
+                if (minKeySize < 40) minKeySize = 40;
+                if (keySize < minKeySize || keySize > maxKeySize) {
+                    throw new InvalidAlgorithmParameterException
+                            ("Key length must be between " + minKeySize +
+                            " and " + maxKeySize + " bits");
+                }
+                if (keyGenMech == CKM_AES_KEY_GEN) {
+                    if ((keySize != 128) && (keySize != 192) &&
+                        (keySize != 256)) {
+                        throw new InvalidAlgorithmParameterException
+                                ("AES key length must be " + minKeySize +
+                                (maxKeySize >= 192? ", 192":"") +
+                                (maxKeySize >= 256? ", or 256":"") + " bits");
+                    }
+                }
+                sigKeySize = keySize;
+        }
+        return sigKeySize;
+    }
 
     P11KeyGenerator(Token token, String algorithm, long mechanism)
             throws PKCS11Exception {
@@ -85,72 +161,44 @@
             supportBothKeySizes =
                 (token.provider.config.isEnabled(CKM_DES2_KEY_GEN) &&
                  (token.getMechanismInfo(CKM_DES2_KEY_GEN) != null));
-        } else if (this.mechanism == CKM_RC4_KEY_GEN) {
-            CK_MECHANISM_INFO info = token.getMechanismInfo(mechanism);
-            // Although PKCS#11 spec documented that these are in bits,
-            // NSS, for one, uses bytes. Multiple by 8 if the number seems
-            // unreasonably small.
-            if (info.ulMinKeySize < 8) {
-                minKeySize = (int)info.ulMinKeySize << 3;
-                maxKeySize = (int)info.ulMaxKeySize << 3;
-            } else {
-                minKeySize = (int)info.ulMinKeySize;
-                maxKeySize = (int)info.ulMaxKeySize;
-            }
-            // Explicitly disallow keys shorter than 40-bits for security
-            if (minKeySize < 40) minKeySize = 40;
-        } else if (this.mechanism == CKM_BLOWFISH_KEY_GEN) {
-            CK_MECHANISM_INFO info = token.getMechanismInfo(mechanism);
-            maxKeySize = (int)info.ulMaxKeySize << 3;
-            minKeySize = (int)info.ulMinKeySize << 3;
-            // Explicitly disallow keys shorter than 40-bits for security
-            if (minKeySize < 40) minKeySize = 40;
         }
-
         setDefaultKeySize();
     }
 
     // set default keysize and also initialize keyType
     private void setDefaultKeySize() {
-        // whether to check default key size against the min and max value
-        boolean validateKeySize = false;
         switch ((int)mechanism) {
         case (int)CKM_DES_KEY_GEN:
             keySize = 64;
-            significantKeySize = 56;
             keyType = CKK_DES;
             break;
         case (int)CKM_DES2_KEY_GEN:
             keySize = 128;
-            significantKeySize = 112;
             keyType = CKK_DES2;
             break;
         case (int)CKM_DES3_KEY_GEN:
             keySize = 192;
-            significantKeySize = 168;
             keyType = CKK_DES3;
             break;
         case (int)CKM_AES_KEY_GEN:
+            keySize = 128;
             keyType = CKK_AES;
-            keySize = 128;
-            significantKeySize = 128;
             break;
         case (int)CKM_RC4_KEY_GEN:
+            keySize = 128;
             keyType = CKK_RC4;
-            keySize = 128;
-            validateKeySize = true;
             break;
         case (int)CKM_BLOWFISH_KEY_GEN:
+            keySize = 128;
             keyType = CKK_BLOWFISH;
-            keySize = 128;
-            validateKeySize = true;
             break;
         default:
             throw new ProviderException("Unknown mechanism " + mechanism);
         }
-        if (validateKeySize &&
-            ((keySize > maxKeySize) || (keySize < minKeySize))) {
-            throw new ProviderException("Unsupported key size");
+        try {
+            significantKeySize = checkKeySize(mechanism, keySize, token);
+        } catch (InvalidAlgorithmParameterException iape) {
+            throw new ProviderException("Unsupported default key size", iape);
         }
     }
 
@@ -170,57 +218,32 @@
     // see JCE spec
     protected void engineInit(int keySize, SecureRandom random) {
         token.ensureValid();
-        switch ((int)mechanism) {
-        case (int)CKM_DES_KEY_GEN:
-            if ((keySize != this.keySize) &&
-                (keySize != this.significantKeySize)) {
-                throw new InvalidParameterException
-                        ("DES key length must be 56 bits");
-            }
-            break;
-        case (int)CKM_DES2_KEY_GEN:
-        case (int)CKM_DES3_KEY_GEN:
-            long newMechanism;
-            if ((keySize == 112) || (keySize == 128)) {
-                newMechanism = CKM_DES2_KEY_GEN;
-            } else if ((keySize == 168) || (keySize == 192)) {
-                newMechanism = CKM_DES3_KEY_GEN;
-            } else {
-                throw new InvalidParameterException
-                    ("DESede key length must be 112, or 168 bits");
-            }
+        int newSignificantKeySize;
+        try {
+            newSignificantKeySize = checkKeySize(mechanism, keySize, token);
+        } catch (InvalidAlgorithmParameterException iape) {
+            throw (InvalidParameterException)
+                    (new InvalidParameterException().initCause(iape));
+        }
+        if ((mechanism == CKM_DES2_KEY_GEN) ||
+            (mechanism == CKM_DES3_KEY_GEN))  {
+            long newMechanism = (newSignificantKeySize == 112 ?
+                CKM_DES2_KEY_GEN : CKM_DES3_KEY_GEN);
             if (mechanism != newMechanism) {
                 if (supportBothKeySizes) {
                     mechanism = newMechanism;
-                    setDefaultKeySize();
+                    // Adjust keyType to reflect the mechanism change
+                    keyType = (mechanism == CKM_DES2_KEY_GEN ?
+                        CKK_DES2 : CKK_DES3);
                 } else {
                     throw new InvalidParameterException
-                        ("Only " + significantKeySize +
-                         "-bit DESede key length is supported");
+                            ("Only " + significantKeySize +
+                             "-bit DESede is supported");
                 }
             }
-            break;
-        case (int)CKM_AES_KEY_GEN:
-            if ((keySize != 128) && (keySize != 192) && (keySize != 256)) {
-                throw new InvalidParameterException
-                        ("AES key length must be 128, 192, or 256 bits");
-            }
-            this.keySize = keySize;
-            significantKeySize = keySize;
-            break;
-        case (int)CKM_RC4_KEY_GEN:
-        case (int)CKM_BLOWFISH_KEY_GEN:
-            if ((keySize < minKeySize) || (keySize > maxKeySize)) {
-                throw new InvalidParameterException
-                    (algorithm + " key length must be between " +
-                     minKeySize + " and " + maxKeySize + " bits");
-            }
-            this.keySize = keySize;
-            this.significantKeySize = keySize;
-            break;
-        default:
-            throw new ProviderException("Unknown mechanism " + mechanism);
         }
+        this.keySize = keySize;
+        this.significantKeySize = newSignificantKeySize;
     }
 
     // see JCE spec
--- a/jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java	Thu Mar 20 16:02:23 2008 -0700
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java	Thu Mar 20 17:17:10 2008 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2003-2008 Sun Microsystems, Inc.  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
@@ -98,7 +98,6 @@
         this.token = token;
         this.algorithm = "RSA";
         this.mechanism = mechanism;
-        session = token.getOpSession();
     }
 
     // modes do not make sense for RSA, but allow ECB
@@ -184,7 +183,8 @@
                 throw new InvalidKeyException
                                 ("Wrap has to be used with public keys");
             }
-            // No further setup needed for C_Wrap(). We remain uninitialized.
+            // No further setup needed for C_Wrap(). We'll initialize later if
+            // we can't use C_Wrap().
             return;
         } else if (opmode == Cipher.UNWRAP_MODE) {
             if (p11Key.isPrivate() == false) {
@@ -383,7 +383,8 @@
         return implDoFinal(out, outOfs, out.length - outOfs);
     }
 
-    private byte[] doFinal() throws BadPaddingException, IllegalBlockSizeException {
+    private byte[] doFinal() throws BadPaddingException,
+            IllegalBlockSizeException {
         byte[] t = new byte[2048];
         int n = implDoFinal(t, 0, t.length);
         byte[] out = new byte[n];
@@ -394,20 +395,37 @@
     // see JCE spec
     protected byte[] engineWrap(Key key) throws InvalidKeyException,
             IllegalBlockSizeException {
-        // XXX Note that if we cannot convert key to a key on this token,
-        // we will fail. For example, trying a wrap an AES key on a token that
-        // does not support AES.
-        // We could implement a fallback that just encrypts the encoding
-        // (assuming the key is not sensitive). For now, we are operating under
-        // the assumption that this is not necessary.
         String keyAlg = key.getAlgorithm();
-        P11Key secretKey = P11SecretKeyFactory.convertKey(token, key, keyAlg);
+        P11Key sKey = null;
+        try {
+            // The conversion may fail, e.g. trying to wrap an AES key on
+            // a token that does not support AES, or when the key size is
+            // not within the range supported by the token.
+            sKey = P11SecretKeyFactory.convertKey(token, key, keyAlg);
+        } catch (InvalidKeyException ike) {
+            byte[] toBeWrappedKey = key.getEncoded();
+            if (toBeWrappedKey == null) {
+                throw new InvalidKeyException
+                        ("wrap() failed, no encoding available", ike);
+            }
+            // Directly encrypt the key encoding when key conversion failed
+            implInit(Cipher.ENCRYPT_MODE, p11Key);
+            implUpdate(toBeWrappedKey, 0, toBeWrappedKey.length);
+            try {
+                return doFinal();
+            } catch (BadPaddingException bpe) {
+                // should not occur
+                throw new InvalidKeyException("wrap() failed", bpe);
+            } finally {
+                // Restore original mode
+                implInit(Cipher.WRAP_MODE, p11Key);
+            }
+        }
         Session s = null;
         try {
             s = token.getOpSession();
-            byte[] b = token.p11.C_WrapKey(s.id(), new CK_MECHANISM(mechanism),
-                p11Key.keyID, secretKey.keyID);
-            return b;
+            return token.p11.C_WrapKey(s.id(), new CK_MECHANISM(mechanism),
+                p11Key.keyID, sKey.keyID);
         } catch (PKCS11Exception e) {
             throw new InvalidKeyException("wrap() failed", e);
         } finally {
@@ -431,11 +449,13 @@
                 };
                 attributes = token.getAttributes
                     (O_IMPORT, CKO_SECRET_KEY, keyType, attributes);
-                long keyID = token.p11.C_UnwrapKey(s.id(), new CK_MECHANISM(mechanism),
-                    p11Key.keyID, wrappedKey, attributes);
-                return P11Key.secretKey(session, keyID, algorithm, 48 << 3, attributes);
+                long keyID = token.p11.C_UnwrapKey(s.id(),
+                        new CK_MECHANISM(mechanism), p11Key.keyID, wrappedKey,
+                        attributes);
+                return P11Key.secretKey(session, keyID, algorithm, 48 << 3,
+                        attributes);
             } catch (PKCS11Exception e) {
-                throw new InvalidKeyException("wrap() failed", e);
+                throw new InvalidKeyException("unwrap() failed", e);
             } finally {
                 token.releaseSession(s);
             }
--- a/jdk/src/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java	Thu Mar 20 16:02:23 2008 -0700
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java	Thu Mar 20 17:17:10 2008 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2003-2008 Sun Microsystems, Inc.  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
@@ -104,9 +104,9 @@
 
     /**
      * Convert an arbitrary key of algorithm into a P11Key of provider.
-     * Used engineTranslateKey(), P11Cipher.init(), and P11Mac.init().
+     * Used in engineTranslateKey(), P11Cipher.init(), and P11Mac.init().
      */
-    static P11Key convertKey(Token token, Key key, String algorithm)
+    static P11Key convertKey(Token token, Key key, String algo)
             throws InvalidKeyException {
         token.ensureValid();
         if (key == null) {
@@ -115,19 +115,19 @@
         if (key instanceof SecretKey == false) {
             throw new InvalidKeyException("Key must be a SecretKey");
         }
-        long algorithmType;
-        if (algorithm == null) {
-            algorithm = key.getAlgorithm();
-            algorithmType = getKeyType(algorithm);
+        long algoType;
+        if (algo == null) {
+            algo = key.getAlgorithm();
+            algoType = getKeyType(algo);
         } else {
-            algorithmType = getKeyType(algorithm);
+            algoType = getKeyType(algo);
             long keyAlgorithmType = getKeyType(key.getAlgorithm());
-            if (algorithmType != keyAlgorithmType) {
-                if ((algorithmType == PCKK_HMAC) || (algorithmType == PCKK_SSLMAC)) {
+            if (algoType != keyAlgorithmType) {
+                if ((algoType == PCKK_HMAC) || (algoType == PCKK_SSLMAC)) {
                     // ignore key algorithm for MACs
                 } else {
                     throw new InvalidKeyException
-                                ("Key algorithm must be " + algorithm);
+                            ("Key algorithm must be " + algo);
                 }
             }
         }
@@ -145,7 +145,7 @@
             throw new InvalidKeyException("Encoded format must be RAW");
         }
         byte[] encoded = key.getEncoded();
-        p11Key = createKey(token, encoded, algorithm, algorithmType);
+        p11Key = createKey(token, encoded, algo, algoType);
         token.secretCache.put(key, p11Key);
         return p11Key;
     }
@@ -160,77 +160,70 @@
 
     private static P11Key createKey(Token token, byte[] encoded,
             String algorithm, long keyType) throws InvalidKeyException {
-        int n = encoded.length;
-        int keyLength;
-        switch ((int)keyType) {
-        case (int)CKK_RC4:
-            if ((n < 5) || (n > 128)) {
-                throw new InvalidKeyException
-                        ("ARCFOUR key length must be between 5 and 128 bytes");
+        int n = encoded.length << 3;
+        int keyLength = n;
+        try {
+            switch ((int)keyType) {
+                case (int)CKK_DES:
+                    keyLength =
+                        P11KeyGenerator.checkKeySize(CKM_DES_KEY_GEN, n, token);
+                    fixDESParity(encoded, 0);
+                    break;
+                case (int)CKK_DES3:
+                    keyLength =
+                        P11KeyGenerator.checkKeySize(CKM_DES3_KEY_GEN, n, token);
+                    fixDESParity(encoded, 0);
+                    fixDESParity(encoded, 8);
+                    if (keyLength == 112) {
+                        keyType = CKK_DES2;
+                    } else {
+                        keyType = CKK_DES3;
+                        fixDESParity(encoded, 16);
+                    }
+                    break;
+                case (int)CKK_AES:
+                    keyLength =
+                        P11KeyGenerator.checkKeySize(CKM_AES_KEY_GEN, n, token);
+                    break;
+                case (int)CKK_RC4:
+                    keyLength =
+                        P11KeyGenerator.checkKeySize(CKM_RC4_KEY_GEN, n, token);
+                    break;
+                case (int)CKK_BLOWFISH:
+                    keyLength =
+                        P11KeyGenerator.checkKeySize(CKM_BLOWFISH_KEY_GEN, n,
+                        token);
+                    break;
+                case (int)CKK_GENERIC_SECRET:
+                case (int)PCKK_TLSPREMASTER:
+                case (int)PCKK_TLSRSAPREMASTER:
+                case (int)PCKK_TLSMASTER:
+                    keyType = CKK_GENERIC_SECRET;
+                    break;
+                case (int)PCKK_SSLMAC:
+                case (int)PCKK_HMAC:
+                    if (n == 0) {
+                        throw new InvalidKeyException
+                                ("MAC keys must not be empty");
+                    }
+                    keyType = CKK_GENERIC_SECRET;
+                    break;
+                default:
+                    throw new InvalidKeyException("Unknown algorithm " +
+                            algorithm);
             }
-            keyLength = n << 3;
-            break;
-        case (int)CKK_DES:
-            if (n != 8) {
-                throw new InvalidKeyException
-                        ("DES key length must be 8 bytes");
-            }
-            keyLength = 56;
-            fixDESParity(encoded, 0);
-            break;
-        case (int)CKK_DES3:
-            if (n == 16) {
-                keyType = CKK_DES2;
-            } else if (n == 24) {
-                keyType = CKK_DES3;
-                fixDESParity(encoded, 16);
-            } else {
-                throw new InvalidKeyException
-                        ("DESede key length must be 16 or 24 bytes");
-            }
-            fixDESParity(encoded, 0);
-            fixDESParity(encoded, 8);
-            keyLength = n * 7;
-            break;
-        case (int)CKK_AES:
-            if ((n != 16) && (n != 24) && (n != 32)) {
-                throw new InvalidKeyException
-                        ("AES key length must be 16, 24, or 32 bytes");
-            }
-            keyLength = n << 3;
-            break;
-        case (int)CKK_BLOWFISH:
-            if ((n < 5) || (n > 56)) {
-                throw new InvalidKeyException
-                        ("Blowfish key length must be between 5 and 56 bytes");
-            }
-            keyLength = n << 3;
-            break;
-        case (int)CKK_GENERIC_SECRET:
-        case (int)PCKK_TLSPREMASTER:
-        case (int)PCKK_TLSRSAPREMASTER:
-        case (int)PCKK_TLSMASTER:
-            keyType = CKK_GENERIC_SECRET;
-            keyLength = n << 3;
-            break;
-        case (int)PCKK_SSLMAC:
-        case (int)PCKK_HMAC:
-            if (n == 0) {
-                throw new InvalidKeyException
-                        ("MAC keys must not be empty");
-            }
-            keyType = CKK_GENERIC_SECRET;
-            keyLength = n << 3;
-            break;
-        default:
-            throw new InvalidKeyException("Unknown algorithm " + algorithm);
+        } catch (InvalidAlgorithmParameterException iape) {
+            throw new InvalidKeyException("Invalid key for " + algorithm,
+                    iape);
+        } catch (ProviderException pe) {
+            throw new InvalidKeyException("Could not create key", pe);
         }
         Session session = null;
         try {
             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
                 new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),
                 new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType),
-                new CK_ATTRIBUTE(CKA_VALUE, encoded),
+                new CK_ATTRIBUTE(CKA_VALUE, encoded)
             };
             attributes = token.getAttributes
                 (O_IMPORT, CKO_SECRET_KEY, keyType, attributes);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/pkcs11/Cipher/TestRSACipherWrap.java	Thu Mar 20 17:17:10 2008 -0700
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * @test
+ * @bug 6572331
+ * @summary basic test for RSA cipher key wrapping functionality
+ * @author Valerie Peng
+ * @library ..
+ */
+import java.io.*;
+import java.util.*;
+
+import java.security.*;
+
+import javax.crypto.*;
+import javax.crypto.spec.SecretKeySpec;
+
+public class TestRSACipherWrap extends PKCS11Test {
+
+    private static final String RSA_ALGO = "RSA/ECB/PKCS1Padding";
+
+    public void main(Provider p) throws Exception {
+        try {
+            Cipher.getInstance(RSA_ALGO, p);
+        } catch (GeneralSecurityException e) {
+            System.out.println("Not supported by provider, skipping");
+            return;
+        }
+        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", p);
+        kpg.initialize(1024);
+        KeyPair kp = kpg.generateKeyPair();
+        PublicKey publicKey = kp.getPublic();
+        PrivateKey privateKey = kp.getPrivate();
+
+        Cipher cipherPKCS11 = Cipher.getInstance(RSA_ALGO, p);
+        Cipher cipherJce = Cipher.getInstance(RSA_ALGO, "SunJCE");
+
+        String algos[] = {"AES", "RC2", "Blowfish"};
+        int keySizes[] = {128, 256};
+
+        for (int j = 0; j < algos.length; j++) {
+            String algorithm = algos[j];
+            KeyGenerator keygen =
+                    KeyGenerator.getInstance(algorithm);
+
+            for (int i = 0; i < keySizes.length; i++) {
+                SecretKey secretKey = null;
+                System.out.print("Generate " + keySizes[i] + "-bit " +
+                        algorithm + " key using ");
+                try {
+                    keygen.init(keySizes[i]);
+                    secretKey = keygen.generateKey();
+                    System.out.println(keygen.getProvider().getName());
+                } catch (InvalidParameterException ipe) {
+                    secretKey = new SecretKeySpec(new byte[32], algorithm);
+                    System.out.println("SecretKeySpec class");
+                }
+                test(kp, secretKey, cipherPKCS11, cipherJce);
+                test(kp, secretKey, cipherPKCS11, cipherPKCS11);
+                test(kp, secretKey, cipherJce, cipherPKCS11);
+            }
+        }
+    }
+
+    private static void test(KeyPair kp, SecretKey secretKey,
+            Cipher wrapCipher, Cipher unwrapCipher)
+            throws Exception {
+        String algo = secretKey.getAlgorithm();
+        wrapCipher.init(Cipher.WRAP_MODE, kp.getPublic());
+        byte[] wrappedKey = wrapCipher.wrap(secretKey);
+        unwrapCipher.init(Cipher.UNWRAP_MODE, kp.getPrivate());
+        Key unwrappedKey =
+                unwrapCipher.unwrap(wrappedKey, algo, Cipher.SECRET_KEY);
+
+        System.out.println("Test " + wrapCipher.getProvider().getName() +
+                "/" + unwrapCipher.getProvider().getName() + ": ");
+        if (!Arrays.equals(secretKey.getEncoded(),
+                unwrappedKey.getEncoded())) {
+            throw new Exception("Test Failed!");
+        }
+        System.out.println("Passed");
+    }
+
+    public static void main(String[] args) throws Exception {
+        main(new TestRSACipherWrap());
+    }
+}
+