8132082: Let OracleUcrypto accept RSAPrivateKey
authorigerasim
Fri, 04 Sep 2015 15:28:01 +0300
changeset 32472 37dabe787932
parent 32457 2050b3a0aadc
child 32473 09672cd2a4a0
8132082: Let OracleUcrypto accept RSAPrivateKey Reviewed-by: xuelei, valeriep, coffeys Contributed-by: valerie.peng@oracle.com
jdk/make/mapfiles/libj2ucrypto/mapfile-vers
jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeKey.java
jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSACipher.java
jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSAKeyFactory.java
jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSASignature.java
jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCrypto.c
jdk/test/com/oracle/security/ucrypto/CipherSignNotSupported.java
--- a/jdk/make/mapfiles/libj2ucrypto/mapfile-vers	Wed Jul 05 20:48:33 2017 +0200
+++ b/jdk/make/mapfiles/libj2ucrypto/mapfile-vers	Fri Sep 04 15:28:01 2015 +0300
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, 2015, 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
@@ -39,6 +39,7 @@
 		Java_com_oracle_security_ucrypto_NativeCipher_nativeUpdate;
 		Java_com_oracle_security_ucrypto_NativeCipher_nativeFinal;
                 Java_com_oracle_security_ucrypto_NativeKey_nativeFree;
+                Java_com_oracle_security_ucrypto_NativeKey_00024RSAPrivate_nativeInit;
                 Java_com_oracle_security_ucrypto_NativeKey_00024RSAPrivateCrt_nativeInit;
                 Java_com_oracle_security_ucrypto_NativeKey_00024RSAPublic_nativeInit;
 		Java_com_oracle_security_ucrypto_NativeRSASignature_nativeInit;
@@ -56,6 +57,7 @@
                 JavaCritical_com_oracle_security_ucrypto_NativeCipher_nativeUpdate;
                 JavaCritical_com_oracle_security_ucrypto_NativeCipher_nativeFinal;
                 JavaCritical_com_oracle_security_ucrypto_NativeKey_nativeFree;
+                JavaCritical_com_oracle_security_ucrypto_NativeKey_00024RSAPrivate_nativeInit;
                 JavaCritical_com_oracle_security_ucrypto_NativeKey_00024RSAPrivateCrt_nativeInit;
                 JavaCritical_com_oracle_security_ucrypto_NativeKey_00024RSAPublic_nativeInit;
 		JavaCritical_com_oracle_security_ucrypto_NativeRSASignature_nativeInit;
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeKey.java	Wed Jul 05 20:48:33 2017 +0200
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeKey.java	Fri Sep 04 15:28:01 2015 +0300
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, 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
@@ -31,19 +31,9 @@
 import java.lang.ref.*;
 
 import java.math.BigInteger;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.security.Key;
