8213010: Supporting keys created with certmgr.exe
authorweijun
Thu, 13 Dec 2018 17:28:30 +0800
changeset 53007 e2798bf6318a
parent 53006 4debb3321e65
child 53008 9a73a4e4011f
8213010: Supporting keys created with certmgr.exe Reviewed-by: valeriep
src/java.base/share/classes/sun/security/util/ECUtil.java
src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java
src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CKey.java
src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CKeyStore.java
src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CPublicKey.java
src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CSignature.java
src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/SunMSCAPI.java
src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp
--- a/src/java.base/share/classes/sun/security/util/ECUtil.java	Thu Dec 13 17:28:19 2018 +0800
+++ b/src/java.base/share/classes/sun/security/util/ECUtil.java	Thu Dec 13 17:28:30 2018 +0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2018, 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
@@ -26,17 +26,11 @@
 package sun.security.util;
 
 import java.io.IOException;
-
 import java.math.BigInteger;
-
 import java.security.*;
-
 import java.security.interfaces.*;
-
 import java.security.spec.*;
-
 import java.util.Arrays;
-
 import sun.security.x509.X509Key;
 
 public class ECUtil {
@@ -227,5 +221,64 @@
         return nameSpec.getName();
     }
 
+    // Convert the concatenation R and S in into their DER encoding
+    public static byte[] encodeSignature(byte[] signature) throws SignatureException {
+
+        try {
+
+            int n = signature.length >> 1;
+            byte[] bytes = new byte[n];
+            System.arraycopy(signature, 0, bytes, 0, n);
+            BigInteger r = new BigInteger(1, bytes);
+            System.arraycopy(signature, n, bytes, 0, n);
+            BigInteger s = new BigInteger(1, bytes);
+
+            DerOutputStream out = new DerOutputStream(signature.length + 10);
+            out.putInteger(r);
+            out.putInteger(s);
+            DerValue result =
+                    new DerValue(DerValue.tag_Sequence, out.toByteArray());
+
+            return result.toByteArray();
+
+        } catch (Exception e) {
+            throw new SignatureException("Could not encode signature", e);
+        }
+    }
+
+    // Convert the DER encoding of R and S into a concatenation of R and S
+    public static byte[] decodeSignature(byte[] sig) throws SignatureException {
+
+        try {
+            // Enforce strict DER checking for signatures
+            DerInputStream in = new DerInputStream(sig, 0, sig.length, false);
+            DerValue[] values = in.getSequence(2);
+
+            // check number of components in the read sequence
+            // and trailing data
+            if ((values.length != 2) || (in.available() != 0)) {
+                throw new IOException("Invalid encoding for signature");
+            }
+
+            BigInteger r = values[0].getPositiveBigInteger();
+            BigInteger s = values[1].getPositiveBigInteger();
+
+            // trim leading zeroes
+            byte[] rBytes = trimZeroes(r.toByteArray());
+            byte[] sBytes = trimZeroes(s.toByteArray());
+            int k = Math.max(rBytes.length, sBytes.length);
+            // r and s each occupy half the array
+            byte[] result = new byte[k << 1];
+            System.arraycopy(rBytes, 0, result, k - rBytes.length,
+                    rBytes.length);
+            System.arraycopy(sBytes, 0, result, result.length - sBytes.length,
+                    sBytes.length);
+            return result;
+
+        } catch (Exception e) {
+            throw new SignatureException("Invalid encoding for signature", e);
+        }
+    }
+
     private ECUtil() {}
 }
--- a/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java	Thu Dec 13 17:28:19 2018 +0800
+++ b/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java	Thu Dec 13 17:28:30 2018 +0800
@@ -25,9 +25,7 @@
 
 package sun.security.ec;
 
-import java.io.IOException;
 import java.nio.ByteBuffer;
-import java.math.BigInteger;
 
 import java.security.*;
 import java.security.interfaces.*;
@@ -453,7 +451,7 @@
         if (p1363Format) {
             return sig;
         } else {
-            return encodeSignature(sig);
+            return ECUtil.encodeSignature(sig);
         }
     }
 
@@ -476,7 +474,7 @@
         if (p1363Format) {
             sig = signature;
         } else {
-            sig = decodeSignature(signature);
+            sig = ECUtil.decodeSignature(signature);
         }
 
         try {
@@ -515,79 +513,6 @@
         return null;
     }
 