-import java.security.PublicKey;
-import java.security.PrivateKey;
-import java.security.KeyFactorySpi;
-import java.security.interfaces.RSAPrivateCrtKey;
-import java.security.interfaces.RSAPublicKey;
-
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
-import java.security.spec.RSAPrivateCrtKeySpec;
-import java.security.spec.RSAPublicKeySpec;
+import java.security.*;
+import java.security.interfaces.*;
+import java.security.spec.*;
 
 /**
  * Wrapper class for native keys needed for using ucrypto APIs.
@@ -87,6 +77,41 @@
         return b;
     }
 
+    static final class RSAPrivate extends NativeKey implements RSAPrivateKey {
+
+        private static final long serialVersionUID = 1622705588904302831L;
+
+        private final RSAPrivateKeySpec keySpec;
+        private final long keyId;
+
+        RSAPrivate(KeySpec keySpec) throws InvalidKeySpecException {
+            super(2);
+            long pKey = 0L;
+            if (keySpec instanceof RSAPrivateKeySpec) {
+                RSAPrivateKeySpec ks = (RSAPrivateKeySpec) keySpec;
+                BigInteger mod = ks.getModulus();
+                BigInteger privateExp =  ks.getPrivateExponent();
+                pKey = nativeInit(NativeKey.getMagnitude(mod),
+                                  NativeKey.getMagnitude(privateExp));
+            } else {
+                throw new InvalidKeySpecException("Only supports RSAPrivateKeySpec");
+            }
+            if (pKey == 0L) {
+                throw new UcryptoException("Error constructing RSA PrivateKey");
+            }
+            // track native resource clean up
+            new KeyRef(this, pKey);
+            this.keySpec = (RSAPrivateKeySpec) keySpec;
+            this.keyId = pKey;
+        }
+
+        long value() { return keyId; }
+        public BigInteger getModulus() { return keySpec.getModulus(); };
+        public BigInteger getPrivateExponent() { return keySpec.getPrivateExponent(); };
+
+        private native static long nativeInit(byte[] mod, byte[] privExp);
+    }
+
     static final class RSAPrivateCrt extends NativeKey implements RSAPrivateCrtKey {
 
         private static final long serialVersionUID = 6812507588904302831L;
@@ -119,7 +144,7 @@
                 throw new InvalidKeySpecException("Only supports RSAPrivateCrtKeySpec");
             }
             if (pKey == 0L) {
-                throw new UcryptoException("Error constructing RSA PrivateKey");
+                throw new UcryptoException("Error constructing RSA PrivateCrtKey");
             }
             // track native resource clean up
             new KeyRef(this, pKey);
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSACipher.java	Wed Jul 05 20:48:33 2017 +0200
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSACipher.java	Fri Sep 04 15:28:01 2015 +0300
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, 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
@@ -37,9 +37,11 @@
 import java.security.PublicKey;
 import java.security.PrivateKey;
 import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPrivateKeySpec;
 import java.security.spec.RSAPublicKeySpec;
 import java.security.interfaces.RSAKey;
 import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
 import java.security.interfaces.RSAPublicKey;
 
 import java.security.KeyFactory;
@@ -205,8 +207,8 @@
         // Make sure the proper opmode uses the proper key
         if (doEncrypt && (!(newKey instanceof RSAPublicKey))) {
             throw new InvalidKeyException("RSAPublicKey required for encryption");
-        } else if (!doEncrypt && (!(newKey instanceof RSAPrivateCrtKey))) {
-            throw new InvalidKeyException("RSAPrivateCrtKey required for decryption");
+        } else if (!doEncrypt && (!(newKey instanceof RSAPrivateKey))) {
+            throw new InvalidKeyException("RSAPrivateKey required for decryption");
         }
 
         NativeKey nativeKey = null;
@@ -223,17 +225,26 @@
                     throw new InvalidKeyException(ikse);
                 }
             } else {
-                RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) newKey;
                 try {
-                    nativeKey = (NativeKey) keyFactory.engineGeneratePrivate
-                        (new RSAPrivateCrtKeySpec(privateKey.getModulus(),
-                                                  privateKey.getPublicExponent(),
-                                                  privateKey.getPrivateExponent(),
-                                                  privateKey.getPrimeP(),
-                                                  privateKey.getPrimeQ(),
-                                                  privateKey.getPrimeExponentP(),
-                                                  privateKey.getPrimeExponentQ(),
-                                                  privateKey.getCrtCoefficient()));
+                    if (newKey instanceof RSAPrivateCrtKey) {
+                        RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) newKey;
+                        nativeKey = (NativeKey) keyFactory.engineGeneratePrivate
+                            (new RSAPrivateCrtKeySpec(privateKey.getModulus(),
+                                                      privateKey.getPublicExponent(),
+                                                      privateKey.getPrivateExponent(),
+                                                      privateKey.getPrimeP(),
+                                                      privateKey.getPrimeQ(),
+                                                      privateKey.getPrimeExponentP(),
+                                                      privateKey.getPrimeExponentQ(),
+                                                      privateKey.getCrtCoefficient()));
+                   } else if (newKey instanceof RSAPrivateKey) {
+                        RSAPrivateKey privateKey = (RSAPrivateKey) newKey;
+                        nativeKey = (NativeKey) keyFactory.engineGeneratePrivate
+                            (new RSAPrivateKeySpec(privateKey.getModulus(),
+                                                   privateKey.getPrivateExponent()));
+                    } else {
+                        throw new InvalidKeyException("Unsupported type of RSAPrivateKey");
+                    }
                 } catch (InvalidKeySpecException ikse) {
                     throw new InvalidKeyException(ikse);
                 }
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSAKeyFactory.java	Wed Jul 05 20:48:33 2017 +0200
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSAKeyFactory.java	Fri Sep 04 15:28:01 2015 +0300
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, 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
@@ -38,16 +38,11 @@
 import java.security.PrivateKey;
 import java.security.KeyFactorySpi;
 
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
-import java.security.spec.RSAPrivateCrtKeySpec;
-import java.security.spec.RSAPublicKeySpec;
+import java.security.spec.*;
 
 /**
  * Ucrypto-private KeyFactory class for generating native keys
- * needed for using ucrypto APIs. Given that it's not used
- * externally, it only needs to support RSAPrivateCrtKeySpec
- * and RSAPublicKeySpec objects.
+ * needed for using ucrypto APIs.
  *
  * @since 1.9
  */
@@ -56,7 +51,13 @@
     @Override
     protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
         throws InvalidKeySpecException {
-        return new NativeKey.RSAPrivateCrt(keySpec);
+        if (keySpec instanceof RSAPrivateCrtKeySpec) {
+            return new NativeKey.RSAPrivateCrt(keySpec);
+        } else if (keySpec instanceof RSAPrivateKeySpec) {
+            return new NativeKey.RSAPrivate(keySpec);
+        } else {
+            throw new InvalidKeySpecException("Unsupported key spec");
+        }
     }
 
     @Override
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSASignature.java	Wed Jul 05 20:48:33 2017 +0200
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSASignature.java	Fri Sep 04 15:28:01 2015 +0300
@@ -43,9 +43,8 @@
 
 import java.security.*;
 import java.security.interfaces.*;
-import java.security.spec.RSAPrivateCrtKeySpec;
-import java.security.spec.RSAPublicKeySpec;
-import java.security.spec.InvalidKeySpecException;
+import java.security.spec.*;
+
 import sun.nio.ch.DirectBuffer;
 import java.nio.ByteBuffer;
 
@@ -192,25 +191,31 @@
         int newSigLength = sigLength;
         // Need to check RSA key length whenever a new private key is set
         if (privateKey != key) {
-            if (privateKey instanceof RSAPrivateCrtKey) {
-                RSAPrivateCrtKey rsaPrivKey = (RSAPrivateCrtKey) privateKey;
-                BigInteger mod = rsaPrivKey.getModulus();
-                newSigLength = checkRSAKeyLength(mod);
-                try {
+            if (!(privateKey instanceof RSAPrivateKey)) {
+                throw new InvalidKeyException("RSAPrivateKey required");
+            }
+            RSAPrivateKey rsaPrivKey = (RSAPrivateKey) privateKey;
+            BigInteger mod = rsaPrivKey.getModulus();
+            newSigLength = checkRSAKeyLength(mod);
+            BigInteger pe = rsaPrivKey.getPrivateExponent();
+            try {
+                if (rsaPrivKey instanceof RSAPrivateCrtKey) {
+                    RSAPrivateCrtKey rsaPrivCrtKey = (RSAPrivateCrtKey) rsaPrivKey;
                     newKey = (NativeKey) keyFactory.engineGeneratePrivate
                         (new RSAPrivateCrtKeySpec(mod,
-                                                  rsaPrivKey.getPublicExponent(),
-                                                  rsaPrivKey.getPrivateExponent(),
-                                                  rsaPrivKey.getPrimeP(),
-                                                  rsaPrivKey.getPrimeQ(),
-                                                  rsaPrivKey.getPrimeExponentP(),
-                                                  rsaPrivKey.getPrimeExponentQ(),
-                                                  rsaPrivKey.getCrtCoefficient()));
-                } catch (InvalidKeySpecException ikse) {
-                    throw new InvalidKeyException(ikse);
+                                                  rsaPrivCrtKey.getPublicExponent(),
+                                                  pe,
+                                                  rsaPrivCrtKey.getPrimeP(),
+                                                  rsaPrivCrtKey.getPrimeQ(),
+                                                  rsaPrivCrtKey.getPrimeExponentP(),
+                                                  rsaPrivCrtKey.getPrimeExponentQ(),
+                                                  rsaPrivCrtKey.getCrtCoefficient()));
+                } else {
+                    newKey = (NativeKey) keyFactory.engineGeneratePrivate
+                           (new RSAPrivateKeySpec(mod, pe));
                 }
-            } else {
-                throw new InvalidKeyException("RSAPrivateCrtKey required");
+            } catch (InvalidKeySpecException ikse) {
+                throw new InvalidKeyException(ikse);
             }
         }
         init(true, newKey, newSigLength);