-    // Convert the concatenation of R and S into their DER encoding
-    private byte[] encodeSignature(byte[] signature) throws SignatureException {
-
-        try {
-
-            int n = signature.length >> 1;
-            byte[] bytes = new byte[n];
-            System.arraycopy(signature, 0, bytes, 0, n);
-            BigInteger r = new BigInteger(1, bytes);
-            System.arraycopy(signature, n, bytes, 0, n);
-            BigInteger s = new BigInteger(1, bytes);
-
-            DerOutputStream out = new DerOutputStream(signature.length + 10);
-            out.putInteger(r);
-            out.putInteger(s);
-            DerValue result =
-            new DerValue(DerValue.tag_Sequence, out.toByteArray());
-
-            return result.toByteArray();
-
-        } catch (Exception e) {
-            throw new SignatureException("Could not encode signature", e);
-        }
-    }
-
-    // Convert the DER encoding of R and S into a concatenation of R and S
-    private byte[] decodeSignature(byte[] sig) throws SignatureException {
-
-        try {
-            // Enforce strict DER checking for signatures
-            DerInputStream in = new DerInputStream(sig, 0, sig.length, false);
-            DerValue[] values = in.getSequence(2);
-
-            // check number of components in the read sequence
-            // and trailing data
-            if ((values.length != 2) || (in.available() != 0)) {
-                throw new IOException("Invalid encoding for signature");
-            }
-
-            BigInteger r = values[0].getPositiveBigInteger();
-            BigInteger s = values[1].getPositiveBigInteger();
-
-            // trim leading zeroes
-            byte[] rBytes = trimZeroes(r.toByteArray());
-            byte[] sBytes = trimZeroes(s.toByteArray());
-            int k = Math.max(rBytes.length, sBytes.length);
-            // r and s each occupy half the array
-            byte[] result = new byte[k << 1];
-            System.arraycopy(rBytes, 0, result, k - rBytes.length,
-            rBytes.length);
-            System.arraycopy(sBytes, 0, result, result.length - sBytes.length,
-            sBytes.length);
-            return result;
-
-        } catch (Exception e) {
-            throw new SignatureException("Invalid encoding for signature", e);
-        }
-    }
-
-    // trim leading (most significant) zeroes from the result
-    private static byte[] trimZeroes(byte[] b) {
-        int i = 0;
-        while ((i < b.length - 1) && (b[i] == 0)) {
-            i++;
-        }
-        if (i == 0) {
-            return b;
-        }
-        byte[] t = new byte[b.length - i];
-        System.arraycopy(b, i, t, 0, t.length);
-        return t;
-    }
-
     /**
      * Signs the digest using the private key.
      *
--- a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CKey.java	Thu Dec 13 17:28:19 2018 +0800
+++ b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CKey.java	Thu Dec 13 17:28:30 2018 +0800
@@ -25,9 +25,13 @@
 
 package sun.security.mscapi;
 
+import sun.security.util.KeyUtil;
 import sun.security.util.Length;
 
+import java.math.BigInteger;
 import java.security.Key;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
 
 /**
  * The handle for a key using the Microsoft Crypto API.
@@ -100,4 +104,51 @@
     protected native static String getContainerName(long hCryptProv);
 
     protected native static String getKeyType(long hCryptKey);
+
+    // This java method generates EC BLOBs for public key or private key.
+    // See https://docs.microsoft.com/en-us/windows/desktop/api/bcrypt/ns-bcrypt-_bcrypt_ecckey_blob
+    static byte[] generateECBlob(Key k) {
+
+        int keyBitLength = KeyUtil.getKeySize(k);
+        int keyLen = (keyBitLength + 7) / 8;
+        boolean isPrivate = k instanceof ECPrivateKey;
+
+        byte[] keyBlob = new byte[8 + keyLen * (isPrivate ? 3 : 2)];
+        keyBlob[0] = 'E';
+        keyBlob[1] = 'C';
+        keyBlob[2] = 'S';
+        if (isPrivate) {
+            keyBlob[3] = (byte) (keyBitLength == 256 ? '2'
+                    : (keyBitLength == 384 ? '4' : '6'));
+        } else {
+            keyBlob[3] = (byte) (keyBitLength == 256 ? '1'
+                    : (keyBitLength == 384 ? '3' : '5'));
+        }
+        BigInteger x;
+        BigInteger y;
+        // Fill the array in reverse order (s -> y -> x -> len) in case
+        // one BigInteger encoding has an extra 0 at the beginning
+        if (isPrivate) {
+            // We can keep X and Y zero and it still works
+            ECPrivateKey prk = (ECPrivateKey)k;
+            BigInteger s = prk.getS();
+            byte[] bs = s.toByteArray();
+            System.arraycopy(
+                    bs, 0,
+                    keyBlob, 8 + keyLen + keyLen + keyLen - bs.length,
+                    bs.length);
+        } else {
+            ECPublicKey puk = (ECPublicKey)k;
+            x = puk.getW().getAffineX();
+            y = puk.getW().getAffineY();
+            byte[] by = y.toByteArray();
+            System.arraycopy(by, 0, keyBlob, 8 + keyLen + keyLen - by.length,
+                    by.length);
+            byte[] bx = x.toByteArray();
+            System.arraycopy(bx, 0, keyBlob, 8 + keyLen - bx.length, bx.length);
+        }
+        keyBlob[4] = (byte) keyLen;
+        keyBlob[5] = keyBlob[6] = keyBlob[7] = 0;
+        return keyBlob;
+    }
 }
--- a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CKeyStore.java	Thu Dec 13 17:28:19 2018 +0800
+++ b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CKeyStore.java	Thu Dec 13 17:28:30 2018 +0800
@@ -759,12 +759,12 @@
     }
 
     /**
-     * Generates RSA key and certificate chain from the private key handle,
+     * Generates key and certificate chain from the private key handle,
      * collection of certificates and stores the result into key entries.
      * <p>
      * This method is called by native codes in security.cpp.
      */