--- a/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCrypto.c	Wed Jul 05 20:48:33 2017 +0200
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/native/libj2ucrypto/nativeCrypto.c	Fri Sep 04 15:28:01 2015 +0300
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, 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
@@ -697,6 +697,86 @@
 }
 
 /*
+ * Class:     com_oracle_security_ucrypto_NativeKey_RSAPrivate
+ * Method:    nativeInit
+ * Signature: ([B[B)J
+ */
+jlong JavaCritical_com_oracle_security_ucrypto_NativeKey_00024RSAPrivate_nativeInit
+(int modLen, jbyte* jMod, int privLen, jbyte* jPriv) {
+
+  unsigned char *mod, *priv;
+  crypto_object_attribute_t* pKey = NULL;
+
+  pKey = calloc(2, sizeof(crypto_object_attribute_t));
+  if (pKey == NULL) {
+    return 0L;
+  }
+  mod = priv = NULL;
+  mod = malloc(modLen);
+  priv = malloc(privLen);
+  if (mod == NULL || priv == NULL) {
+    free(pKey);
+    free(mod);
+    free(priv);
+    return 0L;
+  } else {
+    memcpy(mod, jMod, modLen);
+    memcpy(priv, jPriv, privLen);
+  }
+
+  // NOTE: numOfComponents should be 2
+  pKey[0].oa_type = SUN_CKA_MODULUS;
+  pKey[0].oa_value = (char*) mod;
+  pKey[0].oa_value_len = (size_t) modLen;
+  pKey[1].oa_type = SUN_CKA_PRIVATE_EXPONENT;
+  pKey[1].oa_value = (char*) priv;
+  pKey[1].oa_value_len = (size_t) privLen;
+
+  return (jlong) pKey;
+}
+
+JNIEXPORT jlong JNICALL
+Java_com_oracle_security_ucrypto_NativeKey_00024RSAPrivate_nativeInit
+  (JNIEnv *env, jclass jCls, jbyteArray jMod, jbyteArray jPriv) {
+
+  int modLen, privLen;
+  jbyte *bufMod, *bufPriv;
+  crypto_object_attribute_t* pKey = NULL;
+
+  bufMod = bufPriv = NULL;
+
+  modLen = (*env)->GetArrayLength(env, jMod);
+  bufMod = getBytes(env, jMod, 0, modLen);
+  if ((*env)->ExceptionCheck(env)) goto cleanup;
+
+  privLen = (*env)->GetArrayLength(env, jPriv);
+  bufPriv = getBytes(env, jPriv, 0, privLen);
+  if ((*env)->ExceptionCheck(env)) goto cleanup;
+
+  // proceed if no error; otherwise free allocated memory
+  pKey = calloc(2, sizeof(crypto_object_attribute_t));
+  if (pKey == NULL) {
+    throwOutOfMemoryError(env, NULL);
+    goto cleanup;
+  }
+
+  // NOTE: numOfComponents should be 2
+  pKey[0].oa_type = SUN_CKA_MODULUS;
+  pKey[0].oa_value = (char*) bufMod;
+  pKey[0].oa_value_len = (size_t) modLen;
+  pKey[1].oa_type = SUN_CKA_PRIVATE_EXPONENT;
+  pKey[1].oa_value = (char*) bufPriv;
+  pKey[1].oa_value_len = (size_t) privLen;
+  return (jlong) pKey;
+
+cleanup:
+  free(bufMod);
+  free(bufPriv);
+
+  return 0L;
+}
+
+/*
  * Class:     com_oracle_security_ucrypto_NativeKey_RSAPrivateCrt
  * Method:    nativeInit
  * Signature: ([B[B[B[B[B[B[B[B)J
--- a/jdk/test/com/oracle/security/ucrypto/CipherSignNotSupported.java	Wed Jul 05 20:48:33 2017 +0200
+++ b/jdk/test/com/oracle/security/ucrypto/CipherSignNotSupported.java	Fri Sep 04 15:28:01 2015 +0300
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, 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
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @bug 8029849
+ * @bug 8029849 8132082
  * @summary Make sure signing via encrypt and verifying via decrypt are not
  * supported by OracleUcrypto provider.
  * @author Anthony Scarpino
@@ -31,12 +31,10 @@
  */
 
 import java.util.Random;
-import java.security.KeyPairGenerator;
-import java.security.KeyPair;
+import java.security.*;
+import java.security.interfaces.*;
+import java.security.spec.RSAPrivateKeySpec;
 import javax.crypto.Cipher;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.security.Provider;
 
 public class CipherSignNotSupported extends UcryptoTest {
 
@@ -69,27 +67,43 @@
         c.init(Cipher.ENCRYPT_MODE, kp.getPublic());
         ct = c.doFinal(pt);
         // Decryption
-        c.init(Cipher.DECRYPT_MODE, kp.getPrivate());
-        c.doFinal(ct);
-        // Sign
-        try {
-            c.init(Cipher.ENCRYPT_MODE, kp.getPrivate());
-            ct = c.doFinal(pt);
-            throw new RuntimeException("Encrypt operation should have failed.");
-        } catch (InvalidKeyException e) {
-            if (e.getMessage().compareTo("RSAPublicKey required for " +
-                    "encryption") != 0) {
-                System.out.println("Wrong exception thrown.");
-                throw e;
+        PrivateKey[] privKeys = new PrivateKey[2];
+        privKeys[0] = kp.getPrivate();
+        if (privKeys[0] instanceof RSAPrivateCrtKey) {
+            RSAPrivateCrtKey k = (RSAPrivateCrtKey) privKeys[0];
+            KeyFactory kf = KeyFactory.getInstance("RSA");
+            privKeys[1] = kf.generatePrivate
+                (new RSAPrivateKeySpec(k.getModulus(), k.getPrivateExponent()));
+        } else {
+            privKeys = new PrivateKey[] {privKeys[0]};
+        }
+
+        for (PrivateKey pk : privKeys) {
+            System.out.println("Testing " + pk);
+            c.init(Cipher.DECRYPT_MODE, pk);
+            c.doFinal(ct);
+
+            // Sign
+            try {
+                c.init(Cipher.ENCRYPT_MODE, pk);
+                ct = c.doFinal(pt);
+                throw new RuntimeException("Encrypt operation should have failed.");
+            } catch (InvalidKeyException e) {
+                if (e.getMessage().compareTo("RSAPublicKey required for " +
+                        "encryption") != 0) {
+                    System.out.println("Wrong exception thrown.");
+                    throw e;
+                }
             }
         }
+
         // Verify
         try {
             c.init(Cipher.DECRYPT_MODE, kp.getPublic());
             c.doFinal(ct);
             throw new RuntimeException("Decrypt operation should have failed.");
         } catch (InvalidKeyException e) {
-            if (e.getMessage().compareTo("RSAPrivateCrtKey required for " +
+            if (e.getMessage().compareTo("RSAPrivateKey required for " +
                     "decryption") != 0) {
                 System.out.println("Wrong exception thrown.");
                 throw e;