-    private void generateRSAKeyAndCertificateChain(String alias,
+    private void generateKeyAndCertificateChain(boolean isRSA, String alias,
             long hCryptProv, long hCryptKey, int keyLength,
             Collection<? extends Certificate> certCollection) {
         try {
@@ -777,7 +777,7 @@
                 certChain[i] = (X509Certificate) iter.next();
             }
             storeWithUniqueAlias(alias, new KeyEntry(alias,
-                    CPrivateKey.of("RSA", hCryptProv, hCryptKey, keyLength),
+                    CPrivateKey.of(isRSA ? "RSA" : "EC", hCryptProv, hCryptKey, keyLength),
                     certChain));
         } catch (Throwable e) {
             // Ignore the exception and skip this entry
--- a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CPublicKey.java	Thu Dec 13 17:28:19 2018 +0800
+++ b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CPublicKey.java	Thu Dec 13 17:28:30 2018 +0800
@@ -26,14 +26,22 @@
 package sun.security.mscapi;
 
 import java.math.BigInteger;
+import java.security.AlgorithmParameters;
 import java.security.KeyException;
+import java.security.KeyFactory;
 import java.security.KeyRep;
 import java.security.ProviderException;
 import java.security.PublicKey;
+import java.security.interfaces.ECPublicKey;
 import java.security.interfaces.RSAPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPublicKeySpec;
+import java.util.Arrays;
 
 import sun.security.rsa.RSAUtil.KeyType;
 import sun.security.rsa.RSAPublicKeyImpl;
+import sun.security.util.ECKeySizeParameterSpec;
 
 /**
  * The handle for an RSA public key using the Microsoft Crypto API.
@@ -44,9 +52,69 @@
 
     private static final long serialVersionUID = -2289561342425825391L;
 
-    protected byte[] publicKeyBlob = null;
     protected byte[] encoding = null;
 
+    public static class CECPublicKey extends CPublicKey implements ECPublicKey {
+
+        private ECPoint w = null;
+        private static final long serialVersionUID = 12L;
+
+        CECPublicKey(long hCryptProv, int keyLength) {
+            super("EC", hCryptProv, 0, keyLength);
+        }
+
+        @Override
+        public ECPoint getW() {
+            if (w == null) {
+                // See CKey::generateECBlob.
+                try {
+                    byte[] blob = getPublicKeyBlob(
+                            handles.hCryptProv, handles.hCryptKey);
+                    int len = blob[8] & 0xff;
+                    byte[] x = Arrays.copyOfRange(blob, 8, 8 + len);
+                    byte[] y = Arrays.copyOfRange(blob, 8 + len, 8 + len + len);
+                    w = new ECPoint(new BigInteger(1, x), new BigInteger(1, y));
+                } catch (KeyException e) {
+                    throw new ProviderException(e);
+                }
+            }
+            return w;
+        }
+
+        @Override
+        public byte[] getEncoded() {
+            if (encoding == null) {
+                try {
+                    encoding = KeyFactory.getInstance("EC").generatePublic(
+                                new ECPublicKeySpec(getW(), getParams()))
+                            .getEncoded();
+                } catch (Exception e) {
+                    // ignore
+                }
+            }
+            return encoding;
+        }
+
+        @Override
+        public ECParameterSpec getParams() {
+            try {
+                AlgorithmParameters ap = AlgorithmParameters.getInstance("EC");
+                ap.init(new ECKeySizeParameterSpec(keyLength));
+                return ap.getParameterSpec(ECParameterSpec.class);
+            } catch (Exception e) {
+                throw new ProviderException(e);
+            }
+        }
+
+        public String toString() {
+            StringBuffer sb = new StringBuffer();
+            sb.append(algorithm + "PublicKey [size=").append(keyLength)
+                    .append("]\n  ECPoint: ").append(getW())
+                    .append("\n  params: ").append(getParams());
+            return sb.toString();
+        }
+    }
+
     public static class CRSAPublicKey extends CPublicKey implements RSAPublicKey {
 
         private BigInteger modulus = null;
@@ -71,7 +139,8 @@
         public BigInteger getPublicExponent() {
             if (exponent == null) {
                 try {
-                    publicKeyBlob = getPublicKeyBlob(handles.hCryptKey);
+                    byte[] publicKeyBlob = getPublicKeyBlob(
+                            handles.hCryptProv, handles.hCryptKey);
                     exponent = new BigInteger(1, getExponent(publicKeyBlob));
                 } catch (KeyException e) {
                     throw new ProviderException(e);
@@ -84,7 +153,8 @@
         public BigInteger getModulus() {
             if (modulus == null) {
                 try {
-                    publicKeyBlob = getPublicKeyBlob(handles.hCryptKey);
+                    byte[] publicKeyBlob = getPublicKeyBlob(
+                            handles.hCryptProv, handles.hCryptKey);
                     modulus = new BigInteger(1, getModulus(publicKeyBlob));
                 } catch (KeyException e) {
                     throw new ProviderException(e);
@@ -111,16 +181,20 @@
         private native byte[] getModulus(byte[] keyBlob) throws KeyException;
     }
 
-    public static CPublicKey of(String alg, long hCryptProv, long hCryptKey, int keyLength) {
+    public static CPublicKey of(
+            String alg, long hCryptProv, long hCryptKey, int keyLength) {
         switch (alg) {
             case "RSA":
                 return new CRSAPublicKey(hCryptProv, hCryptKey, keyLength);
+            case "EC":
+                return new CECPublicKey(hCryptProv, keyLength);
             default:
                 throw new AssertionError("Unsupported algorithm: " + alg);
         }
     }
 
-    protected CPublicKey(String alg, long hCryptProv, long hCryptKey, int keyLength) {
+    protected CPublicKey(
+            String alg, long hCryptProv, long hCryptKey, int keyLength) {
         super(alg, hCryptProv, hCryptKey, keyLength);
     }
 
@@ -136,7 +210,7 @@
                         getEncoded());
     }
 
-    // Returns the Microsoft CryptoAPI representation of the key.
-    native byte[] getPublicKeyBlob(long hCryptKey) throws KeyException;
-
+    // Returns the CAPI or CNG representation of the key.
+    native byte[] getPublicKeyBlob(long hCryptProv, long hCryptKey)
+            throws KeyException;
 }
--- a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CSignature.java	Thu Dec 13 17:28:19 2018 +0800
+++ b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CSignature.java	Thu Dec 13 17:28:30 2018 +0800
@@ -27,6 +27,7 @@
 
 import java.nio.ByteBuffer;
 import java.security.*;
+import java.security.interfaces.ECPublicKey;
 import java.security.interfaces.RSAPublicKey;
 import java.security.spec.AlgorithmParameterSpec;
 import java.math.BigInteger;
@@ -35,10 +36,11 @@
 import java.util.Locale;
 
 import sun.security.rsa.RSAKeyFactory;
+import sun.security.util.ECUtil;
+import sun.security.util.KeyUtil;
 
 /**
- * Signature implementation. Supports RSA signing using PKCS#1 v1.5 padding
- * and RSASSA-PSS signing.
+ * Signature implementation.
  *
  * Objects should be instantiated by calling Signature.getInstance() using the
  * following algorithm names:
@@ -51,6 +53,11 @@
  *  . "MD5withRSA"
  *  . "MD2withRSA"
  *  . "RSASSA-PSS"
+ *  . "SHA1withECDSA"
+ *  . "SHA224withECDSA"
+ *  . "SHA256withECDSA"
+ *  . "SHA384withECDSA"
+ *  . "SHA512withECDSA"
  *
  * NOTE: RSA keys must be at least 512 bits long.
  *
@@ -112,7 +119,8 @@
         @Override
         protected void engineInitSign(PrivateKey key) throws InvalidKeyException {
 
-            if ((key instanceof CPrivateKey) == false) {
+            if ((key instanceof CPrivateKey) == false
+                    || !key.getAlgorithm().equalsIgnoreCase("RSA")) {
                 throw new InvalidKeyException("Key type not supported");
             }
             privateKey = (CPrivateKey) key;
@@ -197,7 +205,6 @@
             boolean noHashOID = this instanceof NONEwithRSA;
 
             // Sign hash using MS Crypto APIs
-
             byte[] result = signHash(noHashOID, hash, hash.length,
                         messageDigestAlgorithm, privateKey.getHCryptProvider(),
                         privateKey.getHCryptKey());
@@ -364,6 +371,106 @@
         }
     }
 
+    public static final class SHA1withECDSA extends ECDSA {
+        public SHA1withECDSA() {
+            super("SHA-1");
+        }
+    }
+
+    public static final class SHA224withECDSA extends ECDSA {
+        public SHA224withECDSA() {
+            super("SHA-224");
+        }
+    }
+
+    public static final class SHA256withECDSA extends ECDSA {
+        public SHA256withECDSA() {
+            super("SHA-256");
+        }
+    }
+
+    public static final class SHA384withECDSA extends ECDSA {
+        public SHA384withECDSA() {
+            super("SHA-384");
+        }
+    }
+
+    public static final class SHA512withECDSA extends ECDSA {
+        public SHA512withECDSA() {
+            super("SHA-512");
+        }
+    }
+
+    static class ECDSA extends CSignature {
+
+        public ECDSA(String messageDigestAlgorithm) {
+            super("EC", messageDigestAlgorithm);
+        }
+
+        // initialize for signing. See JCA doc
+        @Override
+        protected void engineInitSign(PrivateKey key) throws InvalidKeyException {
+            if ((key instanceof CPrivateKey) == false
+                    || !key.getAlgorithm().equalsIgnoreCase("EC")) {
+                throw new InvalidKeyException("Key type not supported");
+            }
+            privateKey = (CPrivateKey) key;
+
+            this.publicKey = null;
+            resetDigest();
+        }
+
+        // initialize for signing. See JCA doc
+        @Override
+        protected void engineInitVerify(PublicKey key) throws InvalidKeyException {
+            // This signature accepts only ECPublicKey
+            if ((key instanceof ECPublicKey) == false) {
+                throw new InvalidKeyException("Key type not supported");
+            }
+
+
+            if ((key instanceof CPublicKey) == false) {
+                try {
+                    publicKey = importECPublicKey("EC",
+                            CKey.generateECBlob(key),
+                            KeyUtil.getKeySize(key));
+                } catch (KeyStoreException e) {
+                    throw new InvalidKeyException(e);
+                }
+            } else {
+                publicKey = (CPublicKey) key;
+            }
+
+            this.privateKey = null;
+            resetDigest();
+        }
+
+        @Override
+        protected byte[] engineSign() throws SignatureException {
+            byte[] hash = getDigestValue();
+            byte[] raw = signCngHash(0, hash, hash.length,
+                    0,
+                    null,
+                    privateKey.getHCryptProvider(), 0);
+            return ECUtil.encodeSignature(raw);
+        }
+
+        @Override
+        protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
+            byte[] hash = getDigestValue();
+            sigBytes = ECUtil.decodeSignature(sigBytes);
+            return verifyCngSignedHash(
+                    0,
+                    hash, hash.length,
+                    sigBytes, sigBytes.length,
+                    0,
+                    null,
+                    publicKey.getHCryptProvider(),
+                    0
+            );
+        }
+    }
+
     public static final class PSS extends RSA {
 
         private PSSParameterSpec pssParams = null;
@@ -463,7 +570,7 @@
         protected byte[] engineSign() throws SignatureException {
             ensureInit();
             byte[] hash = getDigestValue();
-            return signCngHash(hash, hash.length,
+            return signCngHash(2, hash, hash.length,
                     pssParams.getSaltLength(),
                     ((MGF1ParameterSpec)
                             pssParams.getMGFParameters()).getDigestAlgorithm(),
@@ -479,7 +586,7 @@
             } else {
                 byte[] hash = getDigestValue();
                 return verifyCngSignedHash(
-                        hash, hash.length,
+                        2, hash, hash.length,
                         sigBytes, sigBytes.length,
                         pssParams.getSaltLength(),
                         ((MGF1ParameterSpec)
@@ -599,19 +706,22 @@
     }
 
     /**
-     * Sign hash using CNG API with HCRYPTKEY. Used by RSASSA-PSS.
+     * Sign hash using CNG API with HCRYPTKEY.
+     * @param type 0 no padding, 1, pkcs1, 2, pss
      */
     native static byte[] signCngHash(
-            byte[] hash, int hashSize, int saltLength, String hashAlgorithm,
+            int type, byte[] hash,
+            int hashSize, int saltLength, String hashAlgorithm,
             long hCryptProv, long nCryptKey)
             throws SignatureException;
 
     /**
-     * Verify a signed hash using CNG API with HCRYPTKEY. Used by RSASSA-PSS.
-     * This method is not used now. See {@link PSS#fallbackSignature}.
+     * Verify a signed hash using CNG API with HCRYPTKEY.
+     * @param type 0 no padding, 1, pkcs1, 2, pss
      */
     private native static boolean verifyCngSignedHash(
-            byte[] hash, int hashSize, byte[] signature, int signatureSize,
+            int type, byte[] hash, int hashSize,
+            byte[] signature, int signatureSize,
             int saltLength, String hashAlgorithm,
             long hCryptProv, long hKey) throws SignatureException;
 
@@ -804,4 +914,7 @@
     // used by CRSACipher
     static native CPublicKey importPublicKey(
             String alg, byte[] keyBlob, int keySize) throws KeyStoreException;
+
+    static native CPublicKey importECPublicKey(
+            String alg, byte[] keyBlob, int keySize) throws KeyStoreException;
 }
--- a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/SunMSCAPI.java	Thu Dec 13 17:28:19 2018 +0800
+++ b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/SunMSCAPI.java	Thu Dec 13 17:28:30 2018 +0800
@@ -106,6 +106,16 @@
                         return new CSignature.MD2withRSA();
                     } else if (algo.equals("RSASSA-PSS")) {
                         return new CSignature.PSS();
+                    } else if (algo.equals("SHA1withECDSA")) {
+                        return new CSignature.SHA1withECDSA();
+                    } else if (algo.equals("SHA224withECDSA")) {
+                        return new CSignature.SHA224withECDSA();
+                    } else if (algo.equals("SHA256withECDSA")) {
+                        return new CSignature.SHA256withECDSA();
+                    } else if (algo.equals("SHA384withECDSA")) {
+                        return new CSignature.SHA384withECDSA();
+                    } else if (algo.equals("SHA512withECDSA")) {
+                        return new CSignature.SHA512withECDSA();
                     }
                 } else if (type.equals("KeyPairGenerator")) {
                     if (algo.equals("RSA")) {
@@ -188,7 +198,26 @@
                 putService(new ProviderService(p, "Signature",
                            "MD2withRSA", "sun.security.mscapi.CSignature$MD2withRSA",
                            null, attrs));
-
+                putService(new ProviderService(p, "Signature",
+                        "SHA1withECDSA", "sun.security.mscapi.CSignature$SHA1withECDSA",
+                        new String[] { "1.2.840.10045.4.1", "OID.1.2.840.10045.4.1" },
+                        attrs));
+                putService(new ProviderService(p, "Signature",
+                        "SHA224withECDSA", "sun.security.mscapi.CSignature$SHA224withECDSA",
+                        new String[] { "1.2.840.10045.4.3.1", "OID.1.2.840.10045.4.3.1"},
+                        attrs));
+                putService(new ProviderService(p, "Signature",
+                        "SHA256withECDSA", "sun.security.mscapi.CSignature$SHA256withECDSA",
+                        new String[] { "1.2.840.10045.4.3.2", "OID.1.2.840.10045.4.3.2"},
+                        attrs));
+                putService(new ProviderService(p, "Signature",
+                        "SHA384withECDSA", "sun.security.mscapi.CSignature$SHA384withECDSA",
+                        new String[] { "1.2.840.10045.4.3.3", "OID.1.2.840.10045.4.3.3"},
+                        attrs));
+                putService(new ProviderService(p, "Signature",
+                        "SHA512withECDSA", "sun.security.mscapi.CSignature$SHA512withECDSA",
+                        new String[] { "1.2.840.10045.4.3.4", "OID.1.2.840.10045.4.3.4"},
+                        attrs));
                 /*
                  * Key Pair Generator engines
                  */
--- a/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp	Thu Dec 13 17:28:19 2018 +0800
+++ b/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp	Thu Dec 13 17:28:30 2018 +0800
@@ -65,44 +65,53 @@
             __leave; \
         }
 
-//#define PP(fmt, ...) \
-//        fprintf(stdout, "MSCAPI (%ld): ", __LINE__); \
-//        fprintf(stdout, fmt, ##__VA_ARGS__); \
-//        fprintf(stdout, "\n"); \
-//        fflush(stdout)
+#define PP(fmt, ...) \
+        if (trace) { \
+            fprintf(stdout, "MSCAPI (%ld): ", __LINE__); \
+            fprintf(stdout, fmt, ##__VA_ARGS__); \
+            fprintf(stdout, "\n"); \
+            fflush(stdout); \
+        }
 
 extern "C" {
 
+char* trace = getenv("CAPI_TRACE");
+
 /*
  * Declare library specific JNI_Onload entry if static build
  */
 DEF_STATIC_JNI_OnLoad
 
-//void dump(LPSTR title, PBYTE data, DWORD len)
-//{
-//    printf("==== %s ====\n", title);
-//    for (DWORD i = 0; i < len; i+=16) {
-//        printf("%04x: ", i);
-//        for (int j = 0; j < 16; j++) {
-//            if (j == 8) {
-//                printf("  ");
-//            }
-//            if (i + j < len) {
-//                printf("%02X ", *(data + i + j) & 0xff);
-//            } else {
-//                printf("   ");
-//            }
-//        }
-//        for (int j = 0; j < 16; j++) {
-//            if (i + j < len) {
-//                int k = *(data + i + j) & 0xff;
-//                if (k < 32 || k > 127) printf(".");
-//                else printf("%c", (char)k);
-//            }
-//        }
-//        printf("\n");
-//    }
-//}
+void showProperty(NCRYPT_HANDLE hKey);
+
+void dump(LPSTR title, PBYTE data, DWORD len)
+{
+    if (trace) {
+        printf("==== %s ====\n", title);
+        for (DWORD i = 0; i < len; i+=16) {
+            printf("%04x: ", i);
+            for (int j = 0; j < 16; j++) {
+                if (j == 8) {
+                    printf("  ");
+                }
+                if (i + j < len) {
+                    printf("%02X ", *(data + i + j) & 0xff);
+                } else {
+                    printf("   ");
+                }
+            }
+            for (int j = 0; j < 16; j++) {
+                if (i + j < len) {
+                    int k = *(data + i + j) & 0xff;
+                    if (k < 32 || k > 127) printf(".");
+                    else printf("%c", (char)k);
+                }
+            }
+            printf("\n");
+        }
+        fflush(stdout);
+    }
+}
 
 /*
  * Throws an arbitrary Java exception with the given message.
@@ -445,10 +454,10 @@
         }
 
         // Determine method ID to generate RSA certificate chain
-        jmethodID mGenRSAKeyAndCertChain = env->GetMethodID(clazzOfThis,
-                                                   "generateRSAKeyAndCertificateChain",
-                                                   "(Ljava/lang/String;JJILjava/util/Collection;)V");
-        if (mGenRSAKeyAndCertChain == NULL) {
+        jmethodID mGenKeyAndCertChain = env->GetMethodID(clazzOfThis,
+                                                   "generateKeyAndCertificateChain",
+                                                   "(ZLjava/lang/String;JJILjava/util/Collection;)V");
+        if (mGenKeyAndCertChain == NULL) {
             __leave;
         }
 
@@ -457,6 +466,7 @@
         // NULL to retrieve the first certificate in the store.
         while (pCertContext = ::CertEnumCertificatesInStore(hCertStore, pCertContext))
         {
+            PP("--------------------------");
             // Check if private key available - client authentication certificate
             // must have private key available.
             HCRYPTPROV hCryptProv = NULL;
@@ -467,10 +477,12 @@
             DWORD dwPublicKeyLength = 0;
 
             // First, probe it silently
-            if (::CryptAcquireCertificatePrivateKey(pCertContext, CRYPT_ACQUIRE_SILENT_FLAG, NULL,
+            if (::CryptAcquireCertificatePrivateKey(pCertContext,
+                    CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG | CRYPT_ACQUIRE_SILENT_FLAG, NULL,
                     &hCryptProv, &dwKeySpec, &bCallerFreeProv) == FALSE
                 && GetLastError() != NTE_SILENT_CONTEXT)
             {
+                PP("bHasNoPrivateKey = TRUE!");
                 bHasNoPrivateKey = TRUE;
             }
             else
@@ -481,27 +493,32 @@
                 }
 
                 // Second, acquire the key normally (not silently)
-                if (::CryptAcquireCertificatePrivateKey(pCertContext, 0, NULL,
+                if (::CryptAcquireCertificatePrivateKey(pCertContext, CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG, NULL,
                         &hCryptProv, &dwKeySpec, &bCallerFreeProv) == FALSE)
                 {
+                    PP("bHasNoPrivateKey = TRUE!!");
                     bHasNoPrivateKey = TRUE;
                 }
                 else
                 {
-                    // Private key is available
-                    BOOL bGetUserKey = ::CryptGetUserKey(hCryptProv, dwKeySpec, &hUserKey); //deprecated
+                    if ((dwKeySpec & CERT_NCRYPT_KEY_SPEC) == CERT_NCRYPT_KEY_SPEC) {
+                        PP("CNG %I64d", hCryptProv);
+                    } else {
+                        // Private key is available
+                        BOOL bGetUserKey = ::CryptGetUserKey(hCryptProv, dwKeySpec, &hUserKey); //deprecated
 
-                    // Skip certificate if cannot find private key
-                    if (bGetUserKey == FALSE) {
-                        if (bCallerFreeProv)
-                            ::CryptReleaseContext(hCryptProv, NULL); // deprecated
-                        continue;
+                        // Skip certificate if cannot find private key
+                        if (bGetUserKey == FALSE) {
+                            if (bCallerFreeProv)
+                                ::CryptReleaseContext(hCryptProv, NULL); // deprecated
+                            continue;
+                        }
+
+                        // Set cipher mode to ECB
+                        DWORD dwCipherMode = CRYPT_MODE_ECB;
+                        ::CryptSetKeyParam(hUserKey, KP_MODE, (BYTE*)&dwCipherMode, NULL); //deprecated
+                        PP("CAPI %I64d %I64d", hCryptProv, hUserKey);
                     }
-
-                    // Set cipher mode to ECB
-                    DWORD dwCipherMode = CRYPT_MODE_ECB;
-                    ::CryptSetKeyParam(hUserKey, KP_MODE, (BYTE*)&dwCipherMode, NULL); //deprecated
-
                     // If the private key is present in smart card, we may not be able to
                     // determine the key length by using the private key handle. However,
                     // since public/private key pairs must have the same length, we could
@@ -573,6 +590,7 @@
                         env->CallVoidMethod(obj, mGenCert, byteArray, jArrayList);
                     }
 
+                    PP("%s: %s", pszNameString, pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId);
                     if (bHasNoPrivateKey)
                     {
                         // Generate certificate chain and store into cert chain
@@ -583,19 +601,40 @@
                     }
                     else
                     {
-                        // Determine key type: RSA or DSA
-                        DWORD dwData = CALG_RSA_KEYX;
-                        DWORD dwSize = sizeof(DWORD);
-                        ::CryptGetKeyParam(hUserKey, KP_ALGID, (BYTE*)&dwData, //deprecated
-                                &dwSize, NULL);
-                        if ((dwData & ALG_TYPE_RSA) == ALG_TYPE_RSA)
-                        {
-                            // Generate RSA certificate chain and store into cert
-                            // chain collection
-                            env->CallVoidMethod(obj, mGenRSAKeyAndCertChain,
-                                    env->NewStringUTF(pszNameString),
-                                    (jlong) hCryptProv, (jlong) hUserKey,
-                                    dwPublicKeyLength, jArrayList);
+                        if (hUserKey) {
+                            // Only accept RSA for CAPI
+                            DWORD dwData = CALG_RSA_KEYX;
+                            DWORD dwSize = sizeof(DWORD);
+                            ::CryptGetKeyParam(hUserKey, KP_ALGID, (BYTE*)&dwData, //deprecated
+                                    &dwSize, NULL);
+                            if ((dwData & ALG_TYPE_RSA) == ALG_TYPE_RSA)
+                            {
+                                // Generate RSA certificate chain and store into cert
+                                // chain collection
+                                env->CallVoidMethod(obj, mGenKeyAndCertChain,
+                                        1,
+                                        env->NewStringUTF(pszNameString),
+                                        (jlong) hCryptProv, (jlong) hUserKey,
+                                        dwPublicKeyLength, jArrayList);
+                            }
+                        } else {
+                            // Only accept EC for CNG
+                            BYTE buffer[32];
+                            DWORD len = 0;
+                            if (::NCryptGetProperty(
+                                    hCryptProv, NCRYPT_ALGORITHM_PROPERTY,
+                                    (PBYTE)buffer, 32, &len, NCRYPT_SILENT_FLAG) == ERROR_SUCCESS) {
+                                if (buffer[0] == 'E' && buffer[2] == 'C'
+                                        && (dwPublicKeyLength == 256
+                                                || dwPublicKeyLength == 384
+                                                || dwPublicKeyLength == 521)) {
+                                    env->CallVoidMethod(obj, mGenKeyAndCertChain,
+                                        0,
+                                        env->NewStringUTF(pszNameString),
+                                        (jlong) hCryptProv, 0,
+                                        dwPublicKeyLength, jArrayList);
+                                }
+                            }
                         }
                     }
                 }
@@ -603,6 +642,8 @@
                 // Free cert chain
                 if (pCertChainContext)
                     ::CertFreeCertificateChain(pCertChainContext);
+            } else {
+                PP("GetCertificateChain failed %d", GetLastError());
             }
         }
     }
@@ -768,10 +809,10 @@
 /*
  * Class:     sun_security_mscapi_CSignature
  * Method:    signCngHash
- * Signature: ([BIILjava/lang/String;JJ)[B
+ * Signature: (I[BIILjava/lang/String;JJ)[B
  */
 JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CSignature_signCngHash
-  (JNIEnv *env, jclass clazz, jbyteArray jHash,
+  (JNIEnv *env, jclass clazz, jint type, jbyteArray jHash,
         jint jHashSize, jint saltLen, jstring jHashAlgorithm, jlong hCryptProv,
         jlong hCryptKey)
 {
@@ -783,13 +824,17 @@
 
     __try
     {
-        SS_CHECK(::NCryptTranslateHandle(
+        if (hCryptKey == 0) {
+            hk = (NCRYPT_KEY_HANDLE)hCryptProv;
+        } else {
+            SS_CHECK(::NCryptTranslateHandle(
                 NULL,
                 &hk,
                 hCryptProv,
                 hCryptKey,
                 NULL,
                 0));
+        }
 
         // Copy hash from Java to native buffer
         pHashBuffer = new (env) jbyte[jHashSize];
@@ -798,43 +843,66 @@
         }
         env->GetByteArrayRegion(jHash, 0, jHashSize, pHashBuffer);
 
-        BCRYPT_PSS_PADDING_INFO pssInfo;
-        pssInfo.pszAlgId = MapHashIdentifier(env, jHashAlgorithm);
-        pssInfo.cbSalt = saltLen;
+        VOID* param;
+        DWORD dwFlags;
 
-        if (pssInfo.pszAlgId == NULL) {
-            ThrowExceptionWithMessage(env, SIGNATURE_EXCEPTION,
-                    "Unrecognised hash algorithm");
-            __leave;
+        switch (type) {
+        case 0:
+            param = NULL;
+            dwFlags = 0;
+            break;
+        case 1:
+            BCRYPT_PKCS1_PADDING_INFO pkcs1Info;
+            pkcs1Info.pszAlgId = MapHashIdentifier(env, jHashAlgorithm);
+            if (pkcs1Info.pszAlgId == NULL) {
+                ThrowExceptionWithMessage(env, SIGNATURE_EXCEPTION,
+                        "Unrecognised hash algorithm");
+                __leave;
+            }
+            param = &pkcs1Info;
+            dwFlags = BCRYPT_PAD_PKCS1;
+            break;
+        case 2:
+            BCRYPT_PSS_PADDING_INFO pssInfo;
+            pssInfo.pszAlgId = MapHashIdentifier(env, jHashAlgorithm);
+            pssInfo.cbSalt = saltLen;
+            if (pssInfo.pszAlgId == NULL) {
+                ThrowExceptionWithMessage(env, SIGNATURE_EXCEPTION,
+                        "Unrecognised hash algorithm");
+                __leave;
+            }
+            param = &pssInfo;
+            dwFlags = BCRYPT_PAD_PSS;
+            break;
         }
 
-        DWORD dwBufLen = 0;
+        DWORD jSignedHashSize = 0;
         SS_CHECK(::NCryptSignHash(
                 hk,
-                &pssInfo,
+                param,
                 (BYTE*)pHashBuffer, jHashSize,
-                NULL, 0, &dwBufLen,
-                BCRYPT_PAD_PSS
+                NULL, 0, &jSignedHashSize,
+                dwFlags
                 ));
 
-        pSignedHashBuffer = new (env) jbyte[dwBufLen];
+        pSignedHashBuffer = new (env) jbyte[jSignedHashSize];
         if (pSignedHashBuffer == NULL) {
             __leave;
         }
 
         SS_CHECK(::NCryptSignHash(
                 hk,
-                &pssInfo,
+                param,
                 (BYTE*)pHashBuffer, jHashSize,
-                (BYTE*)pSignedHashBuffer, dwBufLen, &dwBufLen,
-                BCRYPT_PAD_PSS
+                (BYTE*)pSignedHashBuffer, jSignedHashSize, &jSignedHashSize,
+                dwFlags
                 ));
 
         // Create new byte array
-        jbyteArray temp = env->NewByteArray(dwBufLen);
+        jbyteArray temp = env->NewByteArray(jSignedHashSize);
 
         // Copy data from native buffer
-        env->SetByteArrayRegion(temp, 0, dwBufLen, pSignedHashBuffer);
+        env->SetByteArrayRegion(temp, 0, jSignedHashSize, pSignedHashBuffer);
 
         jSignedHash = temp;
     }
@@ -846,7 +914,7 @@
         if (pHashBuffer)
             delete [] pHashBuffer;
 
-        if (hk != NULL)
+        if (hCryptKey != 0 && hk != NULL)
             ::NCryptFreeObject(hk);
     }
 
@@ -961,10 +1029,10 @@
 /*
  * Class:     sun_security_mscapi_CSignature
  * Method:    verifyCngSignedHash
- * Signature: ([BI[BIILjava/lang/String;JJ)Z
+ * Signature: (I[BI[BIILjava/lang/String;JJ)Z
  */
 JNIEXPORT jboolean JNICALL Java_sun_security_mscapi_CSignature_verifyCngSignedHash
-  (JNIEnv *env, jclass clazz,
+  (JNIEnv *env, jclass clazz, jint type,
         jbyteArray jHash, jint jHashSize,
         jbyteArray jSignedHash, jint jSignedHashSize,
         jint saltLen, jstring jHashAlgorithm,
@@ -977,13 +1045,17 @@
 
     __try
     {
-        SS_CHECK(::NCryptTranslateHandle(
+        if (hCryptKey == 0) {
+            hk = (NCRYPT_KEY_HANDLE)hCryptProv;
+        } else {
+            SS_CHECK(::NCryptTranslateHandle(
                 NULL,
                 &hk,
                 hCryptProv,
                 hCryptKey,
                 NULL,
                 0));
+        }
 
         // Copy hash and signedHash from Java to native buffer
         pHashBuffer = new (env) jbyte[jHashSize];
@@ -999,19 +1071,43 @@
         env->GetByteArrayRegion(jSignedHash, 0, jSignedHashSize,
             pSignedHashBuffer);
 
-        BCRYPT_PSS_PADDING_INFO pssInfo;
-        pssInfo.pszAlgId = MapHashIdentifier(env, jHashAlgorithm);
-        pssInfo.cbSalt = saltLen;
-        if (pssInfo.pszAlgId == NULL) {
-            ThrowExceptionWithMessage(env, SIGNATURE_EXCEPTION,
-                    "Unrecognised hash algorithm");
-            __leave;
+        VOID* param;
+        DWORD dwFlags;
+
+        switch (type) {
+        case 0:
+            param = NULL;
+            dwFlags = 0;
+            break;
+        case 1:
+            BCRYPT_PKCS1_PADDING_INFO pkcs1Info;
+            pkcs1Info.pszAlgId = MapHashIdentifier(env, jHashAlgorithm);
+            if (pkcs1Info.pszAlgId == NULL) {
+                ThrowExceptionWithMessage(env, SIGNATURE_EXCEPTION,
+                        "Unrecognised hash algorithm");
+                __leave;
+            }
+            param = &pkcs1Info;
+            dwFlags = NCRYPT_PAD_PKCS1_FLAG;
+            break;
+        case 2:
+            BCRYPT_PSS_PADDING_INFO pssInfo;
+            pssInfo.pszAlgId = MapHashIdentifier(env, jHashAlgorithm);
+            pssInfo.cbSalt = saltLen;
+            if (pssInfo.pszAlgId == NULL) {
+                ThrowExceptionWithMessage(env, SIGNATURE_EXCEPTION,
+                        "Unrecognised hash algorithm");
+                __leave;
+            }
+            param = &pssInfo;
+            dwFlags = NCRYPT_PAD_PSS_FLAG;
+            break;
         }
 
-        if (::NCryptVerifySignature(hk, &pssInfo,
+        if (::NCryptVerifySignature(hk, param,
                 (BYTE *) pHashBuffer, jHashSize,
                 (BYTE *) pSignedHashBuffer, jSignedHashSize,
-                NCRYPT_PAD_PSS_FLAG) == ERROR_SUCCESS)
+                dwFlags) == ERROR_SUCCESS)
         {
             result = JNI_TRUE;
         }
@@ -1025,13 +1121,108 @@
         if (pHashBuffer)
             delete [] pHashBuffer;
 
-        if (hk != NULL)
+        if (hCryptKey != 0 && hk != NULL)
             ::NCryptFreeObject(hk);
     }
 
     return result;
 }
 
+#define DUMP_PROP(p) \
+    if (::NCryptGetProperty(hKey, p, (PBYTE)buffer, 8192, &len, NCRYPT_SILENT_FLAG) == ERROR_SUCCESS) { \
+        sprintf(header, "%s %ls", #p, p); \
+        dump(header, buffer, len); \
+    }
+
+#define EXPORT_BLOB(p) \
+    desc.cBuffers = 0; \
+    if (::NCryptExportKey(hKey, NULL, p, &desc, (PBYTE)buffer, 8192, &len, NCRYPT_SILENT_FLAG) == ERROR_SUCCESS) { \
+        sprintf(header, "%s %ls (%ld)", #p, p, desc.cBuffers); \
+        dump(header, buffer, len); \
+        for (int i = 0; i < (int)desc.cBuffers; i++) { \
+            sprintf(header, "desc %ld", desc.pBuffers[i].BufferType); \
+            dump(header, (PBYTE)desc.pBuffers[i].pvBuffer, desc.pBuffers[i].cbBuffer); \
+        } \
+    }
+
+void showProperty(NCRYPT_HANDLE hKey) {
+    char header[100];
+    BYTE buffer[8192];
+    DWORD len = 9;
+    NCryptBufferDesc desc;
+    DUMP_PROP(NCRYPT_ALGORITHM_GROUP_PROPERTY);
+    DUMP_PROP(NCRYPT_ALGORITHM_PROPERTY);
+    DUMP_PROP(NCRYPT_ASSOCIATED_ECDH_KEY);
+    DUMP_PROP(NCRYPT_BLOCK_LENGTH_PROPERTY);
+    DUMP_PROP(NCRYPT_CERTIFICATE_PROPERTY);
+    DUMP_PROP(NCRYPT_DH_PARAMETERS_PROPERTY);
+    DUMP_PROP(NCRYPT_EXPORT_POLICY_PROPERTY);
+    DUMP_PROP(NCRYPT_IMPL_TYPE_PROPERTY);
+    DUMP_PROP(NCRYPT_KEY_TYPE_PROPERTY);
+    DUMP_PROP(NCRYPT_KEY_USAGE_PROPERTY);
+    DUMP_PROP(NCRYPT_LAST_MODIFIED_PROPERTY);
+    DUMP_PROP(NCRYPT_LENGTH_PROPERTY);
+    DUMP_PROP(NCRYPT_LENGTHS_PROPERTY);
+    DUMP_PROP(NCRYPT_MAX_NAME_LENGTH_PROPERTY);
+    DUMP_PROP(NCRYPT_NAME_PROPERTY);
+    DUMP_PROP(NCRYPT_PIN_PROMPT_PROPERTY);
+    DUMP_PROP(NCRYPT_PIN_PROPERTY);
+    DUMP_PROP(NCRYPT_PROVIDER_HANDLE_PROPERTY);
+    DUMP_PROP(NCRYPT_READER_PROPERTY);
+    DUMP_PROP(NCRYPT_ROOT_CERTSTORE_PROPERTY);
+    DUMP_PROP(NCRYPT_SCARD_PIN_ID);
+    DUMP_PROP(NCRYPT_SCARD_PIN_INFO);
+    DUMP_PROP(NCRYPT_SECURE_PIN_PROPERTY);
+    DUMP_PROP(NCRYPT_SECURITY_DESCR_PROPERTY);
+    DUMP_PROP(NCRYPT_SECURITY_DESCR_SUPPORT_PROPERTY);
+    DUMP_PROP(NCRYPT_SMARTCARD_GUID_PROPERTY);
+    DUMP_PROP(NCRYPT_UI_POLICY_PROPERTY);
+    DUMP_PROP(NCRYPT_UNIQUE_NAME_PROPERTY);
+    DUMP_PROP(NCRYPT_USE_CONTEXT_PROPERTY);
+    DUMP_PROP(NCRYPT_USE_COUNT_ENABLED_PROPERTY);
+    DUMP_PROP(NCRYPT_USE_COUNT_PROPERTY);
+    DUMP_PROP(NCRYPT_USER_CERTSTORE_PROPERTY);
+    DUMP_PROP(NCRYPT_VERSION_PROPERTY);
+    DUMP_PROP(NCRYPT_WINDOW_HANDLE_PROPERTY);
+
+    EXPORT_BLOB(BCRYPT_DH_PRIVATE_BLOB);
+    EXPORT_BLOB(BCRYPT_DH_PUBLIC_BLOB);
+    EXPORT_BLOB(BCRYPT_DSA_PRIVATE_BLOB);
+    EXPORT_BLOB(BCRYPT_DSA_PUBLIC_BLOB);
+    EXPORT_BLOB(BCRYPT_ECCPRIVATE_BLOB);
+    EXPORT_BLOB(BCRYPT_ECCPUBLIC_BLOB);
+    EXPORT_BLOB(BCRYPT_PUBLIC_KEY_BLOB);
+    EXPORT_BLOB(BCRYPT_PRIVATE_KEY_BLOB);
+    EXPORT_BLOB(BCRYPT_RSAFULLPRIVATE_BLOB);
+    EXPORT_BLOB(BCRYPT_RSAPRIVATE_BLOB);
+    EXPORT_BLOB(BCRYPT_RSAPUBLIC_BLOB);
+    EXPORT_BLOB(LEGACY_DH_PRIVATE_BLOB);
+    EXPORT_BLOB(LEGACY_DH_PUBLIC_BLOB);
+    EXPORT_BLOB(LEGACY_DSA_PRIVATE_BLOB);
+    EXPORT_BLOB(LEGACY_DSA_PUBLIC_BLOB);
+    EXPORT_BLOB(LEGACY_RSAPRIVATE_BLOB);
+    EXPORT_BLOB(LEGACY_RSAPUBLIC_BLOB);
+    EXPORT_BLOB(NCRYPT_CIPHER_KEY_BLOB);
+    EXPORT_BLOB(NCRYPT_OPAQUETRANSPORT_BLOB);
+    EXPORT_BLOB(NCRYPT_PKCS7_ENVELOPE_BLOB);
+    //EXPORT_BLOB(NCRYPTBUFFER_CERT_BLOB);
+    //EXPORT_BLOB(NCRYPT_PKCS8_PRIVATE_KEY_BLOB);
+    BCryptBuffer bb;
+    bb.BufferType = NCRYPTBUFFER_PKCS_SECRET;
+    bb.cbBuffer = 18;
+    bb.pvBuffer = L"changeit";
+    BCryptBufferDesc bbd;
+    bbd.ulVersion = 0;
+    bbd.cBuffers = 1;
+    bbd.pBuffers = &bb;
+    if(::NCryptExportKey(hKey, NULL, NCRYPT_PKCS8_PRIVATE_KEY_BLOB, NULL,
+            (PBYTE)buffer, 8192, &len, NCRYPT_SILENT_FLAG) == ERROR_SUCCESS) {
+        sprintf(header, "NCRYPT_PKCS8_PRIVATE_KEY_BLOB %ls", NCRYPT_PKCS8_PRIVATE_KEY_BLOB);
+        dump(header, buffer, len);
+    }
+    EXPORT_BLOB(NCRYPT_PROTECTED_KEY_BLOB);
+}
+
 /*
  * Class:     sun_security_mscapi_CKeyPairGenerator_RSA
  * Method:    generateCKeyPair
@@ -1673,10 +1864,10 @@
 /*
  * Class:     sun_security_mscapi_CPublicKey
  * Method:    getPublicKeyBlob
- * Signature: (J)[B
+ * Signature: (JJ)[B
  */
 JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CPublicKey_getPublicKeyBlob
-    (JNIEnv *env, jobject clazz, jlong hCryptKey) {
+    (JNIEnv *env, jobject clazz, jlong hCryptProv, jlong hCryptKey) {
 
     jbyteArray blob = NULL;
     DWORD dwBlobLen;
@@ -1686,11 +1877,17 @@
     {
 
         // Determine the size of the blob
-        if (! ::CryptExportKey((HCRYPTKEY) hCryptKey, 0, PUBLICKEYBLOB, 0, NULL, //deprecated
-            &dwBlobLen)) {
+        if (hCryptKey == 0) {
+            SS_CHECK(::NCryptExportKey(
+                hCryptProv, NULL, BCRYPT_ECCPUBLIC_BLOB,
+                NULL, NULL, 0, &dwBlobLen, NCRYPT_SILENT_FLAG));
+        } else {
+            if (! ::CryptExportKey((HCRYPTKEY) hCryptKey, 0, PUBLICKEYBLOB, 0, NULL, //deprecated
+                &dwBlobLen)) {
 
-            ThrowException(env, KEY_EXCEPTION, GetLastError());
-            __leave;
+                ThrowException(env, KEY_EXCEPTION, GetLastError());
+                __leave;
+            }
         }
 
         pbKeyBlob = new (env) BYTE[dwBlobLen];
@@ -1699,11 +1896,17 @@
         }
 
         // Generate key blob
-        if (! ::CryptExportKey((HCRYPTKEY) hCryptKey, 0, PUBLICKEYBLOB, 0, //deprecated
-            pbKeyBlob, &dwBlobLen)) {
+        if (hCryptKey == 0) {
+            SS_CHECK(::NCryptExportKey(
+                hCryptProv, NULL, BCRYPT_ECCPUBLIC_BLOB,
+                NULL, pbKeyBlob, dwBlobLen, &dwBlobLen, NCRYPT_SILENT_FLAG));
+        } else {
+            if (! ::CryptExportKey((HCRYPTKEY) hCryptKey, 0, PUBLICKEYBLOB, 0, //deprecated
+                pbKeyBlob, &dwBlobLen)) {
 
-            ThrowException(env, KEY_EXCEPTION, GetLastError());
-            __leave;
+                ThrowException(env, KEY_EXCEPTION, GetLastError());
+                __leave;
+            }
         }
 
         // Create new byte array
@@ -2177,6 +2380,66 @@
 
 /*
  * Class:     sun_security_mscapi_CSignature
+ * Method:    importECPublicKey
+ * Signature: (Ljava/lang/String;[BI)Lsun/security/mscapi/CPublicKey;
+ */
+JNIEXPORT jobject JNICALL Java_sun_security_mscapi_CSignature_importECPublicKey
+    (JNIEnv *env, jclass clazz, jstring alg, jbyteArray keyBlob, jint keySize)
+{
+    BCRYPT_ALG_HANDLE hSignAlg = NULL;
+    NCRYPT_KEY_HANDLE       hTmpKey         = NULL;
+    DWORD dwBlobLen;
+    BYTE * pbKeyBlob = NULL;
+    jobject publicKey = NULL;
+
+    __try
+    {
+        dwBlobLen = env->GetArrayLength(keyBlob);
+        if ((pbKeyBlob = (BYTE *) env->GetByteArrayElements(keyBlob, 0))
+            == NULL) {
+            __leave;
+        }
+        dump("NCryptImportKey", pbKeyBlob, dwBlobLen);
+        NCRYPT_PROV_HANDLE hProv;
+        SS_CHECK(NCryptOpenStorageProvider(
+                &hProv, L"Microsoft Software Key Storage Provider", 0 ));
+        SS_CHECK(NCryptImportKey(
+                                                    hProv,
+                                                    NULL,
+                                                    BCRYPT_ECCPUBLIC_BLOB,
+                                                    NULL,
+                                                    &hTmpKey,
+                                                    pbKeyBlob,
+                                                    dwBlobLen,
+                                                    0));
+        NCryptFreeObject( hProv );
+        // Get the method ID for the CPublicKey constructor
+        jclass clazzCPublicKey =
+            env->FindClass("sun/security/mscapi/CPublicKey");
+        if (clazzCPublicKey == NULL) {
+            __leave;
+        }
+
+        jmethodID mNewCPublicKey =
+            env->GetStaticMethodID(clazzCPublicKey, "of",
+            "(Ljava/lang/String;JJI)Lsun/security/mscapi/CPublicKey;");
+        if (mNewCPublicKey == NULL) {
+            __leave;
+        }
+
+        // Create a new public key
+        publicKey = env->CallStaticObjectMethod(clazzCPublicKey, mNewCPublicKey,
+            alg, (jlong) hTmpKey, (jlong) 0, keySize);
+    }
+    __finally
+    {
+    }
+
+    return publicKey;
+}
+
+/*
+ * Class:     sun_security_mscapi_CSignature
  * Method:    importPublicKey
  * Signature: (Ljava/lang/String;[BI)Lsun/security/mscapi/CPublicKey;
  */